@metamask/transaction-pay-controller 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +20 -0
  3. package/README.md +19 -0
  4. package/dist/TransactionPayController.cjs +96 -0
  5. package/dist/TransactionPayController.cjs.map +1 -0
  6. package/dist/TransactionPayController.d.cts +9 -0
  7. package/dist/TransactionPayController.d.cts.map +1 -0
  8. package/dist/TransactionPayController.d.mts +9 -0
  9. package/dist/TransactionPayController.d.mts.map +1 -0
  10. package/dist/TransactionPayController.mjs +93 -0
  11. package/dist/TransactionPayController.mjs.map +1 -0
  12. package/dist/actions/update-payment-token.cjs +79 -0
  13. package/dist/actions/update-payment-token.cjs.map +1 -0
  14. package/dist/actions/update-payment-token.d.cts +14 -0
  15. package/dist/actions/update-payment-token.d.cts.map +1 -0
  16. package/dist/actions/update-payment-token.d.mts +14 -0
  17. package/dist/actions/update-payment-token.d.mts.map +1 -0
  18. package/dist/actions/update-payment-token.mjs +75 -0
  19. package/dist/actions/update-payment-token.mjs.map +1 -0
  20. package/dist/constants.cjs +12 -0
  21. package/dist/constants.cjs.map +1 -0
  22. package/dist/constants.d.cts +8 -0
  23. package/dist/constants.d.cts.map +1 -0
  24. package/dist/constants.d.mts +8 -0
  25. package/dist/constants.d.mts.map +1 -0
  26. package/dist/constants.mjs +9 -0
  27. package/dist/constants.mjs.map +1 -0
  28. package/dist/helpers/TransactionPayPublishHook.cjs +61 -0
  29. package/dist/helpers/TransactionPayPublishHook.cjs.map +1 -0
  30. package/dist/helpers/TransactionPayPublishHook.d.cts +12 -0
  31. package/dist/helpers/TransactionPayPublishHook.d.cts.map +1 -0
  32. package/dist/helpers/TransactionPayPublishHook.d.mts +12 -0
  33. package/dist/helpers/TransactionPayPublishHook.d.mts.map +1 -0
  34. package/dist/helpers/TransactionPayPublishHook.mjs +57 -0
  35. package/dist/helpers/TransactionPayPublishHook.mjs.map +1 -0
  36. package/dist/index.cjs +10 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +6 -0
  39. package/dist/index.d.cts.map +1 -0
  40. package/dist/index.d.mts +6 -0
  41. package/dist/index.d.mts.map +1 -0
  42. package/dist/index.mjs +4 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/dist/logger.cjs +8 -0
  45. package/dist/logger.cjs.map +1 -0
  46. package/dist/logger.d.cts +5 -0
  47. package/dist/logger.d.cts.map +1 -0
  48. package/dist/logger.d.mts +5 -0
  49. package/dist/logger.d.mts.map +1 -0
  50. package/dist/logger.mjs +5 -0
  51. package/dist/logger.mjs.map +1 -0
  52. package/dist/strategy/bridge/BridgeStrategy.cjs +30 -0
  53. package/dist/strategy/bridge/BridgeStrategy.cjs.map +1 -0
  54. package/dist/strategy/bridge/BridgeStrategy.d.cts +11 -0
  55. package/dist/strategy/bridge/BridgeStrategy.d.cts.map +1 -0
  56. package/dist/strategy/bridge/BridgeStrategy.d.mts +11 -0
  57. package/dist/strategy/bridge/BridgeStrategy.d.mts.map +1 -0
  58. package/dist/strategy/bridge/BridgeStrategy.mjs +26 -0
  59. package/dist/strategy/bridge/BridgeStrategy.mjs.map +1 -0
  60. package/dist/strategy/bridge/bridge-quotes.cjs +386 -0
  61. package/dist/strategy/bridge/bridge-quotes.cjs.map +1 -0
  62. package/dist/strategy/bridge/bridge-quotes.d.cts +35 -0
  63. package/dist/strategy/bridge/bridge-quotes.d.cts.map +1 -0
  64. package/dist/strategy/bridge/bridge-quotes.d.mts +35 -0
  65. package/dist/strategy/bridge/bridge-quotes.d.mts.map +1 -0
  66. package/dist/strategy/bridge/bridge-quotes.mjs +380 -0
  67. package/dist/strategy/bridge/bridge-quotes.mjs.map +1 -0
  68. package/dist/strategy/bridge/bridge-submit.cjs +155 -0
  69. package/dist/strategy/bridge/bridge-submit.cjs.map +1 -0
  70. package/dist/strategy/bridge/bridge-submit.d.cts +19 -0
  71. package/dist/strategy/bridge/bridge-submit.d.cts.map +1 -0
  72. package/dist/strategy/bridge/bridge-submit.d.mts +19 -0
  73. package/dist/strategy/bridge/bridge-submit.d.mts.map +1 -0
  74. package/dist/strategy/bridge/bridge-submit.mjs +152 -0
  75. package/dist/strategy/bridge/bridge-submit.mjs.map +1 -0
  76. package/dist/strategy/bridge/types.cjs +3 -0
  77. package/dist/strategy/bridge/types.cjs.map +1 -0
  78. package/dist/strategy/bridge/types.d.cts +27 -0
  79. package/dist/strategy/bridge/types.d.cts.map +1 -0
  80. package/dist/strategy/bridge/types.d.mts +27 -0
  81. package/dist/strategy/bridge/types.d.mts.map +1 -0
  82. package/dist/strategy/bridge/types.mjs +2 -0
  83. package/dist/strategy/bridge/types.mjs.map +1 -0
  84. package/dist/strategy/relay/RelayStrategy.cjs +15 -0
  85. package/dist/strategy/relay/RelayStrategy.cjs.map +1 -0
  86. package/dist/strategy/relay/RelayStrategy.d.cts +9 -0
  87. package/dist/strategy/relay/RelayStrategy.d.cts.map +1 -0
  88. package/dist/strategy/relay/RelayStrategy.d.mts +9 -0
  89. package/dist/strategy/relay/RelayStrategy.d.mts.map +1 -0
  90. package/dist/strategy/relay/RelayStrategy.mjs +11 -0
  91. package/dist/strategy/relay/RelayStrategy.mjs.map +1 -0
  92. package/dist/strategy/relay/constants.cjs +9 -0
  93. package/dist/strategy/relay/constants.cjs.map +1 -0
  94. package/dist/strategy/relay/constants.d.cts +6 -0
  95. package/dist/strategy/relay/constants.d.cts.map +1 -0
  96. package/dist/strategy/relay/constants.d.mts +6 -0
  97. package/dist/strategy/relay/constants.d.mts.map +1 -0
  98. package/dist/strategy/relay/constants.mjs +6 -0
  99. package/dist/strategy/relay/constants.mjs.map +1 -0
  100. package/dist/strategy/relay/relay-quotes.cjs +210 -0
  101. package/dist/strategy/relay/relay-quotes.cjs.map +1 -0
  102. package/dist/strategy/relay/relay-quotes.d.cts +10 -0
  103. package/dist/strategy/relay/relay-quotes.d.cts.map +1 -0
  104. package/dist/strategy/relay/relay-quotes.d.mts +10 -0
  105. package/dist/strategy/relay/relay-quotes.d.mts.map +1 -0
  106. package/dist/strategy/relay/relay-quotes.mjs +206 -0
  107. package/dist/strategy/relay/relay-quotes.mjs.map +1 -0
  108. package/dist/strategy/relay/relay-submit.cjs +137 -0
  109. package/dist/strategy/relay/relay-submit.cjs.map +1 -0
  110. package/dist/strategy/relay/relay-submit.d.cts +13 -0
  111. package/dist/strategy/relay/relay-submit.d.cts.map +1 -0
  112. package/dist/strategy/relay/relay-submit.d.mts +13 -0
  113. package/dist/strategy/relay/relay-submit.d.mts.map +1 -0
  114. package/dist/strategy/relay/relay-submit.mjs +133 -0
  115. package/dist/strategy/relay/relay-submit.mjs.map +1 -0
  116. package/dist/strategy/relay/types.cjs +3 -0
  117. package/dist/strategy/relay/types.cjs.map +1 -0
  118. package/dist/strategy/relay/types.d.cts +52 -0
  119. package/dist/strategy/relay/types.d.cts.map +1 -0
  120. package/dist/strategy/relay/types.d.mts +52 -0
  121. package/dist/strategy/relay/types.d.mts.map +1 -0
  122. package/dist/strategy/relay/types.mjs +2 -0
  123. package/dist/strategy/relay/types.mjs.map +1 -0
  124. package/dist/strategy/test/TestStrategy.cjs +48 -0
  125. package/dist/strategy/test/TestStrategy.cjs.map +1 -0
  126. package/dist/strategy/test/TestStrategy.d.cts +9 -0
  127. package/dist/strategy/test/TestStrategy.d.cts.map +1 -0
  128. package/dist/strategy/test/TestStrategy.d.mts +9 -0
  129. package/dist/strategy/test/TestStrategy.d.mts.map +1 -0
  130. package/dist/strategy/test/TestStrategy.mjs +44 -0
  131. package/dist/strategy/test/TestStrategy.mjs.map +1 -0
  132. package/dist/tests/messenger-mock.cjs +76 -0
  133. package/dist/tests/messenger-mock.cjs.map +1 -0
  134. package/dist/tests/messenger-mock.d.cts +215 -0
  135. package/dist/tests/messenger-mock.d.cts.map +1 -0
  136. package/dist/tests/messenger-mock.d.mts +215 -0
  137. package/dist/tests/messenger-mock.d.mts.map +1 -0
  138. package/dist/tests/messenger-mock.mjs +72 -0
  139. package/dist/tests/messenger-mock.mjs.map +1 -0
  140. package/dist/types.cjs +3 -0
  141. package/dist/types.cjs.map +1 -0
  142. package/dist/types.d.cts +264 -0
  143. package/dist/types.d.cts.map +1 -0
  144. package/dist/types.d.mts +264 -0
  145. package/dist/types.d.mts.map +1 -0
  146. package/dist/types.mjs +2 -0
  147. package/dist/types.mjs.map +1 -0
  148. package/dist/utils/gas.cjs +87 -0
  149. package/dist/utils/gas.cjs.map +1 -0
  150. package/dist/utils/gas.d.cts +33 -0
  151. package/dist/utils/gas.d.cts.map +1 -0
  152. package/dist/utils/gas.d.mts +33 -0
  153. package/dist/utils/gas.d.mts.map +1 -0
  154. package/dist/utils/gas.mjs +82 -0
  155. package/dist/utils/gas.mjs.map +1 -0
  156. package/dist/utils/quotes.cjs +168 -0
  157. package/dist/utils/quotes.cjs.map +1 -0
  158. package/dist/utils/quotes.d.cts +21 -0
  159. package/dist/utils/quotes.d.cts.map +1 -0
  160. package/dist/utils/quotes.d.mts +21 -0
  161. package/dist/utils/quotes.d.mts.map +1 -0
  162. package/dist/utils/quotes.mjs +163 -0
  163. package/dist/utils/quotes.mjs.map +1 -0
  164. package/dist/utils/required-tokens.cjs +179 -0
  165. package/dist/utils/required-tokens.cjs.map +1 -0
  166. package/dist/utils/required-tokens.d.cts +11 -0
  167. package/dist/utils/required-tokens.d.cts.map +1 -0
  168. package/dist/utils/required-tokens.d.mts +11 -0
  169. package/dist/utils/required-tokens.d.mts.map +1 -0
  170. package/dist/utils/required-tokens.mjs +175 -0
  171. package/dist/utils/required-tokens.mjs.map +1 -0
  172. package/dist/utils/source-amounts.cjs +72 -0
  173. package/dist/utils/source-amounts.cjs.map +1 -0
  174. package/dist/utils/source-amounts.d.cts +11 -0
  175. package/dist/utils/source-amounts.d.cts.map +1 -0
  176. package/dist/utils/source-amounts.d.mts +11 -0
  177. package/dist/utils/source-amounts.d.mts.map +1 -0
  178. package/dist/utils/source-amounts.mjs +68 -0
  179. package/dist/utils/source-amounts.mjs.map +1 -0
  180. package/dist/utils/strategy.cjs +39 -0
  181. package/dist/utils/strategy.cjs.map +1 -0
  182. package/dist/utils/strategy.d.cts +19 -0
  183. package/dist/utils/strategy.d.cts.map +1 -0
  184. package/dist/utils/strategy.d.mts +19 -0
  185. package/dist/utils/strategy.d.mts.map +1 -0
  186. package/dist/utils/strategy.mjs +34 -0
  187. package/dist/utils/strategy.mjs.map +1 -0
  188. package/dist/utils/token.cjs +161 -0
  189. package/dist/utils/token.cjs.map +1 -0
  190. package/dist/utils/token.d.cts +53 -0
  191. package/dist/utils/token.d.cts.map +1 -0
  192. package/dist/utils/token.d.mts +53 -0
  193. package/dist/utils/token.d.mts.map +1 -0
  194. package/dist/utils/token.mjs +154 -0
  195. package/dist/utils/token.mjs.map +1 -0
  196. package/dist/utils/totals.cjs +69 -0
  197. package/dist/utils/totals.cjs.map +1 -0
  198. package/dist/utils/totals.d.cts +11 -0
  199. package/dist/utils/totals.d.cts.map +1 -0
  200. package/dist/utils/totals.d.mts +11 -0
  201. package/dist/utils/totals.d.mts.map +1 -0
  202. package/dist/utils/totals.mjs +65 -0
  203. package/dist/utils/totals.mjs.map +1 -0
  204. package/dist/utils/transaction.cjs +132 -0
  205. package/dist/utils/transaction.cjs.map +1 -0
  206. package/dist/utils/transaction.d.cts +42 -0
  207. package/dist/utils/transaction.d.cts.map +1 -0
  208. package/dist/utils/transaction.d.mts +42 -0
  209. package/dist/utils/transaction.d.mts.map +1 -0
  210. package/dist/utils/transaction.mjs +126 -0
  211. package/dist/utils/transaction.mjs.map +1 -0
  212. package/package.json +97 -0
@@ -0,0 +1,19 @@
1
+ import type { TransactionMeta } from "@metamask/transaction-controller";
2
+ import type { Hex } from "@metamask/utils";
3
+ import type { TransactionPayBridgeQuote } from "./types.mjs";
4
+ import type { TransactionPayControllerMessenger, TransactionPayQuote } from "../../types.mjs";
5
+ export type SubmitBridgeQuotesRequest = {
6
+ from: Hex;
7
+ isSmartTransaction: (chainId: Hex) => boolean;
8
+ messenger: TransactionPayControllerMessenger;
9
+ quotes: TransactionPayQuote<TransactionPayBridgeQuote>[];
10
+ transaction: TransactionMeta;
11
+ };
12
+ /**
13
+ * Submit multiple bridge quotes sequentially and wait for their completion.
14
+ *
15
+ * @param request - The request object containing necessary data.
16
+ * @returns An object containing the transaction hash if available.
17
+ */
18
+ export declare function submitBridgeQuotes(request: SubmitBridgeQuotesRequest): Promise<void>;
19
+ //# sourceMappingURL=bridge-submit.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-submit.d.mts","sourceRoot":"","sources":["../../../src/strategy/bridge/bridge-submit.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,yCAAyC;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,wBAAwB;AAK3C,OAAO,KAAK,EAAE,yBAAyB,EAAE,oBAAgB;AAEzD,OAAO,KAAK,EACV,iCAAiC,EACjC,mBAAmB,EACpB,wBAAoB;AAQrB,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,GAAG,CAAC;IACV,kBAAkB,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC;IAC9C,SAAS,EAAE,iCAAiC,CAAC;IAC7C,MAAM,EAAE,mBAAmB,CAAC,yBAAyB,CAAC,EAAE,CAAC;IACzD,WAAW,EAAE,eAAe,CAAC;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAmCf"}
@@ -0,0 +1,152 @@
1
+ import { StatusTypes } from "@metamask/bridge-controller";
2
+ import { toHex } from "@metamask/controller-utils";
3
+ import { createModuleLogger } from "@metamask/utils";
4
+ import $lodash from "lodash";
5
+ const { cloneDeep } = $lodash;
6
+ import { refreshQuote } from "./bridge-quotes.mjs";
7
+ import { projectLogger } from "../../logger.mjs";
8
+ import { updateTransaction, waitForTransactionConfirmed } from "../../utils/transaction.mjs";
9
+ const log = createModuleLogger(projectLogger, 'bridge-strategy');
10
+ /**
11
+ * Submit multiple bridge quotes sequentially and wait for their completion.
12
+ *
13
+ * @param request - The request object containing necessary data.
14
+ * @returns An object containing the transaction hash if available.
15
+ */
16
+ export async function submitBridgeQuotes(request) {
17
+ const { quotes, messenger, transaction } = request;
18
+ if (!quotes?.length) {
19
+ log('No quotes found');
20
+ return;
21
+ }
22
+ // Currently we only support a single source meaning we only check the first quote.
23
+ const isSameChain = quotes[0].original.quote.srcChainId ===
24
+ quotes[0].original.quote.destChainId;
25
+ if (isSameChain) {
26
+ log('Ignoring quotes as source is same chain', quotes[0].original.quote.srcChainId);
27
+ return;
28
+ }
29
+ let index = 0;
30
+ for (const quote of quotes) {
31
+ log('Submitting bridge', index, quote);
32
+ const finalQuote = index > 0
33
+ ? await refreshQuote(quote, messenger, transaction)
34
+ : quote.original;
35
+ await submitBridgeTransaction(request, finalQuote);
36
+ index += 1;
37
+ }
38
+ }
39
+ /**
40
+ * Submit a bridge transaction and wait for it to complete.
41
+ *
42
+ * @param request - The request object containing necessary data.
43
+ * @param originalQuote - The original quote to submit.
44
+ */
45
+ async function submitBridgeTransaction(request, originalQuote) {
46
+ const { isSmartTransaction, messenger, from, transaction } = request;
47
+ const quote = cloneDeep(originalQuote);
48
+ const sourceChainId = toHex(quote.quote.srcChainId);
49
+ const isSTX = isSmartTransaction(sourceChainId);
50
+ const requiredTransactionIds = [];
51
+ const bridgeTransactionIdCollector = collectTransactionIds(sourceChainId, from, messenger, (id) => updateTransaction({
52
+ transactionId: transaction.id,
53
+ messenger,
54
+ note: 'Add required transaction ID',
55
+ }, (transactionMeta) => {
56
+ if (!transactionMeta.requiredTransactionIds) {
57
+ transactionMeta.requiredTransactionIds = [];
58
+ }
59
+ transactionMeta?.requiredTransactionIds.push(id);
60
+ requiredTransactionIds.push(id);
61
+ }));
62
+ const tokenAmountValues = {
63
+ amount: '0',
64
+ valueInCurrency: null,
65
+ usd: null,
66
+ };
67
+ const metadata = {
68
+ gasFee: {
69
+ effective: tokenAmountValues,
70
+ max: tokenAmountValues,
71
+ total: tokenAmountValues,
72
+ },
73
+ totalNetworkFee: tokenAmountValues,
74
+ totalMaxNetworkFee: tokenAmountValues,
75
+ toTokenAmount: tokenAmountValues,
76
+ minToTokenAmount: tokenAmountValues,
77
+ adjustedReturn: tokenAmountValues,
78
+ sentAmount: tokenAmountValues,
79
+ swapRate: '0',
80
+ cost: tokenAmountValues,
81
+ };
82
+ const result = await messenger.call('BridgeStatusController:submitTx', from, { ...quote, ...metadata }, isSTX);
83
+ bridgeTransactionIdCollector.end();
84
+ log('Bridge transaction submitted', {
85
+ requiredTransactionIds,
86
+ result,
87
+ });
88
+ await Promise.all(requiredTransactionIds.map((id) => waitForTransactionConfirmed(id, messenger)));
89
+ log('All required transactions confirmed', requiredTransactionIds);
90
+ const { id: bridgeTransactionId } = result;
91
+ log('Waiting for bridge completion', bridgeTransactionId);
92
+ await waitForBridgeCompletion(bridgeTransactionId, messenger);
93
+ }
94
+ /**
95
+ * Wait for a bridge transaction to complete.
96
+ *
97
+ * @param bridgeTransactionId - The bridge transaction ID.
98
+ * @param messenger - The controller messenger.
99
+ */
100
+ async function waitForBridgeCompletion(bridgeTransactionId, messenger) {
101
+ return new Promise((resolve, reject) => {
102
+ const isComplete = (item, fn) => {
103
+ const status = item?.status?.status;
104
+ log('Checking bridge status', status ?? 'missing');
105
+ if (status === StatusTypes.COMPLETE) {
106
+ fn?.();
107
+ resolve();
108
+ return true;
109
+ }
110
+ if (status === StatusTypes.FAILED) {
111
+ fn?.();
112
+ reject(new Error('Bridge failed'));
113
+ return true;
114
+ }
115
+ return false;
116
+ };
117
+ const initialState = messenger.call('BridgeStatusController:getState');
118
+ const initialTx = initialState.txHistory[bridgeTransactionId];
119
+ if (isComplete(initialTx)) {
120
+ return;
121
+ }
122
+ const handler = (bridgeHistory) => {
123
+ const unsubscribe = () => messenger.unsubscribe('BridgeStatusController:stateChange', handler);
124
+ isComplete(bridgeHistory, unsubscribe);
125
+ };
126
+ messenger.subscribe('BridgeStatusController:stateChange', handler, (state) => state.txHistory[bridgeTransactionId]);
127
+ });
128
+ }
129
+ /**
130
+ * Collect all new transactions until `end` is called.
131
+ *
132
+ * @param chainId - The chain ID to filter transactions by.
133
+ * @param from - The address to filter transactions by.
134
+ * @param messenger - The controller messenger.
135
+ * @param onTransaction - Callback called with each matching transaction ID.
136
+ * @returns An object with an `end` method to stop collecting transactions.
137
+ */
138
+ function collectTransactionIds(chainId, from, messenger, onTransaction) {
139
+ const listener = (tx) => {
140
+ if (tx.chainId !== chainId ||
141
+ tx.txParams.from.toLowerCase() !== from.toLowerCase()) {
142
+ return;
143
+ }
144
+ onTransaction(tx.id);
145
+ };
146
+ messenger.subscribe('TransactionController:unapprovedTransactionAdded', listener);
147
+ const end = () => {
148
+ messenger.unsubscribe('TransactionController:unapprovedTransactionAdded', listener);
149
+ };
150
+ return { end };
151
+ }
152
+ //# sourceMappingURL=bridge-submit.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-submit.mjs","sourceRoot":"","sources":["../../../src/strategy/bridge/bridge-submit.ts"],"names":[],"mappings":"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","sourcesContent":["import { StatusTypes } from '@metamask/bridge-controller';\nimport type { QuoteMetadata } from '@metamask/bridge-controller';\nimport type { QuoteResponse } from '@metamask/bridge-controller';\nimport type { BridgeHistoryItem } from '@metamask/bridge-status-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TransactionMeta } from '@metamask/transaction-controller';\nimport type { Hex } from '@metamask/utils';\nimport { createModuleLogger } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\n\nimport { refreshQuote } from './bridge-quotes';\nimport type { TransactionPayBridgeQuote } from './types';\nimport { projectLogger } from '../../logger';\nimport type {\n TransactionPayControllerMessenger,\n TransactionPayQuote,\n} from '../../types';\nimport {\n updateTransaction,\n waitForTransactionConfirmed,\n} from '../../utils/transaction';\n\nconst log = createModuleLogger(projectLogger, 'bridge-strategy');\n\nexport type SubmitBridgeQuotesRequest = {\n from: Hex;\n isSmartTransaction: (chainId: Hex) => boolean;\n messenger: TransactionPayControllerMessenger;\n quotes: TransactionPayQuote<TransactionPayBridgeQuote>[];\n transaction: TransactionMeta;\n};\n\n/**\n * Submit multiple bridge quotes sequentially and wait for their completion.\n *\n * @param request - The request object containing necessary data.\n * @returns An object containing the transaction hash if available.\n */\nexport async function submitBridgeQuotes(\n request: SubmitBridgeQuotesRequest,\n): Promise<void> {\n const { quotes, messenger, transaction } = request;\n\n if (!quotes?.length) {\n log('No quotes found');\n return;\n }\n\n // Currently we only support a single source meaning we only check the first quote.\n const isSameChain =\n quotes[0].original.quote.srcChainId ===\n quotes[0].original.quote.destChainId;\n\n if (isSameChain) {\n log(\n 'Ignoring quotes as source is same chain',\n quotes[0].original.quote.srcChainId,\n );\n return;\n }\n\n let index = 0;\n\n for (const quote of quotes) {\n log('Submitting bridge', index, quote);\n\n const finalQuote =\n index > 0\n ? await refreshQuote(quote, messenger as never, transaction)\n : quote.original;\n\n await submitBridgeTransaction(request, finalQuote);\n\n index += 1;\n }\n}\n\n/**\n * Submit a bridge transaction and wait for it to complete.\n *\n * @param request - The request object containing necessary data.\n * @param originalQuote - The original quote to submit.\n */\nasync function submitBridgeTransaction(\n request: SubmitBridgeQuotesRequest,\n originalQuote: QuoteResponse,\n): Promise<void> {\n const { isSmartTransaction, messenger, from, transaction } = request;\n const quote = cloneDeep(originalQuote);\n const sourceChainId = toHex(quote.quote.srcChainId);\n const isSTX = isSmartTransaction(sourceChainId);\n const requiredTransactionIds: string[] = [];\n\n const bridgeTransactionIdCollector = collectTransactionIds(\n sourceChainId,\n from,\n messenger,\n (id) =>\n updateTransaction(\n {\n transactionId: transaction.id,\n messenger,\n note: 'Add required transaction ID',\n },\n (transactionMeta) => {\n if (!transactionMeta.requiredTransactionIds) {\n transactionMeta.requiredTransactionIds = [];\n }\n\n transactionMeta?.requiredTransactionIds.push(id);\n requiredTransactionIds.push(id);\n },\n ),\n );\n\n const tokenAmountValues = {\n amount: '0',\n valueInCurrency: null,\n usd: null,\n };\n\n const metadata: QuoteMetadata = {\n gasFee: {\n effective: tokenAmountValues,\n max: tokenAmountValues,\n total: tokenAmountValues,\n },\n totalNetworkFee: tokenAmountValues,\n totalMaxNetworkFee: tokenAmountValues,\n toTokenAmount: tokenAmountValues,\n minToTokenAmount: tokenAmountValues,\n adjustedReturn: tokenAmountValues,\n sentAmount: tokenAmountValues,\n swapRate: '0',\n cost: tokenAmountValues,\n };\n\n const result = await messenger.call(\n 'BridgeStatusController:submitTx',\n from,\n { ...quote, ...metadata },\n isSTX,\n );\n\n bridgeTransactionIdCollector.end();\n\n log('Bridge transaction submitted', {\n requiredTransactionIds,\n result,\n });\n\n await Promise.all(\n requiredTransactionIds.map((id) =>\n waitForTransactionConfirmed(id, messenger),\n ),\n );\n\n log('All required transactions confirmed', requiredTransactionIds);\n\n const { id: bridgeTransactionId } = result;\n\n log('Waiting for bridge completion', bridgeTransactionId);\n\n await waitForBridgeCompletion(bridgeTransactionId, messenger);\n}\n\n/**\n * Wait for a bridge transaction to complete.\n *\n * @param bridgeTransactionId - The bridge transaction ID.\n * @param messenger - The controller messenger.\n */\nasync function waitForBridgeCompletion(\n bridgeTransactionId: string,\n messenger: TransactionPayControllerMessenger,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const isComplete = (item?: BridgeHistoryItem, fn?: () => void) => {\n const status = item?.status?.status;\n\n log('Checking bridge status', status ?? 'missing');\n\n if (status === StatusTypes.COMPLETE) {\n fn?.();\n resolve();\n return true;\n }\n\n if (status === StatusTypes.FAILED) {\n fn?.();\n reject(new Error('Bridge failed'));\n return true;\n }\n\n return false;\n };\n\n const initialState = messenger.call('BridgeStatusController:getState');\n\n const initialTx = initialState.txHistory[bridgeTransactionId];\n\n if (isComplete(initialTx)) {\n return;\n }\n\n const handler = (bridgeHistory?: BridgeHistoryItem) => {\n const unsubscribe = () =>\n messenger.unsubscribe('BridgeStatusController:stateChange', handler);\n\n isComplete(bridgeHistory, unsubscribe);\n };\n\n messenger.subscribe(\n 'BridgeStatusController:stateChange',\n handler,\n (state) => state.txHistory[bridgeTransactionId],\n );\n });\n}\n\n/**\n * Collect all new transactions until `end` is called.\n *\n * @param chainId - The chain ID to filter transactions by.\n * @param from - The address to filter transactions by.\n * @param messenger - The controller messenger.\n * @param onTransaction - Callback called with each matching transaction ID.\n * @returns An object with an `end` method to stop collecting transactions.\n */\nfunction collectTransactionIds(\n chainId: Hex,\n from: Hex,\n messenger: TransactionPayControllerMessenger,\n onTransaction: (transactionId: string) => void,\n): { end: () => void } {\n const listener = (tx: TransactionMeta) => {\n if (\n tx.chainId !== chainId ||\n tx.txParams.from.toLowerCase() !== from.toLowerCase()\n ) {\n return;\n }\n\n onTransaction(tx.id);\n };\n\n messenger.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n listener,\n );\n\n const end = () => {\n messenger.unsubscribe(\n 'TransactionController:unapprovedTransactionAdded',\n listener,\n );\n };\n\n return { end };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.cjs","sourceRoot":"","sources":["../../../src/strategy/bridge/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { QuoteResponse } from '@metamask/bridge-controller';\n\nimport type { QuoteRequest } from '../../types';\n\nexport type TransactionPayBridgeQuote = QuoteResponse & {\n metrics?: {\n attempts: number;\n buffer: number;\n latency: number;\n };\n request: BridgeQuoteRequest;\n};\n\nexport type BridgeQuoteRequest = QuoteRequest & {\n attemptsMax: number;\n bufferInitial: number;\n bufferStep: number;\n bufferSubsequent: number;\n slippage: number;\n sourceBalanceRaw: string;\n};\n\nexport type BridgeFeatureFlags = {\n chains?: {\n [chainId: number]: {\n refreshRate?: number;\n };\n };\n refreshRate?: number;\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import type { QuoteResponse } from "@metamask/bridge-controller";
2
+ import type { QuoteRequest } from "../../types.cjs";
3
+ export type TransactionPayBridgeQuote = QuoteResponse & {
4
+ metrics?: {
5
+ attempts: number;
6
+ buffer: number;
7
+ latency: number;
8
+ };
9
+ request: BridgeQuoteRequest;
10
+ };
11
+ export type BridgeQuoteRequest = QuoteRequest & {
12
+ attemptsMax: number;
13
+ bufferInitial: number;
14
+ bufferStep: number;
15
+ bufferSubsequent: number;
16
+ slippage: number;
17
+ sourceBalanceRaw: string;
18
+ };
19
+ export type BridgeFeatureFlags = {
20
+ chains?: {
21
+ [chainId: number]: {
22
+ refreshRate?: number;
23
+ };
24
+ };
25
+ refreshRate?: number;
26
+ };
27
+ //# sourceMappingURL=types.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.cts","sourceRoot":"","sources":["../../../src/strategy/bridge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oCAAoC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD,MAAM,MAAM,yBAAyB,GAAG,aAAa,GAAG;IACtD,OAAO,CAAC,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,CAAC,EAAE;QACP,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { QuoteResponse } from "@metamask/bridge-controller";
2
+ import type { QuoteRequest } from "../../types.mjs";
3
+ export type TransactionPayBridgeQuote = QuoteResponse & {
4
+ metrics?: {
5
+ attempts: number;
6
+ buffer: number;
7
+ latency: number;
8
+ };
9
+ request: BridgeQuoteRequest;
10
+ };
11
+ export type BridgeQuoteRequest = QuoteRequest & {
12
+ attemptsMax: number;
13
+ bufferInitial: number;
14
+ bufferStep: number;
15
+ bufferSubsequent: number;
16
+ slippage: number;
17
+ sourceBalanceRaw: string;
18
+ };
19
+ export type BridgeFeatureFlags = {
20
+ chains?: {
21
+ [chainId: number]: {
22
+ refreshRate?: number;
23
+ };
24
+ };
25
+ refreshRate?: number;
26
+ };
27
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.mts","sourceRoot":"","sources":["../../../src/strategy/bridge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oCAAoC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAoB;AAEhD,MAAM,MAAM,yBAAyB,GAAG,aAAa,GAAG;IACtD,OAAO,CAAC,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,CAAC,EAAE;QACP,CAAC,OAAO,EAAE,MAAM,GAAG;YACjB,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../../src/strategy/bridge/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { QuoteResponse } from '@metamask/bridge-controller';\n\nimport type { QuoteRequest } from '../../types';\n\nexport type TransactionPayBridgeQuote = QuoteResponse & {\n metrics?: {\n attempts: number;\n buffer: number;\n latency: number;\n };\n request: BridgeQuoteRequest;\n};\n\nexport type BridgeQuoteRequest = QuoteRequest & {\n attemptsMax: number;\n bufferInitial: number;\n bufferStep: number;\n bufferSubsequent: number;\n slippage: number;\n sourceBalanceRaw: string;\n};\n\nexport type BridgeFeatureFlags = {\n chains?: {\n [chainId: number]: {\n refreshRate?: number;\n };\n };\n refreshRate?: number;\n};\n"]}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RelayStrategy = void 0;
4
+ const relay_quotes_1 = require("./relay-quotes.cjs");
5
+ const relay_submit_1 = require("./relay-submit.cjs");
6
+ class RelayStrategy {
7
+ async getQuotes(request) {
8
+ return (0, relay_quotes_1.getRelayQuotes)(request);
9
+ }
10
+ async execute(request) {
11
+ return await (0, relay_submit_1.submitRelayQuotes)(request);
12
+ }
13
+ }
14
+ exports.RelayStrategy = RelayStrategy;
15
+ //# sourceMappingURL=RelayStrategy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelayStrategy.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/RelayStrategy.ts"],"names":[],"mappings":";;;AAAA,qDAAgD;AAChD,qDAAmD;AAQnD,MAAa,aAAa;IACxB,KAAK,CAAC,SAAS,CAAC,OAAoC;QAClD,OAAO,IAAA,6BAAc,EAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAA8C;QAC1D,OAAO,MAAM,IAAA,gCAAiB,EAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;CACF;AARD,sCAQC","sourcesContent":["import { getRelayQuotes } from './relay-quotes';\nimport { submitRelayQuotes } from './relay-submit';\nimport type { RelayQuote } from './types';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n} from '../../types';\n\nexport class RelayStrategy implements PayStrategy<RelayQuote> {\n async getQuotes(request: PayStrategyGetQuotesRequest) {\n return getRelayQuotes(request);\n }\n\n async execute(request: PayStrategyExecuteRequest<RelayQuote>) {\n return await submitRelayQuotes(request);\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { RelayQuote } from "./types.cjs";
2
+ import type { PayStrategy, PayStrategyExecuteRequest, PayStrategyGetQuotesRequest } from "../../types.cjs";
3
+ export declare class RelayStrategy implements PayStrategy<RelayQuote> {
4
+ getQuotes(request: PayStrategyGetQuotesRequest): Promise<import("../../types.cjs").TransactionPayQuote<RelayQuote>[]>;
5
+ execute(request: PayStrategyExecuteRequest<RelayQuote>): Promise<{
6
+ transactionHash?: `0x${string}` | undefined;
7
+ }>;
8
+ }
9
+ //# sourceMappingURL=RelayStrategy.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelayStrategy.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/RelayStrategy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAC1C,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EACzB,2BAA2B,EAC5B,wBAAoB;AAErB,qBAAa,aAAc,YAAW,WAAW,CAAC,UAAU,CAAC;IACrD,SAAS,CAAC,OAAO,EAAE,2BAA2B;IAI9C,OAAO,CAAC,OAAO,EAAE,yBAAyB,CAAC,UAAU,CAAC;;;CAG7D"}
@@ -0,0 +1,9 @@
1
+ import type { RelayQuote } from "./types.mjs";
2
+ import type { PayStrategy, PayStrategyExecuteRequest, PayStrategyGetQuotesRequest } from "../../types.mjs";
3
+ export declare class RelayStrategy implements PayStrategy<RelayQuote> {
4
+ getQuotes(request: PayStrategyGetQuotesRequest): Promise<import("../../types.mjs").TransactionPayQuote<RelayQuote>[]>;
5
+ execute(request: PayStrategyExecuteRequest<RelayQuote>): Promise<{
6
+ transactionHash?: `0x${string}` | undefined;
7
+ }>;
8
+ }
9
+ //# sourceMappingURL=RelayStrategy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelayStrategy.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/RelayStrategy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAgB;AAC1C,OAAO,KAAK,EACV,WAAW,EACX,yBAAyB,EACzB,2BAA2B,EAC5B,wBAAoB;AAErB,qBAAa,aAAc,YAAW,WAAW,CAAC,UAAU,CAAC;IACrD,SAAS,CAAC,OAAO,EAAE,2BAA2B;IAI9C,OAAO,CAAC,OAAO,EAAE,yBAAyB,CAAC,UAAU,CAAC;;;CAG7D"}
@@ -0,0 +1,11 @@
1
+ import { getRelayQuotes } from "./relay-quotes.mjs";
2
+ import { submitRelayQuotes } from "./relay-submit.mjs";
3
+ export class RelayStrategy {
4
+ async getQuotes(request) {
5
+ return getRelayQuotes(request);
6
+ }
7
+ async execute(request) {
8
+ return await submitRelayQuotes(request);
9
+ }
10
+ }
11
+ //# sourceMappingURL=RelayStrategy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RelayStrategy.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/RelayStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,2BAAuB;AAChD,OAAO,EAAE,iBAAiB,EAAE,2BAAuB;AAQnD,MAAM,OAAO,aAAa;IACxB,KAAK,CAAC,SAAS,CAAC,OAAoC;QAClD,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,OAA8C;QAC1D,OAAO,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC1C,CAAC;CACF","sourcesContent":["import { getRelayQuotes } from './relay-quotes';\nimport { submitRelayQuotes } from './relay-submit';\nimport type { RelayQuote } from './types';\nimport type {\n PayStrategy,\n PayStrategyExecuteRequest,\n PayStrategyGetQuotesRequest,\n} from '../../types';\n\nexport class RelayStrategy implements PayStrategy<RelayQuote> {\n async getQuotes(request: PayStrategyGetQuotesRequest) {\n return getRelayQuotes(request);\n }\n\n async execute(request: PayStrategyExecuteRequest<RelayQuote>) {\n return await submitRelayQuotes(request);\n }\n}\n"]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RELAY_URL_QUOTE = exports.RELAY_URL_BASE = exports.CHAIN_ID_POLYGON = exports.CHAIN_ID_ARBITRUM = exports.ARBITRUM_USDC_ADDRESS = void 0;
4
+ exports.ARBITRUM_USDC_ADDRESS = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
5
+ exports.CHAIN_ID_ARBITRUM = '0xa4b1';
6
+ exports.CHAIN_ID_POLYGON = '0x89';
7
+ exports.RELAY_URL_BASE = 'https://api.relay.link';
8
+ exports.RELAY_URL_QUOTE = `${exports.RELAY_URL_BASE}/quote`;
9
+ //# sourceMappingURL=constants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,qBAAqB,GAChC,4CAA4C,CAAC;AAClC,QAAA,iBAAiB,GAAG,QAAQ,CAAC;AAC7B,QAAA,gBAAgB,GAAG,MAAM,CAAC;AAC1B,QAAA,cAAc,GAAG,wBAAwB,CAAC;AAC1C,QAAA,eAAe,GAAG,GAAG,sBAAc,QAAQ,CAAC","sourcesContent":["export const ARBITRUM_USDC_ADDRESS =\n '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';\nexport const CHAIN_ID_ARBITRUM = '0xa4b1';\nexport const CHAIN_ID_POLYGON = '0x89';\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;\n"]}
@@ -0,0 +1,6 @@
1
+ export declare const ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
2
+ export declare const CHAIN_ID_ARBITRUM = "0xa4b1";
3
+ export declare const CHAIN_ID_POLYGON = "0x89";
4
+ export declare const RELAY_URL_BASE = "https://api.relay.link";
5
+ export declare const RELAY_URL_QUOTE = "https://api.relay.link/quote";
6
+ //# sourceMappingURL=constants.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare const ARBITRUM_USDC_ADDRESS = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";
2
+ export declare const CHAIN_ID_ARBITRUM = "0xa4b1";
3
+ export declare const CHAIN_ID_POLYGON = "0x89";
4
+ export declare const RELAY_URL_BASE = "https://api.relay.link";
5
+ export declare const RELAY_URL_QUOTE = "https://api.relay.link/quote";
6
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+CACY,CAAC;AAC/C,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,eAAO,MAAM,gBAAgB,SAAS,CAAC;AACvC,eAAO,MAAM,cAAc,2BAA2B,CAAC;AACvD,eAAO,MAAM,eAAe,iCAA4B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const ARBITRUM_USDC_ADDRESS = '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';
2
+ export const CHAIN_ID_ARBITRUM = '0xa4b1';
3
+ export const CHAIN_ID_POLYGON = '0x89';
4
+ export const RELAY_URL_BASE = 'https://api.relay.link';
5
+ export const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;
6
+ //# sourceMappingURL=constants.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../../../src/strategy/relay/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAChC,4CAA4C,CAAC;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,cAAc,QAAQ,CAAC","sourcesContent":["export const ARBITRUM_USDC_ADDRESS =\n '0xaf88d065e77c8cC2239327C5EDb3A432268e5831';\nexport const CHAIN_ID_ARBITRUM = '0xa4b1';\nexport const CHAIN_ID_POLYGON = '0x89';\nexport const RELAY_URL_BASE = 'https://api.relay.link';\nexport const RELAY_URL_QUOTE = `${RELAY_URL_BASE}/quote`;\n"]}
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRelayQuotes = void 0;
4
+ const controller_utils_1 = require("@metamask/controller-utils");
5
+ const utils_1 = require("@metamask/utils");
6
+ const bignumber_js_1 = require("bignumber.js");
7
+ const constants_1 = require("./constants.cjs");
8
+ const __1 = require("../../index.cjs");
9
+ const constants_2 = require("../../constants.cjs");
10
+ const logger_1 = require("../../logger.cjs");
11
+ const gas_1 = require("../../utils/gas.cjs");
12
+ const token_1 = require("../../utils/token.cjs");
13
+ const log = (0, utils_1.createModuleLogger)(logger_1.projectLogger, 'relay-strategy');
14
+ /**
15
+ * Fetches Relay quotes.
16
+ *
17
+ * @param request - Request object.
18
+ * @returns Array of quotes.
19
+ */
20
+ async function getRelayQuotes(request) {
21
+ const { requests } = request;
22
+ log('Fetching quotes', requests);
23
+ const result = requests
24
+ // Ignore gas fee token requests
25
+ .filter((r) => r.targetAmountMinimum !== '0')
26
+ .map((r) => normalizeRequest(r));
27
+ const normalizedRequests = result.map((r) => r.request);
28
+ const isSkipTransaction = result.some((r) => r.isSkipTransaction);
29
+ log('Normalized requests', { normalizedRequests, isSkipTransaction });
30
+ return await Promise.all(normalizedRequests.map((r) => getSingleQuote(r, isSkipTransaction, request)));
31
+ }
32
+ exports.getRelayQuotes = getRelayQuotes;
33
+ /**
34
+ * Fetches a single Relay quote.
35
+ *
36
+ * @param request - Quote request.
37
+ * @param isSkipTransaction - Whether to skip the transaction.
38
+ * @param fullRequest - Full quotes request.
39
+ * @returns Single quote.
40
+ */
41
+ async function getSingleQuote(request, isSkipTransaction, fullRequest) {
42
+ const { messenger } = fullRequest;
43
+ try {
44
+ const body = {
45
+ amount: request.targetAmountMinimum,
46
+ destinationChainId: Number(request.targetChainId),
47
+ destinationCurrency: request.targetTokenAddress,
48
+ originChainId: Number(request.sourceChainId),
49
+ originCurrency: request.sourceTokenAddress,
50
+ recipient: request.from,
51
+ tradeType: 'EXPECTED_OUTPUT',
52
+ user: request.from,
53
+ };
54
+ const url = getFeatureFlags(messenger).relayQuoteUrl;
55
+ const response = await (0, controller_utils_1.successfulFetch)(url, {
56
+ method: 'POST',
57
+ headers: { 'Content-Type': 'application/json' },
58
+ body: JSON.stringify(body),
59
+ });
60
+ const quote = (await response.json());
61
+ quote.skipTransaction = isSkipTransaction;
62
+ log('Fetched relay quote', { quote, url });
63
+ return normalizeQuote(quote, request, fullRequest);
64
+ }
65
+ catch (e) {
66
+ log('Error fetching relay quote', e);
67
+ throw e;
68
+ }
69
+ }
70
+ /**
71
+ * Normalizes requests for Relay.
72
+ *
73
+ * @param request - Quote request to normalize.
74
+ * @returns Normalized request.
75
+ */
76
+ function normalizeRequest(request) {
77
+ const isHyperliquidDeposit = request.targetChainId === constants_1.CHAIN_ID_ARBITRUM &&
78
+ request.targetTokenAddress.toLowerCase() ===
79
+ constants_1.ARBITRUM_USDC_ADDRESS.toLowerCase();
80
+ const isPolygonNativeSource = request.sourceChainId === constants_1.CHAIN_ID_POLYGON &&
81
+ request.sourceTokenAddress === (0, token_1.getNativeToken)(request.sourceChainId);
82
+ const requestOutput = {
83
+ ...request,
84
+ sourceTokenAddress: isPolygonNativeSource
85
+ ? constants_2.NATIVE_TOKEN_ADDRESS
86
+ : request.sourceTokenAddress,
87
+ targetChainId: isHyperliquidDeposit ? (0, controller_utils_1.toHex)(1337) : request.targetChainId,
88
+ targetTokenAddress: isHyperliquidDeposit
89
+ ? '0x00000000000000000000000000000000'
90
+ : request.targetTokenAddress,
91
+ targetAmountMinimum: isHyperliquidDeposit
92
+ ? new bignumber_js_1.BigNumber(request.targetAmountMinimum).shiftedBy(2).toString(10)
93
+ : request.targetAmountMinimum,
94
+ };
95
+ if (isHyperliquidDeposit) {
96
+ log('Converting Arbitrum Hyperliquid deposit to direct deposit', {
97
+ originalRequest: request,
98
+ normalizedRequest: requestOutput,
99
+ });
100
+ }
101
+ return {
102
+ request: requestOutput,
103
+ isSkipTransaction: isHyperliquidDeposit,
104
+ };
105
+ }
106
+ /**
107
+ * Normalizes a Relay quote into a TransactionPayQuote.
108
+ *
109
+ * @param quote - Relay quote.
110
+ * @param request - Original quote request.
111
+ * @param fullRequest - Full quotes request.
112
+ * @returns Normalized quote.
113
+ */
114
+ function normalizeQuote(quote, request, fullRequest) {
115
+ const { messenger, transaction } = fullRequest;
116
+ const { details } = quote;
117
+ const { currencyIn, currencyOut } = details;
118
+ const params = quote.steps[0].items[0].data;
119
+ const { usdToFiatRate } = getFiatRates(messenger, request);
120
+ const dust = getFiatValueFromUsd(calculateDustUsd(quote, request), usdToFiatRate);
121
+ const provider = getFiatValueFromUsd(new bignumber_js_1.BigNumber(currencyIn.amountUsd).minus(currencyOut.amountUsd), usdToFiatRate);
122
+ const sourceNetwork = (0, gas_1.calculateGasCost)({
123
+ ...params,
124
+ maxFeePerGas: undefined,
125
+ maxPriorityFeePerGas: undefined,
126
+ messenger,
127
+ });
128
+ const targetNetwork = quote.skipTransaction
129
+ ? {
130
+ usd: '0',
131
+ fiat: '0',
132
+ }
133
+ : (0, gas_1.calculateTransactionGasCost)(transaction, messenger);
134
+ return {
135
+ dust,
136
+ estimatedDuration: details.timeEstimate,
137
+ fees: {
138
+ provider,
139
+ sourceNetwork,
140
+ targetNetwork,
141
+ },
142
+ original: quote,
143
+ request,
144
+ strategy: __1.TransactionPayStrategy.Relay,
145
+ };
146
+ }
147
+ /**
148
+ * Calculate dust USD value.
149
+ *
150
+ * @param quote - Relay quote.
151
+ * @param request - Quote request.
152
+ * @returns Dust value in USD and fiat.
153
+ */
154
+ function calculateDustUsd(quote, request) {
155
+ const { currencyOut } = quote.details;
156
+ const { amountUsd, amountFormatted, minimumAmount } = currencyOut;
157
+ const { decimals: targetDecimals } = currencyOut.currency;
158
+ const targetUsdRate = new bignumber_js_1.BigNumber(amountUsd).dividedBy(amountFormatted);
159
+ const dustRaw = new bignumber_js_1.BigNumber(minimumAmount).minus(request.targetAmountMinimum);
160
+ return dustRaw.shiftedBy(-targetDecimals).multipliedBy(targetUsdRate);
161
+ }
162
+ /**
163
+ * Converts USD value to fiat value.
164
+ *
165
+ * @param usdValue - USD value.
166
+ * @param usdToFiatRate - USD to fiat rate.
167
+ * @returns Fiat value.
168
+ */
169
+ function getFiatValueFromUsd(usdValue, usdToFiatRate) {
170
+ const fiatValue = usdValue.multipliedBy(usdToFiatRate);
171
+ return {
172
+ usd: usdValue.toString(10),
173
+ fiat: fiatValue.toString(10),
174
+ };
175
+ }
176
+ /**
177
+ * Calculates USD to fiat rate.
178
+ *
179
+ * @param messenger - Controller messenger.
180
+ * @param request - Quote request.
181
+ * @returns USD to fiat rate.
182
+ */
183
+ function getFiatRates(messenger, request) {
184
+ const { sourceChainId, sourceTokenAddress } = request;
185
+ const finalSourceTokenAddress = sourceChainId === constants_1.CHAIN_ID_POLYGON &&
186
+ sourceTokenAddress === constants_2.NATIVE_TOKEN_ADDRESS
187
+ ? (0, token_1.getNativeToken)(sourceChainId)
188
+ : sourceTokenAddress;
189
+ const sourceFiatRate = (0, token_1.getTokenFiatRate)(messenger, finalSourceTokenAddress, sourceChainId);
190
+ if (!sourceFiatRate) {
191
+ throw new Error('Source token fiat rate not found');
192
+ }
193
+ const usdToFiatRate = new bignumber_js_1.BigNumber(sourceFiatRate.fiatRate).dividedBy(sourceFiatRate.usdRate);
194
+ return { sourceFiatRate, usdToFiatRate };
195
+ }
196
+ /**
197
+ * Gets feature flags for Relay quotes.
198
+ *
199
+ * @param messenger - Controller messenger.
200
+ * @returns Feature flags.
201
+ */
202
+ function getFeatureFlags(messenger) {
203
+ const featureFlagState = messenger.call('RemoteFeatureFlagController:getState');
204
+ const featureFlags = featureFlagState.remoteFeatureFlags?.confirmation_pay;
205
+ const relayQuoteUrl = featureFlags?.relayQuoteUrl ?? constants_1.RELAY_URL_QUOTE;
206
+ return {
207
+ relayQuoteUrl,
208
+ };
209
+ }
210
+ //# sourceMappingURL=relay-quotes.cjs.map