Skip to content

Commit 3f58ef5

Browse files
feat: Add simulation receiving value for Predict withdraw metrics (MetaMask#24281)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** Predict withdraw transactions were missing `simulation_receiving_assets_total_value`, limiting visibility into total value withdrawn. Attach `assetsFiatValues.receiving` to Predict withdraw transactions during signing and add tests to verify the value is emitted through the metrics pipeline. ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: ## **Related issues** Fixes: MetaMask/MetaMask-planning#6392 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds missing simulation receiving value for Predict withdraws and validates metrics propagation. > > - Updates `PredictController.beforeSign` to set updated `txParams` and `assetsFiatValues.receiving` (stringified amount), and conditionally apply gas estimates > - Extends tests: `PredictController.test` asserts `assetsFiatValues.receiving`; `metrics.test` verifies `simulation_receiving_assets_total_value` is included when present and adds coverage for Smart Transactions metrics properties > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 574d483. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent dd2a1f5 commit 3f58ef5

3 files changed

Lines changed: 137 additions & 2 deletions

File tree

app/components/UI/Predict/controllers/PredictController.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3841,7 +3841,19 @@ describe('PredictController', () => {
38413841
expect(result).toBeDefined();
38423842
expect(result?.updateTransaction).toBeDefined();
38433843

3844-
const testTransaction = {
3844+
const testTransaction: {
3845+
txParams: {
3846+
from: string;
3847+
to: string;
3848+
data: string;
3849+
gas?: string;
3850+
gasLimit?: string;
3851+
};
3852+
assetsFiatValues?: {
3853+
receiving?: string;
3854+
sending?: string;
3855+
};
3856+
} = {
38453857
txParams: {
38463858
from: '0xFrom',
38473859
to: '0xOldTarget',
@@ -3853,6 +3865,9 @@ describe('PredictController', () => {
38533865

38543866
expect(testTransaction.txParams.data).toBe('0xmodifieddata');
38553867
expect(testTransaction.txParams.to).toBe('0xPredictAddress');
3868+
expect(testTransaction.assetsFiatValues).toEqual({
3869+
receiving: '100',
3870+
});
38563871
});
38573872
});
38583873

app/components/UI/Predict/controllers/PredictController.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,6 +2157,10 @@ export class PredictController extends BaseController<
21572157
transaction.txParams.data = callData;
21582158
transaction.txParams.to = this.state.withdrawTransaction
21592159
?.predictAddress as Hex;
2160+
transaction.assetsFiatValues = {
2161+
...transaction.assetsFiatValues,
2162+
receiving: String(amount),
2163+
};
21602164
// Only update gas if estimation succeeded
21612165
if (updatedGas) {
21622166
transaction.txParams.gas = updatedGas;

app/core/Engine/controllers/transaction-controller/event-handlers/metrics.test.ts

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { merge } from 'lodash';
44
import { MetaMetrics } from '../../../../Analytics';
55
import { TRANSACTION_EVENTS } from '../../../../Analytics/events/confirmations';
66
import { MetricsEventBuilder } from '../../../../Analytics/MetricsEventBuilder';
7+
import { selectShouldUseSmartTransaction } from '../../../../../selectors/smartTransactionsController';
8+
import { getSmartTransactionMetricsProperties } from '../../../../../util/smart-transactions';
79
import {
810
handleTransactionAddedEventForMetrics,
911
handleTransactionApprovedEventForMetrics,
@@ -12,7 +14,10 @@ import {
1214
handleTransactionSubmittedEventForMetrics,
1315
} from './metrics';
1416
import { TransactionEventHandlerRequest } from '../types';
15-
import { enabledSmartTransactionsState } from '../data-helpers';
17+
import {
18+
disabledSmartTransactionsState,
19+
enabledSmartTransactionsState,
20+
} from '../data-helpers';
1621

1722
jest.mock('../../../../../util/smart-transactions', () => {
1823
const actual = jest.requireActual('../../../../../util/smart-transactions');
@@ -64,6 +69,19 @@ jest.mock('../metrics_properties/metamask-pay', () => ({
6469
}),
6570
}));
6671

72+
const mockSelectShouldUseSmartTransaction = jest.mocked(
73+
selectShouldUseSmartTransaction,
74+
);
75+
const mockGetSmartTransactionMetricsProperties = jest.mocked(
76+
getSmartTransactionMetricsProperties,
77+
);
78+
79+
const mockSmartTransactionMetricsProperties = {
80+
smart_transaction_timed_out: false,
81+
smart_transaction_proxied: false,
82+
is_smart_transaction: true,
83+
};
84+
6785
describe('Transaction Metric Event Handlers', () => {
6886
const mockGetState = jest.fn();
6987
const mockInitMessenger = jest.fn();
@@ -212,4 +230,102 @@ describe('Transaction Metric Event Handlers', () => {
212230
}),
213231
);
214232
});
233+
234+
it('includes simulation receiving total value when assetsFiatValues is set', async () => {
235+
const transactionMetaWithFiatValues = {
236+
...mockTransactionMeta,
237+
assetsFiatValues: {
238+
receiving: '123.45',
239+
},
240+
} as unknown as TransactionMeta;
241+
242+
await handleTransactionApprovedEventForMetrics(
243+
transactionMetaWithFiatValues,
244+
mockTransactionMetricRequest,
245+
);
246+
247+
expect(mockEventBuilder.addProperties).toHaveBeenCalledWith(
248+
expect.objectContaining({
249+
simulation_receiving_assets_total_value: 123.45,
250+
}),
251+
);
252+
});
253+
254+
describe('handleTransactionFinalized', () => {
255+
it('adds STX metrics properties if smart transactions are enabled', async () => {
256+
// Force the selector to return true
257+
mockSelectShouldUseSmartTransaction.mockReturnValue(true);
258+
259+
// Force the mock to return the expected properties
260+
mockGetSmartTransactionMetricsProperties.mockResolvedValue({
261+
smart_transaction_timed_out: false,
262+
smart_transaction_proxied: false,
263+
is_smart_transaction: true,
264+
});
265+
266+
await handleTransactionFinalizedEventForMetrics(
267+
mockTransactionMeta,
268+
mockTransactionMetricRequest,
269+
);
270+
271+
// Check if the mock was called
272+
expect(mockGetSmartTransactionMetricsProperties).toHaveBeenCalled();
273+
274+
// Check if addProperties was called with the STX properties
275+
expect(mockEventBuilder.addProperties).toHaveBeenCalledWith(
276+
expect.objectContaining({
277+
smart_transaction_timed_out: false,
278+
smart_transaction_proxied: false,
279+
is_smart_transaction: true,
280+
}),
281+
);
282+
});
283+
284+
it('does not add STX metrics properties if smart transactions are not enabled', async () => {
285+
// Force the selector to return false for this test
286+
mockSelectShouldUseSmartTransaction.mockReturnValue(false);
287+
288+
mockGetState.mockReturnValue(
289+
merge({}, disabledSmartTransactionsState, {
290+
confirmationMetrics: {
291+
metricsById: {
292+
[mockTransactionMeta.id]: {
293+
properties: { test_property: 'test_value' },
294+
sensitiveProperties: { sensitive_property: 'sensitive_value' },
295+
},
296+
},
297+
},
298+
}),
299+
);
300+
301+
await handleTransactionFinalizedEventForMetrics(
302+
mockTransactionMeta,
303+
mockTransactionMetricRequest,
304+
);
305+
306+
expect(mockEventBuilder.addProperties).toHaveBeenCalled();
307+
expect(mockEventBuilder.addProperties).not.toHaveBeenCalledWith(
308+
expect.objectContaining(mockSmartTransactionMetricsProperties),
309+
);
310+
});
311+
312+
it('includes builder metrics', async () => {
313+
await handleTransactionFinalizedEventForMetrics(
314+
mockTransactionMeta,
315+
mockTransactionMetricRequest,
316+
);
317+
318+
expect(mockEventBuilder.addProperties).toHaveBeenCalledWith(
319+
expect.objectContaining({
320+
builder_test: true,
321+
}),
322+
);
323+
324+
expect(mockEventBuilder.addSensitiveProperties).toHaveBeenCalledWith(
325+
expect.objectContaining({
326+
builder_sensitive_test: true,
327+
}),
328+
);
329+
});
330+
});
215331
});

0 commit comments

Comments
 (0)