mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-21 17:37:01 +01:00
extract determineTransactionType from tx controller (#13737)
This commit is contained in:
parent
4bb3ba4aef
commit
9cea401022
@ -3,8 +3,8 @@ import { warn } from 'loglevel';
|
||||
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi';
|
||||
import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts';
|
||||
import { MINUTE } from '../../../shared/constants/time';
|
||||
import { isEqualCaseInsensitive } from '../../../ui/helpers/utils/util';
|
||||
import { MAINNET_CHAIN_ID } from '../../../shared/constants/network';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
|
||||
// By default, poll every 3 minutes
|
||||
const DEFAULT_INTERVAL = MINUTE * 3;
|
||||
|
@ -28,7 +28,7 @@ import {
|
||||
} from '../../../ui/pages/swaps/swaps.util';
|
||||
import fetchWithCache from '../../../ui/helpers/utils/fetch-with-cache';
|
||||
import { MINUTE, SECOND } from '../../../shared/constants/time';
|
||||
import { isEqualCaseInsensitive } from '../../../ui/helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
import { NETWORK_EVENTS } from './network';
|
||||
|
||||
// The MAX_GAS_LIMIT is a number that is higher than the maximum gas costs we have observed on any aggregator
|
||||
|
@ -3,10 +3,8 @@ import { ObservableStore } from '@metamask/obs-store';
|
||||
import { bufferToHex, keccak, toBuffer, isHexString } from 'ethereumjs-util';
|
||||
import EthQuery from 'ethjs-query';
|
||||
import { ethErrors } from 'eth-rpc-errors';
|
||||
import abi from 'human-standard-token-abi';
|
||||
import Common from '@ethereumjs/common';
|
||||
import { TransactionFactory } from '@ethereumjs/tx';
|
||||
import { ethers } from 'ethers';
|
||||
import NonceTracker from 'nonce-tracker';
|
||||
import log from 'loglevel';
|
||||
import BigNumber from 'bignumber.js';
|
||||
@ -47,16 +45,15 @@ import {
|
||||
NETWORK_TYPE_RPC,
|
||||
CHAIN_ID_TO_GAS_LIMIT_BUFFER_MAP,
|
||||
} from '../../../../shared/constants/network';
|
||||
import { isEIP1559Transaction } from '../../../../shared/modules/transaction.utils';
|
||||
import { readAddressAsContract } from '../../../../shared/modules/contract-utils';
|
||||
import { isEqualCaseInsensitive } from '../../../../ui/helpers/utils/util';
|
||||
import {
|
||||
determineTransactionType,
|
||||
isEIP1559Transaction,
|
||||
} from '../../../../shared/modules/transaction.utils';
|
||||
import TransactionStateManager from './tx-state-manager';
|
||||
import TxGasUtil from './tx-gas-utils';
|
||||
import PendingTransactionTracker from './pending-tx-tracker';
|
||||
import * as txUtils from './lib/util';
|
||||
|
||||
const hstInterface = new ethers.utils.Interface(abi);
|
||||
|
||||
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
|
||||
|
||||
const SWAP_TRANSACTION_TYPES = [
|
||||
@ -641,7 +638,7 @@ 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._determineTransactionType` after `generateTxMeta`.
|
||||
* method `determineTransactionType` after `generateTxMeta`.
|
||||
*/
|
||||
let txMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: normalizedTxParams,
|
||||
@ -669,8 +666,9 @@ export default class TransactionController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
const { type, getCodeResponse } = await this._determineTransactionType(
|
||||
const { type, getCodeResponse } = await determineTransactionType(
|
||||
txParams,
|
||||
this.query,
|
||||
);
|
||||
txMeta.type = transactionType || type;
|
||||
|
||||
@ -1726,67 +1724,6 @@ export default class TransactionController extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef { 'transfer' | 'approve' | 'transferfrom' | 'contractInteraction'| 'simpleSend' } 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 {
|
||||
name = data && hstInterface.parseTransaction({ data }).name;
|
||||
} catch (error) {
|
||||
log.debug('Failed to parse transaction data.', error, data);
|
||||
}
|
||||
|
||||
const tokenMethodName = [
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
|
||||
].find((methodName) => isEqualCaseInsensitive(methodName, name));
|
||||
|
||||
let result;
|
||||
if (data && tokenMethodName) {
|
||||
result = tokenMethodName;
|
||||
} else if (data && !to) {
|
||||
result = TRANSACTION_TYPES.DEPLOY_CONTRACT;
|
||||
}
|
||||
|
||||
let contractCode;
|
||||
|
||||
if (!result) {
|
||||
const {
|
||||
contractCode: resultCode,
|
||||
isContractAddress,
|
||||
} = await readAddressAsContract(this.query, to);
|
||||
|
||||
contractCode = resultCode;
|
||||
result = isContractAddress
|
||||
? TRANSACTION_TYPES.CONTRACT_INTERACTION
|
||||
: TRANSACTION_TYPES.SIMPLE_SEND;
|
||||
}
|
||||
|
||||
return { type: result, getCodeResponse: contractCode };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions
|
||||
* in the list have the same nonce
|
||||
|
@ -1305,156 +1305,6 @@ describe('Transaction Controller', function () {
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: null,
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.DEPLOY_CONTRACT,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: '0x',
|
||||
});
|
||||
});
|
||||
|
||||
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, {
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: null,
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
// by default, all accounts are external accounts (not contracts)
|
||||
eth_getCode: '0xa',
|
||||
};
|
||||
const _provider = createTestProviderTools({
|
||||
scaffold: _providerResultStub,
|
||||
}).provider;
|
||||
const _fromAccount = getTestAccounts()[0];
|
||||
const _blockTrackerStub = new EventEmitter();
|
||||
_blockTrackerStub.getCurrentBlock = noop;
|
||||
_blockTrackerStub.getLatestBlock = noop;
|
||||
const _txController = new TransactionController({
|
||||
provider: _provider,
|
||||
getGasPrice() {
|
||||
return '0xee6b2800';
|
||||
},
|
||||
networkStore: new ObservableStore(currentNetworkId),
|
||||
getCurrentChainId: () => currentChainId,
|
||||
txHistoryLimit: 10,
|
||||
blockTracker: _blockTrackerStub,
|
||||
signTransaction: (ethTx) =>
|
||||
new Promise((resolve) => {
|
||||
ethTx.sign(_fromAccount.key);
|
||||
resolve();
|
||||
}),
|
||||
getParticipateInMetrics: () => false,
|
||||
});
|
||||
const result = await _txController._determineTransactionType({
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
data: 'abd',
|
||||
});
|
||||
assert.deepEqual(result, {
|
||||
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
||||
getCodeResponse: '0x0a',
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
// by default, all accounts are external accounts (not contracts)
|
||||
eth_getCode: '0xa',
|
||||
};
|
||||
const _provider = createTestProviderTools({
|
||||
scaffold: _providerResultStub,
|
||||
}).provider;
|
||||
const _fromAccount = getTestAccounts()[0];
|
||||
const _blockTrackerStub = new EventEmitter();
|
||||
_blockTrackerStub.getCurrentBlock = noop;
|
||||
_blockTrackerStub.getLatestBlock = noop;
|
||||
const _txController = new TransactionController({
|
||||
provider: _provider,
|
||||
getGasPrice() {
|
||||
return '0xee6b2800';
|
||||
},
|
||||
networkStore: new ObservableStore(currentNetworkId),
|
||||
getCurrentChainId: () => currentChainId,
|
||||
txHistoryLimit: 10,
|
||||
blockTracker: _blockTrackerStub,
|
||||
signTransaction: (ethTx) =>
|
||||
new Promise((resolve) => {
|
||||
ethTx.sign(_fromAccount.key);
|
||||
resolve();
|
||||
}),
|
||||
getParticipateInMetrics: () => false,
|
||||
});
|
||||
const result = await _txController._determineTransactionType({
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
data: '',
|
||||
});
|
||||
assert.deepEqual(result, {
|
||||
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
||||
getCodeResponse: '0x0a',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPendingTransactions', function () {
|
||||
it('should show only submitted and approved transactions as pending transaction', function () {
|
||||
txController.txStateManager._addTransactionsToState([
|
||||
|
@ -82,7 +82,7 @@ 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 '../../ui/helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import ComposableObservableStore from './lib/ComposableObservableStore';
|
||||
import AccountTracker from './lib/account-tracker';
|
||||
import createLoggerMiddleware from './lib/createLoggerMiddleware';
|
||||
|
6
shared/modules/string-utils.js
Normal file
6
shared/modules/string-utils.js
Normal file
@ -0,0 +1,6 @@
|
||||
export function isEqualCaseInsensitive(value1, value2) {
|
||||
if (typeof value1 !== 'string' || typeof value2 !== 'string') {
|
||||
return false;
|
||||
}
|
||||
return value1.toLowerCase() === value2.toLowerCase();
|
||||
}
|
@ -1,4 +1,24 @@
|
||||
import { isHexString } from 'ethereumjs-util';
|
||||
import { ethers } from 'ethers';
|
||||
import abi from 'human-standard-token-abi';
|
||||
import log from 'loglevel';
|
||||
import { TRANSACTION_TYPES } from '../constants/transaction';
|
||||
import { readAddressAsContract } from './contract-utils';
|
||||
import { isEqualCaseInsensitive } from './string-utils';
|
||||
|
||||
/**
|
||||
* @typedef { 'transfer' | 'approve' | 'transferfrom' | 'contractInteraction'| 'simpleSend' } 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
|
||||
*/
|
||||
|
||||
const hstInterface = new ethers.utils.Interface(abi);
|
||||
|
||||
export function transactionMatchesNetwork(transaction, chainId, networkId) {
|
||||
if (typeof transaction.chainId !== 'undefined') {
|
||||
@ -61,3 +81,53 @@ export function txParamsAreDappSuggested(transaction) {
|
||||
transaction?.dappSuggestedGasFees?.maxFeePerGas === maxFeePerGas)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param {EthQuery} query - EthQuery instance
|
||||
* @returns {InferTransactionTypeResult}
|
||||
*/
|
||||
export async function determineTransactionType(txParams, query) {
|
||||
const { data, to } = txParams;
|
||||
let name;
|
||||
try {
|
||||
name = data && hstInterface.parseTransaction({ data }).name;
|
||||
} catch (error) {
|
||||
log.debug('Failed to parse transaction data.', error, data);
|
||||
}
|
||||
|
||||
const tokenMethodName = [
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
|
||||
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
|
||||
].find((methodName) => isEqualCaseInsensitive(methodName, name));
|
||||
|
||||
let result;
|
||||
if (data && tokenMethodName) {
|
||||
result = tokenMethodName;
|
||||
} else if (data && !to) {
|
||||
result = TRANSACTION_TYPES.DEPLOY_CONTRACT;
|
||||
}
|
||||
|
||||
let contractCode;
|
||||
|
||||
if (!result) {
|
||||
const {
|
||||
contractCode: resultCode,
|
||||
isContractAddress,
|
||||
} = await readAddressAsContract(query, to);
|
||||
|
||||
contractCode = resultCode;
|
||||
result = isContractAddress
|
||||
? TRANSACTION_TYPES.CONTRACT_INTERACTION
|
||||
: TRANSACTION_TYPES.SIMPLE_SEND;
|
||||
}
|
||||
|
||||
return { type: result, getCodeResponse: contractCode };
|
||||
}
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { isEIP1559Transaction, isLegacyTransaction } from './transaction.utils';
|
||||
import EthQuery from 'ethjs-query';
|
||||
import { createTestProviderTools } from '../../test/stub/provider';
|
||||
import { TRANSACTION_TYPES } from '../constants/transaction';
|
||||
import {
|
||||
determineTransactionType,
|
||||
isEIP1559Transaction,
|
||||
isLegacyTransaction,
|
||||
} from './transaction.utils';
|
||||
|
||||
describe('Transaction.utils', function () {
|
||||
describe('isEIP1559Transaction', function () {
|
||||
@ -80,4 +87,143 @@ describe('Transaction.utils', function () {
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('determineTransactionType', function () {
|
||||
const genericProvider = createTestProviderTools().provider;
|
||||
const query = new EthQuery(genericProvider);
|
||||
|
||||
it('should return a simple send type when to is truthy but data is falsy', async function () {
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '0xabc',
|
||||
data: '',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: null,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a token transfer type when data is for the respective method call', async function () {
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '0xabc',
|
||||
data:
|
||||
'0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a token approve type when data is for the respective method call', async function () {
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '0xabc',
|
||||
data:
|
||||
'0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a contract deployment type when to is falsy and there is data', async function () {
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '',
|
||||
data: '0xabd',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.DEPLOY_CONTRACT,
|
||||
getCodeResponse: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
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 determineTransactionType(
|
||||
{
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
data: '0xabd',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: '0x',
|
||||
});
|
||||
});
|
||||
|
||||
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 determineTransactionType(
|
||||
{
|
||||
to: '0xabc',
|
||||
data: '0xabd',
|
||||
},
|
||||
query,
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||
getCodeResponse: null,
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
// by default, all accounts are external accounts (not contracts)
|
||||
eth_getCode: '0xa',
|
||||
};
|
||||
const _provider = createTestProviderTools({
|
||||
scaffold: _providerResultStub,
|
||||
}).provider;
|
||||
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
data: 'abd',
|
||||
},
|
||||
new EthQuery(_provider),
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
||||
getCodeResponse: '0x0a',
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
// by default, all accounts are external accounts (not contracts)
|
||||
eth_getCode: '0xa',
|
||||
};
|
||||
const _provider = createTestProviderTools({
|
||||
scaffold: _providerResultStub,
|
||||
}).provider;
|
||||
|
||||
const result = await determineTransactionType(
|
||||
{
|
||||
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
|
||||
data: '',
|
||||
},
|
||||
new EthQuery(_provider),
|
||||
);
|
||||
expect(result).toMatchObject({
|
||||
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
||||
getCodeResponse: '0x0a',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -18,11 +18,7 @@ import {
|
||||
BLOCK_SIZES,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import {
|
||||
getAssetImageURL,
|
||||
isEqualCaseInsensitive,
|
||||
shortenAddress,
|
||||
} from '../../../helpers/utils/util';
|
||||
import { getAssetImageURL, shortenAddress } from '../../../helpers/utils/util';
|
||||
import {
|
||||
getCurrentChainId,
|
||||
getIpfsGateway,
|
||||
@ -54,6 +50,7 @@ import InfoTooltip from '../../ui/info-tooltip';
|
||||
import { ERC721 } from '../../../helpers/constants/common';
|
||||
import { usePrevious } from '../../../hooks/usePrevious';
|
||||
import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
|
||||
export default function CollectibleDetails({ collectible }) {
|
||||
const {
|
||||
|
@ -13,7 +13,7 @@ import Button from '../../ui/button';
|
||||
import { TOKEN_CATEGORY_HASH } from '../../../helpers/constants/transactions';
|
||||
import { SWAPS_CHAINID_CONTRACT_ADDRESS_MAP } from '../../../../shared/constants/swaps';
|
||||
import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction';
|
||||
import { isEqualCaseInsensitive } from '../../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
|
||||
const PAGE_INCREMENT = 10;
|
||||
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
|
||||
import { conversionUtil } from '../../../shared/modules/conversion.utils';
|
||||
import { getAveragePriceEstimateInHexWEI } from '../../selectors/custom-gas';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
|
||||
// Actions
|
||||
const createActionType = (action) => `metamask/confirm-transaction/${action}`;
|
||||
|
@ -14,9 +14,9 @@ import {
|
||||
import { updateTransaction } from '../../store/actions';
|
||||
import { setCustomGasLimit, setCustomGasPrice } from '../gas/gas.duck';
|
||||
import { decGWEIToHexWEI } from '../../helpers/utils/conversions.util';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
|
||||
import { KEYRING_TYPES } from '../../../shared/constants/hardware-wallets';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
|
||||
export default function reduceMetamask(state = {}, action) {
|
||||
const metamaskState = {
|
||||
|
@ -78,7 +78,6 @@ import {
|
||||
isDefaultMetaMaskChain,
|
||||
isOriginContractAddress,
|
||||
isValidDomainName,
|
||||
isEqualCaseInsensitive,
|
||||
} from '../../helpers/utils/util';
|
||||
import {
|
||||
getGasEstimateType,
|
||||
@ -102,6 +101,7 @@ import {
|
||||
import { TRANSACTION_ENVELOPE_TYPES } from '../../../shared/constants/transaction';
|
||||
import { readAddressAsContract } from '../../../shared/modules/contract-utils';
|
||||
import { INVALID_ASSET_TYPE } from '../../helpers/constants/error-keys';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
// typedefs
|
||||
/**
|
||||
* @typedef {import('@reduxjs/toolkit').PayloadAction} PayloadAction
|
||||
|
@ -65,14 +65,6 @@ export function isDefaultMetaMaskChain(chainId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Both inputs should be strings. This method is currently used to compare tokenAddress hex strings.
|
||||
export function isEqualCaseInsensitive(value1, value2) {
|
||||
if (typeof value1 !== 'string' || typeof value2 !== 'string') {
|
||||
return false;
|
||||
}
|
||||
return value1.toLowerCase() === value2.toLowerCase();
|
||||
}
|
||||
|
||||
export function valuesFor(obj) {
|
||||
if (!obj) {
|
||||
return [];
|
||||
|
@ -3,11 +3,11 @@ import { useRouteMatch } from 'react-router-dom';
|
||||
import { getTokens } from '../ducks/metamask/metamask';
|
||||
import { getCurrentChainId } from '../selectors';
|
||||
import { ASSET_ROUTE } from '../helpers/constants/routes';
|
||||
import { isEqualCaseInsensitive } from '../helpers/utils/util';
|
||||
import {
|
||||
SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
|
||||
ETH_SWAPS_TOKEN_OBJECT,
|
||||
} from '../../shared/constants/swaps';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
|
||||
/**
|
||||
* Returns a token object for the asset that is currently being viewed.
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
} from '../selectors';
|
||||
import { getTokenFiatAmount } from '../helpers/utils/token-util';
|
||||
import { getConversionRate } from '../ducks/metamask/metamask';
|
||||
import { isEqualCaseInsensitive } from '../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
|
||||
/**
|
||||
* Get the token balance converted to fiat and formatted for display
|
||||
|
@ -3,7 +3,7 @@ import TokenTracker from '@metamask/eth-token-tracker';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { getCurrentChainId, getSelectedAddress } from '../selectors';
|
||||
import { SECOND } from '../../shared/constants/time';
|
||||
import { isEqualCaseInsensitive } from '../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import { useEqualityCheck } from './useEqualityCheck';
|
||||
|
||||
export function useTokenTracker(
|
||||
|
@ -11,7 +11,6 @@ import {
|
||||
getTokenValueParam,
|
||||
} from '../helpers/utils/token-util';
|
||||
import {
|
||||
isEqualCaseInsensitive,
|
||||
formatDateWithYearContext,
|
||||
shortenAddress,
|
||||
stripHttpSchemes,
|
||||
@ -28,6 +27,7 @@ import {
|
||||
TRANSACTION_STATUSES,
|
||||
} from '../../shared/constants/transaction';
|
||||
import { captureSingleException } from '../store/actions';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import { useI18nContext } from './useI18nContext';
|
||||
import { useTokenFiatAmount } from './useTokenFiatAmount';
|
||||
import { useUserPreferencedCurrency } from './useUserPreferencedCurrency';
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Redirect, useParams } from 'react-router-dom';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
import CollectibleDetails from '../../components/app/collectible-details/collectible-details';
|
||||
import { getCollectibles, getTokens } from '../../ducks/metamask/metamask';
|
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
|
||||
import NativeAsset from './components/native-asset';
|
||||
import TokenAsset from './components/token-asset';
|
||||
|
@ -7,7 +7,7 @@ import TokenBalance from '../../components/ui/token-balance';
|
||||
import { I18nContext } from '../../contexts/i18n';
|
||||
import { MetaMetricsContext } from '../../contexts/metametrics';
|
||||
import ZENDESK_URLS from '../../helpers/constants/zendesk-url';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
|
||||
function getTokenName(name, symbol) {
|
||||
return typeof name === 'undefined' ? symbol : `${name} (${symbol})`;
|
||||
|
@ -43,7 +43,7 @@ import AdvancedGasFeePopover from '../../components/app/advanced-gas-fee-popover
|
||||
import EditGasFeePopover from '../../components/app/edit-gas-fee-popover';
|
||||
import EditGasPopover from '../../components/app/edit-gas-popover/edit-gas-popover.component';
|
||||
import Loading from '../../components/ui/loading-screen';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
import { getCustomTxParamsData } from './confirm-approve.util';
|
||||
import ConfirmApproveContent from './confirm-approve-content';
|
||||
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
getTokenValueParam,
|
||||
} from '../../helpers/utils/token-util';
|
||||
import { hexWEIToDecETH } from '../../helpers/utils/conversions.util';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
import ConfirmTokenTransactionBase from './confirm-token-transaction-base.component';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
|
@ -14,11 +14,7 @@ import {
|
||||
setDefaultHomeActiveTabName,
|
||||
} from '../../store/actions';
|
||||
import { isBalanceSufficient, calcGasTotal } from '../send/send.utils';
|
||||
import {
|
||||
isEqualCaseInsensitive,
|
||||
shortenAddress,
|
||||
valuesFor,
|
||||
} from '../../helpers/utils/util';
|
||||
import { shortenAddress, valuesFor } from '../../helpers/utils/util';
|
||||
import {
|
||||
getAdvancedInlineGasShown,
|
||||
getCustomNonceValue,
|
||||
@ -55,6 +51,7 @@ import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
|
||||
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 ConfirmTransactionBase from './confirm-transaction-base.component';
|
||||
|
||||
let customNonceValue = '';
|
||||
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import Fuse from 'fuse.js';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
import TextField from '../../../components/ui/text-field';
|
||||
import { isEqualCaseInsensitive } from '../../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
|
||||
export default class TokenSearch extends Component {
|
||||
static contextTypes = {
|
||||
|
@ -7,7 +7,7 @@ import TokenListDisplay from '../../../../components/app/token-list-display';
|
||||
import UserPreferencedCurrencyDisplay from '../../../../components/app/user-preferenced-currency-display';
|
||||
import { ERC20, ERC721, PRIMARY } from '../../../../helpers/constants/common';
|
||||
import { ASSET_TYPES } from '../../../../ducks/send';
|
||||
import { isEqualCaseInsensitive } from '../../../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../../../shared/modules/string-utils';
|
||||
|
||||
export default class SendAssetRow extends Component {
|
||||
static propTypes = {
|
||||
|
@ -3,9 +3,9 @@ import PropTypes from 'prop-types';
|
||||
import Fuse from 'fuse.js';
|
||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
||||
import TextField from '../../../components/ui/text-field';
|
||||
import { isEqualCaseInsensitive } from '../../../helpers/utils/util';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import SearchIcon from '../../../components/ui/search-icon';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
|
||||
export default function SettingsSearch({
|
||||
onSearch,
|
||||
|
@ -77,10 +77,7 @@ import {
|
||||
hexToDecimal,
|
||||
} from '../../../helpers/utils/conversions.util';
|
||||
import { calcTokenAmount } from '../../../helpers/utils/token-util';
|
||||
import {
|
||||
getURLHostName,
|
||||
isEqualCaseInsensitive,
|
||||
} from '../../../helpers/utils/util';
|
||||
import { getURLHostName } from '../../../helpers/utils/util';
|
||||
import { usePrevious } from '../../../hooks/usePrevious';
|
||||
import { useTokenTracker } from '../../../hooks/useTokenTracker';
|
||||
import { useTokenFiatAmount } from '../../../hooks/useTokenFiatAmount';
|
||||
@ -110,6 +107,7 @@ import {
|
||||
shouldEnableDirectWrapping,
|
||||
} from '../swaps.util';
|
||||
import SwapsFooter from '../swaps-footer';
|
||||
import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils';
|
||||
|
||||
const fuseSearchKeys = [
|
||||
{ name: 'name', weight: 0.499 },
|
||||
|
@ -59,10 +59,7 @@ import {
|
||||
} from '../../../selectors';
|
||||
import { getNativeCurrency, getTokens } from '../../../ducks/metamask/metamask';
|
||||
|
||||
import {
|
||||
toPrecisionWithoutTrailingZeros,
|
||||
isEqualCaseInsensitive,
|
||||
} from '../../../helpers/utils/util';
|
||||
import { toPrecisionWithoutTrailingZeros } from '../../../helpers/utils/util';
|
||||
|
||||
import {
|
||||
safeRefetchQuotes,
|
||||
@ -115,6 +112,7 @@ import CountdownTimer from '../countdown-timer';
|
||||
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 ViewQuotePriceDifference from './view-quote-price-difference';
|
||||
|
||||
let intervalId;
|
||||
|
@ -4,7 +4,6 @@ import { Redirect, useHistory, useParams } from 'react-router-dom';
|
||||
import { getTokens } from '../../ducks/metamask/metamask';
|
||||
import { getUseTokenDetection, getTokenList } from '../../selectors';
|
||||
import { useCopyToClipboard } from '../../hooks/useCopyToClipboard';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import Identicon from '../../components/ui/identicon';
|
||||
import { I18nContext } from '../../contexts/i18n';
|
||||
import { useTokenTracker } from '../../hooks/useTokenTracker';
|
||||
@ -25,6 +24,7 @@ import {
|
||||
TEXT_ALIGN,
|
||||
OVERFLOW_WRAP,
|
||||
} from '../../helpers/constants/design-system';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
|
||||
export default function TokenDetailsPage() {
|
||||
const dispatch = useDispatch();
|
||||
|
@ -3,7 +3,7 @@ import configureMockStore from 'redux-mock-store';
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import { renderWithProvider } from '../../../test/lib/render-helpers';
|
||||
import Identicon from '../../components/ui/identicon/identicon.component';
|
||||
import { isEqualCaseInsensitive } from '../../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
|
||||
import TokenDetailsPage from './token-details-page';
|
||||
|
||||
const testTokenAddress = '0xaD6D458402F60fD3Bd25163575031ACDce07538A';
|
||||
|
@ -25,7 +25,7 @@ import {
|
||||
getMaximumGasTotalInHexWei,
|
||||
getMinimumGasTotalInHexWei,
|
||||
} from '../../shared/modules/gas.utils';
|
||||
import { isEqualCaseInsensitive } from '../helpers/utils/util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import { getAveragePriceEstimateInHexWEI } from './custom-gas';
|
||||
import { getCurrentChainId, deprecatedGetCurrentNetworkId } from './selectors';
|
||||
import { checkNetworkAndAccountSupports1559 } from '.';
|
||||
|
@ -33,11 +33,7 @@ import {
|
||||
ALLOWED_SWAPS_CHAIN_IDS,
|
||||
} from '../../shared/constants/swaps';
|
||||
|
||||
import {
|
||||
shortenAddress,
|
||||
getAccountByAddress,
|
||||
isEqualCaseInsensitive,
|
||||
} from '../helpers/utils/util';
|
||||
import { shortenAddress, getAccountByAddress } from '../helpers/utils/util';
|
||||
import {
|
||||
getValueFromWeiHex,
|
||||
hexToDecimal,
|
||||
@ -60,6 +56,7 @@ import {
|
||||
getLedgerWebHidConnectedStatus,
|
||||
getLedgerTransportStatus,
|
||||
} from '../ducks/app/app';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
|
||||
/**
|
||||
* One of the only remaining valid uses of selecting the network subkey of the
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
} from '../helpers/utils/i18n-helper';
|
||||
import { getMethodDataAsync } from '../helpers/utils/transactions.util';
|
||||
import { getSymbolAndDecimals } from '../helpers/utils/token-util';
|
||||
import { isEqualCaseInsensitive } from '../helpers/utils/util';
|
||||
import switchDirection from '../helpers/utils/switch-direction';
|
||||
import {
|
||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||
@ -35,6 +34,7 @@ import {
|
||||
LEDGER_USB_VENDOR_ID,
|
||||
} from '../../shared/constants/hardware-wallets';
|
||||
import { parseSmartTransactionsError } from '../pages/swaps/swaps.util';
|
||||
import { isEqualCaseInsensitive } from '../../shared/modules/string-utils';
|
||||
import * as actionConstants from './actionConstants';
|
||||
|
||||
let background = null;
|
||||
|
Loading…
Reference in New Issue
Block a user