@metamask/bridge-controller 71.1.0 → 72.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/dist/bridge-controller.cjs +150 -102
- package/dist/bridge-controller.cjs.map +1 -1
- package/dist/bridge-controller.d.cts +14 -4
- package/dist/bridge-controller.d.cts.map +1 -1
- package/dist/bridge-controller.d.mts +14 -4
- package/dist/bridge-controller.d.mts.map +1 -1
- package/dist/bridge-controller.mjs +151 -103
- package/dist/bridge-controller.mjs.map +1 -1
- package/dist/constants/bridge.cjs +5 -3
- package/dist/constants/bridge.cjs.map +1 -1
- package/dist/constants/bridge.d.cts.map +1 -1
- package/dist/constants/bridge.d.mts.map +1 -1
- package/dist/constants/bridge.mjs +5 -3
- package/dist/constants/bridge.mjs.map +1 -1
- package/dist/constants/traces.cjs +1 -0
- package/dist/constants/traces.cjs.map +1 -1
- package/dist/constants/traces.d.cts +1 -0
- package/dist/constants/traces.d.cts.map +1 -1
- package/dist/constants/traces.d.mts +1 -0
- package/dist/constants/traces.d.mts.map +1 -1
- package/dist/constants/traces.mjs +1 -0
- package/dist/constants/traces.mjs.map +1 -1
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/selectors.cjs +89 -33
- package/dist/selectors.cjs.map +1 -1
- package/dist/selectors.d.cts +7163 -76
- package/dist/selectors.d.cts.map +1 -1
- package/dist/selectors.d.mts +7163 -76
- package/dist/selectors.d.mts.map +1 -1
- package/dist/selectors.mjs +88 -32
- package/dist/selectors.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +6 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +6 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/utils/fetch.cjs +61 -17
- package/dist/utils/fetch.cjs.map +1 -1
- package/dist/utils/fetch.d.cts +3 -4
- package/dist/utils/fetch.d.cts.map +1 -1
- package/dist/utils/fetch.d.mts +3 -4
- package/dist/utils/fetch.d.mts.map +1 -1
- package/dist/utils/fetch.mjs +62 -18
- package/dist/utils/fetch.mjs.map +1 -1
- package/dist/utils/metrics/properties.cjs +1 -1
- package/dist/utils/metrics/properties.cjs.map +1 -1
- package/dist/utils/metrics/properties.mjs +1 -1
- package/dist/utils/metrics/properties.mjs.map +1 -1
- package/dist/utils/quote.cjs +3 -1
- package/dist/utils/quote.cjs.map +1 -1
- package/dist/utils/quote.d.cts +1 -0
- package/dist/utils/quote.d.cts.map +1 -1
- package/dist/utils/quote.d.mts +1 -0
- package/dist/utils/quote.d.mts.map +1 -1
- package/dist/utils/quote.mjs +1 -0
- package/dist/utils/quote.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _BridgeController_instances, _BridgeController_abortController, _BridgeController_quotesFirstFetched, _BridgeController_location, _BridgeController_clientId, _BridgeController_clientVersion, _BridgeController_getLayer1GasFee, _BridgeController_fetchFn, _BridgeController_trackMetaMetricsFn, _BridgeController_trace, _BridgeController_config, _BridgeController_getUseAssetsControllerForRates, _BridgeController_trackQuoteValidationFailures, _BridgeController_getExchangeRateSources, _BridgeController_fetchAssetExchangeRates, _BridgeController_hasInsufficientBalance, _BridgeController_shouldResetApproval, _BridgeController_fetchBridgeQuotes, _BridgeController_handleQuoteStreaming, _BridgeController_setMinimumBalanceForRentExemptionInLamports, _BridgeController_getMultichainSelectedAccount, _BridgeController_getNetworkClientByChainId, _BridgeController_getJwt, _BridgeController_getRequestMetadata, _BridgeController_getQuoteFetchData, _BridgeController_getEventProperties, _BridgeController_trackInputChangedEvents, _BridgeController_getUSDTMainnetAllowance;
|
|
12
|
+
var _BridgeController_instances, _BridgeController_abortController, _BridgeController_quotesFirstFetched, _BridgeController_location, _BridgeController_clientId, _BridgeController_clientVersion, _BridgeController_getLayer1GasFee, _BridgeController_fetchFn, _BridgeController_trackMetaMetricsFn, _BridgeController_trace, _BridgeController_config, _BridgeController_getUseAssetsControllerForRates, _BridgeController_trackQuoteValidationFailures, _BridgeController_getExchangeRateSources, _BridgeController_fetchAssetExchangeRates, _BridgeController_hasInsufficientBalance, _BridgeController_appendInsufficientBalAndResetApproval, _BridgeController_shouldResetApproval, _BridgeController_fetchBridgeQuotes, _BridgeController_handleQuoteStreaming, _BridgeController_setMinimumBalanceForRentExemptionInLamports, _BridgeController_getMultichainSelectedAccount, _BridgeController_getNetworkClientByChainId, _BridgeController_getJwt, _BridgeController_getRequestMetadata, _BridgeController_getQuoteFetchData, _BridgeController_getEventProperties, _BridgeController_trackInputChangedEvents, _BridgeController_getUSDTMainnetAllowance;
|
|
13
13
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
14
14
|
import { BigNumber } from "@ethersproject/bignumber";
|
|
15
15
|
import { Contract } from "@ethersproject/contracts";
|
|
@@ -30,7 +30,7 @@ import { getBridgeFeatureFlags, hasMinimumRequiredVersion } from "./utils/featur
|
|
|
30
30
|
import { fetchAssetPrices, fetchBridgeQuotes, fetchBridgeQuoteStream } from "./utils/fetch.mjs";
|
|
31
31
|
import { AbortReason, MetaMetricsSwapsEventSource, MetricsActionType, UnifiedSwapBridgeEventName } from "./utils/metrics/constants.mjs";
|
|
32
32
|
import { formatProviderLabel, getAccountHardwareType, getRequestParams, getSwapTypeFromQuote, isCustomSlippage, toInputChangedPropertyKey, toInputChangedPropertyValue } from "./utils/metrics/properties.mjs";
|
|
33
|
-
import { isValidQuoteRequest, sortQuotes } from "./utils/quote.mjs";
|
|
33
|
+
import { isValidQuoteRequest, isValidBatchSellQuoteRequest, sortQuotes } from "./utils/quote.mjs";
|
|
34
34
|
import { appendFeesToQuotes } from "./utils/quote-fees.mjs";
|
|
35
35
|
import { getMinimumBalanceForRentExemptionInLamports } from "./utils/snaps.mjs";
|
|
36
36
|
const metadata = {
|
|
@@ -153,54 +153,48 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
153
153
|
this._executePoll = async (pollingInput) => {
|
|
154
154
|
await __classPrivateFieldGet(this, _BridgeController_fetchBridgeQuotes, "f").call(this, pollingInput);
|
|
155
155
|
};
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Updates the quote request at the specified index with the given parameters, then starts
|
|
158
|
+
* polling for quotes.
|
|
159
|
+
*
|
|
160
|
+
* @param paramsToUpdate - The parameters to update in the quote request at the specified index
|
|
161
|
+
* @param context - metrics context
|
|
162
|
+
* @param quoteRequestIndex - The index of the quote request to update
|
|
163
|
+
* @param quoteRequestCount - The number of quote requests in the UI
|
|
164
|
+
*/
|
|
165
|
+
this.updateBridgeQuoteRequestParams = async (paramsToUpdate, context, quoteRequestIndex = 0, quoteRequestCount = 1) => {
|
|
166
|
+
// Guard against updating a quote request that doesn't exist
|
|
167
|
+
if (quoteRequestIndex >= quoteRequestCount) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
__classPrivateFieldGet(this, _BridgeController_trackInputChangedEvents, "f").call(this, paramsToUpdate, quoteRequestIndex);
|
|
171
|
+
this.resetState(AbortReason.QuoteRequestUpdated, quoteRequestIndex);
|
|
163
172
|
this.update((state) => {
|
|
164
|
-
|
|
173
|
+
// Update only the specified quote request and keep the rest of the quote requests unchanged
|
|
174
|
+
state.quoteRequest = state.quoteRequest
|
|
175
|
+
.slice(0, quoteRequestIndex)
|
|
176
|
+
.concat({
|
|
177
|
+
...DEFAULT_BRIDGE_CONTROLLER_STATE.quoteRequest[0],
|
|
178
|
+
...paramsToUpdate,
|
|
179
|
+
})
|
|
180
|
+
.concat(state.quoteRequest.slice(quoteRequestIndex + 1, quoteRequestCount));
|
|
165
181
|
state.tokenSecurityTypeDestination =
|
|
166
182
|
context.token_security_type_destination ?? null;
|
|
167
183
|
});
|
|
168
|
-
|
|
184
|
+
// BatchSell and Unified swaps both use the same polling logic so both validations should pass
|
|
185
|
+
if (isValidQuoteRequest(paramsToUpdate) &&
|
|
186
|
+
isValidBatchSellQuoteRequest(this.state.quoteRequest)) {
|
|
169
187
|
__classPrivateFieldSet(this, _BridgeController_quotesFirstFetched, Date.now(), "f");
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (isSrcChainNonEVM) {
|
|
177
|
-
// If the source chain is not an EVM network, use value from params
|
|
178
|
-
insufficientBal = paramsToUpdate.insufficientBal;
|
|
179
|
-
}
|
|
180
|
-
else if (providerConfig?.rpcUrl?.includes('tenderly')) {
|
|
181
|
-
// If the rpcUrl is a tenderly fork (e2e tests), set insufficientBal=true
|
|
182
|
-
// The bridge-api filters out quotes if the balance on mainnet is insufficient so this override allows quotes to always be returned
|
|
183
|
-
insufficientBal = true;
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
// Set loading status if RPC calls are made before the quotes are fetched
|
|
187
|
-
this.update((state) => {
|
|
188
|
-
state.quotesLoadingStatus = RequestStatus.LOADING;
|
|
189
|
-
});
|
|
190
|
-
resetApproval = await __classPrivateFieldGet(this, _BridgeController_shouldResetApproval, "f").call(this, updatedQuoteRequest);
|
|
191
|
-
// Otherwise query the src token balance from the RPC provider
|
|
192
|
-
insufficientBal =
|
|
193
|
-
paramsToUpdate.insufficientBal ??
|
|
194
|
-
(await __classPrivateFieldGet(this, _BridgeController_hasInsufficientBalance, "f").call(this, updatedQuoteRequest));
|
|
195
|
-
}
|
|
188
|
+
// Update the insufficientBal and resetApproval params for the quote request
|
|
189
|
+
const quoteWithInsufficientBalAndResetApproval = await __classPrivateFieldGet(this, _BridgeController_appendInsufficientBalAndResetApproval, "f").call(this, paramsToUpdate);
|
|
190
|
+
this.update((state) => {
|
|
191
|
+
state.quoteRequest[quoteRequestIndex] =
|
|
192
|
+
quoteWithInsufficientBalAndResetApproval;
|
|
193
|
+
});
|
|
196
194
|
// Set refresh rate based on the source chain before starting polling
|
|
197
195
|
this.setChainIntervalLength();
|
|
198
196
|
this.startPolling({
|
|
199
|
-
|
|
200
|
-
...updatedQuoteRequest,
|
|
201
|
-
insufficientBal,
|
|
202
|
-
resetApproval,
|
|
203
|
-
},
|
|
197
|
+
quoteRequests: this.state.quoteRequest,
|
|
204
198
|
context,
|
|
205
199
|
});
|
|
206
200
|
}
|
|
@@ -258,25 +252,21 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
258
252
|
* Fetches the exchange rates for the assets in the quote request if they are not already in the state
|
|
259
253
|
* In addition to the selected tokens, this also fetches the native asset for the source and destination chains
|
|
260
254
|
*
|
|
261
|
-
* @param
|
|
262
|
-
* @param quoteRequest.srcChainId - The source chain ID
|
|
263
|
-
* @param quoteRequest.srcTokenAddress - The source token address
|
|
264
|
-
* @param quoteRequest.destChainId - The destination chain ID
|
|
265
|
-
* @param quoteRequest.destTokenAddress - The destination token address
|
|
255
|
+
* @param quoteRequests - The quote requests to fetch the exchange rates for
|
|
266
256
|
*/
|
|
267
|
-
_BridgeController_fetchAssetExchangeRates.set(this, async (
|
|
268
|
-
const assetIds = new Set([]);
|
|
257
|
+
_BridgeController_fetchAssetExchangeRates.set(this, async (quoteRequests) => {
|
|
269
258
|
const exchangeRateSources = __classPrivateFieldGet(this, _BridgeController_getExchangeRateSources, "f").call(this);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
259
|
+
// Get unique assetIds for all quote requests
|
|
260
|
+
const assetIds = new Set(quoteRequests
|
|
261
|
+
.flatMap((quoteRequest) => [
|
|
262
|
+
quoteRequest.srcTokenAddress && quoteRequest.srcChainId
|
|
263
|
+
? getAssetIdsForToken(quoteRequest.srcTokenAddress, quoteRequest.srcChainId)
|
|
264
|
+
: undefined,
|
|
265
|
+
quoteRequest.destTokenAddress && quoteRequest.destChainId
|
|
266
|
+
? getAssetIdsForToken(quoteRequest.destTokenAddress, quoteRequest.destChainId)
|
|
267
|
+
: undefined,
|
|
268
|
+
].flat())
|
|
269
|
+
.filter((assetId) => !selectIsAssetExchangeRateInState(exchangeRateSources, assetId)));
|
|
280
270
|
const currency = __classPrivateFieldGet(this, _BridgeController_getUseAssetsControllerForRates, "f").call(this)
|
|
281
271
|
? this.messenger.call('AssetsController:getExchangeRatesForBridge')
|
|
282
272
|
.currentCurrency
|
|
@@ -317,6 +307,39 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
317
307
|
return true;
|
|
318
308
|
}
|
|
319
309
|
});
|
|
310
|
+
_BridgeController_appendInsufficientBalAndResetApproval.set(this, async (quoteRequest) => {
|
|
311
|
+
const isSrcChainNonEVM = isNonEvmChainId(quoteRequest.srcChainId);
|
|
312
|
+
const providerConfig = isSrcChainNonEVM
|
|
313
|
+
? undefined
|
|
314
|
+
: __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getNetworkClientByChainId).call(this, formatChainIdToHex(quoteRequest.srcChainId))?.configuration;
|
|
315
|
+
let insufficientBal;
|
|
316
|
+
let resetApproval = Boolean(quoteRequest.resetApproval);
|
|
317
|
+
if (isSrcChainNonEVM) {
|
|
318
|
+
// If the source chain is not an EVM network, use value from params
|
|
319
|
+
insufficientBal = quoteRequest.insufficientBal;
|
|
320
|
+
}
|
|
321
|
+
else if (providerConfig?.rpcUrl?.includes('tenderly')) {
|
|
322
|
+
// If the rpcUrl is a tenderly fork (e2e tests), set insufficientBal=true
|
|
323
|
+
// The bridge-api filters out quotes if the balance on mainnet is insufficient so this override allows quotes to always be returned
|
|
324
|
+
insufficientBal = true;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
// Set loading status if RPC calls are made before the quotes are fetched
|
|
328
|
+
this.update((state) => {
|
|
329
|
+
state.quotesLoadingStatus = RequestStatus.LOADING;
|
|
330
|
+
});
|
|
331
|
+
resetApproval = await __classPrivateFieldGet(this, _BridgeController_shouldResetApproval, "f").call(this, quoteRequest);
|
|
332
|
+
// Otherwise query the src token balance from the RPC provider
|
|
333
|
+
insufficientBal =
|
|
334
|
+
quoteRequest.insufficientBal ??
|
|
335
|
+
(await __classPrivateFieldGet(this, _BridgeController_hasInsufficientBalance, "f").call(this, quoteRequest));
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
...quoteRequest,
|
|
339
|
+
insufficientBal,
|
|
340
|
+
resetApproval,
|
|
341
|
+
};
|
|
342
|
+
});
|
|
320
343
|
_BridgeController_shouldResetApproval.set(this, async (quoteRequest) => {
|
|
321
344
|
if (isNonEvmChainId(quoteRequest.srcChainId)) {
|
|
322
345
|
return false;
|
|
@@ -354,11 +377,21 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
354
377
|
this.setLocation = (location) => {
|
|
355
378
|
__classPrivateFieldSet(this, _BridgeController_location, location, "f");
|
|
356
379
|
};
|
|
357
|
-
this.resetState = (reason = AbortReason.ResetState) => {
|
|
380
|
+
this.resetState = (reason = AbortReason.ResetState, quoteRequestIndex = null) => {
|
|
358
381
|
this.stopPollingForQuotes(reason);
|
|
359
382
|
this.update((state) => {
|
|
360
383
|
// Cannot do direct assignment to state, i.e. state = {... }, need to manually assign each field
|
|
361
|
-
|
|
384
|
+
if (quoteRequestIndex === null) {
|
|
385
|
+
// Clear all requests if index is null
|
|
386
|
+
state.quoteRequest = DEFAULT_BRIDGE_CONTROLLER_STATE.quoteRequest;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// Otherwise only clear the specified request
|
|
390
|
+
state.quoteRequest = state.quoteRequest
|
|
391
|
+
.slice(0, quoteRequestIndex)
|
|
392
|
+
.concat(DEFAULT_BRIDGE_CONTROLLER_STATE.quoteRequest[0])
|
|
393
|
+
.concat(state.quoteRequest.slice(quoteRequestIndex + 1));
|
|
394
|
+
}
|
|
362
395
|
state.quotesInitialLoadTime =
|
|
363
396
|
DEFAULT_BRIDGE_CONTROLLER_STATE.quotesInitialLoadTime;
|
|
364
397
|
state.quotes = DEFAULT_BRIDGE_CONTROLLER_STATE.quotes;
|
|
@@ -385,7 +418,9 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
385
418
|
*/
|
|
386
419
|
this.setChainIntervalLength = () => {
|
|
387
420
|
const { state } = this;
|
|
388
|
-
|
|
421
|
+
// Assume that BatchSell quote requests all have the same source chain
|
|
422
|
+
// Use the first one to determine refresh rate
|
|
423
|
+
const { srcChainId } = state.quoteRequest[0];
|
|
389
424
|
const bridgeFeatureFlags = getBridgeFeatureFlags(this.messenger);
|
|
390
425
|
const refreshRateOverride = srcChainId
|
|
391
426
|
? bridgeFeatureFlags.chains[formatChainIdToCaip(srcChainId)]?.refreshRate
|
|
@@ -393,16 +428,16 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
393
428
|
const defaultRefreshRate = bridgeFeatureFlags.refreshRate;
|
|
394
429
|
this.setIntervalLength(refreshRateOverride ?? defaultRefreshRate);
|
|
395
430
|
};
|
|
396
|
-
_BridgeController_fetchBridgeQuotes.set(this, async ({
|
|
431
|
+
_BridgeController_fetchBridgeQuotes.set(this, async ({ quoteRequests, context, }) => {
|
|
397
432
|
__classPrivateFieldGet(this, _BridgeController_abortController, "f")?.abort(AbortReason.NewQuoteRequest);
|
|
398
433
|
__classPrivateFieldSet(this, _BridgeController_abortController, new AbortController(), "f");
|
|
399
|
-
__classPrivateFieldGet(this, _BridgeController_fetchAssetExchangeRates, "f").call(this,
|
|
434
|
+
__classPrivateFieldGet(this, _BridgeController_fetchAssetExchangeRates, "f").call(this, quoteRequests).catch((error) => console.warn('Failed to fetch asset exchange rates', error));
|
|
400
435
|
this.trackUnifiedSwapBridgeEvent(UnifiedSwapBridgeEventName.QuotesRequested, context);
|
|
401
436
|
const { sse, maxRefreshCount } = getBridgeFeatureFlags(this.messenger);
|
|
402
437
|
const shouldStream = sse?.enabled &&
|
|
403
438
|
hasMinimumRequiredVersion(__classPrivateFieldGet(this, _BridgeController_clientVersion, "f"), sse.minimumVersion);
|
|
439
|
+
const isBatchSellRequest = quoteRequests.length > 1;
|
|
404
440
|
this.update((state) => {
|
|
405
|
-
state.quoteRequest = updatedQuoteRequest;
|
|
406
441
|
state.quoteFetchError = DEFAULT_BRIDGE_CONTROLLER_STATE.quoteFetchError;
|
|
407
442
|
state.tokenWarnings = DEFAULT_BRIDGE_CONTROLLER_STATE.tokenWarnings;
|
|
408
443
|
state.quoteStreamComplete =
|
|
@@ -412,26 +447,30 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
412
447
|
});
|
|
413
448
|
const jwt = await __classPrivateFieldGet(this, _BridgeController_getJwt, "f").call(this);
|
|
414
449
|
try {
|
|
450
|
+
const [firstQuoteRequest] = quoteRequests;
|
|
451
|
+
const unifiedSwapTraceName = isCrossChain(firstQuoteRequest.srcChainId, firstQuoteRequest.destChainId)
|
|
452
|
+
? TraceName.BridgeQuotesFetched
|
|
453
|
+
: TraceName.SwapQuotesFetched;
|
|
415
454
|
await __classPrivateFieldGet(this, _BridgeController_trace, "f").call(this, {
|
|
416
|
-
name:
|
|
417
|
-
? TraceName.
|
|
418
|
-
:
|
|
455
|
+
name: isBatchSellRequest
|
|
456
|
+
? TraceName.BatchSellQuotesFetched
|
|
457
|
+
: unifiedSwapTraceName,
|
|
419
458
|
data: {
|
|
420
|
-
srcChainId: formatChainIdToCaip(
|
|
421
|
-
destChainId: formatChainIdToCaip(
|
|
459
|
+
srcChainId: formatChainIdToCaip(firstQuoteRequest.srcChainId),
|
|
460
|
+
destChainId: formatChainIdToCaip(firstQuoteRequest.destChainId),
|
|
422
461
|
},
|
|
423
462
|
}, async () => {
|
|
424
|
-
const selectedAccount = __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getMultichainSelectedAccount).call(this,
|
|
463
|
+
const selectedAccount = __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getMultichainSelectedAccount).call(this, firstQuoteRequest.walletAddress);
|
|
425
464
|
// This call is not awaited to prevent blocking quote fetching if the snap takes too long to respond
|
|
426
465
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
427
|
-
__classPrivateFieldGet(this, _BridgeController_setMinimumBalanceForRentExemptionInLamports, "f").call(this,
|
|
466
|
+
__classPrivateFieldGet(this, _BridgeController_setMinimumBalanceForRentExemptionInLamports, "f").call(this, firstQuoteRequest.srcChainId, selectedAccount?.metadata?.snap?.id);
|
|
428
467
|
// Use SSE if enabled and return early
|
|
429
|
-
if (shouldStream) {
|
|
430
|
-
await __classPrivateFieldGet(this, _BridgeController_handleQuoteStreaming, "f").call(this,
|
|
468
|
+
if (shouldStream || isBatchSellRequest) {
|
|
469
|
+
await __classPrivateFieldGet(this, _BridgeController_handleQuoteStreaming, "f").call(this, quoteRequests, jwt, selectedAccount);
|
|
431
470
|
return;
|
|
432
471
|
}
|
|
433
472
|
// Otherwise use regular fetch
|
|
434
|
-
const quotes = await this.fetchQuotes(
|
|
473
|
+
const quotes = await this.fetchQuotes(firstQuoteRequest, __classPrivateFieldGet(this, _BridgeController_abortController, "f")?.signal);
|
|
435
474
|
this.update((state) => {
|
|
436
475
|
// Set the initial load time if this is the first fetch
|
|
437
476
|
if (state.quotesRefreshCount ===
|
|
@@ -487,14 +526,17 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
487
526
|
this.update((state) => {
|
|
488
527
|
state.quotesRefreshCount += 1;
|
|
489
528
|
});
|
|
490
|
-
|
|
491
|
-
if (
|
|
492
|
-
|
|
493
|
-
|
|
529
|
+
const hasNoFundedQuoteRequests = quoteRequests.every(({ insufficientBal }) => Boolean(insufficientBal));
|
|
530
|
+
if (hasNoFundedQuoteRequests
|
|
531
|
+
? // If all quote requests are insufficiently funded, stop polling
|
|
532
|
+
// So if a BatchSell has at least 1 sufficiently funded quote request, polling continues
|
|
533
|
+
true
|
|
534
|
+
: // Otherwise continue polling until the maximum number of refreshes has been reached
|
|
535
|
+
this.state.quotesRefreshCount >= maxRefreshCount) {
|
|
494
536
|
this.stopAllPolling();
|
|
495
537
|
}
|
|
496
538
|
});
|
|
497
|
-
_BridgeController_handleQuoteStreaming.set(this, async (
|
|
539
|
+
_BridgeController_handleQuoteStreaming.set(this, async (quoteRequests, jwt, selectedAccount) => {
|
|
498
540
|
/**
|
|
499
541
|
* Tracks the number of valid quotes received from the current stream, which is used
|
|
500
542
|
* to determine when to clear the quotes list and set the initial load time
|
|
@@ -505,7 +547,7 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
505
547
|
* before setting quotesLoadingStatus to FETCHED
|
|
506
548
|
*/
|
|
507
549
|
const pendingFeeAppendPromises = new Set();
|
|
508
|
-
await fetchBridgeQuoteStream(__classPrivateFieldGet(this, _BridgeController_fetchFn, "f"),
|
|
550
|
+
await fetchBridgeQuoteStream(__classPrivateFieldGet(this, _BridgeController_fetchFn, "f"), quoteRequests, __classPrivateFieldGet(this, _BridgeController_abortController, "f")?.signal, __classPrivateFieldGet(this, _BridgeController_clientId, "f"), jwt, __classPrivateFieldGet(this, _BridgeController_config, "f").customBridgeApiBaseUrl ?? BRIDGE_PROD_API_BASE_URL, {
|
|
509
551
|
onQuoteValidationFailure: __classPrivateFieldGet(this, _BridgeController_trackQuoteValidationFailures, "f"),
|
|
510
552
|
onValidQuoteReceived: async (quote) => {
|
|
511
553
|
const feeAppendPromise = (async () => {
|
|
@@ -592,15 +634,16 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
592
634
|
return undefined;
|
|
593
635
|
}
|
|
594
636
|
});
|
|
595
|
-
_BridgeController_getRequestMetadata.set(this, () => {
|
|
596
|
-
const
|
|
637
|
+
_BridgeController_getRequestMetadata.set(this, (quoteRequestIndex = 0) => {
|
|
638
|
+
const quoteRequest = this.state.quoteRequest[quoteRequestIndex];
|
|
639
|
+
const { walletAddress } = quoteRequest;
|
|
597
640
|
const accountHardwareType = getAccountHardwareType(walletAddress
|
|
598
641
|
? __classPrivateFieldGet(this, _BridgeController_instances, "m", _BridgeController_getMultichainSelectedAccount).call(this, walletAddress)
|
|
599
642
|
: undefined);
|
|
600
643
|
return {
|
|
601
|
-
slippage_limit:
|
|
602
|
-
swap_type: getSwapTypeFromQuote(
|
|
603
|
-
custom_slippage: isCustomSlippage(
|
|
644
|
+
slippage_limit: quoteRequest.slippage,
|
|
645
|
+
swap_type: getSwapTypeFromQuote(quoteRequest),
|
|
646
|
+
custom_slippage: isCustomSlippage(quoteRequest.slippage),
|
|
604
647
|
account_hardware_type: accountHardwareType,
|
|
605
648
|
is_hardware_wallet: accountHardwareType !== null,
|
|
606
649
|
};
|
|
@@ -613,34 +656,35 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
613
656
|
has_gas_included_quote: this.state.quotes.some(({ quote }) => quote.gasIncluded),
|
|
614
657
|
};
|
|
615
658
|
});
|
|
616
|
-
_BridgeController_getEventProperties.set(this, (eventName, propertiesFromClient) => {
|
|
659
|
+
_BridgeController_getEventProperties.set(this, (eventName, propertiesFromClient, quoteRequestIndex = 0) => {
|
|
617
660
|
const clientProps = propertiesFromClient;
|
|
618
661
|
const baseProperties = {
|
|
619
662
|
...propertiesFromClient,
|
|
620
663
|
location: clientProps?.location ?? __classPrivateFieldGet(this, _BridgeController_location, "f"),
|
|
621
664
|
action_type: MetricsActionType.SWAPBRIDGE_V1,
|
|
622
665
|
};
|
|
666
|
+
const quoteRequest = this.state.quoteRequest[quoteRequestIndex];
|
|
623
667
|
switch (eventName) {
|
|
624
668
|
case UnifiedSwapBridgeEventName.ButtonClicked:
|
|
625
669
|
return {
|
|
626
|
-
...getRequestParams(
|
|
670
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
627
671
|
...baseProperties,
|
|
628
672
|
};
|
|
629
673
|
case UnifiedSwapBridgeEventName.PageViewed:
|
|
630
674
|
return {
|
|
631
|
-
...getRequestParams(
|
|
675
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
632
676
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
633
677
|
...baseProperties,
|
|
634
678
|
};
|
|
635
679
|
case UnifiedSwapBridgeEventName.QuotesValidationFailed:
|
|
636
680
|
return {
|
|
637
|
-
...getRequestParams(
|
|
681
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
638
682
|
refresh_count: this.state.quotesRefreshCount,
|
|
639
683
|
...baseProperties,
|
|
640
684
|
};
|
|
641
685
|
case UnifiedSwapBridgeEventName.QuotesReceived:
|
|
642
686
|
return {
|
|
643
|
-
...getRequestParams(
|
|
687
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
644
688
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
645
689
|
...__classPrivateFieldGet(this, _BridgeController_getQuoteFetchData, "f").call(this),
|
|
646
690
|
refresh_count: this.state.quotesRefreshCount,
|
|
@@ -648,24 +692,24 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
648
692
|
};
|
|
649
693
|
case UnifiedSwapBridgeEventName.QuotesRequested:
|
|
650
694
|
return {
|
|
651
|
-
...getRequestParams(
|
|
695
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
652
696
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
653
|
-
has_sufficient_funds: !
|
|
697
|
+
has_sufficient_funds: !quoteRequest.insufficientBal,
|
|
654
698
|
...baseProperties,
|
|
655
699
|
};
|
|
656
700
|
case UnifiedSwapBridgeEventName.QuotesError:
|
|
657
701
|
return {
|
|
658
|
-
...getRequestParams(
|
|
702
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
659
703
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
660
704
|
error_message: this.state.quoteFetchError,
|
|
661
|
-
has_sufficient_funds: !
|
|
705
|
+
has_sufficient_funds: !quoteRequest.insufficientBal,
|
|
662
706
|
...baseProperties,
|
|
663
707
|
};
|
|
664
708
|
case UnifiedSwapBridgeEventName.AllQuotesOpened:
|
|
665
709
|
case UnifiedSwapBridgeEventName.AllQuotesSorted:
|
|
666
710
|
case UnifiedSwapBridgeEventName.QuoteSelected:
|
|
667
711
|
return {
|
|
668
|
-
...getRequestParams(
|
|
712
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
669
713
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
670
714
|
...__classPrivateFieldGet(this, _BridgeController_getQuoteFetchData, "f").call(this),
|
|
671
715
|
...baseProperties,
|
|
@@ -674,7 +718,7 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
674
718
|
// Populate the properties that the error occurred before the tx was submitted
|
|
675
719
|
return {
|
|
676
720
|
...baseProperties,
|
|
677
|
-
...getRequestParams(
|
|
721
|
+
...getRequestParams(quoteRequest, this.state.tokenSecurityTypeDestination),
|
|
678
722
|
...__classPrivateFieldGet(this, _BridgeController_getRequestMetadata, "f").call(this),
|
|
679
723
|
...__classPrivateFieldGet(this, _BridgeController_getQuoteFetchData, "f").call(this),
|
|
680
724
|
...propertiesFromClient,
|
|
@@ -701,13 +745,15 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
701
745
|
return baseProperties;
|
|
702
746
|
}
|
|
703
747
|
});
|
|
704
|
-
_BridgeController_trackInputChangedEvents.set(this, (paramsToUpdate) => {
|
|
748
|
+
_BridgeController_trackInputChangedEvents.set(this, (paramsToUpdate, quoteRequestIndex = 0) => {
|
|
705
749
|
Object.entries(paramsToUpdate).forEach(([key, value]) => {
|
|
706
750
|
const inputKey = toInputChangedPropertyKey[key];
|
|
707
751
|
const inputValue = toInputChangedPropertyValue[key]?.(paramsToUpdate);
|
|
708
752
|
if (inputKey &&
|
|
709
753
|
inputValue !== undefined &&
|
|
710
|
-
|
|
754
|
+
this.state.quoteRequest[quoteRequestIndex] &&
|
|
755
|
+
value !==
|
|
756
|
+
this.state.quoteRequest[quoteRequestIndex][key]) {
|
|
711
757
|
this.trackUnifiedSwapBridgeEvent(UnifiedSwapBridgeEventName.InputChanged, {
|
|
712
758
|
input: inputKey,
|
|
713
759
|
input_value: inputValue,
|
|
@@ -721,14 +767,15 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
721
767
|
*
|
|
722
768
|
* @param eventName - The name of the event to track
|
|
723
769
|
* @param propertiesFromClient - Properties that can't be calculated from the event name and need to be provided by the client
|
|
770
|
+
* @param quoteRequestIndex - The index of the quote request to track the event for
|
|
724
771
|
* @example
|
|
725
772
|
* this.trackUnifiedSwapBridgeEvent(UnifiedSwapBridgeEventName.ActionOpened, {
|
|
726
773
|
* location: MetaMetricsSwapsEventSource.MainView,
|
|
727
774
|
* });
|
|
728
775
|
*/
|
|
729
|
-
this.trackUnifiedSwapBridgeEvent = (eventName, propertiesFromClient) => {
|
|
776
|
+
this.trackUnifiedSwapBridgeEvent = (eventName, propertiesFromClient, quoteRequestIndex = 0) => {
|
|
730
777
|
try {
|
|
731
|
-
const combinedPropertiesForEvent = __classPrivateFieldGet(this, _BridgeController_getEventProperties, "f").call(this, eventName, propertiesFromClient);
|
|
778
|
+
const combinedPropertiesForEvent = __classPrivateFieldGet(this, _BridgeController_getEventProperties, "f").call(this, eventName, propertiesFromClient, quoteRequestIndex);
|
|
732
779
|
__classPrivateFieldGet(this, _BridgeController_trackMetaMetricsFn, "f").call(this, eventName, combinedPropertiesForEvent);
|
|
733
780
|
}
|
|
734
781
|
catch (error) {
|
|
@@ -769,8 +816,9 @@ export class BridgeController extends StaticIntervalPollingController() {
|
|
|
769
816
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
770
817
|
}
|
|
771
818
|
}
|
|
772
|
-
_BridgeController_abortController = new WeakMap(), _BridgeController_quotesFirstFetched = new WeakMap(), _BridgeController_location = new WeakMap(), _BridgeController_clientId = new WeakMap(), _BridgeController_clientVersion = new WeakMap(), _BridgeController_getLayer1GasFee = new WeakMap(), _BridgeController_fetchFn = new WeakMap(), _BridgeController_trackMetaMetricsFn = new WeakMap(), _BridgeController_trace = new WeakMap(), _BridgeController_config = new WeakMap(), _BridgeController_getUseAssetsControllerForRates = new WeakMap(), _BridgeController_trackQuoteValidationFailures = new WeakMap(), _BridgeController_getExchangeRateSources = new WeakMap(), _BridgeController_fetchAssetExchangeRates = new WeakMap(), _BridgeController_hasInsufficientBalance = new WeakMap(), _BridgeController_shouldResetApproval = new WeakMap(), _BridgeController_fetchBridgeQuotes = new WeakMap(), _BridgeController_handleQuoteStreaming = new WeakMap(), _BridgeController_setMinimumBalanceForRentExemptionInLamports = new WeakMap(), _BridgeController_getJwt = new WeakMap(), _BridgeController_getRequestMetadata = new WeakMap(), _BridgeController_getQuoteFetchData = new WeakMap(), _BridgeController_getEventProperties = new WeakMap(), _BridgeController_trackInputChangedEvents = new WeakMap(), _BridgeController_getUSDTMainnetAllowance = new WeakMap(), _BridgeController_instances = new WeakSet(), _BridgeController_getMultichainSelectedAccount = function _BridgeController_getMultichainSelectedAccount(walletAddress) {
|
|
773
|
-
|
|
819
|
+
_BridgeController_abortController = new WeakMap(), _BridgeController_quotesFirstFetched = new WeakMap(), _BridgeController_location = new WeakMap(), _BridgeController_clientId = new WeakMap(), _BridgeController_clientVersion = new WeakMap(), _BridgeController_getLayer1GasFee = new WeakMap(), _BridgeController_fetchFn = new WeakMap(), _BridgeController_trackMetaMetricsFn = new WeakMap(), _BridgeController_trace = new WeakMap(), _BridgeController_config = new WeakMap(), _BridgeController_getUseAssetsControllerForRates = new WeakMap(), _BridgeController_trackQuoteValidationFailures = new WeakMap(), _BridgeController_getExchangeRateSources = new WeakMap(), _BridgeController_fetchAssetExchangeRates = new WeakMap(), _BridgeController_hasInsufficientBalance = new WeakMap(), _BridgeController_appendInsufficientBalAndResetApproval = new WeakMap(), _BridgeController_shouldResetApproval = new WeakMap(), _BridgeController_fetchBridgeQuotes = new WeakMap(), _BridgeController_handleQuoteStreaming = new WeakMap(), _BridgeController_setMinimumBalanceForRentExemptionInLamports = new WeakMap(), _BridgeController_getJwt = new WeakMap(), _BridgeController_getRequestMetadata = new WeakMap(), _BridgeController_getQuoteFetchData = new WeakMap(), _BridgeController_getEventProperties = new WeakMap(), _BridgeController_trackInputChangedEvents = new WeakMap(), _BridgeController_getUSDTMainnetAllowance = new WeakMap(), _BridgeController_instances = new WeakSet(), _BridgeController_getMultichainSelectedAccount = function _BridgeController_getMultichainSelectedAccount(walletAddress) {
|
|
820
|
+
// Assume that all quotes in a batch are for the same account
|
|
821
|
+
const addressToUse = walletAddress ?? this.state.quoteRequest[0].walletAddress;
|
|
774
822
|
if (!addressToUse) {
|
|
775
823
|
throw new Error('Account address is required');
|
|
776
824
|
}
|