@gibs/bridge-sdk 1.10.1 → 1.13.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 (122) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +234 -432
  3. package/dist/abis.d.ts +1 -0
  4. package/dist/abis.js +3 -0
  5. package/dist/bridge-limits.d.ts +103 -0
  6. package/dist/bridge-limits.js +84 -0
  7. package/dist/{src/chain-info.d.ts → chain-info.d.ts} +66 -27
  8. package/dist/{src/chain-info.js → chain-info.js} +106 -46
  9. package/dist/chain-names.d.ts +160 -0
  10. package/dist/chain-names.js +200 -0
  11. package/dist/chains.d.ts +65 -0
  12. package/dist/chains.js +284 -0
  13. package/dist/config.d.ts +216 -0
  14. package/dist/{src/config.js → config.js} +151 -44
  15. package/dist/consolidated-quote.d.ts +554 -0
  16. package/dist/consolidated-quote.js +773 -0
  17. package/dist/destination-calldata.d.ts +118 -0
  18. package/dist/destination-calldata.js +152 -0
  19. package/dist/ecosystems.d.ts +217 -0
  20. package/dist/ecosystems.js +288 -0
  21. package/dist/hyperliquid-execution.d.ts +152 -0
  22. package/dist/hyperliquid-execution.js +168 -0
  23. package/dist/image-links.d.ts +117 -0
  24. package/dist/image-links.js +142 -0
  25. package/dist/index.d.ts +20 -0
  26. package/dist/index.js +20 -0
  27. package/dist/lifi-execution-guard.d.ts +199 -0
  28. package/dist/lifi-execution-guard.js +400 -0
  29. package/dist/near-intents-conformance.d.ts +85 -0
  30. package/dist/near-intents-conformance.js +329 -0
  31. package/dist/near-intents-route.d.ts +47 -0
  32. package/dist/near-intents-route.js +265 -0
  33. package/dist/near-intents.d.ts +524 -0
  34. package/dist/near-intents.js +1055 -0
  35. package/dist/origin-deposit.d.ts +326 -0
  36. package/dist/origin-deposit.js +68 -0
  37. package/dist/pre-quote.d.ts +198 -0
  38. package/dist/pre-quote.js +175 -0
  39. package/dist/prices.d.ts +107 -0
  40. package/dist/prices.js +162 -0
  41. package/dist/providers.d.ts +221 -0
  42. package/dist/providers.js +157 -0
  43. package/dist/quote-fees.d.ts +102 -0
  44. package/dist/quote-fees.js +195 -0
  45. package/dist/referral.d.ts +77 -0
  46. package/dist/referral.js +72 -0
  47. package/dist/relay-currencies.d.ts +47 -0
  48. package/dist/relay-currencies.js +89 -0
  49. package/dist/relay-quote.d.ts +301 -0
  50. package/dist/relay-quote.js +983 -0
  51. package/dist/route-steps.d.ts +138 -0
  52. package/dist/route-steps.js +305 -0
  53. package/dist/routing/amounts.d.ts +80 -0
  54. package/dist/routing/amounts.js +120 -0
  55. package/dist/routing/candidate-route.d.ts +43 -0
  56. package/dist/routing/candidate-route.js +45 -0
  57. package/dist/routing/candidate.d.ts +237 -0
  58. package/dist/routing/candidate.js +96 -0
  59. package/dist/routing/carriers/ask-answer.d.ts +58 -0
  60. package/dist/routing/carriers/omnibridge.d.ts +137 -0
  61. package/dist/routing/carriers/omnibridge.js +419 -0
  62. package/dist/routing/carriers/pulsex.d.ts +111 -0
  63. package/dist/routing/carriers/pulsex.js +404 -0
  64. package/dist/routing/carriers/wrap.d.ts +25 -0
  65. package/dist/routing/carriers/wrap.js +115 -0
  66. package/dist/routing/composed-route-quality.d.ts +103 -0
  67. package/dist/routing/composed-route-quality.js +108 -0
  68. package/dist/routing/entry-chain-anchor.d.ts +88 -0
  69. package/dist/routing/entry-chain-anchor.js +55 -0
  70. package/dist/routing/format.d.ts +31 -0
  71. package/dist/routing/format.js +58 -0
  72. package/dist/routing/index.d.ts +34 -0
  73. package/dist/routing/index.js +42 -0
  74. package/dist/routing/producers.d.ts +770 -0
  75. package/dist/routing/producers.js +1564 -0
  76. package/dist/routing/providers.d.ts +26 -0
  77. package/dist/routing/providers.js +38 -0
  78. package/dist/routing/route-data.d.ts +355 -0
  79. package/dist/routing/route-data.js +1 -0
  80. package/dist/routing/search/compose.d.ts +168 -0
  81. package/dist/routing/search/compose.js +98 -0
  82. package/dist/routing/search/graph.d.ts +639 -0
  83. package/dist/routing/search/graph.js +445 -0
  84. package/dist/routing/search/plan-route-data.d.ts +244 -0
  85. package/dist/routing/search/plan-route-data.js +767 -0
  86. package/dist/routing/search/score.d.ts +324 -0
  87. package/dist/routing/search/score.js +400 -0
  88. package/dist/routing/usd-value.d.ts +17 -0
  89. package/dist/routing/usd-value.js +25 -0
  90. package/dist/settings.d.ts +692 -0
  91. package/dist/{src/settings.js → settings.js} +338 -71
  92. package/dist/ton-execution.d.ts +117 -0
  93. package/dist/ton-execution.js +247 -0
  94. package/dist/tron-execution.d.ts +146 -0
  95. package/dist/tron-execution.js +239 -0
  96. package/dist/{src/types.d.ts → types.d.ts} +8 -1
  97. package/dist/types.js +1 -0
  98. package/package.json +210 -23
  99. package/dist/src/abis.d.ts +0 -384
  100. package/dist/src/abis.js +0 -68
  101. package/dist/src/chains.d.ts +0 -6
  102. package/dist/src/chains.js +0 -86
  103. package/dist/src/config.d.ts +0 -136
  104. package/dist/src/image-links.d.ts +0 -41
  105. package/dist/src/image-links.js +0 -45
  106. package/dist/src/index.d.ts +0 -8
  107. package/dist/src/index.js +0 -8
  108. package/dist/src/settings.d.ts +0 -357
  109. package/dist/tsconfig.tsbuildinfo +0 -1
  110. package/src/abis.ts +0 -70
  111. package/src/chain-info.ts +0 -464
  112. package/src/chains.ts +0 -88
  113. package/src/config.ts +0 -480
  114. package/src/fee-type.ts +0 -14
  115. package/src/image-links.ts +0 -61
  116. package/src/index.ts +0 -8
  117. package/src/settings.ts +0 -898
  118. package/src/types.ts +0 -48
  119. package/tsconfig.json +0 -16
  120. /package/dist/{src/fee-type.d.ts → fee-type.d.ts} +0 -0
  121. /package/dist/{src/fee-type.js → fee-type.js} +0 -0
  122. /package/dist/{src/types.js → routing/carriers/ask-answer.js} +0 -0
@@ -0,0 +1,26 @@
1
+ import type { Hex } from 'viem';
2
+ import { type Provider } from '../config.js';
3
+ /**
4
+ * Builds the PulseX swap path for a conversion leg, from the bridged anchor to the
5
+ * wanted token. Routes through WPLS (`[anchor, WPLS, wanted]`) by default because
6
+ * most PulseChain tokens have a deep WPLS pool but rarely a direct pool with the USD
7
+ * anchor; it collapses to a direct `[anchor, wanted]` hop only when one side already
8
+ * IS WPLS (no point hopping through WPLS to reach WPLS). The router prices the path
9
+ * with `getAmountsOut`, so a path with no liquidity simply yields no quote.
10
+ *
11
+ * @param anchorAddress - the bridged anchor token (the swap input)
12
+ * @param wantedAddress - the token the user wants (the swap output)
13
+ * @param wplsAddress - the wrapped-native intermediary (WPLS)
14
+ * @returns the ordered swap path for `getAmountsOut`
15
+ */
16
+ export declare const pulseXConversionSwapPath: (anchorAddress: Hex, wantedAddress: Hex, wplsAddress: Hex) => readonly Hex[];
17
+ /**
18
+ * The bridge provider that crosses each omnibridge entry point to PulseChain.
19
+ *
20
+ * Typed `Provider | null` rather than `string | null` — this is the root
21
+ * source `RouteCandidate.omnibridgeProvider` and `RouteData.headlineProviderKey`
22
+ * both derive from, so a widened return type here forced every caller downstream
23
+ * to re-widen too, which is what let a wrong-kind key reach `providerDisplayName`
24
+ * unnoticed. See `routing/candidate.ts` and `routing/route-data.ts`.
25
+ */
26
+ export declare const omnibridgeProviderForEntryChain: (entryChainId: number) => Provider | null;
@@ -0,0 +1,38 @@
1
+ import { Chains, Providers, toChain } from '../config.js';
2
+ import { sameAddress } from '../ecosystems.js';
3
+ /**
4
+ * Builds the PulseX swap path for a conversion leg, from the bridged anchor to the
5
+ * wanted token. Routes through WPLS (`[anchor, WPLS, wanted]`) by default because
6
+ * most PulseChain tokens have a deep WPLS pool but rarely a direct pool with the USD
7
+ * anchor; it collapses to a direct `[anchor, wanted]` hop only when one side already
8
+ * IS WPLS (no point hopping through WPLS to reach WPLS). The router prices the path
9
+ * with `getAmountsOut`, so a path with no liquidity simply yields no quote.
10
+ *
11
+ * @param anchorAddress - the bridged anchor token (the swap input)
12
+ * @param wantedAddress - the token the user wants (the swap output)
13
+ * @param wplsAddress - the wrapped-native intermediary (WPLS)
14
+ * @returns the ordered swap path for `getAmountsOut`
15
+ */
16
+ export const pulseXConversionSwapPath = (anchorAddress, wantedAddress, wplsAddress) => {
17
+ const isWpls = (address) => sameAddress(address, wplsAddress, 'evm');
18
+ if (isWpls(anchorAddress) || isWpls(wantedAddress))
19
+ return [anchorAddress, wantedAddress];
20
+ return [anchorAddress, wplsAddress, wantedAddress];
21
+ };
22
+ /**
23
+ * The bridge provider that crosses each omnibridge entry point to PulseChain.
24
+ *
25
+ * Typed `Provider | null` rather than `string | null` — this is the root
26
+ * source `RouteCandidate.omnibridgeProvider` and `RouteData.headlineProviderKey`
27
+ * both derive from, so a widened return type here forced every caller downstream
28
+ * to re-widen too, which is what let a wrong-kind key reach `providerDisplayName`
29
+ * unnoticed. See `routing/candidate.ts` and `routing/route-data.ts`.
30
+ */
31
+ export const omnibridgeProviderForEntryChain = (entryChainId) => {
32
+ const entryChain = toChain(entryChainId);
33
+ if (entryChain === Chains.ETH)
34
+ return Providers.PULSECHAIN;
35
+ if (entryChain === Chains.BNB)
36
+ return Providers.TOKENSEX;
37
+ return null;
38
+ };
@@ -0,0 +1,355 @@
1
+ import type { Hex } from 'viem';
2
+ import type { QuoteFee } from '../quote-fees.js';
3
+ import type { ProviderKey } from '../providers.js';
4
+ /**
5
+ * The executing engine family a route runs through.
6
+ *
7
+ * `'swap'` is a same-chain PulseX swap: one signature, no crossing, no
8
+ * `entryChainId`, headlined by the PulseX provider rather than an omnibridge
9
+ * or aggregator one. It exists as its own kind rather than being folded into
10
+ * `'direct'` because a swap and a crossing are refused by two DIFFERENT
11
+ * guards (`swapRefusal` versus `crossingRefusal` in `@gibs/bridge-sdk/settings`)
12
+ * — collapsing the kinds would collapse the distinction the guards exist to
13
+ * keep honest.
14
+ */
15
+ export type RouteKind = 'direct' | 'aggregated' | 'conversion' | 'swap';
16
+ /**
17
+ * What grounds a figure that is NOT a live, provider-confirmed quote.
18
+ *
19
+ * DECLARED HERE, NOT IN `routing/search/graph.ts`, even though the general
20
+ * route search is what produces every estimate today. `RouteData` (this
21
+ * module) is the lower layer that `graph.ts` already depends on for
22
+ * `RouteKind` and the rest of the raw route shape — so the union belongs
23
+ * where the module that needs it already reaches, rather than forcing this
24
+ * one to import upward from the module that depends on it. `graph.ts` imports
25
+ * this type and re-exports it rather than declaring its own; there is exactly
26
+ * one definition.
27
+ *
28
+ * - `'probe-rate'` — a tiny reference trade's realized rate, scaled up.
29
+ * - `'priced-conversion'` — a currency conversion applied to a priced figure.
30
+ * - `'provider-model'` — an aggregator carrier's own provider-model estimate
31
+ * (`@gibs/quotes`'s `Carrier.estimate`): a price ratio times (one minus its
32
+ * typical fee) minus a fixed cost, calibrated against observed history.
33
+ * RANKABLE, same as `'probe-rate'` and `'priced-conversion'` — see
34
+ * {@link RANKABLE_ESTIMATE_BASES} in `routing/search/graph.ts` — but NEVER
35
+ * CONFIRMED (see {@link isConfirmedBasis} there): it never asked a real
36
+ * provider for this exact edge, only modeled one, so a search may prune and
37
+ * rank on it but may never report it as the final winner without a live
38
+ * quote first.
39
+ * - `'unpriced'` — a bare decimal rescale with no value behind it at all. This
40
+ * basis never reaches {@link RouteLandingData.estimateBasis} or
41
+ * {@link RouteOutputData.estimateBasis} — a figure grounded on nothing is
42
+ * left out of `amount` entirely rather than labelled; see that field's own
43
+ * note.
44
+ */
45
+ export type EstimateBasis = 'probe-rate' | 'priced-conversion' | 'provider-model' | 'unpriced';
46
+ /**
47
+ * A token reference in raw form — symbol, on-chain address, decimal chain id, and
48
+ * token decimals. Token and chain logos are OPTIONAL pre-resolved passthroughs: a
49
+ * producer that already has the correct image url for its route family (for
50
+ * example the direct path, whose token logos come from the multi-source asset
51
+ * resolver and chain metadata) sets them; a producer that does not leaves them
52
+ * undefined and the user-interface adapter resolves them from `chainId` + `address`
53
+ * via the image service. A field set to `null` means "deliberately no logo" and is
54
+ * preserved as-is (distinct from undefined, which triggers adapter resolution).
55
+ */
56
+ export type RouteTokenRef = {
57
+ /** Token ticker symbol, e.g. "USDC". */
58
+ symbol: string;
59
+ /**
60
+ * Token contract address on `chainId`.
61
+ *
62
+ * Typed as `string` rather than `Hex` because a route can pass through a
63
+ * non-Ethereum chain, where the token identifier is not `0x`-prefixed — a
64
+ * Bitcoin address, a Solana or Tron base58 address, a The Open Network
65
+ * user-friendly address. Treat it as an opaque identifier; anything deriving an
66
+ * image or a checksum from it must check for the `0x` prefix first.
67
+ */
68
+ address: string;
69
+ /** Decimal chain identifier this reference is presented on. */
70
+ chainId: number;
71
+ /**
72
+ * Token decimals, for amount formatting downstream. Optional because an
73
+ * INTERMEDIATE stop carries no amount to format — it renders as an icon only,
74
+ * and the provider quote that named it does not always report its decimals.
75
+ */
76
+ decimals?: number;
77
+ /** Pre-resolved token logo url; undefined → adapter resolves, null → no logo. */
78
+ logoUri?: string | null;
79
+ /** Pre-resolved chain-badge logo url; undefined → adapter resolves, null → none. */
80
+ chainLogoUri?: string | null;
81
+ };
82
+ /**
83
+ * One underlying hop within a signature section, in raw form. United States dollar
84
+ * cost is a NUMBER (`feeUsdValue`); the adapter formats it. Provider identity is a
85
+ * raw display `providerName` plus, when the hop resolves its logo from a provider
86
+ * key rather than a quote-supplied url, an optional `providerKey`. When the hop's
87
+ * logo comes straight from the aggregator quote, `providerLogoUri` carries it and
88
+ * the adapter prefers it over key resolution.
89
+ */
90
+ export type RouteHopData = {
91
+ /** Display name for the hop's provider, e.g. "LI.FI", "PulseChain Bridge". */
92
+ providerName: string;
93
+ /** Raw provider key for logo resolution when no `providerLogoUri` is supplied. */
94
+ providerKey?: string | null;
95
+ /** Quote-supplied provider logo url (aggregator legs); preferred when present. */
96
+ providerLogoUri?: string | null;
97
+ /** Human-readable hop title, e.g. "Bridge to PulseChain". */
98
+ title: string;
99
+ /** Token conversion subtitle derived from symbols, e.g. "ETH → USDC", or null. */
100
+ conversion?: string | null;
101
+ /**
102
+ * The token this hop CONSUMES, when the provider named it. Present alongside
103
+ * {@link conversion} rather than replacing it: the conversion line is prose for
104
+ * the hop detail, while these references are structural, so the section's token
105
+ * flow can be derived from the hops instead of guessing at the endpoints.
106
+ */
107
+ fromToken?: RouteTokenRef | null;
108
+ /**
109
+ * The token this hop PRODUCES — the stop the funds actually reach when the hop
110
+ * completes. Null/undefined when the provider named no output token.
111
+ */
112
+ toToken?: RouteTokenRef | null;
113
+ /** Per-hop fee in United States dollars as a NUMBER, or null when unknown. */
114
+ feeUsdValue?: number | null;
115
+ /** True when this hop runs automatically inside the section's single signature. */
116
+ automatic?: boolean;
117
+ };
118
+ /**
119
+ * What a signature section's funds LAND IN when that step completes — the stop
120
+ * the money actually comes to rest at, named in tokens rather than only drawn as
121
+ * an icon in the flow. Every step of a route ends somewhere, and until this
122
+ * existed only the route's FINAL delivery was stated in words: an intermediate
123
+ * step showed its cost but never how much of what it left the user holding.
124
+ *
125
+ * `amount` is null when the step is quoted only on return (a deferred leg), in
126
+ * which case the step still names the token it will land in.
127
+ */
128
+ export type RouteLandingData = {
129
+ /** Amount landed in base units, or null when the step is not yet quoted. */
130
+ amount: bigint | null;
131
+ /** Landed token decimals, for formatting. */
132
+ decimals: number;
133
+ /** Landed token symbol, e.g. "USDC". */
134
+ symbol: string;
135
+ /** Landed value in United States dollars as a NUMBER, or null when unpriced. */
136
+ usdValue?: number | null;
137
+ /**
138
+ * What grounds `amount` when it is NOT a live, provider-confirmed quote —
139
+ * absent (or null) for an ordinary quoted figure. See {@link EstimateBasis}
140
+ * for the members and why it is declared in this module.
141
+ *
142
+ * `'unpriced'` never reaches here: a figure grounded on no value at all is
143
+ * left out of `amount` entirely rather than labelled.
144
+ */
145
+ estimateBasis?: EstimateBasis | null;
146
+ };
147
+ /**
148
+ * Origin tokens a step does NOT consume, which therefore stay in the user's
149
+ * wallet.
150
+ *
151
+ * This exists because a route is quoted in two phases: the first solves FORWARD
152
+ * for the amount the user typed and reports the provider's guaranteed delivery
153
+ * floor, and the second solves BACKWARD to that floor. Backward-solving to a
154
+ * floor that sits below the forward expectation needs LESS origin token than was
155
+ * typed, so the difference — the slippage cushion, whatever the provider's
156
+ * tolerance happens to be — is simply never spent.
157
+ *
158
+ * It is deliberately NOT modelled as a cost and never enters `totalCostUsdValue`:
159
+ * the user keeps this money. Folding it into either the amount paid or the amount
160
+ * delivered would make one of those figures state something untrue, which is why
161
+ * it is carried as its own fact for the step's breakdown to name.
162
+ */
163
+ export type RouteUnspentData = {
164
+ /** Unspent amount in ORIGIN token base units. */
165
+ amount: bigint;
166
+ /** Origin token decimals, for formatting. */
167
+ decimals: number;
168
+ /** Origin token symbol, e.g. "ETH". */
169
+ symbol: string;
170
+ /** Unspent value in United States dollars as a NUMBER, or null when unpriced. */
171
+ usdValue: number | null;
172
+ };
173
+ /**
174
+ * One signature section of a route, in raw form. One section per manual wallet
175
+ * signature. Token flow is raw references; the section fee is a NUMBER. Provider
176
+ * identity is an optional raw `providerKey` the adapter resolves to name + logo.
177
+ */
178
+ export type RouteSectionData = {
179
+ /** Stable within-route key, e.g. "candidate-1-signature-1". */
180
+ id: string;
181
+ /** Short label naming what this signature does, e.g. "Bridge to PulseChain". */
182
+ label: string;
183
+ /** Raw provider key for the service executing this signature, or null. */
184
+ providerKey?: string | null;
185
+ /**
186
+ * The token-icon flow this signature walks, in raw references: the source, then
187
+ * every INTERMEDIATE stop the funds pass through, then the destination. A
188
+ * producer that knows its hops derives this from them (source, then each hop's
189
+ * output token) so the stops shown are the ones the route actually makes; a
190
+ * producer with a single hop emits just source → destination.
191
+ */
192
+ tokenFlow: RouteTokenRef[];
193
+ /**
194
+ * What this step leaves the user holding when it completes. Absent on a step
195
+ * whose producer cannot say — the step then shows its cost alone, as before.
196
+ */
197
+ landing?: RouteLandingData | null;
198
+ /**
199
+ * Origin tokens this step does not consume; they stay in the user's wallet.
200
+ * Absent on every step that spends exactly what it was given, which is all of
201
+ * them but the aggregator leg. See {@link RouteUnspentData} for why this is not
202
+ * a cost.
203
+ */
204
+ unspent?: RouteUnspentData | null;
205
+ /** Section total fee in United States dollars as a NUMBER, or null. */
206
+ feeUsdValue?: number | null;
207
+ /** Numeric inputs for an optional fee breakdown line (conversion mode). */
208
+ feePercent?: number | null;
209
+ /** Price-impact percentage for an optional fee breakdown line (conversion mode). */
210
+ priceImpactPercent?: number | null;
211
+ /** Estimated duration for this signature in minutes, or null to omit. */
212
+ etaMinutes?: number | null;
213
+ /** Estimated duration for this signature in seconds (sub-minute legs), or null. */
214
+ etaSeconds?: number | null;
215
+ /** The underlying hops this signature performs, first to last. */
216
+ hops: RouteHopData[];
217
+ /** True when signed only after a prior section's crossing settles (deferred). */
218
+ deferred?: boolean;
219
+ /** Explanation shown for a deferred section; the adapter supplies a default. */
220
+ deferredNote?: string;
221
+ /**
222
+ * Per-step transaction-transparency details for the advanced disclosure: the
223
+ * contract address(es) this signature touches and its encoded calldata.
224
+ * Absent until known. The direct route populates {@link bridgeFrom},
225
+ * {@link bridgeTo} and {@link destinationRouter} from the resolved omnibridge
226
+ * pathway; the same-chain PulseX swap route populates {@link destinationRouter}
227
+ * (the PulseX router, never a bridge mediator) and {@link calldata} from the
228
+ * SAME builder its own signing button calls
229
+ * (`pulseXSwapTransactionInputs` in `settings.ts`) — never a second encoding.
230
+ * Every other producer leaves it undefined until its execute path is wired.
231
+ */
232
+ advanced?: {
233
+ /** Source-side bridge mediator address for this step, or null. */
234
+ bridgeFrom?: Hex | null;
235
+ /** Destination-side bridge mediator address for this step, or null. */
236
+ bridgeTo?: Hex | null;
237
+ /**
238
+ * The destination-side router this step's delivery calls, or null when
239
+ * none. For the same-chain swap route this IS the PulseX router — the
240
+ * whole signature, not a delivery leg inside a crossing.
241
+ */
242
+ destinationRouter?: Hex | null;
243
+ /** Encoded calldata for this step's signature, or null when unknown. */
244
+ calldata?: Hex | null;
245
+ };
246
+ /**
247
+ * What the aggregator carrying this signature charges, itemized.
248
+ *
249
+ * The single `feeUsdValue` above is the difference between what the sender
250
+ * pays and what lands, which is a true total and says nothing about where it
251
+ * went. This is the breakdown behind it - and it is the only place a charge
252
+ * levied OUTSIDE `fromAmount` can appear at all, because such a charge never
253
+ * shows up in that difference.
254
+ */
255
+ fees?: QuoteFee[];
256
+ };
257
+ /** What a route delivers, in raw form. `amount` is null when not yet known. */
258
+ export type RouteOutputData = {
259
+ /** Delivered amount in base units, or null when unknown at quote time. */
260
+ amount: bigint | null;
261
+ /** Delivered token decimals, for formatting. */
262
+ decimals: number;
263
+ /** Delivered token symbol. */
264
+ symbol: string;
265
+ /** Delivered value in United States dollars as a NUMBER, or null when unpriced. */
266
+ usdValue?: number | null;
267
+ /**
268
+ * What grounds `amount` when it is NOT a live, provider-confirmed quote. See
269
+ * {@link RouteLandingData.estimateBasis} for the full rule — this is the
270
+ * same field, on the route's final delivery rather than one step's landing.
271
+ */
272
+ estimateBasis?: EstimateBasis | null;
273
+ };
274
+ /**
275
+ * One route in raw, data-only form — the framework-agnostic shape route builders
276
+ * produce. Carries bigint amounts, numeric United States dollar values, chain
277
+ * identifiers, and raw provider keys ONLY: no logo urls, no pre-formatted strings,
278
+ * and no human-readable chain names. The user-interface adapter `toRouteView`
279
+ * derives all of those to produce the display-ready route.
280
+ */
281
+ export type RouteData = {
282
+ /**
283
+ * Structural id. Unset by raw producers in this phase; the user-interface
284
+ * adapter assigns it from the assembled display option so shared links stay
285
+ * stable. Optional so producers need not compute it.
286
+ */
287
+ id?: string;
288
+ /** The executing engine family this route runs through. */
289
+ kind: RouteKind;
290
+ /** The omnibridge entry chain id for non-direct routes; null for direct. */
291
+ entryChainId: number | null;
292
+ /**
293
+ * Optional override for the chain shown as the route's "via" crossing, when it
294
+ * differs from {@link entryChainId}. The outbound route sets this to the chain it
295
+ * bridges TO while keeping `entryChainId` null (it has no aggregator entry chain).
296
+ * Unset on every other route, where the adapter falls back to `entryChainId`.
297
+ */
298
+ viaChainId?: number | null;
299
+ /**
300
+ * Raw provider key for the route's headline provider — the omnibridge crossing
301
+ * when the route has one, otherwise the aggregator that carries the whole
302
+ * journey.
303
+ *
304
+ * Typed `ProviderKey`, not `string`. Every producer always supplies a real
305
+ * one (an omnibridge `Provider` when there is a bridge leg, the aggregator's
306
+ * own `ProviderId` otherwise — see `producers.ts`'s `omnibridgeProviderKey ??
307
+ * candidate.quote.provider`), so there is no case where a route has none.
308
+ * `providerDisplayName` (`producers.ts`) still accepts a bare `string`
309
+ * itself, deliberately: display code reading a STORED or otherwise
310
+ * deserialized `RouteData` cannot rely on this type annotation to have
311
+ * survived the round trip, and must render something rather than throw on a
312
+ * value it no longer recognizes.
313
+ */
314
+ headlineProviderKey: ProviderKey;
315
+ /** The signature sections of the route, top to bottom. */
316
+ sections: RouteSectionData[];
317
+ /** What the route delivers — used for ranking and the output row. */
318
+ output: RouteOutputData;
319
+ /** Aggregate all-in cost in United States dollars as a NUMBER, or null. */
320
+ totalCostUsdValue?: number | null;
321
+ /** The user's net United States dollar outcome; the figure routes are ranked on. */
322
+ netValueUsd?: number | null;
323
+ /** Estimated end-to-end duration in minutes, or null when unknown. */
324
+ etaMinutes?: number | null;
325
+ /** True for the single best route; set by the ranker. */
326
+ isBest?: boolean;
327
+ /** Percentage difference versus the best route, negative; set by the ranker. */
328
+ deltaPercent?: number | null;
329
+ /**
330
+ * The general-search plan's stable path identity, when this route came
331
+ * from one — see the route-search design, section 1, and
332
+ * `RoutePlan.pathKey` in `routing/search/graph.ts`.
333
+ *
334
+ * ABSENT ON EVERY ROUTE PHASE 0 PRODUCES. `journeyPlan.ts`'s `pathKeyFor`
335
+ * derives a route's path key from `entryChainId` alone today; once a route
336
+ * carries this field, Phase 3's `journeyPlan.ts` work prefers it, because
337
+ * `entryChainId` alone cannot tell two plans that share an entry chain but
338
+ * cross through different intermediate assets or carriers apart.
339
+ */
340
+ pathKey?: string;
341
+ /**
342
+ * The decimal chain ids every intermediate hop of the route passes
343
+ * through, origin and destination excluded, in hop order.
344
+ *
345
+ * ABSENT ON EVERY ROUTE PHASE 0 PRODUCES, and on any route with no
346
+ * intermediate chain (a same-chain crossing, or a route with exactly one
347
+ * hop). {@link viaChainId} on `RouteOption` already names the SINGLE entry
348
+ * chain today's two-hop routes pass through; this field exists because a
349
+ * general-search plan can pass through MORE than one intermediate chain
350
+ * (for example Zcash → NEAR's Ethereum settlement → the omnibridge entry
351
+ * chain → PulseChain), and a single `viaChainId` cannot name more than one
352
+ * of them.
353
+ */
354
+ viaChainIds?: number[];
355
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,168 @@
1
+ import { type ComposedPathBasis, type EstimateBasis, type HopEdge } from './graph.js';
2
+ /**
3
+ * PHASE 1 — composes a path's per-hop figures into one end-to-end delivered
4
+ * amount, as design section 3 describes ("Composition"): "A later hop's
5
+ * output is estimated as its probe rate × the actual input. Rank on that
6
+ * estimate."
7
+ *
8
+ * WHY THIS IS ITS OWN MODULE, SEPARATE FROM `graph.ts` AND `score.ts`. A
9
+ * {@link HopEdge} names WHO carries a hop and WHICH two assets it connects;
10
+ * it says nothing about a delivered amount, because Phase 0 introduced no
11
+ * quoting. `PlannedHop.outcome` (`graph.ts`) says what a hop delivers ONCE
12
+ * something has already computed that figure. This module is the thing that
13
+ * computes it: given a starting amount and a sequence of hop figures — each
14
+ * either a REAL QUOTE (an exact amount) or a PROBE RATE (a ratio observed at
15
+ * some other, unrelated amount) — it walks the path and produces the single
16
+ * number a search ranks on.
17
+ *
18
+ * WHY EVERY RESULT IS AN ESTIMATE. Only the route's first signature has to be
19
+ * a binding quote (design section 3: "Only signature 1 must be binding").
20
+ * Composing a chain of figures — even a chain where every individual figure
21
+ * happens to be a real quote — is not itself something any provider quoted
22
+ * end to end, so the composed, path-level figure is never treated as a
23
+ * binding quote. It is always an ESTIMATE, which is what keeps a later leg
24
+ * honestly labelled until the reader returns to it and it is re-quoted for
25
+ * real (design section 3; section 4's `D` still uses this estimate for
26
+ * RANKING, which is a different thing from promising it).
27
+ *
28
+ * WHY BASE-UNIT BIGINTS, NEVER A FLOAT. A composed figure is money. Every
29
+ * amount here is kept as a bigint in the token's own base units all the way
30
+ * through; a rate is an exact bigint ratio ({@link ExchangeRate}), and
31
+ * applying it is one bigint multiply followed by one bigint divide — never a
32
+ * floating-point multiply, which would round a real amount away from what
33
+ * the chain will actually move.
34
+ */
35
+ /**
36
+ * An exact exchange rate, expressed as a bigint ratio: `numerator` output
37
+ * base units per `denominator` input base units, at the amount the rate was
38
+ * observed. Never a float — see this module's doc.
39
+ *
40
+ * This is what a Phase 1 "probe" produces: one carrier asked, once, "what
41
+ * would this hop return for a REFERENCE amount," and the ratio of that
42
+ * reference's output to its input is the rate. The reference amount itself
43
+ * plays no further part once the ratio is taken; only the ratio composes.
44
+ */
45
+ export type ExchangeRate = {
46
+ /** Output base units the rate implies, per {@link denominator} input base units. */
47
+ readonly numerator: bigint;
48
+ /** Input base units the rate is quoted against. Must be a positive number. */
49
+ readonly denominator: bigint;
50
+ };
51
+ /**
52
+ * What one hop knows about its own pricing, before composition applies it to
53
+ * the amount actually arriving at that hop.
54
+ *
55
+ * `'quote'` — the carrier returned an exact `outputAmount` for the exact
56
+ * amount that arrives at this hop in THIS path. Used as given; composition
57
+ * does no further math on it.
58
+ *
59
+ * `'probeRate'` — the carrier was asked at some other, reference amount, and
60
+ * only the resulting {@link ExchangeRate} survived. Composition multiplies
61
+ * this rate by the ACTUAL amount arriving at the hop, per design section 3.
62
+ * Carries the {@link EstimateBasis} that grounds it (`graph.ts`) — PHASE 3:
63
+ * a `'probeRate'` figure is not always a genuine probe; `waves.ts` also uses
64
+ * this kind to carry forward a hop's pre-network `'priced-conversion'` or
65
+ * `'unpriced'` estimate when no fresh answer landed, and the basis is what
66
+ * tells the two apart.
67
+ */
68
+ export type ComposableHopFigure = {
69
+ readonly kind: 'quote';
70
+ readonly outputAmount: bigint;
71
+ } | {
72
+ readonly kind: 'probeRate';
73
+ readonly rate: ExchangeRate;
74
+ readonly basis: EstimateBasis;
75
+ };
76
+ /** The {@link ComposedPathBasis} one hop's figure contributes: `'quoted'` for a bound quote, its own basis for a `'probeRate'`. */
77
+ export declare const composableHopBasis: (figure: ComposableHopFigure) => ComposedPathBasis;
78
+ /**
79
+ * One hop of a path being composed: the edge it travels (which carries the
80
+ * two {@link AssetNode}s composition checks for a decimals disagreement) and
81
+ * what is known about its pricing.
82
+ */
83
+ export type ComposableHop = {
84
+ /** The graph edge this hop travels — supplies both endpoints' decimals. */
85
+ readonly edge: HopEdge;
86
+ /** What this hop knows about its own pricing. */
87
+ readonly figure: ComposableHopFigure;
88
+ };
89
+ /**
90
+ * Why {@link composeRouteDelivery} refused to compose a path, rather than
91
+ * guess at an answer it cannot stand behind.
92
+ *
93
+ * `'empty-path'` — there were no hops to compose across.
94
+ *
95
+ * `'discontinuous-path'` — one hop's `to` asset is not the next hop's `from`
96
+ * asset, so there is no single amount that "arrives" at the second hop; the
97
+ * hops given do not describe one connected path.
98
+ *
99
+ * `'decimals-mismatch'` — two hops name the SAME asset (by
100
+ * {@link assetNodeKey}) with two DIFFERENT decimal counts. This is a data
101
+ * bug — one asset has one true decimals count — and composing through it
102
+ * would silently misplace a decimal point in real money.
103
+ *
104
+ * `'missing-rate'` — a hop's figure is a {@link ComposableHopFigure} of kind
105
+ * `'probeRate'` whose {@link ExchangeRate.denominator} is not a positive
106
+ * number, so the rate names no real ratio.
107
+ */
108
+ export type ComposeRefusalReason = 'empty-path' | 'discontinuous-path' | 'decimals-mismatch' | 'missing-rate';
109
+ /**
110
+ * The result of composing a path: either the estimated delivered amount, or
111
+ * why composition refused to produce one.
112
+ */
113
+ export type ComposedRouteDelivery = {
114
+ readonly kind: 'estimate';
115
+ /** The composed delivered amount, in the LAST hop's `to` asset's base units. */
116
+ readonly deliveredAmount: bigint;
117
+ /**
118
+ * What grounds {@link deliveredAmount} — the WORST (least-grounded)
119
+ * {@link ComposedPathBasis} among every hop composed (see
120
+ * {@link combineComposedPathBasis}). PHASE 3: a ranking must check this
121
+ * before comparing {@link deliveredAmount} against another path's — see
122
+ * `graph.ts`'s {@link isRankableBasis} for the rule.
123
+ */
124
+ readonly basis: ComposedPathBasis;
125
+ } | {
126
+ readonly kind: 'refused';
127
+ readonly reason: ComposeRefusalReason;
128
+ /** Which hop (0-based, into the `hops` argument) triggered the refusal. */
129
+ readonly hopIndex: number;
130
+ };
131
+ /**
132
+ * Composes a path's per-hop figures into one end-to-end estimated delivered
133
+ * amount, applying design section 3's rule: a later hop's output is its
134
+ * probe rate applied to the ACTUAL amount arriving at that hop — never the
135
+ * reference amount the probe itself was taken at.
136
+ *
137
+ * REFUSES RATHER THAN GUESSES in three cases, checked hop by hop so the
138
+ * refusal names the exact hop responsible: the path is empty
139
+ * ({@link ComposeRefusalReason} `'empty-path'`); a hop does not connect to the
140
+ * one before it (`'discontinuous-path'`); two hops disagree about a shared
141
+ * asset's decimals (`'decimals-mismatch'`); or a `'probeRate'` figure names
142
+ * no real ratio (`'missing-rate'`). See {@link ComposeRefusalReason} for why
143
+ * each of these is a refusal and not a best-effort answer.
144
+ *
145
+ * @param inputAmount - the base-unit amount entering the path's first hop
146
+ * @param hops - the path's hops, first to last
147
+ * @returns the composed estimate, or the refusal that stopped composition
148
+ */
149
+ export declare const composeRouteDelivery: (inputAmount: bigint, hops: readonly ComposableHop[]) => ComposedRouteDelivery;
150
+ /**
151
+ * One hop's output amount for the actual amount arriving at it: the quote's
152
+ * own `outputAmount` when the figure is a real quote, or the probe rate
153
+ * applied to `actualInput` when it is a `'probeRate'`. Returns null — never a
154
+ * guessed number — when a `'probeRate'` figure's rate names no positive
155
+ * denominator.
156
+ *
157
+ * EXPORTED SO `waves.ts` REUSES THIS MATH RATHER THAN RESTATING IT.
158
+ * `recomposePath` (`waves.ts`) needs each hop's OWN output amount, not just
159
+ * the path's final total {@link composeRouteDelivery} returns, to refresh
160
+ * every hop's individual `outcome` — this is the one place that division
161
+ * happens, so both call sites agree by construction instead of by two
162
+ * separately-maintained copies of `numerator * input / denominator`.
163
+ *
164
+ * @param hop - the hop to price
165
+ * @param actualInput - the actual base-unit amount arriving at this hop
166
+ * @returns the hop's output amount, or null when its rate is missing
167
+ */
168
+ export declare const hopOutputAmount: (hop: ComposableHop, actualInput: bigint) => bigint | null;