Skip to content

Commit 0cee394

Browse files
fix: add token_symbol_source, token_symbol_destination to Unified Swa… (#9213)
## Explanation <!-- Thanks for your contribution! Take a moment to answer these questions so that reviewers have the information they need to properly understand your changes: * What is the current state of things and why does it need to change? * What is the solution your changes offer and how does it work? * Are there any changes whose purpose might not obvious to those unfamiliar with the domain? * If your primary goal was to update one package but you found you had to update another one along the way, why did you do so? * If you had to upgrade a dependency, why did you do so? --> The `Unified SwapBridge Quotes Received` analytics event is expected to include `token_symbol_source` and `token_symbol_destination` as part of `RequestParams`, but clients building the event payload via `getQuotesReceivedProperties` were not getting those fields. The helper only returned quote/trade-specific properties (gas, provider, warnings, etc.). `getQuotesReceivedProperties` now derives token symbols from the active quote's asset metadata (`activeQuote.quote.srcAsset.symbol` and `activeQuote.quote.destAsset.symbol`). When no active quote is available (e.g. polling stopped while quotes are still loading), fallbacks match `RequestParams`: `''` for source and `null` for destination. `RequiredEventContextFromClient` for `QuotesReceived` is updated to include the symbol fields so the client context type aligns with the full event payload. The `getRequestParams` JSDoc is updated to point callers to `getQuotesReceivedProperties` for symbols, since the quote request only stores addresses. No dependency upgrades in this PR. Extension <img width="853" height="941" alt="Screenshot 2026-06-19 at 12 06 35 PM" src="https://github.com/user-attachments/assets/9c6067b5-fbc3-457a-8472-33cecf971283" /> Mobile <img width="1539" height="811" alt="Screenshot 2026-06-17 at 1 23 28 PM" src="https://github.com/user-attachments/assets/22ff0021-c8c7-47ae-a029-7e5d058564ec" /> ## References <!-- Are there any issues that this pull request is tied to? Are there other links that reviewers should consult to understand these changes better? Are there client or consumer pull requests to adopt any breaking changes? For example: * Fixes #12345 * Related to #67890 --> Fixes [SWAPS-4538](https://consensyssoftware.atlassian.net/browse/SWAPS-4538) ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them [SWAPS-4538]: https://consensyssoftware.atlassian.net/browse/SWAPS-4538?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Analytics-only payload fix in bridge metrics helpers; no transaction or auth logic changes. > > **Overview** > Fixes **Unified SwapBridge Quotes Received** analytics so `token_symbol_source` and `token_symbol_destination` are included when clients build the event via `getQuotesReceivedProperties`. > > `getQuotesReceivedProperties` now sets those fields from the active quote’s `srcAsset` / `destAsset` symbols (`''` and `null` when there is no active quote). The `QuotesReceived` event context type is updated to require the symbol fields, and `getRequestParams` docs point callers at `getQuotesReceivedProperties` for symbols. Tests and a bridge-status-controller snapshot reflect the new payload shape. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit e1137f3. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 9214097 commit 0cee394

5 files changed

Lines changed: 112 additions & 14 deletions

File tree

packages/bridge-controller/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
### Changed
1515

1616
- Bump `@metamask/assets-controllers` from `^109.0.0` to `^109.2.0` ([#9110](https://github.com/MetaMask/core/pull/9110), [#9202](https://github.com/MetaMask/core/pull/9202))
17+
- Bump `@metamask/assets-controllers` from `^109.0.0` to `^109.1.0` ([#9110](https://github.com/MetaMask/core/pull/9110))
1718
- Refactor selector unit tests to prepare for V2 QuoteResponse migration ([#9098](https://github.com/MetaMask/core/pull/9098))
1819
- Bump `@metamask/utils` from `^11.9.0` to `^11.11.0` ([#9074](https://github.com/MetaMask/core/pull/9074))
1920
- Bump `@metamask/assets-controller` from `^9.0.0` to `^9.0.1` ([#9083](https://github.com/MetaMask/core/pull/9083))
2021
- Bump `@metamask/controller-utils` from `^12.1.1` to `^12.2.0` ([#9083](https://github.com/MetaMask/core/pull/9083))
2122
- Bump `@metamask/transaction-controller` from `^67.1.0` to `^68.1.0` ([#9089](https://github.com/MetaMask/core/pull/9089), [#9177](https://github.com/MetaMask/core/pull/9177), [#9203](https://github.com/MetaMask/core/pull/9203))
2223
- Bump `@metamask/profile-sync-controller` from `^28.1.1` to `^28.2.0` ([#9119](https://github.com/MetaMask/core/pull/9119))
2324

25+
### Fixed
26+
27+
- Include `token_symbol_source` and `token_symbol_destination` in `getQuotesReceivedProperties` return value, derived from the active quote's asset metadata ([#9213](https://github.com/MetaMask/core/pull/9213))
28+
2429
## [75.1.1]
2530

2631
### Changed

packages/bridge-controller/src/utils/metrics/properties.test.ts

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SolScope } from '@metamask/keyring-api';
22
import type { CaipChainId } from '@metamask/utils';
33

4-
import type { QuoteResponseV1 } from '../../types';
4+
import type { QuoteMetadata, QuoteResponseV1 } from '../../types';
55
import { getNativeAssetForChainId } from '../bridge';
66
import { formatChainIdToCaip } from '../caip-formatters';
77
import { MetricsSwapType } from './constants';
@@ -214,7 +214,7 @@ describe('properties', () => {
214214
chainId: 1,
215215
to: '0x789',
216216
from: '0xabc',
217-
value: '0',
217+
value: '0x0',
218218
data: '0x',
219219
gasLimit: 100000,
220220
},
@@ -361,8 +361,26 @@ describe('properties', () => {
361361
});
362362

363363
describe('getQuotesReceivedProperties', () => {
364+
const mockTokenAmount = { amount: '0', valueInCurrency: '0', usd: '0' };
365+
const mockQuoteMetadata: QuoteMetadata = {
366+
gasFee: {
367+
effective: mockTokenAmount,
368+
total: mockTokenAmount,
369+
max: mockTokenAmount,
370+
},
371+
totalNetworkFee: mockTokenAmount,
372+
totalMaxNetworkFee: mockTokenAmount,
373+
toTokenAmount: mockTokenAmount,
374+
minToTokenAmount: mockTokenAmount,
375+
adjustedReturn: { valueInCurrency: '0', usd: '0' },
376+
sentAmount: mockTokenAmount,
377+
swapRate: '0',
378+
cost: { valueInCurrency: '0', usd: '0' },
379+
};
380+
364381
it('should return quotes received properties correctly', () => {
365-
const mockQuoteResponse: QuoteResponseV1 = {
382+
const mockQuoteResponse: QuoteResponseV1 & QuoteMetadata = {
383+
...mockQuoteMetadata,
366384
quote: {
367385
requestId: 'request1',
368386
srcChainId: 1,
@@ -407,7 +425,7 @@ describe('properties', () => {
407425
chainId: 1,
408426
to: '0x789',
409427
from: '0xabc',
410-
value: '0',
428+
value: '0x0',
411429
data: '0x',
412430
gasLimit: 100000,
413431
},
@@ -433,12 +451,81 @@ describe('properties', () => {
433451
"price_impact": 0,
434452
"provider": "bridge1_bridge1",
435453
"quoted_time_minutes": 1,
454+
"token_symbol_destination": "USDC",
455+
"token_symbol_source": "ETH",
436456
"usd_balance_source": 0,
437457
"usd_quoted_gas": 0,
438458
"usd_quoted_return": 0,
439459
"warnings": [],
440460
}
441461
`);
442462
});
463+
464+
it('should return empty source and null destination token symbols when activeQuote is null', () => {
465+
const result = getQuotesReceivedProperties(null);
466+
467+
expect(result.token_symbol_source).toBe('');
468+
expect(result.token_symbol_destination).toBeNull();
469+
});
470+
471+
it('should derive token symbols from the active quote asset metadata', () => {
472+
const mockQuoteResponse: QuoteResponseV1 & QuoteMetadata = {
473+
...mockQuoteMetadata,
474+
quote: {
475+
requestId: 'request1',
476+
srcChainId: 1,
477+
srcAsset: {
478+
chainId: 1,
479+
address: '0x123',
480+
symbol: 'WETH',
481+
name: 'Wrapped Ether',
482+
decimals: 18,
483+
assetId: 'eip155:1/erc20:0x123',
484+
},
485+
srcTokenAmount: '1000000000000000000',
486+
destChainId: 1,
487+
destAsset: {
488+
chainId: 1,
489+
address: '0x456',
490+
symbol: 'DAI',
491+
name: 'Dai Stablecoin',
492+
decimals: 18,
493+
assetId: 'eip155:1/erc20:0x456',
494+
},
495+
destTokenAmount: '1000000',
496+
minDestTokenAmount: '950000',
497+
feeData: {
498+
metabridge: {
499+
amount: '10000000000000000',
500+
asset: {
501+
chainId: 1,
502+
address: '0x123',
503+
symbol: 'WETH',
504+
name: 'Wrapped Ether',
505+
decimals: 18,
506+
assetId: 'eip155:1/erc20:0x123',
507+
},
508+
},
509+
},
510+
bridgeId: 'bridge1',
511+
bridges: ['bridge1'],
512+
steps: [],
513+
},
514+
trade: {
515+
chainId: 1,
516+
to: '0x789',
517+
from: '0xabc',
518+
value: '0x0',
519+
data: '0x',
520+
gasLimit: 100000,
521+
},
522+
estimatedProcessingTimeInSeconds: 60,
523+
};
524+
525+
const result = getQuotesReceivedProperties(mockQuoteResponse);
526+
527+
expect(result.token_symbol_source).toBe('WETH');
528+
expect(result.token_symbol_destination).toBe('DAI');
529+
});
443530
});
444531
});

packages/bridge-controller/src/utils/metrics/properties.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ export const formatProviderLabel = ({
8888
* @param tokenSecurityTypeDestination - The security classification of the destination token,
8989
* supplied by the client (e.g. from token security/scanning data). Pass `null` when no
9090
* security data is available for the selected destination token.
91-
* @returns The analytics request params derived from the quote request, minus token symbols
92-
* which the caller provides separately.
91+
* @returns The analytics request params derived from the quote request. Token symbols are
92+
* omitted because the quote request only stores addresses; use
93+
* {@link getQuotesReceivedProperties} when building a `QuotesReceived` payload.
9394
*/
9495
export const getRequestParams = (
9596
{
@@ -178,6 +179,8 @@ export const getQuotesReceivedProperties = (
178179
? formatProviderLabel(recommendedQuote.quote)
179180
: provider,
180181
provider,
182+
token_symbol_source: activeQuote?.quote.srcAsset.symbol ?? '',
183+
token_symbol_destination: activeQuote?.quote.destAsset.symbol ?? null,
181184
warnings,
182185
price_impact: Number(activeQuote?.quote.priceData?.priceImpact ?? 0),
183186
...(hasSufficientGasForQuote !== undefined && {

packages/bridge-controller/src/utils/metrics/types.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,15 @@ type RequiredEventContextFromClientBase = {
142142
token_symbol_destination: RequestParams['token_symbol_destination'];
143143
token_security_type_destination: RequestParams['token_security_type_destination'];
144144
};
145-
[UnifiedSwapBridgeEventName.QuotesReceived]: TradeData & {
146-
warnings: QuoteWarning[];
147-
best_quote_provider: QuoteFetchData['best_quote_provider'];
148-
price_impact: QuoteFetchData['price_impact'];
149-
can_submit: QuoteFetchData['can_submit'];
150-
usd_balance_source?: number;
151-
has_sufficient_gas_for_quote?: boolean | null;
152-
};
145+
[UnifiedSwapBridgeEventName.QuotesReceived]: TradeData &
146+
Pick<RequestParams, 'token_symbol_source' | 'token_symbol_destination'> & {
147+
warnings: QuoteWarning[];
148+
best_quote_provider: QuoteFetchData['best_quote_provider'];
149+
price_impact: QuoteFetchData['price_impact'];
150+
can_submit: QuoteFetchData['can_submit'];
151+
usd_balance_source?: number;
152+
has_sufficient_gas_for_quote?: boolean | null;
153+
};
153154
[UnifiedSwapBridgeEventName.QuotesError]: Pick<
154155
RequestMetadata,
155156
'stx_enabled'

packages/bridge-status-controller/src/__snapshots__/bridge-status-controller.test.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,8 @@ exports[`BridgeStatusController submitTx: EVM bridge should handle smart transac
12821282
"price_impact": 0,
12831283
"provider": "lifi_across",
12841284
"quoted_time_minutes": 0.25,
1285+
"token_symbol_destination": "ETH",
1286+
"token_symbol_source": "ETH",
12851287
"usd_balance_source": 0,
12861288
"usd_quoted_gas": 2.5778,
12871289
"usd_quoted_return": 0.134214,

0 commit comments

Comments
 (0)