@gibs/bridge-sdk 1.13.0 → 1.17.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 (217) hide show
  1. package/README.md +244 -18
  2. package/abis/package.json +6 -0
  3. package/bridge-limits/package.json +6 -0
  4. package/chain-info/package.json +6 -0
  5. package/chain-names/package.json +6 -0
  6. package/chains/package.json +6 -0
  7. package/claims/package.json +6 -0
  8. package/config/package.json +6 -0
  9. package/consolidated-quote/package.json +6 -0
  10. package/destination-calldata/package.json +6 -0
  11. package/dist/chain-info.d.ts +1 -1
  12. package/dist/chain-info.js +11 -12
  13. package/dist/chains.d.ts +25 -0
  14. package/dist/chains.js +55 -20
  15. package/dist/cjs/abis.d.ts +1 -0
  16. package/dist/cjs/abis.js +19 -0
  17. package/dist/cjs/bridge-limits.d.ts +103 -0
  18. package/dist/cjs/bridge-limits.js +89 -0
  19. package/dist/cjs/chain-info.d.ts +169 -0
  20. package/dist/cjs/chain-info.js +452 -0
  21. package/dist/cjs/chain-names.d.ts +160 -0
  22. package/dist/cjs/chain-names.js +207 -0
  23. package/dist/cjs/chains.d.ts +90 -0
  24. package/dist/cjs/chains.js +357 -0
  25. package/dist/cjs/claims.d.ts +198 -0
  26. package/dist/cjs/claims.js +182 -0
  27. package/dist/cjs/config.d.ts +240 -0
  28. package/dist/cjs/config.js +537 -0
  29. package/dist/cjs/consolidated-quote.d.ts +648 -0
  30. package/dist/cjs/consolidated-quote.js +1048 -0
  31. package/dist/cjs/destination-calldata.d.ts +118 -0
  32. package/dist/cjs/destination-calldata.js +156 -0
  33. package/dist/cjs/ecosystems.d.ts +217 -0
  34. package/dist/cjs/ecosystems.js +298 -0
  35. package/dist/cjs/execution.d.ts +346 -0
  36. package/dist/cjs/execution.js +468 -0
  37. package/dist/cjs/fee-type.d.ts +10 -0
  38. package/dist/cjs/fee-type.js +10 -0
  39. package/dist/cjs/hyperliquid-execution.d.ts +152 -0
  40. package/dist/cjs/hyperliquid-execution.js +175 -0
  41. package/dist/cjs/image-links.d.ts +117 -0
  42. package/dist/cjs/image-links.js +153 -0
  43. package/dist/cjs/index.d.ts +23 -0
  44. package/dist/cjs/index.js +39 -0
  45. package/dist/cjs/lifi-execution-guard.d.ts +210 -0
  46. package/dist/cjs/lifi-execution-guard.js +409 -0
  47. package/dist/cjs/near-intents-conformance.d.ts +85 -0
  48. package/dist/cjs/near-intents-conformance.js +337 -0
  49. package/dist/cjs/near-intents-route.d.ts +47 -0
  50. package/dist/cjs/near-intents-route.js +303 -0
  51. package/dist/cjs/near-intents.d.ts +524 -0
  52. package/dist/cjs/near-intents.js +1071 -0
  53. package/dist/cjs/origin-deposit.d.ts +326 -0
  54. package/dist/cjs/origin-deposit.js +82 -0
  55. package/dist/cjs/package.json +3 -0
  56. package/dist/cjs/pre-quote.d.ts +198 -0
  57. package/dist/cjs/pre-quote.js +180 -0
  58. package/dist/cjs/prices.d.ts +107 -0
  59. package/dist/cjs/prices.js +172 -0
  60. package/dist/cjs/providers.d.ts +238 -0
  61. package/dist/cjs/providers.js +171 -0
  62. package/dist/cjs/quote-fees.d.ts +102 -0
  63. package/dist/cjs/quote-fees.js +201 -0
  64. package/dist/cjs/referral.d.ts +85 -0
  65. package/dist/cjs/referral.js +85 -0
  66. package/dist/cjs/relay-currencies.d.ts +47 -0
  67. package/dist/cjs/relay-currencies.js +95 -0
  68. package/dist/cjs/relay-depository.d.ts +2 -0
  69. package/dist/cjs/relay-depository.js +85 -0
  70. package/dist/cjs/relay-quote.d.ts +301 -0
  71. package/dist/cjs/relay-quote.js +996 -0
  72. package/dist/cjs/route-steps.d.ts +138 -0
  73. package/dist/cjs/route-steps.js +310 -0
  74. package/dist/cjs/routing/amounts.d.ts +80 -0
  75. package/dist/cjs/routing/amounts.js +126 -0
  76. package/dist/cjs/routing/candidate-route.d.ts +43 -0
  77. package/dist/cjs/routing/candidate-route.js +50 -0
  78. package/dist/cjs/routing/candidate.d.ts +237 -0
  79. package/dist/cjs/routing/candidate.js +100 -0
  80. package/dist/cjs/routing/carriers/ask-answer.d.ts +77 -0
  81. package/dist/cjs/routing/carriers/ask-answer.js +2 -0
  82. package/dist/cjs/routing/carriers/omnibridge.d.ts +137 -0
  83. package/dist/cjs/routing/carriers/omnibridge.js +459 -0
  84. package/dist/cjs/routing/carriers/pulsex-paths.d.ts +80 -0
  85. package/dist/cjs/routing/carriers/pulsex-paths.js +97 -0
  86. package/dist/cjs/routing/carriers/pulsex-split.d.ts +175 -0
  87. package/dist/cjs/routing/carriers/pulsex-split.js +193 -0
  88. package/dist/cjs/routing/carriers/pulsex.d.ts +159 -0
  89. package/dist/cjs/routing/carriers/pulsex.js +565 -0
  90. package/dist/cjs/routing/carriers/wrap.d.ts +25 -0
  91. package/dist/cjs/routing/carriers/wrap.js +119 -0
  92. package/dist/cjs/routing/composed-route-quality.d.ts +125 -0
  93. package/dist/cjs/routing/composed-route-quality.js +144 -0
  94. package/dist/cjs/routing/entry-chain-anchor.d.ts +88 -0
  95. package/dist/cjs/routing/entry-chain-anchor.js +59 -0
  96. package/dist/cjs/routing/format.d.ts +31 -0
  97. package/dist/cjs/routing/format.js +64 -0
  98. package/dist/cjs/routing/index.d.ts +38 -0
  99. package/dist/cjs/routing/index.js +134 -0
  100. package/dist/cjs/routing/producers.d.ts +770 -0
  101. package/dist/cjs/routing/producers.js +1617 -0
  102. package/dist/cjs/routing/providers.d.ts +31 -0
  103. package/dist/cjs/routing/providers.js +48 -0
  104. package/dist/cjs/routing/route-data.d.ts +355 -0
  105. package/dist/cjs/routing/route-data.js +2 -0
  106. package/dist/cjs/routing/search/compose.d.ts +168 -0
  107. package/dist/cjs/routing/search/compose.js +104 -0
  108. package/dist/cjs/routing/search/graph.d.ts +668 -0
  109. package/dist/cjs/routing/search/graph.js +461 -0
  110. package/dist/cjs/routing/search/plan-route-data.d.ts +269 -0
  111. package/dist/cjs/routing/search/plan-route-data.js +848 -0
  112. package/dist/cjs/routing/search/score.d.ts +356 -0
  113. package/dist/cjs/routing/search/score.js +445 -0
  114. package/dist/cjs/routing/swap-transactions.d.ts +91 -0
  115. package/dist/cjs/routing/swap-transactions.js +131 -0
  116. package/dist/cjs/routing/usd-value.d.ts +17 -0
  117. package/dist/cjs/routing/usd-value.js +29 -0
  118. package/dist/cjs/settings.d.ts +785 -0
  119. package/dist/cjs/settings.js +1074 -0
  120. package/dist/cjs/ton-connect.d.ts +98 -0
  121. package/dist/cjs/ton-connect.js +206 -0
  122. package/dist/cjs/ton-execution.d.ts +7 -0
  123. package/dist/cjs/ton-execution.js +23 -0
  124. package/dist/cjs/ton.d.ts +37 -0
  125. package/dist/cjs/ton.js +83 -0
  126. package/dist/cjs/tron-execution.d.ts +146 -0
  127. package/dist/cjs/tron-execution.js +248 -0
  128. package/dist/cjs/types.d.ts +51 -0
  129. package/dist/cjs/types.js +2 -0
  130. package/dist/claims.d.ts +198 -0
  131. package/dist/claims.js +140 -0
  132. package/dist/config.d.ts +24 -0
  133. package/dist/config.js +39 -5
  134. package/dist/consolidated-quote.d.ts +109 -15
  135. package/dist/consolidated-quote.js +310 -52
  136. package/dist/execution.d.ts +346 -0
  137. package/dist/execution.js +428 -0
  138. package/dist/hyperliquid-execution.js +2 -3
  139. package/dist/index.d.ts +3 -0
  140. package/dist/index.js +3 -0
  141. package/dist/lifi-execution-guard.d.ts +13 -2
  142. package/dist/lifi-execution-guard.js +4 -0
  143. package/dist/near-intents.js +2 -3
  144. package/dist/pre-quote.d.ts +6 -6
  145. package/dist/pre-quote.js +10 -14
  146. package/dist/providers.d.ts +17 -0
  147. package/dist/providers.js +6 -0
  148. package/dist/referral.d.ts +12 -4
  149. package/dist/referral.js +12 -4
  150. package/dist/relay-depository.d.ts +2 -0
  151. package/dist/relay-depository.js +82 -0
  152. package/dist/relay-quote.js +2 -3
  153. package/dist/routing/candidate.d.ts +3 -3
  154. package/dist/routing/candidate.js +3 -3
  155. package/dist/routing/carriers/ask-answer.d.ts +19 -0
  156. package/dist/routing/carriers/omnibridge.js +23 -21
  157. package/dist/routing/carriers/pulsex-paths.d.ts +80 -0
  158. package/dist/routing/carriers/pulsex-paths.js +92 -0
  159. package/dist/routing/carriers/pulsex-split.d.ts +175 -0
  160. package/dist/routing/carriers/pulsex-split.js +185 -0
  161. package/dist/routing/carriers/pulsex.d.ts +69 -21
  162. package/dist/routing/carriers/pulsex.js +184 -65
  163. package/dist/routing/composed-route-quality.d.ts +28 -6
  164. package/dist/routing/composed-route-quality.js +36 -5
  165. package/dist/routing/entry-chain-anchor.d.ts +1 -1
  166. package/dist/routing/entry-chain-anchor.js +1 -1
  167. package/dist/routing/index.d.ts +7 -3
  168. package/dist/routing/index.js +7 -3
  169. package/dist/routing/producers.js +1 -1
  170. package/dist/routing/providers.d.ts +5 -0
  171. package/dist/routing/providers.js +5 -0
  172. package/dist/routing/search/graph.d.ts +29 -0
  173. package/dist/routing/search/plan-route-data.d.ts +25 -0
  174. package/dist/routing/search/plan-route-data.js +43 -7
  175. package/dist/routing/search/score.d.ts +33 -1
  176. package/dist/routing/search/score.js +41 -6
  177. package/dist/routing/swap-transactions.d.ts +91 -0
  178. package/dist/routing/swap-transactions.js +125 -0
  179. package/dist/settings.d.ts +94 -1
  180. package/dist/settings.js +95 -3
  181. package/dist/ton-connect.d.ts +98 -0
  182. package/dist/ton-connect.js +200 -0
  183. package/dist/ton-execution.d.ts +4 -114
  184. package/dist/ton-execution.js +4 -244
  185. package/dist/ton.d.ts +37 -0
  186. package/dist/ton.js +65 -0
  187. package/docs/examples/example-a-ether-to-pulse.ts +300 -0
  188. package/docs/examples/example-b-token-pulsechain-to-ethereum.ts +270 -0
  189. package/docs/examples/shared.ts +261 -0
  190. package/docs/examples/tsconfig.json +18 -0
  191. package/docs/integration-guide.md +617 -0
  192. package/ecosystems/package.json +6 -0
  193. package/execution/package.json +6 -0
  194. package/fee-type/package.json +6 -0
  195. package/hyperliquid-execution/package.json +6 -0
  196. package/image-links/package.json +6 -0
  197. package/lifi-execution-guard/package.json +6 -0
  198. package/llms.txt +234 -0
  199. package/near-intents/package.json +6 -0
  200. package/near-intents-route/package.json +6 -0
  201. package/origin-deposit/package.json +6 -0
  202. package/package.json +818 -10
  203. package/pre-quote/package.json +6 -0
  204. package/prices/package.json +6 -0
  205. package/providers/package.json +6 -0
  206. package/quote-fees/package.json +6 -0
  207. package/referral/package.json +6 -0
  208. package/relay-currencies/package.json +6 -0
  209. package/relay-quote/package.json +6 -0
  210. package/route-steps/package.json +6 -0
  211. package/routing/package.json +6 -0
  212. package/settings/package.json +6 -0
  213. package/ton/package.json +6 -0
  214. package/ton-connect/package.json +6 -0
  215. package/ton-execution/package.json +6 -0
  216. package/tron-execution/package.json +6 -0
  217. package/types/package.json +6 -0
@@ -0,0 +1,468 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.readPulseXSectionQuote = exports.planCandidateExecution = exports.planExecution = exports.assumeNoAllowance = void 0;
37
+ const viem_1 = require("viem");
38
+ const abis = __importStar(require("./abis.js"));
39
+ const config_js_1 = require("./config.js");
40
+ const consolidated_quote_js_1 = require("./consolidated-quote.js");
41
+ const pulsex_js_1 = require("./routing/carriers/pulsex.js");
42
+ const swap_transactions_js_1 = require("./routing/swap-transactions.js");
43
+ const settings_js_1 = require("./settings.js");
44
+ /**
45
+ * An {@link AllowanceReader} that reports no allowance anywhere, so the plan
46
+ * includes every approval. For a caller that reads allowances itself at send
47
+ * time.
48
+ */
49
+ const assumeNoAllowance = async () => 0n;
50
+ exports.assumeNoAllowance = assumeNoAllowance;
51
+ const refusal = (value) => ({ kind: 'refused', refusal: value });
52
+ /** The fee director a delivery choice encodes, or null when the reader buys no delivery. */
53
+ const encodeDelivery = ({ leg, pathway, }) => {
54
+ const { delivery } = leg;
55
+ if (!delivery.shouldDeliver)
56
+ return { kind: 'encoded', feeDirector: null };
57
+ if (!pathway.requiresDelivery)
58
+ return refusal({ reason: 'delivery-not-offered' });
59
+ // A zero fee pays no relayer, so the transfer would wait for a delivery that never comes.
60
+ if (delivery.fee.maximumFee <= 0n)
61
+ return refusal({ reason: 'delivery-fee-missing' });
62
+ const feeDirector = (0, settings_js_1.feeDirectorStructEncoded)({
63
+ recipient: leg.recipient,
64
+ bridgePathway: pathway,
65
+ feeType: delivery.fee.feeType,
66
+ priceCorrective: delivery.fee.priceCorrective,
67
+ gasTipFee: delivery.fee.gasTipFee,
68
+ percentFee: delivery.fee.percentFee,
69
+ feeTypeSettings: (0, settings_js_1.feeTypeSettings)({ feeType: delivery.fee.feeType, unwrap: leg.unwrap }),
70
+ limit: delivery.fee.maximumFee,
71
+ assetOut: delivery.fee.assetOut,
72
+ });
73
+ if (feeDirector === null)
74
+ return refusal({ reason: 'delivery-fee-unencodable' });
75
+ return { kind: 'encoded', feeDirector };
76
+ };
77
+ const deliveryTermsOf = (delivery) => {
78
+ if (!delivery.shouldDeliver)
79
+ return { status: 'not-requested' };
80
+ return {
81
+ status: 'requested',
82
+ feeType: delivery.fee.feeType,
83
+ maximumFee: delivery.fee.maximumFee,
84
+ feeToken: delivery.fee.assetOut,
85
+ };
86
+ };
87
+ const omnibridgeCalls = (leg, account) => {
88
+ if (leg.amountIn <= 0n)
89
+ return refusal({ reason: 'amount-not-positive' });
90
+ const pathway = (0, settings_js_1.bridgePathway)({ bridgeKey: leg.bridgeKey, isProd: leg.isProd, assetIn: leg.assetIn });
91
+ if (pathway === null)
92
+ return refusal({ reason: 'no-pathway' });
93
+ const encoded = encodeDelivery({ leg, pathway });
94
+ if (encoded.kind !== 'encoded')
95
+ return encoded;
96
+ const { feeDirector } = encoded;
97
+ const dataParam = (0, settings_js_1.destinationDataParam)({
98
+ recipient: leg.recipient,
99
+ bridgePathway: pathway,
100
+ assetIn: leg.assetIn,
101
+ destinationRouter: pathway.destinationRouter,
102
+ feeDirectorStructEncoded: feeDirector,
103
+ assetLink: leg.assetLink,
104
+ shouldDeliver: leg.delivery.shouldDeliver,
105
+ unwrap: leg.unwrap,
106
+ });
107
+ const call = (0, settings_js_1.transactionInputs)({
108
+ bridgeKey: leg.bridgeKey,
109
+ signedCrossing: { originChainId: Number(leg.bridgeKey[1]), destinationChainId: Number(leg.bridgeKey[2]) },
110
+ bridgePathway: pathway,
111
+ assetIn: leg.assetIn,
112
+ recipient: leg.recipient,
113
+ account,
114
+ assetLink: leg.assetLink,
115
+ destinationDataParam: dataParam,
116
+ amountToBridge: leg.amountIn,
117
+ feeDirectorStructEncoded: feeDirector,
118
+ shouldDeliver: leg.delivery.shouldDeliver,
119
+ });
120
+ if (call === null)
121
+ return refusal({ reason: 'bridge-call-refused' });
122
+ return {
123
+ kind: 'calls',
124
+ approval: (0, settings_js_1.omnibridgeApproval)({
125
+ bridgePathway: pathway,
126
+ assetIn: leg.assetIn,
127
+ assetLink: leg.assetLink,
128
+ amountToBridge: leg.amountIn,
129
+ }),
130
+ action: { chainId: Number(leg.bridgeKey[1]), kind: 'bridge', ...call, gasLimit: null },
131
+ delivery: deliveryTermsOf(leg.delivery),
132
+ };
133
+ };
134
+ const pulseXSwapCalls = (leg) => {
135
+ const { edge } = leg.hop;
136
+ const chainId = edge.from.chainId;
137
+ const routerAddress = (0, pulsex_js_1.pulseXRouterForEdge)(edge);
138
+ // The builder refuses a hop that records no priced path, a router other
139
+ // than the edge's own, and a leg on screen that disagrees.
140
+ const call = (0, swap_transactions_js_1.buildPulseXSwapTransaction)({
141
+ hop: leg.hop,
142
+ amountIn: leg.amountIn,
143
+ minAmountOut: leg.minAmountOut,
144
+ recipient: leg.recipient,
145
+ deadline: leg.deadline,
146
+ signedLeg: { kind: 'swap', chainId },
147
+ chainId,
148
+ routerAddress,
149
+ });
150
+ if (call === null || routerAddress === null)
151
+ return refusal({ reason: 'swap-refused' });
152
+ const spendsNative = edge.from.address.toLowerCase() === viem_1.zeroAddress;
153
+ return {
154
+ kind: 'calls',
155
+ approval: spendsNative
156
+ ? null
157
+ : { chainId, token: edge.from.address, spender: routerAddress, minimum: leg.amountIn },
158
+ action: { chainId, kind: 'swap', ...call, gasLimit: null },
159
+ delivery: null,
160
+ };
161
+ };
162
+ const wrapCalls = (leg) => {
163
+ const call = (0, swap_transactions_js_1.buildWrapTransaction)({ edge: leg.edge, amountIn: leg.amountIn });
164
+ if (call === null)
165
+ return refusal({ reason: 'wrap-refused' });
166
+ const wraps = leg.edge.from.address.toLowerCase() === viem_1.zeroAddress;
167
+ return {
168
+ kind: 'calls',
169
+ approval: null,
170
+ action: { chainId: leg.edge.from.chainId, kind: wraps ? 'wrap' : 'unwrap', ...call, gasLimit: null },
171
+ delivery: null,
172
+ };
173
+ };
174
+ const aggregatorCalls = (leg) => {
175
+ const origin = (0, consolidated_quote_js_1.aggregatorOriginCalls)({ quote: leg.quote, request: leg.request });
176
+ if (origin.kind === 'refused')
177
+ return refusal({ reason: 'aggregator-origin-refused', origin: origin.refusal });
178
+ const { approval, deposit } = origin;
179
+ const staysOnChain = leg.request.toChainId === leg.request.fromChainId;
180
+ return {
181
+ kind: 'calls',
182
+ approval,
183
+ action: {
184
+ chainId: leg.request.fromChainId,
185
+ kind: staysOnChain ? 'swap' : 'bridge',
186
+ to: deposit.to,
187
+ data: deposit.data,
188
+ value: deposit.value,
189
+ gasLimit: deposit.gasLimit,
190
+ },
191
+ delivery: null,
192
+ };
193
+ };
194
+ const legCalls = (leg, account) => {
195
+ if (leg.kind === 'omnibridge')
196
+ return omnibridgeCalls(leg, account);
197
+ if (leg.kind === 'pulsex-swap')
198
+ return pulseXSwapCalls(leg);
199
+ if (leg.kind === 'wrap')
200
+ return wrapCalls(leg);
201
+ return aggregatorCalls(leg);
202
+ };
203
+ /** The approve transactions an approval needs now: none when the allowance on chain covers it. */
204
+ const approvalTransactions = async ({ approval, account, readAllowance, }) => {
205
+ const allowance = await readAllowance(approval.chainId, approval.token, account, approval.spender);
206
+ return (0, settings_js_1.approvalAmounts)({ allowance, minimum: approval.minimum }).map((amount) => ({
207
+ chainId: approval.chainId,
208
+ kind: 'approve',
209
+ ...(0, settings_js_1.approveCall)({ token: approval.token, spender: approval.spender, amount }),
210
+ gasLimit: null,
211
+ }));
212
+ };
213
+ /**
214
+ * Plans the transactions for a list of legs, in order.
215
+ *
216
+ * Each leg contributes the exact approval it needs when the allowance on
217
+ * chain does not cover it (a reset to zero first when a smaller allowance
218
+ * remains), then its own call. Nothing is sent.
219
+ *
220
+ * @param options.account - the account that signs every transaction
221
+ * @param options.legs - the legs, in the order the wallet signs them
222
+ * @param options.readAllowance - reads an allowance on chain; see {@link AllowanceReader}
223
+ * @returns the ordered transactions, or the first leg that cannot be planned
224
+ */
225
+ const planExecution = async ({ account, legs, readAllowance, }) => {
226
+ const calls = legs.map((leg) => legCalls(leg, account));
227
+ const refusedIndex = calls.findIndex((entry) => entry.kind === 'refused');
228
+ const refused = calls[refusedIndex];
229
+ if (refused !== undefined && refused.kind === 'refused') {
230
+ return { kind: 'refused', legIndex: refusedIndex, refusal: refused.refusal };
231
+ }
232
+ const planned = calls.flatMap((entry) => (entry.kind === 'calls' ? [entry] : []));
233
+ const perLeg = await Promise.all(planned.map(async (entry) => {
234
+ const approvals = entry.approval === null
235
+ ? []
236
+ : await approvalTransactions({ approval: entry.approval, account, readAllowance });
237
+ return [...approvals, entry.action];
238
+ }));
239
+ const ordered = perLeg.flat();
240
+ const transactions = ordered.map((action, index) => ({ ...action, waitForReceipt: index < ordered.length - 1 }));
241
+ const deliveries = planned.flatMap((entry, legIndex) => entry.delivery === null ? [] : [{ ...entry.delivery, legIndex }]);
242
+ return { kind: 'planned', transactions, deliveries };
243
+ };
244
+ exports.planExecution = planExecution;
245
+ const OMNIBRIDGE_CARRIERS = new Set(Object.values(config_js_1.Providers));
246
+ const isOmnibridgeCarrier = (carrier) => OMNIBRIDGE_CARRIERS.has(carrier);
247
+ const missing = (needs) => ({
248
+ kind: 'refused',
249
+ refusal: { reason: 'section-inputs-missing', needs },
250
+ });
251
+ const shape = (detail) => ({ kind: 'refused', refusal: { reason: 'section-shape', detail } });
252
+ const omnibridgeSectionLeg = ({ carrier, from, to, inputs, assetIn, }) => {
253
+ if (inputs.omnibridge === undefined)
254
+ return missing('omnibridge');
255
+ return {
256
+ kind: 'leg',
257
+ leg: {
258
+ kind: 'omnibridge',
259
+ bridgeKey: [carrier, (0, config_js_1.toChain)(from.chainId), (0, config_js_1.toChain)(to.chainId)],
260
+ isProd: inputs.omnibridge.isProd,
261
+ assetIn,
262
+ assetLink: inputs.omnibridge.assetLink,
263
+ amountIn: inputs.amountIn,
264
+ recipient: inputs.recipient,
265
+ delivery: inputs.omnibridge.delivery,
266
+ unwrap: inputs.omnibridge.unwrap,
267
+ },
268
+ };
269
+ };
270
+ const liveQuoteRequired = { kind: 'refused', refusal: { reason: 'live-quote-required' } };
271
+ const aggregatorSectionLeg = (carrier, inputs) => {
272
+ if (inputs.aggregator === undefined)
273
+ return liveQuoteRequired;
274
+ const { quote, request } = inputs.aggregator;
275
+ if (quote.provider !== carrier) {
276
+ return {
277
+ kind: 'refused',
278
+ refusal: { reason: 'quote-provider-mismatch', quoteProvider: quote.provider, sectionCarrier: carrier },
279
+ };
280
+ }
281
+ return { kind: 'leg', leg: { kind: 'aggregator', quote, request } };
282
+ };
283
+ const pulseXSectionLeg = (hop, inputs) => {
284
+ if (inputs.swap === undefined)
285
+ return missing('swap');
286
+ const { quotedAmountOut } = inputs.swap;
287
+ if (quotedAmountOut !== undefined && quotedAmountOut <= 0n) {
288
+ return { kind: 'refused', refusal: { reason: 'swap-quote-not-positive' } };
289
+ }
290
+ // Without a fresh quote the floor comes from the hop's own figure, so it must be a real quote.
291
+ if (quotedAmountOut === undefined && hop.outcome.kind !== 'quote') {
292
+ return { kind: 'refused', refusal: { reason: 'swap-estimate-only' } };
293
+ }
294
+ return {
295
+ kind: 'leg',
296
+ leg: {
297
+ kind: 'pulsex-swap',
298
+ hop,
299
+ amountIn: inputs.amountIn,
300
+ minAmountOut: (0, swap_transactions_js_1.swapMinimumOut)({
301
+ quotedAmount: quotedAmountOut ?? hop.outcome.deliveredAmount,
302
+ slippageBasisPoints: inputs.swap.slippageBasisPoints,
303
+ }),
304
+ recipient: inputs.recipient,
305
+ deadline: inputs.swap.deadline,
306
+ },
307
+ };
308
+ };
309
+ /** Turns one section of an engine plan into its leg, dispatching on the first hop's carrier. */
310
+ const planSectionLeg = ({ hops, inputs, resolveToken, }) => {
311
+ const firstHop = hops[0];
312
+ if (firstHop === undefined)
313
+ return shape('the section has no hops');
314
+ const { carrier, origin, from, to } = firstHop.edge;
315
+ if (origin === 'by-hand')
316
+ return { kind: 'refused', refusal: { reason: 'paid-by-hand' } };
317
+ // An aggregator section may run several hops inside one signature (a fused
318
+ // omnibridge entry); every other carrier signs exactly one hop.
319
+ const singleHop = hops.length === 1;
320
+ if (isOmnibridgeCarrier(carrier)) {
321
+ if (!singleHop)
322
+ return shape('an omnibridge section is exactly one hop');
323
+ return omnibridgeSectionLeg({ carrier, from, to, inputs, assetIn: resolveToken(from) });
324
+ }
325
+ if (carrier === 'PulseX') {
326
+ if (!singleHop)
327
+ return shape('a swap section is exactly one hop');
328
+ return pulseXSectionLeg(firstHop, inputs);
329
+ }
330
+ if (carrier === 'wrap') {
331
+ if (!singleHop)
332
+ return shape('a wrap section is exactly one hop');
333
+ return { kind: 'leg', leg: { kind: 'wrap', edge: firstHop.edge, amountIn: inputs.amountIn } };
334
+ }
335
+ return aggregatorSectionLeg(carrier, inputs);
336
+ };
337
+ /** The sections of a plan, each as its hops. */
338
+ const planSections = (plan) => plan.signatures.map((group) => group.flatMap((hopIndex) => plan.hops[hopIndex] ?? []));
339
+ /**
340
+ * A candidate built without an engine plan is one signature: either a
341
+ * same-chain omnibridge crossing (`buildDirectCrossingCandidate`, whose quote
342
+ * names the bridge) or an aggregator quote.
343
+ *
344
+ * THE CANDIDATE'S OWN QUOTE IS NEVER SIGNED. It priced the route on screen
345
+ * and may be stale or a dry probe; only the live quote in
346
+ * `inputs.aggregator` is. Without one the section is refused with
347
+ * `live-quote-required`.
348
+ */
349
+ const planlessSectionLeg = (candidate, inputs) => {
350
+ const provider = candidate.quote.provider;
351
+ if (isOmnibridgeCarrier(provider)) {
352
+ return omnibridgeSectionLeg({
353
+ carrier: provider,
354
+ from: candidate.originToken,
355
+ to: candidate.destinationToken,
356
+ inputs,
357
+ assetIn: candidate.originToken,
358
+ });
359
+ }
360
+ return aggregatorSectionLeg(provider, inputs);
361
+ };
362
+ /**
363
+ * What is wrong with the requested window of sections, or null when it fits.
364
+ * A window starts at `firstSectionIndex` and spans `plannedCount` sections.
365
+ */
366
+ const sectionWindowProblem = ({ firstSectionIndex, plannedCount, sectionCount, }) => {
367
+ if (!Number.isSafeInteger(firstSectionIndex) || firstSectionIndex < 0) {
368
+ return `firstSectionIndex must be a non-negative safe integer, received ${firstSectionIndex}`;
369
+ }
370
+ if (plannedCount < 1)
371
+ return `pass at least 1 section input, received ${plannedCount}`;
372
+ if (firstSectionIndex + plannedCount > sectionCount) {
373
+ return `sections ${firstSectionIndex} to ${firstSectionIndex + plannedCount - 1} do not fit a route of ${sectionCount} section${sectionCount === 1 ? '' : 's'}`;
374
+ }
375
+ return null;
376
+ };
377
+ /**
378
+ * Plans the transactions for a chosen route candidate: the candidate
379
+ * `buildRouteCandidateFromPlan` returns for an engine plan (the interface's
380
+ * `buildCandidateFromEnginePlan`), or a candidate built without a plan.
381
+ *
382
+ * ONE SECTION IS ONE SIGNATURE. A plan's `signatures` groups its hops into
383
+ * sections; the section's first hop names its carrier. An omnibridge section
384
+ * becomes a crossing, a PulseX section a swap signed on its recorded path, a
385
+ * wrap section a wrap or unwrap, and any other wallet-signed carrier an
386
+ * aggregator deposit from the live quote the caller supplies. A section paid
387
+ * by hand has nothing to sign and is refused.
388
+ *
389
+ * A LATER SECTION CAN BE PLANNED ALONE. Pass `firstSectionIndex` to skip the
390
+ * sections that already landed. The wallet then plans the swap after the
391
+ * crossing arrived, from the amount that arrived, with a fresh
392
+ * `swap.quotedAmountOut` and a fresh `swap.deadline`. The slippage floor and the
393
+ * deadline are not fixed minutes before the swap is signed. Every safety check
394
+ * still applies to the later section: verified spenders, live quotes for
395
+ * aggregator sections, exact approvals.
396
+ *
397
+ * Every `sectionIndex` in a refusal and every `legIndex` in `deliveries` is
398
+ * the absolute section index.
399
+ *
400
+ * @param inputs - see {@link CandidateExecutionInputs}
401
+ * @returns the ordered transactions with the deliveries they buy, or the first section that cannot be planned
402
+ */
403
+ const planCandidateExecution = async (inputs) => {
404
+ const { candidate, account, readAllowance, resolveToken, sections } = inputs;
405
+ const firstSectionIndex = inputs.firstSectionIndex ?? 0;
406
+ const plan = candidate.plan;
407
+ const allSections = plan === undefined ? null : planSections(plan);
408
+ const sectionCount = allSections === null ? 1 : allSections.length;
409
+ const problem = sectionWindowProblem({ firstSectionIndex, plannedCount: sections.length, sectionCount });
410
+ if (problem !== null) {
411
+ const validIndex = Number.isSafeInteger(firstSectionIndex) && firstSectionIndex >= 0;
412
+ return {
413
+ kind: 'refused',
414
+ sectionIndex: validIndex ? firstSectionIndex : 0,
415
+ refusal: { reason: 'section-shape', detail: problem },
416
+ };
417
+ }
418
+ const sectionLegs = sections.map((sectionInputs, index) => allSections === null
419
+ ? planlessSectionLeg(candidate, sectionInputs)
420
+ : planSectionLeg({ hops: allSections[firstSectionIndex + index] ?? [], inputs: sectionInputs, resolveToken }));
421
+ const refusedIndex = sectionLegs.findIndex((entry) => entry.kind === 'refused');
422
+ const refused = sectionLegs[refusedIndex];
423
+ if (refused !== undefined && refused.kind === 'refused') {
424
+ return { kind: 'refused', sectionIndex: firstSectionIndex + refusedIndex, refusal: refused.refusal };
425
+ }
426
+ const legs = sectionLegs.flatMap((entry) => (entry.kind === 'leg' ? [entry.leg] : []));
427
+ const planned = await (0, exports.planExecution)({ account, legs, readAllowance });
428
+ if (planned.kind === 'refused') {
429
+ return { kind: 'refused', sectionIndex: firstSectionIndex + planned.legIndex, refusal: planned.refusal };
430
+ }
431
+ return {
432
+ kind: 'planned',
433
+ transactions: planned.transactions,
434
+ deliveries: planned.deliveries.map((delivery) => ({ ...delivery, legIndex: firstSectionIndex + delivery.legIndex })),
435
+ remainingSectionCount: sectionCount - firstSectionIndex - sections.length,
436
+ };
437
+ };
438
+ exports.planCandidateExecution = planCandidateExecution;
439
+ /**
440
+ * Reads a fresh quote for a PulseX section: what the router's `getAmountsOut`
441
+ * says the swap delivers for `amountIn`, along the exact path the swap signs
442
+ * ({@link pulseXSwapPathForHop}) on the edge's own router. A wallet passes the
443
+ * result as `swap.quotedAmountOut` just before it signs.
444
+ *
445
+ * @param options.hop - the swap hop; its recorded path and edge name what to read
446
+ * @param options.amountIn - the amount the swap spends, in base units
447
+ * @param options.client - a client that can call `readContract`
448
+ * @returns the amount the last token of the path delivers, or null when the hop records no path, names no known router, the amount is not positive, or the read fails or returns nothing
449
+ */
450
+ const readPulseXSectionQuote = async ({ hop, amountIn, client, }) => {
451
+ const path = (0, pulsex_js_1.pulseXSwapPathForHop)(hop);
452
+ const router = (0, pulsex_js_1.pulseXRouterForEdge)(hop.edge);
453
+ if (path === null || router === null || amountIn <= 0n)
454
+ return null;
455
+ try {
456
+ const amounts = await client.readContract({
457
+ address: router,
458
+ abi: abis.univ2Router,
459
+ functionName: 'getAmountsOut',
460
+ args: [amountIn, path],
461
+ });
462
+ return amounts.at(-1) ?? null;
463
+ }
464
+ catch {
465
+ return null;
466
+ }
467
+ };
468
+ exports.readPulseXSectionQuote = readPulseXSectionQuote;
@@ -0,0 +1,10 @@
1
+ /** The type of fee to use for the bridge */
2
+ export declare enum FeeType {
3
+ PERCENT = "%",
4
+ GAS_TIP = "gas+%",
5
+ FIXED = "fixed"
6
+ }
7
+ /** The keys of the fee type */
8
+ export type FeeTypeKeys = keyof typeof FeeType;
9
+ /** A map of fee type values to keys */
10
+ export declare const feeTypeValToKeyMap: Map<FeeType, "PERCENT" | "GAS_TIP" | "FIXED">;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.feeTypeValToKeyMap = exports.FeeType = void 0;
4
+ (function (FeeType) {
5
+ FeeType["PERCENT"] = "%";
6
+ FeeType["GAS_TIP"] = "gas+%";
7
+ FeeType["FIXED"] = "fixed";
8
+ })(exports.FeeType || (exports.FeeType = {}));
9
+ /** A map of fee type values to keys */
10
+ exports.feeTypeValToKeyMap = new Map(Object.keys(exports.FeeType).map((key) => [exports.FeeType[key], key]));
@@ -0,0 +1,152 @@
1
+ import { type Hex } from 'viem';
2
+ import type { HyperliquidAuthorization, HyperliquidDeposit, TypedDataField } from './origin-deposit.js';
3
+ /**
4
+ * Executing a Hyperliquid deposit, as pure data.
5
+ *
6
+ * Hyperliquid is the one origin whose deposit is never broadcast to a chain.
7
+ * The user signs a typed-data ACTION and that signed action is posted to
8
+ * Hyperliquid's own exchange API; Relay then observes the transfer and fills the
9
+ * route. Two details make this impossible to derive from the quote alone, and
10
+ * both are encoded here rather than rediscovered at a call site:
11
+ *
12
+ * 1. Relay's quote supplies `eip712Types`, `eip712PrimaryType` and the action,
13
+ * but NOT the signing domain. The domain is fixed by Hyperliquid and is
14
+ * reconstructed by {@link buildHyperliquidTypedData}.
15
+ * 2. Hyperliquid wants the signature split into `r`/`s`/`v` components, not the
16
+ * concatenated hex string a wallet returns.
17
+ *
18
+ * Kept free of transport so it is fully testable: nothing here signs, fetches,
19
+ * or reads a clock. The caller supplies the signature and performs the request.
20
+ *
21
+ * The shape mirrors Relay's own client, which is the only reference
22
+ * implementation of this exchange — their public documentation covers the
23
+ * generic `signature` step but not this action-bearing `transaction` step.
24
+ */
25
+ /** Where a signed Hyperliquid action is submitted. Hyperliquid's API, not Relay's. */
26
+ export declare const hyperliquidExchangeUrl = "https://api.hyperliquid.xyz/exchange";
27
+ /** The signing domain Hyperliquid requires. Fixed; never supplied by the quote. */
28
+ export declare const hyperliquidDomainName = "HyperliquidSignTransaction";
29
+ /** The signing domain's version. Fixed alongside {@link hyperliquidDomainName}. */
30
+ export declare const hyperliquidDomainVersion = "1";
31
+ /**
32
+ * The domain's `verifyingContract`. Hyperliquid actions are verified off-chain,
33
+ * so no contract is involved and the field is the all-zero address.
34
+ */
35
+ export declare const hyperliquidVerifyingContract: "0x0000000000000000000000000000000000000000";
36
+ /** A complete typed-data payload, ready to hand to a wallet's typed-data signing call. */
37
+ export type HyperliquidTypedData = {
38
+ domain: {
39
+ name: string;
40
+ version: string;
41
+ chainId: number;
42
+ verifyingContract: Hex;
43
+ };
44
+ types: Record<string, TypedDataField[]>;
45
+ primaryType: string;
46
+ /**
47
+ * The signed message. This exact object is ALSO the `action` submitted to the
48
+ * exchange, so the bytes signed and the bytes submitted cannot drift apart.
49
+ */
50
+ message: Record<string, unknown>;
51
+ };
52
+ /**
53
+ * Builds the typed-data payload for a Hyperliquid deposit.
54
+ *
55
+ * The message is the action's parameters plus the action `type` and a
56
+ * `signatureChainId`; the latter is the signing chain in hex and MUST agree
57
+ * with `domain.chainId`, because Hyperliquid recovers the signer using both.
58
+ * They are derived from the single `signatureChainId` argument so they cannot
59
+ * disagree.
60
+ *
61
+ * @param deposit - the parsed Hyperliquid origin deposit
62
+ * @param options.signatureChainId - the chain id the connected wallet signs
63
+ * under. Not the Relay origin chain id: it identifies the signing domain, and
64
+ * Relay's own client uses the wallet's active chain here.
65
+ * @returns the payload to sign, whose `message` doubles as the submitted action
66
+ */
67
+ export declare const buildHyperliquidTypedData: (deposit: HyperliquidDeposit, { signatureChainId }: {
68
+ signatureChainId: number;
69
+ }) => HyperliquidTypedData;
70
+ /** The JSON body Hyperliquid's exchange endpoint expects for a signed action. */
71
+ export type HyperliquidExchangeRequest = {
72
+ /** The signature split into components; the concatenated hex form is rejected. */
73
+ signature: {
74
+ r: Hex;
75
+ s: Hex;
76
+ v: number;
77
+ };
78
+ /** Replay-protection nonce, which must match the nonce inside the signed action. */
79
+ nonce: number;
80
+ /** The signed message, submitted verbatim. */
81
+ action: Record<string, unknown>;
82
+ };
83
+ /**
84
+ * Builds the exchange request for an action the user has signed.
85
+ *
86
+ * The nonce is read back out of the signed message rather than passed in: it is
87
+ * covered by the signature, so any independently supplied value could disagree
88
+ * with what was signed and be rejected.
89
+ *
90
+ * @param options.typedData - the payload that was signed
91
+ * @param options.signature - the wallet's signature over it
92
+ * @returns the request body, or null when the signed action carries no usable nonce
93
+ */
94
+ export declare const buildHyperliquidExchangeRequest: ({ typedData, signature, }: {
95
+ typedData: HyperliquidTypedData;
96
+ signature: Hex;
97
+ }) => HyperliquidExchangeRequest | null;
98
+ /**
99
+ * Whether an exchange response reports success. Hyperliquid answers with HTTP
100
+ * 200 even for a rejected action, so the body's own status is the only reliable
101
+ * signal — treating the status code as the outcome would report a failed
102
+ * transfer as a completed one.
103
+ *
104
+ * @param payload - the parsed response body
105
+ * @returns true only when the body explicitly reports success
106
+ */
107
+ export declare const isHyperliquidExchangeSuccess: (payload: unknown) => boolean;
108
+ /**
109
+ * The typed-data payload for the authorization that must be completed BEFORE
110
+ * the action is submitted.
111
+ *
112
+ * Relay builds the authorization against a chain it picks when quoting, but the
113
+ * signature is produced by whichever chain the wallet is actually on. Both the
114
+ * domain here and `signatureChainId` in {@link buildHyperliquidAuthorizationRequest}
115
+ * are therefore overridden with the active wallet chain; leaving Relay's value in
116
+ * place makes the recovered signer disagree with the submitted one and the
117
+ * authorization is rejected.
118
+ *
119
+ * @param authorization - the authorization carried by the deposit
120
+ * @param options.signatureChainId - the chain id the connected wallet signs under
121
+ * @returns the payload to sign
122
+ */
123
+ export declare const buildHyperliquidAuthorizationTypedData: (authorization: HyperliquidAuthorization, { signatureChainId }: {
124
+ signatureChainId: number;
125
+ }) => HyperliquidTypedData;
126
+ /** A prepared authorization submission: where to send it, and what to send. */
127
+ export type HyperliquidAuthorizationRequest = {
128
+ /**
129
+ * The absolute URL, INCLUDING the signature as a query parameter. Relay reads
130
+ * the signature from the query string, not the body — a request carrying it in
131
+ * the body is accepted and then fails to authorize.
132
+ */
133
+ url: string;
134
+ method: string;
135
+ body: Record<string, unknown>;
136
+ };
137
+ /**
138
+ * Builds the authorization submission for a signed authorization.
139
+ *
140
+ * @param options.authorization - the authorization that was signed
141
+ * @param options.signature - the wallet's signature over its typed data
142
+ * @param options.signatureChainId - the chain id the wallet signed under, which
143
+ * replaces the value Relay quoted so the body agrees with the signature
144
+ * @param options.baseUrl - Relay's API root; the step's endpoint is relative
145
+ * @returns the request to perform, or null when the endpoint is not a usable path
146
+ */
147
+ export declare const buildHyperliquidAuthorizationRequest: ({ authorization, signature, signatureChainId, baseUrl, }: {
148
+ authorization: HyperliquidAuthorization;
149
+ signature: Hex;
150
+ signatureChainId: number;
151
+ baseUrl?: string;
152
+ }) => HyperliquidAuthorizationRequest | null;