diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/incoming-transactions.js index b6227d984..632bd96a4 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/incoming-transactions.js @@ -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 { @@ -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, }; } } diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index f153558d3..d6bfe48c3 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -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'; @@ -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') { @@ -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 @@ -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) { @@ -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); } @@ -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); @@ -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 + */ + + /** + * @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 { @@ -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; @@ -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 }; } /** diff --git a/app/scripts/migrations/053.js b/app/scripts/migrations/053.js new file mode 100644 index 000000000..f9d4dc55c --- /dev/null +++ b/app/scripts/migrations/053.js @@ -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; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index b4368c1b5..b30410202 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -57,6 +57,7 @@ const migrations = [ require('./050').default, require('./051').default, require('./052').default, + require('./053').default, ]; export default migrations; diff --git a/shared/constants/transaction.js b/shared/constants/transaction.js index 833463a60..87c33ebca 100644 --- a/shared/constants/transaction.js +++ b/shared/constants/transaction.js @@ -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. @@ -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', }; /** @@ -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. diff --git a/test/data/transaction-data.json b/test/data/transaction-data.json index e5ae1f5b8..37e7659dd 100644 --- a/test/data/transaction-data.json +++ b/test/data/transaction-data.json @@ -15,9 +15,8 @@ "gas": "0x5208", "gasPrice": "0x2540be400" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 12, @@ -76,9 +75,8 @@ "gas": "0x5208", "gasPrice": "0x2540be400" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 12, @@ -142,9 +140,8 @@ "gas": "0x5208", "gasPrice": "0x2540be400" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 0, @@ -203,9 +200,8 @@ "gas": "0x5208", "gasPrice": "0x2540be400" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 0, @@ -269,9 +265,8 @@ "gas": "0x5208", "gasPrice": "0x306dc4200" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 0, @@ -331,9 +326,8 @@ "gas": "0x5208", "gasPrice": "0x306dc4200" }, - "type": "standard", "origin": "metamask", - "transactionCategory": "sentEther", + "type": "sentEther", "nonceDetails": { "params": { "highestLocallyConfirmed": 0, @@ -398,7 +392,7 @@ "value": "0x1043561a882930000" }, "hash": "0x5ca26d1cdcabef1ac2ad5b2b38604c9ced65d143efc7525f848c46f28e0e4116", - "transactionCategory": "incoming" + "type": "incoming" }, "primaryTransaction": { "blockNumber": "6477257", @@ -415,7 +409,7 @@ "value": "0x1043561a882930000" }, "hash": "0x5ca26d1cdcabef1ac2ad5b2b38604c9ced65d143efc7525f848c46f28e0e4116", - "transactionCategory": "incoming" + "type": "incoming" }, "hasRetried": false, "hasCancelled": false @@ -436,7 +430,7 @@ "value": "0x0" }, "hash": "0xa42b2b433e5bd2616b52e30792aedb6a3c374a752a95d43d99e2a8b143937889", - "transactionCategory": "incoming" + "type": "incoming" }, "primaryTransaction": { "blockNumber": "6454493", @@ -453,7 +447,7 @@ "value": "0x0" }, "hash": "0xa42b2b433e5bd2616b52e30792aedb6a3c374a752a95d43d99e2a8b143937889", - "transactionCategory": "incoming" + "type": "incoming" }, "hasRetried": false, "hasCancelled": false @@ -474,7 +468,7 @@ "value": "0xde0b6b3a7640000" }, "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", - "transactionCategory": "incoming" + "type": "incoming" }, "primaryTransaction": { "blockNumber": "6195526", @@ -491,7 +485,7 @@ "value": "0xde0b6b3a7640000" }, "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", - "transactionCategory": "incoming" + "type": "incoming" }, "hasRetried": false, "hasCancelled": false @@ -514,7 +508,7 @@ "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", "destinationTokenSymbol": "ABC", "sourceTokenSymbol": "ETH", - "transactionCategory": "swap" + "type": "swap" }, "primaryTransaction": { "blockNumber": "6195527", @@ -531,7 +525,7 @@ "value": "0xde0b6b3a7640000" }, "hash": "0xbcb195f393f4468945b4045cd41bcdbc2f19ad75ae92a32cf153a3004e42009a", - "transactionCategory": "swap", + "type": "swap", "destinationTokenSymbol": "ABC", "destinationTokenAddress": "0xabca64466f257793eaa52fcfff5066894b76a149", "sourceTokenSymbol": "ETH" diff --git a/test/unit/app/controllers/incoming-transactions.test.js b/test/unit/app/controllers/incoming-transactions.test.js index d476d18cb..af59bdd92 100644 --- a/test/unit/app/controllers/incoming-transactions.test.js +++ b/test/unit/app/controllers/incoming-transactions.test.js @@ -16,7 +16,7 @@ import { ROPSTEN_NETWORK_ID, } from '../../../../shared/constants/network'; import { - TRANSACTION_CATEGORIES, + TRANSACTION_TYPES, TRANSACTION_STATUSES, } from '../../../../shared/constants/transaction'; import { NETWORK_EVENTS } from '../../../../app/scripts/controllers/network'; @@ -276,7 +276,7 @@ describe('IncomingTransactionsController', function () { chainId: ROPSTEN_CHAIN_ID, status: TRANSACTION_STATUSES.CONFIRMED, time: 16000000000000000, - transactionCategory: TRANSACTION_CATEGORIES.INCOMING, + type: TRANSACTION_TYPES.INCOMING, txParams: { from: '0xfake', gas: '0x0', @@ -620,7 +620,7 @@ describe('IncomingTransactionsController', function () { chainId: ROPSTEN_CHAIN_ID, status: TRANSACTION_STATUSES.CONFIRMED, time: 16000000000000000, - transactionCategory: TRANSACTION_CATEGORIES.INCOMING, + type: TRANSACTION_TYPES.INCOMING, txParams: { from: '0xfake', gas: '0x0', @@ -775,7 +775,7 @@ describe('IncomingTransactionsController', function () { chainId: ROPSTEN_CHAIN_ID, status: TRANSACTION_STATUSES.CONFIRMED, time: 16000000000000000, - transactionCategory: TRANSACTION_CATEGORIES.INCOMING, + type: TRANSACTION_TYPES.INCOMING, txParams: { from: '0xfake', gas: '0x0', @@ -1362,7 +1362,7 @@ describe('IncomingTransactionsController', function () { value: '0xf', }, hash: '0xg', - transactionCategory: TRANSACTION_CATEGORIES.INCOMING, + type: TRANSACTION_TYPES.INCOMING, }); }); @@ -1408,7 +1408,7 @@ describe('IncomingTransactionsController', function () { value: '0xf', }, hash: '0xg', - transactionCategory: TRANSACTION_CATEGORIES.INCOMING, + type: TRANSACTION_TYPES.INCOMING, }); }); }); diff --git a/test/unit/app/controllers/network/stubs.js b/test/unit/app/controllers/network/stubs.js index 421e125a8..4021bcddd 100644 --- a/test/unit/app/controllers/network/stubs.js +++ b/test/unit/app/controllers/network/stubs.js @@ -1,5 +1,4 @@ import { - TRANSACTION_CATEGORIES, TRANSACTION_STATUSES, TRANSACTION_TYPES, } from '../../../../../shared/constants/transaction'; @@ -14,7 +13,7 @@ export const txMetaStub = { metamaskNetworkId: '4', status: TRANSACTION_STATUSES.UNAPPROVED, time: 1572395156620, - transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, + type: TRANSACTION_TYPES.SENT_ETHER, txParams: { from: '0xf231d46dd78806e1dd93442cf33c7671f8538748', gas: '0x5208', @@ -22,7 +21,6 @@ export const txMetaStub = { to: '0xf231d46dd78806e1dd93442cf33c7671f8538748', value: '0x0', }, - type: TRANSACTION_TYPES.STANDARD, }, [ { @@ -196,7 +194,7 @@ export const txMetaStub = { status: TRANSACTION_STATUSES.SUBMITTED, submittedTime: 1572395158570, time: 1572395156620, - transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, + type: TRANSACTION_TYPES.SENT_ETHER, txParams: { from: '0xf231d46dd78806e1dd93442cf33c7671f8538748', gas: '0x5208', @@ -205,6 +203,5 @@ export const txMetaStub = { to: '0xf231d46dd78806e1dd93442cf33c7671f8538748', value: '0x0', }, - type: TRANSACTION_TYPES.STANDARD, v: '0x2c', }; diff --git a/test/unit/app/controllers/transactions/tx-controller.test.js b/test/unit/app/controllers/transactions/tx-controller.test.js index 2dacf3c6a..e6119a948 100644 --- a/test/unit/app/controllers/transactions/tx-controller.test.js +++ b/test/unit/app/controllers/transactions/tx-controller.test.js @@ -11,7 +11,6 @@ import { getTestAccounts, } from '../../../../stub/provider'; import { - TRANSACTION_CATEGORIES, TRANSACTION_STATUSES, TRANSACTION_TYPES, } from '../../../../../shared/constants/transaction'; @@ -776,76 +775,76 @@ describe('Transaction Controller', function () { }); }); - describe('#_determineTransactionCategory', function () { - it('should return a simple send transactionCategory when to is truthy but data is falsy', async function () { - const result = await txController._determineTransactionCategory({ + describe('#_determineTransactionType', function () { + it('should return a simple send type when to is truthy but data is falsy', async function () { + const result = await txController._determineTransactionType({ to: '0xabc', data: '', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, + type: TRANSACTION_TYPES.SENT_ETHER, getCodeResponse: null, }); }); - it('should return a token transfer transactionCategory when data is for the respective method call', async function () { - const result = await txController._determineTransactionCategory({ + it('should return a token transfer type when data is for the respective method call', async function () { + const result = await txController._determineTransactionType({ to: '0xabc', data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER, + type: TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER, getCodeResponse: undefined, }); }); - it('should return a token approve transactionCategory when data is for the respective method call', async function () { - const result = await txController._determineTransactionCategory({ + it('should return a token approve type when data is for the respective method call', async function () { + const result = await txController._determineTransactionType({ to: '0xabc', data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE, + type: TRANSACTION_TYPES.TOKEN_METHOD_APPROVE, getCodeResponse: undefined, }); }); - it('should return a contract deployment transactionCategory when to is falsy and there is data', async function () { - const result = await txController._determineTransactionCategory({ + it('should return a contract deployment type when to is falsy and there is data', async function () { + const result = await txController._determineTransactionType({ to: '', data: '0xabd', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.DEPLOY_CONTRACT, + type: TRANSACTION_TYPES.DEPLOY_CONTRACT, getCodeResponse: undefined, }); }); - it('should return a simple send transactionCategory with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () { - const result = await txController._determineTransactionCategory({ + it('should return a simple send type with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () { + const result = await txController._determineTransactionType({ to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: '0xabd', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, + type: TRANSACTION_TYPES.SENT_ETHER, getCodeResponse: '0x', }); }); - it('should return a simple send transactionCategory with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () { - const result = await txController._determineTransactionCategory({ + it('should return a simple send type with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () { + const result = await txController._determineTransactionType({ to: '0xabc', data: '0xabd', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER, + type: TRANSACTION_TYPES.SENT_ETHER, getCodeResponse: null, }); }); - it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () { + it('should return a contract interaction type with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () { const _providerResultStub = { // 1 gwei eth_gasPrice: '0x0de0b6b3a7640000', @@ -875,17 +874,17 @@ describe('Transaction Controller', function () { }), getParticipateInMetrics: () => false, }); - const result = await _txController._determineTransactionCategory({ + const result = await _txController._determineTransactionType({ to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: 'abd', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION, + type: TRANSACTION_TYPES.CONTRACT_INTERACTION, getCodeResponse: '0x0a', }); }); - it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is a contract address and data is falsy', async function () { + it('should return a contract interaction type with the correct getCodeResponse when to is a contract address and data is falsy', async function () { const _providerResultStub = { // 1 gwei eth_gasPrice: '0x0de0b6b3a7640000', @@ -915,12 +914,12 @@ describe('Transaction Controller', function () { }), getParticipateInMetrics: () => false, }); - const result = await _txController._determineTransactionCategory({ + const result = await _txController._determineTransactionType({ to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', data: '', }); assert.deepEqual(result, { - transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION, + type: TRANSACTION_TYPES.CONTRACT_INTERACTION, getCodeResponse: '0x0a', }); }); diff --git a/test/unit/migrations/053.test.js b/test/unit/migrations/053.test.js new file mode 100644 index 000000000..92d3055bc --- /dev/null +++ b/test/unit/migrations/053.test.js @@ -0,0 +1,136 @@ +import { strict as assert } from 'assert'; +import migration53 from '../../../app/scripts/migrations/053'; +import { TRANSACTION_TYPES } from '../../../shared/constants/transaction'; + +describe('migration #53', function () { + it('should update the version metadata', async function () { + const oldStorage = { + meta: { + version: 52, + }, + data: {}, + }; + + const newStorage = await migration53.migrate(oldStorage); + assert.deepEqual(newStorage.meta, { + version: 53, + }); + }); + + it('should update type of standard transactions', async function () { + const oldStorage = { + meta: {}, + data: { + TransactionController: { + transactions: [ + { + type: TRANSACTION_TYPES.CANCEL, + transactionCategory: TRANSACTION_TYPES.SENT_ETHER, + txParams: { foo: 'bar' }, + }, + { + type: 'standard', + transactionCategory: TRANSACTION_TYPES.SENT_ETHER, + txParams: { foo: 'bar' }, + }, + { + type: 'standard', + transactionCategory: TRANSACTION_TYPES.CONTRACT_INTERACTION, + txParams: { foo: 'bar' }, + }, + { + type: TRANSACTION_TYPES.RETRY, + transactionCategory: TRANSACTION_TYPES.SENT_ETHER, + txParams: { foo: 'bar' }, + }, + ], + }, + IncomingTransactionsController: { + incomingTransactions: { + test: { + transactionCategory: 'incoming', + txParams: { + foo: 'bar', + }, + }, + }, + }, + foo: 'bar', + }, + }; + + const newStorage = await migration53.migrate(oldStorage); + assert.deepEqual(newStorage.data, { + TransactionController: { + transactions: [ + { type: TRANSACTION_TYPES.CANCEL, txParams: { foo: 'bar' } }, + { type: TRANSACTION_TYPES.SENT_ETHER, txParams: { foo: 'bar' } }, + { + type: TRANSACTION_TYPES.CONTRACT_INTERACTION, + txParams: { foo: 'bar' }, + }, + { type: TRANSACTION_TYPES.RETRY, txParams: { foo: 'bar' } }, + ], + }, + IncomingTransactionsController: { + incomingTransactions: { + test: { + type: 'incoming', + txParams: { + foo: 'bar', + }, + }, + }, + }, + foo: 'bar', + }); + }); + + it('should do nothing if transactions state does not exist', async function () { + const oldStorage = { + meta: {}, + data: { + TransactionController: { + bar: 'baz', + }, + IncomingTransactionsController: { + foo: 'baz', + }, + foo: 'bar', + }, + }; + + const newStorage = await migration53.migrate(oldStorage); + assert.deepEqual(oldStorage.data, newStorage.data); + }); + + it('should do nothing if transactions state is empty', async function () { + const oldStorage = { + meta: {}, + data: { + TransactionController: { + transactions: [], + bar: 'baz', + }, + IncomingTransactionsController: { + incomingTransactions: {}, + baz: 'bar', + }, + foo: 'bar', + }, + }; + + const newStorage = await migration53.migrate(oldStorage); + assert.deepEqual(oldStorage.data, newStorage.data); + }); + + it('should do nothing if state is empty', async function () { + const oldStorage = { + meta: {}, + data: {}, + }; + + const newStorage = await migration53.migrate(oldStorage); + assert.deepEqual(oldStorage.data, newStorage.data); + }); +}); diff --git a/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js b/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js index 1ab3b4818..d8f39cdd7 100644 --- a/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js +++ b/ui/app/components/app/transaction-breakdown/transaction-breakdown.container.js @@ -6,19 +6,16 @@ import { } from '../../../selectors'; import { getHexGasTotal } from '../../../helpers/utils/confirm-tx.util'; import { sumHexes } from '../../../helpers/utils/transactions.util'; -import { TRANSACTION_CATEGORIES } from '../../../../../shared/constants/transaction'; import TransactionBreakdown from './transaction-breakdown.component'; const mapStateToProps = (state, ownProps) => { - const { transaction, transactionCategory } = ownProps; + const { transaction, isTokenApprove } = ownProps; const { txParams: { gas, gasPrice, value } = {}, txReceipt: { gasUsed } = {}, } = transaction; const { showFiatInTestnets } = getPreferences(state); const isMainnet = getIsMainnet(state); - const isTokenApprove = - transactionCategory === TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE; const gasLimit = typeof gasUsed === 'string' ? gasUsed : gas; diff --git a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 3c93ff921..c1256d7cb 100644 --- a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -10,6 +10,7 @@ import Tooltip from '../../ui/tooltip'; import Copy from '../../ui/icon/copy-icon.component'; import Popover from '../../ui/popover'; import { getBlockExplorerUrlForTx } from '../../../../../shared/modules/transaction.utils'; +import { TRANSACTION_TYPES } from '../../../../../shared/constants/transaction'; export default class TransactionListItemDetails extends PureComponent { static contextTypes = { @@ -156,7 +157,7 @@ export default class TransactionListItemDetails extends PureComponent { } = this.props; const { primaryTransaction: transaction, - initialTransaction: { transactionCategory }, + initialTransaction: { type }, } = transactionGroup; const { hash } = transaction; @@ -255,7 +256,7 @@ export default class TransactionListItemDetails extends PureComponent {