@metamask-previews/bridge-status-controller 76.3.2-preview-03a246be1 → 76.3.2-preview-ff2ab0583
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 +4 -0
- package/dist/quote-status-manager/quote-status-api-service.js.map +1 -1
- package/dist/quote-status-manager/quotes-status-manager.d.ts.map +1 -1
- package/dist/quote-status-manager/quotes-status-manager.js +9 -10
- package/dist/quote-status-manager/quotes-status-manager.js.map +1 -1
- package/dist/strategy/evm-strategy.js +1 -1
- package/dist/strategy/evm-strategy.js.map +1 -1
- package/dist/strategy/non-evm-strategy.js +2 -2
- package/dist/strategy/non-evm-strategy.js.map +1 -1
- package/dist/utils/bridge-status.js.map +1 -1
- package/dist/utils/transaction.js +1 -1
- package/dist/utils/transaction.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Bump `@metamask/transaction-controller` from `^72.0.0` to `^72.0.1` ([#10462](https://github.com/MetaMask/core/pull/10462))
|
|
13
|
+
|
|
10
14
|
## [76.3.2]
|
|
11
15
|
|
|
12
16
|
### Changed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quote-status-api-service.js","sourceRoot":"","sources":["../../src/quote-status-manager/quote-status-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClientHeaders } from '@metamask/bridge-controller';\nimport { StructError } from '@metamask/superstruct';\n\nimport { BridgeClientId, BridgeStatusControllerMessenger } from '../types.js';\nimport { getJwt } from '../utils/authentication.js';\nimport {\n QuoteStatusBackendStatus,\n QuoteStatusUpdateRetryableBackendTypes,\n QuoteStatusFetchWithRetryOutcomeType,\n} from './constants.js';\nimport { QuoteStatusGetError, QuoteStatusUpdateError } from './errors.js';\nimport { QuoteStatusGetWithRetryOutcome } from './quote-status-get-with-retry-outcome.js';\nimport { QuoteStatusUpdateWithRetryOutcome } from './quote-status-update-with-retry-outcome.js';\nimport {\n QuoteStatusApiServiceOptions,\n QuoteStatusGetResponse,\n QuoteStatusUpdateResponse,\n} from './types.js';\nimport { sleep } from './utils.js';\nimport {\n validateQuoteStatusGetResponse,\n validateQuoteStatusUpdateResponse,\n} from './validators.js';\n\n/**\n * Service responsible for calling bridge quote status update APIs.\n *\n * It performs authentication, sends properly-scoped client headers, and validates\n * error responses so callers can handle known update-status failures.\n */\nexport class QuoteStatusApiService {\n readonly #messenger: BridgeStatusControllerMessenger;\n\n readonly #clientId: BridgeClientId;\n\n readonly #clientProduct: string;\n\n readonly #clientVersion: string | undefined;\n\n readonly #apiBaseUrl: string;\n\n readonly #onError: ((error: QuoteStatusUpdateError) => void) | undefined;\n\n /**\n * Creates an API service for quote status update requests.\n *\n * @param options - Service dependencies and request configuration.\n * @param options.messenger - Messenger used to retrieve the authentication token.\n * @param options.clientId - Bridge client identifier used for request headers.\n * @param options.clientProduct - Product name sent in client product headers.\n * @param options.clientVersion - Optional client version sent in headers.\n * @param options.apiBaseUrl - Base URL for the quote status API.\n * @param options.onError - Optional callback for unexpected response-shape errors.\n */\n constructor({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n }: QuoteStatusApiServiceOptions) {\n this.#messenger = messenger;\n this.#clientId = clientId;\n this.#clientProduct = clientProduct;\n this.#clientVersion = clientVersion;\n this.#apiBaseUrl = apiBaseUrl;\n this.#onError = onError;\n }\n\n /**\n * Updates a quote status in the bridge quote-status API.\n *\n * The endpoint returns no payload on success (`2xx`) and a structured payload\n * on non-`2xx` responses. This method returns `null` for successful updates and\n * the validated error payload for unsuccessful updates.\n *\n * @param data - Request payload identifying quote and target status transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param signal - Optional abort signal for canceling the request.\n * @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.\n * @throws If the non-`2xx` response body does not match the expected schema.\n */\n async updateQuoteStatus(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateResponse | null> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/quote/updateStatus`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n body: JSON.stringify(data),\n signal,\n },\n );\n\n if (res.ok) {\n return null;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusUpdateResponse(responseData);\n return responseData;\n } catch (error) {\n this.#onError?.(\n new QuoteStatusUpdateError(\n 'unexpected response shape from quote/updateStatus',\n { quoteId: data.quoteId, srcTxHash: data.srcTxHash },\n ),\n );\n throw error;\n }\n }\n\n async getQuoteStatus(\n data: {\n quoteId: string;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetResponse> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/getQuoteStatus?quoteId=${data.quoteId}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n signal,\n },\n );\n\n if (!res.ok) {\n // 5xx errors are transient (server-side); 4xx errors are client-side and\n // non-retryable. The `retryable` flag lets `getQuoteStatusWithRetry`\n // distinguish the two and only exit early for permanent failures.\n const retryable = res.status >= 500;\n const error = new QuoteStatusGetError(\n `request error to getQuoteStatus [${res.status}: ${res.statusText}]`,\n { quoteId: data.quoteId },\n retryable,\n );\n this.#onError?.(error);\n throw error;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusGetResponse(responseData);\n return responseData;\n } catch (error) {\n if (error instanceof StructError) {\n const validationFailures = [];\n\n for (const { path } of error.failures()) {\n const aggregatorId =\n (responseData as QuoteStatusGetResponse)?.submittedTx?.bridge ??\n ('unknown' as string);\n const pathString = path?.join('.') || 'unknown';\n validationFailures.push([aggregatorId, pathString].join('|'));\n }\n\n const validationError = new QuoteStatusGetError(\n 'unexpected response shape from getQuoteStatus',\n { quoteId: data.quoteId, validationFailures },\n );\n\n this.#onError?.(validationError);\n\n throw validationError;\n }\n\n throw error;\n }\n }\n\n /**\n * Updates a quote status, retrying on transient backend failures.\n *\n * Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only\n * retried when the backend returns an error whose type is in\n * {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response\n * resolves immediately as non-retryable. Retries are spaced by\n * `options.delayMsBetweenRetries`, and both the abort signal and the optional\n * `options.retry` predicate are checked before each attempt so an\n * in-flight or pending retry can be cancelled (e.g. when the entry's status\n * changed while sleeping between retries).\n *\n * @param data - Request payload identifying the quote and target transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param options - Retry configuration.\n * @param options.maxRetries - Maximum number of retries after the initial attempt.\n * @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.\n * @param options.retry - Optional predicate checked before each attempt;\n * when it returns `false` the loop stops early and resolves as `Interrupted`.\n * @param signal - Optional abort signal for canceling the request and its retries.\n * @returns An outcome describing how the update resolved:\n * `Accepted` when the backend accepted the update, `NonRetryable` for a\n * non-retryable error response, `Interrupted` when aborted, or\n * `RetryableExhausted` when all retries were used up on retryable errors.\n * @throws If a request rejects for a reason other than the abort signal (e.g.\n * an unexpected response shape from {@link updateQuoteStatus}).\n */\n async updateQuoteStatusWithRetry(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n retry?: () => boolean;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted || options.retry?.() === false) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.updateQuoteStatus(data, signal);\n\n if (response === null) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n );\n }\n\n if (!QuoteStatusUpdateRetryableBackendTypes.includes(response.type)) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n response,\n );\n }\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n throw error;\n }\n }\n\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n\n async getQuoteStatusWithRetry(\n data: {\n quoteId: string;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.getQuoteStatus(data, signal);\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n response,\n );\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n // Only short-circuit for non-retryable errors (e.g. 4xx, validation\n // failures). Retryable errors (e.g. 5xx) fall through so the loop can\n // attempt the next retry instead of returning NonRetryable immediately.\n if (error instanceof QuoteStatusGetError && !error.retryable) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n undefined,\n error,\n );\n }\n }\n }\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"quote-status-api-service.js","sourceRoot":"","sources":["../../src/quote-status-manager/quote-status-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClientHeaders } from '@metamask/bridge-controller';\nimport { StructError } from '@metamask/superstruct';\n\nimport { BridgeClientId, BridgeStatusControllerMessenger } from '../types.js';\nimport { getJwt } from '../utils/authentication.js';\nimport {\n QuoteStatusBackendStatus,\n QuoteStatusUpdateRetryableBackendTypes,\n QuoteStatusFetchWithRetryOutcomeType,\n} from './constants.js';\nimport { QuoteStatusGetError, QuoteStatusUpdateError } from './errors.js';\nimport { QuoteStatusGetWithRetryOutcome } from './quote-status-get-with-retry-outcome.js';\nimport { QuoteStatusUpdateWithRetryOutcome } from './quote-status-update-with-retry-outcome.js';\nimport {\n QuoteStatusApiServiceOptions,\n QuoteStatusGetResponse,\n QuoteStatusUpdateResponse,\n} from './types.js';\nimport { sleep } from './utils.js';\nimport {\n validateQuoteStatusGetResponse,\n validateQuoteStatusUpdateResponse,\n} from './validators.js';\n\n/**\n * Service responsible for calling bridge quote status update APIs.\n *\n * It performs authentication, sends properly-scoped client headers, and validates\n * error responses so callers can handle known update-status failures.\n */\nexport class QuoteStatusApiService {\n readonly #messenger: BridgeStatusControllerMessenger;\n\n readonly #clientId: BridgeClientId;\n\n readonly #clientProduct: string;\n\n readonly #clientVersion: string | undefined;\n\n readonly #apiBaseUrl: string;\n\n readonly #onError: ((error: QuoteStatusUpdateError) => void) | undefined;\n\n /**\n * Creates an API service for quote status update requests.\n *\n * @param options - Service dependencies and request configuration.\n * @param options.messenger - Messenger used to retrieve the authentication token.\n * @param options.clientId - Bridge client identifier used for request headers.\n * @param options.clientProduct - Product name sent in client product headers.\n * @param options.clientVersion - Optional client version sent in headers.\n * @param options.apiBaseUrl - Base URL for the quote status API.\n * @param options.onError - Optional callback for unexpected response-shape errors.\n */\n constructor({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n }: QuoteStatusApiServiceOptions) {\n this.#messenger = messenger;\n this.#clientId = clientId;\n this.#clientProduct = clientProduct;\n this.#clientVersion = clientVersion;\n this.#apiBaseUrl = apiBaseUrl;\n this.#onError = onError;\n }\n\n /**\n * Updates a quote status in the bridge quote-status API.\n *\n * The endpoint returns no payload on success (`2xx`) and a structured payload\n * on non-`2xx` responses. This method returns `null` for successful updates and\n * the validated error payload for unsuccessful updates.\n *\n * @param data - Request payload identifying quote and target status transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param signal - Optional abort signal for canceling the request.\n * @returns `null` for `2xx` responses, or a validated error response for non-`2xx`.\n * @throws If the non-`2xx` response body does not match the expected schema.\n */\n async updateQuoteStatus(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateResponse | null> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/quote/updateStatus`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n body: JSON.stringify(data),\n signal,\n },\n );\n\n if (res.ok) {\n return null;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusUpdateResponse(responseData);\n return responseData;\n } catch (error) {\n this.#onError?.(\n new QuoteStatusUpdateError(\n 'unexpected response shape from quote/updateStatus',\n { quoteId: data.quoteId, srcTxHash: data.srcTxHash },\n ),\n );\n throw error;\n }\n }\n\n async getQuoteStatus(\n data: {\n quoteId: string;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetResponse> {\n const jwt = await getJwt(this.#messenger);\n\n // This method uses `globalThis.fetch` and reads the raw\n // `Response` (including JSON on non-2xx). Wrappers like `handleFetch` that\n // throw on non-2xx would prevent typed error handling in callers.\n const res = await globalThis.fetch(\n `${this.#apiBaseUrl}/getQuoteStatus?quoteId=${data.quoteId}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'x-metamask-clientproduct': this.#clientProduct,\n ...(this.#clientVersion\n ? { 'x-metamask-clientversion': this.#clientVersion }\n : {}),\n ...getClientHeaders({\n clientId: this.#clientId,\n jwt,\n }),\n },\n signal,\n },\n );\n\n if (!res.ok) {\n // 5xx errors are transient (server-side); 4xx errors are client-side and\n // non-retryable. The `retryable` flag lets `getQuoteStatusWithRetry`\n // distinguish the two and only exit early for permanent failures.\n const retryable = res.status >= 500;\n const error = new QuoteStatusGetError(\n `request error to getQuoteStatus [${res.status}: ${res.statusText}]`,\n { quoteId: data.quoteId },\n retryable,\n );\n this.#onError?.(error);\n throw error;\n }\n\n const responseData = await res.json();\n\n try {\n validateQuoteStatusGetResponse(responseData);\n return responseData;\n } catch (error) {\n if (error instanceof StructError) {\n const validationFailures = [];\n\n for (const { path } of error.failures()) {\n const aggregatorId =\n (responseData as QuoteStatusGetResponse)?.submittedTx?.bridge ??\n 'unknown';\n const pathString = path?.join('.') || 'unknown';\n validationFailures.push([aggregatorId, pathString].join('|'));\n }\n\n const validationError = new QuoteStatusGetError(\n 'unexpected response shape from getQuoteStatus',\n { quoteId: data.quoteId, validationFailures },\n );\n\n this.#onError?.(validationError);\n\n throw validationError;\n }\n\n throw error;\n }\n }\n\n /**\n * Updates a quote status, retrying on transient backend failures.\n *\n * Wraps {@link updateQuoteStatus} in a bounded retry loop. A request is only\n * retried when the backend returns an error whose type is in\n * {@link QuoteStatusUpdateRetryableBackendTypes}; any other error response\n * resolves immediately as non-retryable. Retries are spaced by\n * `options.delayMsBetweenRetries`, and both the abort signal and the optional\n * `options.retry` predicate are checked before each attempt so an\n * in-flight or pending retry can be cancelled (e.g. when the entry's status\n * changed while sleeping between retries).\n *\n * @param data - Request payload identifying the quote and target transition.\n * @param data.quoteId - Unique quote identifier to update.\n * @param data.srcTxHash - Source transaction hash associated with the quote.\n * @param data.newStatus - Target quote status to persist.\n * @param options - Retry configuration.\n * @param options.maxRetries - Maximum number of retries after the initial attempt.\n * @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.\n * @param options.retry - Optional predicate checked before each attempt;\n * when it returns `false` the loop stops early and resolves as `Interrupted`.\n * @param signal - Optional abort signal for canceling the request and its retries.\n * @returns An outcome describing how the update resolved:\n * `Accepted` when the backend accepted the update, `NonRetryable` for a\n * non-retryable error response, `Interrupted` when aborted, or\n * `RetryableExhausted` when all retries were used up on retryable errors.\n * @throws If a request rejects for a reason other than the abort signal (e.g.\n * an unexpected response shape from {@link updateQuoteStatus}).\n */\n async updateQuoteStatusWithRetry(\n data: {\n quoteId: string;\n srcTxHash: string;\n newStatus: QuoteStatusBackendStatus;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n retry?: () => boolean;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusUpdateWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted || options.retry?.() === false) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.updateQuoteStatus(data, signal);\n\n if (response === null) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n );\n }\n\n if (!QuoteStatusUpdateRetryableBackendTypes.includes(response.type)) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n response,\n );\n }\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n throw error;\n }\n }\n\n return new QuoteStatusUpdateWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n\n async getQuoteStatusWithRetry(\n data: {\n quoteId: string;\n },\n options: {\n maxRetries: number;\n delayMsBetweenRetries: number;\n },\n signal?: AbortSignal,\n ): Promise<QuoteStatusGetWithRetryOutcome> {\n for (let attempt = 0; attempt <= options.maxRetries; attempt += 1) {\n if (attempt > 0) {\n await sleep(options.delayMsBetweenRetries);\n }\n\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n try {\n const response = await this.getQuoteStatus(data, signal);\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Accepted,\n response,\n );\n } catch (error) {\n if (signal?.aborted) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.Interrupted,\n );\n }\n\n // Only short-circuit for non-retryable errors (e.g. 4xx, validation\n // failures). Retryable errors (e.g. 5xx) fall through so the loop can\n // attempt the next retry instead of returning NonRetryable immediately.\n if (error instanceof QuoteStatusGetError && !error.retryable) {\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.NonRetryable,\n undefined,\n error,\n );\n }\n }\n }\n\n return new QuoteStatusGetWithRetryOutcome(\n QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes-status-manager.d.ts","sourceRoot":"","sources":["../../src/quote-status-manager/quotes-status-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAa9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAG1F,OAAO,EAAE,uBAAuB,EAA2B,MAAM,YAAY,CAAC;AAE9E;;;;;;;;;GASG;AACH,qBAAa,kBAAkB;;IAqB7B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,EACP,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,QAAQ,EAAE,cAAc,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,CAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,KAC7C,IAAI,CAAC;QACV,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;QAClD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;KACtD,EAoBA;IAED;;;;;;;;OAQG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAiDN;IAED;;;;;;;;;;;;;OAaG;IACH,eAAe,CACb,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAC3B,IAAI,CA+BN;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAGd;IAED;;;;;;;;;;;;;;OAcG;IACH,IAAI,IAAI,IAAI,CA+CX;IAED;;;;;;;;;;;;OAYG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAIhC,GACA,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CAmBrD;
|
|
1
|
+
{"version":3,"file":"quotes-status-manager.d.ts","sourceRoot":"","sources":["../../src/quote-status-manager/quotes-status-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAa9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAG1F,OAAO,EAAE,uBAAuB,EAA2B,MAAM,YAAY,CAAC;AAE9E;;;;;;;;;GASG;AACH,qBAAa,kBAAkB;;IAqB7B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,YAAY,EACV,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,UAAU,EACV,OAAO,EACP,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,EAAE;QACD,SAAS,EAAE,+BAA+B,CAAC;QAC3C,QAAQ,EAAE,cAAc,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,CAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,KAC7C,IAAI,CAAC;QACV,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;QAClD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;KACtD,EAoBA;IAED;;;;;;;;OAQG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,IAAI,CAiDN;IAED;;;;;;;;;;;;;OAaG;IACH,eAAe,CACb,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAC3B,IAAI,CA+BN;IAED;;;OAGG;IACH,OAAO,IAAI,IAAI,CAGd;IAED;;;;;;;;;;;;;;OAcG;IACH,IAAI,IAAI,IAAI,CA+CX;IAED;;;;;;;;;;;;OAYG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAIhC,GACA,OAAO,CAAC,8BAA8B,GAAG,SAAS,CAAC,CAmBrD;CAiYF"}
|
|
@@ -389,8 +389,7 @@ export class QuoteStatusManager {
|
|
|
389
389
|
// finalization).
|
|
390
390
|
const retry = () => {
|
|
391
391
|
const live = this.#quoteStatusEntryStore.get(QuoteStatusEntryStore.hash(entry));
|
|
392
|
-
return Boolean(live &&
|
|
393
|
-
live.status.state === sentStatus &&
|
|
392
|
+
return Boolean(live?.status.state === sentStatus &&
|
|
394
393
|
live.acknowledgedState !== sentStatus);
|
|
395
394
|
};
|
|
396
395
|
this.#quoteStatusApiService
|
|
@@ -410,12 +409,12 @@ export class QuoteStatusManager {
|
|
|
410
409
|
// The entry can only be absent if the store was cleared (e.g. via
|
|
411
410
|
// `destroy`) while the request was in flight; nothing left to do.
|
|
412
411
|
if (!current) {
|
|
413
|
-
return
|
|
412
|
+
return;
|
|
414
413
|
}
|
|
415
414
|
if (current.status.state !== sentStatus) {
|
|
416
415
|
// The status advanced mid-flight; report the newer status.
|
|
417
416
|
this.#processEntry(current);
|
|
418
|
-
return
|
|
417
|
+
return;
|
|
419
418
|
}
|
|
420
419
|
if (sentStatus === QuoteStatusState.FinalizedSuccess ||
|
|
421
420
|
sentStatus === QuoteStatusState.FinalizedFailed) {
|
|
@@ -423,7 +422,7 @@ export class QuoteStatusManager {
|
|
|
423
422
|
// `Completed` state and keep the entry so any later duplicate
|
|
424
423
|
// `reportSubmitted` for this quote is rejected instead of looping.
|
|
425
424
|
this.#markCompleted(current);
|
|
426
|
-
return
|
|
425
|
+
return;
|
|
427
426
|
}
|
|
428
427
|
// A non-final status (e.g. `Submitted`) was accepted. The quote is
|
|
429
428
|
// not done yet: it still needs to be finalized via a later
|
|
@@ -433,20 +432,20 @@ export class QuoteStatusManager {
|
|
|
433
432
|
current.acknowledgedState = sentStatus;
|
|
434
433
|
this.#quoteStatusEntryStore.update(current);
|
|
435
434
|
this.#stopRetryTimerIfIdle();
|
|
436
|
-
return
|
|
435
|
+
return;
|
|
437
436
|
}
|
|
438
437
|
case QuoteStatusFetchWithRetryOutcomeType.NonRetryable:
|
|
439
438
|
this.#handleNonRetryableUpdateStatusError(entry, outcome);
|
|
440
|
-
return
|
|
439
|
+
return;
|
|
441
440
|
case QuoteStatusFetchWithRetryOutcomeType.Interrupted:
|
|
442
441
|
this.#processEntry(entry);
|
|
443
|
-
return
|
|
442
|
+
return;
|
|
444
443
|
case QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted:
|
|
445
444
|
entry.lastAttemptAt = Date.now();
|
|
446
445
|
this.#quoteStatusEntryStore.update(entry);
|
|
447
|
-
return
|
|
446
|
+
return;
|
|
448
447
|
default:
|
|
449
|
-
return
|
|
448
|
+
return;
|
|
450
449
|
}
|
|
451
450
|
})
|
|
452
451
|
.catch(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quotes-status-manager.js","sourceRoot":"","sources":["../../src/quote-status-manager/quotes-status-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionStatus } from '@metamask/transaction-controller';\n\nimport { BridgeClientId, BridgeStatusControllerMessenger } from '../types.js';\nimport {\n getTransactionMetaById,\n hasNestedSwapTransactions,\n isCrossChainTx,\n} from '../utils/transaction.js';\nimport {\n QuoteStatusState,\n QuoteStatusStateToBackendStatus,\n QuoteStatusUpdateBackendErrorType,\n QuoteStatusBackendStatus,\n QuoteStatusFetchWithRetryOutcomeType,\n} from './constants.js';\nimport { QuoteStatusUpdateError } from './errors.js';\nimport { QuoteStatusApiService } from './quote-status-api-service.js';\nimport { QuoteStatusEntryStore } from './quote-status-entry-store.js';\nimport { QuoteStatusGetWithRetryOutcome } from './quote-status-get-with-retry-outcome.js';\nimport { QuoteStatusStateFsm } from './quote-status-state-fsm.js';\nimport { QuoteStatusUpdateWithRetryOutcome } from './quote-status-update-with-retry-outcome.js';\nimport { QuoteStatusPersistEntry, QuoteStatusRuntimeEntry } from './types.js';\n\n/**\n * Tracks bridge/swap quotes through their lifecycle and keeps the backend in\n * sync with the latest known status of each quote.\n *\n * Quotes are reported via {@link reportSubmitted} and {@link reportFinalised},\n * stored as runtime entries, and pushed to the backend. Updates that fail in a\n * retryable way are retried on a periodic timer until each entry reaches a\n * terminal state, at which point it is evicted and the timer stops once the\n * store is empty.\n */\nexport class QuoteStatusManager {\n readonly #messenger: BridgeStatusControllerMessenger;\n\n readonly #quoteStatusApiService: QuoteStatusApiService;\n\n readonly #quoteStatusEntryStore: QuoteStatusEntryStore;\n\n readonly #isEnabled: (() => boolean) | undefined;\n\n readonly #onError: ((error: QuoteStatusUpdateError) => void) | undefined;\n\n readonly #updateIntervalMs: number;\n\n /**\n * Handle for the periodic retry timer. While running, every\n * {@link QUOTE_STATUS_UPDATE_RETRY_INTERVAL_MS} all entries that have not yet\n * reached a terminal state (Completed/Expired) are re-processed. It is started\n * lazily when there is work to do and stopped once the store is empty.\n */\n #retryIntervalId: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Creates a new manager and immediately processes any persisted entries.\n *\n * @param options - Constructor options.\n * @param options.messenger - Messenger used to communicate with the backend\n * API service.\n * @param options.clientId - Identifier of the client making the requests.\n * @param options.clientProduct - Name of the client product making the\n * requests.\n * @param options.clientVersion - Optional version of the client product.\n * @param options.apiBaseUrl - Base URL of the quote status backend API.\n * @param options.onPersistUpdates - Callback invoked to persist entry updates.\n * @param options.onError - Optional callback invoked when a non-recoverable\n * error occurs.\n * @param options.isEnabled - Optional predicate gating whether the manager\n * performs any work.\n * @param options.entryTtlMs - Time-to-live, in milliseconds, after which a\n * tracked entry is evicted.\n * @param options.updateIntervalMs - How often the manager re-processes entries that\n * have not yet reached a terminal state\n * @param options.initialData - Persisted entries to rehydrate on startup.\n */\n constructor({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n isEnabled,\n onPersistUpdates,\n entryTtlMs,\n updateIntervalMs,\n initialData,\n }: {\n messenger: BridgeStatusControllerMessenger;\n clientId: BridgeClientId;\n clientProduct: string;\n clientVersion?: string;\n apiBaseUrl: string;\n onPersistUpdates: (\n updates: Record<string, QuoteStatusPersistEntry>,\n ) => void;\n onError?: (error: QuoteStatusUpdateError) => void;\n isEnabled?: () => boolean;\n entryTtlMs: number;\n updateIntervalMs: number;\n initialData: Record<string, QuoteStatusPersistEntry>;\n }) {\n this.#isEnabled = isEnabled;\n this.#onError = onError;\n this.#updateIntervalMs = updateIntervalMs;\n this.#messenger = messenger;\n\n this.#quoteStatusApiService = new QuoteStatusApiService({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n });\n\n this.#quoteStatusEntryStore = new QuoteStatusEntryStore({\n onPersistUpdates,\n entryTtlMs,\n initial: initialData,\n });\n }\n\n /**\n * Whether quote-status tracking and backend sync are currently active.\n *\n * Reflects the latest value returned by the optional `isEnabled` predicate\n * supplied at construction time. When no predicate was provided, this is\n * always `false` and all public methods that gate on enablement no-op.\n *\n * @returns `true` when the `isEnabled` predicate returns a truthy value.\n */\n get enabled(): boolean {\n return Boolean(this.#isEnabled?.());\n }\n\n /**\n * Reports that a previously submitted quote has finalized on-chain.\n *\n * Looks up the tracked entry by its transaction metadata id, transitions it to\n * the appropriate terminal state, and processes the update. No-ops when the\n * manager is disabled, and surfaces an error when the entry is missing or\n * cannot transition to the finalized state.\n *\n * A single 7702/nested batch transaction submits multiple quotes under one\n * `txMetaId`, so every entry sharing that id is finalized together.\n *\n * @param txMetaId - Transaction metadata id of the finalized quote(s).\n * @param success - Whether the transaction finalized successfully.\n * @param srcChainId - Optional source-chain id, forwarded to error reporting\n * to aid debugging when no matching entry is found.\n * @param srcTxHash - Optional source-chain transaction hash, forwarded to\n * error reporting to aid debugging when no matching entry is found.\n */\n reportFinalised(\n txMetaId: string,\n success: boolean,\n srcChainId?: string | number,\n srcTxHash?: string,\n ): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n const entries = this.#quoteStatusEntryStore.getAllByTxMetaId(txMetaId);\n\n if (entries.length === 0) {\n this.#onError?.(\n new QuoteStatusUpdateError(\n 'reporting finalization status but entry was not found',\n { quoteId: '', txMetaId, srcChainId, srcTxHash },\n ),\n );\n return;\n }\n\n const nextState = success\n ? QuoteStatusState.FinalizedSuccess\n : QuoteStatusState.FinalizedFailed;\n\n let hasEntryToProcess = false;\n\n for (const entry of entries) {\n if (!entry.status.canTransitionTo(nextState)) {\n // This is expected, there are race conditions where\n // reportFinalized can be called twice. If the second\n // call fails due to the first completed sucesfully\n // backend will report that we cannot transition outside\n // a final state, which is correct and we can safely skip\n // this entry.\n continue;\n }\n\n entry.status.transitionTo(nextState);\n hasEntryToProcess = true;\n }\n\n if (!hasEntryToProcess) {\n return;\n }\n\n this.#ensureRetryTimerRunning();\n\n for (const entry of entries) {\n if (entry.status.state === nextState) {\n this.#processEntry(entry);\n }\n }\n }\n\n /**\n * Reports that a quote has been submitted on-chain and begins tracking it.\n *\n * Creates a new entry in the `Submitted` state, starts the retry timer, and\n * processes the initial status update. No-ops when the manager is disabled,\n * and surfaces an error if the entry cannot be retrieved after being stored.\n *\n * @param quoteId - Identifier of the submitted quote.\n * @param srcTxHash - Hash of the source-chain transaction for the quote.\n * @param txMetaId - Optional transaction metadata id used to correlate\n * finalization reports.\n * @param srcChainId - Optional source-chain id of the quote, retained on the\n * entry to enrich error reporting.\n */\n reportSubmitted(\n quoteId: string,\n srcTxHash: string,\n txMetaId?: string,\n srcChainId?: string | number,\n ): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n // Once a quote has advanced past `Submitted` (finalized or terminal), it is\n // done: reporting `SUBMITTED` again would be rejected by the backend as an\n // invalid transition. Retained terminal entries let us recognize and drop\n // these late/duplicate submissions instead of looping on a 400.\n const isQuoteAlreadyTracked = this.#quoteStatusEntryStore\n .getByQuoteId(quoteId)\n .some((entry) => entry.status.state !== QuoteStatusState.Submitted);\n if (isQuoteAlreadyTracked) {\n return;\n }\n\n const entryKey = QuoteStatusEntryStore.hash({\n quoteId,\n srcTxHash,\n });\n\n const entry = this.#quoteStatusEntryStore.put(entryKey, {\n quoteId,\n srcTxHash,\n txMetaId,\n srcChainId,\n status: new QuoteStatusStateFsm(QuoteStatusState.Submitted),\n });\n\n this.#ensureRetryTimerRunning();\n this.#processEntry(entry);\n }\n\n /**\n * Tears down the manager by stopping the retry timer and clearing all tracked\n * entries.\n */\n destroy(): void {\n this.#stopRetryTimer();\n this.#quoteStatusEntryStore.clear();\n }\n\n /**\n * Reconciles quote-status entries whose finalization was missed while the\n * client was closed. Called once during initialization.\n *\n * Swap/bridge source transactions report their final status through the\n * `TransactionController:transactionStatusUpdated` subscription\n * ({@link #onTransactionConfirmed}/{@link #onTransactionFailed}). When a source\n * transaction reaches a terminal state while the client is not running, that\n * event is never re-emitted on the next startup, so the persisted entry would\n * remain `Submitted` until it expires via TTL. This replays the missed terminal\n * event for both swaps and bridges: a confirmed source transaction is reported\n * as a finalized success and a failed/dropped one as a finalized failure.\n *\n * `rejected` is ignored because the transaction was never broadcast.\n */\n init(): void {\n this.#processInitial();\n\n for (const entry of this.#quoteStatusEntryStore.values()) {\n // Only entries still awaiting finalization need catching up. Entries\n // already in a finalized state are re-sent by `processInitial()`.\n if (\n entry.status.state !== QuoteStatusState.Submitted ||\n !entry.txMetaId\n ) {\n continue;\n }\n\n const txMeta = getTransactionMetaById(this.#messenger, entry.txMetaId);\n if (!txMeta) {\n continue;\n }\n\n // Reconcile swaps and bridges alike: a terminal source transaction\n // finalizes the quote status. `hasNestedSwapTransactions` also covers\n // batch/7702 swaps whose type may still read as `batch` rather than `swap`.\n const isCrossChainTrade =\n (txMeta.type !== undefined && isCrossChainTx(txMeta.type)) ||\n hasNestedSwapTransactions(txMeta);\n if (!isCrossChainTrade) {\n continue;\n }\n\n if (txMeta.status === TransactionStatus.confirmed) {\n this.reportFinalised(\n entry.txMetaId,\n true,\n entry.srcChainId,\n entry.srcTxHash,\n );\n } else if (\n txMeta.status === TransactionStatus.failed ||\n txMeta.status === TransactionStatus.dropped\n ) {\n this.reportFinalised(\n entry.txMetaId,\n false,\n entry.srcChainId,\n entry.srcTxHash,\n );\n }\n }\n }\n\n /**\n * Fetches the current quote status from the backend with automatic retries.\n *\n * Unlike {@link reportSubmitted} and {@link reportFinalised}, this is a\n * read-only query and does not mutate tracked entries. Returns `null` when\n * the manager is disabled ({@link enabled} is `false`).\n *\n * @param quoteId - Identifier of the quote whose status should be fetched.\n * @param options - Retry configuration.\n * @param options.maxRetries - Maximum number of retries after the initial attempt.\n * @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.\n * @returns The quote status outcome, or `undefined` when the manager is disabled.\n */\n async getStatus(\n quoteId: string,\n options: {\n maxRetries?: number;\n delayMsBetweenRetries?: number;\n } = {\n maxRetries: 0,\n delayMsBetweenRetries: 1000,\n },\n ): Promise<QuoteStatusGetWithRetryOutcome | undefined> {\n if (!this.#isEnabled?.()) {\n return undefined;\n }\n\n const response = this.#quoteStatusApiService\n .getQuoteStatusWithRetry(\n {\n quoteId,\n },\n {\n maxRetries: options.maxRetries ?? 0,\n delayMsBetweenRetries: options.delayMsBetweenRetries ?? 1000,\n },\n )\n // Errors already reported by #onError handlers of `getQuoteStatusWithRetry()`\n .catch(() => undefined);\n\n return response;\n }\n\n /**\n * Processes every entry rehydrated from persisted data on startup and starts\n * the retry timer if any entries still require further updates.\n */\n #processInitial(): void {\n for (const entry of this.#quoteStatusEntryStore.values()) {\n this.#processEntry(entry);\n }\n\n // Terminal entries (Completed/Expired) are retained, so the store is never\n // empty. Only start the retry timer when there is an entry whose status\n // still needs to be reported; otherwise it would tick forever doing nothing.\n if (this.#hasPendingUpdates()) {\n this.#ensureRetryTimerRunning();\n }\n }\n\n /**\n * Starts the periodic retry timer if it is not already running.\n *\n * The timer re-processes every non-terminal entry on each tick. It is\n * idempotent so callers can invoke it freely whenever new work is enqueued.\n */\n #ensureRetryTimerRunning(): void {\n if (this.#retryIntervalId !== null) {\n return;\n }\n\n this.#retryIntervalId = setInterval(\n () => this.#processRetries(),\n this.#updateIntervalMs,\n );\n }\n\n /**\n * Stops the periodic retry timer if it is running.\n */\n #stopRetryTimer(): void {\n if (this.#retryIntervalId !== null) {\n clearInterval(this.#retryIntervalId);\n this.#retryIntervalId = null;\n }\n }\n\n /**\n * Retry tick: re-processes every entry. Reading `values()` first transitions\n * TTL-expired entries to `Expired` (keeping them), and `#processEntry` no-ops\n * for terminal/acknowledged entries. When no entry has a status left to report\n * the timer stops until new work is enqueued.\n */\n #processRetries(): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n // Snapshot first: `#processEntry` can mutate the store (e.g. transitioning an\n // accepted entry to a terminal state), so iterating a live iterator would be\n // unsafe.\n const entries = [...this.#quoteStatusEntryStore.values()];\n\n if (!this.#hasPendingUpdates()) {\n this.#stopRetryTimer();\n return;\n }\n\n for (const entry of entries) {\n this.#processEntry(entry);\n }\n }\n\n /**\n * Returns whether any tracked entry still has a status that needs to be\n * reported to the backend.\n *\n * Terminal entries (`Completed`/`Expired`) and entries whose current status\n * has already been acknowledged are excluded, so this is the signal used to\n * decide whether the retry timer has any work left to do.\n *\n * @returns `true` when at least one entry has an unreported status.\n */\n #hasPendingUpdates(): boolean {\n for (const entry of this.#quoteStatusEntryStore.values()) {\n const { state } = entry.status;\n const isTerminal =\n state === QuoteStatusState.Completed ||\n state === QuoteStatusState.Expired;\n if (!isTerminal && entry.acknowledgedState !== state) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Stops the retry timer when there are no entries left whose status needs\n * reporting. Since terminal entries are retained, the store is never empty, so\n * the timer's idle condition is \"no pending updates\" rather than \"no entries\".\n */\n #stopRetryTimerIfIdle(): void {\n if (!this.#hasPendingUpdates()) {\n this.#stopRetryTimer();\n }\n }\n\n /**\n * Pushes a single entry's current status to the backend and reconciles the\n * local state with the request outcome.\n *\n * Terminal entries are kept but no longer reported. Accepted finalized updates\n * advance the entry to `Completed` (kept so duplicate reports are rejected);\n * accepted non-final updates (e.g. `Submitted`) are kept tracked so a later\n * {@link reportFinalised} can find them, while being flagged so the retry loop\n * stops re-sending the acknowledged status. Updates whose status advanced\n * mid-flight are reprocessed, retryable failures are left for the next retry\n * tick, and non-retryable failures are delegated to\n * {@link #handleNonRetryableUpdateStatusError}.\n *\n * @param entry - The runtime entry to process.\n */\n #processEntry(entry: QuoteStatusRuntimeEntry): void {\n // The backend already accepted the entry's current status, so there is\n // nothing new to report. The entry is kept tracked (e.g. a `Submitted`\n // quote awaiting finalization) until its status advances past the\n // acknowledged one, at which point it is reprocessed.\n if (entry.acknowledgedState === entry.status.state) {\n return;\n }\n\n const sentStatus = entry.status.state;\n const sentStatusBackend = QuoteStatusStateToBackendStatus[sentStatus];\n\n // Terminal states (`Completed`/`Expired`) have no backend status to report.\n // The entry is retained so future interactions with the quote are rejected.\n if (sentStatusBackend === null) {\n this.#stopRetryTimerIfIdle();\n return;\n }\n\n // Re-checked before each retry attempt so an in-flight retry stops early when\n // the entry has since advanced, been acknowledged, become terminal, or\n // expired (a later `reportFinalised` re-triggers processing). This avoids\n // firing a request the backend would reject (e.g. `SUBMITTED` after\n // finalization).\n const retry = (): boolean => {\n const live = this.#quoteStatusEntryStore.get(\n QuoteStatusEntryStore.hash(entry),\n );\n return Boolean(\n live &&\n live.status.state === sentStatus &&\n live.acknowledgedState !== sentStatus,\n );\n };\n\n this.#quoteStatusApiService\n .updateQuoteStatusWithRetry(\n {\n quoteId: entry.quoteId,\n srcTxHash: entry.srcTxHash,\n newStatus: sentStatusBackend,\n },\n {\n maxRetries: 5,\n delayMsBetweenRetries: 3000,\n retry,\n },\n )\n .then((outcome) => {\n switch (outcome.type) {\n case QuoteStatusFetchWithRetryOutcomeType.Accepted: {\n const current = this.#quoteStatusEntryStore.get(\n QuoteStatusEntryStore.hash(entry),\n );\n // The entry can only be absent if the store was cleared (e.g. via\n // `destroy`) while the request was in flight; nothing left to do.\n if (!current) {\n return undefined;\n }\n if (current.status.state !== sentStatus) {\n // The status advanced mid-flight; report the newer status.\n this.#processEntry(current);\n return undefined;\n }\n if (\n sentStatus === QuoteStatusState.FinalizedSuccess ||\n sentStatus === QuoteStatusState.FinalizedFailed\n ) {\n // A finalized status was accepted; advance to the terminal\n // `Completed` state and keep the entry so any later duplicate\n // `reportSubmitted` for this quote is rejected instead of looping.\n this.#markCompleted(current);\n\n return undefined;\n }\n // A non-final status (e.g. `Submitted`) was accepted. The quote is\n // not done yet: it still needs to be finalized via a later\n // `reportFinalised`, which looks the entry up by `txMetaId`. Keep\n // the entry tracked and record the acknowledgement so the retry\n // loop stops re-sending the already-accepted status.\n current.acknowledgedState = sentStatus;\n this.#quoteStatusEntryStore.update(current);\n this.#stopRetryTimerIfIdle();\n return undefined;\n }\n case QuoteStatusFetchWithRetryOutcomeType.NonRetryable:\n this.#handleNonRetryableUpdateStatusError(entry, outcome);\n return undefined;\n case QuoteStatusFetchWithRetryOutcomeType.Interrupted:\n this.#processEntry(entry);\n return undefined;\n case QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted:\n entry.lastAttemptAt = Date.now();\n this.#quoteStatusEntryStore.update(entry);\n return undefined;\n default:\n return undefined;\n }\n })\n .catch(() => {\n entry.lastAttemptAt = Date.now();\n this.#quoteStatusEntryStore.update(entry);\n });\n }\n\n /**\n * Advances an entry to the terminal `Completed` state and stops the retry\n * timer if no work remains. The entry is kept in the store so later duplicate\n * reports for the same quote are recognized and rejected.\n *\n * @param entry - The runtime entry to complete.\n * @param finalizedState - Optional finalized state the backend reports as\n * current. When provided and reachable, the entry is first advanced through it\n * so the FSM's forward-only path (`Submitted -> FinalizedX -> Completed`) is\n * respected before reaching `Completed`.\n */\n #markCompleted(\n entry: QuoteStatusRuntimeEntry,\n finalizedState?: QuoteStatusState,\n ): void {\n if (finalizedState && entry.status.canTransitionTo(finalizedState)) {\n entry.status.transitionTo(finalizedState);\n }\n\n if (entry.status.canTransitionTo(QuoteStatusState.Completed)) {\n entry.status.transitionTo(QuoteStatusState.Completed);\n }\n\n this.#stopRetryTimerIfIdle();\n }\n\n /**\n * Advances an entry to the terminal `Expired` state (abandoning it) and stops\n * the retry timer if no work remains. The entry is kept in the store so later\n * interactions with the same quote are rejected.\n *\n * @param entry - The runtime entry to abandon.\n */\n #markExpired(entry: QuoteStatusRuntimeEntry): void {\n if (entry.status.canTransitionTo(QuoteStatusState.Expired)) {\n entry.status.transitionTo(QuoteStatusState.Expired);\n }\n\n this.#stopRetryTimerIfIdle();\n }\n\n /**\n * Reconciles local state in response to a non-retryable backend error.\n *\n * When the backend reports a terminal status, the entry is either advanced to\n * match and reprocessed (if it is behind) or converged to `Completed` (if it\n * is already finalized), surfacing an error only for a genuine status\n * discrepancy. Other non-retryable errors that cannot be reconciled mark the\n * entry `Expired` (abandoned). Entries are always kept in the store so future\n * interactions with the quote are rejected rather than looping.\n *\n * @param entry - The runtime entry whose update failed.\n * @param outcome - The non-retryable outcome returned by the API service,\n * including the backend response used for reconciliation.\n */\n #handleNonRetryableUpdateStatusError(\n entry: QuoteStatusRuntimeEntry,\n outcome: QuoteStatusUpdateWithRetryOutcome,\n ): void {\n const { response } = outcome;\n\n const backendFinalizedToState: Partial<\n Record<QuoteStatusBackendStatus, QuoteStatusState>\n > = {\n [QuoteStatusBackendStatus.FinalizedSuccess]:\n QuoteStatusState.FinalizedSuccess,\n [QuoteStatusBackendStatus.FinalizedFailed]:\n QuoteStatusState.FinalizedFailed,\n };\n\n // The transition we requested is invalid because the backend is already in a\n // terminal state (e.g. we re-sent `SUBMITTED` after finalization). There is\n // nothing left to report, so advance the entry to `Completed` and keep it.\n if (\n response?.type ===\n QuoteStatusUpdateBackendErrorType.InvalidStatusTransaction &&\n (response.currentStatus === QuoteStatusBackendStatus.FinalizedSuccess ||\n response.currentStatus === QuoteStatusBackendStatus.FinalizedFailed)\n ) {\n this.#markCompleted(\n entry,\n backendFinalizedToState[response.currentStatus],\n );\n return;\n }\n\n // For mismatch errors the backend reports the status it currently has, which\n // lets us reconcile our local state. The discriminant check also narrows\n // `response` to the variant carrying `currentStatus`.\n if (\n response?.type ===\n QuoteStatusUpdateBackendErrorType.InvalidStatusTransaction ||\n response?.type ===\n QuoteStatusUpdateBackendErrorType.QuoteStatusOnChainMismatch\n ) {\n const nextState = backendFinalizedToState[response.currentStatus];\n\n if (nextState) {\n // We are behind the backend's terminal status; advance our local state\n // and reprocess so the correct finalization status is reported.\n if (entry.status.canTransitionTo(nextState)) {\n entry.status.transitionTo(nextState);\n this.#processEntry(entry);\n return;\n }\n\n // The backend reports a finalized status but we cannot transition there.\n // If we already hold that same finalized state, this can be a stale\n // `SUBMITTED` response racing with an in-flight finalized update. Do not\n // complete in this case: keep the entry pending so the finalized update\n // can continue retrying on transient backend errors such as\n // `CONCURRENT_UPDATE`.\n if (entry.status.state === nextState) {\n return;\n }\n\n // Any other non-transitionable finalized mismatch indicates we've reached\n // (or passed) a terminal state but disagree with the backend's final\n // status. Converge to `Completed` (kept) rather than expiring.\n if (\n entry.status.state !== QuoteStatusState.Completed &&\n entry.status.state !== QuoteStatusState.Expired\n ) {\n // Genuine discrepancy between our finalized status and the backend's\n // (e.g. we observed the opposite outcome); surface it for visibility,\n // but still complete the entry instead of looping or abandoning it.\n this.#onError?.(\n new QuoteStatusUpdateError(\n `reporting finalization status but entry cannot transition from \"${entry.status.state}\" to \"${nextState}\"`,\n {\n quoteId: entry.quoteId,\n txMetaId: entry.txMetaId,\n srcTxHash: entry.srcTxHash,\n srcChainId: entry.srcChainId,\n },\n ),\n );\n }\n this.#markCompleted(entry);\n return;\n }\n }\n\n // Any non-retryable error we could not reconcile means we cannot make\n // progress on this entry, so abandon it rather than leaving it stuck.\n this.#markExpired(entry);\n this.#onError?.(\n new QuoteStatusUpdateError(\n `abandoning entry due to non-retryable error`,\n {\n quoteId: entry.quoteId,\n errorType: response?.type,\n txMetaId: entry.txMetaId,\n srcTxHash: entry.srcTxHash,\n srcChainId: entry.srcChainId,\n },\n ),\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"quotes-status-manager.js","sourceRoot":"","sources":["../../src/quote-status-manager/quotes-status-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { TransactionStatus } from '@metamask/transaction-controller';\n\nimport { BridgeClientId, BridgeStatusControllerMessenger } from '../types.js';\nimport {\n getTransactionMetaById,\n hasNestedSwapTransactions,\n isCrossChainTx,\n} from '../utils/transaction.js';\nimport {\n QuoteStatusState,\n QuoteStatusStateToBackendStatus,\n QuoteStatusUpdateBackendErrorType,\n QuoteStatusBackendStatus,\n QuoteStatusFetchWithRetryOutcomeType,\n} from './constants.js';\nimport { QuoteStatusUpdateError } from './errors.js';\nimport { QuoteStatusApiService } from './quote-status-api-service.js';\nimport { QuoteStatusEntryStore } from './quote-status-entry-store.js';\nimport { QuoteStatusGetWithRetryOutcome } from './quote-status-get-with-retry-outcome.js';\nimport { QuoteStatusStateFsm } from './quote-status-state-fsm.js';\nimport { QuoteStatusUpdateWithRetryOutcome } from './quote-status-update-with-retry-outcome.js';\nimport { QuoteStatusPersistEntry, QuoteStatusRuntimeEntry } from './types.js';\n\n/**\n * Tracks bridge/swap quotes through their lifecycle and keeps the backend in\n * sync with the latest known status of each quote.\n *\n * Quotes are reported via {@link reportSubmitted} and {@link reportFinalised},\n * stored as runtime entries, and pushed to the backend. Updates that fail in a\n * retryable way are retried on a periodic timer until each entry reaches a\n * terminal state, at which point it is evicted and the timer stops once the\n * store is empty.\n */\nexport class QuoteStatusManager {\n readonly #messenger: BridgeStatusControllerMessenger;\n\n readonly #quoteStatusApiService: QuoteStatusApiService;\n\n readonly #quoteStatusEntryStore: QuoteStatusEntryStore;\n\n readonly #isEnabled: (() => boolean) | undefined;\n\n readonly #onError: ((error: QuoteStatusUpdateError) => void) | undefined;\n\n readonly #updateIntervalMs: number;\n\n /**\n * Handle for the periodic retry timer. While running, every\n * {@link QUOTE_STATUS_UPDATE_RETRY_INTERVAL_MS} all entries that have not yet\n * reached a terminal state (Completed/Expired) are re-processed. It is started\n * lazily when there is work to do and stopped once the store is empty.\n */\n #retryIntervalId: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Creates a new manager and immediately processes any persisted entries.\n *\n * @param options - Constructor options.\n * @param options.messenger - Messenger used to communicate with the backend\n * API service.\n * @param options.clientId - Identifier of the client making the requests.\n * @param options.clientProduct - Name of the client product making the\n * requests.\n * @param options.clientVersion - Optional version of the client product.\n * @param options.apiBaseUrl - Base URL of the quote status backend API.\n * @param options.onPersistUpdates - Callback invoked to persist entry updates.\n * @param options.onError - Optional callback invoked when a non-recoverable\n * error occurs.\n * @param options.isEnabled - Optional predicate gating whether the manager\n * performs any work.\n * @param options.entryTtlMs - Time-to-live, in milliseconds, after which a\n * tracked entry is evicted.\n * @param options.updateIntervalMs - How often the manager re-processes entries that\n * have not yet reached a terminal state\n * @param options.initialData - Persisted entries to rehydrate on startup.\n */\n constructor({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n isEnabled,\n onPersistUpdates,\n entryTtlMs,\n updateIntervalMs,\n initialData,\n }: {\n messenger: BridgeStatusControllerMessenger;\n clientId: BridgeClientId;\n clientProduct: string;\n clientVersion?: string;\n apiBaseUrl: string;\n onPersistUpdates: (\n updates: Record<string, QuoteStatusPersistEntry>,\n ) => void;\n onError?: (error: QuoteStatusUpdateError) => void;\n isEnabled?: () => boolean;\n entryTtlMs: number;\n updateIntervalMs: number;\n initialData: Record<string, QuoteStatusPersistEntry>;\n }) {\n this.#isEnabled = isEnabled;\n this.#onError = onError;\n this.#updateIntervalMs = updateIntervalMs;\n this.#messenger = messenger;\n\n this.#quoteStatusApiService = new QuoteStatusApiService({\n messenger,\n clientId,\n clientProduct,\n clientVersion,\n apiBaseUrl,\n onError,\n });\n\n this.#quoteStatusEntryStore = new QuoteStatusEntryStore({\n onPersistUpdates,\n entryTtlMs,\n initial: initialData,\n });\n }\n\n /**\n * Whether quote-status tracking and backend sync are currently active.\n *\n * Reflects the latest value returned by the optional `isEnabled` predicate\n * supplied at construction time. When no predicate was provided, this is\n * always `false` and all public methods that gate on enablement no-op.\n *\n * @returns `true` when the `isEnabled` predicate returns a truthy value.\n */\n get enabled(): boolean {\n return Boolean(this.#isEnabled?.());\n }\n\n /**\n * Reports that a previously submitted quote has finalized on-chain.\n *\n * Looks up the tracked entry by its transaction metadata id, transitions it to\n * the appropriate terminal state, and processes the update. No-ops when the\n * manager is disabled, and surfaces an error when the entry is missing or\n * cannot transition to the finalized state.\n *\n * A single 7702/nested batch transaction submits multiple quotes under one\n * `txMetaId`, so every entry sharing that id is finalized together.\n *\n * @param txMetaId - Transaction metadata id of the finalized quote(s).\n * @param success - Whether the transaction finalized successfully.\n * @param srcChainId - Optional source-chain id, forwarded to error reporting\n * to aid debugging when no matching entry is found.\n * @param srcTxHash - Optional source-chain transaction hash, forwarded to\n * error reporting to aid debugging when no matching entry is found.\n */\n reportFinalised(\n txMetaId: string,\n success: boolean,\n srcChainId?: string | number,\n srcTxHash?: string,\n ): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n const entries = this.#quoteStatusEntryStore.getAllByTxMetaId(txMetaId);\n\n if (entries.length === 0) {\n this.#onError?.(\n new QuoteStatusUpdateError(\n 'reporting finalization status but entry was not found',\n { quoteId: '', txMetaId, srcChainId, srcTxHash },\n ),\n );\n return;\n }\n\n const nextState = success\n ? QuoteStatusState.FinalizedSuccess\n : QuoteStatusState.FinalizedFailed;\n\n let hasEntryToProcess = false;\n\n for (const entry of entries) {\n if (!entry.status.canTransitionTo(nextState)) {\n // This is expected, there are race conditions where\n // reportFinalized can be called twice. If the second\n // call fails due to the first completed sucesfully\n // backend will report that we cannot transition outside\n // a final state, which is correct and we can safely skip\n // this entry.\n continue;\n }\n\n entry.status.transitionTo(nextState);\n hasEntryToProcess = true;\n }\n\n if (!hasEntryToProcess) {\n return;\n }\n\n this.#ensureRetryTimerRunning();\n\n for (const entry of entries) {\n if (entry.status.state === nextState) {\n this.#processEntry(entry);\n }\n }\n }\n\n /**\n * Reports that a quote has been submitted on-chain and begins tracking it.\n *\n * Creates a new entry in the `Submitted` state, starts the retry timer, and\n * processes the initial status update. No-ops when the manager is disabled,\n * and surfaces an error if the entry cannot be retrieved after being stored.\n *\n * @param quoteId - Identifier of the submitted quote.\n * @param srcTxHash - Hash of the source-chain transaction for the quote.\n * @param txMetaId - Optional transaction metadata id used to correlate\n * finalization reports.\n * @param srcChainId - Optional source-chain id of the quote, retained on the\n * entry to enrich error reporting.\n */\n reportSubmitted(\n quoteId: string,\n srcTxHash: string,\n txMetaId?: string,\n srcChainId?: string | number,\n ): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n // Once a quote has advanced past `Submitted` (finalized or terminal), it is\n // done: reporting `SUBMITTED` again would be rejected by the backend as an\n // invalid transition. Retained terminal entries let us recognize and drop\n // these late/duplicate submissions instead of looping on a 400.\n const isQuoteAlreadyTracked = this.#quoteStatusEntryStore\n .getByQuoteId(quoteId)\n .some((entry) => entry.status.state !== QuoteStatusState.Submitted);\n if (isQuoteAlreadyTracked) {\n return;\n }\n\n const entryKey = QuoteStatusEntryStore.hash({\n quoteId,\n srcTxHash,\n });\n\n const entry = this.#quoteStatusEntryStore.put(entryKey, {\n quoteId,\n srcTxHash,\n txMetaId,\n srcChainId,\n status: new QuoteStatusStateFsm(QuoteStatusState.Submitted),\n });\n\n this.#ensureRetryTimerRunning();\n this.#processEntry(entry);\n }\n\n /**\n * Tears down the manager by stopping the retry timer and clearing all tracked\n * entries.\n */\n destroy(): void {\n this.#stopRetryTimer();\n this.#quoteStatusEntryStore.clear();\n }\n\n /**\n * Reconciles quote-status entries whose finalization was missed while the\n * client was closed. Called once during initialization.\n *\n * Swap/bridge source transactions report their final status through the\n * `TransactionController:transactionStatusUpdated` subscription\n * ({@link #onTransactionConfirmed}/{@link #onTransactionFailed}). When a source\n * transaction reaches a terminal state while the client is not running, that\n * event is never re-emitted on the next startup, so the persisted entry would\n * remain `Submitted` until it expires via TTL. This replays the missed terminal\n * event for both swaps and bridges: a confirmed source transaction is reported\n * as a finalized success and a failed/dropped one as a finalized failure.\n *\n * `rejected` is ignored because the transaction was never broadcast.\n */\n init(): void {\n this.#processInitial();\n\n for (const entry of this.#quoteStatusEntryStore.values()) {\n // Only entries still awaiting finalization need catching up. Entries\n // already in a finalized state are re-sent by `processInitial()`.\n if (\n entry.status.state !== QuoteStatusState.Submitted ||\n !entry.txMetaId\n ) {\n continue;\n }\n\n const txMeta = getTransactionMetaById(this.#messenger, entry.txMetaId);\n if (!txMeta) {\n continue;\n }\n\n // Reconcile swaps and bridges alike: a terminal source transaction\n // finalizes the quote status. `hasNestedSwapTransactions` also covers\n // batch/7702 swaps whose type may still read as `batch` rather than `swap`.\n const isCrossChainTrade =\n (txMeta.type !== undefined && isCrossChainTx(txMeta.type)) ||\n hasNestedSwapTransactions(txMeta);\n if (!isCrossChainTrade) {\n continue;\n }\n\n if (txMeta.status === TransactionStatus.confirmed) {\n this.reportFinalised(\n entry.txMetaId,\n true,\n entry.srcChainId,\n entry.srcTxHash,\n );\n } else if (\n txMeta.status === TransactionStatus.failed ||\n txMeta.status === TransactionStatus.dropped\n ) {\n this.reportFinalised(\n entry.txMetaId,\n false,\n entry.srcChainId,\n entry.srcTxHash,\n );\n }\n }\n }\n\n /**\n * Fetches the current quote status from the backend with automatic retries.\n *\n * Unlike {@link reportSubmitted} and {@link reportFinalised}, this is a\n * read-only query and does not mutate tracked entries. Returns `null` when\n * the manager is disabled ({@link enabled} is `false`).\n *\n * @param quoteId - Identifier of the quote whose status should be fetched.\n * @param options - Retry configuration.\n * @param options.maxRetries - Maximum number of retries after the initial attempt.\n * @param options.delayMsBetweenRetries - Delay in milliseconds between attempts.\n * @returns The quote status outcome, or `undefined` when the manager is disabled.\n */\n async getStatus(\n quoteId: string,\n options: {\n maxRetries?: number;\n delayMsBetweenRetries?: number;\n } = {\n maxRetries: 0,\n delayMsBetweenRetries: 1000,\n },\n ): Promise<QuoteStatusGetWithRetryOutcome | undefined> {\n if (!this.#isEnabled?.()) {\n return undefined;\n }\n\n const response = this.#quoteStatusApiService\n .getQuoteStatusWithRetry(\n {\n quoteId,\n },\n {\n maxRetries: options.maxRetries ?? 0,\n delayMsBetweenRetries: options.delayMsBetweenRetries ?? 1000,\n },\n )\n // Errors already reported by #onError handlers of `getQuoteStatusWithRetry()`\n .catch(() => undefined);\n\n return response;\n }\n\n /**\n * Processes every entry rehydrated from persisted data on startup and starts\n * the retry timer if any entries still require further updates.\n */\n #processInitial(): void {\n for (const entry of this.#quoteStatusEntryStore.values()) {\n this.#processEntry(entry);\n }\n\n // Terminal entries (Completed/Expired) are retained, so the store is never\n // empty. Only start the retry timer when there is an entry whose status\n // still needs to be reported; otherwise it would tick forever doing nothing.\n if (this.#hasPendingUpdates()) {\n this.#ensureRetryTimerRunning();\n }\n }\n\n /**\n * Starts the periodic retry timer if it is not already running.\n *\n * The timer re-processes every non-terminal entry on each tick. It is\n * idempotent so callers can invoke it freely whenever new work is enqueued.\n */\n #ensureRetryTimerRunning(): void {\n if (this.#retryIntervalId !== null) {\n return;\n }\n\n this.#retryIntervalId = setInterval(\n () => this.#processRetries(),\n this.#updateIntervalMs,\n );\n }\n\n /**\n * Stops the periodic retry timer if it is running.\n */\n #stopRetryTimer(): void {\n if (this.#retryIntervalId !== null) {\n clearInterval(this.#retryIntervalId);\n this.#retryIntervalId = null;\n }\n }\n\n /**\n * Retry tick: re-processes every entry. Reading `values()` first transitions\n * TTL-expired entries to `Expired` (keeping them), and `#processEntry` no-ops\n * for terminal/acknowledged entries. When no entry has a status left to report\n * the timer stops until new work is enqueued.\n */\n #processRetries(): void {\n if (!this.#isEnabled?.()) {\n return;\n }\n\n // Snapshot first: `#processEntry` can mutate the store (e.g. transitioning an\n // accepted entry to a terminal state), so iterating a live iterator would be\n // unsafe.\n const entries = [...this.#quoteStatusEntryStore.values()];\n\n if (!this.#hasPendingUpdates()) {\n this.#stopRetryTimer();\n return;\n }\n\n for (const entry of entries) {\n this.#processEntry(entry);\n }\n }\n\n /**\n * Returns whether any tracked entry still has a status that needs to be\n * reported to the backend.\n *\n * Terminal entries (`Completed`/`Expired`) and entries whose current status\n * has already been acknowledged are excluded, so this is the signal used to\n * decide whether the retry timer has any work left to do.\n *\n * @returns `true` when at least one entry has an unreported status.\n */\n #hasPendingUpdates(): boolean {\n for (const entry of this.#quoteStatusEntryStore.values()) {\n const { state } = entry.status;\n const isTerminal =\n state === QuoteStatusState.Completed ||\n state === QuoteStatusState.Expired;\n if (!isTerminal && entry.acknowledgedState !== state) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Stops the retry timer when there are no entries left whose status needs\n * reporting. Since terminal entries are retained, the store is never empty, so\n * the timer's idle condition is \"no pending updates\" rather than \"no entries\".\n */\n #stopRetryTimerIfIdle(): void {\n if (!this.#hasPendingUpdates()) {\n this.#stopRetryTimer();\n }\n }\n\n /**\n * Pushes a single entry's current status to the backend and reconciles the\n * local state with the request outcome.\n *\n * Terminal entries are kept but no longer reported. Accepted finalized updates\n * advance the entry to `Completed` (kept so duplicate reports are rejected);\n * accepted non-final updates (e.g. `Submitted`) are kept tracked so a later\n * {@link reportFinalised} can find them, while being flagged so the retry loop\n * stops re-sending the acknowledged status. Updates whose status advanced\n * mid-flight are reprocessed, retryable failures are left for the next retry\n * tick, and non-retryable failures are delegated to\n * {@link #handleNonRetryableUpdateStatusError}.\n *\n * @param entry - The runtime entry to process.\n */\n #processEntry(entry: QuoteStatusRuntimeEntry): void {\n // The backend already accepted the entry's current status, so there is\n // nothing new to report. The entry is kept tracked (e.g. a `Submitted`\n // quote awaiting finalization) until its status advances past the\n // acknowledged one, at which point it is reprocessed.\n if (entry.acknowledgedState === entry.status.state) {\n return;\n }\n\n const sentStatus = entry.status.state;\n const sentStatusBackend = QuoteStatusStateToBackendStatus[sentStatus];\n\n // Terminal states (`Completed`/`Expired`) have no backend status to report.\n // The entry is retained so future interactions with the quote are rejected.\n if (sentStatusBackend === null) {\n this.#stopRetryTimerIfIdle();\n return;\n }\n\n // Re-checked before each retry attempt so an in-flight retry stops early when\n // the entry has since advanced, been acknowledged, become terminal, or\n // expired (a later `reportFinalised` re-triggers processing). This avoids\n // firing a request the backend would reject (e.g. `SUBMITTED` after\n // finalization).\n const retry = (): boolean => {\n const live = this.#quoteStatusEntryStore.get(\n QuoteStatusEntryStore.hash(entry),\n );\n return Boolean(\n live?.status.state === sentStatus &&\n live.acknowledgedState !== sentStatus,\n );\n };\n\n this.#quoteStatusApiService\n .updateQuoteStatusWithRetry(\n {\n quoteId: entry.quoteId,\n srcTxHash: entry.srcTxHash,\n newStatus: sentStatusBackend,\n },\n {\n maxRetries: 5,\n delayMsBetweenRetries: 3000,\n retry,\n },\n )\n .then((outcome) => {\n switch (outcome.type) {\n case QuoteStatusFetchWithRetryOutcomeType.Accepted: {\n const current = this.#quoteStatusEntryStore.get(\n QuoteStatusEntryStore.hash(entry),\n );\n // The entry can only be absent if the store was cleared (e.g. via\n // `destroy`) while the request was in flight; nothing left to do.\n if (!current) {\n return;\n }\n if (current.status.state !== sentStatus) {\n // The status advanced mid-flight; report the newer status.\n this.#processEntry(current);\n return;\n }\n if (\n sentStatus === QuoteStatusState.FinalizedSuccess ||\n sentStatus === QuoteStatusState.FinalizedFailed\n ) {\n // A finalized status was accepted; advance to the terminal\n // `Completed` state and keep the entry so any later duplicate\n // `reportSubmitted` for this quote is rejected instead of looping.\n this.#markCompleted(current);\n\n return;\n }\n // A non-final status (e.g. `Submitted`) was accepted. The quote is\n // not done yet: it still needs to be finalized via a later\n // `reportFinalised`, which looks the entry up by `txMetaId`. Keep\n // the entry tracked and record the acknowledgement so the retry\n // loop stops re-sending the already-accepted status.\n current.acknowledgedState = sentStatus;\n this.#quoteStatusEntryStore.update(current);\n this.#stopRetryTimerIfIdle();\n return;\n }\n case QuoteStatusFetchWithRetryOutcomeType.NonRetryable:\n this.#handleNonRetryableUpdateStatusError(entry, outcome);\n return;\n case QuoteStatusFetchWithRetryOutcomeType.Interrupted:\n this.#processEntry(entry);\n return;\n case QuoteStatusFetchWithRetryOutcomeType.RetryableExhausted:\n entry.lastAttemptAt = Date.now();\n this.#quoteStatusEntryStore.update(entry);\n return;\n default:\n return;\n }\n })\n .catch(() => {\n entry.lastAttemptAt = Date.now();\n this.#quoteStatusEntryStore.update(entry);\n });\n }\n\n /**\n * Advances an entry to the terminal `Completed` state and stops the retry\n * timer if no work remains. The entry is kept in the store so later duplicate\n * reports for the same quote are recognized and rejected.\n *\n * @param entry - The runtime entry to complete.\n * @param finalizedState - Optional finalized state the backend reports as\n * current. When provided and reachable, the entry is first advanced through it\n * so the FSM's forward-only path (`Submitted -> FinalizedX -> Completed`) is\n * respected before reaching `Completed`.\n */\n #markCompleted(\n entry: QuoteStatusRuntimeEntry,\n finalizedState?: QuoteStatusState,\n ): void {\n if (finalizedState && entry.status.canTransitionTo(finalizedState)) {\n entry.status.transitionTo(finalizedState);\n }\n\n if (entry.status.canTransitionTo(QuoteStatusState.Completed)) {\n entry.status.transitionTo(QuoteStatusState.Completed);\n }\n\n this.#stopRetryTimerIfIdle();\n }\n\n /**\n * Advances an entry to the terminal `Expired` state (abandoning it) and stops\n * the retry timer if no work remains. The entry is kept in the store so later\n * interactions with the same quote are rejected.\n *\n * @param entry - The runtime entry to abandon.\n */\n #markExpired(entry: QuoteStatusRuntimeEntry): void {\n if (entry.status.canTransitionTo(QuoteStatusState.Expired)) {\n entry.status.transitionTo(QuoteStatusState.Expired);\n }\n\n this.#stopRetryTimerIfIdle();\n }\n\n /**\n * Reconciles local state in response to a non-retryable backend error.\n *\n * When the backend reports a terminal status, the entry is either advanced to\n * match and reprocessed (if it is behind) or converged to `Completed` (if it\n * is already finalized), surfacing an error only for a genuine status\n * discrepancy. Other non-retryable errors that cannot be reconciled mark the\n * entry `Expired` (abandoned). Entries are always kept in the store so future\n * interactions with the quote are rejected rather than looping.\n *\n * @param entry - The runtime entry whose update failed.\n * @param outcome - The non-retryable outcome returned by the API service,\n * including the backend response used for reconciliation.\n */\n #handleNonRetryableUpdateStatusError(\n entry: QuoteStatusRuntimeEntry,\n outcome: QuoteStatusUpdateWithRetryOutcome,\n ): void {\n const { response } = outcome;\n\n const backendFinalizedToState: Partial<\n Record<QuoteStatusBackendStatus, QuoteStatusState>\n > = {\n [QuoteStatusBackendStatus.FinalizedSuccess]:\n QuoteStatusState.FinalizedSuccess,\n [QuoteStatusBackendStatus.FinalizedFailed]:\n QuoteStatusState.FinalizedFailed,\n };\n\n // The transition we requested is invalid because the backend is already in a\n // terminal state (e.g. we re-sent `SUBMITTED` after finalization). There is\n // nothing left to report, so advance the entry to `Completed` and keep it.\n if (\n response?.type ===\n QuoteStatusUpdateBackendErrorType.InvalidStatusTransaction &&\n (response.currentStatus === QuoteStatusBackendStatus.FinalizedSuccess ||\n response.currentStatus === QuoteStatusBackendStatus.FinalizedFailed)\n ) {\n this.#markCompleted(\n entry,\n backendFinalizedToState[response.currentStatus],\n );\n return;\n }\n\n // For mismatch errors the backend reports the status it currently has, which\n // lets us reconcile our local state. The discriminant check also narrows\n // `response` to the variant carrying `currentStatus`.\n if (\n response?.type ===\n QuoteStatusUpdateBackendErrorType.InvalidStatusTransaction ||\n response?.type ===\n QuoteStatusUpdateBackendErrorType.QuoteStatusOnChainMismatch\n ) {\n const nextState = backendFinalizedToState[response.currentStatus];\n\n if (nextState) {\n // We are behind the backend's terminal status; advance our local state\n // and reprocess so the correct finalization status is reported.\n if (entry.status.canTransitionTo(nextState)) {\n entry.status.transitionTo(nextState);\n this.#processEntry(entry);\n return;\n }\n\n // The backend reports a finalized status but we cannot transition there.\n // If we already hold that same finalized state, this can be a stale\n // `SUBMITTED` response racing with an in-flight finalized update. Do not\n // complete in this case: keep the entry pending so the finalized update\n // can continue retrying on transient backend errors such as\n // `CONCURRENT_UPDATE`.\n if (entry.status.state === nextState) {\n return;\n }\n\n // Any other non-transitionable finalized mismatch indicates we've reached\n // (or passed) a terminal state but disagree with the backend's final\n // status. Converge to `Completed` (kept) rather than expiring.\n if (\n entry.status.state !== QuoteStatusState.Completed &&\n entry.status.state !== QuoteStatusState.Expired\n ) {\n // Genuine discrepancy between our finalized status and the backend's\n // (e.g. we observed the opposite outcome); surface it for visibility,\n // but still complete the entry instead of looping or abandoning it.\n this.#onError?.(\n new QuoteStatusUpdateError(\n `reporting finalization status but entry cannot transition from \"${entry.status.state}\" to \"${nextState}\"`,\n {\n quoteId: entry.quoteId,\n txMetaId: entry.txMetaId,\n srcTxHash: entry.srcTxHash,\n srcChainId: entry.srcChainId,\n },\n ),\n );\n }\n this.#markCompleted(entry);\n return;\n }\n }\n\n // Any non-retryable error we could not reconcile means we cannot make\n // progress on this entry, so abandon it rather than leaving it stuck.\n this.#markExpired(entry);\n this.#onError?.(\n new QuoteStatusUpdateError(\n `abandoning entry due to non-retryable error`,\n {\n quoteId: entry.quoteId,\n errorType: response?.type,\n txMetaId: entry.txMetaId,\n srcTxHash: entry.srcTxHash,\n srcChainId: entry.srcChainId,\n },\n ),\n );\n }\n}\n"]}
|
|
@@ -54,7 +54,7 @@ const approve = async (args) => {
|
|
|
54
54
|
const { quoteResponses: [quoteResponse], isBridgeTx, } = args;
|
|
55
55
|
const { approval, resetApproval } = quoteResponse;
|
|
56
56
|
if (!approval || !isEvmTxData(approval)) {
|
|
57
|
-
return
|
|
57
|
+
return;
|
|
58
58
|
}
|
|
59
59
|
const transactionType = isBridgeTx
|
|
60
60
|
? TransactionType.bridgeApproval
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evm-strategy.js","sourceRoot":"","sources":["../../src/strategy/evm-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable consistent-return */\n/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport { formatChainIdToHex, isEvmTxData } from '@metamask/bridge-controller';\nimport type { TxData } from '@metamask/bridge-controller';\nimport {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\n\nimport { BridgeStatusControllerMessenger } from '../types.js';\nimport { getAccountByAddress } from '../utils/accounts.js';\nimport { getNetworkClientIdByChainId } from '../utils/network.js';\nimport { getApprovalTraceParams } from '../utils/trace.js';\nimport {\n addTransaction,\n generateActionId,\n handleApprovalDelay,\n handleMobileHardwareWalletDelay,\n toTransactionParams,\n waitForTxConfirmation,\n} from '../utils/transaction.js';\nimport { SubmitStep } from './types.js';\nimport type { SubmitStrategyParams, SubmitStepResult } from './types.js';\n\n/**\n * Submits a single tx to the TransactionController and returns the txMetaId\n *\n * @param args - The parameters for the transaction\n * @param args.transactionType - The type of transaction to submit\n * @param args.trade - The trade data to confirm\n * @param args.requireApproval - Whether to require approval for the transaction\n * @param args.txFee - Optional gas fee parameters from the quote (used when gasIncluded is true)\n * @param args.txFee.maxFeePerGas - The maximum fee per gas from the quote\n * @param args.txFee.maxPriorityFeePerGas - The maximum priority fee per gas from the quote\n * @param args.actionId - Optional actionId for pre-submission history (if not provided, one is generated)\n * @param args.messenger - The messenger to use for the transaction\n * @returns The transaction meta\n */\nexport const handleSingleTx = async ({\n messenger,\n trade,\n transactionType,\n requireApproval = false,\n txFee,\n // Use provided actionId (for pre-submission history) or generate one\n actionId = generateActionId(),\n}: {\n messenger: BridgeStatusControllerMessenger;\n transactionType: TransactionType;\n trade: TxData;\n requireApproval?: boolean;\n txFee?: { maxFeePerGas: string; maxPriorityFeePerGas: string };\n actionId?: string;\n}): Promise<TransactionMeta> => {\n const selectedAccount = getAccountByAddress(messenger, trade.from);\n if (!selectedAccount) {\n throw new Error(\n 'Failed to submit cross-chain swap transaction: unknown account in trade data',\n );\n }\n const hexChainId = formatChainIdToHex(trade.chainId);\n const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);\n\n const requestOptions = {\n actionId,\n networkClientId,\n requireApproval,\n type: transactionType,\n origin: 'metamask',\n isInternal: true,\n };\n\n const transactionParamsWithMaxGas = await toTransactionParams(\n messenger,\n trade,\n networkClientId,\n hexChainId,\n txFee,\n );\n\n return await addTransaction(\n messenger,\n { ...transactionParamsWithMaxGas, from: trade.from },\n requestOptions,\n );\n};\n\n/**\n * Submits the approval and resetApproval transactions through the TransactionController.\n * If there is a resetApproval, it will be submitted first.\n * But only the approval's txMetaId will be returned.\n *\n * @param args - The parameters for the submission flow\n *\n * @returns The approvalTxId of the approval transaction\n */\nconst approve = async (args: SubmitStrategyParams) => {\n const {\n quoteResponses: [quoteResponse],\n isBridgeTx,\n } = args;\n const { approval, resetApproval } = quoteResponse;\n if (!approval || !isEvmTxData(approval)) {\n return undefined;\n }\n\n const transactionType = isBridgeTx\n ? TransactionType.bridgeApproval\n : TransactionType.swapApproval;\n\n if (resetApproval) {\n await handleSingleTx({\n ...args,\n transactionType,\n trade: resetApproval,\n });\n }\n\n if (approval) {\n const approvalTxMeta = await handleSingleTx({\n ...args,\n transactionType,\n trade: approval,\n });\n return approvalTxMeta?.id;\n }\n};\n\nexport const handleEvmApprovals = async (args: SubmitStrategyParams) =>\n await args.traceFn(\n getApprovalTraceParams(args.quoteResponses[0], args.isStxEnabled),\n async () => await approve(args),\n );\n\n/**\n * Sequentially submits EVM resetApproval, approval and trade transactions through the TransactionController.\n *\n * @param args - The parameters for the transaction\n * @yields Data for updating the BridgeStatusController\n */\nexport async function* submitEvmHandler(\n args: SubmitStrategyParams<TxData>,\n): AsyncGenerator<SubmitStepResult, void, void> {\n const {\n quoteResponses: [quoteResponse],\n requireApproval,\n isBridgeTx,\n } = args;\n\n // Submit resetApproval and approval transactions if present\n const approvalTxId = await handleEvmApprovals(args);\n\n // Delay after approval\n if (approvalTxId) {\n await handleApprovalDelay(quoteResponse.quote.srcChainId);\n }\n // Hardware-wallet delay first (Ledger second-prompt spacing), then wait for\n // on-chain approval confirmation so swap gas estimation runs after allowance is set.\n await handleMobileHardwareWalletDelay(requireApproval);\n if (requireApproval && approvalTxId) {\n await waitForTxConfirmation(args.messenger, approvalTxId);\n }\n\n // Generate trade actionId for pre-submission history\n const actionId = generateActionId();\n\n // Add pre-submission history keyed by actionId\n // This ensures we have quote data available if transaction fails during submission\n yield {\n type: SubmitStep.AddHistoryItem,\n payload: {\n historyKey: actionId,\n approvalTxId,\n actionId,\n quoteResponse,\n },\n };\n\n const transactionType = isBridgeTx\n ? TransactionType.bridge\n : TransactionType.swap;\n\n const tradeMeta = await handleSingleTx({\n ...args,\n transactionType,\n trade: quoteResponse.trade,\n // TODO figure out if this is needed\n // Pass txFee when gasIncluded is true to use the quote's gas fees\n // instead of re-estimating (which would fail for max native token swaps)\n txFee: quoteResponse.quote.gasIncluded\n ? quoteResponse.quote.feeData.txFee\n : undefined,\n actionId,\n });\n\n // Use the tradeMeta's id as history key\n yield {\n type: SubmitStep.RekeyHistoryItem,\n payload: {\n oldHistoryKey: actionId,\n newHistoryKey: tradeMeta.id,\n tradeMeta,\n },\n };\n\n yield {\n type: SubmitStep.SetTradeMeta,\n payload: {\n tradeMeta,\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"evm-strategy.js","sourceRoot":"","sources":["../../src/strategy/evm-strategy.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable consistent-return */\n/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport { formatChainIdToHex, isEvmTxData } from '@metamask/bridge-controller';\nimport type { TxData } from '@metamask/bridge-controller';\nimport {\n TransactionMeta,\n TransactionType,\n} from '@metamask/transaction-controller';\n\nimport { BridgeStatusControllerMessenger } from '../types.js';\nimport { getAccountByAddress } from '../utils/accounts.js';\nimport { getNetworkClientIdByChainId } from '../utils/network.js';\nimport { getApprovalTraceParams } from '../utils/trace.js';\nimport {\n addTransaction,\n generateActionId,\n handleApprovalDelay,\n handleMobileHardwareWalletDelay,\n toTransactionParams,\n waitForTxConfirmation,\n} from '../utils/transaction.js';\nimport { SubmitStep } from './types.js';\nimport type { SubmitStrategyParams, SubmitStepResult } from './types.js';\n\n/**\n * Submits a single tx to the TransactionController and returns the txMetaId\n *\n * @param args - The parameters for the transaction\n * @param args.transactionType - The type of transaction to submit\n * @param args.trade - The trade data to confirm\n * @param args.requireApproval - Whether to require approval for the transaction\n * @param args.txFee - Optional gas fee parameters from the quote (used when gasIncluded is true)\n * @param args.txFee.maxFeePerGas - The maximum fee per gas from the quote\n * @param args.txFee.maxPriorityFeePerGas - The maximum priority fee per gas from the quote\n * @param args.actionId - Optional actionId for pre-submission history (if not provided, one is generated)\n * @param args.messenger - The messenger to use for the transaction\n * @returns The transaction meta\n */\nexport const handleSingleTx = async ({\n messenger,\n trade,\n transactionType,\n requireApproval = false,\n txFee,\n // Use provided actionId (for pre-submission history) or generate one\n actionId = generateActionId(),\n}: {\n messenger: BridgeStatusControllerMessenger;\n transactionType: TransactionType;\n trade: TxData;\n requireApproval?: boolean;\n txFee?: { maxFeePerGas: string; maxPriorityFeePerGas: string };\n actionId?: string;\n}): Promise<TransactionMeta> => {\n const selectedAccount = getAccountByAddress(messenger, trade.from);\n if (!selectedAccount) {\n throw new Error(\n 'Failed to submit cross-chain swap transaction: unknown account in trade data',\n );\n }\n const hexChainId = formatChainIdToHex(trade.chainId);\n const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);\n\n const requestOptions = {\n actionId,\n networkClientId,\n requireApproval,\n type: transactionType,\n origin: 'metamask',\n isInternal: true,\n };\n\n const transactionParamsWithMaxGas = await toTransactionParams(\n messenger,\n trade,\n networkClientId,\n hexChainId,\n txFee,\n );\n\n return await addTransaction(\n messenger,\n { ...transactionParamsWithMaxGas, from: trade.from },\n requestOptions,\n );\n};\n\n/**\n * Submits the approval and resetApproval transactions through the TransactionController.\n * If there is a resetApproval, it will be submitted first.\n * But only the approval's txMetaId will be returned.\n *\n * @param args - The parameters for the submission flow\n *\n * @returns The approvalTxId of the approval transaction\n */\nconst approve = async (args: SubmitStrategyParams) => {\n const {\n quoteResponses: [quoteResponse],\n isBridgeTx,\n } = args;\n const { approval, resetApproval } = quoteResponse;\n if (!approval || !isEvmTxData(approval)) {\n return;\n }\n\n const transactionType = isBridgeTx\n ? TransactionType.bridgeApproval\n : TransactionType.swapApproval;\n\n if (resetApproval) {\n await handleSingleTx({\n ...args,\n transactionType,\n trade: resetApproval,\n });\n }\n\n if (approval) {\n const approvalTxMeta = await handleSingleTx({\n ...args,\n transactionType,\n trade: approval,\n });\n return approvalTxMeta?.id;\n }\n};\n\nexport const handleEvmApprovals = async (args: SubmitStrategyParams) =>\n await args.traceFn(\n getApprovalTraceParams(args.quoteResponses[0], args.isStxEnabled),\n async () => await approve(args),\n );\n\n/**\n * Sequentially submits EVM resetApproval, approval and trade transactions through the TransactionController.\n *\n * @param args - The parameters for the transaction\n * @yields Data for updating the BridgeStatusController\n */\nexport async function* submitEvmHandler(\n args: SubmitStrategyParams<TxData>,\n): AsyncGenerator<SubmitStepResult, void, void> {\n const {\n quoteResponses: [quoteResponse],\n requireApproval,\n isBridgeTx,\n } = args;\n\n // Submit resetApproval and approval transactions if present\n const approvalTxId = await handleEvmApprovals(args);\n\n // Delay after approval\n if (approvalTxId) {\n await handleApprovalDelay(quoteResponse.quote.srcChainId);\n }\n // Hardware-wallet delay first (Ledger second-prompt spacing), then wait for\n // on-chain approval confirmation so swap gas estimation runs after allowance is set.\n await handleMobileHardwareWalletDelay(requireApproval);\n if (requireApproval && approvalTxId) {\n await waitForTxConfirmation(args.messenger, approvalTxId);\n }\n\n // Generate trade actionId for pre-submission history\n const actionId = generateActionId();\n\n // Add pre-submission history keyed by actionId\n // This ensures we have quote data available if transaction fails during submission\n yield {\n type: SubmitStep.AddHistoryItem,\n payload: {\n historyKey: actionId,\n approvalTxId,\n actionId,\n quoteResponse,\n },\n };\n\n const transactionType = isBridgeTx\n ? TransactionType.bridge\n : TransactionType.swap;\n\n const tradeMeta = await handleSingleTx({\n ...args,\n transactionType,\n trade: quoteResponse.trade,\n // TODO figure out if this is needed\n // Pass txFee when gasIncluded is true to use the quote's gas fees\n // instead of re-estimating (which would fail for max native token swaps)\n txFee: quoteResponse.quote.gasIncluded\n ? quoteResponse.quote.feeData.txFee\n : undefined,\n actionId,\n });\n\n // Use the tradeMeta's id as history key\n yield {\n type: SubmitStep.RekeyHistoryItem,\n payload: {\n oldHistoryKey: actionId,\n newHistoryKey: tradeMeta.id,\n tradeMeta,\n },\n };\n\n yield {\n type: SubmitStep.SetTradeMeta,\n payload: {\n tradeMeta,\n },\n };\n}\n"]}
|
|
@@ -17,14 +17,14 @@ const handleTronApproval = async (args) => {
|
|
|
17
17
|
const txMeta = await handleNonEvmTx(args.messenger, quoteResponse.approval, quoteResponse, args.selectedAccount);
|
|
18
18
|
return txMeta.id;
|
|
19
19
|
}
|
|
20
|
-
return
|
|
20
|
+
return;
|
|
21
21
|
});
|
|
22
22
|
if (approvalTxId) {
|
|
23
23
|
// Add delay after approval similar to EVM flow
|
|
24
24
|
await handleApprovalDelay(quoteResponse.quote.srcChainId);
|
|
25
25
|
return approvalTxId;
|
|
26
26
|
}
|
|
27
|
-
return
|
|
27
|
+
return;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
30
|
* Submits Solana, Bitcoin, or Tron transactions to the snap controller
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"non-evm-strategy.js","sourceRoot":"","sources":["../../src/strategy/non-evm-strategy.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAQ5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,KAAK,EAC9B,IAEC,EACD,EAAE;IACF,MAAM,EACJ,cAAc,EAAE,CAAC,aAAa,CAAC,EAC/B,OAAO,GACR,GAAG,IAAI,CAAC;IAET,MAAM,YAAY,GAAG,MAAM,OAAO,CAChC,sBAAsB,CAAC,aAAa,EAAE,KAAK,CAAC,EAC5C,KAAK,IAAI,EAAE;QACT,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,IAAI,CAAC,SAAS,EACd,aAAa,CAAC,QAAQ,EACtB,aAAa,EACb,IAAI,CAAC,eAAe,CACrB,CAAC;YACF,OAAO,MAAM,CAAC,EAAE,CAAC;QACnB,CAAC;QACD,OAAO
|
|
1
|
+
{"version":3,"file":"non-evm-strategy.js","sourceRoot":"","sources":["../../src/strategy/non-evm-strategy.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAQ5D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,KAAK,EAC9B,IAEC,EACD,EAAE;IACF,MAAM,EACJ,cAAc,EAAE,CAAC,aAAa,CAAC,EAC/B,OAAO,GACR,GAAG,IAAI,CAAC;IAET,MAAM,YAAY,GAAG,MAAM,OAAO,CAChC,sBAAsB,CAAC,aAAa,EAAE,KAAK,CAAC,EAC5C,KAAK,IAAI,EAAE;QACT,IAAI,aAAa,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,IAAI,CAAC,SAAS,EACd,aAAa,CAAC,QAAQ,EACtB,aAAa,EACb,IAAI,CAAC,eAAe,CACrB,CAAC;YACF,OAAO,MAAM,CAAC,EAAE,CAAC;QACnB,CAAC;QACD,OAAO;IACT,CAAC,CACF,CAAC;IAEF,IAAI,YAAY,EAAE,CAAC;QACjB,+CAA+C;QAC/C,MAAM,mBAAmB,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1D,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,OAAO;AACT,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,mBAAmB,CACxC,IAEC;IAED,MAAM,EACJ,cAAc,EAAE,CAAC,aAAa,CAAC,EAC/B,UAAU,GACX,GAAG,IAAI,CAAC;IAET,MAAM,YAAY,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAEpD,oFAAoF;IAEpF,MAAM,SAAS,GAAG,MAAM,cAAc,CACpC,IAAI,CAAC,SAAS,EACd,aAAa,CAAC,KAAK,EACnB,aAAa,EACb,IAAI,CAAC,eAAe,CACrB,CAAC;IAEF,MAAM;QACJ,IAAI,EAAE,UAAU,CAAC,YAAY;QAC7B,OAAO,EAAE,EAAE,SAAS,EAAE;KACvB,CAAC;IAEF,MAAM;QACJ,IAAI,EAAE,UAAU,CAAC,cAAc;QAC/B,OAAO,EAAE;YACP,UAAU,EAAE,SAAS,CAAC,EAAE;YACxB,YAAY;YACZ,YAAY,EAAE;gBACZ,EAAE,EAAE,SAAS,CAAC,EAAE;gBAChB,IAAI,EAAE,SAAS,CAAC,IAAI;aACrB;YACD,aAAa;SACd;KACF,CAAC;IAEF,MAAM;QACJ,IAAI,EAAE,UAAU,CAAC,YAAY;QAC7B,OAAO,EAAE;YACP,UAAU,EAAE,SAAS,CAAC,EAAE;SACzB;KACF,CAAC;IAEF,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAClE,MAAM;YACJ,IAAI,EAAE,UAAU,CAAC,qBAAqB;YACtC,OAAO,EAAE;gBACP,UAAU,EAAE,SAAS,CAAC,EAAE;aACzB;SACF,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport { isTronChainId } from '@metamask/bridge-controller';\nimport type {\n BitcoinTradeData,\n StellarTradeData,\n TronTradeData,\n TxData,\n} from '@metamask/bridge-controller';\n\nimport { handleNonEvmTx } from '../utils/snaps.js';\nimport { getApprovalTraceParams } from '../utils/trace.js';\nimport { handleApprovalDelay } from '../utils/transaction.js';\nimport { SubmitStep } from './types.js';\nimport type { SubmitStrategyParams, SubmitStepResult } from './types.js';\n\n/**\n * Submits the approval transaction for a non-EVM transaction if present\n *\n * @param args - The parameters for the transaction\n * @returns The tx id of the approval transaction\n */\nconst handleTronApproval = async (\n args: SubmitStrategyParams<\n TronTradeData | BitcoinTradeData | StellarTradeData | string | TxData\n >,\n) => {\n const {\n quoteResponses: [quoteResponse],\n traceFn,\n } = args;\n\n const approvalTxId = await traceFn(\n getApprovalTraceParams(quoteResponse, false),\n async () => {\n if (quoteResponse.approval) {\n const txMeta = await handleNonEvmTx(\n args.messenger,\n quoteResponse.approval,\n quoteResponse,\n args.selectedAccount,\n );\n return txMeta.id;\n }\n return;\n },\n );\n\n if (approvalTxId) {\n // Add delay after approval similar to EVM flow\n await handleApprovalDelay(quoteResponse.quote.srcChainId);\n return approvalTxId;\n }\n return;\n};\n\n/**\n * Submits Solana, Bitcoin, or Tron transactions to the snap controller\n *\n * @param args - The parameters for the transaction\n * @param args.quoteResponse - The quote response\n * @param args.messenger - The messenger\n * @param args.selectedAccount - The selected account\n * @param args.traceFn - The trace function\n * @param args.isBridgeTx - Whether the transaction is a bridge transaction\n * @yields The approvalTxId and tradeMeta for the non-EVM transaction\n */\nexport async function* submitNonEvmHandler(\n args: SubmitStrategyParams<\n BitcoinTradeData | StellarTradeData | TronTradeData | string | TxData\n >,\n): AsyncGenerator<SubmitStepResult, void, void> {\n const {\n quoteResponses: [quoteResponse],\n isBridgeTx,\n } = args;\n\n const approvalTxId = await handleTronApproval(args);\n\n // TODO bridge-status should update history with actionId if approvalTxId is present\n\n const tradeMeta = await handleNonEvmTx(\n args.messenger,\n quoteResponse.trade,\n quoteResponse,\n args.selectedAccount,\n );\n\n yield {\n type: SubmitStep.SetTradeMeta,\n payload: { tradeMeta },\n };\n\n yield {\n type: SubmitStep.AddHistoryItem,\n payload: {\n historyKey: tradeMeta.id,\n approvalTxId,\n bridgeTxMeta: {\n id: tradeMeta.id,\n hash: tradeMeta.hash,\n },\n quoteResponse,\n },\n };\n\n yield {\n type: SubmitStep.StartPolling,\n payload: {\n historyKey: tradeMeta.id,\n },\n };\n\n if (!isTronChainId(quoteResponse.quote.srcChainId) && !isBridgeTx) {\n yield {\n type: SubmitStep.PublishCompletedEvent,\n payload: {\n historyKey: tradeMeta.id,\n },\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-status.js","sourceRoot":"","sources":["../../src/utils/bridge-status.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getClientHeaders,\n isNonEvmChainId,\n StatusTypes,\n} from '@metamask/bridge-controller';\nimport type { QuoteResponseV1 } from '@metamask/bridge-controller';\nimport type { Provider } from '@metamask/network-controller';\nimport { StructError } from '@metamask/superstruct';\n\nimport { REFRESH_INTERVAL_MS } from '../constants.js';\nimport { QuoteStatusManager } from '../quote-status-manager/quotes-status-manager.js';\nimport type {\n StatusResponse,\n StatusRequestWithSrcTxHash,\n StatusRequestDto,\n FetchFunction,\n BridgeHistoryItem,\n StatusRequest,\n BridgeStatusControllerMessenger,\n} from '../types.js';\nimport { isHistoryItemTooOld } from './history.js';\nimport { getNetworkClientByChainId } from './network.js';\nimport { validateBridgeStatusResponse } from './validators.js';\n\nexport const getBridgeStatusUrl = (bridgeApiBaseUrl: string): string =>\n `${bridgeApiBaseUrl}/getTxStatus`;\n\nexport const getStatusRequestDto = (\n statusRequest: StatusRequestWithSrcTxHash,\n): StatusRequestDto => {\n const { quote, ...statusRequestNoQuote } = statusRequest;\n\n const statusRequestNoQuoteFormatted = Object.fromEntries(\n Object.entries(statusRequestNoQuote).map(([key, value]) => [\n key,\n value.toString(),\n ]),\n ) as unknown as Omit<StatusRequestDto, 'requestId'>;\n\n const requestId: { requestId: string } | Record<string, never> =\n quote?.requestId ? { requestId: quote.requestId } : {};\n\n return {\n ...statusRequestNoQuoteFormatted,\n ...requestId,\n };\n};\n\nexport const fetchBridgeQuoteStatus = async (\n quoteStatusManager: QuoteStatusManager,\n quoteId: string,\n): Promise<{ status: StatusResponse; validationFailures: string[] } | null> => {\n const response = await quoteStatusManager.getStatus(quoteId);\n\n const status = response?.response?.submittedTx;\n\n if (!status) {\n return null;\n }\n\n return {\n status,\n validationFailures: response.error?.details?.validationFailures ?? [],\n };\n};\n\nexport const fetchBridgeTxStatus = async (\n statusRequest: StatusRequestWithSrcTxHash,\n clientId: string,\n jwt: string | undefined,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n): Promise<{ status: StatusResponse; validationFailures: string[] }> => {\n const statusRequestDto = getStatusRequestDto(statusRequest);\n const params = new URLSearchParams(statusRequestDto);\n\n // Fetch\n const url = `${getBridgeStatusUrl(bridgeApiBaseUrl)}?${params.toString()}`;\n\n const rawTxStatus: unknown = await fetchFn(url, {\n headers: getClientHeaders({ clientId, jwt }),\n });\n\n const validationFailures: string[] = [];\n\n try {\n validateBridgeStatusResponse(rawTxStatus);\n } catch (error) {\n // Build validation failure event properties\n if (error instanceof StructError) {\n error.failures().forEach(({ path }) => {\n const aggregatorId =\n (rawTxStatus as StatusResponse)?.bridge ??\n (statusRequest.bridge || statusRequest.bridgeId) ??\n ('unknown' as string);\n const pathString = path?.join('.') || 'unknown';\n validationFailures.push([aggregatorId, pathString].join('|'));\n });\n }\n }\n return {\n status: rawTxStatus as StatusResponse,\n validationFailures,\n };\n};\n\nexport const getStatusRequestWithSrcTxHash = (\n quote: QuoteResponseV1['quote'],\n srcTxHash: string,\n): StatusRequestWithSrcTxHash => {\n const { bridgeId, bridges, srcChainId, destChainId, refuel } = quote;\n return {\n bridgeId,\n srcTxHash,\n bridge: bridges[0],\n srcChainId,\n destChainId,\n quote,\n refuel: Boolean(refuel),\n };\n};\n\nexport const shouldSkipFetchDueToFetchFailures = (\n attempts?: BridgeHistoryItem['attempts'],\n): boolean => {\n // If there's an attempt, it means we've failed at least once,\n // so we need to check if we need to wait longer due to exponential backoff\n if (attempts) {\n // Calculate exponential backoff delay: base interval * 2^(attempts-1)\n const backoffDelay =\n REFRESH_INTERVAL_MS * Math.pow(2, attempts.counter - 1);\n const timeSinceLastAttempt = Date.now() - attempts.lastAttemptTime;\n\n if (timeSinceLastAttempt < backoffDelay) {\n // Not enough time has passed, skip this fetch\n return true;\n }\n }\n return false;\n};\n\n/*\n * Checks if a pending history item is older than 2 days and does not have a valid tx hash\n *\n * @param messenger - The messenger to use to get the transaction meta by hash or id\n * @param historyItem - The history item to check\n *\n * @returns true if the src tx hash is valid or we should still wait for it, false otherwise\n */\nexport const shouldWaitForFinalBridgeStatus = async (\n messenger: BridgeStatusControllerMessenger,\n historyItem: BridgeHistoryItem,\n): Promise<boolean> => {\n // Keep waiting for status if the history is not pending or is not old enough yet\n if (\n !(\n isHistoryItemTooOld(messenger, historyItem) &&\n [StatusTypes.PENDING, StatusTypes.UNKNOWN].includes(\n historyItem.status.status,\n )\n )\n ) {\n return true;\n }\n\n if (isNonEvmChainId(historyItem.quote.srcChainId)) {\n return false;\n }\n\n let provider: Provider;\n try {\n provider = getNetworkClientByChainId(\n messenger,\n historyItem.quote.srcChainId,\n );\n } catch {\n // This happens when the network is disabled while the tx is pending\n return true;\n }\n\n if (!historyItem.status.srcChain.txHash) {\n return false;\n }\n\n // Otherwise check if the tx has been mined on chain\n return provider\n .request({\n method: 'eth_getTransactionReceipt',\n params: [historyItem.status.srcChain.txHash],\n })\n .then((txReceipt) => {\n if (txReceipt) {\n return true;\n }\n return false;\n })\n .catch(() => {\n return false;\n });\n};\n\n/**\n * @deprecated Use getStatusRequestWithSrcTxHash instead\n * @param quoteResponse - The quote response to get the status request parameters from\n * @returns The status request parameters\n */\nexport const getStatusRequestParams = (\n quoteResponse: QuoteResponseV1,\n): StatusRequest => {\n return {\n bridgeId: quoteResponse.quote.bridgeId,\n bridge: quoteResponse.quote.bridges[0],\n srcChainId: quoteResponse.quote.srcChainId,\n destChainId: quoteResponse.quote.destChainId,\n quote: quoteResponse.quote,\n refuel: Boolean(quoteResponse.quote.refuel),\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"bridge-status.js","sourceRoot":"","sources":["../../src/utils/bridge-status.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAWtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,gBAAwB,EAAU,EAAE,CACrE,GAAG,gBAAgB,cAAc,CAAC;AAEpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,aAAyC,EACvB,EAAE;IACpB,MAAM,EAAE,KAAK,EAAE,GAAG,oBAAoB,EAAE,GAAG,aAAa,CAAC;IAEzD,MAAM,6BAA6B,GAAG,MAAM,CAAC,WAAW,CACtD,MAAM,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACzD,GAAG;QACH,KAAK,CAAC,QAAQ,EAAE;KACjB,CAAC,CAC+C,CAAC;IAEpD,MAAM,SAAS,GACb,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzD,OAAO;QACL,GAAG,6BAA6B;QAChC,GAAG,SAAS;KACb,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,kBAAsC,EACtC,OAAe,EAC2D,EAAE;IAC5E,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAE7D,MAAM,MAAM,GAAG,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC;IAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,MAAM;QACN,kBAAkB,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,kBAAkB,IAAI,EAAE;KACtE,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,aAAyC,EACzC,QAAgB,EAChB,GAAuB,EACvB,OAAsB,EACtB,gBAAwB,EAC2C,EAAE;IACrE,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,gBAAgB,CAAC,CAAC;IAErD,QAAQ;IACR,MAAM,GAAG,GAAG,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IAE3E,MAAM,WAAW,GAAY,MAAM,OAAO,CAAC,GAAG,EAAE;QAC9C,OAAO,EAAE,gBAAgB,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;KAC7C,CAAC,CAAC;IAEH,MAAM,kBAAkB,GAAa,EAAE,CAAC;IAExC,IAAI,CAAC;QACH,4BAA4B,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4CAA4C;QAC5C,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,KAAK,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;gBACpC,MAAM,YAAY,GACf,WAA8B,EAAE,MAAM;oBACvC,CAAC,aAAa,CAAC,MAAM,IAAI,aAAa,CAAC,QAAQ,CAAC;oBAChD,SAAS,CAAC;gBACZ,MAAM,UAAU,GAAG,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;gBAChD,kBAAkB,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO;QACL,MAAM,EAAE,WAA6B;QACrC,kBAAkB;KACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,KAA+B,EAC/B,SAAiB,EACW,EAAE;IAC9B,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACrE,OAAO;QACL,QAAQ;QACR,SAAS;QACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAClB,UAAU;QACV,WAAW;QACX,KAAK;QACL,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;KACxB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAC/C,QAAwC,EAC/B,EAAE;IACX,8DAA8D;IAC9D,2EAA2E;IAC3E,IAAI,QAAQ,EAAE,CAAC;QACb,sEAAsE;QACtE,MAAM,YAAY,GAChB,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;QAC1D,MAAM,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAEnE,IAAI,oBAAoB,GAAG,YAAY,EAAE,CAAC;YACxC,8CAA8C;YAC9C,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,KAAK,EACjD,SAA0C,EAC1C,WAA8B,EACZ,EAAE;IACpB,iFAAiF;IACjF,IACE,CAAC,CACC,mBAAmB,CAAC,SAAS,EAAE,WAAW,CAAC;QAC3C,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,QAAQ,CACjD,WAAW,CAAC,MAAM,CAAC,MAAM,CAC1B,CACF,EACD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,eAAe,CAAC,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QAClD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,yBAAyB,CAClC,SAAS,EACT,WAAW,CAAC,KAAK,CAAC,UAAU,CAC7B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,oDAAoD;IACpD,OAAO,QAAQ;SACZ,OAAO,CAAC;QACP,MAAM,EAAE,2BAA2B;QACnC,MAAM,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;KAC7C,CAAC;SACD,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;QAClB,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;SACD,KAAK,CAAC,GAAG,EAAE;QACV,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,aAA8B,EACf,EAAE;IACjB,OAAO;QACL,QAAQ,EAAE,aAAa,CAAC,KAAK,CAAC,QAAQ;QACtC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,UAAU,EAAE,aAAa,CAAC,KAAK,CAAC,UAAU;QAC1C,WAAW,EAAE,aAAa,CAAC,KAAK,CAAC,WAAW;QAC5C,KAAK,EAAE,aAAa,CAAC,KAAK;QAC1B,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;KAC5C,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n getClientHeaders,\n isNonEvmChainId,\n StatusTypes,\n} from '@metamask/bridge-controller';\nimport type { QuoteResponseV1 } from '@metamask/bridge-controller';\nimport type { Provider } from '@metamask/network-controller';\nimport { StructError } from '@metamask/superstruct';\n\nimport { REFRESH_INTERVAL_MS } from '../constants.js';\nimport { QuoteStatusManager } from '../quote-status-manager/quotes-status-manager.js';\nimport type {\n StatusResponse,\n StatusRequestWithSrcTxHash,\n StatusRequestDto,\n FetchFunction,\n BridgeHistoryItem,\n StatusRequest,\n BridgeStatusControllerMessenger,\n} from '../types.js';\nimport { isHistoryItemTooOld } from './history.js';\nimport { getNetworkClientByChainId } from './network.js';\nimport { validateBridgeStatusResponse } from './validators.js';\n\nexport const getBridgeStatusUrl = (bridgeApiBaseUrl: string): string =>\n `${bridgeApiBaseUrl}/getTxStatus`;\n\nexport const getStatusRequestDto = (\n statusRequest: StatusRequestWithSrcTxHash,\n): StatusRequestDto => {\n const { quote, ...statusRequestNoQuote } = statusRequest;\n\n const statusRequestNoQuoteFormatted = Object.fromEntries(\n Object.entries(statusRequestNoQuote).map(([key, value]) => [\n key,\n value.toString(),\n ]),\n ) as unknown as Omit<StatusRequestDto, 'requestId'>;\n\n const requestId: { requestId: string } | Record<string, never> =\n quote?.requestId ? { requestId: quote.requestId } : {};\n\n return {\n ...statusRequestNoQuoteFormatted,\n ...requestId,\n };\n};\n\nexport const fetchBridgeQuoteStatus = async (\n quoteStatusManager: QuoteStatusManager,\n quoteId: string,\n): Promise<{ status: StatusResponse; validationFailures: string[] } | null> => {\n const response = await quoteStatusManager.getStatus(quoteId);\n\n const status = response?.response?.submittedTx;\n\n if (!status) {\n return null;\n }\n\n return {\n status,\n validationFailures: response.error?.details?.validationFailures ?? [],\n };\n};\n\nexport const fetchBridgeTxStatus = async (\n statusRequest: StatusRequestWithSrcTxHash,\n clientId: string,\n jwt: string | undefined,\n fetchFn: FetchFunction,\n bridgeApiBaseUrl: string,\n): Promise<{ status: StatusResponse; validationFailures: string[] }> => {\n const statusRequestDto = getStatusRequestDto(statusRequest);\n const params = new URLSearchParams(statusRequestDto);\n\n // Fetch\n const url = `${getBridgeStatusUrl(bridgeApiBaseUrl)}?${params.toString()}`;\n\n const rawTxStatus: unknown = await fetchFn(url, {\n headers: getClientHeaders({ clientId, jwt }),\n });\n\n const validationFailures: string[] = [];\n\n try {\n validateBridgeStatusResponse(rawTxStatus);\n } catch (error) {\n // Build validation failure event properties\n if (error instanceof StructError) {\n error.failures().forEach(({ path }) => {\n const aggregatorId =\n (rawTxStatus as StatusResponse)?.bridge ??\n (statusRequest.bridge || statusRequest.bridgeId) ??\n 'unknown';\n const pathString = path?.join('.') || 'unknown';\n validationFailures.push([aggregatorId, pathString].join('|'));\n });\n }\n }\n return {\n status: rawTxStatus as StatusResponse,\n validationFailures,\n };\n};\n\nexport const getStatusRequestWithSrcTxHash = (\n quote: QuoteResponseV1['quote'],\n srcTxHash: string,\n): StatusRequestWithSrcTxHash => {\n const { bridgeId, bridges, srcChainId, destChainId, refuel } = quote;\n return {\n bridgeId,\n srcTxHash,\n bridge: bridges[0],\n srcChainId,\n destChainId,\n quote,\n refuel: Boolean(refuel),\n };\n};\n\nexport const shouldSkipFetchDueToFetchFailures = (\n attempts?: BridgeHistoryItem['attempts'],\n): boolean => {\n // If there's an attempt, it means we've failed at least once,\n // so we need to check if we need to wait longer due to exponential backoff\n if (attempts) {\n // Calculate exponential backoff delay: base interval * 2^(attempts-1)\n const backoffDelay =\n REFRESH_INTERVAL_MS * Math.pow(2, attempts.counter - 1);\n const timeSinceLastAttempt = Date.now() - attempts.lastAttemptTime;\n\n if (timeSinceLastAttempt < backoffDelay) {\n // Not enough time has passed, skip this fetch\n return true;\n }\n }\n return false;\n};\n\n/*\n * Checks if a pending history item is older than 2 days and does not have a valid tx hash\n *\n * @param messenger - The messenger to use to get the transaction meta by hash or id\n * @param historyItem - The history item to check\n *\n * @returns true if the src tx hash is valid or we should still wait for it, false otherwise\n */\nexport const shouldWaitForFinalBridgeStatus = async (\n messenger: BridgeStatusControllerMessenger,\n historyItem: BridgeHistoryItem,\n): Promise<boolean> => {\n // Keep waiting for status if the history is not pending or is not old enough yet\n if (\n !(\n isHistoryItemTooOld(messenger, historyItem) &&\n [StatusTypes.PENDING, StatusTypes.UNKNOWN].includes(\n historyItem.status.status,\n )\n )\n ) {\n return true;\n }\n\n if (isNonEvmChainId(historyItem.quote.srcChainId)) {\n return false;\n }\n\n let provider: Provider;\n try {\n provider = getNetworkClientByChainId(\n messenger,\n historyItem.quote.srcChainId,\n );\n } catch {\n // This happens when the network is disabled while the tx is pending\n return true;\n }\n\n if (!historyItem.status.srcChain.txHash) {\n return false;\n }\n\n // Otherwise check if the tx has been mined on chain\n return provider\n .request({\n method: 'eth_getTransactionReceipt',\n params: [historyItem.status.srcChain.txHash],\n })\n .then((txReceipt) => {\n if (txReceipt) {\n return true;\n }\n return false;\n })\n .catch(() => {\n return false;\n });\n};\n\n/**\n * @deprecated Use getStatusRequestWithSrcTxHash instead\n * @param quoteResponse - The quote response to get the status request parameters from\n * @returns The status request parameters\n */\nexport const getStatusRequestParams = (\n quoteResponse: QuoteResponseV1,\n): StatusRequest => {\n return {\n bridgeId: quoteResponse.quote.bridgeId,\n bridge: quoteResponse.quote.bridges[0],\n srcChainId: quoteResponse.quote.srcChainId,\n destChainId: quoteResponse.quote.destChainId,\n quote: quoteResponse.quote,\n refuel: Boolean(quoteResponse.quote.refuel),\n };\n};\n"]}
|
|
@@ -45,7 +45,7 @@ export const getGasFeeEstimates = async (messenger, args) => {
|
|
|
45
45
|
if (estimates?.type === GasFeeEstimateType.FeeMarket) {
|
|
46
46
|
return estimates[BRIDGE_PREFERRED_GAS_ESTIMATE];
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return;
|
|
49
49
|
};
|
|
50
50
|
export const getTransactions = (messenger) => {
|
|
51
51
|
return messenger.call('TransactionController:getState').transactions ?? [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/utils/transaction.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport {\n ChainId,\n formatChainIdToHex,\n BRIDGE_PREFERRED_GAS_ESTIMATE,\n isEvmTxData,\n FeeType,\n BatchSellTransactionType,\n} from '@metamask/bridge-controller';\nimport type {\n BatchSellTradesResponse,\n QuoteMetadata,\n QuoteResponseV1,\n SimulatedGasFeeLimits,\n Trade,\n TxData,\n TxFeeGasLimits,\n} from '@metamask/bridge-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport {\n GasFeeEstimateType,\n TransactionStatus,\n TransactionType,\n} from '@metamask/transaction-controller';\nimport type {\n IsAtomicBatchSupportedResultEntry,\n TransactionController,\n TransactionMeta,\n TransactionBatchSingleRequest,\n BatchTransactionParams,\n} from '@metamask/transaction-controller';\nimport { createProjectLogger, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { APPROVAL_DELAY_MS } from '../constants.js';\nimport type { BridgeStatusControllerMessenger } from '../types.js';\nimport type { QuoteAndTxMetadata } from '../types.js';\nimport { getAccountByAddress } from './accounts.js';\nimport { getNetworkClientIdByChainId } from './network.js';\n\nexport const isApprovalTx = (type: TransactionType) =>\n type === TransactionType.bridgeApproval ||\n type === TransactionType.swapApproval;\nexport const isTradeTx = (type: TransactionType) =>\n type === TransactionType.bridge || type === TransactionType.swap;\nexport const isCrossChainTx = (type: TransactionType) =>\n isTradeTx(type) || isApprovalTx(type);\n\n/**\n * For 7702 delegated transactions, check for delegation-specific fields\n * These transactions might have authorizationList or delegationAddress\n *\n * @param tx - The transaction meta\n * @returns Whether the transaction is a 7702 transaction\n */\nexport const is7702Tx = (tx: TransactionMeta) => {\n return (\n (Array.isArray(tx.txParams.authorizationList) &&\n tx.txParams.authorizationList.length > 0) ||\n Boolean(tx.delegationAddress)\n );\n};\n\nexport const shouldDisable7702 = (\n gasIncluded7702: boolean = false,\n gasIncluded: boolean = false,\n isDelegatedAccount: boolean = false,\n): boolean => {\n // Enable 7702 batching when the quote includes gasless 7702 support\n if (gasIncluded7702) {\n return false;\n }\n // Enable batching when the account is already delegated (to avoid the in-flight transaction limit for delegated accounts)\n // For gasless transactions with STX/sendBundle we keep disabling 7702\n if (isDelegatedAccount && !gasIncluded) {\n return false;\n }\n /**\n * Explicitly return default instead of falsy value (see TransactionBatchRequest.disable7702)\n */\n return true;\n};\n\nexport const hasNestedSwapTransactions = (txMeta: TransactionMeta) => {\n return Boolean(\n txMeta?.nestedTransactions?.some((tx) => tx.type === TransactionType.swap),\n );\n};\n\nexport const getGasFeeEstimates = async (\n messenger: BridgeStatusControllerMessenger,\n args: Parameters<TransactionController['estimateGasFee']>[0],\n) => {\n const { estimates } = await messenger.call(\n 'TransactionController:estimateGasFee',\n args,\n );\n\n if (estimates?.type === GasFeeEstimateType.FeeMarket) {\n return estimates[BRIDGE_PREFERRED_GAS_ESTIMATE];\n }\n\n return undefined;\n};\n\nexport const getTransactions = (messenger: BridgeStatusControllerMessenger) => {\n return messenger.call('TransactionController:getState').transactions ?? [];\n};\n\nexport const getTransactionMetaById = (\n messenger: BridgeStatusControllerMessenger,\n txId?: string,\n) => {\n return getTransactions(messenger).find(\n (tx: TransactionMeta) => tx.id === txId,\n );\n};\n\nexport const getTransactionMetaByHash = (\n messenger: BridgeStatusControllerMessenger,\n txHash?: string,\n) => {\n return getTransactions(messenger).find(\n (tx: TransactionMeta) => tx.hash?.toLowerCase() === txHash?.toLowerCase(),\n );\n};\n\nexport const updateTransaction = (\n messenger: BridgeStatusControllerMessenger,\n txMeta: TransactionMeta,\n txMetaUpdates: Partial<TransactionMeta>,\n note: string,\n) => {\n return messenger.call(\n 'TransactionController:updateTransaction',\n { ...txMeta, ...txMetaUpdates },\n note,\n );\n};\n\nexport const checkIsDelegatedAccount = async (\n messenger: BridgeStatusControllerMessenger,\n fromAddress: Hex,\n chainIds: Hex[],\n): Promise<boolean> => {\n try {\n const atomicBatchSupport = await messenger.call(\n 'TransactionController:isAtomicBatchSupported',\n {\n address: fromAddress,\n chainIds,\n },\n );\n return atomicBatchSupport.some(\n (entry: IsAtomicBatchSupportedResultEntry) =>\n entry.isSupported && entry.delegationAddress,\n );\n } catch {\n return false;\n }\n};\n\nconst waitForHashAndReturnFinalTxMeta = async (\n messenger: BridgeStatusControllerMessenger,\n hashPromise?: Awaited<\n ReturnType<TransactionController['addTransaction']>\n >['result'],\n): Promise<TransactionMeta> => {\n const txHash = await hashPromise;\n const finalTransactionMeta = getTransactionMetaByHash(messenger, txHash);\n if (!finalTransactionMeta) {\n throw new Error(\n 'Failed to submit cross-chain swap tx: txMeta for txHash was not found',\n );\n }\n return finalTransactionMeta;\n};\n\nexport const addTransaction = async (\n messenger: BridgeStatusControllerMessenger,\n ...args: Parameters<TransactionController['addTransaction']>\n) => {\n const { result } = await messenger.call(\n 'TransactionController:addTransaction',\n ...args,\n );\n return await waitForHashAndReturnFinalTxMeta(messenger, result);\n};\n\nexport const generateActionId = () => (Date.now() + Math.random()).toString();\n\n/**\n * Adds a synthetic transaction to the TransactionController to display pending intent orders in the UI\n *\n * @param messenger - The messenger to use for the transaction\n * @param args - The arguments for the transaction\n * @returns The transaction meta\n */\nexport const addSyntheticTransaction = async (\n messenger: BridgeStatusControllerMessenger,\n ...args: Parameters<TransactionController['addTransaction']>\n) => {\n const { transactionMeta } = await messenger.call(\n 'TransactionController:addTransaction',\n args[0],\n {\n origin: 'metamask',\n actionId: generateActionId(),\n isStateOnly: true,\n isInternal: true,\n ...args[1],\n },\n );\n return transactionMeta;\n};\n\nexport const handleApprovalDelay = async (\n srcChainId: QuoteResponseV1['quote']['srcChainId'],\n) => {\n if ([ChainId.LINEA, ChainId.BASE].includes(srcChainId)) {\n const debugLog = createProjectLogger('bridge');\n debugLog(\n 'Delaying submitting bridge tx to make Linea and Base confirmation more likely',\n );\n const waitPromise = new Promise((resolve) =>\n setTimeout(resolve, APPROVAL_DELAY_MS),\n );\n await waitPromise;\n }\n};\n\n/**\n * Adds a delay for hardware wallet transactions on mobile to fix an issue\n * where the Ledger does not get prompted for the 2nd approval.\n * Extension does not have this issue.\n *\n * @param requireApproval - Whether the delay should be applied\n */\nexport const handleMobileHardwareWalletDelay = async (\n requireApproval: boolean,\n) => {\n if (requireApproval) {\n const mobileHardwareWalletDelay = new Promise((resolve) =>\n setTimeout(resolve, 1000),\n );\n await mobileHardwareWalletDelay;\n }\n};\n\n/**\n * Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.\n *\n * @deprecated use addTransaction util\n * @param messenger - the BridgeStatusControllerMessenger\n * @param txId - the transaction ID\n * @param options - the options for the timeout and poll\n * @param options.timeoutMs - the timeout in milliseconds\n * @param options.pollMs - the poll interval in milliseconds\n * @returns the transaction meta\n */\nexport const waitForTxConfirmation = async (\n messenger: BridgeStatusControllerMessenger,\n txId: string,\n {\n timeoutMs = 5 * 60_000,\n pollMs = 3_000,\n }: { timeoutMs?: number; pollMs?: number } = {},\n): Promise<TransactionMeta> => {\n const start = Date.now();\n while (true) {\n const meta = getTransactionMetaById(messenger, txId);\n\n if (meta) {\n if (meta.status === TransactionStatus.confirmed) {\n return meta;\n }\n if (\n meta.status === TransactionStatus.failed ||\n meta.status === TransactionStatus.dropped ||\n meta.status === TransactionStatus.rejected\n ) {\n throw new Error('Approval transaction did not confirm');\n }\n }\n\n if (Date.now() - start > timeoutMs) {\n throw new Error('Timed out waiting for approval confirmation');\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollMs));\n }\n};\n\nexport const toQuoteAndTxMetadata = ({\n quoteResponse,\n isBridgeTx,\n}: {\n quoteResponse: QuoteResponseV1<Trade, Trade> & QuoteMetadata;\n isBridgeTx: boolean;\n}): Omit<QuoteAndTxMetadata, 'txMeta'>[] => {\n const tradeData: QuoteAndTxMetadata[] = [];\n\n const approvalTxType = isBridgeTx\n ? TransactionType.bridgeApproval\n : TransactionType.swapApproval;\n\n if (quoteResponse.resetApproval) {\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.resetApproval,\n type: approvalTxType,\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n }\n if (quoteResponse.approval && isEvmTxData(quoteResponse.approval)) {\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.approval,\n type: approvalTxType,\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n }\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.trade as TxData,\n type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,\n assetsFiatValues: {\n sending: quoteResponse.sentAmount?.valueInCurrency?.toString(),\n receiving: quoteResponse.toTokenAmount?.valueInCurrency?.toString(),\n },\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n\n return tradeData;\n};\n\n/**\n * Build the trade+quote metadata array for the batch sell transaction\n * This ties together the quote, the tx params and the txMeta after submission\n *\n * @param options - The options for the batch sell transaction\n * @param options.quoteResponses - The quote responses for the batch sell transaction\n * @param options.batchSellTrades - The batch sell trades for the batch sell transaction\n * @returns The trade+quote metadata array for the batch sell transaction\n */\nexport const toQuoteAndTxMetadataBatch = ({\n quoteResponses,\n batchSellTrades,\n}: {\n quoteResponses: (QuoteResponseV1<TxData, TxData> & QuoteMetadata)[];\n batchSellTrades: BatchSellTradesResponse;\n}): Omit<QuoteAndTxMetadata, 'txMeta'>[] => {\n const tradeData: QuoteAndTxMetadata[] = [];\n\n const {\n transactions,\n gasIncluded7702,\n gasIncluded,\n gasSponsored = false,\n } = batchSellTrades;\n\n for (const transaction of transactions) {\n const { type, maxFeePerGas, maxPriorityFeePerGas, ...tx } = transaction;\n // Match the trade or approval tx data with the quote response\n const matchingQuoteResponse =\n quoteResponses.find(\n ({ approval, trade }) =>\n trade?.data.toLowerCase() === tx.data.toLowerCase() ||\n approval?.data.toLowerCase() === tx.data.toLowerCase(),\n ) ?? quoteResponses[0];\n\n // Include gasIncluded and gasIncluded7702 from the gasless batch\n const normalizedQuote = {\n ...matchingQuoteResponse,\n quote: {\n ...matchingQuoteResponse.quote,\n gasIncluded,\n gasIncluded7702,\n gasSponsored,\n },\n };\n\n const commonTradeData = {\n tx,\n quoteResponse: normalizedQuote,\n txFee: { maxFeePerGas, maxPriorityFeePerGas },\n };\n\n if (type === BatchSellTransactionType.TRADE) {\n tradeData.push({\n ...commonTradeData,\n type: TransactionType.swap,\n assetsFiatValues: {\n sending:\n matchingQuoteResponse.sentAmount?.valueInCurrency?.toString(),\n receiving:\n matchingQuoteResponse.toTokenAmount?.valueInCurrency?.toString(),\n },\n });\n } else {\n tradeData.push({\n ...commonTradeData,\n type:\n type === BatchSellTransactionType.APPROVAL\n ? TransactionType.swapApproval\n : TransactionType.tokenMethodTransfer,\n });\n }\n }\n\n return tradeData;\n};\n\n/**\n * Appends the gas fee estimates for a transaction and normalizes the trade data\n *\n * @param messenger - The messenger for the gas fee estimates\n * @param trade - the trade data to append gas fees to\n * @param trade.chainId - ignored, use chainId instead\n * @param trade.gasLimit - the gas limit to use for the gas fee estimates\n * @param networkClientId - the network client ID to use for the gas fee estimates\n * @param chainId - the chain ID to use for the gas fee estimates\n * @param simulatedGasFeeLimits - either the txFee from the quote or the simulated gas fee limits for the batch sell\n * @returns The gas fee estimates for the transaction\n */\nexport const toTransactionParams = async (\n messenger: BridgeStatusControllerMessenger,\n { chainId: tradeChainId, gasLimit, ...trade }: TxData,\n networkClientId: string,\n chainId: Hex,\n simulatedGasFeeLimits?: SimulatedGasFeeLimits | TxFeeGasLimits,\n): Promise<BatchTransactionParams> => {\n const transactionParams = {\n data: trade.data,\n to: trade.to,\n from: trade.from,\n value: trade.value,\n // Only add gas if it's truthy\n gas: gasLimit ? toHex(gasLimit) : undefined,\n };\n\n // Use bridge-api's provided gas fee estimates\n if (simulatedGasFeeLimits) {\n return {\n ...transactionParams,\n // Sometimes estimates are hex, somethings numeric strings\n maxFeePerGas: isStrictHexString(simulatedGasFeeLimits.maxFeePerGas)\n ? simulatedGasFeeLimits.maxFeePerGas\n : toHex(simulatedGasFeeLimits.maxFeePerGas),\n maxPriorityFeePerGas: isStrictHexString(\n simulatedGasFeeLimits.maxPriorityFeePerGas,\n )\n ? simulatedGasFeeLimits.maxPriorityFeePerGas\n : toHex(simulatedGasFeeLimits.maxPriorityFeePerGas),\n };\n }\n\n // Get transaction's 1559 gas fee estimates\n const gasFeeEstimates = await getGasFeeEstimates(messenger, {\n transactionParams,\n networkClientId,\n chainId,\n });\n\n return {\n ...transactionParams,\n maxFeePerGas: gasFeeEstimates?.maxFeePerGas,\n maxPriorityFeePerGas: gasFeeEstimates?.maxPriorityFeePerGas,\n };\n};\n\nexport const getAddTransactionBatchParams = async ({\n messenger,\n tradeData,\n requireApproval = false,\n isDelegatedAccount,\n ...addTransactionBatchParams\n}: Partial<Parameters<TransactionController['addTransactionBatch']>[0]> & {\n messenger: BridgeStatusControllerMessenger;\n tradeData: QuoteAndTxMetadata[];\n requireApproval?: boolean;\n isDelegatedAccount?: boolean;\n}): Promise<Parameters<TransactionController['addTransactionBatch']>[0]> => {\n const trade = tradeData[0].tx;\n const selectedAccount = getAccountByAddress(messenger, trade.from);\n if (!selectedAccount) {\n throw new Error(\n 'Failed to submit cross-chain swap batch transaction: unknown account in trade data',\n );\n }\n const hexChainId = formatChainIdToHex(trade.chainId);\n const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);\n\n const transactions: TransactionBatchSingleRequest[] = await Promise.all(\n tradeData.map(async ({ tx, txFee, assetsFiatValues, type }) => ({\n params: await toTransactionParams(\n messenger,\n tx,\n networkClientId,\n hexChainId,\n txFee,\n ),\n assetsFiatValues,\n type,\n })),\n );\n\n return {\n networkClientId,\n requireApproval,\n origin: 'metamask',\n from: selectedAccount.address as Hex,\n isInternal: true,\n transactions,\n ...addTransactionBatchParams,\n };\n};\n\nexport const findAllTransactionsInBatch = ({\n messenger,\n batchId,\n tradeData,\n}: {\n messenger: BridgeStatusControllerMessenger;\n batchId: string;\n tradeData: QuoteAndTxMetadata[];\n}): QuoteAndTxMetadata[] => {\n // Filter for transactions with batchId\n const txs = getTransactions(messenger).filter(\n (tx: TransactionMeta) => tx.batchId === batchId,\n );\n\n return tradeData.map((tradeWithMetadata) => {\n const { tx, type } = tradeWithMetadata;\n return {\n ...tradeWithMetadata,\n txMeta: txs.find((txMeta: TransactionMeta) => {\n if (is7702Tx(txMeta)) {\n // For 7702 transactions, we need to match based on transaction type\n // since the data field might be different (batch execute call)\n if (isTradeTx(type) && txMeta.type === TransactionType.batch) {\n return true;\n }\n // Also check if it's an approval transaction for 7702\n if (isApprovalTx(type) && txMeta.txParams.data === tx.data) {\n return true;\n }\n }\n // Default matching logic for non-7702 transactions\n if (txMeta.txParams.data === tx.data) {\n return true;\n }\n return false;\n }),\n };\n });\n};\n\n/**\n * This is a workaround to update the tx type after submission. Batch txs are submitted with\n * the \"batch\" type, but we need to update to swap/bridge for display purposes.\n *\n * @param params - The parameters for the transaction search\n * @param params.messenger - The messenger to use for the transaction\n * @param params.allTradesWithMetadata - The quote, tx data and type for each transaction in the batch\n * @returns A list of transaction metas for each trade in the batch]\n *\n * @example\n * [\n * {...tradeData[0], tradeMeta: TransactionMeta}\n * {...tradeData[1], tradeMeta: TransactionMeta}\n * {...tradeData[2], tradeMeta: TransactionMeta}\n * {...tradeData[3], tradeMeta: TransactionMeta}\n * ]\n */\nexport const updateTransactionsInBatch = ({\n messenger,\n allTradesWithMetadata,\n}: {\n messenger: BridgeStatusControllerMessenger;\n allTradesWithMetadata: QuoteAndTxMetadata[];\n}) => {\n return allTradesWithMetadata.map((tradeWithMetadata) => {\n const { txMeta, type } = tradeWithMetadata;\n\n if (txMeta) {\n // Update the tx type from batch to swap/bridge\n updateTransaction(\n messenger,\n txMeta,\n { type },\n `Update tx type to ${type}`,\n );\n const updatedTx = { ...txMeta, type };\n return { ...tradeWithMetadata, txMeta: updatedTx, type };\n }\n\n return tradeWithMetadata;\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/utils/transaction.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/explicit-function-return-type */\nimport {\n ChainId,\n formatChainIdToHex,\n BRIDGE_PREFERRED_GAS_ESTIMATE,\n isEvmTxData,\n FeeType,\n BatchSellTransactionType,\n} from '@metamask/bridge-controller';\nimport type {\n BatchSellTradesResponse,\n QuoteMetadata,\n QuoteResponseV1,\n SimulatedGasFeeLimits,\n Trade,\n TxData,\n TxFeeGasLimits,\n} from '@metamask/bridge-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport {\n GasFeeEstimateType,\n TransactionStatus,\n TransactionType,\n} from '@metamask/transaction-controller';\nimport type {\n IsAtomicBatchSupportedResultEntry,\n TransactionController,\n TransactionMeta,\n TransactionBatchSingleRequest,\n BatchTransactionParams,\n} from '@metamask/transaction-controller';\nimport { createProjectLogger, isStrictHexString } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport { APPROVAL_DELAY_MS } from '../constants.js';\nimport type { BridgeStatusControllerMessenger } from '../types.js';\nimport type { QuoteAndTxMetadata } from '../types.js';\nimport { getAccountByAddress } from './accounts.js';\nimport { getNetworkClientIdByChainId } from './network.js';\n\nexport const isApprovalTx = (type: TransactionType) =>\n type === TransactionType.bridgeApproval ||\n type === TransactionType.swapApproval;\nexport const isTradeTx = (type: TransactionType) =>\n type === TransactionType.bridge || type === TransactionType.swap;\nexport const isCrossChainTx = (type: TransactionType) =>\n isTradeTx(type) || isApprovalTx(type);\n\n/**\n * For 7702 delegated transactions, check for delegation-specific fields\n * These transactions might have authorizationList or delegationAddress\n *\n * @param tx - The transaction meta\n * @returns Whether the transaction is a 7702 transaction\n */\nexport const is7702Tx = (tx: TransactionMeta) => {\n return (\n (Array.isArray(tx.txParams.authorizationList) &&\n tx.txParams.authorizationList.length > 0) ||\n Boolean(tx.delegationAddress)\n );\n};\n\nexport const shouldDisable7702 = (\n gasIncluded7702: boolean = false,\n gasIncluded: boolean = false,\n isDelegatedAccount: boolean = false,\n): boolean => {\n // Enable 7702 batching when the quote includes gasless 7702 support\n if (gasIncluded7702) {\n return false;\n }\n // Enable batching when the account is already delegated (to avoid the in-flight transaction limit for delegated accounts)\n // For gasless transactions with STX/sendBundle we keep disabling 7702\n if (isDelegatedAccount && !gasIncluded) {\n return false;\n }\n /**\n * Explicitly return default instead of falsy value (see TransactionBatchRequest.disable7702)\n */\n return true;\n};\n\nexport const hasNestedSwapTransactions = (txMeta: TransactionMeta) => {\n return Boolean(\n txMeta?.nestedTransactions?.some((tx) => tx.type === TransactionType.swap),\n );\n};\n\nexport const getGasFeeEstimates = async (\n messenger: BridgeStatusControllerMessenger,\n args: Parameters<TransactionController['estimateGasFee']>[0],\n) => {\n const { estimates } = await messenger.call(\n 'TransactionController:estimateGasFee',\n args,\n );\n\n if (estimates?.type === GasFeeEstimateType.FeeMarket) {\n return estimates[BRIDGE_PREFERRED_GAS_ESTIMATE];\n }\n\n return;\n};\n\nexport const getTransactions = (messenger: BridgeStatusControllerMessenger) => {\n return messenger.call('TransactionController:getState').transactions ?? [];\n};\n\nexport const getTransactionMetaById = (\n messenger: BridgeStatusControllerMessenger,\n txId?: string,\n) => {\n return getTransactions(messenger).find(\n (tx: TransactionMeta) => tx.id === txId,\n );\n};\n\nexport const getTransactionMetaByHash = (\n messenger: BridgeStatusControllerMessenger,\n txHash?: string,\n) => {\n return getTransactions(messenger).find(\n (tx: TransactionMeta) => tx.hash?.toLowerCase() === txHash?.toLowerCase(),\n );\n};\n\nexport const updateTransaction = (\n messenger: BridgeStatusControllerMessenger,\n txMeta: TransactionMeta,\n txMetaUpdates: Partial<TransactionMeta>,\n note: string,\n) => {\n return messenger.call(\n 'TransactionController:updateTransaction',\n { ...txMeta, ...txMetaUpdates },\n note,\n );\n};\n\nexport const checkIsDelegatedAccount = async (\n messenger: BridgeStatusControllerMessenger,\n fromAddress: Hex,\n chainIds: Hex[],\n): Promise<boolean> => {\n try {\n const atomicBatchSupport = await messenger.call(\n 'TransactionController:isAtomicBatchSupported',\n {\n address: fromAddress,\n chainIds,\n },\n );\n return atomicBatchSupport.some(\n (entry: IsAtomicBatchSupportedResultEntry) =>\n entry.isSupported && entry.delegationAddress,\n );\n } catch {\n return false;\n }\n};\n\nconst waitForHashAndReturnFinalTxMeta = async (\n messenger: BridgeStatusControllerMessenger,\n hashPromise?: Awaited<\n ReturnType<TransactionController['addTransaction']>\n >['result'],\n): Promise<TransactionMeta> => {\n const txHash = await hashPromise;\n const finalTransactionMeta = getTransactionMetaByHash(messenger, txHash);\n if (!finalTransactionMeta) {\n throw new Error(\n 'Failed to submit cross-chain swap tx: txMeta for txHash was not found',\n );\n }\n return finalTransactionMeta;\n};\n\nexport const addTransaction = async (\n messenger: BridgeStatusControllerMessenger,\n ...args: Parameters<TransactionController['addTransaction']>\n) => {\n const { result } = await messenger.call(\n 'TransactionController:addTransaction',\n ...args,\n );\n return await waitForHashAndReturnFinalTxMeta(messenger, result);\n};\n\nexport const generateActionId = () => (Date.now() + Math.random()).toString();\n\n/**\n * Adds a synthetic transaction to the TransactionController to display pending intent orders in the UI\n *\n * @param messenger - The messenger to use for the transaction\n * @param args - The arguments for the transaction\n * @returns The transaction meta\n */\nexport const addSyntheticTransaction = async (\n messenger: BridgeStatusControllerMessenger,\n ...args: Parameters<TransactionController['addTransaction']>\n) => {\n const { transactionMeta } = await messenger.call(\n 'TransactionController:addTransaction',\n args[0],\n {\n origin: 'metamask',\n actionId: generateActionId(),\n isStateOnly: true,\n isInternal: true,\n ...args[1],\n },\n );\n return transactionMeta;\n};\n\nexport const handleApprovalDelay = async (\n srcChainId: QuoteResponseV1['quote']['srcChainId'],\n) => {\n if ([ChainId.LINEA, ChainId.BASE].includes(srcChainId)) {\n const debugLog = createProjectLogger('bridge');\n debugLog(\n 'Delaying submitting bridge tx to make Linea and Base confirmation more likely',\n );\n const waitPromise = new Promise((resolve) =>\n setTimeout(resolve, APPROVAL_DELAY_MS),\n );\n await waitPromise;\n }\n};\n\n/**\n * Adds a delay for hardware wallet transactions on mobile to fix an issue\n * where the Ledger does not get prompted for the 2nd approval.\n * Extension does not have this issue.\n *\n * @param requireApproval - Whether the delay should be applied\n */\nexport const handleMobileHardwareWalletDelay = async (\n requireApproval: boolean,\n) => {\n if (requireApproval) {\n const mobileHardwareWalletDelay = new Promise((resolve) =>\n setTimeout(resolve, 1000),\n );\n await mobileHardwareWalletDelay;\n }\n};\n\n/**\n * Waits until a given transaction (by id) reaches confirmed/finalized status or fails/times out.\n *\n * @deprecated use addTransaction util\n * @param messenger - the BridgeStatusControllerMessenger\n * @param txId - the transaction ID\n * @param options - the options for the timeout and poll\n * @param options.timeoutMs - the timeout in milliseconds\n * @param options.pollMs - the poll interval in milliseconds\n * @returns the transaction meta\n */\nexport const waitForTxConfirmation = async (\n messenger: BridgeStatusControllerMessenger,\n txId: string,\n {\n timeoutMs = 5 * 60_000,\n pollMs = 3_000,\n }: { timeoutMs?: number; pollMs?: number } = {},\n): Promise<TransactionMeta> => {\n const start = Date.now();\n while (true) {\n const meta = getTransactionMetaById(messenger, txId);\n\n if (meta) {\n if (meta.status === TransactionStatus.confirmed) {\n return meta;\n }\n if (\n meta.status === TransactionStatus.failed ||\n meta.status === TransactionStatus.dropped ||\n meta.status === TransactionStatus.rejected\n ) {\n throw new Error('Approval transaction did not confirm');\n }\n }\n\n if (Date.now() - start > timeoutMs) {\n throw new Error('Timed out waiting for approval confirmation');\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollMs));\n }\n};\n\nexport const toQuoteAndTxMetadata = ({\n quoteResponse,\n isBridgeTx,\n}: {\n quoteResponse: QuoteResponseV1<Trade, Trade> & QuoteMetadata;\n isBridgeTx: boolean;\n}): Omit<QuoteAndTxMetadata, 'txMeta'>[] => {\n const tradeData: QuoteAndTxMetadata[] = [];\n\n const approvalTxType = isBridgeTx\n ? TransactionType.bridgeApproval\n : TransactionType.swapApproval;\n\n if (quoteResponse.resetApproval) {\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.resetApproval,\n type: approvalTxType,\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n }\n if (quoteResponse.approval && isEvmTxData(quoteResponse.approval)) {\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.approval,\n type: approvalTxType,\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n }\n tradeData.push({\n quoteResponse,\n tx: quoteResponse.trade as TxData,\n type: isBridgeTx ? TransactionType.bridge : TransactionType.swap,\n assetsFiatValues: {\n sending: quoteResponse.sentAmount?.valueInCurrency?.toString(),\n receiving: quoteResponse.toTokenAmount?.valueInCurrency?.toString(),\n },\n txFee: quoteResponse.quote.feeData[FeeType.TX_FEE],\n });\n\n return tradeData;\n};\n\n/**\n * Build the trade+quote metadata array for the batch sell transaction\n * This ties together the quote, the tx params and the txMeta after submission\n *\n * @param options - The options for the batch sell transaction\n * @param options.quoteResponses - The quote responses for the batch sell transaction\n * @param options.batchSellTrades - The batch sell trades for the batch sell transaction\n * @returns The trade+quote metadata array for the batch sell transaction\n */\nexport const toQuoteAndTxMetadataBatch = ({\n quoteResponses,\n batchSellTrades,\n}: {\n quoteResponses: (QuoteResponseV1<TxData, TxData> & QuoteMetadata)[];\n batchSellTrades: BatchSellTradesResponse;\n}): Omit<QuoteAndTxMetadata, 'txMeta'>[] => {\n const tradeData: QuoteAndTxMetadata[] = [];\n\n const {\n transactions,\n gasIncluded7702,\n gasIncluded,\n gasSponsored = false,\n } = batchSellTrades;\n\n for (const transaction of transactions) {\n const { type, maxFeePerGas, maxPriorityFeePerGas, ...tx } = transaction;\n // Match the trade or approval tx data with the quote response\n const matchingQuoteResponse =\n quoteResponses.find(\n ({ approval, trade }) =>\n trade?.data.toLowerCase() === tx.data.toLowerCase() ||\n approval?.data.toLowerCase() === tx.data.toLowerCase(),\n ) ?? quoteResponses[0];\n\n // Include gasIncluded and gasIncluded7702 from the gasless batch\n const normalizedQuote = {\n ...matchingQuoteResponse,\n quote: {\n ...matchingQuoteResponse.quote,\n gasIncluded,\n gasIncluded7702,\n gasSponsored,\n },\n };\n\n const commonTradeData = {\n tx,\n quoteResponse: normalizedQuote,\n txFee: { maxFeePerGas, maxPriorityFeePerGas },\n };\n\n if (type === BatchSellTransactionType.TRADE) {\n tradeData.push({\n ...commonTradeData,\n type: TransactionType.swap,\n assetsFiatValues: {\n sending:\n matchingQuoteResponse.sentAmount?.valueInCurrency?.toString(),\n receiving:\n matchingQuoteResponse.toTokenAmount?.valueInCurrency?.toString(),\n },\n });\n } else {\n tradeData.push({\n ...commonTradeData,\n type:\n type === BatchSellTransactionType.APPROVAL\n ? TransactionType.swapApproval\n : TransactionType.tokenMethodTransfer,\n });\n }\n }\n\n return tradeData;\n};\n\n/**\n * Appends the gas fee estimates for a transaction and normalizes the trade data\n *\n * @param messenger - The messenger for the gas fee estimates\n * @param trade - the trade data to append gas fees to\n * @param trade.chainId - ignored, use chainId instead\n * @param trade.gasLimit - the gas limit to use for the gas fee estimates\n * @param networkClientId - the network client ID to use for the gas fee estimates\n * @param chainId - the chain ID to use for the gas fee estimates\n * @param simulatedGasFeeLimits - either the txFee from the quote or the simulated gas fee limits for the batch sell\n * @returns The gas fee estimates for the transaction\n */\nexport const toTransactionParams = async (\n messenger: BridgeStatusControllerMessenger,\n { chainId: tradeChainId, gasLimit, ...trade }: TxData,\n networkClientId: string,\n chainId: Hex,\n simulatedGasFeeLimits?: SimulatedGasFeeLimits | TxFeeGasLimits,\n): Promise<BatchTransactionParams> => {\n const transactionParams = {\n data: trade.data,\n to: trade.to,\n from: trade.from,\n value: trade.value,\n // Only add gas if it's truthy\n gas: gasLimit ? toHex(gasLimit) : undefined,\n };\n\n // Use bridge-api's provided gas fee estimates\n if (simulatedGasFeeLimits) {\n return {\n ...transactionParams,\n // Sometimes estimates are hex, somethings numeric strings\n maxFeePerGas: isStrictHexString(simulatedGasFeeLimits.maxFeePerGas)\n ? simulatedGasFeeLimits.maxFeePerGas\n : toHex(simulatedGasFeeLimits.maxFeePerGas),\n maxPriorityFeePerGas: isStrictHexString(\n simulatedGasFeeLimits.maxPriorityFeePerGas,\n )\n ? simulatedGasFeeLimits.maxPriorityFeePerGas\n : toHex(simulatedGasFeeLimits.maxPriorityFeePerGas),\n };\n }\n\n // Get transaction's 1559 gas fee estimates\n const gasFeeEstimates = await getGasFeeEstimates(messenger, {\n transactionParams,\n networkClientId,\n chainId,\n });\n\n return {\n ...transactionParams,\n maxFeePerGas: gasFeeEstimates?.maxFeePerGas,\n maxPriorityFeePerGas: gasFeeEstimates?.maxPriorityFeePerGas,\n };\n};\n\nexport const getAddTransactionBatchParams = async ({\n messenger,\n tradeData,\n requireApproval = false,\n isDelegatedAccount,\n ...addTransactionBatchParams\n}: Partial<Parameters<TransactionController['addTransactionBatch']>[0]> & {\n messenger: BridgeStatusControllerMessenger;\n tradeData: QuoteAndTxMetadata[];\n requireApproval?: boolean;\n isDelegatedAccount?: boolean;\n}): Promise<Parameters<TransactionController['addTransactionBatch']>[0]> => {\n const trade = tradeData[0].tx;\n const selectedAccount = getAccountByAddress(messenger, trade.from);\n if (!selectedAccount) {\n throw new Error(\n 'Failed to submit cross-chain swap batch transaction: unknown account in trade data',\n );\n }\n const hexChainId = formatChainIdToHex(trade.chainId);\n const networkClientId = getNetworkClientIdByChainId(messenger, hexChainId);\n\n const transactions: TransactionBatchSingleRequest[] = await Promise.all(\n tradeData.map(async ({ tx, txFee, assetsFiatValues, type }) => ({\n params: await toTransactionParams(\n messenger,\n tx,\n networkClientId,\n hexChainId,\n txFee,\n ),\n assetsFiatValues,\n type,\n })),\n );\n\n return {\n networkClientId,\n requireApproval,\n origin: 'metamask',\n from: selectedAccount.address as Hex,\n isInternal: true,\n transactions,\n ...addTransactionBatchParams,\n };\n};\n\nexport const findAllTransactionsInBatch = ({\n messenger,\n batchId,\n tradeData,\n}: {\n messenger: BridgeStatusControllerMessenger;\n batchId: string;\n tradeData: QuoteAndTxMetadata[];\n}): QuoteAndTxMetadata[] => {\n // Filter for transactions with batchId\n const txs = getTransactions(messenger).filter(\n (tx: TransactionMeta) => tx.batchId === batchId,\n );\n\n return tradeData.map((tradeWithMetadata) => {\n const { tx, type } = tradeWithMetadata;\n return {\n ...tradeWithMetadata,\n txMeta: txs.find((txMeta: TransactionMeta) => {\n if (is7702Tx(txMeta)) {\n // For 7702 transactions, we need to match based on transaction type\n // since the data field might be different (batch execute call)\n if (isTradeTx(type) && txMeta.type === TransactionType.batch) {\n return true;\n }\n // Also check if it's an approval transaction for 7702\n if (isApprovalTx(type) && txMeta.txParams.data === tx.data) {\n return true;\n }\n }\n // Default matching logic for non-7702 transactions\n if (txMeta.txParams.data === tx.data) {\n return true;\n }\n return false;\n }),\n };\n });\n};\n\n/**\n * This is a workaround to update the tx type after submission. Batch txs are submitted with\n * the \"batch\" type, but we need to update to swap/bridge for display purposes.\n *\n * @param params - The parameters for the transaction search\n * @param params.messenger - The messenger to use for the transaction\n * @param params.allTradesWithMetadata - The quote, tx data and type for each transaction in the batch\n * @returns A list of transaction metas for each trade in the batch]\n *\n * @example\n * [\n * {...tradeData[0], tradeMeta: TransactionMeta}\n * {...tradeData[1], tradeMeta: TransactionMeta}\n * {...tradeData[2], tradeMeta: TransactionMeta}\n * {...tradeData[3], tradeMeta: TransactionMeta}\n * ]\n */\nexport const updateTransactionsInBatch = ({\n messenger,\n allTradesWithMetadata,\n}: {\n messenger: BridgeStatusControllerMessenger;\n allTradesWithMetadata: QuoteAndTxMetadata[];\n}) => {\n return allTradesWithMetadata.map((tradeWithMetadata) => {\n const { txMeta, type } = tradeWithMetadata;\n\n if (txMeta) {\n // Update the tx type from batch to swap/bridge\n updateTransaction(\n messenger,\n txMeta,\n { type },\n `Update tx type to ${type}`,\n );\n const updatedTx = { ...txMeta, type };\n return { ...tradeWithMetadata, txMeta: updatedTx, type };\n }\n\n return tradeWithMetadata;\n });\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/bridge-status-controller",
|
|
3
|
-
"version": "76.3.2-preview-
|
|
3
|
+
"version": "76.3.2-preview-ff2ab0583",
|
|
4
4
|
"description": "Manages bridge-related status fetching functionality for MetaMask",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@metamask/profile-sync-controller": "^33.0.0",
|
|
62
62
|
"@metamask/snaps-controllers": "^19.0.0",
|
|
63
63
|
"@metamask/superstruct": "^3.4.1",
|
|
64
|
-
"@metamask/transaction-controller": "^72.0.
|
|
64
|
+
"@metamask/transaction-controller": "^72.0.1",
|
|
65
65
|
"@metamask/utils": "^12.0.0",
|
|
66
66
|
"bignumber.js": "^9.1.2",
|
|
67
67
|
"uuid": "^11.1.1"
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@metamask/auto-changelog": "^6.2.1",
|
|
71
71
|
"@types/jest": "^30.0.0",
|
|
72
72
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
73
|
-
"deepmerge": "^4.
|
|
73
|
+
"deepmerge": "^4.3.1",
|
|
74
74
|
"jest": "^30.4.2",
|
|
75
75
|
"jest-environment-jsdom": "^30.4.1",
|
|
76
76
|
"lodash-es": "^4.17.21",
|