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