Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/bridge-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Bump `@metamask/remote-feature-flag-controller` from `^6.0.0` to `^6.1.0` ([#9980](https://github.com/MetaMask/core/pull/9980))

### Fixed

- Include sufficient-funds and normalized slippage properties in Unified SwapBridge quote metrics ([#9986](https://github.com/MetaMask/core/pull/9986))

## [80.0.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent bridge-status-controller c
"quotes_count": 0,
"quotes_list": [],
"security_warnings": [],
"slippage_limit": undefined,
"slippage_limit": 0,
"source_transaction": "PENDING",
"stx_enabled": false,
"swap_type": "crosschain",
Expand Down Expand Up @@ -262,7 +262,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"price_impact": 6,
"quotes_count": 0,
"quotes_list": [],
"slippage_limit": undefined,
"slippage_limit": 0,
"stx_enabled": false,
"swap_type": "crosschain",
"token_address_destination": null,
Expand Down Expand Up @@ -296,7 +296,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"price_impact": 6,
"quotes_count": 0,
"quotes_list": [],
"slippage_limit": undefined,
"slippage_limit": 0,
"sort_order": "cost_ascending",
"stx_enabled": false,
"swap_type": "crosschain",
Expand Down Expand Up @@ -408,7 +408,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"input_primary_denomination": "token_amount",
"is_hardware_wallet": false,
"location": "Unknown",
"slippage_limit": undefined,
"slippage_limit": 0,
"swap_type": "crosschain",
"token_address_destination": null,
"token_address_source": "eip155:1/slip44:60",
Expand Down Expand Up @@ -443,7 +443,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"quoted_time_minutes": 10,
"quotes_count": 0,
"quotes_list": [],
"slippage_limit": undefined,
"slippage_limit": 0,
"swap_type": "crosschain",
"token_address_destination": null,
"token_address_source": "eip155:1/slip44:60",
Expand Down Expand Up @@ -480,6 +480,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"gas_included": false,
"gas_included_7702": false,
"has_gas_included_quote": false,
"has_sufficient_funds": true,
"initial_load_time_all_quotes": 0,
"input_primary_denomination": "token_amount",
"is_hardware_wallet": false,
Expand All @@ -490,7 +491,7 @@ exports[`BridgeController trackUnifiedSwapBridgeEvent client-side calls should t
"quotes_count": 0,
"quotes_list": [],
"refresh_count": 0,
"slippage_limit": undefined,
"slippage_limit": 0,
"swap_type": "crosschain",
"token_address_destination": null,
"token_address_source": "eip155:1/slip44:60",
Expand Down Expand Up @@ -588,6 +589,7 @@ exports[`BridgeController updateBridgeQuoteRequestParams should only poll once i
"gas_included": false,
"gas_included_7702": false,
"has_gas_included_quote": false,
"has_sufficient_funds": false,
"initial_load_time_all_quotes": 11000,
"input_primary_denomination": "token_amount",
"is_hardware_wallet": false,
Expand Down
3 changes: 2 additions & 1 deletion packages/bridge-controller/src/bridge-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
);

return {
slippage_limit: quoteRequest.slippage,
slippage_limit: quoteRequest.slippage ?? 0,
swap_type: getSwapTypeFromQuote(quoteRequest),
custom_slippage: isCustomSlippage(quoteRequest.slippage),
account_hardware_type: accountHardwareType,
Expand Down Expand Up @@ -1361,6 +1361,7 @@ export class BridgeController extends StaticIntervalPollingController<BridgePoll
...this.#getRequestMetadata(),
...this.#getQuoteFetchData(),
refresh_count: this.state.quotesRefreshCount,
has_sufficient_funds: !quoteRequest.insufficientBal,
...inputPrimaryDenominationProperties,
...baseProperties,
};
Expand Down
64 changes: 64 additions & 0 deletions packages/bridge-controller/src/utils/metrics/properties.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ describe('properties', () => {
"price_impact": 0,
"provider": "bridge1_bridge1",
"quoted_time_minutes": 1,
"slippage_limit": 0,
"token_symbol_destination": "USDC",
"token_symbol_source": "ETH",
"usd_amount_source": 0,
Expand All @@ -445,13 +446,76 @@ describe('properties', () => {
"warnings": [],
}
`);

const quoteWithSlippage = {
...mockQuoteResponseV2,
quote: {
...mockQuoteResponseV2.quote,
slippage: 0.5,
},
};

expect(
getQuotesReceivedProperties(
quoteWithSlippage,
[],
true,
undefined,
undefined,
undefined,
{ slippage_limit: 3.5 },
).slippage_limit,
).toBe(3.5);
expect(
getQuotesReceivedProperties(
quoteWithSlippage,
[],
true,
undefined,
undefined,
undefined,
{ custom_slippage: true, slippage_limit: undefined },
).slippage_limit,
).toBe(0.5);
expect(
getQuotesReceivedProperties(quoteWithSlippage).slippage_limit,
).toBe(0.5);
});

it('should return empty source and null destination token symbols when activeQuote is null', () => {
const result = getQuotesReceivedProperties(null);

expect(result.token_symbol_source).toBe('');
expect(result.token_symbol_destination).toBeNull();
expect(result.slippage_limit).toBe(0);
});

it('should use client fallbacks and explicit slippage context', () => {
const result = getQuotesReceivedProperties(
null,
[],
true,
undefined,
undefined,
undefined,
{
custom_slippage: true,
slippage_limit: 3.5,
usd_amount_source: 100,
token_symbol_source: 'ETH',
token_symbol_destination: 'USDC',
},
);

expect(result).toStrictEqual(
expect.objectContaining({
custom_slippage: true,
slippage_limit: 3.5,
token_symbol_source: 'ETH',
token_symbol_destination: 'USDC',
usd_amount_source: 100,
}),
);
});

it('should derive token symbols from the active quote asset metadata', () => {
Expand Down
32 changes: 29 additions & 3 deletions packages/bridge-controller/src/utils/metrics/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,28 @@ export const getQuotesReceivedProperties = (
recommendedQuote?: null | QuoteResponse,
usdBalanceSource?: number,
hasSufficientGasForQuote?: boolean | null,
options: {
// eslint-disable-next-line @typescript-eslint/naming-convention -- analytics property
custom_slippage?: boolean;
// eslint-disable-next-line @typescript-eslint/naming-convention -- analytics property
slippage_limit?: number;
// eslint-disable-next-line @typescript-eslint/naming-convention -- analytics property
usd_amount_source?: number;
// eslint-disable-next-line @typescript-eslint/naming-convention -- analytics property
token_symbol_source?: string;
// eslint-disable-next-line @typescript-eslint/naming-convention -- analytics property
token_symbol_destination?: string | null;
} = {},
) => {
const provider = activeQuote ? formatProviderLabel(activeQuote.quote) : '_';
const quoteUsdAmountSource = activeQuote?.quote?.src?.usd;
const quoteTokenSymbolSource = activeQuote?.quote.src.asset.symbol;
const quoteTokenSymbolDestination = activeQuote?.quote.dest.asset.symbol;
const usdAmountSource = Number(
quoteUsdAmountSource ?? options.usd_amount_source ?? 0,
);
const slippageLimit =
options.slippage_limit ?? activeQuote?.quote?.slippage ?? 0;
return {
can_submit: isSubmittable,
gas_included: Boolean(activeQuote?.quote?.gasIncluded),
Expand All @@ -178,20 +198,26 @@ export const getQuotesReceivedProperties = (
usd_quoted_gas: Number(activeQuote?.quote?.feeData?.network?.[0]?.usd ?? 0),
usd_quoted_return: Number(activeQuote?.quote?.dest?.usd ?? 0),
usd_balance_source: usdBalanceSource ?? 0,
usd_amount_source: Number(activeQuote?.quote?.src?.usd ?? 0),
usd_amount_source: usdAmountSource,
slippage_limit: slippageLimit,
best_quote_provider: recommendedQuote
? formatProviderLabel(recommendedQuote.quote)
: provider,
provider,
token_symbol_source: activeQuote?.quote.src.asset.symbol ?? '',
token_symbol_destination: activeQuote?.quote.dest.asset.symbol ?? null,
token_symbol_source:
quoteTokenSymbolSource ?? options.token_symbol_source ?? '',
token_symbol_destination:
quoteTokenSymbolDestination ?? options.token_symbol_destination ?? null,
warnings,
price_impact: Number(
activeQuote?.quote.priceData?.priceImpact?.amount ?? 0,
),
...(hasSufficientGasForQuote !== undefined && {
has_sufficient_gas_for_quote: hasSufficientGasForQuote,
}),
...(options.custom_slippage !== undefined && {
custom_slippage: options.custom_slippage,
}),
feature_id: activeQuote?.featureId ?? FeatureId.UNIFIED_SWAP_BRIDGE,
};
};
6 changes: 5 additions & 1 deletion packages/bridge-controller/src/utils/metrics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export type AccountHardwareType =
| null;

export type RequestMetadata = {
slippage_limit?: number; // undefined === auto
slippage_limit: number; // 0 === auto when no numeric limit is available
custom_slippage: boolean;
usd_amount_source: number; // Use quoteResponse when available
stx_enabled: boolean;
Expand Down Expand Up @@ -221,6 +221,7 @@ type RequiredEventContextFromClientBase = {
token_symbol_source: RequestParams['token_symbol_source'];
token_symbol_destination: RequestParams['token_symbol_destination'];
token_security_type_destination: RequestParams['token_security_type_destination'];
custom_slippage?: RequestMetadata['custom_slippage'];
} & InputPrimaryDenominationData;
[UnifiedSwapBridgeEventName.QuotesReceived]: TradeData &
Pick<RequestParams, 'token_symbol_source' | 'token_symbol_destination'> &
Expand All @@ -232,6 +233,8 @@ type RequiredEventContextFromClientBase = {
usd_balance_source?: number;
has_sufficient_gas_for_quote?: boolean | null;
usd_amount_source: number;
custom_slippage?: RequestMetadata['custom_slippage'];
slippage_limit?: RequestMetadata['slippage_limit'];
};
[UnifiedSwapBridgeEventName.QuotesError]: Pick<
RequestMetadata,
Expand Down Expand Up @@ -401,6 +404,7 @@ export type EventPropertiesFromControllerState = {
QuoteFetchData &
TradeData & {
refresh_count: number; // starts from 0
has_sufficient_funds: boolean;
} & InputPrimaryDenominationData;
[UnifiedSwapBridgeEventName.QuotesError]: RequestParams &
RequestMetadata & {
Expand Down
4 changes: 4 additions & 0 deletions packages/bridge-status-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Preserve explicit slippage intent and normalized slippage limits in post-submission Unified SwapBridge metrics ([#9986](https://github.com/MetaMask/core/pull/9986))

## [75.3.0]

### Changed
Expand Down
Loading