@gibs/bridge-sdk 1.12.0 → 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.
- package/LICENSE +15 -0
- package/README.md +234 -432
- package/dist/abis.d.ts +1 -0
- package/dist/bridge-limits.d.ts +103 -0
- package/dist/bridge-limits.js +84 -0
- package/dist/chain-info.d.ts +169 -0
- package/dist/chain-info.js +410 -0
- package/dist/chain-names.d.ts +160 -0
- package/dist/chain-names.js +200 -0
- package/dist/chains.d.ts +65 -0
- package/dist/chains.js +284 -0
- package/dist/config.d.ts +216 -0
- package/dist/config.js +493 -0
- package/dist/consolidated-quote.d.ts +554 -0
- package/dist/consolidated-quote.js +773 -0
- package/dist/destination-calldata.d.ts +118 -0
- package/dist/destination-calldata.js +152 -0
- package/dist/ecosystems.d.ts +217 -0
- package/dist/ecosystems.js +288 -0
- package/dist/fee-type.d.ts +10 -0
- package/dist/fee-type.js +9 -0
- package/dist/hyperliquid-execution.d.ts +152 -0
- package/dist/hyperliquid-execution.js +168 -0
- package/dist/image-links.d.ts +117 -0
- package/dist/image-links.js +142 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/lifi-execution-guard.d.ts +199 -0
- package/dist/lifi-execution-guard.js +400 -0
- package/dist/near-intents-conformance.d.ts +85 -0
- package/dist/near-intents-conformance.js +329 -0
- package/dist/near-intents-route.d.ts +47 -0
- package/dist/near-intents-route.js +265 -0
- package/dist/near-intents.d.ts +524 -0
- package/dist/near-intents.js +1055 -0
- package/dist/origin-deposit.d.ts +326 -0
- package/dist/origin-deposit.js +68 -0
- package/dist/pre-quote.d.ts +198 -0
- package/dist/pre-quote.js +175 -0
- package/dist/prices.d.ts +107 -0
- package/dist/prices.js +162 -0
- package/dist/providers.d.ts +221 -0
- package/dist/providers.js +157 -0
- package/dist/quote-fees.d.ts +102 -0
- package/dist/quote-fees.js +195 -0
- package/dist/referral.d.ts +77 -0
- package/dist/referral.js +72 -0
- package/dist/relay-currencies.d.ts +47 -0
- package/dist/relay-currencies.js +89 -0
- package/dist/relay-quote.d.ts +301 -0
- package/dist/relay-quote.js +983 -0
- package/dist/route-steps.d.ts +138 -0
- package/dist/route-steps.js +305 -0
- package/dist/routing/amounts.d.ts +80 -0
- package/dist/routing/amounts.js +120 -0
- package/dist/routing/candidate-route.d.ts +43 -0
- package/dist/routing/candidate-route.js +45 -0
- package/dist/routing/candidate.d.ts +237 -0
- package/dist/routing/candidate.js +96 -0
- package/dist/routing/carriers/ask-answer.d.ts +58 -0
- package/dist/routing/carriers/ask-answer.js +1 -0
- package/dist/routing/carriers/omnibridge.d.ts +137 -0
- package/dist/routing/carriers/omnibridge.js +419 -0
- package/dist/routing/carriers/pulsex.d.ts +111 -0
- package/dist/routing/carriers/pulsex.js +404 -0
- package/dist/routing/carriers/wrap.d.ts +25 -0
- package/dist/routing/carriers/wrap.js +115 -0
- package/dist/routing/composed-route-quality.d.ts +103 -0
- package/dist/routing/composed-route-quality.js +108 -0
- package/dist/routing/entry-chain-anchor.d.ts +88 -0
- package/dist/routing/entry-chain-anchor.js +55 -0
- package/dist/routing/format.d.ts +31 -0
- package/dist/routing/format.js +58 -0
- package/dist/routing/index.d.ts +34 -0
- package/dist/routing/index.js +42 -0
- package/dist/routing/producers.d.ts +770 -0
- package/dist/routing/producers.js +1564 -0
- package/dist/routing/providers.d.ts +26 -0
- package/dist/routing/providers.js +38 -0
- package/dist/routing/route-data.d.ts +355 -0
- package/dist/routing/route-data.js +1 -0
- package/dist/routing/search/compose.d.ts +168 -0
- package/dist/routing/search/compose.js +98 -0
- package/dist/routing/search/graph.d.ts +639 -0
- package/dist/routing/search/graph.js +445 -0
- package/dist/routing/search/plan-route-data.d.ts +244 -0
- package/dist/routing/search/plan-route-data.js +767 -0
- package/dist/routing/search/score.d.ts +324 -0
- package/dist/routing/search/score.js +400 -0
- package/dist/routing/usd-value.d.ts +17 -0
- package/dist/routing/usd-value.js +25 -0
- package/dist/settings.d.ts +692 -0
- package/dist/settings.js +909 -0
- package/dist/ton-execution.d.ts +117 -0
- package/dist/ton-execution.js +247 -0
- package/dist/tron-execution.d.ts +146 -0
- package/dist/tron-execution.js +239 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.js +1 -0
- package/package.json +203 -23
- package/src/chain-info.test.ts +0 -968
- package/src/chain-info.ts +0 -498
- package/src/chains.test.ts +0 -123
- package/src/chains.ts +0 -88
- package/src/config.test.ts +0 -679
- package/src/config.ts +0 -500
- package/src/fee-type.test.ts +0 -45
- package/src/fee-type.ts +0 -14
- package/src/image-links.test.ts +0 -160
- package/src/image-links.ts +0 -65
- package/src/index.ts +0 -8
- package/src/settings.test.ts +0 -2754
- package/src/settings.ts +0 -875
- package/src/types.ts +0 -48
- package/tsconfig.json +0 -17
- package/vitest.config.ts +0 -13
- /package/{src/abis.ts → dist/abis.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;
|