mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
implement event fragments for tx controller (#13331)
This commit is contained in:
parent
b2a9b72c04
commit
c58cc631c7
@ -148,9 +148,9 @@ export default class MetaMetricsController {
|
|||||||
/**
|
/**
|
||||||
* Create an event fragment in state and returns the event fragment object.
|
* Create an event fragment in state and returns the event fragment object.
|
||||||
*
|
*
|
||||||
* @param {MetaMetricsFunnel} options - Fragment settings and properties
|
* @param {MetaMetricsEventFragment} options - Fragment settings and properties
|
||||||
* to initiate the fragment with.
|
* to initiate the fragment with.
|
||||||
* @returns {MetaMetricsFunnel}
|
* @returns {MetaMetricsEventFragment}
|
||||||
*/
|
*/
|
||||||
createEventFragment(options) {
|
createEventFragment(options) {
|
||||||
if (!options.successEvent || !options.category) {
|
if (!options.successEvent || !options.category) {
|
||||||
@ -168,7 +168,7 @@ export default class MetaMetricsController {
|
|||||||
}
|
}
|
||||||
const { fragments } = this.store.getState();
|
const { fragments } = this.store.getState();
|
||||||
|
|
||||||
const id = generateUUID();
|
const id = options.uniqueIdentifier ?? generateUUID();
|
||||||
const fragment = {
|
const fragment = {
|
||||||
id,
|
id,
|
||||||
...options,
|
...options,
|
||||||
@ -180,6 +180,37 @@ export default class MetaMetricsController {
|
|||||||
[id]: fragment,
|
[id]: fragment,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (options.initialEvent) {
|
||||||
|
this.trackEvent({
|
||||||
|
event: fragment.initialEvent,
|
||||||
|
category: fragment.category,
|
||||||
|
properties: fragment.properties,
|
||||||
|
sensitiveProperties: fragment.sensitiveProperties,
|
||||||
|
page: fragment.page,
|
||||||
|
referrer: fragment.referrer,
|
||||||
|
revenue: fragment.revenue,
|
||||||
|
value: fragment.value,
|
||||||
|
currency: fragment.currency,
|
||||||
|
environmentType: fragment.environmentType,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fragment stored in memory with provided id or undefined if it
|
||||||
|
* does not exist.
|
||||||
|
*
|
||||||
|
* @param {string} id - id of fragment to retrieve
|
||||||
|
* @returns {[MetaMetricsEventFragment]}
|
||||||
|
*/
|
||||||
|
getEventFragmentById(id) {
|
||||||
|
const { fragments } = this.store.getState();
|
||||||
|
|
||||||
|
const fragment = fragments[id];
|
||||||
|
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +255,7 @@ export default class MetaMetricsController {
|
|||||||
* originated the fragment. This is for fallback only, the fragment referrer
|
* originated the fragment. This is for fallback only, the fragment referrer
|
||||||
* property will take precedence.
|
* property will take precedence.
|
||||||
*/
|
*/
|
||||||
finalizeEventFragment(id, { abandoned = false, page, referrer }) {
|
finalizeEventFragment(id, { abandoned = false, page, referrer } = {}) {
|
||||||
const fragment = this.store.getState().fragments[id];
|
const fragment = this.store.getState().fragments[id];
|
||||||
if (!fragment) {
|
if (!fragment) {
|
||||||
throw new Error(`Funnel with id ${id} does not exist.`);
|
throw new Error(`Funnel with id ${id} does not exist.`);
|
||||||
|
@ -25,6 +25,7 @@ import {
|
|||||||
TRANSACTION_STATUSES,
|
TRANSACTION_STATUSES,
|
||||||
TRANSACTION_TYPES,
|
TRANSACTION_TYPES,
|
||||||
TRANSACTION_ENVELOPE_TYPES,
|
TRANSACTION_ENVELOPE_TYPES,
|
||||||
|
TRANSACTION_EVENTS,
|
||||||
} from '../../../../shared/constants/transaction';
|
} from '../../../../shared/constants/transaction';
|
||||||
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
|
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
|
||||||
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
||||||
@ -54,13 +55,10 @@ 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',
|
* @typedef {import('../../../../shared/constants/transaction').TransactionMeta} TransactionMeta
|
||||||
APPROVED: 'Transaction Approved',
|
* @typedef {import('../../../../shared/constants/transaction').TransactionMetaMetricsEventString} TransactionMetaMetricsEventString
|
||||||
FINALIZED: 'Transaction Finalized',
|
*/
|
||||||
REJECTED: 'Transaction Rejected',
|
|
||||||
SUBMITTED: 'Transaction Submitted',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} CustomGasSettings
|
* @typedef {Object} CustomGasSettings
|
||||||
@ -118,6 +116,10 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this._trackMetaMetricsEvent = opts.trackMetaMetricsEvent;
|
this._trackMetaMetricsEvent = opts.trackMetaMetricsEvent;
|
||||||
this._getParticipateInMetrics = opts.getParticipateInMetrics;
|
this._getParticipateInMetrics = opts.getParticipateInMetrics;
|
||||||
this._getEIP1559GasFeeEstimates = opts.getEIP1559GasFeeEstimates;
|
this._getEIP1559GasFeeEstimates = opts.getEIP1559GasFeeEstimates;
|
||||||
|
this.createEventFragment = opts.createEventFragment;
|
||||||
|
this.updateEventFragment = opts.updateEventFragment;
|
||||||
|
this.finalizeEventFragment = opts.finalizeEventFragment;
|
||||||
|
this.getEventFragmentById = opts.getEventFragmentById;
|
||||||
|
|
||||||
this.memStore = new ObservableStore({});
|
this.memStore = new ObservableStore({});
|
||||||
this.query = new EthQuery(this.provider);
|
this.query = new EthQuery(this.provider);
|
||||||
@ -662,9 +664,8 @@ export default class TransactionController extends EventEmitter {
|
|||||||
* which is defined by specifying a numerator. 11 is a 10% bump, 12 would be
|
* which is defined by specifying a numerator. 11 is a 10% bump, 12 would be
|
||||||
* a 20% bump, and so on.
|
* a 20% bump, and so on.
|
||||||
*
|
*
|
||||||
* @param {import(
|
* @param {TransactionMeta} originalTxMeta - Original transaction to use as
|
||||||
* '../../../../shared/constants/transaction'
|
* base
|
||||||
* ).TransactionMeta} originalTxMeta - Original transaction to use as base
|
|
||||||
* @param {CustomGasSettings} [customGasSettings] - overrides for the gas
|
* @param {CustomGasSettings} [customGasSettings] - overrides for the gas
|
||||||
* fields to use instead of the multiplier
|
* fields to use instead of the multiplier
|
||||||
* @param {number} [incrementNumerator] - Numerator from which to generate a
|
* @param {number} [incrementNumerator] - Numerator from which to generate a
|
||||||
@ -1120,6 +1121,28 @@ export default class TransactionController extends EventEmitter {
|
|||||||
this.txStateManager.updateTransaction(txMeta, 'transactions#setTxHash');
|
this.txStateManager.updateTransaction(txMeta, 'transactions#setTxHash');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for the UI to easily create event fragments when the
|
||||||
|
* fragment does not exist in state.
|
||||||
|
*
|
||||||
|
* @param {number} transactionId - The transaction id to create the event
|
||||||
|
* fragment for
|
||||||
|
* @param {valueOf<TRANSACTION_EVENTS>} event - event type to create
|
||||||
|
*/
|
||||||
|
createTransactionEventFragment(transactionId, event) {
|
||||||
|
const txMeta = this.txStateManager.getTransaction(transactionId);
|
||||||
|
const {
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
} = this._buildEventFragmentProperties(txMeta);
|
||||||
|
this._createTransactionEventFragment(
|
||||||
|
txMeta,
|
||||||
|
event,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
//
|
//
|
||||||
@ -1450,20 +1473,7 @@ export default class TransactionController extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
_buildEventFragmentProperties(txMeta, extraParams) {
|
||||||
* 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 = {}) {
|
|
||||||
if (!txMeta) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
type,
|
type,
|
||||||
time,
|
time,
|
||||||
@ -1501,17 +1511,15 @@ export default class TransactionController extends EventEmitter {
|
|||||||
|
|
||||||
const gasParamsInGwei = this._getGasValuesInGWEI(gasParams);
|
const gasParamsInGwei = this._getGasValuesInGWEI(gasParams);
|
||||||
|
|
||||||
this._trackMetaMetricsEvent({
|
const properties = {
|
||||||
event,
|
|
||||||
category: 'Transactions',
|
|
||||||
properties: {
|
|
||||||
chain_id: chainId,
|
chain_id: chainId,
|
||||||
referrer,
|
referrer,
|
||||||
source,
|
source,
|
||||||
network,
|
network,
|
||||||
type,
|
type,
|
||||||
},
|
};
|
||||||
sensitiveProperties: {
|
|
||||||
|
const sensitiveProperties = {
|
||||||
status,
|
status,
|
||||||
transaction_envelope_type: isEIP1559Transaction(txMeta)
|
transaction_envelope_type: isEIP1559Transaction(txMeta)
|
||||||
? TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET
|
? TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET
|
||||||
@ -1520,8 +1528,185 @@ export default class TransactionController extends EventEmitter {
|
|||||||
gas_limit: gasLimit,
|
gas_limit: gasLimit,
|
||||||
...gasParamsInGwei,
|
...gasParamsInGwei,
|
||||||
...extraParams,
|
...extraParams,
|
||||||
},
|
};
|
||||||
|
|
||||||
|
return { properties, sensitiveProperties };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method that checks for the presence of an existing fragment by id
|
||||||
|
* appropriate for the type of event that triggered fragment creation. If the
|
||||||
|
* appropriate fragment exists, then nothing is done. If it does not exist a
|
||||||
|
* new event fragment is created with the appropriate payload.
|
||||||
|
*
|
||||||
|
* @param {TransactionMeta} txMeta - Transaction meta object
|
||||||
|
* @param {TransactionMetaMetricsEventString} event - The event type that
|
||||||
|
* triggered fragment creation
|
||||||
|
* @param {Object} properties - properties to include in the fragment
|
||||||
|
* @param {Object} [sensitiveProperties] - sensitive properties to include in
|
||||||
|
* the fragment
|
||||||
|
*/
|
||||||
|
_createTransactionEventFragment(
|
||||||
|
txMeta,
|
||||||
|
event,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
) {
|
||||||
|
const isSubmitted = [
|
||||||
|
TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
TRANSACTION_EVENTS.SUBMITTED,
|
||||||
|
].includes(event);
|
||||||
|
const uniqueIdentifier = `transaction-${
|
||||||
|
isSubmitted ? 'submitted' : 'added'
|
||||||
|
}-${txMeta.id}`;
|
||||||
|
|
||||||
|
const fragment = this.getEventFragmentById(uniqueIdentifier);
|
||||||
|
if (typeof fragment !== 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
// When a transaction is added to the controller, we know that the user
|
||||||
|
// will be presented with a confirmation screen. The user will then
|
||||||
|
// either confirm or reject that transaction. Each has an associated
|
||||||
|
// event we want to track. While we don't necessarily need an event
|
||||||
|
// fragment to model this, having one allows us to record additional
|
||||||
|
// properties onto the event from the UI. For example, when the user
|
||||||
|
// edits the transactions gas params we can record that property and
|
||||||
|
// then get analytics on the number of transactions in which gas edits
|
||||||
|
// occur.
|
||||||
|
case TRANSACTION_EVENTS.ADDED:
|
||||||
|
this.createEventFragment({
|
||||||
|
category: 'Transactions',
|
||||||
|
initialEvent: TRANSACTION_EVENTS.ADDED,
|
||||||
|
successEvent: TRANSACTION_EVENTS.APPROVED,
|
||||||
|
failureEvent: TRANSACTION_EVENTS.REJECTED,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
persist: true,
|
||||||
|
uniqueIdentifier,
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
// If for some reason an approval or rejection occurs without the added
|
||||||
|
// fragment existing in memory, we create the added fragment but without
|
||||||
|
// the initialEvent firing. This is to prevent possible duplication of
|
||||||
|
// events. A good example why this might occur is if the user had
|
||||||
|
// unapproved transactions in memory when updating to the version that
|
||||||
|
// includes this change. A migration would have also helped here but this
|
||||||
|
// implementation hardens against other possible bugs where a fragment
|
||||||
|
// does not exist.
|
||||||
|
case TRANSACTION_EVENTS.APPROVED:
|
||||||
|
case TRANSACTION_EVENTS.REJECTED:
|
||||||
|
this.createEventFragment({
|
||||||
|
category: 'Transactions',
|
||||||
|
successEvent: TRANSACTION_EVENTS.APPROVED,
|
||||||
|
failureEvent: TRANSACTION_EVENTS.REJECTED,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
persist: true,
|
||||||
|
uniqueIdentifier,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
// When a transaction is submitted it will always result in updating
|
||||||
|
// to a finalized state (dropped, failed, confirmed) -- eventually.
|
||||||
|
// However having a fragment started at this stage allows augmenting
|
||||||
|
// analytics data with user interactions such as speeding up and
|
||||||
|
// canceling the transactions. From this controllers perspective a new
|
||||||
|
// transaction with a new id is generated for speed up and cancel
|
||||||
|
// transactions, but from the UI we could augment the previous ID with
|
||||||
|
// supplemental data to show user intent. Such as when they open the
|
||||||
|
// cancel UI but don't submit. We can record that this happened and add
|
||||||
|
// properties to the transaction event.
|
||||||
|
case TRANSACTION_EVENTS.SUBMITTED:
|
||||||
|
this.createEventFragment({
|
||||||
|
category: 'Transactions',
|
||||||
|
initialEvent: TRANSACTION_EVENTS.SUBMITTED,
|
||||||
|
successEvent: TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
persist: true,
|
||||||
|
uniqueIdentifier,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
// If for some reason a transaction is finalized without the submitted
|
||||||
|
// fragment existing in memory, we create the submitted fragment but
|
||||||
|
// without the initialEvent firing. This is to prevent possible
|
||||||
|
// duplication of events. A good example why this might occur is if th
|
||||||
|
// user had pending transactions in memory when updating to the version
|
||||||
|
// that includes this change. A migration would have also helped here but
|
||||||
|
// this implementation hardens against other possible bugs where a
|
||||||
|
// fragment does not exist.
|
||||||
|
case TRANSACTION_EVENTS.FINALIZED:
|
||||||
|
this.createEventFragment({
|
||||||
|
category: 'Transactions',
|
||||||
|
successEvent: TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
persist: true,
|
||||||
|
uniqueIdentifier,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {TransactionMetaMetricsEventString} event - the name of the transaction event
|
||||||
|
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
|
||||||
|
*/
|
||||||
|
_trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
|
||||||
|
if (!txMeta) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
} = this._buildEventFragmentProperties(txMeta, extraParams);
|
||||||
|
|
||||||
|
// Create event fragments for event types that spawn fragments, and ensure
|
||||||
|
// existence of fragments for event types that act upon them.
|
||||||
|
this._createTransactionEventFragment(
|
||||||
|
txMeta,
|
||||||
|
event,
|
||||||
|
properties,
|
||||||
|
sensitiveProperties,
|
||||||
|
);
|
||||||
|
|
||||||
|
let id;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
// If the user approves a transaction, finalize the transaction added
|
||||||
|
// event fragment.
|
||||||
|
case TRANSACTION_EVENTS.APPROVED:
|
||||||
|
id = `transaction-added-${txMeta.id}`;
|
||||||
|
this.updateEventFragment(id, { properties, sensitiveProperties });
|
||||||
|
this.finalizeEventFragment(id);
|
||||||
|
break;
|
||||||
|
// If the user rejects a transaction, finalize the transaction added
|
||||||
|
// event fragment. with the abandoned flag set.
|
||||||
|
case TRANSACTION_EVENTS.REJECTED:
|
||||||
|
id = `transaction-added-${txMeta.id}`;
|
||||||
|
this.updateEventFragment(id, { properties, sensitiveProperties });
|
||||||
|
this.finalizeEventFragment(id, {
|
||||||
|
abandoned: true,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
// When a transaction is finalized, also finalize the transaction
|
||||||
|
// submitted event fragment.
|
||||||
|
case TRANSACTION_EVENTS.FINALIZED:
|
||||||
|
id = `transaction-submitted-${txMeta.id}`;
|
||||||
|
this.updateEventFragment(id, { properties, sensitiveProperties });
|
||||||
|
this.finalizeEventFragment(`transaction-submitted-${txMeta.id}`);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getTransactionCompletionTime(submittedTime) {
|
_getTransactionCompletionTime(submittedTime) {
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
TRANSACTION_STATUSES,
|
TRANSACTION_STATUSES,
|
||||||
TRANSACTION_TYPES,
|
TRANSACTION_TYPES,
|
||||||
TRANSACTION_ENVELOPE_TYPES,
|
TRANSACTION_ENVELOPE_TYPES,
|
||||||
|
TRANSACTION_EVENTS,
|
||||||
} from '../../../../shared/constants/transaction';
|
} from '../../../../shared/constants/transaction';
|
||||||
|
|
||||||
import { SECOND } from '../../../../shared/constants/time';
|
import { SECOND } from '../../../../shared/constants/time';
|
||||||
@ -22,7 +23,7 @@ import {
|
|||||||
} from '../../../../shared/constants/gas';
|
} from '../../../../shared/constants/gas';
|
||||||
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
|
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
|
||||||
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
|
||||||
import TransactionController, { TRANSACTION_EVENTS } from '.';
|
import TransactionController from '.';
|
||||||
|
|
||||||
const noop = () => true;
|
const noop = () => true;
|
||||||
const currentNetworkId = '42';
|
const currentNetworkId = '42';
|
||||||
@ -35,9 +36,10 @@ const VALID_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|||||||
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
|
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
|
||||||
|
|
||||||
describe('Transaction Controller', function () {
|
describe('Transaction Controller', function () {
|
||||||
let txController, provider, providerResultStub, fromAccount;
|
let txController, provider, providerResultStub, fromAccount, fragmentExists;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
fragmentExists = false;
|
||||||
providerResultStub = {
|
providerResultStub = {
|
||||||
// 1 gwei
|
// 1 gwei
|
||||||
eth_gasPrice: '0x0de0b6b3a7640000',
|
eth_gasPrice: '0x0de0b6b3a7640000',
|
||||||
@ -70,6 +72,11 @@ describe('Transaction Controller', function () {
|
|||||||
getCurrentChainId: () => currentChainId,
|
getCurrentChainId: () => currentChainId,
|
||||||
getParticipateInMetrics: () => false,
|
getParticipateInMetrics: () => false,
|
||||||
trackMetaMetricsEvent: () => undefined,
|
trackMetaMetricsEvent: () => undefined,
|
||||||
|
createEventFragment: () => undefined,
|
||||||
|
updateEventFragment: () => undefined,
|
||||||
|
finalizeEventFragment: () => undefined,
|
||||||
|
getEventFragmentById: () =>
|
||||||
|
fragmentExists === false ? undefined : { id: 0 },
|
||||||
getEIP1559GasFeeEstimates: () => undefined,
|
getEIP1559GasFeeEstimates: () => undefined,
|
||||||
});
|
});
|
||||||
txController.nonceTracker.getNonceLock = () =>
|
txController.nonceTracker.getNonceLock = () =>
|
||||||
@ -1536,20 +1543,33 @@ describe('Transaction Controller', function () {
|
|||||||
|
|
||||||
describe('#_trackTransactionMetricsEvent', function () {
|
describe('#_trackTransactionMetricsEvent', function () {
|
||||||
let trackMetaMetricsEventSpy;
|
let trackMetaMetricsEventSpy;
|
||||||
|
let createEventFragmentSpy;
|
||||||
|
let finalizeEventFragmentSpy;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
trackMetaMetricsEventSpy = sinon.spy(
|
trackMetaMetricsEventSpy = sinon.spy(
|
||||||
txController,
|
txController,
|
||||||
'_trackMetaMetricsEvent',
|
'_trackMetaMetricsEvent',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
createEventFragmentSpy = sinon.spy(txController, 'createEventFragment');
|
||||||
|
|
||||||
|
finalizeEventFragmentSpy = sinon.spy(
|
||||||
|
txController,
|
||||||
|
'finalizeEventFragment',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
trackMetaMetricsEventSpy.restore();
|
trackMetaMetricsEventSpy.restore();
|
||||||
|
createEventFragmentSpy.restore();
|
||||||
|
finalizeEventFragmentSpy.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call _trackMetaMetricsEvent with the correct payload (user source)', function () {
|
describe('On transaction created by the user', function () {
|
||||||
const txMeta = {
|
let txMeta;
|
||||||
|
before(function () {
|
||||||
|
txMeta = {
|
||||||
id: 1,
|
id: 1,
|
||||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
txParams: {
|
txParams: {
|
||||||
@ -1565,9 +1585,16 @@ describe('Transaction Controller', function () {
|
|||||||
time: 1624408066355,
|
time: 1624408066355,
|
||||||
metamaskNetworkId: currentNetworkId,
|
metamaskNetworkId: currentNetworkId,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an event fragment when transaction added', function () {
|
||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
event: 'Transaction Added',
|
initialEvent: 'Transaction Added',
|
||||||
|
successEvent: 'Transaction Approved',
|
||||||
|
failureEvent: 'Transaction Rejected',
|
||||||
|
uniqueIdentifier: 'transaction-added-1',
|
||||||
category: 'Transactions',
|
category: 'Transactions',
|
||||||
|
persist: true,
|
||||||
properties: {
|
properties: {
|
||||||
chain_id: '0x2a',
|
chain_id: '0x2a',
|
||||||
network: '42',
|
network: '42',
|
||||||
@ -1588,15 +1615,107 @@ describe('Transaction Controller', function () {
|
|||||||
txMeta,
|
txMeta,
|
||||||
TRANSACTION_EVENTS.ADDED,
|
TRANSACTION_EVENTS.ADDED,
|
||||||
);
|
);
|
||||||
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
assert.equal(createEventFragmentSpy.callCount, 1);
|
||||||
|
assert.equal(finalizeEventFragmentSpy.callCount, 0);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
trackMetaMetricsEventSpy.getCall(0).args[0],
|
createEventFragmentSpy.getCall(0).args[0],
|
||||||
expectedPayload,
|
expectedPayload,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call _trackMetaMetricsEvent with the correct payload (dapp source)', function () {
|
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', function () {
|
||||||
const txMeta = {
|
fragmentExists = true;
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.REJECTED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
fragmentExists = true;
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.APPROVED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
const expectedPayload = {
|
||||||
|
initialEvent: 'Transaction Submitted',
|
||||||
|
successEvent: 'Transaction Finalized',
|
||||||
|
uniqueIdentifier: 'transaction-submitted-1',
|
||||||
|
category: 'Transactions',
|
||||||
|
persist: true,
|
||||||
|
properties: {
|
||||||
|
chain_id: '0x2a',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'metamask',
|
||||||
|
source: 'user',
|
||||||
|
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||||
|
},
|
||||||
|
sensitiveProperties: {
|
||||||
|
gas_price: '2',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
|
||||||
|
status: 'unapproved',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.SUBMITTED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
fragmentExists = true;
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
);
|
||||||
|
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,
|
id: 1,
|
||||||
status: TRANSACTION_STATUSES.UNAPPROVED,
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
txParams: {
|
txParams: {
|
||||||
@ -1612,9 +1731,16 @@ describe('Transaction Controller', function () {
|
|||||||
time: 1624408066355,
|
time: 1624408066355,
|
||||||
metamaskNetworkId: currentNetworkId,
|
metamaskNetworkId: currentNetworkId,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create an event fragment when transaction added', function () {
|
||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
event: 'Transaction Added',
|
initialEvent: 'Transaction Added',
|
||||||
|
successEvent: 'Transaction Approved',
|
||||||
|
failureEvent: 'Transaction Rejected',
|
||||||
|
uniqueIdentifier: 'transaction-added-1',
|
||||||
category: 'Transactions',
|
category: 'Transactions',
|
||||||
|
persist: true,
|
||||||
properties: {
|
properties: {
|
||||||
chain_id: '0x2a',
|
chain_id: '0x2a',
|
||||||
network: '42',
|
network: '42',
|
||||||
@ -1635,13 +1761,162 @@ describe('Transaction Controller', function () {
|
|||||||
txMeta,
|
txMeta,
|
||||||
TRANSACTION_EVENTS.ADDED,
|
TRANSACTION_EVENTS.ADDED,
|
||||||
);
|
);
|
||||||
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
assert.equal(createEventFragmentSpy.callCount, 1);
|
||||||
|
assert.equal(finalizeEventFragmentSpy.callCount, 0);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
trackMetaMetricsEventSpy.getCall(0).args[0],
|
createEventFragmentSpy.getCall(0).args[0],
|
||||||
expectedPayload,
|
expectedPayload,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should finalize the transaction added fragment as abandoned if user rejects transaction', function () {
|
||||||
|
fragmentExists = true;
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.REJECTED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
fragmentExists = true;
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.APPROVED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
const expectedPayload = {
|
||||||
|
initialEvent: 'Transaction Submitted',
|
||||||
|
successEvent: 'Transaction Finalized',
|
||||||
|
uniqueIdentifier: 'transaction-submitted-1',
|
||||||
|
category: 'Transactions',
|
||||||
|
persist: true,
|
||||||
|
properties: {
|
||||||
|
chain_id: '0x2a',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'other',
|
||||||
|
source: 'dapp',
|
||||||
|
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||||
|
},
|
||||||
|
sensitiveProperties: {
|
||||||
|
gas_price: '2',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
|
||||||
|
status: 'unapproved',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.SUBMITTED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
fragmentExists = true;
|
||||||
|
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.FINALIZED,
|
||||||
|
);
|
||||||
|
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', function () {
|
||||||
|
const txMeta = {
|
||||||
|
id: 1,
|
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED,
|
||||||
|
txParams: {
|
||||||
|
from: fromAccount.address,
|
||||||
|
to: '0x1678a085c290ebd122dc42cba69373b5953b831d',
|
||||||
|
gasPrice: '0x77359400',
|
||||||
|
gas: '0x7b0d',
|
||||||
|
nonce: '0x4b',
|
||||||
|
},
|
||||||
|
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||||
|
origin: 'other',
|
||||||
|
chainId: currentChainId,
|
||||||
|
time: 1624408066355,
|
||||||
|
metamaskNetworkId: currentNetworkId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedPayload = {
|
||||||
|
successEvent: 'Transaction Approved',
|
||||||
|
failureEvent: 'Transaction Rejected',
|
||||||
|
uniqueIdentifier: 'transaction-added-1',
|
||||||
|
category: 'Transactions',
|
||||||
|
persist: true,
|
||||||
|
properties: {
|
||||||
|
chain_id: '0x2a',
|
||||||
|
network: '42',
|
||||||
|
referrer: 'other',
|
||||||
|
source: 'dapp',
|
||||||
|
type: TRANSACTION_TYPES.SIMPLE_SEND,
|
||||||
|
},
|
||||||
|
sensitiveProperties: {
|
||||||
|
gas_price: '2',
|
||||||
|
gas_limit: '0x7b0d',
|
||||||
|
first_seen: 1624408066355,
|
||||||
|
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
|
||||||
|
status: 'unapproved',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
txController._trackTransactionMetricsEvent(
|
||||||
|
txMeta,
|
||||||
|
TRANSACTION_EVENTS.APPROVED,
|
||||||
|
);
|
||||||
|
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)', function () {
|
it('should call _trackMetaMetricsEvent with the correct payload (extra params)', function () {
|
||||||
const txMeta = {
|
const txMeta = {
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -1660,7 +1935,11 @@ describe('Transaction Controller', function () {
|
|||||||
metamaskNetworkId: currentNetworkId,
|
metamaskNetworkId: currentNetworkId,
|
||||||
};
|
};
|
||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
event: 'Transaction Added',
|
initialEvent: 'Transaction Added',
|
||||||
|
successEvent: 'Transaction Approved',
|
||||||
|
failureEvent: 'Transaction Rejected',
|
||||||
|
uniqueIdentifier: 'transaction-added-1',
|
||||||
|
persist: true,
|
||||||
category: 'Transactions',
|
category: 'Transactions',
|
||||||
properties: {
|
properties: {
|
||||||
network: '42',
|
network: '42',
|
||||||
@ -1688,9 +1967,10 @@ describe('Transaction Controller', function () {
|
|||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
assert.equal(createEventFragmentSpy.callCount, 1);
|
||||||
|
assert.equal(finalizeEventFragmentSpy.callCount, 0);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
trackMetaMetricsEventSpy.getCall(0).args[0],
|
createEventFragmentSpy.getCall(0).args[0],
|
||||||
expectedPayload,
|
expectedPayload,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -1716,7 +1996,11 @@ describe('Transaction Controller', function () {
|
|||||||
metamaskNetworkId: currentNetworkId,
|
metamaskNetworkId: currentNetworkId,
|
||||||
};
|
};
|
||||||
const expectedPayload = {
|
const expectedPayload = {
|
||||||
event: 'Transaction Added',
|
initialEvent: 'Transaction Added',
|
||||||
|
successEvent: 'Transaction Approved',
|
||||||
|
failureEvent: 'Transaction Rejected',
|
||||||
|
uniqueIdentifier: 'transaction-added-1',
|
||||||
|
persist: true,
|
||||||
category: 'Transactions',
|
category: 'Transactions',
|
||||||
properties: {
|
properties: {
|
||||||
chain_id: '0x2a',
|
chain_id: '0x2a',
|
||||||
@ -1747,9 +2031,10 @@ describe('Transaction Controller', function () {
|
|||||||
foo: 'bar',
|
foo: 'bar',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert.equal(trackMetaMetricsEventSpy.callCount, 1);
|
assert.equal(createEventFragmentSpy.callCount, 1);
|
||||||
|
assert.equal(finalizeEventFragmentSpy.callCount, 0);
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
trackMetaMetricsEventSpy.getCall(0).args[0],
|
createEventFragmentSpy.getCall(0).args[0],
|
||||||
expectedPayload,
|
expectedPayload,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -577,6 +577,18 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
),
|
),
|
||||||
provider: this.provider,
|
provider: this.provider,
|
||||||
blockTracker: this.blockTracker,
|
blockTracker: this.blockTracker,
|
||||||
|
createEventFragment: this.metaMetricsController.createEventFragment.bind(
|
||||||
|
this.metaMetricsController,
|
||||||
|
),
|
||||||
|
updateEventFragment: this.metaMetricsController.updateEventFragment.bind(
|
||||||
|
this.metaMetricsController,
|
||||||
|
),
|
||||||
|
finalizeEventFragment: this.metaMetricsController.finalizeEventFragment.bind(
|
||||||
|
this.metaMetricsController,
|
||||||
|
),
|
||||||
|
getEventFragmentById: this.metaMetricsController.getEventFragmentById.bind(
|
||||||
|
this.metaMetricsController,
|
||||||
|
),
|
||||||
trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind(
|
trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind(
|
||||||
this.metaMetricsController,
|
this.metaMetricsController,
|
||||||
),
|
),
|
||||||
@ -1282,6 +1294,9 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
addUnapprovedTransaction: txController.addUnapprovedTransaction.bind(
|
addUnapprovedTransaction: txController.addUnapprovedTransaction.bind(
|
||||||
txController,
|
txController,
|
||||||
),
|
),
|
||||||
|
createTransactionEventFragment: txController.createTransactionEventFragment.bind(
|
||||||
|
txController,
|
||||||
|
),
|
||||||
|
|
||||||
// messageManager
|
// messageManager
|
||||||
signMessage: this.signMessage.bind(this),
|
signMessage: this.signMessage.bind(this),
|
||||||
|
@ -88,6 +88,9 @@
|
|||||||
* is closed in an affirmative action.
|
* is closed in an affirmative action.
|
||||||
* @property {string} [failureEvent] - The event name to fire when the fragment
|
* @property {string} [failureEvent] - The event name to fire when the fragment
|
||||||
* is closed with a rejection.
|
* is closed with a rejection.
|
||||||
|
* @property {string} [initialEvent] - An event name to fire immediately upon
|
||||||
|
* fragment creation. This is useful for building funnels in mixpanel and for
|
||||||
|
* reduction of code duplication.
|
||||||
* @property {string} category - the event category to use for both the success
|
* @property {string} category - the event category to use for both the success
|
||||||
* and failure events
|
* and failure events
|
||||||
* @property {boolean} [persist] - Should this fragment be persisted in
|
* @property {boolean} [persist] - Should this fragment be persisted in
|
||||||
@ -113,6 +116,10 @@
|
|||||||
* occurred on
|
* occurred on
|
||||||
* @property {MetaMetricsReferrerObject} [referrer] - the origin of the dapp
|
* @property {MetaMetricsReferrerObject} [referrer] - the origin of the dapp
|
||||||
* that initiated the event fragment.
|
* that initiated the event fragment.
|
||||||
|
* @property {string} [uniqueIdentifier] - optional argument to override the
|
||||||
|
* automatic generation of UUID for the event fragment. This is useful when
|
||||||
|
* tracking events for subsystems that already generate UUIDs so to avoid
|
||||||
|
* unnecessary lookups and reduce accidental duplication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -236,3 +236,49 @@ export const TRANSACTION_GROUP_CATEGORIES = {
|
|||||||
* the network, in Unix epoch time (ms).
|
* the network, in Unix epoch time (ms).
|
||||||
* @property {TxError} [err] - The error encountered during the transaction
|
* @property {TxError} [err] - The error encountered during the transaction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the possible types
|
||||||
|
*
|
||||||
|
* @typedef {Object} TransactionMetaMetricsEvents
|
||||||
|
* @property {'Transaction Added'} ADDED - All transactions, except incoming
|
||||||
|
* ones, are added to the controller state in an unapproved status. When this
|
||||||
|
* happens we fire the Transaction Added event to show that the transaction
|
||||||
|
* has been added to the user's MetaMask.
|
||||||
|
* @property {'Transaction Approved'} APPROVED - When an unapproved transaction
|
||||||
|
* is in the controller state, MetaMask will render a confirmation screen for
|
||||||
|
* that transaction. If the user approves the transaction we fire this event
|
||||||
|
* to indicate that the user has approved the transaction for submission to
|
||||||
|
* the network.
|
||||||
|
* @property {'Transaction Rejected'} REJECTED - When an unapproved transaction
|
||||||
|
* is in the controller state, MetaMask will render a confirmation screen for
|
||||||
|
* that transaction. If the user rejects the transaction we fire this event
|
||||||
|
* to indicate that the user has rejected the transaction. It will be removed
|
||||||
|
* from state as a result.
|
||||||
|
* @property {'Transaction Submitted'} SUBMITTED - After a transaction is
|
||||||
|
* approved by the user, it is then submitted to the network for inclusion in
|
||||||
|
* a block. When this happens we fire the Transaction Submitted event to
|
||||||
|
* indicate that MetaMask is submitting a transaction at the user's request.
|
||||||
|
* @property {'Transaction Finalized'} FINALIZED - All transactions that are
|
||||||
|
* submitted will finalized (eventually) by either being dropped, failing
|
||||||
|
* or being confirmed. When this happens we track this event, along with the
|
||||||
|
* status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type will work anywhere you expect a string that can be one of the
|
||||||
|
* above transaction event types.
|
||||||
|
*
|
||||||
|
* @typedef {TransactionMetaMetricsEvents[keyof TransactionMetaMetricsEvents]} TransactionMetaMetricsEventString
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {TransactionMetaMetricsEvents}
|
||||||
|
*/
|
||||||
|
export const TRANSACTION_EVENTS = {
|
||||||
|
ADDED: 'Transaction Added',
|
||||||
|
APPROVED: 'Transaction Approved',
|
||||||
|
FINALIZED: 'Transaction Finalized',
|
||||||
|
REJECTED: 'Transaction Rejected',
|
||||||
|
SUBMITTED: 'Transaction Submitted',
|
||||||
|
};
|
||||||
|
@ -485,6 +485,46 @@
|
|||||||
"usePhishDetect": true,
|
"usePhishDetect": true,
|
||||||
"useTokenDetection": true
|
"useTokenDetection": true
|
||||||
},
|
},
|
||||||
|
"MetaMetricsController": {
|
||||||
|
"fragments": {
|
||||||
|
"transaction-added-7911313280012623": {
|
||||||
|
"category": "Transactions",
|
||||||
|
"initialEvent": "Transaction Added",
|
||||||
|
"successEvent": "Transaction Approved",
|
||||||
|
"failureEvent": "Transaction Rejected",
|
||||||
|
"properties": {},
|
||||||
|
"persist": true,
|
||||||
|
"uniqueIdentifier": "transaction-added-7911313280012623"
|
||||||
|
},
|
||||||
|
"transaction-added-7911313280012624": {
|
||||||
|
"category": "Transactions",
|
||||||
|
"initialEvent": "Transaction Added",
|
||||||
|
"successEvent": "Transaction Approved",
|
||||||
|
"failureEvent": "Transaction Rejected",
|
||||||
|
"properties": {},
|
||||||
|
"persist": true,
|
||||||
|
"uniqueIdentifier": "transaction-added-7911313280012624"
|
||||||
|
},
|
||||||
|
"transaction-added-7911313280012625": {
|
||||||
|
"category": "Transactions",
|
||||||
|
"initialEvent": "Transaction Added",
|
||||||
|
"successEvent": "Transaction Approved",
|
||||||
|
"failureEvent": "Transaction Rejected",
|
||||||
|
"properties": {},
|
||||||
|
"persist": true,
|
||||||
|
"uniqueIdentifier": "transaction-added-7911313280012625"
|
||||||
|
},
|
||||||
|
"transaction-added-7911313280012626": {
|
||||||
|
"category": "Transactions",
|
||||||
|
"initialEvent": "Transaction Added",
|
||||||
|
"successEvent": "Transaction Approved",
|
||||||
|
"failureEvent": "Transaction Rejected",
|
||||||
|
"properties": {},
|
||||||
|
"persist": true,
|
||||||
|
"uniqueIdentifier": "transaction-added-7911313280012626"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"TransactionController": {
|
"TransactionController": {
|
||||||
"transactions": {
|
"transactions": {
|
||||||
"7911313280012623": {
|
"7911313280012623": {
|
||||||
|
@ -129,6 +129,19 @@
|
|||||||
"useNonceField": false,
|
"useNonceField": false,
|
||||||
"usePhishDetect": true
|
"usePhishDetect": true
|
||||||
},
|
},
|
||||||
|
"MetaMetricsController": {
|
||||||
|
"fragments": {
|
||||||
|
"transaction-added-4046084157914634": {
|
||||||
|
"category": "Transactions",
|
||||||
|
"initialEvent": "Transaction Added",
|
||||||
|
"successEvent": "Transaction Approved",
|
||||||
|
"failureEvent": "Transaction Rejected",
|
||||||
|
"properties": {},
|
||||||
|
"persist": true,
|
||||||
|
"uniqueIdentifier": "transaction-added-4046084157914634"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"TransactionController": {
|
"TransactionController": {
|
||||||
"transactions": {
|
"transactions": {
|
||||||
"4046084157914634": {
|
"4046084157914634": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user