mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #11423 from MetaMask/Version-v9.7.1
Version v9.7.1 RC
This commit is contained in:
commit
bd38b02d8e
@ -108,7 +108,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['**/*.test.js'],
|
files: ['**/*.test.js'],
|
||||||
excludedFiles: ['ui/**/*.test.js', 'ui/__mocks__/*.js'],
|
excludedFiles: [
|
||||||
|
'ui/**/*.test.js',
|
||||||
|
'ui/__mocks__/*.js',
|
||||||
|
'shared/**/*.test.js',
|
||||||
|
],
|
||||||
extends: ['@metamask/eslint-config-mocha'],
|
extends: ['@metamask/eslint-config-mocha'],
|
||||||
rules: {
|
rules: {
|
||||||
'mocha/no-setup-in-describe': 'off',
|
'mocha/no-setup-in-describe': 'off',
|
||||||
@ -125,7 +129,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['ui/**/*.test.js', 'ui/__mocks__/*.js'],
|
files: ['ui/**/*.test.js', 'ui/__mocks__/*.js', 'shared/**/*.test.js'],
|
||||||
extends: ['@metamask/eslint-config-jest'],
|
extends: ['@metamask/eslint-config-jest'],
|
||||||
rules: {
|
rules: {
|
||||||
'jest/no-restricted-matchers': 'off',
|
'jest/no-restricted-matchers': 'off',
|
||||||
|
@ -140,7 +140,6 @@ const state = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participateInMetaMetrics": true,
|
"participateInMetaMetrics": true,
|
||||||
"metaMetricsSendCount": 2,
|
|
||||||
"nextNonce": 71,
|
"nextNonce": 71,
|
||||||
"connectedStatusPopoverHasBeenShown": true,
|
"connectedStatusPopoverHasBeenShown": true,
|
||||||
"swapsWelcomeMessageHasBeenShown": true,
|
"swapsWelcomeMessageHasBeenShown": true,
|
||||||
|
@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [9.7.1]
|
||||||
|
### Fixed
|
||||||
|
- [#11426](https://github.com/MetaMask/metamask-extension/pull/11426): Fixed bug that broke transaction speed up and cancel, when attempting those actions immediately after opening MetaMask
|
||||||
|
|
||||||
## [9.7.0]
|
## [9.7.0]
|
||||||
### Added
|
### Added
|
||||||
- [#11021](https://github.com/MetaMask/metamask-extension/pull/11021): Add periodic reminder modal for backing up recovery phrase
|
- [#11021](https://github.com/MetaMask/metamask-extension/pull/11021): Add periodic reminder modal for backing up recovery phrase
|
||||||
@ -2317,7 +2321,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Uncategorized
|
### Uncategorized
|
||||||
- Added the ability to restore accounts from seed words.
|
- Added the ability to restore accounts from seed words.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v9.7.0...HEAD
|
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v9.7.1...HEAD
|
||||||
|
[9.7.1]: https://github.com/MetaMask/metamask-extension/compare/v9.7.0...v9.7.1
|
||||||
[9.7.0]: https://github.com/MetaMask/metamask-extension/compare/v9.6.1...v9.7.0
|
[9.7.0]: https://github.com/MetaMask/metamask-extension/compare/v9.6.1...v9.7.0
|
||||||
[9.6.1]: https://github.com/MetaMask/metamask-extension/compare/v9.6.0...v9.6.1
|
[9.6.1]: https://github.com/MetaMask/metamask-extension/compare/v9.6.0...v9.6.1
|
||||||
[9.6.0]: https://github.com/MetaMask/metamask-extension/compare/v9.5.9...v9.6.0
|
[9.6.0]: https://github.com/MetaMask/metamask-extension/compare/v9.5.9...v9.6.0
|
||||||
|
@ -7,30 +7,6 @@ import {
|
|||||||
METAMETRICS_BACKGROUND_PAGE_OBJECT,
|
METAMETRICS_BACKGROUND_PAGE_OBJECT,
|
||||||
} from '../../../shared/constants/metametrics';
|
} from '../../../shared/constants/metametrics';
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to determine whether or not to attach a user's metametrics id
|
|
||||||
* to events that include on-chain data. This helps to prevent identifying
|
|
||||||
* a user by being able to trace their activity on etherscan/block exploring
|
|
||||||
*/
|
|
||||||
const trackableSendCounts = {
|
|
||||||
1: true,
|
|
||||||
10: true,
|
|
||||||
30: true,
|
|
||||||
50: true,
|
|
||||||
100: true,
|
|
||||||
250: true,
|
|
||||||
500: true,
|
|
||||||
1000: true,
|
|
||||||
2500: true,
|
|
||||||
5000: true,
|
|
||||||
10000: true,
|
|
||||||
25000: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function sendCountIsTrackable(sendCount) {
|
|
||||||
return Boolean(trackableSendCounts[sendCount]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsContext} MetaMetricsContext
|
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsContext} MetaMetricsContext
|
||||||
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsEventPayload} MetaMetricsEventPayload
|
* @typedef {import('../../../shared/constants/metametrics').MetaMetricsEventPayload} MetaMetricsEventPayload
|
||||||
@ -48,9 +24,6 @@ export function sendCountIsTrackable(sendCount) {
|
|||||||
* @property {?boolean} participateInMetaMetrics - The user's preference for
|
* @property {?boolean} participateInMetaMetrics - The user's preference for
|
||||||
* participating in the MetaMetrics analytics program. This setting controls
|
* participating in the MetaMetrics analytics program. This setting controls
|
||||||
* whether or not events are tracked
|
* whether or not events are tracked
|
||||||
* @property {number} metaMetricsSendCount - How many send transactions have
|
|
||||||
* been tracked through this controller. Used to prevent attaching sensitive
|
|
||||||
* data that can be traced through on chain data.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class MetaMetricsController {
|
export default class MetaMetricsController {
|
||||||
@ -89,7 +62,6 @@ export default class MetaMetricsController {
|
|||||||
this.store = new ObservableStore({
|
this.store = new ObservableStore({
|
||||||
participateInMetaMetrics: null,
|
participateInMetaMetrics: null,
|
||||||
metaMetricsId: null,
|
metaMetricsId: null,
|
||||||
metaMetricsSendCount: 0,
|
|
||||||
...initState,
|
...initState,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -138,10 +110,6 @@ export default class MetaMetricsController {
|
|||||||
return this.store.getState();
|
return this.store.getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
setMetaMetricsSendCount(val) {
|
|
||||||
this.store.updateState({ metaMetricsSendCount: val });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the context object to attach to page and track events.
|
* Build the context object to attach to page and track events.
|
||||||
* @private
|
* @private
|
||||||
@ -231,11 +199,7 @@ export default class MetaMetricsController {
|
|||||||
// to be updated to work with the new tracking plan. I think we should use
|
// to be updated to work with the new tracking plan. I think we should use
|
||||||
// a config setting for this instead of trying to match the event name
|
// a config setting for this instead of trying to match the event name
|
||||||
const isSendFlow = Boolean(payload.event.match(/^send|^confirm/iu));
|
const isSendFlow = Boolean(payload.event.match(/^send|^confirm/iu));
|
||||||
if (
|
if (isSendFlow) {
|
||||||
isSendFlow &&
|
|
||||||
this.state.metaMetricsSendCount &&
|
|
||||||
!sendCountIsTrackable(this.state.metaMetricsSendCount + 1)
|
|
||||||
) {
|
|
||||||
excludeMetaMetricsId = true;
|
excludeMetaMetricsId = true;
|
||||||
}
|
}
|
||||||
// If we are tracking sensitive data we will always use the anonymousId
|
// If we are tracking sensitive data we will always use the anonymousId
|
||||||
|
@ -84,7 +84,6 @@ function getMockPreferencesStore({ currentLocale = LOCALE } = {}) {
|
|||||||
function getMetaMetricsController({
|
function getMetaMetricsController({
|
||||||
participateInMetaMetrics = true,
|
participateInMetaMetrics = true,
|
||||||
metaMetricsId = TEST_META_METRICS_ID,
|
metaMetricsId = TEST_META_METRICS_ID,
|
||||||
metaMetricsSendCount = 0,
|
|
||||||
preferencesStore = getMockPreferencesStore(),
|
preferencesStore = getMockPreferencesStore(),
|
||||||
networkController = getMockNetworkController(),
|
networkController = getMockNetworkController(),
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@ -106,7 +105,6 @@ function getMetaMetricsController({
|
|||||||
initState: {
|
initState: {
|
||||||
participateInMetaMetrics,
|
participateInMetaMetrics,
|
||||||
metaMetricsId,
|
metaMetricsId,
|
||||||
metaMetricsSendCount,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -198,14 +196,6 @@ describe('MetaMetricsController', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setMetaMetricsSendCount', function () {
|
|
||||||
it('should update the send count in state', function () {
|
|
||||||
const metaMetricsController = getMetaMetricsController();
|
|
||||||
metaMetricsController.setMetaMetricsSendCount(1);
|
|
||||||
assert.equal(metaMetricsController.state.metaMetricsSendCount, 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('trackEvent', function () {
|
describe('trackEvent', function () {
|
||||||
it('should not track an event if user is not participating in metametrics', function () {
|
it('should not track an event if user is not participating in metametrics', function () {
|
||||||
const mock = sinon.mock(segment);
|
const mock = sinon.mock(segment);
|
||||||
@ -337,61 +327,6 @@ describe('MetaMetricsController', function () {
|
|||||||
mock.verify();
|
mock.verify();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use anonymousId when metametrics send count is not trackable in send flow', function () {
|
|
||||||
const mock = sinon.mock(segment);
|
|
||||||
const metaMetricsController = getMetaMetricsController({
|
|
||||||
metaMetricsSendCount: 1,
|
|
||||||
});
|
|
||||||
mock
|
|
||||||
.expects('track')
|
|
||||||
.once()
|
|
||||||
.withArgs({
|
|
||||||
event: 'Send Fake Event',
|
|
||||||
anonymousId: METAMETRICS_ANONYMOUS_ID,
|
|
||||||
context: DEFAULT_TEST_CONTEXT,
|
|
||||||
properties: {
|
|
||||||
test: 1,
|
|
||||||
...DEFAULT_EVENT_PROPERTIES,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
metaMetricsController.trackEvent({
|
|
||||||
event: 'Send Fake Event',
|
|
||||||
category: 'Unit Test',
|
|
||||||
properties: {
|
|
||||||
test: 1,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use user metametrics id when metametrics send count is trackable in send flow', function () {
|
|
||||||
const mock = sinon.mock(segment);
|
|
||||||
const metaMetricsController = getMetaMetricsController();
|
|
||||||
mock
|
|
||||||
.expects('track')
|
|
||||||
.once()
|
|
||||||
.withArgs({
|
|
||||||
event: 'Send Fake Event',
|
|
||||||
userId: TEST_META_METRICS_ID,
|
|
||||||
context: DEFAULT_TEST_CONTEXT,
|
|
||||||
properties: {
|
|
||||||
test: 1,
|
|
||||||
...DEFAULT_EVENT_PROPERTIES,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
metaMetricsController.trackEvent(
|
|
||||||
{
|
|
||||||
event: 'Send Fake Event',
|
|
||||||
category: 'Unit Test',
|
|
||||||
properties: {
|
|
||||||
test: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ metaMetricsSendCount: 0 },
|
|
||||||
);
|
|
||||||
mock.verify();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should immediately flush queue if flushImmediately set to true', async function () {
|
it('should immediately flush queue if flushImmediately set to true', async function () {
|
||||||
const metaMetricsController = getMetaMetricsController();
|
const metaMetricsController = getMetaMetricsController();
|
||||||
const flushStub = sinon.stub(segment, 'flush');
|
const flushStub = sinon.stub(segment, 'flush');
|
||||||
|
@ -285,7 +285,7 @@ export default class PreferencesController {
|
|||||||
*/
|
*/
|
||||||
syncAddresses(addresses) {
|
syncAddresses(addresses) {
|
||||||
if (!Array.isArray(addresses) || addresses.length === 0) {
|
if (!Array.isArray(addresses) || addresses.length === 0) {
|
||||||
throw new Error('Expected non-empty array of addresses.');
|
throw new Error('Expected non-empty array of addresses. Error #11201');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { identities, lostIdentities } = this.store.getState();
|
const { identities, lostIdentities } = this.store.getState();
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
} from '../../../../shared/constants/transaction';
|
} from '../../../../shared/constants/transaction';
|
||||||
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
||||||
import { GAS_LIMITS } from '../../../../shared/constants/gas';
|
import { GAS_LIMITS } from '../../../../shared/constants/gas';
|
||||||
|
import { isEIP1559Transaction } from '../../../../shared/modules/transaction.utils';
|
||||||
import TransactionStateManager from './tx-state-manager';
|
import TransactionStateManager from './tx-state-manager';
|
||||||
import TxGasUtil from './tx-gas-utils';
|
import TxGasUtil from './tx-gas-utils';
|
||||||
import PendingTransactionTracker from './pending-tx-tracker';
|
import PendingTransactionTracker from './pending-tx-tracker';
|
||||||
@ -33,6 +34,14 @@ const hstInterface = new ethers.utils.Interface(abi);
|
|||||||
|
|
||||||
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
|
const MAX_MEMSTORE_TX_LIST_SIZE = 100; // Number of transactions (by unique nonces) to keep in memory
|
||||||
|
|
||||||
|
export const TRANSACTION_EVENTS = {
|
||||||
|
ADDED: 'Transaction Added',
|
||||||
|
APPROVED: 'Transaction Approved',
|
||||||
|
FINALIZED: 'Transaction Finalized',
|
||||||
|
REJECTED: 'Transaction Rejected',
|
||||||
|
SUBMITTED: 'Transaction Submitted',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Transaction Controller is an aggregate of sub-controllers and trackers
|
Transaction Controller is an aggregate of sub-controllers and trackers
|
||||||
composing them in a way to be exposed to the metamask controller
|
composing them in a way to be exposed to the metamask controller
|
||||||
@ -153,6 +162,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
addTransaction(txMeta) {
|
addTransaction(txMeta) {
|
||||||
this.txStateManager.addTransaction(txMeta);
|
this.txStateManager.addTransaction(txMeta);
|
||||||
this.emit(`${txMeta.id}:unapproved`, txMeta);
|
this.emit(`${txMeta.id}:unapproved`, txMeta);
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.ADDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -532,12 +542,13 @@ export default class TransactionController extends EventEmitter {
|
|||||||
// sign transaction
|
// sign transaction
|
||||||
const rawTx = await this.signTransaction(txId);
|
const rawTx = await this.signTransaction(txId);
|
||||||
await this.publishTransaction(txId, rawTx);
|
await this.publishTransaction(txId, rawTx);
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.APPROVED);
|
||||||
// must set transaction to submitted/failed before releasing lock
|
// must set transaction to submitted/failed before releasing lock
|
||||||
nonceLock.releaseLock();
|
nonceLock.releaseLock();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// this is try-catch wrapped so that we can guarantee that the nonceLock is released
|
// this is try-catch wrapped so that we can guarantee that the nonceLock is released
|
||||||
try {
|
try {
|
||||||
this.txStateManager.setTxStatusFailed(txId, err);
|
this._failTransaction(txId, err);
|
||||||
} catch (err2) {
|
} catch (err2) {
|
||||||
log.error(err2);
|
log.error(err2);
|
||||||
}
|
}
|
||||||
@ -615,6 +626,8 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this.setTxHash(txId, txHash);
|
this.setTxHash(txId, txHash);
|
||||||
|
|
||||||
this.txStateManager.setTxStatusSubmitted(txId);
|
this.txStateManager.setTxStatusSubmitted(txId);
|
||||||
|
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.SUBMITTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -647,6 +660,29 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this.txStateManager.setTxStatusConfirmed(txId);
|
this.txStateManager.setTxStatusConfirmed(txId);
|
||||||
this._markNonceDuplicatesDropped(txId);
|
this._markNonceDuplicatesDropped(txId);
|
||||||
|
|
||||||
|
const { submittedTime } = txMeta;
|
||||||
|
const { blockNumber } = txReceipt;
|
||||||
|
const metricsParams = { gas_used: gasUsed };
|
||||||
|
const completionTime = await this._getTransactionCompletionTime(
|
||||||
|
blockNumber,
|
||||||
|
submittedTime,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (completionTime) {
|
||||||
|
metricsParams.completion_time = completionTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txReceipt.status === '0x0') {
|
||||||
|
metricsParams.status = 'failed on-chain';
|
||||||
|
// metricsParams.error = TODO: figure out a way to get the on-chain failure reason
|
||||||
|
}
|
||||||
|
|
||||||
|
this._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
metricsParams,
|
||||||
|
);
|
||||||
|
|
||||||
this.txStateManager.updateTransaction(
|
this.txStateManager.updateTransaction(
|
||||||
txMeta,
|
txMeta,
|
||||||
'transactions#confirmTransaction - add txReceipt',
|
'transactions#confirmTransaction - add txReceipt',
|
||||||
@ -680,7 +716,9 @@ export default class TransactionController extends EventEmitter {
|
|||||||
@returns {Promise<void>}
|
@returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async cancelTransaction(txId) {
|
async cancelTransaction(txId) {
|
||||||
|
const txMeta = this.txStateManager.getTransaction(txId);
|
||||||
this.txStateManager.setTxStatusRejected(txId);
|
this.txStateManager.setTxStatusRejected(txId);
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -763,7 +801,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
txMeta,
|
txMeta,
|
||||||
'failed to estimate gas during boot cleanup.',
|
'failed to estimate gas during boot cleanup.',
|
||||||
);
|
);
|
||||||
this.txStateManager.setTxStatusFailed(txMeta.id, error);
|
this._failTransaction(txMeta.id, error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -777,7 +815,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
const txSignError = new Error(
|
const txSignError = new Error(
|
||||||
'Transaction found as "approved" during boot - possibly stuck during signing',
|
'Transaction found as "approved" during boot - possibly stuck during signing',
|
||||||
);
|
);
|
||||||
this.txStateManager.setTxStatusFailed(txMeta.id, txSignError);
|
this._failTransaction(txMeta.id, txSignError);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,17 +835,15 @@ export default class TransactionController extends EventEmitter {
|
|||||||
'transactions/pending-tx-tracker#event: tx:warning',
|
'transactions/pending-tx-tracker#event: tx:warning',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.pendingTxTracker.on(
|
this.pendingTxTracker.on('tx:failed', (txId, error) => {
|
||||||
'tx:failed',
|
this._failTransaction(txId, error);
|
||||||
this.txStateManager.setTxStatusFailed.bind(this.txStateManager),
|
});
|
||||||
);
|
|
||||||
this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) =>
|
this.pendingTxTracker.on('tx:confirmed', (txId, transactionReceipt) =>
|
||||||
this.confirmTransaction(txId, transactionReceipt),
|
this.confirmTransaction(txId, transactionReceipt),
|
||||||
);
|
);
|
||||||
this.pendingTxTracker.on(
|
this.pendingTxTracker.on('tx:dropped', (txId) => {
|
||||||
'tx:dropped',
|
this._dropTransaction(txId);
|
||||||
this.txStateManager.setTxStatusDropped.bind(this.txStateManager),
|
});
|
||||||
);
|
|
||||||
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
|
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
|
||||||
if (!txMeta.firstRetryBlockNumber) {
|
if (!txMeta.firstRetryBlockNumber) {
|
||||||
txMeta.firstRetryBlockNumber = latestBlockNumber;
|
txMeta.firstRetryBlockNumber = latestBlockNumber;
|
||||||
@ -917,7 +953,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
txMeta,
|
txMeta,
|
||||||
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
|
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
|
||||||
);
|
);
|
||||||
this.txStateManager.setTxStatusDropped(otherTxMeta.id);
|
this._dropTransaction(otherTxMeta.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,4 +1046,84 @@ export default class TransactionController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts relevant properties from a transaction meta
|
||||||
|
* object and uses them to create and send metrics for various transaction
|
||||||
|
* events.
|
||||||
|
* @param {Object} txMeta - the txMeta object
|
||||||
|
* @param {string} event - the name of the transaction event
|
||||||
|
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
|
||||||
|
*/
|
||||||
|
_trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
time,
|
||||||
|
status,
|
||||||
|
chainId,
|
||||||
|
origin: referrer,
|
||||||
|
txParams: { gasPrice, gas: gasLimit, maxFeePerGas, maxPriorityFeePerGas },
|
||||||
|
metamaskNetworkId: network,
|
||||||
|
} = txMeta;
|
||||||
|
const source = referrer === 'metamask' ? 'user' : 'dapp';
|
||||||
|
|
||||||
|
const gasParams = {};
|
||||||
|
|
||||||
|
if (isEIP1559Transaction(txMeta)) {
|
||||||
|
gasParams.max_fee_per_gas = maxFeePerGas;
|
||||||
|
gasParams.max_priority_fee_per_gas = maxPriorityFeePerGas;
|
||||||
|
} else {
|
||||||
|
gasParams.gas_price = gasPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._trackMetaMetricsEvent({
|
||||||
|
event,
|
||||||
|
category: 'Transactions',
|
||||||
|
sensitiveProperties: {
|
||||||
|
type,
|
||||||
|
status,
|
||||||
|
referrer,
|
||||||
|
source,
|
||||||
|
network,
|
||||||
|
chain_id: chainId,
|
||||||
|
transaction_envelope_type: isEIP1559Transaction(txMeta)
|
||||||
|
? 'fee-market'
|
||||||
|
: 'legacy',
|
||||||
|
first_seen: time,
|
||||||
|
gas_limit: gasLimit,
|
||||||
|
...gasParams,
|
||||||
|
...extraParams,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getTransactionCompletionTime(blockNumber, submittedTime) {
|
||||||
|
const transactionBlock = await this.query.getBlockByNumber(
|
||||||
|
blockNumber.toString(16),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!transactionBlock) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BigNumber(transactionBlock.timestamp, 10)
|
||||||
|
.minus(submittedTime / 1000)
|
||||||
|
.round()
|
||||||
|
.toString(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
_failTransaction(txId, error) {
|
||||||
|
this.txStateManager.setTxStatusFailed(txId, error);
|
||||||
|
const txMeta = this.txStateManager.getTransaction(txId);
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED, {
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_dropTransaction(txId) {
|
||||||
|
this.txStateManager.setTxStatusDropped(txId);
|
||||||
|
const txMeta = this.txStateManager.getTransaction(txId);
|
||||||
|
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import {
|
|||||||
} from '../../../../shared/constants/transaction';
|
} from '../../../../shared/constants/transaction';
|
||||||
import { SECOND } from '../../../../shared/constants/time';
|
import { SECOND } from '../../../../shared/constants/time';
|
||||||
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
||||||
import TransactionController from '.';
|
import TransactionController, { TRANSACTION_EVENTS } from '.';
|
||||||
|
|
||||||
const noop = () => true;
|
const noop = () => true;
|
||||||
const currentNetworkId = '42';
|
const currentNetworkId = '42';
|
||||||
@ -56,6 +56,7 @@ describe('Transaction Controller', function () {
|
|||||||
getPermittedAccounts: () => undefined,
|
getPermittedAccounts: () => undefined,
|
||||||
getCurrentChainId: () => currentChainId,
|
getCurrentChainId: () => currentChainId,
|
||||||
getParticipateInMetrics: () => false,
|
getParticipateInMetrics: () => false,
|
||||||
|
trackMetaMetricsEvent: () => undefined,
|
||||||
});
|
});
|
||||||
txController.nonceTracker.getNonceLock = () =>
|
txController.nonceTracker.getNonceLock = () =>
|
||||||
Promise.resolve({ nextNonce: 0, releaseLock: noop });
|
Promise.resolve({ nextNonce: 0, releaseLock: noop });
|
||||||
@ -414,6 +415,19 @@ describe('Transaction Controller', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#addTransaction', function () {
|
describe('#addTransaction', function () {
|
||||||
|
let trackTransactionMetricsEventSpy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
trackTransactionMetricsEventSpy = sinon.spy(
|
||||||
|
txController,
|
||||||
|
'_trackTransactionMetricsEvent',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
trackTransactionMetricsEventSpy.restore();
|
||||||
|
});
|
||||||
|
|
||||||
it('should emit updates', function (done) {
|
it('should emit updates', function (done) {
|
||||||
const txMeta = {
|
const txMeta = {
|
||||||
id: '1',
|
id: '1',
|
||||||
@ -451,6 +465,38 @@ describe('Transaction Controller', function () {
|
|||||||
.catch(done);
|
.catch(done);
|
||||||
txController.addTransaction(txMeta);
|
txController.addTransaction(txMeta);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call _trackTransactionMetricsEvent with the correct params', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
gasPrice: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: 'sentEther',
|
||||||
|
transaction_envelope_type: 'legacy',
|
||||||
|
origin: 'metamask',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
|
||||||
|
txController.addTransaction(txMeta);
|
||||||
|
|
||||||
|
assert.equal(trackTransactionMetricsEventSpy.callCount, 1);
|
||||||
|
assert.deepEqual(
|
||||||
|
trackTransactionMetricsEventSpy.getCall(0).args[0],
|
||||||
|
txMeta,
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
trackTransactionMetricsEventSpy.getCall(0).args[1],
|
||||||
|
TRANSACTION_EVENTS.ADDED,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#approveTransaction', function () {
|
describe('#approveTransaction', function () {
|
||||||
@ -723,7 +769,8 @@ describe('Transaction Controller', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('#publishTransaction', function () {
|
describe('#publishTransaction', function () {
|
||||||
let hash, txMeta;
|
let hash, txMeta, trackTransactionMetricsEventSpy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
hash =
|
hash =
|
||||||
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
|
'0x2a5523c6fa98b47b7d9b6c8320179785150b42a16bcff36b398c5062b65657e8';
|
||||||
@ -731,12 +778,21 @@ describe('Transaction Controller', function () {
|
|||||||
id: 1,
|
id: 1,
|
||||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
txParams: {
|
txParams: {
|
||||||
|
gas: '0x7b0d',
|
||||||
to: VALID_ADDRESS,
|
to: VALID_ADDRESS,
|
||||||
from: VALID_ADDRESS_TWO,
|
from: VALID_ADDRESS_TWO,
|
||||||
},
|
},
|
||||||
metamaskNetworkId: currentNetworkId,
|
metamaskNetworkId: currentNetworkId,
|
||||||
};
|
};
|
||||||
providerResultStub.eth_sendRawTransaction = hash;
|
providerResultStub.eth_sendRawTransaction = hash;
|
||||||
|
trackTransactionMetricsEventSpy = sinon.spy(
|
||||||
|
txController,
|
||||||
|
'_trackTransactionMetricsEvent',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
trackTransactionMetricsEventSpy.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should publish a tx, updates the rawTx when provided a one', async function () {
|
it('should publish a tx, updates the rawTx when provided a one', async function () {
|
||||||
@ -764,6 +820,22 @@ describe('Transaction Controller', function () {
|
|||||||
);
|
);
|
||||||
assert.equal(publishedTx.status, TRANSACTION_STATUSES.SUBMITTED);
|
assert.equal(publishedTx.status, TRANSACTION_STATUSES.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],
|
||||||
|
TRANSACTION_EVENTS.SUBMITTED,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#_markNonceDuplicatesDropped', function () {
|
describe('#_markNonceDuplicatesDropped', function () {
|
||||||
@ -1105,4 +1177,213 @@ describe('Transaction Controller', function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#_trackTransactionMetricsEvent', function () {
|
||||||
|
let trackMetaMetricsEventSpy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
trackMetaMetricsEventSpy = sinon.spy(
|
||||||
|
txController,
|
||||||
|
'_trackMetaMetricsEvent',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
trackMetaMetricsEventSpy.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call _trackMetaMetricsEvent with the correct payload (user source)', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
gasPrice: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: 'sentEther',
|
||||||
|
origin: 'metamask',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
const expectedPayload = {
|
||||||
|
event: 'Transaction Added',
|
||||||
|
category: 'Transactions',
|
||||||
|
sensitiveProperties: {
|
||||||
|
chain_id: '0x2a',
|
||||||
|
gas_price: '0x77359400',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: 'legacy',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'metamask',
|
||||||
|
source: 'user',
|
||||||
|
status: 'unapproved',
|
||||||
|
type: 'sentEther',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.ADDED,
|
||||||
|
);
|
||||||
|
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
||||||
|
assert.deepEqual(
|
||||||
|
trackMetaMetricsEventSpy.getCall(0).args[0],
|
||||||
|
expectedPayload,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call _trackMetaMetricsEvent with the correct payload (dapp source)', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
gasPrice: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: 'sentEther',
|
||||||
|
origin: 'other',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
const expectedPayload = {
|
||||||
|
event: 'Transaction Added',
|
||||||
|
category: 'Transactions',
|
||||||
|
sensitiveProperties: {
|
||||||
|
chain_id: '0x2a',
|
||||||
|
gas_price: '0x77359400',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: 'legacy',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'other',
|
||||||
|
source: 'dapp',
|
||||||
|
status: 'unapproved',
|
||||||
|
type: 'sentEther',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.ADDED,
|
||||||
|
);
|
||||||
|
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
||||||
|
assert.deepEqual(
|
||||||
|
trackMetaMetricsEventSpy.getCall(0).args[0],
|
||||||
|
expectedPayload,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
gasPrice: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: 'sentEther',
|
||||||
|
origin: 'other',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
const expectedPayload = {
|
||||||
|
event: 'Transaction Added',
|
||||||
|
category: 'Transactions',
|
||||||
|
sensitiveProperties: {
|
||||||
|
baz: 3.0,
|
||||||
|
foo: 'bar',
|
||||||
|
chain_id: '0x2a',
|
||||||
|
gas_price: '0x77359400',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: 'legacy',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'other',
|
||||||
|
source: 'dapp',
|
||||||
|
status: 'unapproved',
|
||||||
|
type: 'sentEther',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.ADDED,
|
||||||
|
{
|
||||||
|
baz: 3.0,
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
||||||
|
assert.deepEqual(
|
||||||
|
trackMetaMetricsEventSpy.getCall(0).args[0],
|
||||||
|
expectedPayload,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call _trackMetaMetricsEvent with the correct payload (EIP-1559)', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
maxFeePerGas: '0x77359400',
|
||||||
|
maxPriorityFeePerGas: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: 'sentEther',
|
||||||
|
origin: 'other',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
const expectedPayload = {
|
||||||
|
event: 'Transaction Added',
|
||||||
|
category: 'Transactions',
|
||||||
|
sensitiveProperties: {
|
||||||
|
baz: 3.0,
|
||||||
|
foo: 'bar',
|
||||||
|
chain_id: '0x2a',
|
||||||
|
max_fee_per_gas: '0x77359400',
|
||||||
|
max_priority_fee_per_gas: '0x77359400',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: 'fee-market',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'other',
|
||||||
|
source: 'dapp',
|
||||||
|
status: 'unapproved',
|
||||||
|
type: 'sentEther',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.ADDED,
|
||||||
|
{
|
||||||
|
baz: 3.0,
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
||||||
|
assert.deepEqual(
|
||||||
|
trackMetaMetricsEventSpy.getCall(0).args[0],
|
||||||
|
expectedPayload,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -36,7 +36,6 @@ export const SENTRY_STATE = {
|
|||||||
isInitialized: true,
|
isInitialized: true,
|
||||||
isUnlocked: true,
|
isUnlocked: true,
|
||||||
metaMetricsId: true,
|
metaMetricsId: true,
|
||||||
metaMetricsSendCount: true,
|
|
||||||
nativeCurrency: true,
|
nativeCurrency: true,
|
||||||
network: true,
|
network: true,
|
||||||
nextNonce: true,
|
nextNonce: true,
|
||||||
|
@ -676,7 +676,6 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
setUsePhishDetect: this.setUsePhishDetect.bind(this),
|
setUsePhishDetect: this.setUsePhishDetect.bind(this),
|
||||||
setIpfsGateway: this.setIpfsGateway.bind(this),
|
setIpfsGateway: this.setIpfsGateway.bind(this),
|
||||||
setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this),
|
setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this),
|
||||||
setMetaMetricsSendCount: this.setMetaMetricsSendCount.bind(this),
|
|
||||||
setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this),
|
setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this),
|
||||||
setCurrentLocale: this.setCurrentLocale.bind(this),
|
setCurrentLocale: this.setCurrentLocale.bind(this),
|
||||||
markPasswordForgotten: this.markPasswordForgotten.bind(this),
|
markPasswordForgotten: this.markPasswordForgotten.bind(this),
|
||||||
@ -2760,18 +2759,6 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setMetaMetricsSendCount(val, cb) {
|
|
||||||
try {
|
|
||||||
this.metaMetricsController.setMetaMetricsSendCount(val);
|
|
||||||
cb(null);
|
|
||||||
return;
|
|
||||||
} catch (err) {
|
|
||||||
cb(err);
|
|
||||||
// eslint-disable-next-line no-useless-return
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the type of first time flow the user wishes to follow: create or import
|
* Sets the type of first time flow the user wishes to follow: create or import
|
||||||
* @param {string} type - Indicates the type of first time flow the user wishes to follow
|
* @param {string} type - Indicates the type of first time flow the user wishes to follow
|
||||||
|
28
app/scripts/migrations/062.js
Normal file
28
app/scripts/migrations/062.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
|
const version = 62;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes metaMetricsSendCount from MetaMetrics controller
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
version,
|
||||||
|
async migrate(originalVersionedData) {
|
||||||
|
const versionedData = cloneDeep(originalVersionedData);
|
||||||
|
versionedData.meta.version = version;
|
||||||
|
const state = versionedData.data;
|
||||||
|
const newState = transformState(state);
|
||||||
|
versionedData.data = newState;
|
||||||
|
return versionedData;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function transformState(state) {
|
||||||
|
if (state.MetaMetricsController) {
|
||||||
|
const { metaMetricsSendCount } = state.MetaMetricsController;
|
||||||
|
if (metaMetricsSendCount !== undefined) {
|
||||||
|
delete state.MetaMetricsController.metaMetricsSendCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
80
app/scripts/migrations/062.test.js
Normal file
80
app/scripts/migrations/062.test.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import migration62 from './062';
|
||||||
|
|
||||||
|
describe('migration #62', function () {
|
||||||
|
it('should update the version metadata', async function () {
|
||||||
|
const oldStorage = {
|
||||||
|
meta: {
|
||||||
|
version: 61,
|
||||||
|
},
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const newStorage = await migration62.migrate(oldStorage);
|
||||||
|
assert.deepEqual(newStorage.meta, {
|
||||||
|
version: 62,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove metaMetricsSendCount from MetaMetricsController', async function () {
|
||||||
|
const oldStorage = {
|
||||||
|
meta: {},
|
||||||
|
data: {
|
||||||
|
MetaMetricsController: {
|
||||||
|
metaMetricsSendCount: 1,
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const newStorage = await migration62.migrate(oldStorage);
|
||||||
|
assert.deepStrictEqual(newStorage.data, {
|
||||||
|
MetaMetricsController: {
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove metaMetricsSendCount from MetaMetricsController (falsey but defined)', async function () {
|
||||||
|
const oldStorage = {
|
||||||
|
meta: {},
|
||||||
|
data: {
|
||||||
|
MetaMetricsController: {
|
||||||
|
metaMetricsSendCount: 0,
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const newStorage = await migration62.migrate(oldStorage);
|
||||||
|
assert.deepStrictEqual(newStorage.data, {
|
||||||
|
MetaMetricsController: {
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not modify MetaMetricsController when metaMetricsSendCount is undefined', async function () {
|
||||||
|
const oldStorage = {
|
||||||
|
meta: {},
|
||||||
|
data: {
|
||||||
|
MetaMetricsController: {
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const newStorage = await migration62.migrate(oldStorage);
|
||||||
|
assert.deepStrictEqual(newStorage.data, {
|
||||||
|
MetaMetricsController: {
|
||||||
|
bar: 'baz',
|
||||||
|
},
|
||||||
|
foo: 'bar',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -66,6 +66,7 @@ const migrations = [
|
|||||||
require('./059').default,
|
require('./059').default,
|
||||||
require('./060').default,
|
require('./060').default,
|
||||||
require('./061').default,
|
require('./061').default,
|
||||||
|
require('./062').default,
|
||||||
];
|
];
|
||||||
|
|
||||||
export default migrations;
|
export default migrations;
|
||||||
|
@ -13,5 +13,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
setupFiles: ['./test/setup.js', './test/env.js'],
|
setupFiles: ['./test/setup.js', './test/env.js'],
|
||||||
setupFilesAfterEnv: ['./test/jest/setup.js'],
|
setupFilesAfterEnv: ['./test/jest/setup.js'],
|
||||||
testMatch: ['**/ui/**/?(*.)+(test).js'],
|
testMatch: [
|
||||||
|
'<rootDir>/ui/**/?(*.)+(test).js',
|
||||||
|
'<rootDir>/shared/**/?(*.)+(test).js',
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "metamask-crx",
|
"name": "metamask-crx",
|
||||||
"version": "9.7.0",
|
"version": "9.7.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -23,13 +23,13 @@
|
|||||||
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
|
"dapp-chain": "GANACHE_ARGS='-b 2' concurrently -k -n ganache,dapp -p '[{time}][{name}]' 'yarn ganache:start' 'sleep 5 && yarn dapp'",
|
||||||
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010",
|
"forwarder": "node ./development/static-server.js ./node_modules/@metamask/forwarder/dist/ --port 9010",
|
||||||
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'",
|
"dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'",
|
||||||
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './{app,shared}/**/*.test.js'",
|
"test:unit": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/**/*.test.js'",
|
||||||
"test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js",
|
"test:unit:global": "mocha --exit --require test/env.js --require test/setup.js --recursive test/unit-global/*.test.js",
|
||||||
"test:unit:jest": "jest",
|
"test:unit:jest": "jest",
|
||||||
"test:unit:jest:watch": "jest --watch",
|
"test:unit:jest:watch": "jest --watch",
|
||||||
"test:unit:jest:watch:silent": "jest --watch --silent",
|
"test:unit:jest:watch:silent": "jest --watch --silent",
|
||||||
"test:unit:jest:ci": "jest --maxWorkers=2",
|
"test:unit:jest:ci": "jest --maxWorkers=2",
|
||||||
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --recursive './{app,shared}/**/*.test.js'",
|
"test:unit:lax": "mocha --exit --require test/env.js --require test/setup.js --ignore './app/scripts/controllers/permissions/*.test.js' --recursive './app/**/*.test.js'",
|
||||||
"test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/scripts/controllers/permissions/*.test.js'",
|
"test:unit:strict": "mocha --exit --require test/env.js --require test/setup.js --recursive './app/scripts/controllers/permissions/*.test.js'",
|
||||||
"test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive",
|
"test:unit:path": "mocha --exit --require test/env.js --require test/setup.js --recursive",
|
||||||
"test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/run-all.sh",
|
"test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/run-all.sh",
|
||||||
@ -53,7 +53,7 @@
|
|||||||
"verify-locales": "node ./development/verify-locale-strings.js",
|
"verify-locales": "node ./development/verify-locale-strings.js",
|
||||||
"verify-locales:fix": "node ./development/verify-locale-strings.js --fix",
|
"verify-locales:fix": "node ./development/verify-locale-strings.js --fix",
|
||||||
"mozilla-lint": "addons-linter dist/firefox",
|
"mozilla-lint": "addons-linter dist/firefox",
|
||||||
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/**/*.test.js\" \"shared/**/*.test.js\"",
|
"watch": "mocha --watch --require test/env.js --require test/setup.js --reporter min --recursive \"test/unit/**/*.js\" \"ui/**/*.test.js\"",
|
||||||
"devtools:react": "react-devtools",
|
"devtools:react": "react-devtools",
|
||||||
"devtools:redux": "remotedev --hostname=localhost --port=8000",
|
"devtools:redux": "remotedev --hostname=localhost --port=8000",
|
||||||
"start:dev": "concurrently -k -n build,react,redux yarn:start yarn:devtools:react yarn:devtools:redux",
|
"start:dev": "concurrently -k -n build,react,redux yarn:start yarn:devtools:react yarn:devtools:redux",
|
||||||
|
@ -1,6 +1,40 @@
|
|||||||
|
import { isHexString } from 'ethereumjs-util';
|
||||||
|
|
||||||
export function transactionMatchesNetwork(transaction, chainId, networkId) {
|
export function transactionMatchesNetwork(transaction, chainId, networkId) {
|
||||||
if (typeof transaction.chainId !== 'undefined') {
|
if (typeof transaction.chainId !== 'undefined') {
|
||||||
return transaction.chainId === chainId;
|
return transaction.chainId === chainId;
|
||||||
}
|
}
|
||||||
return transaction.metamaskNetworkId === networkId;
|
return transaction.metamaskNetworkId === networkId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the maxFeePerGas and maxPriorityFeePerGas fields are supplied
|
||||||
|
* and valid inputs. This will return false for non hex string inputs.
|
||||||
|
* @param {import("../constants/transaction").TransactionMeta} transaction -
|
||||||
|
* the transaction to check
|
||||||
|
* @returns {boolean} true if transaction uses valid EIP1559 fields
|
||||||
|
*/
|
||||||
|
export function isEIP1559Transaction(transaction) {
|
||||||
|
return (
|
||||||
|
isHexString(transaction.txParams.maxFeePerGas) &&
|
||||||
|
isHexString(transaction.txParams.maxPriorityFeePerGas)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the maxFeePerGas and maxPriorityFeePerGas fields are not
|
||||||
|
* supplied and that the gasPrice field is valid if it is provided. This will
|
||||||
|
* return false if gasPrice is a non hex string.
|
||||||
|
* @param {import("../constants/transaction").TransactionMeta} transaction -
|
||||||
|
* the transaction to check
|
||||||
|
* @returns {boolean} true if transaction uses valid Legacy fields OR lacks
|
||||||
|
* EIP1559 fields
|
||||||
|
*/
|
||||||
|
export function isLegacyTransaction(transaction) {
|
||||||
|
return (
|
||||||
|
typeof transaction.txParams.maxFeePerGas === 'undefined' &&
|
||||||
|
typeof transaction.txParams.maxPriorityFeePerGas === 'undefined' &&
|
||||||
|
(typeof transaction.txParams.gasPrice === 'undefined' ||
|
||||||
|
isHexString(transaction.txParams.gasPrice))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
83
shared/modules/transaction.utils.test.js
Normal file
83
shared/modules/transaction.utils.test.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { isEIP1559Transaction, isLegacyTransaction } from './transaction.utils';
|
||||||
|
|
||||||
|
describe('Transaction.utils', function () {
|
||||||
|
describe('isEIP1559Transaction', function () {
|
||||||
|
it('should return true if both maxFeePerGas and maxPriorityFeePerGas are hex strings', () => {
|
||||||
|
expect(
|
||||||
|
isEIP1559Transaction({
|
||||||
|
txParams: { maxFeePerGas: '0x1', maxPriorityFeePerGas: '0x1' },
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if either maxFeePerGas and maxPriorityFeePerGas are non-hex strings', () => {
|
||||||
|
expect(
|
||||||
|
isEIP1559Transaction({
|
||||||
|
txParams: { maxFeePerGas: 0, maxPriorityFeePerGas: '0x1' },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
isEIP1559Transaction({
|
||||||
|
txParams: { maxFeePerGas: '0x1', maxPriorityFeePerGas: 'fail' },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if either maxFeePerGas or maxPriorityFeePerGas are not supplied', () => {
|
||||||
|
expect(
|
||||||
|
isEIP1559Transaction({
|
||||||
|
txParams: { maxPriorityFeePerGas: '0x1' },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
expect(
|
||||||
|
isEIP1559Transaction({
|
||||||
|
txParams: { maxFeePerGas: '0x1' },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isLegacyTransaction', function () {
|
||||||
|
it('should return true if no gas related fields are supplied', () => {
|
||||||
|
expect(
|
||||||
|
isLegacyTransaction({
|
||||||
|
txParams: {},
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true if gasPrice is solely provided', () => {
|
||||||
|
expect(
|
||||||
|
isLegacyTransaction({
|
||||||
|
txParams: { gasPrice: '0x1' },
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if gasPrice is not a hex string', () => {
|
||||||
|
expect(
|
||||||
|
isLegacyTransaction({
|
||||||
|
txParams: { gasPrice: 100 },
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false if either maxFeePerGas or maxPriorityFeePerGas are supplied', () => {
|
||||||
|
expect(
|
||||||
|
isLegacyTransaction({
|
||||||
|
txParams: {
|
||||||
|
maxFeePerGas: '0x1',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
isLegacyTransaction({
|
||||||
|
txParams: {
|
||||||
|
maxPriorityFeePerGas: 'any data',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -128,7 +128,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
|
@ -138,7 +138,6 @@
|
|||||||
},
|
},
|
||||||
"completedOnboarding": true,
|
"completedOnboarding": true,
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"ipfsGateway": "dweb.link",
|
"ipfsGateway": "dweb.link",
|
||||||
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
|
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
|
||||||
},
|
},
|
||||||
|
@ -129,7 +129,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
|
@ -121,7 +121,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
|
@ -125,8 +125,7 @@
|
|||||||
},
|
},
|
||||||
"MetaMetricsController": {
|
"MetaMetricsController": {
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null
|
||||||
"metaMetricsSendCount": 1
|
|
||||||
},
|
},
|
||||||
"PermissionsController": {
|
"PermissionsController": {
|
||||||
"permissionsRequests": [],
|
"permissionsRequests": [],
|
||||||
|
@ -114,7 +114,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
|
@ -114,7 +114,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"showFiatInTestnets": true,
|
"showFiatInTestnets": true,
|
||||||
|
@ -138,7 +138,6 @@
|
|||||||
},
|
},
|
||||||
"completedOnboarding": true,
|
"completedOnboarding": true,
|
||||||
"metaMetricsId": "fake-metrics-id",
|
"metaMetricsId": "fake-metrics-id",
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"ipfsGateway": "dweb.link",
|
"ipfsGateway": "dweb.link",
|
||||||
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
|
"selectedAddress": "0x5cfe73b6021e818b776b421b1c4db2474086a7e1"
|
||||||
},
|
},
|
||||||
|
@ -115,7 +115,6 @@
|
|||||||
"knownMethodData": {},
|
"knownMethodData": {},
|
||||||
"lostIdentities": {},
|
"lostIdentities": {},
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"metaMetricsSendCount": 0,
|
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false,
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
"useNativeCurrencyAsPrimaryCurrency": true
|
||||||
|
@ -120,8 +120,7 @@
|
|||||||
},
|
},
|
||||||
"MetaMetricsController": {
|
"MetaMetricsController": {
|
||||||
"metaMetricsId": null,
|
"metaMetricsId": null,
|
||||||
"participateInMetaMetrics": false,
|
"participateInMetaMetrics": false
|
||||||
"metaMetricsSendCount": 0
|
|
||||||
},
|
},
|
||||||
"ThreeBoxController": {
|
"ThreeBoxController": {
|
||||||
"threeBoxSyncingAllowed": true,
|
"threeBoxSyncingAllowed": true,
|
||||||
|
@ -41,6 +41,7 @@ import {
|
|||||||
getAveragePriceEstimateInHexWEI,
|
getAveragePriceEstimateInHexWEI,
|
||||||
isCustomPriceExcessive,
|
isCustomPriceExcessive,
|
||||||
getIsGasEstimatesFetched,
|
getIsGasEstimatesFetched,
|
||||||
|
getIsCustomNetworkGasPriceFetched,
|
||||||
} from '../../../../selectors';
|
} from '../../../../selectors';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -141,13 +142,17 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
conversionRate,
|
conversionRate,
|
||||||
});
|
});
|
||||||
const isGasEstimate = getIsGasEstimatesFetched(state);
|
const isGasEstimate = getIsGasEstimatesFetched(state);
|
||||||
|
const customNetworkEstimateWasFetched = getIsCustomNetworkGasPriceFetched(
|
||||||
|
state,
|
||||||
|
);
|
||||||
|
|
||||||
let customPriceIsSafe;
|
let customPriceIsSafe = true;
|
||||||
if ((isMainnet || process.env.IN_TEST) && isGasEstimate) {
|
if ((isMainnet || process.env.IN_TEST) && isGasEstimate) {
|
||||||
customPriceIsSafe = isCustomPriceSafe(state);
|
customPriceIsSafe = isCustomPriceSafe(state);
|
||||||
} else if (isTestnet) {
|
} else if (
|
||||||
customPriceIsSafe = true;
|
!(isMainnet || process.env.IN_TEST || isTestnet) &&
|
||||||
} else {
|
customNetworkEstimateWasFetched
|
||||||
|
) {
|
||||||
customPriceIsSafe = isCustomPriceSafeForCustomNetwork(state);
|
customPriceIsSafe = isCustomPriceSafeForCustomNetwork(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ export default function reduceMetamask(state = {}, action) {
|
|||||||
completedOnboarding: false,
|
completedOnboarding: false,
|
||||||
knownMethodData: {},
|
knownMethodData: {},
|
||||||
participateInMetaMetrics: null,
|
participateInMetaMetrics: null,
|
||||||
metaMetricsSendCount: 0,
|
|
||||||
nextNonce: null,
|
nextNonce: null,
|
||||||
conversionRate: null,
|
conversionRate: null,
|
||||||
nativeCurrency: 'ETH',
|
nativeCurrency: 'ETH',
|
||||||
@ -126,12 +125,6 @@ export default function reduceMetamask(state = {}, action) {
|
|||||||
participateInMetaMetrics: action.value,
|
participateInMetaMetrics: action.value,
|
||||||
};
|
};
|
||||||
|
|
||||||
case actionConstants.SET_METAMETRICS_SEND_COUNT:
|
|
||||||
return {
|
|
||||||
...metamaskState,
|
|
||||||
metaMetricsSendCount: action.value,
|
|
||||||
};
|
|
||||||
|
|
||||||
case actionConstants.SET_USE_BLOCKIE:
|
case actionConstants.SET_USE_BLOCKIE:
|
||||||
return {
|
return {
|
||||||
...metamaskState,
|
...metamaskState,
|
||||||
|
@ -86,8 +86,6 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
hideSubtitle: PropTypes.bool,
|
hideSubtitle: PropTypes.bool,
|
||||||
identiconAddress: PropTypes.string,
|
identiconAddress: PropTypes.string,
|
||||||
onEdit: PropTypes.func,
|
onEdit: PropTypes.func,
|
||||||
setMetaMetricsSendCount: PropTypes.func,
|
|
||||||
metaMetricsSendCount: PropTypes.number,
|
|
||||||
subtitleComponent: PropTypes.node,
|
subtitleComponent: PropTypes.node,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
advancedInlineGasShown: PropTypes.bool,
|
advancedInlineGasShown: PropTypes.bool,
|
||||||
@ -475,35 +473,16 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleCancel() {
|
handleCancel() {
|
||||||
const { metricsEvent } = this.context;
|
|
||||||
const {
|
const {
|
||||||
txData,
|
txData,
|
||||||
cancelTransaction,
|
cancelTransaction,
|
||||||
history,
|
history,
|
||||||
mostRecentOverviewPage,
|
mostRecentOverviewPage,
|
||||||
clearConfirmTransaction,
|
clearConfirmTransaction,
|
||||||
actionKey,
|
|
||||||
txData: { origin },
|
|
||||||
methodData = {},
|
|
||||||
updateCustomNonce,
|
updateCustomNonce,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this._removeBeforeUnload();
|
this._removeBeforeUnload();
|
||||||
metricsEvent({
|
|
||||||
eventOpts: {
|
|
||||||
category: 'Transactions',
|
|
||||||
action: 'Confirm Screen',
|
|
||||||
name: 'Cancel',
|
|
||||||
},
|
|
||||||
customVariables: {
|
|
||||||
recipientKnown: null,
|
|
||||||
functionType:
|
|
||||||
actionKey ||
|
|
||||||
getMethodName(methodData.name) ||
|
|
||||||
TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
|
||||||
origin,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
updateCustomNonce('');
|
updateCustomNonce('');
|
||||||
cancelTransaction(txData).then(() => {
|
cancelTransaction(txData).then(() => {
|
||||||
clearConfirmTransaction();
|
clearConfirmTransaction();
|
||||||
@ -512,18 +491,12 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
const { metricsEvent } = this.context;
|
|
||||||
const {
|
const {
|
||||||
txData: { origin },
|
|
||||||
sendTransaction,
|
sendTransaction,
|
||||||
clearConfirmTransaction,
|
clearConfirmTransaction,
|
||||||
txData,
|
txData,
|
||||||
history,
|
history,
|
||||||
actionKey,
|
|
||||||
mostRecentOverviewPage,
|
mostRecentOverviewPage,
|
||||||
metaMetricsSendCount = 0,
|
|
||||||
setMetaMetricsSendCount,
|
|
||||||
methodData = {},
|
|
||||||
updateCustomNonce,
|
updateCustomNonce,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { submitting } = this.state;
|
const { submitting } = this.state;
|
||||||
@ -539,44 +512,27 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this._removeBeforeUnload();
|
this._removeBeforeUnload();
|
||||||
metricsEvent({
|
|
||||||
eventOpts: {
|
|
||||||
category: 'Transactions',
|
|
||||||
action: 'Confirm Screen',
|
|
||||||
name: 'Transaction Completed',
|
|
||||||
},
|
|
||||||
customVariables: {
|
|
||||||
recipientKnown: null,
|
|
||||||
functionType:
|
|
||||||
actionKey ||
|
|
||||||
getMethodName(methodData.name) ||
|
|
||||||
TRANSACTION_TYPES.CONTRACT_INTERACTION,
|
|
||||||
origin,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
setMetaMetricsSendCount(metaMetricsSendCount + 1).then(() => {
|
sendTransaction(txData)
|
||||||
sendTransaction(txData)
|
.then(() => {
|
||||||
.then(() => {
|
clearConfirmTransaction();
|
||||||
clearConfirmTransaction();
|
this.setState(
|
||||||
this.setState(
|
{
|
||||||
{
|
|
||||||
submitting: false,
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
history.push(mostRecentOverviewPage);
|
|
||||||
updateCustomNonce('');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.setState({
|
|
||||||
submitting: false,
|
submitting: false,
|
||||||
submitError: error.message,
|
},
|
||||||
});
|
() => {
|
||||||
updateCustomNonce('');
|
history.push(mostRecentOverviewPage);
|
||||||
|
updateCustomNonce('');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
submitting: false,
|
||||||
|
submitError: error.message,
|
||||||
});
|
});
|
||||||
});
|
updateCustomNonce('');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -643,18 +599,7 @@ export default class ConfirmTransactionBase extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_beforeUnload = () => {
|
_beforeUnload = () => {
|
||||||
const { txData: { origin, id } = {}, cancelTransaction } = this.props;
|
const { txData: { id } = {}, cancelTransaction } = this.props;
|
||||||
const { metricsEvent } = this.context;
|
|
||||||
metricsEvent({
|
|
||||||
eventOpts: {
|
|
||||||
category: 'Transactions',
|
|
||||||
action: 'Confirm Screen',
|
|
||||||
name: 'Cancel Tx Via Notification Close',
|
|
||||||
},
|
|
||||||
customVariables: {
|
|
||||||
origin,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
cancelTransaction({ id });
|
cancelTransaction({ id });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
cancelTxs,
|
cancelTxs,
|
||||||
updateAndApproveTx,
|
updateAndApproveTx,
|
||||||
showModal,
|
showModal,
|
||||||
setMetaMetricsSendCount,
|
|
||||||
updateTransaction,
|
updateTransaction,
|
||||||
getNextNonce,
|
getNextNonce,
|
||||||
tryReverseResolveAddress,
|
tryReverseResolveAddress,
|
||||||
@ -76,7 +75,6 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
assetImages,
|
assetImages,
|
||||||
network,
|
network,
|
||||||
unapprovedTxs,
|
unapprovedTxs,
|
||||||
metaMetricsSendCount,
|
|
||||||
nextNonce,
|
nextNonce,
|
||||||
provider: { chainId },
|
provider: { chainId },
|
||||||
} = metamask;
|
} = metamask;
|
||||||
@ -186,7 +184,6 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
insufficientBalance,
|
insufficientBalance,
|
||||||
hideSubtitle: !isMainnet && !showFiatInTestnets,
|
hideSubtitle: !isMainnet && !showFiatInTestnets,
|
||||||
hideFiatConversion: !isMainnet && !showFiatInTestnets,
|
hideFiatConversion: !isMainnet && !showFiatInTestnets,
|
||||||
metaMetricsSendCount,
|
|
||||||
type,
|
type,
|
||||||
nextNonce,
|
nextNonce,
|
||||||
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
mostRecentOverviewPage: getMostRecentOverviewPage(state),
|
||||||
@ -234,7 +231,6 @@ export const mapDispatchToProps = (dispatch) => {
|
|||||||
cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)),
|
cancelAllTransactions: (txList) => dispatch(cancelTxs(txList)),
|
||||||
sendTransaction: (txData) =>
|
sendTransaction: (txData) =>
|
||||||
dispatch(updateAndApproveTx(customNonceMerge(txData))),
|
dispatch(updateAndApproveTx(customNonceMerge(txData))),
|
||||||
setMetaMetricsSendCount: (val) => dispatch(setMetaMetricsSendCount(val)),
|
|
||||||
getNextNonce: () => dispatch(getNextNonce()),
|
getNextNonce: () => dispatch(getNextNonce()),
|
||||||
setDefaultHomeActiveTabName: (tabName) =>
|
setDefaultHomeActiveTabName: (tabName) =>
|
||||||
dispatch(setDefaultHomeActiveTabName(tabName)),
|
dispatch(setDefaultHomeActiveTabName(tabName)),
|
||||||
|
@ -32,11 +32,11 @@ export default class SendGasRow extends Component {
|
|||||||
|
|
||||||
static contextTypes = {
|
static contextTypes = {
|
||||||
t: PropTypes.func,
|
t: PropTypes.func,
|
||||||
metricsEvent: PropTypes.func,
|
trackEvent: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
renderAdvancedOptionsButton() {
|
renderAdvancedOptionsButton() {
|
||||||
const { metricsEvent } = this.context;
|
const { trackEvent } = this.context;
|
||||||
const {
|
const {
|
||||||
showCustomizeGasModal,
|
showCustomizeGasModal,
|
||||||
isMainnet,
|
isMainnet,
|
||||||
@ -54,12 +54,9 @@ export default class SendGasRow extends Component {
|
|||||||
<div
|
<div
|
||||||
className="advanced-gas-options-btn"
|
className="advanced-gas-options-btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
metricsEvent({
|
trackEvent({
|
||||||
eventOpts: {
|
category: 'Transactions',
|
||||||
category: 'Transactions',
|
event: 'Clicked "Advanced Options"',
|
||||||
action: 'Edit Screen',
|
|
||||||
name: 'Clicked "Advanced Options"',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
showCustomizeGasModal();
|
showCustomizeGasModal();
|
||||||
}}
|
}}
|
||||||
@ -105,7 +102,7 @@ export default class SendGasRow extends Component {
|
|||||||
isEthGasPrice,
|
isEthGasPrice,
|
||||||
noGasPrice,
|
noGasPrice,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { metricsEvent } = this.context;
|
const { trackEvent } = this.context;
|
||||||
const gasPriceFetchFailure = isEthGasPrice || noGasPrice;
|
const gasPriceFetchFailure = isEthGasPrice || noGasPrice;
|
||||||
|
|
||||||
const gasPriceButtonGroup = (
|
const gasPriceButtonGroup = (
|
||||||
@ -115,11 +112,11 @@ export default class SendGasRow extends Component {
|
|||||||
showCheck={false}
|
showCheck={false}
|
||||||
{...gasPriceButtonGroupProps}
|
{...gasPriceButtonGroupProps}
|
||||||
handleGasPriceSelection={async (opts) => {
|
handleGasPriceSelection={async (opts) => {
|
||||||
metricsEvent({
|
trackEvent({
|
||||||
eventOpts: {
|
category: 'Transactions',
|
||||||
category: 'Transactions',
|
event: 'User Clicked Gas Estimate Button',
|
||||||
action: 'Edit Screen',
|
properties: {
|
||||||
name: 'Changed Gas Button',
|
gasEstimateType: opts.gasEstimateType.toLowerCase(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await gasPriceButtonGroupProps.handleGasPriceSelection(opts);
|
await gasPriceButtonGroupProps.handleGasPriceSelection(opts);
|
||||||
|
@ -32,7 +32,7 @@ describe('SendGasRow Component', () => {
|
|||||||
anotherGasPriceButtonGroupProp: 'bar',
|
anotherGasPriceButtonGroupProp: 'bar',
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
{ context: { t: (str) => `${str}_t`, metricsEvent: () => ({}) } },
|
{ context: { t: (str) => `${str}_t`, trackEvent: () => ({}) } },
|
||||||
);
|
);
|
||||||
wrapper.setProps({ isMainnet: true });
|
wrapper.setProps({ isMainnet: true });
|
||||||
});
|
});
|
||||||
|
@ -109,6 +109,10 @@ export function isCustomPriceSafeForCustomNetwork(state) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!estimatedPrice) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const customPriceSafe = conversionGreaterThan(
|
const customPriceSafe = conversionGreaterThan(
|
||||||
{
|
{
|
||||||
value: customGasPrice,
|
value: customGasPrice,
|
||||||
@ -391,6 +395,15 @@ export function getIsEthGasPriceFetched(state) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getIsCustomNetworkGasPriceFetched(state) {
|
||||||
|
const gasState = state.gas;
|
||||||
|
return Boolean(
|
||||||
|
gasState.estimateSource === GAS_SOURCE.ETHGASPRICE &&
|
||||||
|
gasState.basicEstimateStatus === BASIC_ESTIMATE_STATES.READY &&
|
||||||
|
!getIsMainnet(state),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function getNoGasPriceFetched(state) {
|
export function getNoGasPriceFetched(state) {
|
||||||
const gasState = state.gas;
|
const gasState = state.gas;
|
||||||
return Boolean(gasState.basicEstimateStatus === BASIC_ESTIMATE_STATES.FAILED);
|
return Boolean(gasState.basicEstimateStatus === BASIC_ESTIMATE_STATES.FAILED);
|
||||||
|
@ -60,7 +60,6 @@ export const UPDATE_CUSTOM_NONCE = 'UPDATE_CUSTOM_NONCE';
|
|||||||
export const SET_IPFS_GATEWAY = 'SET_IPFS_GATEWAY';
|
export const SET_IPFS_GATEWAY = 'SET_IPFS_GATEWAY';
|
||||||
|
|
||||||
export const SET_PARTICIPATE_IN_METAMETRICS = 'SET_PARTICIPATE_IN_METAMETRICS';
|
export const SET_PARTICIPATE_IN_METAMETRICS = 'SET_PARTICIPATE_IN_METAMETRICS';
|
||||||
export const SET_METAMETRICS_SEND_COUNT = 'SET_METAMETRICS_SEND_COUNT';
|
|
||||||
|
|
||||||
// locale
|
// locale
|
||||||
export const SET_CURRENT_LOCALE = 'SET_CURRENT_LOCALE';
|
export const SET_CURRENT_LOCALE = 'SET_CURRENT_LOCALE';
|
||||||
|
@ -1968,27 +1968,6 @@ export function setParticipateInMetaMetrics(val) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setMetaMetricsSendCount(val) {
|
|
||||||
return (dispatch) => {
|
|
||||||
log.debug(`background.setMetaMetricsSendCount`);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
background.setMetaMetricsSendCount(val, (err) => {
|
|
||||||
if (err) {
|
|
||||||
dispatch(displayWarning(err.message));
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: actionConstants.SET_METAMETRICS_SEND_COUNT,
|
|
||||||
value: val,
|
|
||||||
});
|
|
||||||
resolve(val);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setUseBlockie(val) {
|
export function setUseBlockie(val) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(showLoadingIndication());
|
dispatch(showLoadingIndication());
|
||||||
|
Loading…
Reference in New Issue
Block a user