diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index a3afaeebb..1997ea777 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -2594,6 +2594,9 @@
"rpcUrl": {
"message": "New RPC URL"
},
+ "safeTransferFrom": {
+ "message": "Safe Transfer From"
+ },
"save": {
"message": "Save"
},
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index bd5fbdb5e..2abae9066 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -85,8 +85,8 @@ import {
import { hexToDecimal } from '../../ui/helpers/utils/conversions.util';
import { getTokenValueParam } from '../../ui/helpers/utils/token-util';
-import { getTransactionData } from '../../ui/helpers/utils/transactions.util';
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
+import { parseStandardTokenTransactionData } from '../../shared/modules/transaction.utils';
import ComposableObservableStore from './lib/ComposableObservableStore';
import AccountTracker from './lib/account-tracker';
import createLoggerMiddleware from './lib/createLoggerMiddleware';
@@ -777,7 +777,7 @@ export default class MetamaskController extends EventEmitter {
from: userAddress,
} = txMeta.txParams;
const { chainId } = txMeta;
- const transactionData = getTransactionData(data);
+ const transactionData = parseStandardTokenTransactionData(data);
const tokenAmountOrTokenId = getTokenValueParam(transactionData);
const { allCollectibles } = this.collectiblesController.state;
diff --git a/package.json b/package.json
index 65fb850f6..5b17dcc77 100644
--- a/package.json
+++ b/package.json
@@ -117,6 +117,7 @@
"@metamask/iframe-execution-environment-service": "^0.10.2",
"@metamask/jazzicon": "^2.0.0",
"@metamask/logo": "^3.1.1",
+ "@metamask/metamask-eth-abis": "^3.0.0",
"@metamask/obs-store": "^5.0.0",
"@metamask/post-message-stream": "^4.0.0",
"@metamask/providers": "^8.1.1",
diff --git a/shared/constants/transaction.js b/shared/constants/transaction.js
index b1ea01c39..1e461f491 100644
--- a/shared/constants/transaction.js
+++ b/shared/constants/transaction.js
@@ -48,6 +48,7 @@ export const TRANSACTION_TYPES = {
RETRY: 'retry',
TOKEN_METHOD_TRANSFER: 'transfer',
TOKEN_METHOD_TRANSFER_FROM: 'transferfrom',
+ TOKEN_METHOD_SAFE_TRANSFER_FROM: 'safetransferfrom',
TOKEN_METHOD_APPROVE: 'approve',
INCOMING: 'incoming',
SIMPLE_SEND: 'simpleSend',
diff --git a/shared/modules/transaction.utils.js b/shared/modules/transaction.utils.js
index e79e569c3..08adb46e3 100644
--- a/shared/modules/transaction.utils.js
+++ b/shared/modules/transaction.utils.js
@@ -1,6 +1,6 @@
import { isHexString } from 'ethereumjs-util';
import { ethers } from 'ethers';
-import abi from 'human-standard-token-abi';
+import { abiERC721, abiERC20, abiERC1155 } from '@metamask/metamask-eth-abis';
import log from 'loglevel';
import { TOKEN_STANDARDS } from '../../ui/helpers/constants/common';
import { ASSET_TYPES, TRANSACTION_TYPES } from '../constants/transaction';
@@ -19,7 +19,22 @@ import { isEqualCaseInsensitive } from './string-utils';
* code
*/
-const hstInterface = new ethers.utils.Interface(abi);
+/**
+ * @typedef EthersContractCall
+ * @type object
+ * @property {any[]} args - The args/params to the function call.
+ * An array-like object with numerical and string indices.
+ * @property {string} name - The name of the function.
+ * @property {string} signature - The function signature.
+ * @property {string} sighash - The function signature hash.
+ * @property {EthersBigNumber} value - The ETH value associated with the call.
+ * @property {FunctionFragment} functionFragment - The Ethers function fragment
+ * representation of the function.
+ */
+
+const erc20Interface = new ethers.utils.Interface(abiERC20);
+const erc721Interface = new ethers.utils.Interface(abiERC721);
+const erc1155Interface = new ethers.utils.Interface(abiERC1155);
export function transactionMatchesNetwork(transaction, chainId, networkId) {
if (typeof transaction.chainId !== 'undefined') {
@@ -83,6 +98,36 @@ export function txParamsAreDappSuggested(transaction) {
);
}
+/**
+ * Attempts to decode transaction data using ABIs for three different token standards: ERC20, ERC721, ERC1155.
+ * The data will decode correctly if the transaction is an interaction with a contract that matches one of these
+ * contract standards
+ *
+ * @param data - encoded transaction data
+ * @returns {EthersContractCall | undefined}
+ */
+export function parseStandardTokenTransactionData(data) {
+ try {
+ return erc20Interface.parseTransaction({ data });
+ } catch {
+ // ignore and next try to parse with erc721 ABI
+ }
+
+ try {
+ return erc721Interface.parseTransaction({ data });
+ } catch {
+ // ignore and next try to parse with erc1155 ABI
+ }
+
+ try {
+ return erc1155Interface.parseTransaction({ data });
+ } catch {
+ // ignore and return undefined
+ }
+
+ return undefined;
+}
+
/**
* Determines the type of the transaction by analyzing the txParams.
* This method will return one of the types defined in shared/constants/transactions
@@ -98,7 +143,7 @@ export async function determineTransactionType(txParams, query) {
const { data, to } = txParams;
let name;
try {
- name = data && hstInterface.parseTransaction({ data }).name;
+ ({ name } = data && parseStandardTokenTransactionData(data));
} catch (error) {
log.debug('Failed to parse transaction data.', error, data);
}
@@ -107,6 +152,7 @@ export async function determineTransactionType(txParams, query) {
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
+ TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM,
].find((methodName) => isEqualCaseInsensitive(methodName, name));
let result;
diff --git a/shared/modules/transaction.utils.test.js b/shared/modules/transaction.utils.test.js
index f6d816160..fba8c7827 100644
--- a/shared/modules/transaction.utils.test.js
+++ b/shared/modules/transaction.utils.test.js
@@ -5,9 +5,28 @@ import {
determineTransactionType,
isEIP1559Transaction,
isLegacyTransaction,
+ parseStandardTokenTransactionData,
} from './transaction.utils';
describe('Transaction.utils', function () {
+ describe('parseStandardTokenTransactionData', () => {
+ it('should return token data', () => {
+ const tokenData = parseStandardTokenTransactionData(
+ '0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20',
+ );
+ expect(tokenData).toStrictEqual(expect.anything());
+ const { name, args } = tokenData;
+ expect(name).toStrictEqual(TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER);
+ const to = args._to;
+ const value = args._value.toString();
+ expect(to).toStrictEqual('0x50A9D56C2B8BA9A5c7f2C08C3d26E0499F23a706');
+ expect(value).toStrictEqual('20000');
+ });
+
+ it('should not throw errors when called without arguments', () => {
+ expect(() => parseStandardTokenTransactionData()).not.toThrow();
+ });
+ });
describe('isEIP1559Transaction', function () {
it('should return true if both maxFeePerGas and maxPriorityFeePerGas are hex strings', () => {
expect(
diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
index 7da4ddeba..218fc99a7 100644
--- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
+++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-summary/confirm-page-container-summary.component.js
@@ -38,6 +38,7 @@ const ConfirmPageContainerSummary = (props) => {
TRANSACTION_TYPES.CONTRACT_INTERACTION,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
+ TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM,
];
const isContractTypeTransaction = contractInitiatedTransactionType.includes(
transactionType,
@@ -49,7 +50,8 @@ const ConfirmPageContainerSummary = (props) => {
// type of contract interaction it is passed as toAddress
contractAddress =
transactionType === TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER ||
- transactionType === TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM
+ transactionType === TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM ||
+ transactionType === TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM
? tokenAddress
: toAddress;
}
diff --git a/ui/ducks/confirm-transaction/confirm-transaction.duck.js b/ui/ducks/confirm-transaction/confirm-transaction.duck.js
index c05050f28..b16d60312 100644
--- a/ui/ducks/confirm-transaction/confirm-transaction.duck.js
+++ b/ui/ducks/confirm-transaction/confirm-transaction.duck.js
@@ -13,14 +13,12 @@ import {
addEth,
} from '../../helpers/utils/confirm-tx.util';
-import {
- getTransactionData,
- sumHexes,
-} from '../../helpers/utils/transactions.util';
+import { sumHexes } from '../../helpers/utils/transactions.util';
import { conversionUtil } from '../../../shared/modules/conversion.utils';
import { getAveragePriceEstimateInHexWEI } from '../../selectors/custom-gas';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
+import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils';
// Actions
const createActionType = (action) => `metamask/confirm-transaction/${action}`;
@@ -285,7 +283,7 @@ export function setTransactionToConfirm(transactionId) {
if (txParams.data) {
const { to: tokenAddress, data } = txParams;
- const tokenData = getTransactionData(data);
+ const tokenData = parseStandardTokenTransactionData(data);
const tokens = getTokens(state);
const currentToken = tokens?.find(({ address }) =>
isEqualCaseInsensitive(tokenAddress, address),
diff --git a/ui/helpers/constants/routes.js b/ui/helpers/constants/routes.js
index 83d659dbf..519e0a098 100644
--- a/ui/helpers/constants/routes.js
+++ b/ui/helpers/constants/routes.js
@@ -88,6 +88,7 @@ const CONFIRM_SEND_TOKEN_PATH = '/send-token';
const CONFIRM_DEPLOY_CONTRACT_PATH = '/deploy-contract';
const CONFIRM_APPROVE_PATH = '/approve';
const CONFIRM_TRANSFER_FROM_PATH = '/transfer-from';
+const CONFIRM_SAFE_TRANSFER_FROM_PATH = '/safe-transfer-from';
const CONFIRM_TOKEN_METHOD_PATH = '/token-method';
const SIGNATURE_REQUEST_PATH = '/signature-request';
const DECRYPT_MESSAGE_REQUEST_PATH = '/decrypt-message-request';
@@ -140,6 +141,7 @@ const PATH_NAME_MAP = {
[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_DEPLOY_CONTRACT_PATH}`]: 'Confirm Deploy Contract Transaction Page',
[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_APPROVE_PATH}`]: 'Confirm Approve Transaction Page',
[`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_TRANSFER_FROM_PATH}`]: 'Confirm Transfer From Transaction Page',
+ [`${CONFIRM_TRANSACTION_ROUTE}/:id${CONFIRM_SAFE_TRANSFER_FROM_PATH}`]: 'Confirm Safe Transfer From Transaction Page',
[`${CONFIRM_TRANSACTION_ROUTE}/:id${SIGNATURE_REQUEST_PATH}`]: 'Signature Request Page',
[`${CONFIRM_TRANSACTION_ROUTE}/:id${DECRYPT_MESSAGE_REQUEST_PATH}`]: 'Decrypt Message Request Page',
[`${CONFIRM_TRANSACTION_ROUTE}/:id${ENCRYPTION_PUBLIC_KEY_REQUEST_PATH}`]: 'Encryption Public Key Request Page',
@@ -200,6 +202,7 @@ export {
CONFIRM_DEPLOY_CONTRACT_PATH,
CONFIRM_APPROVE_PATH,
CONFIRM_TRANSFER_FROM_PATH,
+ CONFIRM_SAFE_TRANSFER_FROM_PATH,
CONFIRM_TOKEN_METHOD_PATH,
SIGNATURE_REQUEST_PATH,
DECRYPT_MESSAGE_REQUEST_PATH,
diff --git a/ui/helpers/utils/token-util.js b/ui/helpers/utils/token-util.js
index a75db6da6..b934ed176 100644
--- a/ui/helpers/utils/token-util.js
+++ b/ui/helpers/utils/token-util.js
@@ -7,15 +7,14 @@ import {
import { getTokenStandardAndDetails } from '../../store/actions';
import { ERC1155, ERC721 } from '../constants/common';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
+import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils';
import * as util from './util';
import { formatCurrency } from './confirm-tx.util';
-import { getTransactionData } from './transactions.util';
const DEFAULT_SYMBOL = '';
async function getSymbolFromContract(tokenAddress) {
const token = util.getContractAtAddress(tokenAddress);
-
try {
const result = await token.symbol();
return result[0];
@@ -136,7 +135,8 @@ export function calcTokenValue(value, decimals) {
* @returns {string | undefined} A lowercase address string.
*/
export function getTokenAddressParam(tokenData = {}) {
- const value = tokenData?.args?._to || tokenData?.args?.[0];
+ const value =
+ tokenData?.args?._to || tokenData?.args?.to || tokenData?.args?.[0];
return value?.toString().toLowerCase();
}
@@ -223,7 +223,7 @@ export async function getAssetDetails(
transactionData,
existingCollectibles,
) {
- const tokenData = getTransactionData(transactionData);
+ const tokenData = parseStandardTokenTransactionData(transactionData);
if (!tokenData) {
throw new Error('Unable to detect valid token data');
}
diff --git a/ui/helpers/utils/transactions.util.js b/ui/helpers/utils/transactions.util.js
index 6bdf6f548..25a38593f 100644
--- a/ui/helpers/utils/transactions.util.js
+++ b/ui/helpers/utils/transactions.util.js
@@ -1,6 +1,4 @@
import { MethodRegistry } from 'eth-method-registry';
-import abi from 'human-standard-token-abi';
-import { ethers } from 'ethers';
import log from 'loglevel';
import { addHexPrefix } from '../../../app/scripts/lib/util';
@@ -14,8 +12,6 @@ import { addCurrencies } from '../../../shared/modules/conversion.utils';
import { readAddressAsContract } from '../../../shared/modules/contract-utils';
import fetchWithCache from './fetch-with-cache';
-const hstInterface = new ethers.utils.Interface(abi);
-
/**
* @typedef EthersContractCall
* @type object
@@ -29,19 +25,6 @@ const hstInterface = new ethers.utils.Interface(abi);
* representation of the function.
*/
-/**
- * @param data
- * @returns {EthersContractCall | undefined}
- */
-export function getTransactionData(data) {
- try {
- return hstInterface.parseTransaction({ data });
- } catch (error) {
- log.debug('Failed to parse transaction data.', error, data);
- return undefined;
- }
-}
-
async function getMethodFrom4Byte(fourBytePrefix) {
const fourByteResponse = await fetchWithCache(
`https://www.4byte.directory/api/v1/signatures/?hex_signature=${fourBytePrefix}`,
@@ -122,6 +105,7 @@ export function isTokenMethodAction(type) {
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
+ TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM,
].includes(type);
}
@@ -215,6 +199,9 @@ export function getTransactionTypeTitle(t, type, nativeCurrency = 'ETH') {
case TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM: {
return t('transferFrom');
}
+ case TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM: {
+ return t('safeTransferFrom');
+ }
case TRANSACTION_TYPES.TOKEN_METHOD_APPROVE: {
return t('approve');
}
diff --git a/ui/helpers/utils/transactions.util.test.js b/ui/helpers/utils/transactions.util.test.js
index ce5225076..591e46d07 100644
--- a/ui/helpers/utils/transactions.util.test.js
+++ b/ui/helpers/utils/transactions.util.test.js
@@ -1,5 +1,4 @@
import {
- TRANSACTION_TYPES,
TRANSACTION_GROUP_STATUSES,
TRANSACTION_STATUSES,
TRANSACTION_ENVELOPE_TYPES,
@@ -7,25 +6,6 @@ import {
import * as utils from './transactions.util';
describe('Transactions utils', () => {
- describe('getTransactionData', () => {
- it('should return token data', () => {
- const tokenData = utils.getTransactionData(
- '0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20',
- );
- expect(tokenData).toStrictEqual(expect.anything());
- const { name, args } = tokenData;
- expect(name).toStrictEqual(TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER);
- const to = args._to;
- const value = args._value.toString();
- expect(to).toStrictEqual('0x50A9D56C2B8BA9A5c7f2C08C3d26E0499F23a706');
- expect(value).toStrictEqual('20000');
- });
-
- it('should not throw errors when called without arguments', () => {
- expect(() => utils.getTransactionData()).not.toThrow();
- });
- });
-
describe('getStatusKey', () => {
it('should return the correct status', () => {
const tests = [
diff --git a/ui/hooks/useAssetDetails.js b/ui/hooks/useAssetDetails.js
index ac12ed494..ce9ef30ba 100644
--- a/ui/hooks/useAssetDetails.js
+++ b/ui/hooks/useAssetDetails.js
@@ -1,5 +1,6 @@
import { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
+import { parseStandardTokenTransactionData } from '../../shared/modules/transaction.utils';
import { getCollectibles, getTokens } from '../ducks/metamask/metamask';
import { ERC1155, ERC721, ERC20 } from '../helpers/constants/common';
import {
@@ -8,14 +9,12 @@ import {
getTokenAddressParam,
getTokenValueParam,
} from '../helpers/utils/token-util';
-import { getTransactionData } from '../helpers/utils/transactions.util';
import { getTokenList } from '../selectors';
import { hideLoadingIndication, showLoadingIndication } from '../store/actions';
import { usePrevious } from './usePrevious';
export function useAssetDetails(tokenAddress, userAddress, transactionData) {
const dispatch = useDispatch();
-
// state selectors
const tokens = useSelector(getTokens);
const collectibles = useSelector(getCollectibles);
@@ -84,7 +83,7 @@ export function useAssetDetails(tokenAddress, userAddress, transactionData) {
balance,
decimals: currentAssetDecimals,
} = currentAsset;
- const tokenData = getTransactionData(transactionData);
+ const tokenData = parseStandardTokenTransactionData(transactionData);
assetStandard = standard;
assetAddress = tokenAddress;
tokenSymbol = symbol;
diff --git a/ui/hooks/useTokenData.js b/ui/hooks/useTokenData.js
index d1d7e1ffe..654bb50ff 100644
--- a/ui/hooks/useTokenData.js
+++ b/ui/hooks/useTokenData.js
@@ -1,5 +1,5 @@
import { useMemo } from 'react';
-import { getTransactionData } from '../helpers/utils/transactions.util';
+import { parseStandardTokenTransactionData } from '../../shared/modules/transaction.utils';
/**
* useTokenData
@@ -19,6 +19,6 @@ export function useTokenData(transactionData, isTokenTransaction = true) {
if (!isTokenTransaction || !transactionData) {
return null;
}
- return getTransactionData(transactionData);
+ return parseStandardTokenTransactionData(transactionData);
}, [isTokenTransaction, transactionData]);
}
diff --git a/ui/hooks/useTokenDisplayValue.test.js b/ui/hooks/useTokenDisplayValue.test.js
index 9be126f81..26e2a4374 100644
--- a/ui/hooks/useTokenDisplayValue.test.js
+++ b/ui/hooks/useTokenDisplayValue.test.js
@@ -1,7 +1,7 @@
import { renderHook } from '@testing-library/react-hooks';
import sinon from 'sinon';
import * as tokenUtil from '../helpers/utils/token-util';
-import * as txUtil from '../helpers/utils/transactions.util';
+import * as txUtil from '../../shared/modules/transaction.utils';
import { useTokenDisplayValue } from './useTokenDisplayValue';
const tests = [
@@ -122,9 +122,12 @@ describe('useTokenDisplayValue', () => {
describe(`when input is decimals: ${token.decimals} and value: ${tokenValue}`, () => {
it(`should return ${displayValue} as displayValue`, () => {
const getTokenValueStub = sinon.stub(tokenUtil, 'getTokenValueParam');
- const getTokenDataStub = sinon.stub(txUtil, 'getTransactionData');
+ const parseStandardTokenTransactionDataStub = sinon.stub(
+ txUtil,
+ 'parseStandardTokenTransactionData',
+ );
- getTokenDataStub.callsFake(() => tokenData);
+ parseStandardTokenTransactionDataStub.callsFake(() => tokenData);
getTokenValueStub.callsFake(() => tokenValue);
const { result } = renderHook(() =>
diff --git a/ui/pages/confirm-approve/confirm-approve.util.js b/ui/pages/confirm-approve/confirm-approve.util.js
index 7bc3ea550..022dc108a 100644
--- a/ui/pages/confirm-approve/confirm-approve.util.js
+++ b/ui/pages/confirm-approve/confirm-approve.util.js
@@ -1,16 +1,16 @@
import { TRANSACTION_TYPES } from '../../../shared/constants/transaction';
+import { parseStandardTokenTransactionData } from '../../../shared/modules/transaction.utils';
import { decimalToHex } from '../../helpers/utils/conversions.util';
import {
calcTokenValue,
getTokenAddressParam,
} from '../../helpers/utils/token-util';
-import { getTransactionData } from '../../helpers/utils/transactions.util';
export function getCustomTxParamsData(
data,
{ customPermissionAmount, decimals },
) {
- const tokenData = getTransactionData(data);
+ const tokenData = parseStandardTokenTransactionData(data);
if (!tokenData) {
throw new Error('Invalid data');
diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
index e5c325242..e375a3c96 100644
--- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -43,6 +43,7 @@ import {
} from '../../ducks/metamask/metamask';
import {
+ parseStandardTokenTransactionData,
transactionMatchesNetwork,
txParamsAreDappSuggested,
} from '../../../shared/modules/transaction.utils';
@@ -52,6 +53,7 @@ import { getGasLoadingAnimationIsShowing } from '../../ducks/app/app';
import { isLegacyTransaction } from '../../helpers/utils/transactions.util';
import { CUSTOM_GAS_ESTIMATE } from '../../../shared/constants/gas';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
+import { getTokenAddressParam } from '../../helpers/utils/token-util';
import ConfirmTransactionBase from './confirm-transaction-base.component';
let customNonceValue = '';
@@ -104,9 +106,12 @@ const mapStateToProps = (state, ownProps) => {
} = (transaction && transaction.txParams) || txParams;
const accounts = getMetaMaskAccounts(state);
+ const transactionData = parseStandardTokenTransactionData(data);
+ const tokenToAddress = getTokenAddressParam(transactionData);
+
const { balance } = accounts[fromAddress];
const { name: fromName } = identities[fromAddress];
- const toAddress = propsToAddress || txParamsToAddress;
+ const toAddress = propsToAddress || tokenToAddress || txParamsToAddress;
const tokenList = getTokenList(state);
const useTokenDetection = getUseTokenDetection(state);
diff --git a/ui/pages/confirm-transaction-switch/confirm-transaction-switch.component.js b/ui/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
index 7e9882d65..db58cc640 100644
--- a/ui/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
+++ b/ui/pages/confirm-transaction-switch/confirm-transaction-switch.component.js
@@ -13,6 +13,7 @@ import {
SIGNATURE_REQUEST_PATH,
DECRYPT_MESSAGE_REQUEST_PATH,
ENCRYPTION_PUBLIC_KEY_REQUEST_PATH,
+ CONFIRM_SAFE_TRANSFER_FROM_PATH,
} from '../../helpers/constants/routes';
import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { TRANSACTION_TYPES } from '../../../shared/constants/transaction';
@@ -50,6 +51,10 @@ export default class ConfirmTransactionSwitch extends Component {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TRANSFER_FROM_PATH}`;
return ;
}
+ case TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM: {
+ const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SAFE_TRANSFER_FROM_PATH}`;
+ return ;
+ }
default: {
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TOKEN_METHOD_PATH}`;
return ;
diff --git a/ui/pages/confirm-transaction/confirm-token-transaction-switch.js b/ui/pages/confirm-transaction/confirm-token-transaction-switch.js
index ea06c0d0b..036f2b149 100644
--- a/ui/pages/confirm-transaction/confirm-token-transaction-switch.js
+++ b/ui/pages/confirm-transaction/confirm-token-transaction-switch.js
@@ -4,6 +4,7 @@ import { useSelector } from 'react-redux';
import { Switch, Route } from 'react-router-dom';
import {
CONFIRM_APPROVE_PATH,
+ CONFIRM_SAFE_TRANSFER_FROM_PATH,
CONFIRM_SEND_TOKEN_PATH,
CONFIRM_TRANSACTION_ROUTE,
CONFIRM_TRANSFER_FROM_PATH,
@@ -88,6 +89,29 @@ export default function ConfirmTokenTransactionSwitch({ transaction }) {
/>
)}
/>
+ (
+
+ )}
+ />