Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove transactionCategory in favor of more types #10615

Merged
merged 2 commits into from
Mar 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/scripts/controllers/incoming-transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { bnToHex } from '../lib/util';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';

import {
TRANSACTION_CATEGORIES,
TRANSACTION_TYPES,
TRANSACTION_STATUSES,
} from '../../../shared/constants/transaction';
import {
Expand Down Expand Up @@ -296,7 +296,7 @@ export default class IncomingTransactionsController {
value: bnToHex(new BN(txMeta.value)),
},
hash: txMeta.hash,
transactionCategory: TRANSACTION_CATEGORIES.INCOMING,
type: TRANSACTION_TYPES.INCOMING,
};
}
}
Expand Down
58 changes: 36 additions & 22 deletions app/scripts/controllers/transactions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys';
import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/app/pages/swaps/swaps.util';
import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
} from '../../../../shared/constants/transaction';
Expand Down Expand Up @@ -235,11 +234,10 @@ export default class TransactionController extends EventEmitter {
`generateTxMeta` adds the default txMeta properties to the passed object.
These include the tx's `id`. As we use the id for determining order of
txes in the tx-state-manager, it is necessary to call the asynchronous
method `this._determineTransactionCategory` after `generateTxMeta`.
method `this._determineTransactionType` after `generateTxMeta`.
*/
let txMeta = this.txStateManager.generateTxMeta({
txParams: normalizedTxParams,
type: TRANSACTION_TYPES.STANDARD,
});

if (origin === 'metamask') {
Expand All @@ -265,11 +263,10 @@ export default class TransactionController extends EventEmitter {

txMeta.origin = origin;

const {
transactionCategory,
getCodeResponse,
} = await this._determineTransactionCategory(txParams);
txMeta.transactionCategory = transactionCategory;
const { type, getCodeResponse } = await this._determineTransactionType(
txParams,
);
txMeta.type = type;

// ensure value
txMeta.txParams.value = txMeta.txParams.value
Expand Down Expand Up @@ -347,7 +344,7 @@ export default class TransactionController extends EventEmitter {
return {};
} else if (
txMeta.txParams.to &&
txMeta.transactionCategory === TRANSACTION_CATEGORIES.SENT_ETHER
txMeta.type === TRANSACTION_TYPES.SENT_ETHER
) {
// if there's data in the params, but there's no contract code, it's not a valid transaction
if (txMeta.txParams.data) {
Expand Down Expand Up @@ -581,7 +578,7 @@ export default class TransactionController extends EventEmitter {
async publishTransaction(txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId);
txMeta.rawTx = rawTx;
if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) {
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const preTxBalance = await this.query.getBalance(txMeta.txParams.from);
txMeta.preTxBalance = preTxBalance.toString(16);
}
Expand Down Expand Up @@ -637,7 +634,7 @@ export default class TransactionController extends EventEmitter {
'transactions#confirmTransaction - add txReceipt',
);

if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) {
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
const latestTxMeta = this.txStateManager.getTx(txId);

Expand Down Expand Up @@ -812,10 +809,27 @@ export default class TransactionController extends EventEmitter {
}

/**
Returns a "type" for a transaction out of the following list: simpleSend, tokenTransfer, tokenApprove,
contractDeployment, contractMethodCall
*/
async _determineTransactionCategory(txParams) {
* @typedef { 'transfer' | 'approve' | 'transferfrom' | 'contractInteraction'| 'sentEther' } InferrableTransactionTypes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat! This is appreciated.

*/

/**
* @typedef {Object} InferTransactionTypeResult
* @property {InferrableTransactionTypes} type - The type of transaction
* @property {string} getCodeResponse - The contract code, in hex format if
* it exists. '0x0' or '0x' are also indicators of non-existent contract
* code
*/

/**
* Determines the type of the transaction by analyzing the txParams.
* This method will return one of the types defined in shared/constants/transactions
* It will never return TRANSACTION_TYPE_CANCEL or TRANSACTION_TYPE_RETRY as these
* represent specific events that we control from the extension and are added manually
* at transaction creation.
* @param {Object} txParams - Parameters for the transaction
* @returns {InferTransactionTypeResult}
*/
async _determineTransactionType(txParams) {
const { data, to } = txParams;
let name;
try {
Expand All @@ -825,16 +839,16 @@ export default class TransactionController extends EventEmitter {
}

const tokenMethodName = [
TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER_FROM,
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
].find((methodName) => methodName === name && name.toLowerCase());

let result;
if (data && tokenMethodName) {
result = tokenMethodName;
} else if (data && !to) {
result = TRANSACTION_CATEGORIES.DEPLOY_CONTRACT;
result = TRANSACTION_TYPES.DEPLOY_CONTRACT;
}

let code;
Expand All @@ -849,11 +863,11 @@ export default class TransactionController extends EventEmitter {
const codeIsEmpty = !code || code === '0x' || code === '0x0';

result = codeIsEmpty
? TRANSACTION_CATEGORIES.SENT_ETHER
: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION;
? TRANSACTION_TYPES.SENT_ETHER
: TRANSACTION_TYPES.CONTRACT_INTERACTION;
}

return { transactionCategory: result, getCodeResponse: code };
return { type: result, getCodeResponse: code };
}

/**
Expand Down
46 changes: 46 additions & 0 deletions app/scripts/migrations/053.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { cloneDeep } from 'lodash';
import { TRANSACTION_TYPES } from '../../../shared/constants/transaction';

const version = 53;

/**
* Deprecate transactionCategory and consolidate on 'type'
*/
export default {
version,
async migrate(originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData);
versionedData.meta.version = version;
const state = versionedData.data;
versionedData.data = transformState(state);
return versionedData;
},
};

function transformState(state) {
const transactions = state?.TransactionController?.transactions;
const incomingTransactions =
state?.IncomingTransactionsController?.incomingTransactions;
if (Array.isArray(transactions)) {
transactions.forEach((transaction) => {
if (
transaction.type !== TRANSACTION_TYPES.RETRY &&
transaction.type !== TRANSACTION_TYPES.CANCEL
) {
transaction.type = transaction.transactionCategory;
}
delete transaction.transactionCategory;
});
}
if (incomingTransactions) {
const incomingTransactionsEntries = Object.entries(incomingTransactions);
incomingTransactionsEntries.forEach(([key, transaction]) => {
delete transaction.transactionCategory;
state.IncomingTransactionsController.incomingTransactions[key] = {
...transaction,
type: TRANSACTION_TYPES.INCOMING,
};
});
}
return state;
}
1 change: 1 addition & 0 deletions app/scripts/migrations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const migrations = [
require('./050').default,
require('./051').default,
require('./052').default,
require('./053').default,
];

export default migrations;
71 changes: 29 additions & 42 deletions shared/constants/transaction.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
/**
* Transaction Type is a MetaMask construct used internally
* @typedef {Object} TransactionTypes
* @property {'standard'} STANDARD - A standard transaction, usually the first with
* a given nonce
* @property {'transfer'} TOKEN_METHOD_TRANSFER - A token transaction where the user
* is sending tokens that they own to another address
* @property {'transferfrom'} TOKEN_METHOD_TRANSFER_FROM - A token transaction
* transferring tokens from an account that the sender has an allowance of.
* For more information on allowances, see the approve type.
* @property {'approve'} TOKEN_METHOD_APPROVE - A token transaction requesting an
* allowance of the token to spend on behalf of the user
* @property {'incoming'} INCOMING - An incoming (deposit) transaction
* @property {'sentEther'} SENT_ETHER - A transaction sending ether to a recipient
* @property {'contractInteraction'} CONTRACT_INTERACTION - A transaction that is
* interacting with a smart contract's methods that we have not treated as a special
* case, such as approve, transfer, and transferfrom
* @property {'contractDeployment'} DEPLOY_CONTRACT - A transaction that deployed
* a smart contract
* @property {'swap'} SWAP - A transaction swapping one token for another through
* MetaMask Swaps
* @property {'swapApproval'} SWAP_APPROVAL - Similar to the approve type, a swap
* approval is a special case of ERC20 approve method that requests an allowance of
* the token to spend on behalf of the user for the MetaMask Swaps contract. The first
* swap for any token will have an accompanying swapApproval transaction.
* @property {'cancel'} CANCEL - A transaction submitted with the same nonce as a
* previous transaction, a higher gas price and a zeroed out send amount. Useful
* for users who accidentally send to erroneous addresses or if they send too much.
Expand All @@ -16,9 +34,17 @@
* @type {TransactionTypes}
*/
export const TRANSACTION_TYPES = {
STANDARD: 'standard',
CANCEL: 'cancel',
RETRY: 'retry',
TOKEN_METHOD_TRANSFER: 'transfer',
TOKEN_METHOD_TRANSFER_FROM: 'transferfrom',
TOKEN_METHOD_APPROVE: 'approve',
INCOMING: 'incoming',
SENT_ETHER: 'sentEther',
CONTRACT_INTERACTION: 'contractInteraction',
DEPLOY_CONTRACT: 'contractDeployment',
SWAP: 'swap',
SWAP_APPROVAL: 'swapApproval',
};

/**
Expand Down Expand Up @@ -53,45 +79,6 @@ export const TRANSACTION_STATUSES = {
CONFIRMED: 'confirmed',
};

/**
* @typedef {Object} TransactionCategories
* @property {'transfer'} TOKEN_METHOD_TRANSFER - A token transaction where the user
* is sending tokens that they own to another address
* @property {'transferfrom'} TOKEN_METHOD_TRANSFER_FROM - A token transaction
* transferring tokens from an account that the sender has an allowance of.
* For more information on allowances, see the approve category.
* @property {'approve'} TOKEN_METHOD_APPROVE - A token transaction requesting an
* allowance of the token to spend on behalf of the user
* @property {'incoming'} INCOMING - An incoming (deposit) transaction
* @property {'sentEther'} SENT_ETHER - A transaction sending ether to a recipient
* @property {'contractInteraction'} CONTRACT_INTERACTION - A transaction that is
* interacting with a smart contract's methods that we have not treated as a special
* case, such as approve, transfer, and transferfrom
* @property {'contractDeployment'} DEPLOY_CONTRACT - A transaction that deployed
* a smart contract
* @property {'swap'} SWAP - A transaction swapping one token for another through
* MetaMask Swaps
* @property {'swapApproval'} SWAP_APPROVAL - Similar to the approve category, a swap
* approval is a special case of ERC20 approve method that requests an allowance of
* the token to spend on behalf of the user for the MetaMask Swaps contract. The first
* swap for any token will have an accompanying swapApproval transaction.
*/

/**
* @type {TransactionCategories}
*/
export const TRANSACTION_CATEGORIES = {
TOKEN_METHOD_TRANSFER: 'transfer',
TOKEN_METHOD_TRANSFER_FROM: 'transferfrom',
TOKEN_METHOD_APPROVE: 'approve',
INCOMING: 'incoming',
SENT_ETHER: 'sentEther',
CONTRACT_INTERACTION: 'contractInteraction',
DEPLOY_CONTRACT: 'contractDeployment',
SWAP: 'swap',
SWAP_APPROVAL: 'swapApproval',
};

/**
* Transaction Group Status is a MetaMask construct to track the status of groups
* of transactions.
Expand Down
Loading