@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
@@ -1,68 +1,12 @@
1
- /**
2
- * The ecosystem whose signer a deposit needs, or null for a deposit that needs
3
- * no signer at all.
4
- *
5
- * THE ONE PLACE THE ECOSYSTEM TAG IS READ. A {@link DepositAddressDeposit} has
6
- * no `ecosystem`, so every guard below asks through this instead of reading the
7
- * field directly — which also means no ecosystem guard can ever answer true for
8
- * a deposit the reader pays by hand.
9
- *
10
- * TYPED `Ecosystem | null`, NOT `string | null`. A `string` return let a typo
11
- * such as `signerEcosystemOf(deposit) === 'hypvm'` compile silently — the
12
- * comparison is just false forever, so `isHyperliquidDeposit` would always
13
- * answer false and every Hyperliquid deposit would fall through to the
14
- * Ethereum branch. Typed on the union, the same typo fails to compile instead.
15
- */
16
1
  const signerEcosystemOf = (deposit) => 'ecosystem' in deposit ? deposit.ecosystem : null;
17
2
  export const isEvmDeposit = (deposit) => signerEcosystemOf(deposit) === 'evm';
18
3
  export const isSolanaDeposit = (deposit) => signerEcosystemOf(deposit) === 'svm';
19
- /**
20
- * Narrows a Solana deposit to the instruction form, which must be compiled
21
- * before it can be signed.
22
- */
23
4
  export const isSolanaInstructionsDeposit = (deposit) => deposit.form === 'instructions';
24
- /**
25
- * Narrows a Solana deposit to the pre-compiled form, which must be signed
26
- * as-is.
27
- */
28
5
  export const isSolanaSerializedDeposit = (deposit) => deposit.form === 'serialized';
29
6
  export const isBitcoinDeposit = (deposit) => signerEcosystemOf(deposit) === 'bvm';
30
7
  export const isTronDeposit = (deposit) => signerEcosystemOf(deposit) === 'tvm';
31
8
  export const isTonDeposit = (deposit) => signerEcosystemOf(deposit) === 'tonvm';
32
9
  export const isHyperliquidDeposit = (deposit) => signerEcosystemOf(deposit) === 'hypevm';
33
- /**
34
- * Narrows a deposit to the pay-by-hand shape: an address, an amount, and
35
- * nothing to sign.
36
- *
37
- * THE GUARD EVERY EXECUTION PATH MUST ASK FIRST. A surface that falls through
38
- * to a signer with one of these has no transaction to give it, and a surface
39
- * that asks the reader to connect a wallet is asking for one that does not
40
- * exist for this chain.
41
- *
42
- * @param deposit - any origin deposit
43
- * @returns whether the reader pays this one by hand
44
- */
45
10
  export const isDepositAddressDeposit = (deposit) => 'kind' in deposit && deposit.kind === 'deposit-address';
46
- /**
47
- * Narrows a deposit to the priced-but-not-reserved shape: a route on display,
48
- * with nothing to pay until a live quote replaces it.
49
- *
50
- * @param deposit - any origin deposit
51
- * @returns whether the route must be quoted live before anything is paid
52
- */
53
11
  export const isUnreservedDeposit = (deposit) => 'kind' in deposit && deposit.kind === 'unreserved';
54
- /**
55
- * Names a deposit's family for a message shown to someone: its ecosystem, or
56
- * its `kind` for a deposit that has none — a {@link DepositAddressDeposit}
57
- * reads as `"deposit-address"`, an {@link UnreservedDeposit} as `"unreserved"`.
58
- *
59
- * THE ONE COPY. The same `'ecosystem' in deposit ? deposit.ecosystem :
60
- * deposit.kind` expression used to be written out separately in
61
- * `consolidated-quote.ts` and in the interface's `consolidated-execute.ts`;
62
- * each copy was a chance for the two to describe the same deposit
63
- * differently. Import this instead of restating the expression.
64
- *
65
- * @param deposit - any origin deposit
66
- * @returns the ecosystem name, or the deposit's `kind` when it has none
67
- */
68
12
  export const depositFamilyOf = (deposit) => 'ecosystem' in deposit ? deposit.ecosystem : deposit.kind;
package/dist/pre-quote.js CHANGED
@@ -2,47 +2,12 @@ import { buildQuery } from '@gibs/common/url';
2
2
  import { isNonEthereumVirtualMachineOrigin, } from './consolidated-quote.js';
3
3
  import { resolveAttribution } from './referral.js';
4
4
  import { relayReferrerField, slippageToBasisPoints, } from './relay-quote.js';
5
- /**
6
- * Plain LI.FI swap quote endpoint (forward-solving), re-exported from
7
- * `consolidated-quote.js` rather than redeclared here — both modules must
8
- * agree on the same address, and a second literal would be free to drift from
9
- * it.
10
- */
11
5
  export { lifiQuoteUrl, lifiRequestHeaders } from './consolidated-quote.js';
12
- /**
13
- * Builds the Relay EXACT_INPUT swap pre-quote body for a fixed input. NO `txs`
14
- * are attached: Relay solves FORWARD and reports the delivered anchor amount.
15
- *
16
- * `recipient` and `refundTo` name TWO DIFFERENT chains and must never be
17
- * conflated. `refundTo` is always the user's OWN origin-chain address — Relay
18
- * refunds a failed (or, here, never-run) swap on the origin chain, and an
19
- * Ethereum fallback address could not receive one there. `recipient` names
20
- * where the swap lands on the ENTRY chain (`toChainId`), which is always
21
- * Ethereum Virtual Machine — for an Ethereum origin the user's own address
22
- * already satisfies that and is the default; for a non-Ethereum origin
23
- * (Solana base58, Bitcoin bech32, ...) it does NOT, and Relay's `/quote/v2`
24
- * validates the recipient's FORMAT against `toChainId` even though this
25
- * pre-quote never executes. Sending the origin account there — as an earlier
26
- * version of this builder did, reasoning that an unexecuted quote's recipient
27
- * is "informational" — gets Relay's `400 INVALID_ADDRESS` on every
28
- * non-Ethereum-origin pre-quote, which starves `fetchBestEntryAnchorPreQuote`
29
- * of its only capable provider and surfaces as "No route available" for the
30
- * whole non-Ethereum-origin flow. `request.recipient` (an explicit
31
- * Ethereum-format address the caller supplies) is therefore REQUIRED for a
32
- * non-Ethereum origin; without it this returns null.
33
- *
34
- * @param request - the provider-agnostic pre-quote request
35
- * @returns the request body, or null when the input amount is non-positive or
36
- * a non-Ethereum origin has no explicit Ethereum-format `recipient`
37
- */
38
6
  export const buildRelayPreQuoteRequest = (request) => {
39
7
  if (request.amount <= 0n) {
40
8
  return null;
41
9
  }
42
10
  const nonEthereumOrigin = isNonEthereumVirtualMachineOrigin(request);
43
- // A non-Ethereum origin's own address cannot stand in for an entry-chain
44
- // recipient; it must be supplied explicitly. An Ethereum origin's own
45
- // address already IS a valid entry-chain address, so it remains the default.
46
11
  const recipient = nonEthereumOrigin ? request.recipient : (request.recipient ?? request.fromAddress);
47
12
  if (recipient === undefined) {
48
13
  return null;
@@ -56,10 +21,6 @@ export const buildRelayPreQuoteRequest = (request) => {
56
21
  amount: request.amount.toString(),
57
22
  tradeType: 'EXACT_INPUT',
58
23
  recipient,
59
- // Relay always refunds on the ORIGIN chain, so the origin's own address
60
- // is the correct refund target regardless of ecosystem — unlike
61
- // `recipient` above, this one is deliberately NOT Ethereum-format for a
62
- // non-Ethereum origin.
63
24
  refundTo: request.fromAddress,
64
25
  ...relayReferrerField(request),
65
26
  ...(request.slippage === undefined
@@ -67,17 +28,6 @@ export const buildRelayPreQuoteRequest = (request) => {
67
28
  : { slippageTolerance: slippageToBasisPoints(request.slippage) }),
68
29
  };
69
30
  };
70
- /**
71
- * Builds the plain LI.FI swap pre-quote as a query string for `GET /v1/quote`.
72
- * LI.FI's plain `/quote` is forward-solving by construction (`fromAmount` in,
73
- * `estimate.toAmount` out), so no trade-type flag is needed.
74
- *
75
- * Returns null for a non-Ethereum origin (LI.FI cannot bridge across
76
- * virtual-machine ecosystems) and for a non-positive input amount.
77
- *
78
- * @param request - the provider-agnostic pre-quote request
79
- * @returns the URL query string (without a leading `?`), or null
80
- */
81
31
  export const buildLifiPreQuoteRequest = (request) => {
82
32
  if (request.amount <= 0n) {
83
33
  return null;
@@ -85,9 +35,6 @@ export const buildLifiPreQuoteRequest = (request) => {
85
35
  if (isNonEthereumVirtualMachineOrigin(request)) {
86
36
  return null;
87
37
  }
88
- // Left out or `null` OMITS the query parameter (LI.FI's own schema marks it
89
- // optional); a string is sent as-is. No package default: attribution is the
90
- // caller's to choose. See `PreQuoteRequest.lifiIntegrator`'s doc.
91
38
  const integrator = resolveAttribution(request.lifiIntegrator, undefined);
92
39
  return buildQuery({
93
40
  fromChain: request.fromChainId.toString(),
@@ -96,7 +43,6 @@ export const buildLifiPreQuoteRequest = (request) => {
96
43
  toToken: request.toTokenAddress,
97
44
  fromAmount: request.amount.toString(),
98
45
  fromAddress: request.fromAddress,
99
- // Each optional parameter is left out when it is undefined.
100
46
  integrator,
101
47
  slippage: request.slippage?.toString(),
102
48
  });
@@ -107,11 +53,6 @@ const asRecord = (value) => {
107
53
  }
108
54
  return value;
109
55
  };
110
- /**
111
- * Parses a decimal-string amount into a bigint.
112
- *
113
- * @returns the bigint value, or null when the input is not a parseable amount
114
- */
115
56
  const parseAmount = (value) => {
116
57
  if (typeof value !== 'string' || value === '') {
117
58
  return null;
@@ -123,13 +64,6 @@ const parseAmount = (value) => {
123
64
  return null;
124
65
  }
125
66
  };
126
- /**
127
- * Assembles the expected/minimum pair, defaulting the minimum to the expected
128
- * amount when the provider omits a guaranteed floor. Shared by both parsers so
129
- * the fallback rule lives in exactly one place.
130
- *
131
- * @returns the result, or null when the expected amount is absent
132
- */
133
67
  const toPreQuoteResult = (expected, minimum) => {
134
68
  const expectedAmount = parseAmount(expected);
135
69
  if (expectedAmount === null) {
@@ -141,13 +75,6 @@ const toPreQuoteResult = (expected, minimum) => {
141
75
  minimumAmount: minimumAmount ?? expectedAmount,
142
76
  };
143
77
  };
144
- /**
145
- * Parses a Relay EXACT_INPUT pre-quote response. The delivered anchor figures
146
- * live under `details.currencyOut`: `amount` (expected) and `minimumAmount`
147
- * (guaranteed slippage floor). Verified live against `api.relay.link/quote/v2`.
148
- *
149
- * @returns the delivered amounts, or null when the payload shape is unexpected
150
- */
151
78
  export const parseRelayPreQuote = (payload) => {
152
79
  const currencyOut = asRecord(asRecord(asRecord(payload)?.details)?.currencyOut);
153
80
  if (!currencyOut) {
@@ -155,13 +82,6 @@ export const parseRelayPreQuote = (payload) => {
155
82
  }
156
83
  return toPreQuoteResult(currencyOut.amount, currencyOut.minimumAmount);
157
84
  };
158
- /**
159
- * Parses a plain LI.FI `/quote` response. The delivered anchor figures live
160
- * under `estimate`: `toAmount` (expected) and `toAmountMin` (guaranteed minimum
161
- * after slippage) — the same estimate shape the route-step normalizer reads.
162
- *
163
- * @returns the delivered amounts, or null when the payload shape is unexpected
164
- */
165
85
  export const parseLifiPreQuote = (payload) => {
166
86
  const estimate = asRecord(asRecord(payload)?.estimate);
167
87
  if (!estimate) {
package/dist/prices.js CHANGED
@@ -1,50 +1,15 @@
1
1
  import { formatUnits } from 'viem';
2
2
  import { Chains, nativeAssetOut, toChain } from './config.js';
3
- /**
4
- * PulseChain mainnet numeric chain id (`Chains.PLS` = `0x171`). Tokens on this
5
- * chain (and its testnet sibling below) are priced on-chain via PulseX rather
6
- * than from an off-chain price feed.
7
- */
8
3
  export const PULSECHAIN_CHAIN_ID = Number(Chains.PLS);
9
- /**
10
- * PulseChain V4 testnet numeric chain id (`Chains.V4PLS` = `0x3af`). Shares the
11
- * PulseX on-chain pricing path with mainnet.
12
- */
13
4
  export const PULSECHAIN_TESTNET_CHAIN_ID = Number(Chains.V4PLS);
14
- /**
15
- * Bridged DAI on PulseChain (18 decimals) — the USD anchor stablecoin for
16
- * on-chain PulseX pricing. One token's `getAmountsOut` ending in this address
17
- * yields that token's USD price directly (DAI is treated as exactly $1).
18
- *
19
- * Kept as an exported constant so the anchor can be swapped without touching the
20
- * pricing math. Mirrors `DAI_ADDRESS` in `packages/tx-report/src/server/prices.ts`.
21
- */
22
5
  export const PULSECHAIN_USD_ANCHOR_ADDRESS = '0xefd766ccb38eaf1dfd701853bfce31359239f305';
23
- /** Decimals of the {@link PULSECHAIN_USD_ANCHOR_ADDRESS} stablecoin. */
24
6
  export const PULSECHAIN_USD_ANCHOR_DECIMALS = 18;
25
- /** Wrapped PLS on PulseChain — the routing intermediary for PulseX paths. */
26
7
  export const WPLS_ADDRESS = nativeAssetOut[Chains.PLS];
27
- /** The native (gas) token sentinel address used across the dapp. */
28
8
  const NATIVE_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000';
29
- /** Lowercases an address for case-insensitive map keys and comparisons. */
30
9
  export const lowercaseAddress = (address) => address.toLowerCase();
31
- /** True when two addresses are equal ignoring case (and 0x-checksum casing). */
32
10
  const sameAddress = (left, right) => lowercaseAddress(left) === lowercaseAddress(right);
33
- /**
34
- * Map key for a foreign (LI.FI-priced) token: `${chainId}-${lowercased address}`.
35
- * Matches the key the UI builds when assembling the LI.FI price map.
36
- */
37
11
  export const lifiPriceKey = (chainId, address) => `${chainId}-${lowercaseAddress(address)}`;
38
- /** True when a chain id is priced on-chain via PulseX (mainnet or V4 testnet). */
39
12
  export const isPulsechain = (chainId) => chainId === PULSECHAIN_CHAIN_ID || chainId === PULSECHAIN_TESTNET_CHAIN_ID;
40
- /**
41
- * The PulseChain-origin address a bridged token backs out to, when the token's
42
- * `extensions.bridgeInfo` records a PulseChain counterpart. Bridged tokens are
43
- * 1:1 with their origin, so the origin's PulseX price is the token's USD value.
44
- *
45
- * @param token - the token whose PulseChain-origin link to resolve
46
- * @returns the PulseChain origin address, or null when the token has no such link
47
- */
48
13
  export const pulsechainOriginAddress = (token) => {
49
14
  const link = token.extensions?.bridgeInfo?.[PULSECHAIN_CHAIN_ID];
50
15
  if (!link) {
@@ -52,22 +17,6 @@ export const pulsechainOriginAddress = (token) => {
52
17
  }
53
18
  return link.tokenAddress;
54
19
  };
55
- /**
56
- * The set of PulseX swap paths to price one whole unit of `token` into the USD
57
- * anchor stablecoin. Edge cases collapse to shorter paths:
58
- *
59
- * - `token` is the stablecoin itself -> no swap needed (priced as exactly 1).
60
- * - `token` is WPLS (or the native zero-address) -> `[WPLS, stable]` only.
61
- * - otherwise -> both `[token, WPLS, stable]` and `[token, stable]`.
62
- *
63
- * Returned addresses are always concrete (the native sentinel is rewritten to
64
- * WPLS) so they can be fed straight into `getAmountsOut`.
65
- *
66
- * @param options.token - the token (only its address is read) to build paths for
67
- * @param options.wpls - the wrapped-native intermediary (defaults to {@link WPLS_ADDRESS})
68
- * @param options.stable - the USD anchor (defaults to {@link PULSECHAIN_USD_ANCHOR_ADDRESS})
69
- * @returns `{ paths }` — the candidate paths; empty when the token is the stablecoin
70
- */
71
20
  export const pulsexPricePaths = ({ token, wpls = WPLS_ADDRESS, stable = PULSECHAIN_USD_ANCHOR_ADDRESS, }) => {
72
21
  const address = sameAddress(token.address, NATIVE_TOKEN_ADDRESS) ? wpls : token.address;
73
22
  if (sameAddress(address, stable)) {
@@ -83,11 +32,6 @@ export const pulsexPricePaths = ({ token, wpls = WPLS_ADDRESS, stable = PULSECHA
83
32
  ],
84
33
  };
85
34
  };
86
- /**
87
- * The final output amount of one `getAmountsOut` result, or null when the call
88
- * failed (Hex) or returned an empty array. The last element of a `bigint[]`
89
- * `getAmountsOut` is the output-token amount.
90
- */
91
35
  const finalOutput = (result) => {
92
36
  if (typeof result === 'string') {
93
37
  return null;
@@ -97,16 +41,6 @@ const finalOutput = (result) => {
97
41
  }
98
42
  return result[result.length - 1];
99
43
  };
100
- /**
101
- * Reduces every `getAmountsOut` result (across all paths and all routers for one
102
- * token) to a single USD price by taking the MAX final output, then scaling out
103
- * of the stablecoin's decimals. Failed/empty results are dropped; when none
104
- * succeed the price is null (no liquidity).
105
- *
106
- * @param options.results - the `getAmountsOut` outcomes for the token's paths/routers
107
- * @param options.stableDecimals - decimals of the anchor (defaults to {@link PULSECHAIN_USD_ANCHOR_DECIMALS})
108
- * @returns the USD price as a number, or null when no path produced a value
109
- */
110
44
  export const computeUsdPriceFromAmountsOut = ({ results, stableDecimals = PULSECHAIN_USD_ANCHOR_DECIMALS, }) => {
111
45
  const outputs = results.flatMap((result) => {
112
46
  const output = finalOutput(result);
@@ -121,22 +55,6 @@ export const computeUsdPriceFromAmountsOut = ({ results, stableDecimals = PULSEC
121
55
  }
122
56
  return Number(formatUnits(maxOutput, stableDecimals));
123
57
  };
124
- /**
125
- * Resolves a token's USD price using pre-fetched price maps, following the
126
- * co-designed precedence:
127
- *
128
- * 1. PulseChain (mainnet or V4 testnet): the token's own PulseX price.
129
- * 2. Bridged PulseChain-origin token: the origin's PulseX price (1:1 value).
130
- * 3. Genuinely foreign token: the LI.FI inline price.
131
- *
132
- * The stablecoin anchor itself resolves to exactly 1. All address lookups are
133
- * case-insensitive (maps are keyed by lowercased address).
134
- *
135
- * @param token - the token to price
136
- * @param options.pulsexPrices - lowercased PulseChain address -> USD price
137
- * @param options.lifiPrices - `${chainId}-${lowercased address}` -> USD price
138
- * @returns the USD price as a number, or null when no source can price it
139
- */
140
58
  export const resolveTokenPriceUsd = (token, { pulsexPrices, lifiPrices, }) => {
141
59
  const wrappedNative = sameChainWrappedNative(token);
142
60
  if (wrappedNative !== null) {
@@ -144,15 +62,6 @@ export const resolveTokenPriceUsd = (token, { pulsexPrices, lifiPrices, }) => {
144
62
  }
145
63
  return resolveOwnPriceUsd(token, { pulsexPrices, lifiPrices });
146
64
  };
147
- /**
148
- * The chain's canonical wrapped native address when `token` is the native
149
- * coin (zero address) or that wrapper itself, and null for every other token.
150
- * Only the SAME chain's pair is returned: a bridged copy of a wrapper on
151
- * another chain is a different token and keeps its own price.
152
- *
153
- * @param token - the token to test
154
- * @returns the wrapped native address on the token's own chain, or null
155
- */
156
65
  export const sameChainWrappedNative = (token) => {
157
66
  const wrapped = nativeAssetOut[toChain(token.chainId)];
158
67
  if (wrapped === undefined) {
@@ -161,22 +70,6 @@ export const sameChainWrappedNative = (token) => {
161
70
  const isNativeCoin = sameAddress(token.address, NATIVE_TOKEN_ADDRESS);
162
71
  return isNativeCoin || sameAddress(token.address, wrapped) ? wrapped : null;
163
72
  };
164
- /**
165
- * One price for a native coin and its canonical wrapper. The contract wraps
166
- * and unwraps 1:1, so two prices would show a value loss on a wrap step that
167
- * loses nothing.
168
- *
169
- * Off PulseChain the native coin's market feed (LI.FI) wins. The wrapper's
170
- * own price there is the PulseX price of its bridged copy (it carries a
171
- * PulseChain origin link), which is a derivative market with its own
172
- * premium or discount. The coin's feed prices the underlying asset. When the
173
- * feed has no native price, the wrapper's feed price, then its own resolved
174
- * price, stand in.
175
- *
176
- * On PulseChain both are priced by PulseX through the WPLS path, so the
177
- * wrapper's entry is used and the coin's entry stands in when the wrapper was
178
- * not in the priced set.
179
- */
180
73
  const resolveNativeFamilyPriceUsd = (token, wrappedNative, maps) => {
181
74
  const wrapped = { ...token, address: wrappedNative };
182
75
  if (isPulsechain(token.chainId)) {
@@ -187,7 +80,6 @@ const resolveNativeFamilyPriceUsd = (token, wrappedNative, maps) => {
187
80
  maps.lifiPrices.get(lifiPriceKey(token.chainId, wrappedNative)) ??
188
81
  resolveOwnPriceUsd(wrapped, maps));
189
82
  };
190
- /** The token's price by its own address, with no native-wrapper pairing. */
191
83
  const resolveOwnPriceUsd = (token, { pulsexPrices, lifiPrices, }) => {
192
84
  if (isPulsechain(token.chainId)) {
193
85
  if (sameAddress(token.address, PULSECHAIN_USD_ANCHOR_ADDRESS)) {
@@ -200,11 +92,6 @@ const resolveOwnPriceUsd = (token, { pulsexPrices, lifiPrices, }) => {
200
92
  if (sameAddress(origin, PULSECHAIN_USD_ANCHOR_ADDRESS)) {
201
93
  return 1;
202
94
  }
203
- // Prefer the bridged origin's on-chain PulseX price. Fall back to the token's
204
- // OWN home-chain LI.FI inline price when PulseX cannot price it — a bridged
205
- // major (e.g. wrapped ether / wrapped binance coin) whose PulseChain pool path
206
- // returns nothing would otherwise resolve to null despite a well-known market
207
- // price on its home chain.
208
95
  return (pulsexPrices.get(lowercaseAddress(origin)) ??
209
96
  lifiPrices.get(lifiPriceKey(token.chainId, token.address)) ??
210
97
  null);
package/dist/providers.js CHANGED
@@ -7,11 +7,9 @@ const lifiDescriptor = {
7
7
  id: 'lifi',
8
8
  label: 'LI.FI',
9
9
  supportedSourceEcosystems: ['evm'],
10
- // Its contract-calls endpoint exists to deliver and then call something.
11
10
  executesDestinationCalls: true,
12
11
  destinationCallOriginChainIds: [Number(Chains.ETH)],
13
12
  destinationCallCarriesNativeValue: false,
14
- // Its quote names the Diamond as `estimate.approvalAddress`.
15
13
  originTokenSpend: 'allowance',
16
14
  preQuote: {
17
15
  method: 'GET',
@@ -27,15 +25,10 @@ const lifiDescriptor = {
27
25
  const relayDescriptor = {
28
26
  id: 'relay',
29
27
  label: 'Relay',
30
- // Relay carries every origin family the registry models. Listed explicitly
31
- // rather than derived from the registry so that registering a future
32
- // ecosystem does not silently claim Relay support the integration lacks.
33
28
  supportedSourceEcosystems: ['evm', 'svm', 'bvm', 'tvm', 'tonvm', 'hypevm'],
34
- // Its solver performs the `txs` attached to a quote on arrival.
35
29
  executesDestinationCalls: true,
36
30
  destinationCallOriginChainIds: 'any',
37
31
  destinationCallCarriesNativeValue: true,
38
- // Its quote carries an approve step; the parser lifts its spender.
39
32
  originTokenSpend: 'allowance',
40
33
  preQuote: {
41
34
  method: 'POST',
@@ -51,21 +44,10 @@ const relayDescriptor = {
51
44
  const nearIntentsDescriptor = {
52
45
  id: 'near-intents',
53
46
  label: 'NEAR Intents',
54
- // ETHEREUM ORIGINS, AND THE CHAINS A READER PAYS BY HAND. The service
55
- // carries Solana, Bitcoin, Tron, The Open Network and more, but it returns a
56
- // deposit ADDRESS and no transaction. For a wallet-connected origin the
57
- // transfer that funds a route has to be composed on this side, and only the
58
- // Ethereum one is composed today (`nearIntentsOriginDeposit`); claiming a
59
- // family whose transfer nothing here can build would offer a route that
60
- // dead-ends at the signing step. A pay-by-hand chain needs nothing composed:
61
- // the address and the amount ARE the deposit (`DepositAddressDeposit`).
62
47
  supportedSourceEcosystems: ['evm', 'zcash'],
63
- // The measured answer, and the reason this provider's routes take two
64
- // signatures. See the head of `near-intents.ts`.
65
48
  executesDestinationCalls: false,
66
49
  destinationCallOriginChainIds: [],
67
50
  destinationCallCarriesNativeValue: false,
68
- // The reader sends the token to a deposit address.
69
51
  originTokenSpend: 'transfer',
70
52
  preQuote: {
71
53
  method: 'POST',
@@ -78,38 +60,13 @@ const nearIntentsDescriptor = {
78
60
  parse: parseNearIntentsQuote,
79
61
  },
80
62
  };
81
- /**
82
- * Every integrated provider. LI.FI is first: the interface preserves this order
83
- * in its active lists, and LI.FI-first is the existing tie-break that prefers
84
- * the verified provider on an equal-cost quote. NEAR Intents is last, so it
85
- * wins a tie against neither — appropriate for the one provider whose route
86
- * costs the reader a second signature.
87
- */
88
63
  export const providerRegistry = [
89
64
  lifiDescriptor,
90
65
  relayDescriptor,
91
66
  nearIntentsDescriptor,
92
67
  ];
93
68
  const byId = new Map(providerRegistry.map((descriptor) => [descriptor.id, descriptor]));
94
- /**
95
- * Looks up a provider descriptor for ANY carrier id, answering null for an id
96
- * the registry does not hold. The route-search engine carries hops for
97
- * carriers that are not providers at all (a local wrap, a pool swap, a
98
- * host's own plug-in), so a caller holding an open carrier id must ask this,
99
- * never cast the id to {@link ProviderId} and call {@link providerById}, which
100
- * throws for such an id.
101
- *
102
- * @param id - any carrier id
103
- * @returns the descriptor, or null when no provider is registered under `id`
104
- */
105
69
  export const findProviderById = (id) => byId.get(id) ?? null;
106
- /**
107
- * Looks up a provider descriptor. Total over the `ProviderId` union; throws only
108
- * if the registry is left incomplete.
109
- *
110
- * @param id - the provider key
111
- * @returns the descriptor whose `id` equals `id`
112
- */
113
70
  export const providerById = (id) => {
114
71
  const descriptor = byId.get(id);
115
72
  if (descriptor === undefined) {
@@ -117,47 +74,7 @@ export const providerById = (id) => {
117
74
  }
118
75
  return descriptor;
119
76
  };
120
- /**
121
- * The providers that can originate a route from `ecosystem`, in registry order.
122
- * This is the data that used to be the hand-written capability conditional.
123
- *
124
- * @param ecosystem - the source ecosystem
125
- * @returns the descriptors whose `supportedSourceEcosystems` include `ecosystem`
126
- */
127
77
  export const providersForOrigin = (ecosystem) => providerRegistry.filter((descriptor) => descriptor.supportedSourceEcosystems.includes(ecosystem));
128
- /**
129
- * The providers that may bid in the entry-anchor pre-quote for an origin.
130
- *
131
- * A STRICTER LIST THAN {@link providersForOrigin}, AND THE DIFFERENCE IS NOT
132
- * COSMETIC. The pre-quote exists for one purpose: to learn, for the reader's
133
- * fixed input, how much anchor an entry really delivers, so that figure can
134
- * become the exact-output target of the execution quote. The winner is whoever
135
- * delivers MOST.
136
- *
137
- * A provider that cannot execute the entry call can still win that comparison —
138
- * it has one less thing to pay for. Its number then becomes a target handed to
139
- * the providers that must actually fill it, and they cannot, so the whole entry
140
- * produces no route. The failure is silent and looks like an absent quote.
141
- *
142
- * So the pre-quote is restricted to providers that execute. This is not a
143
- * judgement about quality; it is that a pre-quote and an execution quote have
144
- * to be answerable by the same provider for the handoff between them to mean
145
- * anything.
146
- *
147
- * @param ecosystem - the source ecosystem
148
- * @returns the descriptors that may pre-quote this origin, in registry order
149
- */
150
78
  export const preQuoteProvidersForOrigin = (ecosystem) => providersForOrigin(ecosystem).filter((descriptor) => descriptor.executesDestinationCalls);
151
- // A request with no origin family is the existing-caller shape and is treated as
152
- // Ethereum, preserving the original single-ecosystem default.
153
79
  const ecosystemOf = (request) => request.originVmType ?? 'evm';
154
- /**
155
- * Whether a provider can quote a request's origin ecosystem, derived from the
156
- * registry. Equivalent to `providersForOrigin(...).some(...)`, kept as a named
157
- * predicate for the call sites that ask about one provider at a time.
158
- *
159
- * @param provider - the aggregator under consideration
160
- * @param request - the request whose origin is being checked
161
- * @returns true when the provider supports the request's origin ecosystem
162
- */
163
80
  export const providerSupportsOrigin = (provider, request) => providerById(provider).supportedSourceEcosystems.includes(ecosystemOf(request));
@@ -1,37 +1,5 @@
1
- /**
2
- * What a consolidated route actually charges, normalized across the aggregators.
3
- *
4
- * WHY THIS EXISTS. A quote used to carry `fromAmount` and nothing else about
5
- * cost, so the interface could show the reader only the omnibridge crossing fee
6
- * — a figure that is real, and on a twenty-five dollar transfer is a rounding
7
- * error beside what the aggregator takes. Measured on one live route on
8
- * 2026-09-01: Relay charged 1.466338 USD Coin, or 5.54%, and none of it
9
- * appeared anywhere on screen.
10
- *
11
- * THE FLAG THAT MATTERS IS `includedInFromAmount`. The two providers express
12
- * cost differently, and the difference is not cosmetic:
13
- *
14
- * Relay folds everything into `fromAmount`. You send 26.466338 to receive
15
- * 25.000000, and the 1.466338 difference IS the fee.
16
- *
17
- * LI.FI does not. On the same route it quoted `fromAmount` 25.317074 and a
18
- * SEPARATE LayerZero fee of 0.000561734871157119 ether — about 1.37 dollars —
19
- * marked `included: false`, which the sender pays on top in native currency.
20
- *
21
- * So comparing the two on `fromAmount` alone reads LI.FI as more than a dollar
22
- * cheaper when it is in fact slightly dearer. Anything that ranks or displays
23
- * cost has to add the charges that sit outside `fromAmount`, and that is what
24
- * this flag is for.
25
- */
26
1
  const asRecord = (value) => typeof value === 'object' && value !== null ? value : null;
27
2
  const asNumber = (value) => typeof value === 'number' && Number.isFinite(value) ? value : null;
28
- /**
29
- * Reads a provider's currency block into a token descriptor.
30
- *
31
- * Returns null rather than filling in defaults: a charge whose token is unknown
32
- * cannot be formatted, and inventing eighteen decimals for it would print a
33
- * number wrong by many orders of magnitude.
34
- */
35
3
  const feeToken = (value) => {
36
4
  const currency = asRecord(value);
37
5
  const decimals = asNumber(currency?.decimals);
@@ -41,15 +9,11 @@ const feeToken = (value) => {
41
9
  }
42
10
  return { symbol: currency.symbol, decimals, chainId };
43
11
  };
44
- /** Parses a provider's amount string, dropping a charge that is zero or unreadable. */
45
12
  const feeAmount = (value) => {
46
13
  if (typeof value !== 'string' && typeof value !== 'number') {
47
14
  return null;
48
15
  }
49
16
  try {
50
- // Relay reports "0.0" for an unused fee slot, which BigInt rejects; a
51
- // fractional string here is always zero in practice, and a charge we cannot
52
- // read exactly is one we must not display.
53
17
  const amount = BigInt(String(value).split('.')[0] ?? '');
54
18
  return amount > 0n ? amount : null;
55
19
  }
@@ -58,19 +22,6 @@ const feeAmount = (value) => {
58
22
  }
59
23
  };
60
24
  const usdOf = (value) => typeof value === 'string' || typeof value === 'number' ? String(value) : null;
61
- /**
62
- * The charges Relay reports, in the order a reader meets them.
63
- *
64
- * `fees.relayer` IS DELIBERATELY SKIPPED. It is the sum of `relayerGas` and
65
- * `relayerService`, so listing it beside them would count the same money twice
66
- * and make the breakdown disagree with the amount the sender pays.
67
- *
68
- * `fees.gas` is the sender's OWN origin-chain transaction cost. It sits outside
69
- * `fromAmount` because the wallet pays it directly, which is exactly the case
70
- * `includedInFromAmount` exists to mark.
71
- * @param payload - the raw body from Relay's quote endpoint
72
- * @returns the charges, in display order
73
- */
74
25
  export const relayQuoteFees = (payload) => {
75
26
  const fees = asRecord(asRecord(payload)?.fees);
76
27
  if (!fees) {
@@ -101,16 +52,6 @@ export const relayQuoteFees = (payload) => {
101
52
  ];
102
53
  });
103
54
  };
104
- /**
105
- * The charges LI.FI reports.
106
- *
107
- * `feeCosts` CARRIES ITS OWN `included` FLAG and it is the whole point of
108
- * reading this: a fee marked `included: false` is paid on top of `fromAmount`,
109
- * in that fee's own token, and on a live route it was worth more than a dollar.
110
- * `gasCosts` is the sender's own origin transaction and is never included.
111
- * @param payload - the raw body from LI.FI's quote endpoint
112
- * @returns the charges, in display order
113
- */
114
55
  export const lifiQuoteFees = (payload) => {
115
56
  const estimate = asRecord(asRecord(payload)?.estimate);
116
57
  if (!estimate) {
@@ -132,9 +73,6 @@ export const lifiQuoteFees = (payload) => {
132
73
  amount,
133
74
  token,
134
75
  amountUsd: usdOf(fee?.amountUSD),
135
- // Absent is treated as NOT included. A fee we wrongly call included
136
- // disappears from the total and understates the route; one we wrongly
137
- // call excluded overstates it. Overstating is the safe direction.
138
76
  includedInFromAmount: fee?.included === true,
139
77
  },
140
78
  ];
@@ -159,21 +97,6 @@ export const lifiQuoteFees = (payload) => {
159
97
  });
160
98
  return [...fromFeeCosts, ...fromGasCosts];
161
99
  };
162
- /**
163
- * What the route costs the sender all in, in United States dollars.
164
- *
165
- * `fromAmount` already contains every charge marked included, so only the ones
166
- * marked otherwise are added. This is the figure two providers must be compared
167
- * on: ranking them on `fromAmount` alone picked LI.FI over Relay by more than a
168
- * dollar on a route where LI.FI was in fact the dearer of the two, because its
169
- * LayerZero fee is charged outside the amount.
170
- *
171
- * Returns null when the input's own dollar value is unknown — a partial total
172
- * would rank routes against each other on different bases.
173
- * @param quote.fromAmountUsd - the provider's dollar value for the input amount
174
- * @param quote.fees - the route's charges
175
- * @returns the all-in dollar cost, or null when it cannot be totalled
176
- */
177
100
  export const totalQuoteCostUsd = ({ fromAmountUsd, fees, }) => {
178
101
  if (fromAmountUsd === null) {
179
102
  return null;
@@ -187,9 +110,6 @@ export const totalQuoteCostUsd = ({ fromAmountUsd, fees, }) => {
187
110
  return total;
188
111
  }
189
112
  const value = Number(fee.amountUsd);
190
- // A charge outside the amount whose dollar value we cannot read is left out
191
- // rather than guessed. It is named in the breakdown either way, so the
192
- // reader still sees it even when the total cannot count it.
193
113
  return Number.isFinite(value) ? total + value : total;
194
114
  }, base);
195
115
  };