@metamask/transaction-pay-controller 22.7.0 → 22.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/TransactionPayController-method-action-types.cjs.map +1 -1
  3. package/dist/TransactionPayController-method-action-types.d.cts +15 -1
  4. package/dist/TransactionPayController-method-action-types.d.cts.map +1 -1
  5. package/dist/TransactionPayController-method-action-types.d.mts +15 -1
  6. package/dist/TransactionPayController-method-action-types.d.mts.map +1 -1
  7. package/dist/TransactionPayController-method-action-types.mjs.map +1 -1
  8. package/dist/TransactionPayController.cjs +19 -3
  9. package/dist/TransactionPayController.cjs.map +1 -1
  10. package/dist/TransactionPayController.d.cts +13 -2
  11. package/dist/TransactionPayController.d.cts.map +1 -1
  12. package/dist/TransactionPayController.d.mts +13 -2
  13. package/dist/TransactionPayController.d.mts.map +1 -1
  14. package/dist/TransactionPayController.mjs +19 -3
  15. package/dist/TransactionPayController.mjs.map +1 -1
  16. package/dist/constants.cjs +1 -0
  17. package/dist/constants.cjs.map +1 -1
  18. package/dist/constants.d.cts +1 -0
  19. package/dist/constants.d.cts.map +1 -1
  20. package/dist/constants.d.mts +1 -0
  21. package/dist/constants.d.mts.map +1 -1
  22. package/dist/constants.mjs +1 -0
  23. package/dist/constants.mjs.map +1 -1
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +1 -1
  26. package/dist/index.d.cts.map +1 -1
  27. package/dist/index.d.mts +1 -1
  28. package/dist/index.d.mts.map +1 -1
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/strategy/relay/relay-quotes.cjs +20 -3
  31. package/dist/strategy/relay/relay-quotes.cjs.map +1 -1
  32. package/dist/strategy/relay/relay-quotes.d.cts.map +1 -1
  33. package/dist/strategy/relay/relay-quotes.d.mts.map +1 -1
  34. package/dist/strategy/relay/relay-quotes.mjs +20 -3
  35. package/dist/strategy/relay/relay-quotes.mjs.map +1 -1
  36. package/dist/strategy/relay/relay-submit.cjs +24 -11
  37. package/dist/strategy/relay/relay-submit.cjs.map +1 -1
  38. package/dist/strategy/relay/relay-submit.mjs +24 -11
  39. package/dist/strategy/relay/relay-submit.mjs.map +1 -1
  40. package/dist/strategy/server/ServerStrategy.cjs +35 -0
  41. package/dist/strategy/server/ServerStrategy.cjs.map +1 -0
  42. package/dist/strategy/server/ServerStrategy.d.cts +15 -0
  43. package/dist/strategy/server/ServerStrategy.d.cts.map +1 -0
  44. package/dist/strategy/server/ServerStrategy.d.mts +15 -0
  45. package/dist/strategy/server/ServerStrategy.d.mts.map +1 -0
  46. package/dist/strategy/server/ServerStrategy.mjs +31 -0
  47. package/dist/strategy/server/ServerStrategy.mjs.map +1 -0
  48. package/dist/strategy/server/constants.cjs +11 -0
  49. package/dist/strategy/server/constants.cjs.map +1 -0
  50. package/dist/strategy/server/constants.d.cts +8 -0
  51. package/dist/strategy/server/constants.d.cts.map +1 -0
  52. package/dist/strategy/server/constants.d.mts +8 -0
  53. package/dist/strategy/server/constants.d.mts.map +1 -0
  54. package/dist/strategy/server/constants.mjs +8 -0
  55. package/dist/strategy/server/constants.mjs.map +1 -0
  56. package/dist/strategy/server/perps.cjs +71 -0
  57. package/dist/strategy/server/perps.cjs.map +1 -0
  58. package/dist/strategy/server/perps.d.cts +36 -0
  59. package/dist/strategy/server/perps.d.cts.map +1 -0
  60. package/dist/strategy/server/perps.d.mts +36 -0
  61. package/dist/strategy/server/perps.d.mts.map +1 -0
  62. package/dist/strategy/server/perps.mjs +66 -0
  63. package/dist/strategy/server/perps.mjs.map +1 -0
  64. package/dist/strategy/server/server-api.cjs +98 -0
  65. package/dist/strategy/server/server-api.cjs.map +1 -0
  66. package/dist/strategy/server/server-api.d.cts +35 -0
  67. package/dist/strategy/server/server-api.d.cts.map +1 -0
  68. package/dist/strategy/server/server-api.d.mts +35 -0
  69. package/dist/strategy/server/server-api.d.mts.map +1 -0
  70. package/dist/strategy/server/server-api.mjs +92 -0
  71. package/dist/strategy/server/server-api.mjs.map +1 -0
  72. package/dist/strategy/server/server-quotes.cjs +315 -0
  73. package/dist/strategy/server/server-quotes.cjs.map +1 -0
  74. package/dist/strategy/server/server-quotes.d.cts +10 -0
  75. package/dist/strategy/server/server-quotes.d.cts.map +1 -0
  76. package/dist/strategy/server/server-quotes.d.mts +10 -0
  77. package/dist/strategy/server/server-quotes.d.mts.map +1 -0
  78. package/dist/strategy/server/server-quotes.mjs +311 -0
  79. package/dist/strategy/server/server-quotes.mjs.map +1 -0
  80. package/dist/strategy/server/server-submit.cjs +296 -0
  81. package/dist/strategy/server/server-submit.cjs.map +1 -0
  82. package/dist/strategy/server/server-submit.d.cts +13 -0
  83. package/dist/strategy/server/server-submit.d.cts.map +1 -0
  84. package/dist/strategy/server/server-submit.d.mts +13 -0
  85. package/dist/strategy/server/server-submit.d.mts.map +1 -0
  86. package/dist/strategy/server/server-submit.mjs +292 -0
  87. package/dist/strategy/server/server-submit.mjs.map +1 -0
  88. package/dist/strategy/server/types.cjs +26 -0
  89. package/dist/strategy/server/types.cjs.map +1 -0
  90. package/dist/strategy/server/types.d.cts +153 -0
  91. package/dist/strategy/server/types.d.cts.map +1 -0
  92. package/dist/strategy/server/types.d.mts +153 -0
  93. package/dist/strategy/server/types.d.mts.map +1 -0
  94. package/dist/strategy/server/types.mjs +23 -0
  95. package/dist/strategy/server/types.mjs.map +1 -0
  96. package/dist/tests/messenger-mock.cjs +3 -0
  97. package/dist/tests/messenger-mock.cjs.map +1 -1
  98. package/dist/tests/messenger-mock.d.cts +255 -3
  99. package/dist/tests/messenger-mock.d.cts.map +1 -1
  100. package/dist/tests/messenger-mock.d.mts +255 -3
  101. package/dist/tests/messenger-mock.d.mts.map +1 -1
  102. package/dist/tests/messenger-mock.mjs +3 -0
  103. package/dist/tests/messenger-mock.mjs.map +1 -1
  104. package/dist/types.cjs.map +1 -1
  105. package/dist/types.d.cts +43 -17
  106. package/dist/types.d.cts.map +1 -1
  107. package/dist/types.d.mts +43 -17
  108. package/dist/types.d.mts.map +1 -1
  109. package/dist/types.mjs.map +1 -1
  110. package/dist/utils/feature-flags.cjs +43 -3
  111. package/dist/utils/feature-flags.cjs.map +1 -1
  112. package/dist/utils/feature-flags.d.cts +21 -0
  113. package/dist/utils/feature-flags.d.cts.map +1 -1
  114. package/dist/utils/feature-flags.d.mts +21 -0
  115. package/dist/utils/feature-flags.d.mts.map +1 -1
  116. package/dist/utils/feature-flags.mjs +40 -2
  117. package/dist/utils/feature-flags.mjs.map +1 -1
  118. package/dist/utils/gas.cjs +11 -10
  119. package/dist/utils/gas.cjs.map +1 -1
  120. package/dist/utils/gas.d.cts +12 -0
  121. package/dist/utils/gas.d.cts.map +1 -1
  122. package/dist/utils/gas.d.mts +12 -0
  123. package/dist/utils/gas.d.mts.map +1 -1
  124. package/dist/utils/gas.mjs +10 -10
  125. package/dist/utils/gas.mjs.map +1 -1
  126. package/dist/utils/quotes.cjs +9 -3
  127. package/dist/utils/quotes.cjs.map +1 -1
  128. package/dist/utils/quotes.d.cts.map +1 -1
  129. package/dist/utils/quotes.d.mts.map +1 -1
  130. package/dist/utils/quotes.mjs +10 -4
  131. package/dist/utils/quotes.mjs.map +1 -1
  132. package/dist/utils/strategy.cjs +3 -0
  133. package/dist/utils/strategy.cjs.map +1 -1
  134. package/dist/utils/strategy.d.cts.map +1 -1
  135. package/dist/utils/strategy.d.mts.map +1 -1
  136. package/dist/utils/strategy.mjs +3 -0
  137. package/dist/utils/strategy.mjs.map +1 -1
  138. package/package.json +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perps.mjs","sourceRoot":"","sources":["../../../src/strategy/server/perps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,qBAAqB;AAEzC,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACd,4BAAwB;AAGzB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mCAAmC,GAC9C,4CAAmD,CAAC;AAEtD,MAAM,gCAAgC,GACpC,4CAA4C,CAAC;AAE/C,MAAM,oCAAoC,GACxC,gCAAgC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAGC,EACD,WAAqE;IAErE,IACE,OAAO,CAAC,WAAW,KAAK,IAAI;QAC5B,OAAO,CAAC,aAAa,KAAK,iBAAiB;QAC3C,OAAO,CAAC,kBAAkB,CAAC,WAAW,EAAE;YACtC,qBAAqB,CAAC,WAAW,EAAE,EACrC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,+BAA+B,CAAC,WAAW,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAqB,EACrB,WAAqE;IAErE,IAAI,CAAC,2BAA2B,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;QACvD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,mBAAmB,EAAE,IAAI,SAAS,CAAC,OAAO,CAAC,mBAAmB,CAAC;aAC5D,SAAS,CAAC,uBAAuB,GAAG,aAAa,CAAC;aAClD,OAAO,CAAC,CAAC,CAAC;QACb,aAAa,EAAE,kBAAkB;QACjC,kBAAkB,EAAE,mCAAmC;KACxD,CAAC;AACJ,CAAC;AAED,SAAS,+BAA+B,CACtC,WAAqE;IAErE,MAAM,SAAS,GAA2B;QACxC,WAAW,CAAC,QAAQ,EAAE,EAAE;QACxB,GAAG,CAAC,WAAW,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;KAC7D,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CACnB,CAAC,KAAK,EAAE,EAAE,CACR,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC,CACrE,CAAC;AACJ,CAAC","sourcesContent":["import type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { BigNumber } from 'bignumber.js';\n\nimport {\n ARBITRUM_USDC_ADDRESS,\n CHAIN_ID_ARBITRUM,\n CHAIN_ID_HYPERCORE,\n HYPERCORE_USDC_DECIMALS,\n USDC_DECIMALS,\n} from '../../constants';\nimport type { QuoteRequest } from '../../types';\n\n/**\n * Shared 20-byte sentinel address emitted by the server strategy to flag a\n * Hyperliquid perps deposit. Backend providers translate this to their own\n * on-chain destination (e.g. Relay's 16-byte HyperCore USDC sentinel, Across's\n * native USDC-PERPS token at the same address).\n */\nexport const SERVER_HYPERCORE_USDC_PERPS_ADDRESS =\n '0x2100000000000000000000000000000000000000' as Hex;\n\nconst HYPERLIQUID_BRIDGE_ADDRESS_LOWER =\n '0x2df1c51e09aecf9cacb7bc98cb1742757f163df7';\n\nconst HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT =\n HYPERLIQUID_BRIDGE_ADDRESS_LOWER.slice(2);\n\n/**\n * Detect whether a quote request represents a Hyperliquid perps deposit by\n * sniffing the parent transaction calldata for a reference to the Hyperliquid\n * bridge contract. Transaction type is intentionally NOT consulted so that any\n * caller funnelling a bridge deposit through Pay is supported.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Whether the request matches a Hyperliquid bridge deposit.\n */\nexport function isServerPerpsDepositRequest(\n request: Pick<\n QuoteRequest,\n 'isPostQuote' | 'targetChainId' | 'targetTokenAddress'\n >,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n if (\n request.isPostQuote === true ||\n request.targetChainId !== CHAIN_ID_ARBITRUM ||\n request.targetTokenAddress.toLowerCase() !==\n ARBITRUM_USDC_ADDRESS.toLowerCase()\n ) {\n return false;\n }\n\n return transactionDataReferencesBridge(transaction);\n}\n\n/**\n * Translate a Hyperliquid perps-deposit quote request into the HyperCore\n * direct-deposit shape with a provider-agnostic sentinel destination. Backend\n * providers detect the sentinel and rewrite it to their respective on-chain\n * destinations.\n *\n * Transaction pay starts from the parent on-chain asset (Arbitrum USDC,\n * 6 decimals); HyperCore expects an 8-decimal amount, so the target amount is\n * shifted accordingly.\n *\n * @param request - Quote request from the transaction-pay controller.\n * @param transaction - Parent transaction whose calldata is inspected.\n * @returns Normalized request, or the original request if not a perps deposit.\n */\nexport function normalizeServerPerpsRequest(\n request: QuoteRequest,\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): QuoteRequest {\n if (!isServerPerpsDepositRequest(request, transaction)) {\n return request;\n }\n\n return {\n ...request,\n targetAmountMinimum: new BigNumber(request.targetAmountMinimum)\n .shiftedBy(HYPERCORE_USDC_DECIMALS - USDC_DECIMALS)\n .toFixed(0),\n targetChainId: CHAIN_ID_HYPERCORE,\n targetTokenAddress: SERVER_HYPERCORE_USDC_PERPS_ADDRESS,\n };\n}\n\nfunction transactionDataReferencesBridge(\n transaction: Pick<TransactionMeta, 'txParams' | 'nestedTransactions'>,\n): boolean {\n const fragments: (string | undefined)[] = [\n transaction.txParams?.to,\n ...(transaction.nestedTransactions ?? []).map((tx) => tx.to),\n ];\n\n return fragments.some(\n (value) =>\n typeof value === 'string' &&\n value.toLowerCase().includes(HYPERLIQUID_BRIDGE_CALLDATA_FRAGMENT),\n );\n}\n"]}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServerStatus = exports.submitServerIntent = exports.fetchServerQuote = void 0;
4
+ const utils_1 = require("@metamask/utils");
5
+ const logger_1 = require("../../logger.cjs");
6
+ const feature_flags_1 = require("../../utils/feature-flags.cjs");
7
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'server-api');
8
+ /**
9
+ * Fetch a quote from the server intents API.
10
+ *
11
+ * @param messenger - Controller messenger.
12
+ * @param body - Quote request parameters.
13
+ * @param signal - Optional abort signal that cancels the underlying fetch.
14
+ * @returns The server quote response.
15
+ */
16
+ async function fetchServerQuote(messenger, body, signal) {
17
+ const { server } = (0, feature_flags_1.getPayStrategiesConfig)(messenger);
18
+ const quoteUrl = `${server.baseUrl}/quote`;
19
+ log('Fetching quote', { url: quoteUrl });
20
+ const response = await serverFetch(quoteUrl, {
21
+ method: 'POST',
22
+ headers: { 'Content-Type': 'application/json' },
23
+ body: JSON.stringify(body),
24
+ signal,
25
+ });
26
+ return (await response.json());
27
+ }
28
+ exports.fetchServerQuote = fetchServerQuote;
29
+ /**
30
+ * Submit a gasless intent via the server intents API.
31
+ *
32
+ * @param messenger - Controller messenger.
33
+ * @param body - Submit request parameters.
34
+ * @returns The submit response.
35
+ */
36
+ async function submitServerIntent(messenger, body) {
37
+ const { server } = (0, feature_flags_1.getPayStrategiesConfig)(messenger);
38
+ const submitUrl = `${server.baseUrl}/submit`;
39
+ log('Submitting intent', { url: submitUrl });
40
+ const response = await serverFetch(submitUrl, {
41
+ method: 'POST',
42
+ headers: { 'Content-Type': 'application/json' },
43
+ body: JSON.stringify(body),
44
+ });
45
+ return (await response.json());
46
+ }
47
+ exports.submitServerIntent = submitServerIntent;
48
+ /**
49
+ * Fetch the status of a server intent.
50
+ *
51
+ * @param messenger - Controller messenger.
52
+ * @param params - Status query parameters.
53
+ * @param params.provider - The provider that the intent was submitted to.
54
+ * @param params.id - The intent ID.
55
+ * @param params.hash - Optional transaction hash to include in the status query.
56
+ * @returns The current status of the intent.
57
+ */
58
+ async function getServerStatus(messenger, params) {
59
+ const { server } = (0, feature_flags_1.getPayStrategiesConfig)(messenger);
60
+ const query = new URLSearchParams({
61
+ provider: params.provider,
62
+ id: params.id,
63
+ });
64
+ if (params.hash) {
65
+ query.set('hash', params.hash);
66
+ }
67
+ const url = `${server.baseUrl}/status?${query.toString()}`;
68
+ log('Fetching status', { url });
69
+ const response = await serverFetch(url, { method: 'GET' });
70
+ return (await response.json());
71
+ }
72
+ exports.getServerStatus = getServerStatus;
73
+ /**
74
+ * Fetch a server intents-api endpoint, throwing an error containing the
75
+ * response body's `message` or `error` field (or status code) on non-OK
76
+ * responses so the server's actual reason is preserved without leaking the
77
+ * request URL.
78
+ *
79
+ * @param url - The endpoint to fetch.
80
+ * @param init - Fetch init options.
81
+ * @returns The successful response.
82
+ */
83
+ async function serverFetch(url, init) {
84
+ const response = await fetch(url, init);
85
+ if (!response.ok) {
86
+ let detail;
87
+ try {
88
+ const body = (await response.json());
89
+ detail = body.message ?? body.error;
90
+ }
91
+ catch {
92
+ // Body wasn't JSON; fall through to status-only error.
93
+ }
94
+ throw new Error(detail ? `${response.status} - ${detail}` : String(response.status));
95
+ }
96
+ return response;
97
+ }
98
+ //# sourceMappingURL=server-api.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-api.cjs","sourceRoot":"","sources":["../../../src/strategy/server/server-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type { TransactionPayControllerMessenger } from '../../types';\nimport { getPayStrategiesConfig } from '../../utils/feature-flags';\nimport type {\n ServerProviderName,\n ServerQuoteRequest,\n ServerQuoteResponse,\n ServerStatusResponse,\n ServerSubmitRequest,\n ServerSubmitResponse,\n} from './types';\n\nconst log = createModuleLogger(projectLogger, 'server-api');\n\n/**\n * Fetch a quote from the server intents API.\n *\n * @param messenger - Controller messenger.\n * @param body - Quote request parameters.\n * @param signal - Optional abort signal that cancels the underlying fetch.\n * @returns The server quote response.\n */\nexport async function fetchServerQuote(\n messenger: TransactionPayControllerMessenger,\n body: ServerQuoteRequest,\n signal?: AbortSignal,\n): Promise<ServerQuoteResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const quoteUrl = `${server.baseUrl}/quote`;\n\n log('Fetching quote', { url: quoteUrl });\n\n const response = await serverFetch(quoteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n });\n\n return (await response.json()) as ServerQuoteResponse;\n}\n\n/**\n * Submit a gasless intent via the server intents API.\n *\n * @param messenger - Controller messenger.\n * @param body - Submit request parameters.\n * @returns The submit response.\n */\nexport async function submitServerIntent(\n messenger: TransactionPayControllerMessenger,\n body: ServerSubmitRequest,\n): Promise<ServerSubmitResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const submitUrl = `${server.baseUrl}/submit`;\n\n log('Submitting intent', { url: submitUrl });\n\n const response = await serverFetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n return (await response.json()) as ServerSubmitResponse;\n}\n\n/**\n * Fetch the status of a server intent.\n *\n * @param messenger - Controller messenger.\n * @param params - Status query parameters.\n * @param params.provider - The provider that the intent was submitted to.\n * @param params.id - The intent ID.\n * @param params.hash - Optional transaction hash to include in the status query.\n * @returns The current status of the intent.\n */\nexport async function getServerStatus(\n messenger: TransactionPayControllerMessenger,\n params: { provider: ServerProviderName; id: string; hash?: string },\n): Promise<ServerStatusResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const query = new URLSearchParams({\n provider: params.provider,\n id: params.id,\n });\n if (params.hash) {\n query.set('hash', params.hash);\n }\n const url = `${server.baseUrl}/status?${query.toString()}`;\n\n log('Fetching status', { url });\n\n const response = await serverFetch(url, { method: 'GET' });\n\n return (await response.json()) as ServerStatusResponse;\n}\n\n/**\n * Fetch a server intents-api endpoint, throwing an error containing the\n * response body's `message` or `error` field (or status code) on non-OK\n * responses so the server's actual reason is preserved without leaking the\n * request URL.\n *\n * @param url - The endpoint to fetch.\n * @param init - Fetch init options.\n * @returns The successful response.\n */\nasync function serverFetch(url: string, init?: RequestInit): Promise<Response> {\n const response = await fetch(url, init);\n\n if (!response.ok) {\n let detail: string | undefined;\n try {\n const body = (await response.json()) as {\n message?: string;\n error?: string;\n };\n detail = body.message ?? body.error;\n } catch {\n // Body wasn't JSON; fall through to status-only error.\n }\n throw new Error(\n detail ? `${response.status} - ${detail}` : String(response.status),\n );\n }\n\n return response;\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import type { TransactionPayControllerMessenger } from "../../types.cjs";
2
+ import type { ServerProviderName, ServerQuoteRequest, ServerQuoteResponse, ServerStatusResponse, ServerSubmitRequest, ServerSubmitResponse } from "./types.cjs";
3
+ /**
4
+ * Fetch a quote from the server intents API.
5
+ *
6
+ * @param messenger - Controller messenger.
7
+ * @param body - Quote request parameters.
8
+ * @param signal - Optional abort signal that cancels the underlying fetch.
9
+ * @returns The server quote response.
10
+ */
11
+ export declare function fetchServerQuote(messenger: TransactionPayControllerMessenger, body: ServerQuoteRequest, signal?: AbortSignal): Promise<ServerQuoteResponse>;
12
+ /**
13
+ * Submit a gasless intent via the server intents API.
14
+ *
15
+ * @param messenger - Controller messenger.
16
+ * @param body - Submit request parameters.
17
+ * @returns The submit response.
18
+ */
19
+ export declare function submitServerIntent(messenger: TransactionPayControllerMessenger, body: ServerSubmitRequest): Promise<ServerSubmitResponse>;
20
+ /**
21
+ * Fetch the status of a server intent.
22
+ *
23
+ * @param messenger - Controller messenger.
24
+ * @param params - Status query parameters.
25
+ * @param params.provider - The provider that the intent was submitted to.
26
+ * @param params.id - The intent ID.
27
+ * @param params.hash - Optional transaction hash to include in the status query.
28
+ * @returns The current status of the intent.
29
+ */
30
+ export declare function getServerStatus(messenger: TransactionPayControllerMessenger, params: {
31
+ provider: ServerProviderName;
32
+ id: string;
33
+ hash?: string;
34
+ }): Promise<ServerStatusResponse>;
35
+ //# sourceMappingURL=server-api.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-api.d.cts","sourceRoot":"","sources":["../../../src/strategy/server/server-api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAoB;AAErE,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACrB,oBAAgB;AAIjB;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,kBAAkB,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAc9B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAa/B;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,iCAAiC,EAC5C,MAAM,EAAE;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAClE,OAAO,CAAC,oBAAoB,CAAC,CAgB/B"}
@@ -0,0 +1,35 @@
1
+ import type { TransactionPayControllerMessenger } from "../../types.mjs";
2
+ import type { ServerProviderName, ServerQuoteRequest, ServerQuoteResponse, ServerStatusResponse, ServerSubmitRequest, ServerSubmitResponse } from "./types.mjs";
3
+ /**
4
+ * Fetch a quote from the server intents API.
5
+ *
6
+ * @param messenger - Controller messenger.
7
+ * @param body - Quote request parameters.
8
+ * @param signal - Optional abort signal that cancels the underlying fetch.
9
+ * @returns The server quote response.
10
+ */
11
+ export declare function fetchServerQuote(messenger: TransactionPayControllerMessenger, body: ServerQuoteRequest, signal?: AbortSignal): Promise<ServerQuoteResponse>;
12
+ /**
13
+ * Submit a gasless intent via the server intents API.
14
+ *
15
+ * @param messenger - Controller messenger.
16
+ * @param body - Submit request parameters.
17
+ * @returns The submit response.
18
+ */
19
+ export declare function submitServerIntent(messenger: TransactionPayControllerMessenger, body: ServerSubmitRequest): Promise<ServerSubmitResponse>;
20
+ /**
21
+ * Fetch the status of a server intent.
22
+ *
23
+ * @param messenger - Controller messenger.
24
+ * @param params - Status query parameters.
25
+ * @param params.provider - The provider that the intent was submitted to.
26
+ * @param params.id - The intent ID.
27
+ * @param params.hash - Optional transaction hash to include in the status query.
28
+ * @returns The current status of the intent.
29
+ */
30
+ export declare function getServerStatus(messenger: TransactionPayControllerMessenger, params: {
31
+ provider: ServerProviderName;
32
+ id: string;
33
+ hash?: string;
34
+ }): Promise<ServerStatusResponse>;
35
+ //# sourceMappingURL=server-api.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-api.d.mts","sourceRoot":"","sources":["../../../src/strategy/server/server-api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iCAAiC,EAAE,wBAAoB;AAErE,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACrB,oBAAgB;AAIjB;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,kBAAkB,EACxB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAc9B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,iCAAiC,EAC5C,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAa/B;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,iCAAiC,EAC5C,MAAM,EAAE;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAClE,OAAO,CAAC,oBAAoB,CAAC,CAgB/B"}
@@ -0,0 +1,92 @@
1
+ import { createModuleLogger } from "@metamask/utils";
2
+ import { projectLogger } from "../../logger.mjs";
3
+ import { getPayStrategiesConfig } from "../../utils/feature-flags.mjs";
4
+ const log = createModuleLogger(projectLogger, 'server-api');
5
+ /**
6
+ * Fetch a quote from the server intents API.
7
+ *
8
+ * @param messenger - Controller messenger.
9
+ * @param body - Quote request parameters.
10
+ * @param signal - Optional abort signal that cancels the underlying fetch.
11
+ * @returns The server quote response.
12
+ */
13
+ export async function fetchServerQuote(messenger, body, signal) {
14
+ const { server } = getPayStrategiesConfig(messenger);
15
+ const quoteUrl = `${server.baseUrl}/quote`;
16
+ log('Fetching quote', { url: quoteUrl });
17
+ const response = await serverFetch(quoteUrl, {
18
+ method: 'POST',
19
+ headers: { 'Content-Type': 'application/json' },
20
+ body: JSON.stringify(body),
21
+ signal,
22
+ });
23
+ return (await response.json());
24
+ }
25
+ /**
26
+ * Submit a gasless intent via the server intents API.
27
+ *
28
+ * @param messenger - Controller messenger.
29
+ * @param body - Submit request parameters.
30
+ * @returns The submit response.
31
+ */
32
+ export async function submitServerIntent(messenger, body) {
33
+ const { server } = getPayStrategiesConfig(messenger);
34
+ const submitUrl = `${server.baseUrl}/submit`;
35
+ log('Submitting intent', { url: submitUrl });
36
+ const response = await serverFetch(submitUrl, {
37
+ method: 'POST',
38
+ headers: { 'Content-Type': 'application/json' },
39
+ body: JSON.stringify(body),
40
+ });
41
+ return (await response.json());
42
+ }
43
+ /**
44
+ * Fetch the status of a server intent.
45
+ *
46
+ * @param messenger - Controller messenger.
47
+ * @param params - Status query parameters.
48
+ * @param params.provider - The provider that the intent was submitted to.
49
+ * @param params.id - The intent ID.
50
+ * @param params.hash - Optional transaction hash to include in the status query.
51
+ * @returns The current status of the intent.
52
+ */
53
+ export async function getServerStatus(messenger, params) {
54
+ const { server } = getPayStrategiesConfig(messenger);
55
+ const query = new URLSearchParams({
56
+ provider: params.provider,
57
+ id: params.id,
58
+ });
59
+ if (params.hash) {
60
+ query.set('hash', params.hash);
61
+ }
62
+ const url = `${server.baseUrl}/status?${query.toString()}`;
63
+ log('Fetching status', { url });
64
+ const response = await serverFetch(url, { method: 'GET' });
65
+ return (await response.json());
66
+ }
67
+ /**
68
+ * Fetch a server intents-api endpoint, throwing an error containing the
69
+ * response body's `message` or `error` field (or status code) on non-OK
70
+ * responses so the server's actual reason is preserved without leaking the
71
+ * request URL.
72
+ *
73
+ * @param url - The endpoint to fetch.
74
+ * @param init - Fetch init options.
75
+ * @returns The successful response.
76
+ */
77
+ async function serverFetch(url, init) {
78
+ const response = await fetch(url, init);
79
+ if (!response.ok) {
80
+ let detail;
81
+ try {
82
+ const body = (await response.json());
83
+ detail = body.message ?? body.error;
84
+ }
85
+ catch {
86
+ // Body wasn't JSON; fall through to status-only error.
87
+ }
88
+ throw new Error(detail ? `${response.status} - ${detail}` : String(response.status));
89
+ }
90
+ return response;
91
+ }
92
+ //# sourceMappingURL=server-api.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-api.mjs","sourceRoot":"","sources":["../../../src/strategy/server/server-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { createModuleLogger } from '@metamask/utils';\n\nimport { projectLogger } from '../../logger';\nimport type { TransactionPayControllerMessenger } from '../../types';\nimport { getPayStrategiesConfig } from '../../utils/feature-flags';\nimport type {\n ServerProviderName,\n ServerQuoteRequest,\n ServerQuoteResponse,\n ServerStatusResponse,\n ServerSubmitRequest,\n ServerSubmitResponse,\n} from './types';\n\nconst log = createModuleLogger(projectLogger, 'server-api');\n\n/**\n * Fetch a quote from the server intents API.\n *\n * @param messenger - Controller messenger.\n * @param body - Quote request parameters.\n * @param signal - Optional abort signal that cancels the underlying fetch.\n * @returns The server quote response.\n */\nexport async function fetchServerQuote(\n messenger: TransactionPayControllerMessenger,\n body: ServerQuoteRequest,\n signal?: AbortSignal,\n): Promise<ServerQuoteResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const quoteUrl = `${server.baseUrl}/quote`;\n\n log('Fetching quote', { url: quoteUrl });\n\n const response = await serverFetch(quoteUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal,\n });\n\n return (await response.json()) as ServerQuoteResponse;\n}\n\n/**\n * Submit a gasless intent via the server intents API.\n *\n * @param messenger - Controller messenger.\n * @param body - Submit request parameters.\n * @returns The submit response.\n */\nexport async function submitServerIntent(\n messenger: TransactionPayControllerMessenger,\n body: ServerSubmitRequest,\n): Promise<ServerSubmitResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const submitUrl = `${server.baseUrl}/submit`;\n\n log('Submitting intent', { url: submitUrl });\n\n const response = await serverFetch(submitUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n return (await response.json()) as ServerSubmitResponse;\n}\n\n/**\n * Fetch the status of a server intent.\n *\n * @param messenger - Controller messenger.\n * @param params - Status query parameters.\n * @param params.provider - The provider that the intent was submitted to.\n * @param params.id - The intent ID.\n * @param params.hash - Optional transaction hash to include in the status query.\n * @returns The current status of the intent.\n */\nexport async function getServerStatus(\n messenger: TransactionPayControllerMessenger,\n params: { provider: ServerProviderName; id: string; hash?: string },\n): Promise<ServerStatusResponse> {\n const { server } = getPayStrategiesConfig(messenger);\n const query = new URLSearchParams({\n provider: params.provider,\n id: params.id,\n });\n if (params.hash) {\n query.set('hash', params.hash);\n }\n const url = `${server.baseUrl}/status?${query.toString()}`;\n\n log('Fetching status', { url });\n\n const response = await serverFetch(url, { method: 'GET' });\n\n return (await response.json()) as ServerStatusResponse;\n}\n\n/**\n * Fetch a server intents-api endpoint, throwing an error containing the\n * response body's `message` or `error` field (or status code) on non-OK\n * responses so the server's actual reason is preserved without leaking the\n * request URL.\n *\n * @param url - The endpoint to fetch.\n * @param init - Fetch init options.\n * @returns The successful response.\n */\nasync function serverFetch(url: string, init?: RequestInit): Promise<Response> {\n const response = await fetch(url, init);\n\n if (!response.ok) {\n let detail: string | undefined;\n try {\n const body = (await response.json()) as {\n message?: string;\n error?: string;\n };\n detail = body.message ?? body.error;\n } catch {\n // Body wasn't JSON; fall through to status-only error.\n }\n throw new Error(\n detail ? `${response.status} - ${detail}` : String(response.status),\n );\n }\n\n return response;\n}\n"]}
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getServerQuotes = void 0;
4
+ const abi_1 = require("@ethersproject/abi");
5
+ const controller_utils_1 = require("@metamask/controller-utils");
6
+ const utils_1 = require("@metamask/utils");
7
+ const bignumber_js_1 = require("bignumber.js");
8
+ const constants_1 = require("../../constants.cjs");
9
+ const logger_1 = require("../../logger.cjs");
10
+ const amounts_1 = require("../../utils/amounts.cjs");
11
+ const feature_flags_1 = require("../../utils/feature-flags.cjs");
12
+ const gas_1 = require("../../utils/gas.cjs");
13
+ const gas_station_1 = require("../../utils/gas-station.cjs");
14
+ const quote_gas_1 = require("../../utils/quote-gas.cjs");
15
+ const token_1 = require("../../utils/token.cjs");
16
+ const perps_1 = require("./perps.cjs");
17
+ const server_api_1 = require("./server-api.cjs");
18
+ const types_1 = require("./types.cjs");
19
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'server-quotes');
20
+ const TOKEN_TRANSFER_FOUR_BYTE = '0xa9059cbb';
21
+ const TRANSFER_INTERFACE = new abi_1.Interface([
22
+ 'function transfer(address to, uint256 amount)',
23
+ ]);
24
+ const ZERO_AMOUNT = { fiat: '0', human: '0', raw: '0', usd: '0' };
25
+ const ZERO_FIAT_VALUE = { fiat: '0', usd: '0' };
26
+ /**
27
+ * Fetch server intents-api quotes and normalize them into Transaction Pay quotes.
28
+ *
29
+ * @param request - Quote request context.
30
+ * @returns Normalized server strategy quotes.
31
+ */
32
+ async function getServerQuotes(request) {
33
+ const quoteRequests = request.requests.filter(shouldRequestQuote);
34
+ log('Fetching quotes', { quoteRequests });
35
+ const quotes = await Promise.all(quoteRequests.map((quoteRequest) => getQuotesForRequest(quoteRequest, request)));
36
+ return quotes.flat();
37
+ }
38
+ exports.getServerQuotes = getServerQuotes;
39
+ async function getQuotesForRequest(quoteRequest, fullRequest) {
40
+ const { accountSupports7702, messenger, signal, transaction } = fullRequest;
41
+ const body = await buildServerQuoteRequest(quoteRequest, transaction, messenger, accountSupports7702);
42
+ try {
43
+ log('Request body', body);
44
+ const response = await (0, server_api_1.fetchServerQuote)(messenger, body, signal);
45
+ log('Raw quote response', response);
46
+ const fulfilledResults = response.results.filter(isFulfilledResult);
47
+ const normalized = await Promise.all(fulfilledResults.map((result) => normalizeQuote(result, quoteRequest, messenger)));
48
+ log('Normalized quotes', normalized);
49
+ return normalized;
50
+ }
51
+ catch (error) {
52
+ log('Error fetching quotes', { error });
53
+ return [];
54
+ }
55
+ }
56
+ async function buildServerQuoteRequest(quoteRequest, transaction, messenger, accountSupports7702) {
57
+ const normalizedRequest = (0, perps_1.normalizeServerPerpsRequest)(quoteRequest, transaction);
58
+ const { from, isMaxAmount, isPostQuote, sourceChainId, sourceTokenAddress, sourceTokenAmount, targetAmountMinimum, targetChainId, targetTokenAddress, } = normalizedRequest;
59
+ const useExactInput = (isMaxAmount ?? false) || (isPostQuote ?? false);
60
+ const singleData = getSingleTransactionData(transaction);
61
+ const isHypercore = targetChainId === constants_1.CHAIN_ID_HYPERCORE;
62
+ const isTokenTransfer = !isHypercore && Boolean(singleData?.startsWith(TOKEN_TRANSFER_FOUR_BYTE));
63
+ let recipient = from;
64
+ if (isTokenTransfer && singleData) {
65
+ recipient = decodeTransferRecipient(singleData);
66
+ }
67
+ const supportsGasless = accountSupports7702 && (0, feature_flags_1.isEIP7702Chain)(messenger, sourceChainId);
68
+ const body = {
69
+ source: { chainId: Number(sourceChainId), token: sourceTokenAddress },
70
+ target: { chainId: Number(targetChainId), token: targetTokenAddress },
71
+ amount: useExactInput ? sourceTokenAmount : targetAmountMinimum,
72
+ tradeType: useExactInput
73
+ ? types_1.ServerTradeType.ExactInput
74
+ : types_1.ServerTradeType.ExpectedOutput,
75
+ sender: from,
76
+ recipient,
77
+ slippage: Math.round((0, feature_flags_1.getSlippage)(messenger, sourceChainId, sourceTokenAddress) * 10000),
78
+ supportsGasless,
79
+ };
80
+ const hasNoData = singleData === undefined || singleData === '0x';
81
+ const skipDelegation = hasNoData ||
82
+ isTokenTransfer ||
83
+ isHypercore ||
84
+ (isPostQuote ?? false) ||
85
+ (isMaxAmount ?? false);
86
+ if (!skipDelegation) {
87
+ const delegation = await messenger.call('TransactionPayController:getDelegationTransaction', { transaction });
88
+ body.calls = [
89
+ {
90
+ data: buildTransferData(from, targetAmountMinimum),
91
+ to: targetTokenAddress,
92
+ value: '0x0',
93
+ },
94
+ {
95
+ data: delegation.data,
96
+ to: delegation.to,
97
+ value: delegation.value,
98
+ },
99
+ ];
100
+ if (delegation.authorizationList?.length) {
101
+ body.authorizationList = delegation.authorizationList.map((entry) => ({
102
+ address: entry.address,
103
+ chainId: Number(entry.chainId),
104
+ nonce: Number(entry.nonce),
105
+ r: entry.r,
106
+ s: entry.s,
107
+ yParity: Number(entry.yParity),
108
+ }));
109
+ }
110
+ }
111
+ return body;
112
+ }
113
+ function shouldRequestQuote(quoteRequest) {
114
+ return (quoteRequest.targetAmountMinimum !== '0' ||
115
+ Boolean(quoteRequest.isPostQuote) ||
116
+ Boolean(quoteRequest.isMaxAmount));
117
+ }
118
+ async function normalizeQuote(result, quoteRequest, messenger) {
119
+ const { quote } = result;
120
+ const { gasless } = quote;
121
+ const sourceNetwork = await calculateSourceNetworkCost({
122
+ gasless,
123
+ messenger,
124
+ quoteRequest,
125
+ steps: quote.steps,
126
+ });
127
+ const sourceFiatRate = (0, token_1.getTokenFiatRate)(messenger, quoteRequest.sourceTokenAddress, quoteRequest.sourceChainId);
128
+ const usdToFiatRate = sourceFiatRate
129
+ ? new bignumber_js_1.BigNumber(sourceFiatRate.fiatRate).dividedBy(sourceFiatRate.usdRate)
130
+ : new bignumber_js_1.BigNumber(1);
131
+ const metaMask = (0, amounts_1.getFiatValueFromUsd)(new bignumber_js_1.BigNumber(quote.fees.metamask), usdToFiatRate);
132
+ const provider = (0, amounts_1.getFiatValueFromUsd)(new bignumber_js_1.BigNumber(quote.fees.provider), usdToFiatRate);
133
+ return {
134
+ dust: ZERO_FIAT_VALUE,
135
+ estimatedDuration: quote.duration,
136
+ fees: {
137
+ ...(sourceNetwork.isSourceGasFeeToken
138
+ ? { isSourceGasFeeToken: true }
139
+ : {}),
140
+ metaMask,
141
+ provider,
142
+ sourceNetwork: {
143
+ estimate: sourceNetwork.estimate,
144
+ max: sourceNetwork.max,
145
+ },
146
+ targetNetwork: ZERO_FIAT_VALUE,
147
+ },
148
+ original: {
149
+ client: {
150
+ gasLimits: sourceNetwork.gasLimits,
151
+ is7702: sourceNetwork.is7702,
152
+ maxFeePerGas: sourceNetwork.maxFeePerGas,
153
+ maxPriorityFeePerGas: sourceNetwork.maxPriorityFeePerGas,
154
+ },
155
+ duration: quote.duration,
156
+ fees: quote.fees,
157
+ gasless,
158
+ id: quote.id,
159
+ input: quote.input,
160
+ output: quote.output,
161
+ provider: result.provider,
162
+ steps: quote.steps,
163
+ },
164
+ request: quoteRequest,
165
+ sourceAmount: {
166
+ fiat: sourceFiatRate
167
+ ? new bignumber_js_1.BigNumber(quote.input.formatted)
168
+ .multipliedBy(sourceFiatRate.fiatRate)
169
+ .toString(10)
170
+ : '0',
171
+ human: quote.input.formatted,
172
+ raw: quote.input.raw,
173
+ usd: sourceFiatRate
174
+ ? new bignumber_js_1.BigNumber(quote.input.formatted)
175
+ .multipliedBy(sourceFiatRate.usdRate)
176
+ .toString(10)
177
+ : '0',
178
+ },
179
+ strategy: constants_1.TransactionPayStrategy.Server,
180
+ targetAmount: {
181
+ fiat: '0',
182
+ usd: '0',
183
+ },
184
+ };
185
+ }
186
+ async function calculateSourceNetworkCost({ gasless, messenger, quoteRequest, steps, }) {
187
+ const noFees = {
188
+ estimate: ZERO_AMOUNT,
189
+ gasLimits: [],
190
+ is7702: false,
191
+ max: ZERO_AMOUNT,
192
+ maxFeePerGas: undefined,
193
+ maxPriorityFeePerGas: undefined,
194
+ };
195
+ if (gasless) {
196
+ log('Zeroing source network fees for gasless quote');
197
+ return noFees;
198
+ }
199
+ if (steps.length === 0) {
200
+ log('No quote steps; zeroing source network fees');
201
+ return noFees;
202
+ }
203
+ const { from, sourceChainId, sourceTokenAddress } = quoteRequest;
204
+ const firstStep = steps[0];
205
+ const chainIdHex = (0, controller_utils_1.toHex)(firstStep.chainId);
206
+ const needsGasFeeEstimate = !firstStep.maxFeePerGas && !firstStep.maxPriorityFeePerGas;
207
+ const gasFeeEstimate = needsGasFeeEstimate
208
+ ? (0, gas_1.getGasFee)(chainIdHex, messenger)
209
+ : { maxFeePerGas: undefined, maxPriorityFeePerGas: undefined };
210
+ const maxFeePerGas = firstStep.maxFeePerGas ?? gasFeeEstimate.maxFeePerGas;
211
+ const maxPriorityFeePerGas = firstStep.maxPriorityFeePerGas ?? gasFeeEstimate.maxPriorityFeePerGas;
212
+ const gasTransactions = steps.map((step) => stepToGasTransaction(step, from));
213
+ const gasResult = await (0, quote_gas_1.estimateQuoteGasLimits)({
214
+ fallbackGas: (0, feature_flags_1.getFeatureFlags)(messenger).relayFallbackGas,
215
+ fallbackOnSimulationFailure: true,
216
+ messenger,
217
+ transactions: gasTransactions,
218
+ });
219
+ const { is7702 } = gasResult;
220
+ const gasLimits = is7702
221
+ ? [gasResult.gasLimits[0].max]
222
+ : gasResult.gasLimits.map((gasLimit) => gasLimit.max);
223
+ const estimate = (0, gas_1.calculateGasCost)({
224
+ chainId: chainIdHex,
225
+ gas: gasResult.totalGasEstimate,
226
+ maxFeePerGas: maxFeePerGas ?? '0',
227
+ maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',
228
+ messenger,
229
+ });
230
+ const max = (0, gas_1.calculateGasCost)({
231
+ chainId: chainIdHex,
232
+ gas: gasResult.totalGasLimit,
233
+ isMax: true,
234
+ maxFeePerGas: maxFeePerGas ?? '0',
235
+ maxPriorityFeePerGas: maxPriorityFeePerGas ?? '0',
236
+ messenger,
237
+ });
238
+ const nativeBalance = (0, token_1.getTokenBalance)(messenger, from, sourceChainId, (0, token_1.getNativeToken)(sourceChainId));
239
+ const fees = { maxFeePerGas, maxPriorityFeePerGas };
240
+ if (new bignumber_js_1.BigNumber(nativeBalance).isGreaterThanOrEqualTo(max.raw)) {
241
+ return { estimate, gasLimits, is7702, max, ...fees };
242
+ }
243
+ const eligibility = (0, gas_station_1.getGasStationEligibility)(messenger, sourceChainId);
244
+ if (eligibility.isDisabledChain || !eligibility.chainSupportsGasStation) {
245
+ log('Skipping gas station for source network', {
246
+ isDisabledChain: eligibility.isDisabledChain,
247
+ sourceChainId,
248
+ supportsGasStation: eligibility.chainSupportsGasStation,
249
+ });
250
+ return { estimate, gasLimits, is7702, max, ...fees };
251
+ }
252
+ log('Checking gas fee tokens due to insufficient native balance', {
253
+ max: max.raw,
254
+ nativeBalance,
255
+ });
256
+ const gasFeeTokenCost = await (0, gas_station_1.getGasStationCostInSourceTokenRaw)({
257
+ firstStepData: {
258
+ data: firstStep.data,
259
+ to: firstStep.to,
260
+ value: firstStep.value,
261
+ },
262
+ messenger,
263
+ request: {
264
+ from,
265
+ sourceChainId,
266
+ sourceTokenAddress,
267
+ },
268
+ totalGasEstimate: gasResult.totalGasEstimate,
269
+ totalItemCount: steps.length,
270
+ });
271
+ if (!gasFeeTokenCost) {
272
+ return { estimate, gasLimits, is7702, max, ...fees };
273
+ }
274
+ log('Using gas fee token for source network', { gasFeeTokenCost });
275
+ return {
276
+ estimate: gasFeeTokenCost,
277
+ gasLimits,
278
+ is7702,
279
+ isSourceGasFeeToken: true,
280
+ max: gasFeeTokenCost,
281
+ ...fees,
282
+ };
283
+ }
284
+ function stepToGasTransaction(step, from) {
285
+ return {
286
+ chainId: (0, controller_utils_1.toHex)(step.chainId),
287
+ data: step.data,
288
+ from,
289
+ to: step.to,
290
+ value: step.value,
291
+ };
292
+ }
293
+ function getSingleTransactionData(transaction) {
294
+ for (const nested of transaction.nestedTransactions ?? []) {
295
+ if (nested.data && nested.data !== '0x') {
296
+ return nested.data;
297
+ }
298
+ }
299
+ return transaction.txParams?.data;
300
+ }
301
+ function isFulfilledResult(result) {
302
+ return (result.quote?.id !== undefined &&
303
+ result.quote.input !== undefined &&
304
+ result.quote.output !== undefined);
305
+ }
306
+ function decodeTransferRecipient(data) {
307
+ return TRANSFER_INTERFACE.decodeFunctionData('transfer', data).to.toLowerCase();
308
+ }
309
+ function buildTransferData(recipient, amountRaw) {
310
+ return TRANSFER_INTERFACE.encodeFunctionData('transfer', [
311
+ recipient,
312
+ amountRaw,
313
+ ]);
314
+ }
315
+ //# sourceMappingURL=server-quotes.cjs.map