From 484ba7ad3098b13508ce0cdc52d66936449a1a3b Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Tue, 7 Jan 2025 13:32:27 +0000 Subject: [PATCH 1/4] Add new completion_time_onchain property to Transaction Finalized events --- app/scripts/lib/transaction/metrics.ts | 34 +++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index ee09d60259cd..26d2f3d748a1 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -33,6 +33,7 @@ import { TRANSACTION_ENVELOPE_TYPE_NAMES, } from '../../../../shared/lib/transactions-controller-utils'; import { + hexToDecimal, hexWEIToDecETH, hexWEIToDecGWEI, } from '../../../../shared/modules/conversion.utils'; @@ -229,12 +230,19 @@ export const handleTransactionConfirmed = async ( extraParams.gas_used = txReceipt?.gasUsed; - const { submittedTime } = transactionMeta; + const { submittedTime, blockTimestamp } = transactionMeta; if (submittedTime) { extraParams.completion_time = getTransactionCompletionTime(submittedTime); } + if (submittedTime && blockTimestamp) { + extraParams.completion_time_onchain = getTransactionOnchainCompletionTime( + submittedTime, + blockTimestamp, + ); + } + if (txReceipt?.status === '0x0') { extraParams.status = METRICS_STATUS_FAILED; } @@ -1133,6 +1141,30 @@ function getTransactionCompletionTime(submittedTime: number) { return Math.round((Date.now() - submittedTime) / 1000).toString(); } +/** + * Returns number of seconds (rounded to the hundredths) between submitted time + * and the block timestamp. + * + * @param submittedTime - The UNIX timestamp in milliseconds in which the + * transaction has been submitted + * @param blockTimestamp - The UNIX timestamp in seconds in hexadecimal in which + * the transaction has been confirmed in a block + */ +function getTransactionOnchainCompletionTime( + submittedTime: number, + blockTimestamp: string, +): string { + const DECIMAL_DIGITS = 2; + + return ( + Math.round( + (Number(hexToDecimal(blockTimestamp)) - submittedTime / 1000) * + 10 ** DECIMAL_DIGITS, + ) / + 10 ** DECIMAL_DIGITS + ).toString(); +} + /** * The allowance amount in relation to the dapp proposed amount for specific token * From 08ef0d374ad8dfb931536ab4efc5413c06213852 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Thu, 9 Jan 2025 14:17:06 +0000 Subject: [PATCH 2/4] wip --- app/scripts/lib/transaction/metrics.test.ts | 62 +++++++++++++++++++++ app/scripts/lib/transaction/metrics.ts | 22 ++++---- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index 8e2924a0e30f..3b054eda6c24 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -36,6 +36,7 @@ import { METRICS_STATUS_FAILED, TransactionMetricsRequest, } from './metrics'; +import { decimalToHex } from '../../../../shared/modules/conversion.utils'; const providerResultStub = { eth_getCode: '0x123', @@ -828,6 +829,67 @@ describe('Transaction metrics', () => { mockTransactionMetricsRequest.finalizeEventFragment, ).toHaveBeenCalledWith(expectedUniqueId); }); + + it.only('should create, update, finalize event fragment with completion_time_onchain', async () => { + mockTransactionMeta.txReceipt = { + gasUsed: '0x123', + status: '0x0', + }; + mockTransactionMeta.blockTimestamp = decimalToHex(124); + mockTransactionMeta.submittedTime = 123123; + + await handleTransactionConfirmed(mockTransactionMetricsRequest, { + ...mockTransactionMeta, + actionId: mockActionId, + // TODO: Replace `any` with type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + + const expectedUniqueId = 'transaction-submitted-1'; + + expect(mockTransactionMetricsRequest.createEventFragment).toBeCalledTimes( + 1, + ); + expect(mockTransactionMetricsRequest.createEventFragment).toBeCalledWith({ + actionId: mockActionId, + category: MetaMetricsEventCategory.Transactions, + successEvent: TransactionMetaMetricsEvent.finalized, + uniqueIdentifier: expectedUniqueId, + persist: true, + properties: expectedProperties, + sensitiveProperties: { + ...expectedSensitiveProperties, + completion_time: expect.any(String), + completion_time_onchain: '0.88', + gas_used: '0.000000291', + status: METRICS_STATUS_FAILED, + }, + }); + + expect(mockTransactionMetricsRequest.updateEventFragment).toBeCalledTimes( + 1, + ); + expect(mockTransactionMetricsRequest.updateEventFragment).toBeCalledWith( + expectedUniqueId, + { + properties: expectedProperties, + sensitiveProperties: { + ...expectedSensitiveProperties, + completion_time: expect.any(String), + completion_time_onchain: '0.88', + gas_used: '0.000000291', + status: METRICS_STATUS_FAILED, + }, + }, + ); + + expect( + mockTransactionMetricsRequest.finalizeEventFragment, + ).toBeCalledTimes(1); + expect( + mockTransactionMetricsRequest.finalizeEventFragment, + ).toBeCalledWith(expectedUniqueId); + }); }); describe('handleTransactionDropped', () => { diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index 26d2f3d748a1..b576beb639cc 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -1145,24 +1145,24 @@ function getTransactionCompletionTime(submittedTime: number) { * Returns number of seconds (rounded to the hundredths) between submitted time * and the block timestamp. * - * @param submittedTime - The UNIX timestamp in milliseconds in which the + * @param submittedTimeMs - The UNIX timestamp in milliseconds in which the * transaction has been submitted - * @param blockTimestamp - The UNIX timestamp in seconds in hexadecimal in which + * @param blockTimestampHex - The UNIX timestamp in seconds in hexadecimal in which * the transaction has been confirmed in a block */ function getTransactionOnchainCompletionTime( - submittedTime: number, - blockTimestamp: string, + submittedTimeMs: number, + blockTimestampHex: string, ): string { const DECIMAL_DIGITS = 2; - return ( - Math.round( - (Number(hexToDecimal(blockTimestamp)) - submittedTime / 1000) * - 10 ** DECIMAL_DIGITS, - ) / - 10 ** DECIMAL_DIGITS - ).toString(); + const blockTimestampSeconds = Number(hexToDecimal(blockTimestampHex)); + const completionTimeSeconds = blockTimestampSeconds - submittedTimeMs / 1000; + const completionTimeSecondsRoundedToThousands = + Math.round(completionTimeSeconds * 10 ** DECIMAL_DIGITS) / + 10 ** DECIMAL_DIGITS; + + return completionTimeSecondsRoundedToThousands.toString(); } /** From 61a4566aef5fc4df911489354900164867ec95b8 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Thu, 9 Jan 2025 14:33:54 +0000 Subject: [PATCH 3/4] wip --- app/scripts/lib/transaction/metrics.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index 3b054eda6c24..e7bc6cb7f4bb 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -25,6 +25,7 @@ import { BlockaidReason, BlockaidResultType, } from '../../../../shared/constants/security-provider'; +import { decimalToHex } from '../../../../shared/modules/conversion.utils'; import { handleTransactionAdded, handleTransactionApproved, @@ -36,7 +37,6 @@ import { METRICS_STATUS_FAILED, TransactionMetricsRequest, } from './metrics'; -import { decimalToHex } from '../../../../shared/modules/conversion.utils'; const providerResultStub = { eth_getCode: '0x123', From 0b99632bb009d93f72ecd1755f63a619c63b56b9 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Fri, 10 Jan 2025 14:19:17 +0000 Subject: [PATCH 4/4] wip --- app/scripts/lib/transaction/metrics.test.ts | 2 +- app/scripts/lib/transaction/metrics.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/lib/transaction/metrics.test.ts b/app/scripts/lib/transaction/metrics.test.ts index e7bc6cb7f4bb..58f2c9c8fc20 100644 --- a/app/scripts/lib/transaction/metrics.test.ts +++ b/app/scripts/lib/transaction/metrics.test.ts @@ -830,7 +830,7 @@ describe('Transaction metrics', () => { ).toHaveBeenCalledWith(expectedUniqueId); }); - it.only('should create, update, finalize event fragment with completion_time_onchain', async () => { + it('should create, update, finalize event fragment with completion_time_onchain', async () => { mockTransactionMeta.txReceipt = { gasUsed: '0x123', status: '0x0', diff --git a/app/scripts/lib/transaction/metrics.ts b/app/scripts/lib/transaction/metrics.ts index b576beb639cc..8329a6e5b4ca 100644 --- a/app/scripts/lib/transaction/metrics.ts +++ b/app/scripts/lib/transaction/metrics.ts @@ -1158,11 +1158,11 @@ function getTransactionOnchainCompletionTime( const blockTimestampSeconds = Number(hexToDecimal(blockTimestampHex)); const completionTimeSeconds = blockTimestampSeconds - submittedTimeMs / 1000; - const completionTimeSecondsRoundedToThousands = + const completionTimeSecondsRounded = Math.round(completionTimeSeconds * 10 ** DECIMAL_DIGITS) / 10 ** DECIMAL_DIGITS; - return completionTimeSecondsRoundedToThousands.toString(); + return completionTimeSecondsRounded.toString(); } /**