Skip to content

Commit ddc4a85

Browse files
dan437rarquevaux
andauthored
feat: Add metrics for gasless 7702, refactoring (#6363)
## Explanation This PR adds metrics for gasless 7702 and includes refactoring (renaming, updated gasIncluded7702 checks). It also makes the `getBridgeHistoryItemByTxMetaId` function available via messaging system. ## References ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [ ] 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/contributing.md#updating-changelogs), highlighting breaking changes as necessary - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --------- Signed-off-by: dan437 <[email protected]> Co-authored-by: rarquevaux <[email protected]>
1 parent 2e4ac7f commit ddc4a85

20 files changed

+236
-43
lines changed

packages/bridge-controller/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add `gas_included_7702` field to metrics tracking for EIP-7702 gasless transactions ([#6363](https://github.com/MetaMask/core/pull/6363))
13+
1014
### Changed
1115

1216
- **BREAKING** Rename QuotesError and InputSourceDestinationSwitched events to match segment schema ([#6447](https://github.com/MetaMask/core/pull/6447))
1317
- Bump `@metamask/base-controller` from `^8.2.0` to `^8.3.0` ([#6465](https://github.com/MetaMask/core/pull/6465))
18+
- **BREAKING** Rename `gasless7702` to `gasIncluded7702` in QuoteRequest and Quote types
1419

1520
## [41.4.0]
1621

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Array [
6363
"custom_slippage": true,
6464
"destination_transaction": "PENDING",
6565
"gas_included": false,
66+
"gas_included_7702": false,
6667
"is_hardware_wallet": false,
6768
"price_impact": 6,
6869
"provider": "provider_bridge",
@@ -101,6 +102,7 @@ Array [
101102
"destination_transaction": "PENDING",
102103
"error_message": "error_message",
103104
"gas_included": false,
105+
"gas_included_7702": false,
104106
"initial_load_time_all_quotes": 0,
105107
"is_hardware_wallet": false,
106108
"price_impact": 0,
@@ -136,6 +138,7 @@ Array [
136138
"custom_slippage": true,
137139
"error_message": "Failed to submit tx",
138140
"gas_included": false,
141+
"gas_included_7702": false,
139142
"initial_load_time_all_quotes": 0,
140143
"is_hardware_wallet": false,
141144
"price_impact": 12,
@@ -171,6 +174,7 @@ Array [
171174
"chain_id_source": "eip155:1",
172175
"custom_slippage": false,
173176
"gas_included": false,
177+
"gas_included_7702": false,
174178
"is_hardware_wallet": false,
175179
"price_impact": 0,
176180
"provider": "provider_bridge",
@@ -210,6 +214,7 @@ Array [
210214
"chain_id_source": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
211215
"custom_slippage": false,
212216
"gas_included": false,
217+
"gas_included_7702": false,
213218
"is_hardware_wallet": false,
214219
"price_impact": 12,
215220
"provider": "provider_bridge",
@@ -367,6 +372,7 @@ Array [
367372
"chain_id_source": "eip155:1",
368373
"custom_slippage": false,
369374
"gas_included": false,
375+
"gas_included_7702": false,
370376
"initial_load_time_all_quotes": 0,
371377
"is_best_quote": true,
372378
"is_hardware_wallet": false,
@@ -398,6 +404,7 @@ Array [
398404
"chain_id_source": "eip155:1",
399405
"custom_slippage": false,
400406
"gas_included": false,
407+
"gas_included_7702": false,
401408
"initial_load_time_all_quotes": 0,
402409
"is_hardware_wallet": false,
403410
"price_impact": 0,
@@ -485,6 +492,7 @@ Array [
485492
"chain_id_source": "eip155:1",
486493
"custom_slippage": true,
487494
"gas_included": false,
495+
"gas_included_7702": false,
488496
"initial_load_time_all_quotes": 11000,
489497
"is_hardware_wallet": false,
490498
"price_impact": 0,

packages/bridge-controller/src/bridge-controller.test.ts

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ describe('BridgeController', function () {
911911
warnings: ['warning1'],
912912
usd_quoted_gas: 0,
913913
gas_included: false,
914+
gas_included_7702: false,
914915
quoted_time_minutes: 10,
915916
usd_quoted_return: 100,
916917
price_impact: 0,
@@ -1494,6 +1495,66 @@ describe('BridgeController', function () {
14941495
);
14951496
});
14961497

1498+
it('returns early on AbortError without updating post-fetch state', async () => {
1499+
jest.useFakeTimers();
1500+
1501+
const abortError = new Error('Aborted');
1502+
// Make it look like an AbortError to hit the early return
1503+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1504+
// @ts-ignore
1505+
abortError.name = 'AbortError';
1506+
1507+
const fetchBridgeQuotesSpy = jest
1508+
.spyOn(fetchUtils, 'fetchBridgeQuotes')
1509+
.mockImplementationOnce(
1510+
async () =>
1511+
await new Promise((_resolve, reject) => {
1512+
setTimeout(() => reject(abortError), 1000);
1513+
}),
1514+
);
1515+
1516+
// Minimal messenger/env setup to allow polling to start
1517+
messengerMock.call.mockReturnValue({
1518+
address: '0x123',
1519+
provider: jest.fn(),
1520+
selectedNetworkClientId: 'selectedNetworkClientId',
1521+
currencyRates: {},
1522+
marketData: {},
1523+
conversionRates: {},
1524+
} as never);
1525+
1526+
jest.spyOn(balanceUtils, 'hasSufficientBalance').mockResolvedValue(true);
1527+
1528+
const quoteParams = {
1529+
srcChainId: '0x1',
1530+
destChainId: '0xa',
1531+
srcTokenAddress: '0x0000000000000000000000000000000000000000',
1532+
destTokenAddress: '0x123',
1533+
srcTokenAmount: '1000000000000000000',
1534+
walletAddress: '0x123',
1535+
slippage: 0.5,
1536+
};
1537+
1538+
await bridgeController.updateBridgeQuoteRequestParams(
1539+
quoteParams,
1540+
metricsContext,
1541+
);
1542+
1543+
// Trigger the fetch + abort rejection
1544+
jest.advanceTimersByTime(1000);
1545+
await flushPromises();
1546+
1547+
// Early return path: no post-fetch updates
1548+
expect(fetchBridgeQuotesSpy).toHaveBeenCalledTimes(1);
1549+
expect(bridgeController.state.quoteFetchError).toBeNull();
1550+
expect(bridgeController.state.quotesLoadingStatus).toBe(
1551+
RequestStatus.LOADING,
1552+
);
1553+
expect(bridgeController.state.quotesLastFetched).toBeNull();
1554+
expect(bridgeController.state.quotesRefreshCount).toBe(0);
1555+
expect(bridgeController.state.quotes).toStrictEqual([]);
1556+
});
1557+
14971558
it.each([
14981559
[
14991560
'should append solanaFees for Solana quotes',
@@ -1821,6 +1882,7 @@ describe('BridgeController', function () {
18211882
is_best_quote: true,
18221883
usd_quoted_gas: 0,
18231884
gas_included: false,
1885+
gas_included_7702: false,
18241886
quoted_time_minutes: 10,
18251887
usd_quoted_return: 100,
18261888
price_impact: 0,
@@ -1841,6 +1903,7 @@ describe('BridgeController', function () {
18411903
warnings: ['warning1'],
18421904
usd_quoted_gas: 0,
18431905
gas_included: false,
1906+
gas_included_7702: false,
18441907
quoted_time_minutes: 10,
18451908
usd_quoted_return: 100,
18461909
price_impact: 0,
@@ -1893,6 +1956,7 @@ describe('BridgeController', function () {
18931956
price_impact: 0,
18941957
usd_quoted_gas: 0,
18951958
gas_included: false,
1959+
gas_included_7702: false,
18961960
quoted_time_minutes: 0,
18971961
usd_quoted_return: 0,
18981962
provider: 'provider_bridge',
@@ -1926,6 +1990,7 @@ describe('BridgeController', function () {
19261990
slippage_limit: 0.5,
19271991
usd_quoted_gas: 1,
19281992
gas_included: false,
1993+
gas_included_7702: false,
19291994
quoted_time_minutes: 2,
19301995
usd_quoted_return: 113,
19311996
provider: 'provider_bridge',
@@ -1965,6 +2030,7 @@ describe('BridgeController', function () {
19652030
provider: 'provider_bridge',
19662031
price_impact: 6,
19672032
gas_included: false,
2033+
gas_included_7702: false,
19682034
usd_quoted_gas: 0,
19692035
quoted_time_minutes: 0,
19702036
usd_quoted_return: 0,
@@ -1988,6 +2054,7 @@ describe('BridgeController', function () {
19882054
destination_transaction: StatusTypes.PENDING,
19892055
usd_quoted_gas: 0,
19902056
gas_included: false,
2057+
gas_included_7702: false,
19912058
quoted_time_minutes: 0,
19922059
usd_quoted_return: 0,
19932060
price_impact: 0,
@@ -2040,6 +2107,7 @@ describe('BridgeController', function () {
20402107
error_message: 'Failed to submit tx',
20412108
usd_quoted_gas: 1,
20422109
gas_included: false,
2110+
gas_included_7702: false,
20432111
quoted_time_minutes: 2,
20442112
usd_quoted_return: 113,
20452113
provider: 'provider_bridge',
@@ -2140,6 +2208,7 @@ describe('BridgeController', function () {
21402208
warnings: ['warning1'],
21412209
usd_quoted_gas: 0,
21422210
gas_included: false,
2211+
gas_included_7702: false,
21432212
quoted_time_minutes: 10,
21442213
usd_quoted_return: 100,
21452214
price_impact: 0,
@@ -2215,7 +2284,7 @@ describe('BridgeController', function () {
22152284
aggIds: ['other'],
22162285
bridgeIds: ['other', 'debridge'],
22172286
gasIncluded: false,
2218-
gasless7702: false,
2287+
gasIncluded7702: false,
22192288
noFee: false,
22202289
},
22212290
null,
@@ -2238,7 +2307,7 @@ describe('BridgeController', function () {
22382307
"destChainId": "1",
22392308
"destTokenAddress": "0x1234",
22402309
"gasIncluded": false,
2241-
"gasless7702": false,
2310+
"gasIncluded7702": false,
22422311
"noFee": true,
22432312
"slippage": 0.5,
22442313
"srcChainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
@@ -2276,7 +2345,7 @@ describe('BridgeController', function () {
22762345
walletAddress: '0x123',
22772346
slippage: 0.5,
22782347
gasIncluded: false,
2279-
gasless7702: false,
2348+
gasIncluded7702: false,
22802349
},
22812350
null,
22822351
FeatureId.PERPS,
@@ -2298,7 +2367,7 @@ describe('BridgeController', function () {
22982367
"destChainId": "1",
22992368
"destTokenAddress": "0x1234",
23002369
"gasIncluded": false,
2301-
"gasless7702": false,
2370+
"gasIncluded7702": false,
23022371
"noFee": true,
23032372
"slippage": 0.5,
23042373
"srcChainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
@@ -2336,7 +2405,7 @@ describe('BridgeController', function () {
23362405
walletAddress: '0x123',
23372406
slippage: 0.5,
23382407
gasIncluded: false,
2339-
gasless7702: false,
2408+
gasIncluded7702: false,
23402409
},
23412410
null,
23422411
);
@@ -2349,7 +2418,7 @@ describe('BridgeController', function () {
23492418
"destChainId": "1",
23502419
"destTokenAddress": "0x1234",
23512420
"gasIncluded": false,
2352-
"gasless7702": false,
2421+
"gasIncluded7702": false,
23532422
"slippage": 0.5,
23542423
"srcChainId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
23552424
"srcTokenAddress": "NATIVE",

packages/bridge-controller/src/selectors.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ describe('Bridge Selectors', () => {
472472
txFee,
473473
},
474474
gasIncluded: Boolean(txFee),
475+
gasIncluded7702: false,
475476
srcTokenAmount,
476477
destTokenAmount: new BigNumber('9')
477478
.dividedBy(marketData['0x38'][destAsset.address].price)

packages/bridge-controller/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ export type QuoteRequest<
222222
/**
223223
* Whether to request quotes that use EIP-7702 delegated gasless execution
224224
*/
225-
gasless7702: boolean;
225+
gasIncluded7702: boolean;
226226
noFee?: boolean;
227227
};
228228

packages/bridge-controller/src/utils/fetch.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,15 @@ describe('fetch', () => {
159159

160160
const result = await fetchBridgeQuotes(
161161
{
162-
walletAddress: '0x388c818ca8b9251b393131c08a736a67ccb19297',
162+
walletAddress: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
163163
srcChainId: 1,
164164
destChainId: 10,
165165
srcTokenAddress: AddressZero,
166166
destTokenAddress: AddressZero,
167167
srcTokenAmount: '20000',
168168
slippage: 0.5,
169169
gasIncluded: false,
170-
gasless7702: false,
170+
gasIncluded7702: false,
171171
},
172172
signal,
173173
BridgeClientId.EXTENSION,
@@ -176,7 +176,7 @@ describe('fetch', () => {
176176
);
177177

178178
expect(mockFetchFn).toHaveBeenCalledWith(
179-
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&destWalletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasless7702=false&slippage=0.5',
179+
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&destWalletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasIncluded7702=false&slippage=0.5',
180180
{
181181
cacheOptions: {
182182
cacheRefreshTime: 0,
@@ -213,15 +213,15 @@ describe('fetch', () => {
213213

214214
const result = await fetchBridgeQuotes(
215215
{
216-
walletAddress: '0x388c818ca8b9251b393131c08a736a67ccb19297',
216+
walletAddress: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
217217
srcChainId: 1,
218218
destChainId: 10,
219219
srcTokenAddress: AddressZero,
220220
destTokenAddress: AddressZero,
221221
srcTokenAmount: '20000',
222222
slippage: 0.5,
223223
gasIncluded: false,
224-
gasless7702: false,
224+
gasIncluded7702: false,
225225
},
226226
signal,
227227
BridgeClientId.EXTENSION,
@@ -230,7 +230,7 @@ describe('fetch', () => {
230230
);
231231

232232
expect(mockFetchFn).toHaveBeenCalledWith(
233-
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&destWalletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasless7702=false&slippage=0.5',
233+
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&destWalletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasIncluded7702=false&slippage=0.5',
234234
{
235235
cacheOptions: {
236236
cacheRefreshTime: 0,
@@ -285,15 +285,15 @@ describe('fetch', () => {
285285

286286
const result = await fetchBridgeQuotes(
287287
{
288-
walletAddress: '0x388c818ca8b9251b393131c08a736a67ccb19297',
288+
walletAddress: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
289289
srcChainId: 1,
290290
destChainId: 10,
291291
srcTokenAddress: AddressZero,
292292
destTokenAddress: AddressZero,
293293
srcTokenAmount: '20000',
294294
slippage: 0.5,
295295
gasIncluded: false,
296-
gasless7702: false,
296+
gasIncluded7702: false,
297297
},
298298
signal,
299299
BridgeClientId.EXTENSION,
@@ -302,7 +302,7 @@ describe('fetch', () => {
302302
);
303303

304304
expect(mockFetchFn).toHaveBeenCalledWith(
305-
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&destWalletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasless7702=false&slippage=0.5',
305+
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&destWalletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasIncluded7702=false&slippage=0.5',
306306
{
307307
cacheOptions: {
308308
cacheRefreshTime: 0,
@@ -349,15 +349,15 @@ describe('fetch', () => {
349349

350350
const result = await fetchBridgeQuotes(
351351
{
352-
walletAddress: '0x388c818ca8b9251b393131c08a736a67ccb19297',
352+
walletAddress: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984',
353353
srcChainId: 1,
354354
destChainId: 10,
355355
srcTokenAddress: AddressZero,
356356
destTokenAddress: AddressZero,
357357
srcTokenAmount: '20000',
358358
slippage: 0.5,
359359
gasIncluded: false,
360-
gasless7702: false,
360+
gasIncluded7702: false,
361361
aggIds: ['socket', 'lifi'],
362362
bridgeIds: ['bridge1', 'bridge2'],
363363
noFee: true,
@@ -369,7 +369,7 @@ describe('fetch', () => {
369369
);
370370

371371
expect(mockFetchFn).toHaveBeenCalledWith(
372-
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&destWalletAddress=0x388C818CA8B9251b393131C08a736A67ccB19297&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasless7702=false&slippage=0.5&noFee=true&aggIds=socket%2Clifi&bridgeIds=bridge1%2Cbridge2',
372+
'https://bridge.api.cx.metamask.io/getQuote?walletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&destWalletAddress=0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984&srcChainId=1&destChainId=10&srcTokenAddress=0x0000000000000000000000000000000000000000&destTokenAddress=0x0000000000000000000000000000000000000000&srcTokenAmount=20000&insufficientBal=false&resetApproval=false&gasIncluded=false&gasIncluded7702=false&slippage=0.5&noFee=true&aggIds=socket%2Clifi&bridgeIds=bridge1%2Cbridge2',
373373
{
374374
cacheOptions: {
375375
cacheRefreshTime: 0,

0 commit comments

Comments
 (0)