1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/app/scripts/controllers/transactions/index.test.js

3471 lines
108 KiB
JavaScript
Raw Permalink Normal View History

/* eslint-disable prefer-promise-reject-errors */
import { strict as assert } from 'assert';
import EventEmitter from 'events';
2021-04-16 17:05:13 +02:00
import { toBuffer } from 'ethereumjs-util';
import { TransactionFactory } from '@ethereumjs/tx';
import { ObservableStore } from '@metamask/obs-store';
2023-05-10 07:36:01 +02:00
import { ApprovalType } from '@metamask/controller-utils';
import sinon from 'sinon';
import { errorCodes, ethErrors } from 'eth-rpc-errors';
import {
BlockaidReason,
BlockaidResultType,
} from '../../../../shared/constants/security-provider';
2020-11-03 00:41:28 +01:00
import {
createTestProviderTools,
getTestAccounts,
} from '../../../../test/stub/provider';
import mockEstimates from '../../../../test/data/mock-estimates.json';
import {
MetaMetricsEventCategory,
MetaMetricsTransactionEventSource,
} from '../../../../shared/constants/metametrics';
import {
TransactionStatus,
TransactionType,
TransactionEnvelopeType,
TransactionMetaMetricsEvent,
AssetType,
TokenStandard,
} from '../../../../shared/constants/transaction';
import {
GasEstimateTypes,
GasRecommendations,
} from '../../../../shared/constants/gas';
2023-05-10 07:36:01 +02:00
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
import { NetworkStatus } from '../../../../shared/constants/network';
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../shared/lib/transactions-controller-utils';
import TxGasUtil from './tx-gas-utils';
import * as IncomingTransactionHelperClass from './IncomingTransactionHelper';
import TransactionController from '.';
const noop = () => true;
const currentNetworkId = '5';
const currentChainId = '0x5';
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
const currentNetworkStatus = NetworkStatus.Available;
const providerConfig = {
type: 'goerli',
};
const actionId = 'DUMMY_ACTION_ID';
const VALID_ADDRESS = '0x0000000000000000000000000000000000000000';
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
const TRANSACTION_META_MOCK = {
hash: '0x1',
id: 1,
status: TransactionStatus.confirmed,
time: 123456789,
txParams: {
from: VALID_ADDRESS,
},
};
async function flushPromises() {
await new Promise((resolve) => setImmediate(resolve));
}
2017-08-02 17:34:45 +02:00
describe('Transaction Controller', function () {
let txController,
provider,
providerResultStub,
fromAccount,
fragmentExists,
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
networkStatusStore,
preferencesStore,
getCurrentChainId,
messengerMock,
resultCallbacksMock,
updateSpy,
incomingTransactionHelperClassMock,
incomingTransactionHelperEventMock;
2017-05-04 23:35:10 +02:00
beforeEach(function () {
fragmentExists = false;
providerResultStub = {
// 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000',
// by default, all accounts are external accounts (not contracts)
eth_getCode: '0x',
eth_sendRawTransaction:
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8',
};
provider = createTestProviderTools({
scaffold: providerResultStub,
networkId: currentNetworkId,
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
chainId: parseInt(currentChainId, 16),
}).provider;
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
networkStatusStore = new ObservableStore(currentNetworkStatus);
preferencesStore = new ObservableStore({ advancedGasFee: {} });
fromAccount = getTestAccounts()[0];
const blockTrackerStub = new EventEmitter();
blockTrackerStub.getCurrentBlock = noop;
blockTrackerStub.getLatestBlock = noop;
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
getCurrentChainId = sinon.stub().callsFake(() => currentChainId);
resultCallbacksMock = {
success: sinon.spy(),
error: sinon.spy(),
};
messengerMock = {
call: sinon.stub(),
};
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
incomingTransactionHelperEventMock = sinon.spy();
incomingTransactionHelperClassMock = sinon
.stub(IncomingTransactionHelperClass, 'IncomingTransactionHelper')
.returns({
hub: {
on: incomingTransactionHelperEventMock,
},
});
2017-05-16 19:27:41 +02:00
txController = new TransactionController({
2017-08-09 00:30:22 +02:00
provider,
2020-11-03 00:41:28 +01:00
getGasPrice() {
return '0xee6b2800';
},
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
getNetworkId: () => currentNetworkId,
getNetworkStatus: () => networkStatusStore.getState(),
onNetworkStateChange: (listener) =>
networkStatusStore.subscribe(listener),
getCurrentNetworkEIP1559Compatibility: () => Promise.resolve(false),
getCurrentAccountEIP1559Compatibility: () => false,
2016-12-16 19:33:36 +01:00
txHistoryLimit: 10,
blockTracker: blockTrackerStub,
2020-11-03 00:41:28 +01:00
signTransaction: (ethTx) =>
new Promise((resolve) => {
resolve(ethTx.sign(fromAccount.key));
2020-11-03 00:41:28 +01:00
}),
getProviderConfig: () => providerConfig,
getPermittedAccounts: () => undefined,
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
getCurrentChainId,
getParticipateInMetrics: () => false,
trackMetaMetricsEvent: () => undefined,
createEventFragment: () => undefined,
updateEventFragment: () => undefined,
finalizeEventFragment: () => undefined,
getEventFragmentById: () =>
fragmentExists === false ? undefined : { id: 0 },
getEIP1559GasFeeEstimates: () => undefined,
getAccountType: () => 'MetaMask',
getDeviceModel: () => 'N/A',
securityProviderRequest: () => undefined,
preferencesStore,
messenger: messengerMock,
});
2020-11-03 00:41:28 +01:00
txController.nonceTracker.getNonceLock = () =>
Promise.resolve({ nextNonce: 0, releaseLock: noop });
updateSpy = sinon.spy(txController.txStateManager, 'updateTransaction');
messengerMock.call.callsFake((_) =>
Promise.resolve({
value: { txMeta: getLastTxMeta() },
resultCallbacks: resultCallbacksMock,
}),
);
});
afterEach(function () {
incomingTransactionHelperClassMock.restore();
});
function getLastTxMeta() {
return updateSpy.lastCall.args[0];
}
describe('#getState', function () {
it('should return a state object with the right keys and data types', function () {
const exposedState = txController.getState();
2020-11-03 00:41:28 +01:00
assert.ok(
'transactions' in exposedState,
'state should have the key transactions',
);
assert.ok(Array.isArray(exposedState.transactions), 'should be an array');
});
});
describe('#getUnapprovedTxCount', function () {
it('should return the number of unapproved txs', function () {
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 2,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 3,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
]);
const unapprovedTxCount = txController.getUnapprovedTxCount();
assert.equal(unapprovedTxCount, 3, 'should be 3');
});
});
2017-09-13 23:07:22 +02:00
describe('#getPendingTxCount', function () {
it('should return the number of pending txs', function () {
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 2,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 3,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
]);
const pendingTxCount = txController.getPendingTxCount();
assert.equal(pendingTxCount, 3, 'should be 3');
});
});
2017-09-13 23:07:22 +02:00
2017-09-23 01:15:18 +02:00
describe('#getConfirmedTransactions', function () {
it('should return the number of confirmed txs', function () {
const address = '0xc684832530fcbddae4b4230a47e991ddcec2831d';
2017-09-23 01:15:18 +02:00
const txParams = {
2020-11-03 00:41:28 +01:00
from: address,
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
};
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 0,
status: TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 1,
status: TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 2,
status: TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 3,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 4,
status: TransactionStatus.rejected,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 5,
status: TransactionStatus.approved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 6,
status: TransactionStatus.signed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 7,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
{
id: 8,
status: TransactionStatus.failed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
]);
2020-11-03 00:41:28 +01:00
assert.equal(
txController.nonceTracker.getConfirmedTransactions(address).length,
3,
);
});
});
2017-09-23 01:15:18 +02:00
describe('#addTransaction', function () {
const selectedAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d';
const recipientAddress = '0xc684832530fcbddae4b4230a47e991ddcec2831d';
let txMeta,
txParams,
getPermittedAccounts,
signStub,
getSelectedAddress,
getDefaultGasFees;
beforeEach(function () {
txParams = {
from: selectedAddress,
to: recipientAddress,
};
txMeta = {
status: TransactionStatus.unapproved,
id: 1,
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
};
txController.txStateManager._addTransactionsToState([txMeta]);
getPermittedAccounts = sinon
.stub(txController, 'getPermittedAccounts')
.returns([txParams.from]);
2020-11-03 00:41:28 +01:00
getSelectedAddress = sinon
.stub(txController, 'getSelectedAddress')
.returns(selectedAddress);
getDefaultGasFees = sinon
.stub(txController, '_getDefaultGasFees')
.returns({});
});
afterEach(function () {
txController.txStateManager._addTransactionsToState([]);
getPermittedAccounts.restore();
signStub?.restore();
getSelectedAddress.restore();
getDefaultGasFees.restore();
});
2018-01-14 23:01:37 +01:00
it('adds an unapproved transaction and returns transaction metadata', async function () {
({ transactionMeta: txMeta } = await txController.addTransaction({
2020-11-03 00:41:28 +01:00
from: selectedAddress,
to: recipientAddress,
}));
assert.ok('id' in txMeta, 'should have a id');
assert.ok('time' in txMeta, 'should have a time stamp');
2020-11-03 00:41:28 +01:00
assert.ok(
'metamaskNetworkId' in txMeta,
'should have a metamaskNetworkId',
);
assert.ok('txParams' in txMeta, 'should have a txParams');
assert.ok('history' in txMeta, 'should have a history');
2020-11-03 00:41:28 +01:00
assert.equal(
txMeta.txParams.value,
'0x0',
'should have added 0x0 as the value',
);
const memTxMeta = txController.txStateManager.getTransaction(txMeta.id);
assert.deepEqual(txMeta, memTxMeta);
});
2018-01-14 23:01:37 +01:00
it('creates an approval request', async function () {
await txController.addTransaction(txParams);
const txId = getLastTxMeta().id;
assert.equal(messengerMock.call.callCount, 1);
assert.deepEqual(messengerMock.call.getCall(0).args, [
'ApprovalController:addRequest',
{
id: String(txId),
origin: undefined,
requestData: { txId },
type: ApprovalType.Transaction,
expectsResult: true,
},
true, // Show popup
]);
});
it('throws if the from address is not the selected address', async function () {
2020-11-03 00:41:28 +01:00
await assert.rejects(() =>
txController.addTransaction({
2020-11-03 00:41:28 +01:00
from: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2',
}),
);
});
it('throws if the network status is not available', async function () {
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
networkStatusStore.putState(NetworkStatus.Unknown);
await assert.rejects(
2020-11-03 00:41:28 +01:00
() =>
txController.addTransaction({
2020-11-03 00:41:28 +01:00
from: selectedAddress,
to: '0x0d1d4e623D10F9FBA5Db95830F7d3839406C6AF2',
}),
{ message: 'MetaMask is having trouble connecting to the network' },
);
});
it('updates meta if type is swap approval', async function () {
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
type: TransactionType.swapApproval,
actionId: '12345',
swaps: { meta: { type: 'swapApproval', sourceTokenSymbol: 'XBN' } },
},
);
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.type, 'swapApproval');
assert.equal(transaction.sourceTokenSymbol, 'XBN');
});
it('updates meta if type is swap', async function () {
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
type: TransactionType.swap,
actionId: '12345',
swaps: {
meta: {
sourceTokenSymbol: 'BTCX',
destinationTokenSymbol: 'ETH',
type: 'swapped',
destinationTokenDecimals: 8,
destinationTokenAddress: VALID_ADDRESS_TWO,
swapTokenValue: '0x0077',
},
},
},
);
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.sourceTokenSymbol, 'BTCX');
assert.equal(transaction.destinationTokenSymbol, 'ETH');
assert.equal(transaction.type, 'swapped');
assert.equal(transaction.destinationTokenDecimals, 8);
assert.equal(transaction.destinationTokenAddress, VALID_ADDRESS_TWO);
assert.equal(transaction.swapTokenValue, '0x0077');
});
describe('if swaps trade with no approval transaction and simulation fails', function () {
let analyzeGasUsageOriginal;
beforeEach(function () {
analyzeGasUsageOriginal = TxGasUtil.prototype.analyzeGasUsage;
sinon.stub(TxGasUtil.prototype, 'analyzeGasUsage').returns({
simulationFails: true,
});
});
afterEach(function () {
// Sinon restore didn't work
TxGasUtil.prototype.analyzeGasUsage = analyzeGasUsageOriginal;
});
it('throws error', async function () {
await assert.rejects(
txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
type: TransactionType.swap,
actionId: '12345',
swaps: {
hasApproveTx: false,
},
},
),
new Error('Simulation failed'),
);
});
it('cancels transaction', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
try {
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
type: TransactionType.swap,
actionId: '12345',
swaps: {
hasApproveTx: false,
},
},
);
} catch (error) {
// Expected error
}
assert.equal(listener.callCount, 1, listener.args);
const [txId, status] = listener.args[0];
assert.equal(status, TransactionStatus.rejected);
assert.equal(txId, getLastTxMeta().id);
});
});
describe('with actionId', function () {
it('adds single unapproved transaction when called twice with same actionId', async function () {
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ actionId: '12345' },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ actionId: '12345' },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1, transactionCount2);
});
it('adds single approval request when called twice with same actionId', async function () {
await txController.addTransaction(txParams, { actionId: '12345' });
await txController.addTransaction(txParams, { actionId: '12345' });
const txId = getLastTxMeta().id;
assert.equal(messengerMock.call.callCount, 1);
assert.deepEqual(messengerMock.call.getCall(0).args, [
'ApprovalController:addRequest',
{
id: String(txId),
origin: undefined,
requestData: { txId },
type: ApprovalType.Transaction,
expectsResult: true,
},
true, // Show popup
]);
});
it('adds multiple transactions when called with different actionId', async function () {
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ actionId: '12345' },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ actionId: '00000' },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1 + 1, transactionCount2);
});
it('resolves second result when first transaction is finished', async function () {
let firstTransactionResolve;
let firstTransactionCompleted = false;
let secondTransactionCompleted = false;
messengerMock.call.returns(
new Promise((resolve) => {
firstTransactionResolve = resolve;
}),
);
const { result: firstResult } = await txController.addTransaction(
txParams,
{ actionId: '12345' },
);
firstResult.then(() => {
firstTransactionCompleted = true;
});
const { result: secondResult } = await txController.addTransaction(
txParams,
{ actionId: '12345' },
);
secondResult.then(() => {
secondTransactionCompleted = true;
});
await flushPromises();
assert.equal(firstTransactionCompleted, false);
assert.equal(secondTransactionCompleted, false);
firstTransactionResolve({ value: { txMeta: getLastTxMeta() } });
await flushPromises();
await firstResult;
await secondResult;
assert.equal(firstTransactionCompleted, true);
assert.equal(secondTransactionCompleted, true);
});
});
describe('on success', function () {
it('resolves result with the transaction hash', async function () {
const { result } = await txController.addTransaction(txParams);
const hash = await result;
assert.ok(hash, 'addTransaction needs to return the hash');
});
it('changes status to submitted', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await result;
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.status, TransactionStatus.submitted);
});
it('emits approved, signed, and submitted status events', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await result;
const txId = getLastTxMeta().id;
assert.equal(listener.callCount, 3);
assert.equal(listener.args[0][0], txId);
assert.equal(listener.args[0][1], TransactionStatus.approved);
assert.equal(listener.args[1][0], txId);
assert.equal(listener.args[1][1], TransactionStatus.signed);
assert.equal(listener.args[2][0], txId);
assert.equal(listener.args[2][1], TransactionStatus.submitted);
});
it('reports success to approval request acceptor', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await result;
assert.equal(resultCallbacksMock.success.callCount, 1);
});
it('does not overwrite set values', async function () {
const originalValue = '0x01';
const wrongValue = '0x05';
providerResultStub.eth_gasPrice = wrongValue;
providerResultStub.eth_estimateGas = '0x5209';
signStub = sinon
.stub(txController, '_signTransaction')
.callsFake(() => Promise.resolve());
const pubStub = sinon
.stub(txController, '_publishTransaction')
.callsFake(() => {
const txId = getLastTxMeta().id;
txController.setTxHash(txId, originalValue);
txController.txStateManager.setTxStatusSubmitted(txId);
});
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
nonce: originalValue,
gas: originalValue,
gasPrice: originalValue,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await result;
const txId = getLastTxMeta().id;
const finalMeta = txController.txStateManager.getTransaction(txId);
const params = finalMeta.txParams;
assert.equal(params.gas, originalValue, 'gas unmodified');
assert.equal(params.gasPrice, originalValue, 'gas price unmodified');
assert.equal(finalMeta.hash, originalValue);
assert.equal(
finalMeta.status,
TransactionStatus.submitted,
'should have reached the submitted status.',
);
signStub.restore();
pubStub.restore();
});
});
describe('on cancel', function () {
beforeEach(async function () {
messengerMock.call.returns(
Promise.reject({ code: errorCodes.provider.userRejectedRequest }),
);
});
it('rejects result', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await assert.rejects(result, {
code: ethErrors.provider.userRejectedRequest().code,
message: 'MetaMask Tx Signature: User denied transaction signature.',
});
});
it('emits rejected status event', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionid: '12345' },
);
try {
await result;
} catch (error) {
// Expected error
}
assert.equal(listener.callCount, 1);
const [txId, status] = listener.args[0];
assert.equal(status, TransactionStatus.rejected);
assert.equal(txId, getLastTxMeta().id);
});
});
describe('on signing error', function () {
const signError = new Error('TestSignError');
beforeEach(async function () {
signStub = sinon.stub(txController, 'signEthTx').throws(signError);
});
afterEach(function () {
signStub.restore();
});
it('changes status to failed', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch {
// Expected error
}
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.status, TransactionStatus.failed);
});
it('rejects result', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await assert.rejects(result, signError);
});
it('emits approved and failed status events', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch (error) {
// Expected error
}
const txId = getLastTxMeta().id;
assert.equal(listener.callCount, 2);
assert.equal(listener.args[0][0], txId);
assert.equal(listener.args[0][1], TransactionStatus.approved);
assert.equal(listener.args[1][0], txId);
assert.equal(listener.args[1][1], TransactionStatus.failed);
});
it('reports error to approval request acceptor', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch {
// Expected error
}
assert.equal(resultCallbacksMock.error.callCount, 1);
assert.strictEqual(
resultCallbacksMock.error.getCall(0).args[0].message,
signError.message,
);
});
});
describe('on publish error', function () {
const publishError = new Error('TestPublishError');
let originalQuery;
beforeEach(async function () {
originalQuery = txController.query;
txController.query = {
sendRawTransaction: sinon.stub().throws(publishError),
};
});
afterEach(function () {
txController.query = originalQuery;
});
it('changes status to failed', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch {
// Expected error
}
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.status, TransactionStatus.failed);
});
it('rejects result', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
await assert.rejects(result, publishError);
});
it('emits approved, signed, and failed status events', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch (error) {
// Expected error
}
const txId = getLastTxMeta().id;
assert.equal(listener.callCount, 3);
assert.equal(listener.args[0][0], txId);
assert.equal(listener.args[0][1], TransactionStatus.approved);
assert.equal(listener.args[1][0], txId);
assert.equal(listener.args[1][1], TransactionStatus.signed);
assert.equal(listener.args[2][0], txId);
assert.equal(listener.args[2][1], TransactionStatus.failed);
});
it('reports error to approval request acceptor', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ origin: ORIGIN_METAMASK, actionId: '12345' },
);
try {
await result;
} catch {
// Expected error
}
assert.equal(resultCallbacksMock.error.callCount, 1);
assert.strictEqual(
resultCallbacksMock.error.getCall(0).args[0].message,
publishError.message,
);
});
});
describe('with require approval set to false', function () {
beforeEach(function () {
// Ensure that the default approval mock is not being used
messengerMock.call.callsFake(() => Promise.reject());
});
it('resolves result with the transaction hash', async function () {
const { result } = await txController.addTransaction(txParams, {
requireApproval: false,
});
const hash = await result;
assert.ok(hash, 'addTransaction needs to return the hash');
});
it('changes status to submitted', async function () {
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
actionid: '12345',
requireApproval: false,
},
);
await result;
const transaction = txController.getTransactions({
searchCriteria: { id: getLastTxMeta().id },
})[0];
assert.equal(transaction.status, TransactionStatus.submitted);
});
it('emits approved, signed, and submitted status events', async function () {
const listener = sinon.spy();
txController.on('tx:status-update', listener);
const { result } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{
origin: ORIGIN_METAMASK,
actionId: '12345',
requireApproval: false,
},
);
await result;
const txId = getLastTxMeta().id;
assert.equal(listener.callCount, 3);
assert.equal(listener.args[0][0], txId);
assert.equal(listener.args[0][1], TransactionStatus.approved);
assert.equal(listener.args[1][0], txId);
assert.equal(listener.args[1][1], TransactionStatus.signed);
assert.equal(listener.args[2][0], txId);
assert.equal(listener.args[2][1], TransactionStatus.submitted);
});
});
});
describe('#createCancelTransaction', function () {
const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d';
const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813';
let getSelectedAddress,
getPermittedAccounts,
getDefaultGasFees,
getDefaultGasLimit;
beforeEach(function () {
const hash =
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
providerResultStub.eth_sendRawTransaction = hash;
getSelectedAddress = sinon
.stub(txController, 'getSelectedAddress')
.returns(selectedAddress);
getDefaultGasFees = sinon
.stub(txController, '_getDefaultGasFees')
.returns({});
getDefaultGasLimit = sinon
.stub(txController, '_getDefaultGasLimit')
.returns({});
getPermittedAccounts = sinon
.stub(txController, 'getPermittedAccounts')
.returns([selectedAddress]);
});
afterEach(function () {
getSelectedAddress.restore();
getPermittedAccounts.restore();
getDefaultGasFees.restore();
getDefaultGasLimit.restore();
});
it('should add a cancel transaction and return a valid txMeta', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction({
from: selectedAddress,
to: recipientAddress,
});
await result;
const cancelTxMeta = await txController.createCancelTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
assert.equal(cancelTxMeta.type, TransactionType.cancel);
const memTxMeta = txController.txStateManager.getTransaction(
cancelTxMeta.id,
);
assert.deepEqual(cancelTxMeta, memTxMeta);
assert.equal(messengerMock.call.callCount, 1);
});
it('should add only 1 cancel transaction when called twice with same actionId', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction({
from: selectedAddress,
to: recipientAddress,
});
await result;
await txController.createCancelTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.createCancelTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1, transactionCount2);
});
it('should add multiple transactions when called with different actionId', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction({
from: selectedAddress,
to: recipientAddress,
});
await result;
await txController.createCancelTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.createCancelTransaction(
txMeta.id,
{},
{ actionId: 11111 },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1 + 1, transactionCount2);
});
});
describe('_addTxGasDefaults', function () {
it('should add the tx defaults if their are none', async function () {
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
]);
2017-09-23 01:15:18 +02:00
const txMeta = {
id: 1,
txParams: {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
2017-08-02 17:34:45 +02:00
},
history: [{}],
};
providerResultStub.eth_gasPrice = '4a817c800';
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' };
providerResultStub.eth_estimateGas = '5209';
const txMetaWithDefaults = await txController._addTxGasDefaults(txMeta);
2020-11-03 00:41:28 +01:00
assert.ok(
txMetaWithDefaults.txParams.gasPrice,
'should have added the gas price',
);
2020-11-03 00:41:28 +01:00
assert.ok(
txMetaWithDefaults.txParams.gas,
'should have added the gas field',
);
});
it('should add EIP1559 tx defaults', async function () {
const TEST_MAX_FEE_PER_GAS = '0x12a05f200';
const TEST_MAX_PRIORITY_FEE_PER_GAS = '0x77359400';
const stub1 = sinon
.stub(txController, '_getEIP1559Compatibility')
.returns(true);
const stub2 = sinon
.stub(txController, '_getDefaultGasFees')
.callsFake(() => ({
maxFeePerGas: TEST_MAX_FEE_PER_GAS,
maxPriorityFeePerGas: TEST_MAX_PRIORITY_FEE_PER_GAS,
}));
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);
const txMeta = {
id: 1,
txParams: {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
},
history: [{}],
};
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' };
providerResultStub.eth_estimateGas = '5209';
const txMetaWithDefaults = await txController._addTxGasDefaults(txMeta);
assert.equal(
txMetaWithDefaults.txParams.maxFeePerGas,
TEST_MAX_FEE_PER_GAS,
'should have added the correct max fee per gas',
);
assert.equal(
txMetaWithDefaults.txParams.maxPriorityFeePerGas,
TEST_MAX_PRIORITY_FEE_PER_GAS,
'should have added the correct max priority fee per gas',
);
stub1.restore();
stub2.restore();
});
it('should add gasPrice as maxFeePerGas and maxPriorityFeePerGas if there are no sources of other fee data available', async function () {
const TEST_GASPRICE = '0x12a05f200';
const stub1 = sinon
.stub(txController, '_getEIP1559Compatibility')
.returns(true);
const stub2 = sinon
.stub(txController, '_getDefaultGasFees')
.callsFake(() => ({ gasPrice: TEST_GASPRICE }));
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);
const txMeta = {
id: 1,
txParams: {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
},
history: [{}],
};
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' };
providerResultStub.eth_estimateGas = '5209';
const txMetaWithDefaults = await txController._addTxGasDefaults(txMeta);
assert.equal(
txMetaWithDefaults.txParams.maxFeePerGas,
TEST_GASPRICE,
'should have added the correct max fee per gas',
);
assert.equal(
txMetaWithDefaults.txParams.maxPriorityFeePerGas,
TEST_GASPRICE,
'should have added the correct max priority fee per gas',
);
stub1.restore();
stub2.restore();
});
it('should not add maxFeePerGas and maxPriorityFeePerGas to type-0 transactions', async function () {
const TEST_GASPRICE = '0x12a05f200';
const stub1 = sinon
.stub(txController, '_getEIP1559Compatibility')
.returns(true);
const stub2 = sinon
.stub(txController, '_getDefaultGasFees')
.callsFake(() => ({ gasPrice: TEST_GASPRICE }));
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
type: TransactionEnvelopeType.legacy,
},
history: [{}],
},
]);
const txMeta = {
id: 1,
txParams: {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
type: TransactionEnvelopeType.legacy,
},
history: [{}],
};
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' };
providerResultStub.eth_estimateGas = '5209';
const txMetaWithDefaults = await txController._addTxGasDefaults(txMeta);
assert.equal(
txMetaWithDefaults.txParams.maxFeePerGas,
undefined,
'should not have maxFeePerGas',
);
assert.equal(
txMetaWithDefaults.txParams.maxPriorityFeePerGas,
undefined,
'should not have max priority fee per gas',
);
stub1.restore();
stub2.restore();
});
it('should not add gasPrice if the fee data is available from the dapp', async function () {
const TEST_GASPRICE = '0x12a05f200';
const TEST_MAX_FEE_PER_GAS = '0x12a05f200';
const TEST_MAX_PRIORITY_FEE_PER_GAS = '0x77359400';
const stub1 = sinon
.stub(txController, '_getEIP1559Compatibility')
.returns(true);
const stub2 = sinon
.stub(txController, '_getDefaultGasFees')
.callsFake(() => ({ gasPrice: TEST_GASPRICE }));
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
maxFeePerGas: TEST_MAX_FEE_PER_GAS,
maxPriorityFeePerGas: TEST_MAX_PRIORITY_FEE_PER_GAS,
},
history: [{}],
},
]);
const txMeta = {
id: 1,
txParams: {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
},
history: [{}],
};
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' };
providerResultStub.eth_estimateGas = '5209';
const txMetaWithDefaults = await txController._addTxGasDefaults(txMeta);
assert.equal(
txMetaWithDefaults.txParams.maxFeePerGas,
TEST_MAX_FEE_PER_GAS,
'should have added the correct max fee per gas',
);
assert.equal(
txMetaWithDefaults.txParams.maxPriorityFeePerGas,
TEST_MAX_PRIORITY_FEE_PER_GAS,
'should have added the correct max priority fee per gas',
);
stub1.restore();
stub2.restore();
});
});
describe('_getDefaultGasFees', function () {
let getGasFeeStub;
beforeEach(function () {
getGasFeeStub = sinon.stub(txController, '_getEIP1559GasFeeEstimates');
});
afterEach(function () {
getGasFeeStub.restore();
});
it('should return the correct fee data when the gas estimate type is FEE_MARKET', async function () {
const EXPECTED_MAX_FEE_PER_GAS = '12a05f200';
const EXPECTED_MAX_PRIORITY_FEE_PER_GAS = '77359400';
getGasFeeStub.callsFake(() => ({
gasFeeEstimates: {
medium: {
suggestedMaxPriorityFeePerGas: '2',
suggestedMaxFeePerGas: '5',
},
},
gasEstimateType: GasEstimateTypes.feeMarket,
}));
const defaultGasFees = await txController._getDefaultGasFees(
{ txParams: {} },
true,
);
assert.deepEqual(defaultGasFees, {
maxPriorityFeePerGas: EXPECTED_MAX_PRIORITY_FEE_PER_GAS,
maxFeePerGas: EXPECTED_MAX_FEE_PER_GAS,
});
});
it('should return the correct fee data when the gas estimate type is LEGACY', async function () {
const EXPECTED_GAS_PRICE = '77359400';
getGasFeeStub.callsFake(() => ({
gasFeeEstimates: { medium: '2' },
gasEstimateType: GasEstimateTypes.legacy,
}));
const defaultGasFees = await txController._getDefaultGasFees(
{ txParams: {} },
false,
);
assert.deepEqual(defaultGasFees, {
gasPrice: EXPECTED_GAS_PRICE,
});
});
it('should return the correct fee data when the gas estimate type is ETH_GASPRICE', async function () {
const EXPECTED_GAS_PRICE = '77359400';
getGasFeeStub.callsFake(() => ({
gasFeeEstimates: { gasPrice: '2' },
gasEstimateType: GasEstimateTypes.ethGasPrice,
}));
const defaultGasFees = await txController._getDefaultGasFees(
{ txParams: {} },
false,
);
assert.deepEqual(defaultGasFees, {
gasPrice: EXPECTED_GAS_PRICE,
});
});
});
2017-08-02 17:34:45 +02:00
2017-05-04 23:35:10 +02:00
describe('#sign replay-protected tx', function () {
it('prepares a tx with the chainId set', async function () {
txController._addTransaction(
2020-11-03 00:41:28 +01:00
{
id: '1',
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
},
noop,
);
const rawTx = await txController._signTransaction('1');
const ethTx = TransactionFactory.fromSerializedData(toBuffer(rawTx));
assert.equal(Number(ethTx.common.chainId()), 5);
});
});
2017-09-23 01:15:18 +02:00
describe('_getChainId', function () {
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
it('returns the chain ID of the network when it is available', function () {
networkStatusStore.putState(NetworkStatus.Available);
assert.equal(txController._getChainId(), 5);
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
});
it('returns 0 when the network is not available', function () {
networkStatusStore.putState('NOT_INTEGER');
assert.equal(txController._getChainId(), 0);
NetworkController: Split `network` into `networkId` and `networkStatus` (#17556) The `network` store of the network controller crams two types of data into one place. It roughly tracks whether we have enough information to make requests to the network and whether the network is capable of receiving requests, but it also stores the ID of the network (as obtained via `net_version`). Generally we shouldn't be using the network ID for anything, as it has been completely replaced by chain ID, which all custom RPC endpoints have been required to support for over a year now. However, as the network ID is used in various places within the extension codebase, removing it entirely would be a non-trivial effort. So, minimally, this commit splits `network` into two stores: `networkId` and `networkStatus`. But it also expands the concept of network status. Previously, the network was in one of two states: "loading" and "not-loading". But now it can be in one of four states: - `available`: The network is able to receive and respond to requests. - `unavailable`: The network is not able to receive and respond to requests for unknown reasons. - `blocked`: The network is actively blocking requests based on the user's geolocation. (This is specific to Infura.) - `unknown`: We don't know whether the network can receive and respond to requests, either because we haven't checked or we tried to check and were unsuccessful. This commit also changes how the network status is determined — specifically, how many requests are used to determine that status, when they occur, and whether they are awaited. Previously, the network controller would make 2 to 3 requests during the course of running `lookupNetwork`. * First, if it was an Infura network, it would make a request for `eth_blockNumber` to determine whether Infura was blocking requests or not, then emit an appropriate event. This operation was not awaited. * Then, regardless of the network, it would fetch the network ID via `net_version`. This operation was awaited. * Finally, regardless of the network, it would fetch the latest block via `eth_getBlockByNumber`, then use the result to determine whether the network supported EIP-1559. This operation was awaited. Now: * One fewer request is made, specifically `eth_blockNumber`, as we don't need to make an extra request to determine whether Infura is blocking requests; we can reuse `eth_getBlockByNumber`; * All requests are awaited, which makes `lookupNetwork` run fully in-band instead of partially out-of-band; and * Both requests for `net_version` and `eth_getBlockByNumber` are performed in parallel to make `lookupNetwork` run slightly faster.
2023-03-31 00:49:12 +02:00
});
it('returns 0 when the chain ID cannot be parsed as a hex string', function () {
networkStatusStore.putState(NetworkStatus.Available);
getCurrentChainId.returns('NOT_INTEGER');
assert.equal(txController._getChainId(), 0);
});
});
2017-09-23 01:15:18 +02:00
describe('#createSpeedUpTransaction', function () {
let addTransactionSpy;
let approveTransactionSpy;
let txParams;
let expectedTxParams;
const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d';
const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813';
let getSelectedAddress,
getPermittedAccounts,
getDefaultGasFees,
getDefaultGasLimit;
beforeEach(function () {
addTransactionSpy = sinon.spy(txController, '_addTransaction');
approveTransactionSpy = sinon.spy(txController, '_approveTransaction');
const hash =
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
providerResultStub.eth_sendRawTransaction = hash;
getSelectedAddress = sinon
.stub(txController, 'getSelectedAddress')
.returns(selectedAddress);
getDefaultGasFees = sinon
.stub(txController, '_getDefaultGasFees')
.returns({});
getDefaultGasLimit = sinon
.stub(txController, '_getDefaultGasLimit')
.returns({});
getPermittedAccounts = sinon
.stub(txController, 'getPermittedAccounts')
.returns([selectedAddress]);
txParams = {
nonce: '0x00',
from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',
to: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4',
gas: '0x5209',
gasPrice: '0xa',
estimateSuggested: GasRecommendations.medium,
estimateUsed: GasRecommendations.high,
};
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams,
history: [{}],
},
]);
expectedTxParams = { ...txParams, gasPrice: '0xb' };
});
afterEach(function () {
addTransactionSpy.restore();
approveTransactionSpy.restore();
getSelectedAddress.restore();
getPermittedAccounts.restore();
getDefaultGasFees.restore();
getDefaultGasLimit.restore();
});
it('should call this.addTransaction and this.approveTransaction with the expected args', async function () {
await txController.createSpeedUpTransaction(1);
assert.equal(addTransactionSpy.callCount, 1);
const addTransactionArgs = addTransactionSpy.getCall(0).args[0];
assert.deepEqual(addTransactionArgs.txParams, expectedTxParams);
const { previousGasParams, type } = addTransactionArgs;
2020-11-03 00:41:28 +01:00
assert.deepEqual(
{ gasPrice: previousGasParams.gasPrice, type },
2020-11-03 00:41:28 +01:00
{
gasPrice: '0xa',
type: TransactionType.retry,
2020-11-03 00:41:28 +01:00
},
);
assert.equal(messengerMock.call.callCount, 0);
});
it('should call this.approveTransaction with the id of the returned tx', async function () {
const result = await txController.createSpeedUpTransaction(1);
assert.equal(approveTransactionSpy.callCount, 1);
const approveTransactionArg = approveTransactionSpy.getCall(0).args[0];
assert.equal(result.id, approveTransactionArg);
});
it('should return the expected txMeta', async function () {
const result = await txController.createSpeedUpTransaction(1);
assert.deepEqual(result.txParams, expectedTxParams);
const { previousGasParams, type } = result;
2020-11-03 00:41:28 +01:00
assert.deepEqual(
{ gasPrice: previousGasParams.gasPrice, type },
2020-11-03 00:41:28 +01:00
{
gasPrice: '0xa',
type: TransactionType.retry,
2020-11-03 00:41:28 +01:00
},
);
});
it('should add only 1 speedup transaction when called twice with same actionId', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction({
from: selectedAddress,
to: recipientAddress,
});
await result;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1, transactionCount2);
});
it('should add multiple transactions when called with different actionId', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction({
from: selectedAddress,
to: recipientAddress,
});
await result;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 11111 },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1 + 1, transactionCount2);
});
it('should add multiple transactions when called with different actionId and txMethodType defined', async function () {
const { transactionMeta: txMeta, result } =
await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ method: 'eth_sendTransaction' },
);
await result;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 12345 },
);
const transactionCount1 =
txController.txStateManager.getTransactions().length;
await txController.createSpeedUpTransaction(
txMeta.id,
{},
{ actionId: 11111 },
);
const transactionCount2 =
txController.txStateManager.getTransactions().length;
assert.equal(transactionCount1 + 1, transactionCount2);
});
it('should call securityProviderRequest and have flagAsDangerous inside txMeta', async function () {
const { transactionMeta: txMeta } = await txController.addTransaction(
{
from: selectedAddress,
to: recipientAddress,
},
{ method: 'eth_sendTransaction' },
);
assert.ok(
'securityProviderResponse' in txMeta,
'should have a securityProviderResponse',
);
});
});
describe('#signTransaction', function () {
let fromTxDataSpy;
beforeEach(function () {
fromTxDataSpy = sinon.spy(TransactionFactory, 'fromTxData');
});
afterEach(function () {
fromTxDataSpy.restore();
});
it('sets txParams.type to 0x0 (non-EIP-1559)', async function () {
txController.txStateManager._addTransactionsToState([
{
status: TransactionStatus.unapproved,
id: 1,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
from: VALID_ADDRESS_TWO,
to: VALID_ADDRESS,
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
},
]);
await txController._signTransaction('1');
assert.equal(fromTxDataSpy.getCall(0).args[0].type, '0x0');
});
it('sets txParams.type to 0x2 (EIP-1559)', async function () {
const eip1559CompatibilityStub = sinon
.stub(txController, '_getEIP1559Compatibility')
.returns(true);
txController.txStateManager._addTransactionsToState([
{
status: TransactionStatus.unapproved,
id: 2,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
from: VALID_ADDRESS_TWO,
to: VALID_ADDRESS,
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
},
]);
await txController._signTransaction('2');
assert.equal(fromTxDataSpy.getCall(0).args[0].type, '0x2');
eip1559CompatibilityStub.restore();
});
});
describe('_publishTransaction', function () {
let hash, txMeta, trackTransactionMetricsEventSpy;
2017-09-23 01:15:18 +02:00
beforeEach(function () {
2020-11-03 00:41:28 +01:00
hash =
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
2017-09-23 01:15:18 +02:00
txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
gas: '0x7b0d',
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2017-09-23 01:15:18 +02:00
metamaskNetworkId: currentNetworkId,
};
providerResultStub.eth_sendRawTransaction = hash;
trackTransactionMetricsEventSpy = sinon.spy(
txController,
'_trackTransactionMetricsEvent',
);
});
afterEach(function () {
trackTransactionMetricsEventSpy.restore();
});
2017-09-26 04:47:03 +02:00
2017-09-23 01:15:18 +02:00
it('should publish a tx, updates the rawTx when provided a one', async function () {
2020-11-03 00:41:28 +01:00
const rawTx =
'0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c';
txController.txStateManager.addTransaction(txMeta);
await txController._publishTransaction(txMeta.id, rawTx);
const publishedTx = txController.txStateManager.getTransaction(1);
assert.equal(publishedTx.hash, hash);
assert.equal(publishedTx.status, TransactionStatus.submitted);
});
it('should ignore the error "Transaction Failed: known transaction" and be as usual', async function () {
providerResultStub.eth_sendRawTransaction = async (_, __, ___, end) => {
end('Transaction Failed: known transaction');
};
2020-11-03 00:41:28 +01:00
const rawTx =
'0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a';
txController.txStateManager.addTransaction(txMeta);
await txController._publishTransaction(txMeta.id, rawTx);
const publishedTx = txController.txStateManager.getTransaction(1);
2020-11-03 00:41:28 +01:00
assert.equal(
publishedTx.hash,
'0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09',
);
assert.equal(publishedTx.status, TransactionStatus.submitted);
});
it('should call _trackTransactionMetricsEvent with the correct params', async function () {
const rawTx =
'0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c';
txController.txStateManager.addTransaction(txMeta);
await txController._publishTransaction(txMeta.id, rawTx);
assert.equal(trackTransactionMetricsEventSpy.callCount, 1);
assert.deepEqual(
trackTransactionMetricsEventSpy.getCall(0).args[0],
txMeta,
);
assert.equal(
trackTransactionMetricsEventSpy.getCall(0).args[1],
TransactionMetaMetricsEvent.submitted,
);
});
});
2017-09-23 01:15:18 +02:00
describe('#_markNonceDuplicatesDropped', function () {
it('should mark all nonce duplicates as dropped without marking the confirmed transaction as dropped', function () {
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 2,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 3,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 4,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 5,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 6,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
{
id: 7,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
2020-11-03 00:41:28 +01:00
},
]);
txController._markNonceDuplicatesDropped(1);
const confirmedTx = txController.txStateManager.getTransaction(1);
const droppedTxs = txController.txStateManager.getTransactions({
searchCriteria: {
nonce: '0x01',
status: TransactionStatus.dropped,
},
});
2020-11-03 00:41:28 +01:00
assert.equal(
confirmedTx.status,
TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
'the confirmedTx should remain confirmed',
);
assert.equal(droppedTxs.length, 6, 'their should be 6 dropped txs');
});
});
2017-09-23 01:15:18 +02:00
describe('#getPendingTransactions', function () {
it('should show only submitted and approved transactions as pending transaction', function () {
txController.txStateManager._addTransactionsToState([
2020-11-03 00:41:28 +01:00
{
id: 1,
status: TransactionStatus.unapproved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
},
{
id: 2,
status: TransactionStatus.rejected,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 3,
status: TransactionStatus.approved,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 4,
status: TransactionStatus.signed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 5,
status: TransactionStatus.submitted,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 6,
status: TransactionStatus.confirmed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
{
id: 7,
status: TransactionStatus.failed,
2020-11-03 00:41:28 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
2020-11-03 00:41:28 +01:00
history: [{}],
},
]);
2020-11-03 00:41:28 +01:00
assert.equal(
txController.pendingTxTracker.getPendingTransactions().length,
2,
);
2020-11-03 00:41:28 +01:00
const states = txController.pendingTxTracker
.getPendingTransactions()
.map((tx) => tx.status);
assert.ok(
states.includes(TransactionStatus.approved),
'includes approved',
);
assert.ok(
states.includes(TransactionStatus.submitted),
'includes submitted',
);
});
});
describe('#_trackTransactionMetricsEvent', function () {
let trackMetaMetricsEventSpy;
let createEventFragmentSpy;
let finalizeEventFragmentSpy;
beforeEach(function () {
trackMetaMetricsEventSpy = sinon.spy(
txController,
'_trackMetaMetricsEvent',
);
createEventFragmentSpy = sinon.spy(txController, 'createEventFragment');
finalizeEventFragmentSpy = sinon.spy(
txController,
'finalizeEventFragment',
);
sinon
.stub(txController, '_getEIP1559GasFeeEstimates')
.resolves(mockEstimates['fee-market']);
});
afterEach(function () {
trackMetaMetricsEventSpy.restore();
createEventFragmentSpy.restore();
finalizeEventFragmentSpy.restore();
});
describe('On transaction created by the user', function () {
let txMeta;
before(function () {
txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: ORIGIN_METAMASK,
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
gas: '0x7b0d',
gasPrice: '0x77359400',
},
securityProviderResponse: {
flagAsDangerous: 0,
},
};
});
it('should create an event fragment when transaction added', async function () {
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: MetaMetricsEventCategory.Transactions,
persist: true,
properties: {
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: ORIGIN_METAMASK,
source: MetaMetricsTransactionEventSource.User,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.rejected,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], {
abandoned: true,
});
});
it('Should finalize the transaction added fragment if user approves transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.approved,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
it('should create an event fragment when transaction is submitted', async function () {
const expectedPayload = {
actionId,
initialEvent: 'Transaction Submitted',
successEvent: 'Transaction Finalized',
uniqueIdentifier: 'transaction-submitted-1',
category: MetaMetricsEventCategory.Transactions,
persist: true,
properties: {
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: ORIGIN_METAMASK,
source: MetaMetricsTransactionEventSource.User,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.submitted,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction submitted fragment when transaction finalizes', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.finalized,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-submitted-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
});
describe('On transaction suggested by dapp', function () {
let txMeta;
before(function () {
txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
gas: '0x7b0d',
gasPrice: '0x77359400',
},
securityProviderResponse: {
flagAsDangerous: 0,
},
};
});
it('should create an event fragment when transaction added', async function () {
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: MetaMetricsEventCategory.Transactions,
persist: true,
properties: {
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.rejected,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], {
abandoned: true,
});
});
it('Should finalize the transaction added fragment if user approves transaction', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.approved,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
it('should create an event fragment when transaction is submitted', async function () {
const expectedPayload = {
actionId,
initialEvent: 'Transaction Submitted',
successEvent: 'Transaction Finalized',
uniqueIdentifier: 'transaction-submitted-1',
category: MetaMetricsEventCategory.Transactions,
persist: true,
properties: {
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.submitted,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('Should finalize the transaction submitted fragment when transaction finalizes', async function () {
fragmentExists = true;
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.finalized,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 0);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-submitted-1',
);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[1],
undefined,
);
});
});
it('should create missing fragments when events happen out of order or are missing', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
securityProviderResponse: {
flagAsDangerous: 0,
},
securityAlertResponse: {
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
},
};
const expectedPayload = {
actionId,
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
category: MetaMetricsEventCategory.Transactions,
persist: true,
properties: {
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.approved,
actionId,
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
assert.equal(finalizeEventFragmentSpy.callCount, 1);
assert.deepEqual(
finalizeEventFragmentSpy.getCall(0).args[0],
'transaction-added-1',
);
assert.deepEqual(finalizeEventFragmentSpy.getCall(0).args[1], undefined);
});
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
securityProviderResponse: {
flagAsDangerous: 0,
},
};
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: MetaMetricsEventCategory.Transactions,
properties: {
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
2023-08-03 12:54:54 +02:00
it('should call _trackMetaMetricsEvent with the correct payload when blockaid verification fails', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
securityAlertResponse: {
result_type: BlockaidResultType.Failed,
reason: 'some error',
},
};
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: MetaMetricsEventCategory.Transactions,
properties: {
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
status: 'unapproved',
transaction_type: TransactionType.simpleSend,
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: ['security_alert_failed'],
security_alert_reason: 'some error',
security_alert_response: BlockaidResultType.Failed,
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (extra params) when flagAsDangerous is malicious', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
securityProviderResponse: {
flagAsDangerous: 1,
},
};
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: MetaMetricsEventCategory.Transactions,
properties: {
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: ['flagged_as_malicious'],
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (extra params) when flagAsDangerous is unknown', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
gasPrice: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
securityProviderResponse: {
flagAsDangerous: 2,
},
};
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: MetaMetricsEventCategory.Transactions,
properties: {
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
chain_id: '0x5',
eip_1559_version: '0',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: ['flagged_as_safety_unknown'],
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
it('should call _trackMetaMetricsEvent with the correct payload (EIP-1559)', async function () {
const txMeta = {
id: 1,
status: TransactionStatus.unapproved,
txParams: {
from: fromAccount.address,
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x77359400',
gas: '0x7b0d',
nonce: '0x4b',
estimateSuggested: GasRecommendations.medium,
estimateUsed: GasRecommendations.high,
},
type: TransactionType.simpleSend,
origin: 'other',
chainId: currentChainId,
time: 1624408066355,
metamaskNetworkId: currentNetworkId,
defaultGasEstimates: {
estimateType: 'medium',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x77359400',
},
securityProviderResponse: {
flagAsDangerous: 0,
},
};
const expectedPayload = {
actionId,
initialEvent: 'Transaction Added',
successEvent: 'Transaction Approved',
failureEvent: 'Transaction Rejected',
uniqueIdentifier: 'transaction-added-1',
persist: true,
category: MetaMetricsEventCategory.Transactions,
properties: {
chain_id: '0x5',
eip_1559_version: '2',
gas_edit_attempted: 'none',
gas_edit_type: 'none',
network: '5',
referrer: 'other',
source: MetaMetricsTransactionEventSource.Dapp,
transaction_type: TransactionType.simpleSend,
account_type: 'MetaMask',
asset_type: AssetType.native,
token_standard: TokenStandard.none,
device_model: 'N/A',
transaction_speed_up: false,
ui_customizations: null,
security_alert_reason: BlockaidReason.notApplicable,
security_alert_response: BlockaidResultType.NotApplicable,
status: 'unapproved',
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
max_fee_per_gas: '2',
max_priority_fee_per_gas: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET,
estimate_suggested: GasRecommendations.medium,
estimate_used: GasRecommendations.high,
default_estimate: 'medium',
default_max_fee_per_gas: '70',
default_max_priority_fee_per_gas: '7',
},
};
await txController._trackTransactionMetricsEvent(
txMeta,
TransactionMetaMetricsEvent.added,
actionId,
{
baz: 3.0,
foo: 'bar',
},
);
assert.equal(createEventFragmentSpy.callCount, 1);
assert.equal(finalizeEventFragmentSpy.callCount, 0);
assert.deepEqual(
createEventFragmentSpy.getCall(0).args[0],
expectedPayload,
);
});
});
describe('#_getTransactionCompletionTime', function () {
let nowStub;
beforeEach(function () {
nowStub = sinon.stub(Date, 'now').returns(1625782016341);
});
afterEach(function () {
nowStub.restore();
});
it('calculates completion time (one)', function () {
const submittedTime = 1625781997397;
const result = txController._getTransactionCompletionTime(submittedTime);
assert.equal(result, '19');
});
it('calculates completion time (two)', function () {
const submittedTime = 1625781995397;
const result = txController._getTransactionCompletionTime(submittedTime);
assert.equal(result, '21');
});
});
describe('#_getGasValuesInGWEI', function () {
it('converts gas values in hex GWEi to dec GWEI (EIP-1559)', function () {
const params = {
max_fee_per_gas: '0x77359400',
max_priority_fee_per_gas: '0x77359400',
};
const expectedParams = {
max_fee_per_gas: '2',
max_priority_fee_per_gas: '2',
};
const result = txController._getGasValuesInGWEI(params);
assert.deepEqual(result, expectedParams);
});
it('converts gas values in hex GWEi to dec GWEI (non EIP-1559)', function () {
const params = {
gas_price: '0x37e11d600',
};
const expectedParams = {
gas_price: '15',
};
const result = txController._getGasValuesInGWEI(params);
assert.deepEqual(result, expectedParams);
});
it('converts gas values in hex GWEi to dec GWEI, retains estimate fields', function () {
const params = {
max_fee_per_gas: '0x77359400',
max_priority_fee_per_gas: '0x77359400',
estimate_suggested: GasRecommendations.medium,
estimate_used: GasRecommendations.high,
};
const expectedParams = {
max_fee_per_gas: '2',
max_priority_fee_per_gas: '2',
estimate_suggested: GasRecommendations.medium,
estimate_used: GasRecommendations.high,
};
const result = txController._getGasValuesInGWEI(params);
assert.deepEqual(result, expectedParams);
});
});
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
describe('update transaction methods', function () {
let txStateManager;
beforeEach(function () {
txStateManager = txController.txStateManager;
txStateManager.addTransaction({
id: '1',
status: TransactionStatus.unapproved,
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
gasLimit: '0x001',
gasPrice: '0x002',
// max fees can not be mixed with gasPrice
// maxPriorityFeePerGas: '0x003',
// maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x005',
estimatedBaseFee: '0x006',
decEstimatedBaseFee: '6',
type: 'swap',
sourceTokenSymbol: 'ETH',
destinationTokenSymbol: 'UNI',
destinationTokenDecimals: 16,
destinationTokenAddress: VALID_ADDRESS,
swapMetaData: {},
swapTokenValue: '0x007',
userEditedGasLimit: '0x008',
userFeeLevel: 'medium',
});
});
it('updates transaction gas fees', function () {
// test update gasFees
txController.updateTransactionGasFees('1', {
gasPrice: '0x0022',
gasLimit: '0x0011',
});
let result = txStateManager.getTransaction('1');
assert.equal(result.txParams.gasPrice, '0x0022');
// TODO: weird behavior here...only gasPrice gets returned.
// assert.equal(result.txParams.gasLimit, '0x0011');
// test update maxPriorityFeePerGas
txStateManager.addTransaction({
id: '2',
status: TransactionStatus.unapproved,
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
maxPriorityFeePerGas: '0x003',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x005',
});
txController.updateTransactionGasFees('2', {
maxPriorityFeePerGas: '0x0033',
});
result = txStateManager.getTransaction('2');
assert.equal(result.txParams.maxPriorityFeePerGas, '0x0033');
// test update maxFeePerGas
txStateManager.addTransaction({
id: '3',
status: TransactionStatus.unapproved,
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
maxPriorityFeePerGas: '0x003',
maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x005',
});
txController.updateTransactionGasFees('3', { maxFeePerGas: '0x0044' });
result = txStateManager.getTransaction('3');
assert.equal(result.txParams.maxFeePerGas, '0x0044');
// test update estimate used
txController.updateTransactionGasFees('3', { estimateUsed: '0x0055' });
result = txStateManager.getTransaction('3');
assert.equal(result.estimateUsed, '0x0055');
});
it('should not update and should throw error if status is not type "unapproved"', function () {
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
txStateManager.addTransaction({
id: '4',
status: TransactionStatus.dropped,
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
metamaskNetworkId: currentNetworkId,
txParams: {
maxPriorityFeePerGas: '0x007',
maxFeePerGas: '0x008',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x009',
});
assert.throws(
() =>
txController.updateTransactionGasFees('4', {
maxFeePerGas: '0x0088',
}),
Error,
`TransactionsController: Can only call updateTransactionGasFees on an unapproved transaction.
Current tx status: ${TransactionStatus.dropped}`,
);
const transaction = txStateManager.getTransaction('4');
assert.equal(transaction.txParams.maxFeePerGas, '0x008');
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
});
it('does not update unknown parameters in update method', function () {
txController.updateTransactionGasFees('1', {
estimateUsed: '0x13',
gasPrice: '0x14',
destinationTokenAddress: VALID_ADDRESS,
});
const result = txStateManager.getTransaction('1');
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
assert.equal(result.estimateUsed, '0x13');
assert.equal(result.txParams.gasPrice, '0x14');
assert.equal(result.destinationTokenAddress, VALID_ADDRESS); // not updated even though it's passed in to update
Replace uses of updateTransaction (from the tx controller) with less powerful methods for each specific state transition (#13496) * Draft methods to brak updateTransaction into smaller more targeted methods. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * normalize and validate tx params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Method to normalize tx and check if it's unapproved. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Move the methods to controllers/transactions/index.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Flesh out the methods to update transaction with custom notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * enforce that only the properties for the specific methid can be updated via the method. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Rename calls to check transaction status. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update gas fees Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Test update estimated base fee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update swap approval transaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * use lodash to remove undefined properties update swap transaction tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Updates transaction user settings. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove commented log lines Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more parameters to updateSwapTransaction approvalTxId estimatedBaseFee Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix documentation for updateSwapTransaction Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add Update Transaction Metrics Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update transaction gas fees actions.js Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update EIP 1559 Params. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint Fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Documentations. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove metrics from this PR Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Lint fixes: Removed unused variables Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Add more params to updateTransactionGasFees. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Update eip1559 method to editableParams. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * lint fixes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Fix Mocha tests Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * add gasPrice to updateEditableParams Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * Remove duplicated Params in notes. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com> * A few more tests to cover if transaction status is not unapproved transaction is passed more parameters than it requires. Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
2022-02-24 19:26:58 +01:00
});
});
describe('updateEditableParams', function () {
let txStateManager;
beforeEach(function () {
txStateManager = txController.txStateManager;
txStateManager.addTransaction({
id: '1',
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
gas: '0x001',
gasPrice: '0x002',
// max fees can not be mixed with gasPrice
// maxPriorityFeePerGas: '0x003',
// maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x005',
estimatedBaseFee: '0x006',
decEstimatedBaseFee: '6',
type: 'simpleSend',
userEditedGasLimit: '0x008',
userFeeLevel: 'medium',
});
});
it('updates editible params when type changes from simple send to token transfer', async function () {
providerResultStub.eth_getCode = '0xab';
// test update gasFees
await txController.updateEditableParams('1', {
2022-07-31 20:26:40 +02:00
data: '0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
});
const result = txStateManager.getTransaction('1');
assert.equal(
result.txParams.data,
'0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
);
assert.equal(result.type, TransactionType.tokenMethodTransfer);
});
it('updates editible params when type changes from token transfer to simple send', async function () {
// test update gasFees
txStateManager.addTransaction({
id: '2',
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
gas: '0x001',
gasPrice: '0x002',
// max fees can not be mixed with gasPrice
// maxPriorityFeePerGas: '0x003',
// maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
2022-07-31 20:26:40 +02:00
data: '0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
},
estimateUsed: '0x005',
estimatedBaseFee: '0x006',
decEstimatedBaseFee: '6',
type: TransactionType.tokenMethodTransfer,
userEditedGasLimit: '0x008',
userFeeLevel: 'medium',
});
await txController.updateEditableParams('2', {
data: '0x',
});
const result = txStateManager.getTransaction('2');
assert.equal(result.txParams.data, '0x');
assert.equal(result.type, TransactionType.simpleSend);
});
it('updates editible params when type changes from simpleSend to contract interaction', async function () {
// test update gasFees
txStateManager.addTransaction({
id: '3',
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
gas: '0x001',
gasPrice: '0x002',
// max fees can not be mixed with gasPrice
// maxPriorityFeePerGas: '0x003',
// maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
},
estimateUsed: '0x005',
estimatedBaseFee: '0x006',
decEstimatedBaseFee: '6',
type: TransactionType.tokenMethodTransfer,
userEditedGasLimit: '0x008',
userFeeLevel: 'medium',
});
providerResultStub.eth_getCode = '0x5';
await txController.updateEditableParams('3', {
data: '0x123',
});
const result = txStateManager.getTransaction('3');
assert.equal(result.txParams.data, '0x123');
assert.equal(result.type, TransactionType.contractInteraction);
});
it('updates editible params when type does not change', async function () {
// test update gasFees
await txController.updateEditableParams('1', {
data: '0x123',
gas: '0xabc',
from: VALID_ADDRESS_TWO,
});
const result = txStateManager.getTransaction('1');
assert.equal(result.txParams.data, '0x123');
assert.equal(result.txParams.gas, '0xabc');
assert.equal(result.txParams.from, VALID_ADDRESS_TWO);
assert.equal(result.txParams.to, VALID_ADDRESS);
assert.equal(result.txParams.gasPrice, '0x002');
assert.equal(result.type, TransactionType.simpleSend);
});
});
describe('initApprovals', function () {
it('adds unapprovedTxs as approvals', async function () {
const firstTxId = '1';
const firstTxMeta = {
id: firstTxId,
origin: ORIGIN_METAMASK,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
};
const secondTxId = '2';
const secondTxMeta = {
id: secondTxId,
origin: ORIGIN_METAMASK,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
};
txController._addTransaction(firstTxMeta);
txController._addTransaction(secondTxMeta);
await txController.initApprovals();
assert.deepEqual(messengerMock.call.getCall(0).args, [
'ApprovalController:addRequest',
{
id: firstTxId,
origin: ORIGIN_METAMASK,
requestData: { txId: firstTxId },
type: ApprovalType.Transaction,
expectsResult: true,
},
false,
]);
assert.deepEqual(messengerMock.call.getCall(1).args, [
'ApprovalController:addRequest',
{
id: secondTxId,
origin: ORIGIN_METAMASK,
requestData: { txId: secondTxId },
type: ApprovalType.Transaction,
expectsResult: true,
},
false,
]);
});
});
describe('#updateTransactionSendFlowHistory', function () {
it('returns same result after two sequential calls with same history', async function () {
const txId = 1;
const txMeta = {
id: txId,
origin: ORIGIN_METAMASK,
status: TransactionStatus.unapproved,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
};
txController._addTransaction(txMeta);
const transaction1 = txController.updateTransactionSendFlowHistory(
txId,
2,
['foo1', 'foo2'],
);
const transaction2 = txController.updateTransactionSendFlowHistory(
txId,
2,
['foo1', 'foo2'],
);
assert.deepEqual(transaction1, transaction2);
});
});
describe('on incoming transaction helper transactions event', function () {
it('adds new transactions to state', async function () {
const existingTransaction = TRANSACTION_META_MOCK;
const incomingTransaction1 = {
...TRANSACTION_META_MOCK,
id: 2,
hash: '0x2',
};
const incomingTransaction2 = {
...TRANSACTION_META_MOCK,
id: 3,
hash: '0x3',
};
txController.store.getState().transactions = {
[existingTransaction.id]: existingTransaction,
};
await incomingTransactionHelperEventMock.firstCall.args[1]({
added: [incomingTransaction1, incomingTransaction2],
updated: [],
});
assert.deepEqual(txController.store.getState().transactions, {
[existingTransaction.id]: existingTransaction,
[incomingTransaction1.id]: incomingTransaction1,
[incomingTransaction2.id]: incomingTransaction2,
});
});
it('ignores new transactions if hash matches existing transaction', async function () {
const existingTransaction = TRANSACTION_META_MOCK;
const incomingTransaction1 = { ...TRANSACTION_META_MOCK, id: 2 };
const incomingTransaction2 = { ...TRANSACTION_META_MOCK, id: 3 };
txController.store.getState().transactions = {
[existingTransaction.id]: existingTransaction,
};
await incomingTransactionHelperEventMock.firstCall.args[1]({
added: [incomingTransaction1, incomingTransaction2],
updated: [],
});
assert.deepEqual(txController.store.getState().transactions, {
[existingTransaction.id]: existingTransaction,
});
});
});
describe('on incoming transaction helper updatedLastFetchedBlockNumbers event', function () {
it('updates state', async function () {
const lastFetchedBlockNumbers = {
key: 234,
};
assert.deepEqual(
txController.store.getState().lastFetchedBlockNumbers,
undefined,
);
await incomingTransactionHelperEventMock.secondCall.args[1]({
lastFetchedBlockNumbers,
});
assert.deepEqual(
txController.store.getState().lastFetchedBlockNumbers,
lastFetchedBlockNumbers,
);
});
});
});