@gibs/bridge-sdk 1.18.0 → 1.20.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 (120) hide show
  1. package/README.md +33 -0
  2. package/dist/abis.js +0 -2
  3. package/dist/bridge-limits.js +0 -38
  4. package/dist/chain-info.js +0 -116
  5. package/dist/chain-names.js +0 -151
  6. package/dist/chains.js +0 -198
  7. package/dist/cjs/abis.js +0 -2
  8. package/dist/cjs/bridge-limits.js +0 -38
  9. package/dist/cjs/chain-info.js +0 -116
  10. package/dist/cjs/chain-names.js +0 -151
  11. package/dist/cjs/chains.js +0 -198
  12. package/dist/cjs/claims.js +0 -60
  13. package/dist/cjs/config.js +1 -208
  14. package/dist/cjs/consolidated-quote.js +2 -464
  15. package/dist/cjs/destination-calldata.js +0 -71
  16. package/dist/cjs/ecosystems.js +0 -183
  17. package/dist/cjs/execution.js +0 -92
  18. package/dist/cjs/fee-type.js +0 -1
  19. package/dist/cjs/hyperliquid-execution.js +0 -98
  20. package/dist/cjs/image-links.js +0 -108
  21. package/dist/cjs/lifi-execution-guard.js +65 -172
  22. package/dist/cjs/near-intents-conformance.js +0 -110
  23. package/dist/cjs/near-intents-route.d.ts +13 -0
  24. package/dist/cjs/near-intents-route.js +7 -140
  25. package/dist/cjs/near-intents.js +0 -562
  26. package/dist/cjs/origin-deposit.js +0 -56
  27. package/dist/cjs/pre-quote.js +0 -80
  28. package/dist/cjs/prices.js +0 -113
  29. package/dist/cjs/providers.js +0 -83
  30. package/dist/cjs/quote-fees.js +0 -80
  31. package/dist/cjs/referral.js +0 -75
  32. package/dist/cjs/relay-currencies.js +0 -31
  33. package/dist/cjs/relay-depository.js +52 -77
  34. package/dist/cjs/relay-quote.js +0 -394
  35. package/dist/cjs/route-steps.js +0 -100
  36. package/dist/cjs/routing/amounts.js +0 -83
  37. package/dist/cjs/routing/candidate-route.d.ts +46 -1
  38. package/dist/cjs/routing/candidate-route.js +12 -40
  39. package/dist/cjs/routing/candidate.js +0 -46
  40. package/dist/cjs/routing/carrier-provider-key.js +0 -27
  41. package/dist/cjs/routing/carriers/omnibridge.js +0 -120
  42. package/dist/cjs/routing/carriers/pulsex-paths.js +0 -57
  43. package/dist/cjs/routing/carriers/pulsex-split.js +0 -92
  44. package/dist/cjs/routing/carriers/pulsex.js +0 -279
  45. package/dist/cjs/routing/carriers/wrap.js +0 -57
  46. package/dist/cjs/routing/composed-route-quality.js +0 -95
  47. package/dist/cjs/routing/entry-chain-anchor.js +0 -27
  48. package/dist/cjs/routing/format.js +0 -50
  49. package/dist/cjs/routing/index.d.ts +1 -1
  50. package/dist/cjs/routing/index.js +3 -30
  51. package/dist/cjs/routing/producers.js +0 -854
  52. package/dist/cjs/routing/providers.js +0 -27
  53. package/dist/cjs/routing/search/compose.js +0 -56
  54. package/dist/cjs/routing/search/graph.js +0 -364
  55. package/dist/cjs/routing/search/plan-route-data.js +5 -510
  56. package/dist/cjs/routing/search/score.js +0 -344
  57. package/dist/cjs/routing/swap-transactions.js +0 -74
  58. package/dist/cjs/routing/usd-value.js +0 -12
  59. package/dist/cjs/settings.js +1 -456
  60. package/dist/cjs/swap-venues.js +0 -17
  61. package/dist/cjs/ton-connect.js +0 -82
  62. package/dist/cjs/ton-execution.js +0 -6
  63. package/dist/cjs/ton.js +0 -42
  64. package/dist/cjs/tron-execution.js +0 -145
  65. package/dist/cjs/types.d.ts +8 -0
  66. package/dist/claims.js +0 -60
  67. package/dist/config.js +1 -211
  68. package/dist/consolidated-quote.js +2 -464
  69. package/dist/destination-calldata.js +0 -71
  70. package/dist/ecosystems.js +0 -183
  71. package/dist/execution.js +0 -92
  72. package/dist/fee-type.js +0 -2
  73. package/dist/hyperliquid-execution.js +0 -98
  74. package/dist/image-links.js +0 -108
  75. package/dist/lifi-execution-guard.js +65 -172
  76. package/dist/near-intents-conformance.js +0 -110
  77. package/dist/near-intents-route.d.ts +13 -0
  78. package/dist/near-intents-route.js +5 -139
  79. package/dist/near-intents.js +0 -562
  80. package/dist/origin-deposit.js +0 -56
  81. package/dist/pre-quote.js +0 -80
  82. package/dist/prices.js +0 -113
  83. package/dist/providers.js +0 -83
  84. package/dist/quote-fees.js +0 -80
  85. package/dist/referral.js +0 -75
  86. package/dist/relay-currencies.js +0 -31
  87. package/dist/relay-depository.js +52 -77
  88. package/dist/relay-quote.js +0 -394
  89. package/dist/route-steps.js +0 -100
  90. package/dist/routing/amounts.js +0 -83
  91. package/dist/routing/candidate-route.d.ts +46 -1
  92. package/dist/routing/candidate-route.js +10 -39
  93. package/dist/routing/candidate.js +0 -46
  94. package/dist/routing/carrier-provider-key.js +0 -27
  95. package/dist/routing/carriers/omnibridge.js +0 -120
  96. package/dist/routing/carriers/pulsex-paths.js +0 -57
  97. package/dist/routing/carriers/pulsex-split.js +0 -92
  98. package/dist/routing/carriers/pulsex.js +0 -279
  99. package/dist/routing/carriers/wrap.js +0 -57
  100. package/dist/routing/composed-route-quality.js +0 -95
  101. package/dist/routing/entry-chain-anchor.js +0 -27
  102. package/dist/routing/format.js +0 -50
  103. package/dist/routing/index.d.ts +1 -1
  104. package/dist/routing/index.js +1 -29
  105. package/dist/routing/producers.js +0 -854
  106. package/dist/routing/providers.js +0 -27
  107. package/dist/routing/search/compose.js +0 -56
  108. package/dist/routing/search/graph.js +0 -364
  109. package/dist/routing/search/plan-route-data.js +6 -511
  110. package/dist/routing/search/score.js +0 -344
  111. package/dist/routing/swap-transactions.js +0 -74
  112. package/dist/routing/usd-value.js +0 -12
  113. package/dist/settings.js +1 -456
  114. package/dist/swap-venues.js +0 -17
  115. package/dist/ton-connect.js +0 -82
  116. package/dist/ton-execution.js +0 -6
  117. package/dist/ton.js +0 -42
  118. package/dist/tron-execution.js +0 -145
  119. package/dist/types.d.ts +8 -0
  120. package/package.json +3 -3
@@ -9,64 +9,9 @@ const referral_js_1 = require("./referral.js");
9
9
  const chain_names_js_1 = require("./chain-names.js");
10
10
  const route_steps_js_1 = require("./route-steps.js");
11
11
  const quote_fees_js_1 = require("./quote-fees.js");
12
- /**
13
- * Relay (relay.link) as a second consolidated-route quote provider, competing
14
- * with LI.FI on price. Relay quotes the same backwards-from-destination route:
15
- * deliver exactly `toAmount` of the Ethereum-side token, then run our omnibridge
16
- * entry call against it.
17
- *
18
- * One semantic differs from LI.FI and the difference is load-bearing. Relay has
19
- * NO destination-chain fallback address. When the destination call cannot fill,
20
- * Relay refunds on the ORIGIN chain to `refundTo`, in the origin currency — the
21
- * user ends up back where they started, not holding the Ethereum-side token at
22
- * a fallback. We therefore map our `fallbackAddress` onto `refundTo`; a failed
23
- * Relay route is recovered on the origin chain, never stranded on Ethereum.
24
- */
25
- /**
26
- * Relay's API root. Steps carry RELATIVE post endpoints (`/authorize`), so a
27
- * caller completing one has to resolve it against this.
28
- */
29
12
  exports.relayApiBaseUrl = 'https://api.relay.link';
30
- /** Relay quote endpoint. Anonymous access works at a 50-requests-per-minute tier. */
31
13
  exports.relayQuoteUrl = `${exports.relayApiBaseUrl}/quote/v2`;
32
- /** Relay requests endpoint; filters by origin or destination transaction hash. */
33
- /**
34
- * The request-lookup endpoint, used to poll a route's progress.
35
- *
36
- * v3 RATHER THAN v2 BECAUSE v2 IS GOING AWAY. Relay began staged rate limiting
37
- * of `/requests/v2` on 2026-09-01 and retires it on 2026-11-24, saying so in a
38
- * `deprecation` block on every v2 response. v3 REQUIRES `x-api-key` - it
39
- * answers 400 without one, where v2 served anonymous callers from a shared
40
- * pool - so a caller must send `relayRequestHeaders(yourRelayApiKey)`.
41
- */
42
14
  exports.relayRequestsUrl = 'https://api.relay.link/requests/v3';
43
- /**
44
- * Builds the headers for a Relay request. `apiKey` is Relay's `x-api-key`
45
- * value. This package ships no key: the caller supplies its own (the Gibs
46
- * interface keeps its key in `packages/ui/src/lib/config.ts`).
47
- * Relay raises the account's rate limit and attributes traffic to it when the
48
- * header is present.
49
- *
50
- * When `apiKey` is absent or an empty string, the returned headers carry NO
51
- * `x-api-key` entry at all — not an empty one.
52
- *
53
- * WHETHER THAT IS SURVIVABLE DEPENDS ENTIRELY ON WHICH ENDPOINT IS BEING CALLED,
54
- * and this note used to say only the reassuring half. Measured against the live
55
- * service:
56
- *
57
- * POST /quote no key -> 200 routing works anonymously
58
- * GET /requests/v3 no key -> 400 "headers must have required
59
- * property 'x-api-key'"
60
- *
61
- * So a missing key is a normal operating state for ROUTING — a reader on a
62
- * local build or the anonymous InterPlanetary File System deployment still gets
63
- * real quotes, and clearing the key disables attribution rather than the
64
- * product. It is NOT survivable for STATUS. Every status poll from a keyless
65
- * build fails, which means a consolidated record never learns its provider
66
- * finished, never records the entry-chain transaction, and never releases from
67
- * the pending list. That is not a degraded rate limit; it is the feature not
68
- * working at all, silently.
69
- */
70
15
  const relayRequestHeaders = (apiKey) => {
71
16
  const headers = { 'Content-Type': 'application/json' };
72
17
  if (apiKey) {
@@ -75,158 +20,48 @@ const relayRequestHeaders = (apiKey) => {
75
20
  return headers;
76
21
  };
77
22
  exports.relayRequestHeaders = relayRequestHeaders;
78
- /**
79
- * Gibs Finance's own Relay `referrer`, for callers that want to attribute to
80
- * Gibs Finance. The request builders do NOT default to it: pass it, or your
81
- * own, as `relayReferrer` on the request. Relay reads any `referrer` as "a
82
- * referrer was supplied" and then requires an API key, so a default would
83
- * break every caller without one.
84
- */
85
23
  exports.relayReferrer = referral_js_1.referralIntegrator;
86
- /**
87
- * Application fee in basis points charged on Relay routes. Ten basis points is
88
- * one tenth of a percent. Sent as `appFees[0].fee` when a payout recipient is
89
- * configured; absent entirely when the recipient is missing.
90
- */
91
24
  exports.relayReferralFeeBasisPoints = referral_js_1.defaultReferralFeeBasisPoints;
92
25
  var referral_js_2 = require("./referral.js");
93
26
  Object.defineProperty(exports, "relayReferralRecipient", { enumerable: true, get: function () { return referral_js_2.relayReferralRecipient; } });
94
- /** Extra gas added to the destination budget to cover a prepended approval call. */
95
27
  exports.relayApprovalGasBuffer = 60000n;
96
- /**
97
- * Relay's chain identifiers and their display names live in `chain-names.ts`
98
- * so the route-step normalizer can name a Relay chain without importing this
99
- * module, which imports it. Re-exported here because callers reach for them
100
- * alongside the rest of the Relay surface.
101
- */
102
28
  var chain_names_js_2 = require("./chain-names.js");
103
29
  Object.defineProperty(exports, "relayChainIds", { enumerable: true, get: function () { return chain_names_js_2.relayChainIds; } });
104
30
  Object.defineProperty(exports, "relayChainNames", { enumerable: true, get: function () { return chain_names_js_2.relayChainNames; } });
105
- /**
106
- * Relay's pseudo chain identifiers, mapped to the ecosystem each belongs to.
107
- * Data rather than a branch chain, so registering another Relay origin is one
108
- * entry here instead of another conditional.
109
- */
110
31
  const ecosystemByRelayChainId = new Map([
111
32
  [chain_names_js_1.relayChainIds.solana, 'svm'],
112
- // two chain ids, one ecosystem: the mapping is many-to-one by design
113
33
  [chain_names_js_1.relayChainIds.eclipse, 'svm'],
114
34
  [chain_names_js_1.relayChainIds.bitcoin, 'bvm'],
115
35
  [chain_names_js_1.relayChainIds.tron, 'tvm'],
116
36
  [chain_names_js_1.relayChainIds.ton, 'tonvm'],
117
37
  [chain_names_js_1.relayChainIds.hyperliquid, 'hypevm'],
118
38
  ]);
119
- /**
120
- * The chains a reader pays by hand, mapped to the ecosystem each belongs to.
121
- *
122
- * KEPT APART FROM THE RELAY MAP ABOVE, because none of these is a Relay chain
123
- * and a map named for Relay should not claim one. They are here at all because
124
- * {@link ecosystemByChainId} answers `evm` for every identifier it does not
125
- * know. An unregistered Zcash identifier would therefore read as an Ethereum
126
- * chain — which has a wallet, a signer and a transaction — and the reader would
127
- * be asked to sign on a chain they do not hold.
128
- *
129
- * Typed `Record<DepositAddressChain, Ecosystem>` rather than `Map<number, …>`
130
- * so a chain added to {@link depositAddressChainIds} without an ecosystem
131
- * here is a compile error. This is the table finding this danger is about: a
132
- * silent miss is exactly the "reads as Ethereum" failure the comment above
133
- * warns against, and a compile error is the only guard that cannot be
134
- * forgotten.
135
- */
136
39
  const ecosystemByDepositAddressChain = {
137
40
  zcash: 'zcash',
138
41
  };
139
- /** {@link ecosystemByDepositAddressChain}, keyed by chain id for lookup. */
140
42
  const ecosystemByDepositAddressChainId = new Map(Object.keys(chain_names_js_1.depositAddressChainIds).map((chain) => [
141
43
  chain_names_js_1.depositAddressChainIds[chain],
142
44
  ecosystemByDepositAddressChain[chain],
143
45
  ]));
144
- /**
145
- * Maps a chain identifier to its virtual-machine ecosystem. Relay's non-Ethereum
146
- * pseudo chain identifiers map to their own ecosystem; every other identifier
147
- * (every Ethereum Virtual Machine chain) maps to `evm`. Total — never throws.
148
- *
149
- * Lives here rather than in `ecosystems.ts` because it depends on
150
- * `relayChainIds` (defined in this file); the `Ecosystem` import is type-only,
151
- * so `ecosystems.ts` stays a dependency-free leaf and no import cycle is formed.
152
- *
153
- * @param chainId - a chain identifier (an Ethereum chain id, or a Relay pseudo id)
154
- * @returns the ecosystem that chain belongs to
155
- */
156
46
  const ecosystemByChainId = (chainId) => ecosystemByRelayChainId.get(chainId) ?? ecosystemByDepositAddressChainId.get(chainId) ?? 'evm';
157
47
  exports.ecosystemByChainId = ecosystemByChainId;
158
- /**
159
- * Relay's native-currency address strings, used verbatim as `originCurrency`
160
- * when the origin pays in the chain's native asset.
161
- *
162
- * Source: https://api.relay.link/chains.
163
- */
164
48
  exports.relayNativeCurrencyAddresses = {
165
- /**
166
- * Ethereum Virtual Machine native currency (Ether, native gas tokens). The
167
- * all-zero address Relay uses across every Ethereum Virtual Machine chain.
168
- */
169
49
  ethereumVirtualMachine: '0x0000000000000000000000000000000000000000',
170
- /**
171
- * Solana native currency (SOL), addressed by the System Program. Nine
172
- * decimals.
173
- */
174
50
  solana: '11111111111111111111111111111111',
175
- /** Bitcoin native currency (BTC). Eight decimals. */
176
51
  bitcoin: 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8',
177
- /** Tron native currency (TRX). Six decimals. */
178
52
  tron: 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb',
179
- /**
180
- * The Open Network's native currency as Relay reports it: Gram, NOT the
181
- * Toncoin gas asset. Nine decimals.
182
- */
183
53
  ton: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c',
184
- /**
185
- * Hyperliquid's native currency as Relay reports it: USD Coin, NOT the Hype
186
- * gas asset, addressed by a sixteen-byte HyperCore token identifier. Eight
187
- * decimals. Deliberately NOT the twenty-byte all-zero Ethereum address.
188
- */
189
54
  hyperliquid: '0x00000000000000000000000000000000',
190
55
  };
191
- /**
192
- * Converts a slippage fraction into the basis-point string Relay expects.
193
- *
194
- * @param slippage - tolerance as a fraction (0.005 means half a percent)
195
- * @returns basis points as a string (0.005 becomes "50")
196
- */
197
56
  const slippageToBasisPoints = (slippage) => Math.round(slippage * 10_000).toString();
198
57
  exports.slippageToBasisPoints = slippageToBasisPoints;
199
- /**
200
- * The `referrer` field of a Relay request body, present only when the caller
201
- * named one. Relay reads any `referrer`, an empty one included, as "a referrer
202
- * was supplied" and then requires an API key, so absence is the safe default.
203
- *
204
- * @param request - carries the caller's `relayReferrer`, if any
205
- * @returns `{ referrer }`, or an empty object
206
- */
207
58
  const relayReferrerField = (request) => {
208
59
  const referrer = (0, referral_js_1.resolveAttribution)(request.relayReferrer, undefined);
209
60
  return referrer === undefined ? {} : { referrer };
210
61
  };
211
62
  exports.relayReferrerField = relayReferrerField;
212
- /**
213
- * Builds the Relay contract-call quote request from a provider-agnostic
214
- * consolidated request. The omnibridge entry call becomes the final `txs`
215
- * entry; when it needs an ERC20 allowance (the relayTokens shape, where
216
- * `approvalTarget` is set) an `approve` call is prepended so Relay's executor
217
- * grants it before relaying.
218
- *
219
- * @returns the request body, or null when the inputs cannot form a valid call
220
- */
221
63
  const buildRelayQuoteRequest = (request) => {
222
64
  const { destinationCall, toAmount } = request;
223
- // A DIRECT ROUTE — no omnibridge leg, so nothing to call on arrival.
224
- //
225
- // Solved FORWARDS rather than backwards, which is the whole difference. A
226
- // route into the omnibridge must deliver an exact amount to the entry call,
227
- // so it asks Relay for an exact OUTPUT. Here the reader says what they are
228
- // spending and the delivered amount is whatever the market gives, so it asks
229
- // for an exact INPUT and names a `recipient` instead of a transaction to run.
230
65
  if (destinationCall === undefined) {
231
66
  const fromAmount = request.fromAmount;
232
67
  if (fromAmount === undefined || fromAmount <= 0n) {
@@ -241,12 +76,7 @@ const buildRelayQuoteRequest = (request) => {
241
76
  destinationCurrency: request.toTokenAddress,
242
77
  amount: fromAmount.toString(),
243
78
  tradeType: 'EXACT_INPUT',
244
- // Where the funds land. On a route through the omnibridge this is encoded
245
- // inside the entry call; with no call to carry it, Relay is told directly.
246
79
  recipient: request.recipient,
247
- // Same rule as the omnibridge path below: Relay refunds on the ORIGIN
248
- // chain, so a non-Ethereum origin cannot be refunded to an Ethereum
249
- // fallback address and must name its own.
250
80
  refundTo: nonEthereumOriginDirect ? request.fromAddress : request.fallbackAddress,
251
81
  ...(0, exports.relayReferrerField)(request),
252
82
  ...(request.slippage === undefined
@@ -275,21 +105,12 @@ const buildRelayQuoteRequest = (request) => {
275
105
  if (toAmount <= 0n) {
276
106
  return null;
277
107
  }
278
- // A NATIVE ENTRY (`wrapAndRelayTokens`) CARRIES VALUE, and Relay's solver
279
- // attaches it: a dry quote with this exact call simulates it on the entry
280
- // chain (see `providers.ts`'s `destinationCallCarriesNativeValue` for the
281
- // measurement). Relay delivers the native coin itself, so no approval is
282
- // prepended — the call's own `approvalTarget` is null for this shape.
283
108
  const entryCall = {
284
109
  to: destinationCall.to,
285
110
  value: destinationCall.value.toString(),
286
111
  data: destinationCall.data,
287
112
  };
288
113
  const needsApproval = destinationCall.approvalTarget !== null;
289
- // grant an unbounded allowance, the standard executor pattern: Relay's
290
- // Multicaller holds the bridged tokens only transiently during the call
291
- // sequence, and an exact allowance would strand funds if the entry call ever
292
- // pulls a balance rather than the fixed amount encoded in its calldata
293
114
  const approvalCall = needsApproval
294
115
  ? {
295
116
  to: request.toTokenAddress,
@@ -303,24 +124,10 @@ const buildRelayQuoteRequest = (request) => {
303
124
  : null;
304
125
  const txs = approvalCall ? [approvalCall, entryCall] : [entryCall];
305
126
  const txsGasLimit = destinationCall.gasLimit + (needsApproval ? exports.relayApprovalGasBuffer : 0n);
306
- // The omnibridge has two entry points: Ethereum and Binance Smart Chain. The
307
- // destination chain MUST track the entry chain the request targets, because
308
- // `destinationCurrency` is the entry-chain token address — pairing a
309
- // Binance-side token with a hardcoded Ethereum destination makes Relay reject
310
- // the quote with "Invalid input or output currency" (that token does not exist
311
- // on Ethereum). Defaults to Ethereum, preserving the original single-entry
312
- // behavior when `toChainId` is omitted.
313
127
  const destinationChainId = request.toChainId ?? Number(config_js_1.Chains.ETH);
314
128
  const nonEthereumOrigin = (0, consolidated_quote_js_1.isNonEthereumVirtualMachineOrigin)(request);
315
- // Relay always refunds a failed route on the ORIGIN chain. For an Ethereum
316
- // Virtual Machine origin the user's Ethereum-side fallback address doubles as
317
- // that origin refund target (unchanged behavior). For a non-Ethereum origin
318
- // the fallback address is an Ethereum address Relay cannot refund to on the
319
- // origin chain, so the refund must go to the user's own origin-chain address.
320
129
  const refundTo = nonEthereumOrigin ? request.fromAddress : request.fallbackAddress;
321
- // Relay's Solana fee sponsorship; only included for a Solana origin that names a payer.
322
130
  const includeDepositFeePayer = request.originVmType === 'svm' && request.solanaFeePayer !== undefined;
323
- // Relay's Bitcoin pay-to-script-hash public key; only for a Bitcoin origin that supplies one.
324
131
  const includeBitcoinPublicKey = request.originVmType === 'bvm' && request.bitcoinPublicKey !== undefined;
325
132
  return {
326
133
  user: request.fromAddress,
@@ -330,7 +137,6 @@ const buildRelayQuoteRequest = (request) => {
330
137
  destinationCurrency: request.toTokenAddress,
331
138
  amount: toAmount.toString(),
332
139
  tradeType: 'EXACT_OUTPUT',
333
- // origin-chain refund target — Relay's only failure remedy for this route
334
140
  refundTo,
335
141
  ...(0, exports.relayReferrerField)(request),
336
142
  txs,
@@ -349,12 +155,6 @@ const buildRelayQuoteRequest = (request) => {
349
155
  };
350
156
  exports.buildRelayQuoteRequest = buildRelayQuoteRequest;
351
157
  const isHexString = (value) => typeof value === 'string' && value.startsWith('0x');
352
- /**
353
- * Parses a quantity Relay may report as a hex string, a decimal string, or a
354
- * number into a bigint.
355
- *
356
- * @returns the bigint value, or null when the input is not a parseable quantity
357
- */
358
158
  const parseQuantity = (value) => {
359
159
  if (typeof value === 'number' && Number.isInteger(value)) {
360
160
  return BigInt(value);
@@ -375,11 +175,6 @@ const asRecord = (value) => {
375
175
  }
376
176
  return value;
377
177
  };
378
- /**
379
- * Pulls the signable transaction out of a Relay step item.
380
- *
381
- * @returns the transaction data, or null when the item has no usable transaction
382
- */
383
178
  const stepItemTransaction = (item) => {
384
179
  const record = asRecord(item);
385
180
  const data = asRecord(record?.data);
@@ -391,13 +186,6 @@ const stepItemTransaction = (item) => {
391
186
  }
392
187
  return data;
393
188
  };
394
- /**
395
- * Pulls a Solana instruction set out of a Relay deposit step item. A Solana
396
- * deposit carries `data.instructions[]` plus the address-lookup-table addresses
397
- * to compile a versioned transaction, and no `to`/`data` hex fields.
398
- *
399
- * @returns the instruction set, or null when the item is not a Solana deposit
400
- */
401
189
  const stepItemSolanaInstructions = (item) => {
402
190
  const data = asRecord(asRecord(item)?.data);
403
191
  if (!data || !Array.isArray(data.instructions)) {
@@ -417,13 +205,6 @@ const stepItemSolanaInstructions = (item) => {
417
205
  : [];
418
206
  return { instructions, addressLookupTableAddresses: lookupTables };
419
207
  };
420
- /**
421
- * Pulls a Bitcoin partially-signed transaction out of a Relay deposit step
422
- * item. Relay hex-encodes it (the "psbt\xff" magic, `70736274ff…`) and it is not
423
- * `0x`-prefixed, so the Ethereum hex gate does not match it.
424
- *
425
- * @returns the partially-signed transaction, or null when the item is not a Bitcoin deposit
426
- */
427
208
  const stepItemBitcoinPsbt = (item) => {
428
209
  const data = asRecord(asRecord(item)?.data);
429
210
  if (!data || typeof data.psbt !== 'string' || data.psbt === '') {
@@ -431,13 +212,6 @@ const stepItemBitcoinPsbt = (item) => {
431
212
  }
432
213
  return { psbt: data.psbt };
433
214
  };
434
- /**
435
- * Normalizes a typed-data type table, keeping only well-formed `{name, type}`
436
- * fields. Shared by the Hyperliquid action and its authorization, which carry
437
- * the same table shape under different keys.
438
- *
439
- * @returns the type table; empty when the payload carries none
440
- */
441
215
  const typedDataTypes = (value) => {
442
216
  const record = asRecord(value);
443
217
  if (!record) {
@@ -457,14 +231,6 @@ const typedDataTypes = (value) => {
457
231
  });
458
232
  return Object.fromEntries(entries);
459
233
  };
460
- /**
461
- * Pulls a Tron contract call out of a Relay deposit step item. Tron's wire shape
462
- * nests snake_case fields under `parameter` and names the contract kind in
463
- * `type`; its `data` is bare hex with no `0x` prefix, so the Ethereum hex gate
464
- * never claims it.
465
- *
466
- * @returns the contract call, or null when the item is not a Tron deposit
467
- */
468
234
  const stepItemTronContract = (item) => {
469
235
  const data = asRecord(asRecord(item)?.data);
470
236
  if (!data || typeof data.type !== 'string') {
@@ -477,8 +243,6 @@ const stepItemTronContract = (item) => {
477
243
  const ownerAddress = parameter.owner_address;
478
244
  const contractAddress = parameter.contract_address;
479
245
  const callData = parameter.data;
480
- // require every field we map, so a wire-shape change fails closed rather than
481
- // producing a deposit with silently empty addresses
482
246
  if (typeof ownerAddress !== 'string' ||
483
247
  typeof contractAddress !== 'string' ||
484
248
  typeof callData !== 'string') {
@@ -488,18 +252,10 @@ const stepItemTronContract = (item) => {
488
252
  contractType: data.type,
489
253
  ownerAddress,
490
254
  contractAddress,
491
- // a call that sends no TRX omits the field rather than sending zero
492
255
  callValue: parseQuantity(parameter.call_value) ?? 0n,
493
256
  data: callData,
494
257
  };
495
258
  };
496
- /**
497
- * Pulls a TON message list out of a Relay deposit step item. TON wallets send a
498
- * list of messages rather than one transaction, and each payload is a base64
499
- * bag-of-cells rather than hex.
500
- *
501
- * @returns the message list, or null when the item is not a TON deposit
502
- */
503
259
  const stepItemTonMessages = (item) => {
504
260
  const data = asRecord(asRecord(item)?.data);
505
261
  if (!data || !Array.isArray(data.messages)) {
@@ -519,9 +275,7 @@ const stepItemTonMessages = (item) => {
519
275
  to: record.to,
520
276
  value,
521
277
  body: record.body,
522
- // mode 0 sends with no special flags, TON's own default
523
278
  mode: typeof record.mode === 'number' ? record.mode : 0,
524
- // absent means non-bouncing; only an explicit true bounces
525
279
  bounce: record.bounce === true,
526
280
  from: typeof record.from === 'string' ? record.from : null,
527
281
  },
@@ -532,14 +286,6 @@ const stepItemTonMessages = (item) => {
532
286
  }
533
287
  return { messages };
534
288
  };
535
- /**
536
- * Pulls the typed-data action out of a Relay Hyperliquid deposit step item.
537
- * Nothing here is broadcast: the action is signed and posted to Hyperliquid's
538
- * API, so there is no `to`, no calldata, and no gas for the Ethereum hex gate to
539
- * match.
540
- *
541
- * @returns the action, or null when the item is not a Hyperliquid deposit
542
- */
543
289
  const stepItemHyperliquidAction = (item) => {
544
290
  const data = asRecord(asRecord(item)?.data);
545
291
  if (!data || typeof data.eip712PrimaryType !== 'string') {
@@ -556,15 +302,6 @@ const stepItemHyperliquidAction = (item) => {
556
302
  nonce: parseQuantity(data.nonce) ?? 0n,
557
303
  };
558
304
  };
559
- /**
560
- * Finds the authorization a Hyperliquid deposit must complete before its action
561
- * can be submitted. It arrives as its own `signature` step ahead of the deposit,
562
- * which the deposit scan skips because it carries no deposit shape — so it is
563
- * collected separately and attached to the deposit, rather than lost.
564
- *
565
- * @param steps - every step on the quote
566
- * @returns the authorization, or null when the quote carries none
567
- */
568
305
  const stepAuthorization = (steps) => {
569
306
  for (const step of steps) {
570
307
  if (step.kind !== 'signature' || !Array.isArray(step.items)) {
@@ -598,17 +335,6 @@ const stepAuthorization = (steps) => {
598
335
  }
599
336
  return null;
600
337
  };
601
- /**
602
- * Recognizes the one deposit shape a Relay step item carries, trying the
603
- * Ethereum transaction shape first (the only one gated on hex `to`/`data`), then
604
- * each non-Ethereum shape in turn. Every shape is keyed on a field the others do
605
- * not carry, so the recognizers are mutually exclusive and the order is a
606
- * cheapest-check-first convenience rather than a correctness requirement — a
607
- * property the tests pin, because a future overlap would silently mis-route a
608
- * deposit to the wrong ecosystem's signer.
609
- *
610
- * @returns the discriminated deposit, or null when the item carries none
611
- */
612
338
  const stepItemDeposit = (item) => {
613
339
  const transaction = stepItemTransaction(item);
614
340
  if (transaction) {
@@ -636,13 +362,6 @@ const stepItemDeposit = (item) => {
636
362
  }
637
363
  return null;
638
364
  };
639
- /**
640
- * Extracts the ERC20 spender from a Relay `approve` step so our own approval
641
- * machinery can grant it. The origin token, not Relay, decides the spender, so
642
- * we decode it from the ready-made approval calldata rather than guessing.
643
- *
644
- * @returns the spender address, or null when the step is absent or undecodable
645
- */
646
365
  const approvalSpender = (steps) => {
647
366
  const approveStep = steps.find((step) => step.id === 'approve');
648
367
  if (!approveStep) {
@@ -664,18 +383,10 @@ const approvalSpender = (steps) => {
664
383
  }
665
384
  }
666
385
  catch {
667
- // not an approve call we recognize; keep scanning
668
386
  }
669
387
  }
670
388
  return null;
671
389
  };
672
- /**
673
- * Finds the deposit the user signs after any approval — the first
674
- * deposit-bearing item on a step that is not the `approve` step — and reports
675
- * which source ecosystem's shape it carries.
676
- *
677
- * @returns the step and its discriminated deposit, or null when none is present
678
- */
679
390
  const depositStep = (steps) => {
680
391
  for (const step of steps) {
681
392
  if (step.id === 'approve') {
@@ -694,24 +405,6 @@ const depositStep = (steps) => {
694
405
  }
695
406
  return null;
696
407
  };
697
- /**
698
- * Maps a discriminated Relay deposit onto the shared `OriginDeposit` union.
699
- * Ethereum reads its chain id from the deposit transaction; the non-Ethereum
700
- * variants have no chain id on the deposit payload, so they read it from the
701
- * quote's origin currency (`details.currencyIn.currency.chainId`).
702
- *
703
- * The non-Ethereum variants are matched by an EXHAUSTIVE switch rather than a
704
- * trailing fallback: an unhandled variant must be a compile error, because
705
- * quietly treating one ecosystem's deposit as another's would hand a payload to
706
- * the wrong signer.
707
- *
708
- * @param found - the deposit and the step it was found on
709
- * @param currencyIn - the quote's `details.currencyIn`, the only source of an
710
- * origin chain id for a non-Ethereum deposit
711
- * @param steps - every step on the quote, needed to collect the Hyperliquid
712
- * authorization that arrives as its own step
713
- * @returns the origin deposit, or null when a required field is unparseable
714
- */
715
408
  const relayOriginDeposit = (found, currencyIn, steps) => {
716
409
  const { step, deposit } = found;
717
410
  if (deposit.kind === 'evm') {
@@ -768,14 +461,6 @@ const relayOriginDeposit = (found, currencyIn, steps) => {
768
461
  }
769
462
  }
770
463
  };
771
- /**
772
- * Normalizes a Relay `/quote/v2` response into the shared consolidated quote
773
- * shape. The origin approval Relay returns as its own step is folded back into
774
- * `approvalAddress` so the executor raises it through the same path as LI.FI;
775
- * the deposit step becomes the single `originDeposit`.
776
- *
777
- * @returns the normalized quote, or null when the payload shape is unexpected
778
- */
779
464
  const parseRelayQuote = (payload) => {
780
465
  const quote = asRecord(payload);
781
466
  if (!quote) {
@@ -803,8 +488,6 @@ const parseRelayQuote = (payload) => {
803
488
  if (!found) {
804
489
  return null;
805
490
  }
806
- // the identifier lives on the steps in the verified response shape; fall back
807
- // through a top-level field so a future nesting change does not reject quotes
808
491
  const requestId = typeof quote.requestId === 'string'
809
492
  ? quote.requestId
810
493
  : steps.map((step) => step.requestId).find((id) => typeof id === 'string');
@@ -822,102 +505,39 @@ const parseRelayQuote = (payload) => {
822
505
  tool: 'relay',
823
506
  toolName: 'Relay',
824
507
  fromAmount,
825
- // WHAT THE ROUTE DELIVERS, WHEN ONLY RELAY KNOWS. An omnibridge route names
826
- // its own delivered amount in the request and asks for an exact output, so
827
- // this repeats what the caller already said. A direct route asks for an
828
- // exact input, and the delivered amount exists nowhere until this answer.
829
- // Undefined rather than zero when the field is missing: zero is a real
830
- // quantity and would read as "this route delivers nothing".
831
508
  ...(() => {
832
509
  const out = parseQuantity(asRecord(details?.currencyOut)?.amount);
833
510
  return out === null ? {} : { toAmount: out };
834
511
  })(),
835
512
  fromAmountUsd: typeof currencyIn.amountUsd === 'string' ? currencyIn.amountUsd : null,
836
- // The delivered side valued by the same answer that valued the paid side —
837
- // see `ConsolidatedQuote.toAmountUsd` for why it may not come from anywhere
838
- // else. Omitted rather than nulled when Relay leaves it out.
839
513
  ...(() => {
840
514
  const outUsd = asRecord(details?.currencyOut)?.amountUsd;
841
515
  return typeof outUsd === 'string' ? { toAmountUsd: outUsd } : {};
842
516
  })(),
843
- // a native origin token is pulled with no allowance, so no spender applies
844
517
  approvalAddress: spender !== null && spender !== viem_1.zeroAddress ? spender : null,
845
518
  executionDurationSeconds: details.timeEstimate,
846
- // Relay's `steps` are operational (approve + deposit); the per-leg route
847
- // lives in `details.route`, so the whole quote is normalized, not `steps`.
848
519
  steps: (0, route_steps_js_1.normalizeRelaySteps)(quote),
849
520
  originDeposit,
850
521
  fees: (0, quote_fees_js_1.relayQuoteFees)(payload),
851
522
  };
852
523
  };
853
524
  exports.parseRelayQuote = parseRelayQuote;
854
- /**
855
- * Builds the requests-lookup address for a Relay route BY ITS QUOTE
856
- * IDENTIFIER.
857
- *
858
- * IT USED TO ASK BY ORIGIN TRANSACTION HASH, AND THAT RETURNED OTHER PEOPLE'S
859
- * TRANSFERS. `/requests/v3` does not accept a `hash` filter: it ignores the
860
- * parameter entirely and answers with the twenty most recent requests ACROSS
861
- * ALL USERS. Measured, with two different origin hashes a minute apart:
862
- *
863
- * ?hash=0x447149ed… -> 20 requests, first is 8453:0x7d7c3de2… -> 4663:…
864
- * ?hash=0xa650d2d7… -> the SAME 20 requests, same first entry
865
- *
866
- * `parseRelayStatus` reads `requests[0]`, so both of this account's transfers
867
- * were updated from a stranger's — they took the same entry-chain transaction
868
- * hash, and neither was their own. A transfer was reported finished because
869
- * somebody else's had finished.
870
- *
871
- * `id` is the filter v3 actually honours. The same lookup by quote identifier
872
- * returns exactly ONE request, and its `inTxs` name the origin transaction the
873
- * reader really signed. The caller should assert that correspondence rather
874
- * than trust it — see `checkConsolidatedRecord`.
875
- */
876
525
  const relayStatusUrl = ({ quoteId }) => {
877
526
  return (0, url_1.buildUrl)(exports.relayRequestsUrl, { id: quoteId });
878
527
  };
879
528
  exports.relayStatusUrl = relayStatusUrl;
880
- /**
881
- * Relay's request lifecycle states. Terminal states are `success` (the
882
- * destination call filled), `failure`, and `refund` (made whole on the origin
883
- * chain). Every other state is still in flight.
884
- */
885
529
  const relayInFlightStatuses = ['waiting', 'depositing', 'pending', 'submitted', 'delayed'];
886
530
  const isEthereumTransactionHash = (value) => typeof value === 'string' && /^0x[0-9a-fA-F]{64}$/.test(value);
887
- /**
888
- * Finds the destination-chain transaction hash among a Relay request's output
889
- * transactions — the hash that gates the handover to the omnibridge indexer.
890
- * The destination chain is the omnibridge entry chain the route targeted
891
- * (Ethereum or Binance Smart Chain), so it is supplied by the caller rather
892
- * than assumed.
893
- *
894
- * @param request - a Relay request record
895
- * @param destinationChainId - the omnibridge entry chain the route targeted
896
- * @returns the destination-chain transaction hash, or null when none recorded
897
- */
898
531
  const outputTransactions = (request) => {
899
- // RELAY NESTS THESE UNDER `data`. An earlier version read `request.outTxs`,
900
- // which no response has ever carried: measured 2026-09-01 across a hundred
901
- // live records, `request.outTxs` was present on ZERO and `request.data.outTxs`
902
- // on every one. So this returned null for every completed route, and the
903
- // interface reported DONE while linking nothing. The unit tests missed it
904
- // because they were written to the same wrong shape as the parser.
905
532
  const data = asRecord(request.data);
906
533
  if (Array.isArray(data?.outTxs)) {
907
534
  return data.outTxs;
908
535
  }
909
- // Kept as a fallback rather than deleted: it costs one array check, and a
910
- // response that does flatten them still reads correctly.
911
536
  if (Array.isArray(request.outTxs)) {
912
537
  return request.outTxs;
913
538
  }
914
539
  return [];
915
540
  };
916
- /**
917
- * The transaction hash on one output entry. `/requests/v2` names the field
918
- * `hash` and `/requests/v3` names it `txHash`; both appear in the wild, so both
919
- * are read rather than choosing by endpoint version.
920
- */
921
541
  const outputHashOf = (entry) => {
922
542
  const record = asRecord(entry);
923
543
  if (isEthereumTransactionHash(record?.txHash)) {
@@ -947,19 +567,6 @@ const destinationOutputHash = (request, destinationChainId) => {
947
567
  }
948
568
  return null;
949
569
  };
950
- /**
951
- * Maps a Relay request status onto the provider-agnostic consolidated status.
952
- * `success` reports `DONE`/`COMPLETED` because for this route the destination
953
- * fill IS our omnibridge entry call; `refund` reports `DONE`/`REFUNDED` because
954
- * the user was made whole on the origin chain. Relay never strands funds on
955
- * Ethereum, so the partial/stranded status LI.FI can return has no analogue.
956
- *
957
- * @param payload - a `/requests/v2?hash=` response body
958
- * @param options.destinationChainId - the omnibridge entry chain the route
959
- * targeted (Ethereum or Binance Smart Chain); defaults to Ethereum,
960
- * preserving the original single-entry behavior
961
- * @returns the normalized status, or null when no matching request is present
962
- */
963
570
  const parseRelayStatus = (payload, { destinationChainId = Number(config_js_1.Chains.ETH) } = {}) => {
964
571
  const data = asRecord(payload);
965
572
  if (!data) {
@@ -990,7 +597,6 @@ const parseRelayStatus = (payload, { destinationChainId = Number(config_js_1.Cha
990
597
  if (relayInFlightStatuses.some((inFlight) => inFlight === status)) {
991
598
  return { status: 'PENDING', substatus: status, receivingTxHash };
992
599
  }
993
- // an unrecognized status is treated as still indexing rather than terminal
994
600
  return { status: 'NOT_FOUND', substatus: status, receivingTxHash };
995
601
  };
996
602
  exports.parseRelayStatus = parseRelayStatus;