mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
Fix issue where we show contract address as recipient when calling safe transfer method on erc721 or erc1155 contracts (#13535)
* fix issue where we show contract address as recipient when calling safe transfer method on erc721 or erc1155 contracts * updates function name getTransactionData -> parseStandardTokenTransactionData, and adds documentation
This commit is contained in:
parent
41974cec3b
commit
e3ea4f2cd0
3
app/_locales/en/messages.json
generated
3
app/_locales/en/messages.json
generated
@ -2594,6 +2594,9 @@
|
||||
"rpcUrl": {
|
||||
"message": "New RPC URL"
|
||||
},
|
||||
"safeTransferFrom": {
|
||||
"message": "Safe Transfer From"
|
||||
},
|
||||
"save": {
|
||||
"message": "Save"
|
||||
},
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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 = [
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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(() =>
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
|
@ -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 <Redirect to={{ pathname }} />;
|
||||
}
|
||||
case TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM: {
|
||||
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_SAFE_TRANSFER_FROM_PATH}`;
|
||||
return <Redirect to={{ pathname }} />;
|
||||
}
|
||||
default: {
|
||||
const pathname = `${CONFIRM_TRANSACTION_ROUTE}/${id}${CONFIRM_TOKEN_METHOD_PATH}`;
|
||||
return <Redirect to={{ pathname }} />;
|
||||
|
@ -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 }) {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_SAFE_TRANSFER_FROM_PATH}`}
|
||||
render={() => (
|
||||
<ConfirmTokenTransactionBase
|
||||
assetStandard={assetStandard}
|
||||
assetName={assetName}
|
||||
userBalance={userBalance}
|
||||
tokenSymbol={tokenSymbol}
|
||||
decimals={decimals}
|
||||
image={tokenImage}
|
||||
tokenAddress={tokenAddress}
|
||||
toAddress={toAddress}
|
||||
tokenAmount={tokenAmount}
|
||||
tokenId={tokenId}
|
||||
userAddress={userAddress}
|
||||
transaction={transaction}
|
||||
ethTransactionTotal={ethTransactionTotal}
|
||||
fiatTransactionTotal={fiatTransactionTotal}
|
||||
hexMaximumTransactionFee={hexMaximumTransactionFee}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={`${CONFIRM_TRANSACTION_ROUTE}/:id?${CONFIRM_SEND_TOKEN_PATH}`}
|
||||
|
@ -75,7 +75,6 @@ import {
|
||||
SWAPS_ERROR_ROUTE,
|
||||
AWAITING_SWAP_ROUTE,
|
||||
} from '../../../helpers/constants/routes';
|
||||
import { getTransactionData } from '../../../helpers/utils/transactions.util';
|
||||
import {
|
||||
calcTokenAmount,
|
||||
calcTokenValue,
|
||||
@ -113,6 +112,7 @@ import SwapsFooter from '../swaps-footer';
|
||||
import PulseLoader from '../../../components/ui/pulse-loader'; // TODO: Replace this with a different loading component.
|
||||
import Box from '../../../components/ui/box';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
import { parseStandardTokenTransactionData } from '../../../../shared/modules/transaction.utils';
|
||||
import ViewQuotePriceDifference from './view-quote-price-difference';
|
||||
|
||||
let intervalId;
|
||||
@ -320,7 +320,7 @@ export default function ViewQuote() {
|
||||
const tokenBalanceUnavailable =
|
||||
tokensWithBalances && balanceToken === undefined;
|
||||
|
||||
const approveData = getTransactionData(approveTxParams?.data);
|
||||
const approveData = parseStandardTokenTransactionData(approveTxParams?.data);
|
||||
const approveValue = approveData && getTokenValueParam(approveData);
|
||||
const approveAmount =
|
||||
approveValue &&
|
||||
|
@ -2914,7 +2914,7 @@
|
||||
gl-mat4 "1.1.4"
|
||||
gl-vec3 "1.0.3"
|
||||
|
||||
"@metamask/metamask-eth-abis@3.0.0":
|
||||
"@metamask/metamask-eth-abis@3.0.0", "@metamask/metamask-eth-abis@^3.0.0":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@metamask/metamask-eth-abis/-/metamask-eth-abis-3.0.0.tgz#eccc0746b3ab1ab63000444403819c16e88b5272"
|
||||
integrity sha512-YtIl4e1VzqwwHGafuLIVPqbcWWWqQ0Ezo8/Ci5m5OGllqE2oTTx9iVHdUmXNkgCVD37SBfwn/fm/S1IGkM8BQA==
|
||||
|
Loading…
Reference in New Issue
Block a user