@gibs/bridge-sdk 1.17.0 → 1.19.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/README.md +85 -1
- package/dist/cjs/config.d.ts +18 -3
- package/dist/cjs/config.js +49 -17
- package/dist/cjs/consolidated-quote.js +3 -0
- package/dist/cjs/execution.d.ts +17 -4
- package/dist/cjs/execution.js +40 -13
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/near-intents-route.d.ts +13 -0
- package/dist/cjs/near-intents-route.js +19 -3
- package/dist/cjs/prices.d.ts +10 -0
- package/dist/cjs/prices.js +54 -2
- package/dist/cjs/routing/candidate-route.d.ts +46 -1
- package/dist/cjs/routing/candidate-route.js +47 -2
- package/dist/cjs/routing/carrier-provider-key.d.ts +31 -0
- package/dist/cjs/routing/carrier-provider-key.js +42 -0
- package/dist/cjs/routing/carriers/pulsex.d.ts +50 -25
- package/dist/cjs/routing/carriers/pulsex.js +135 -85
- package/dist/cjs/routing/index.d.ts +7 -3
- package/dist/cjs/routing/index.js +11 -2
- package/dist/cjs/routing/route-data.d.ts +47 -5
- package/dist/cjs/routing/search/plan-route-data.d.ts +17 -1
- package/dist/cjs/routing/search/plan-route-data.js +39 -13
- package/dist/cjs/routing/swap-transactions.d.ts +7 -3
- package/dist/cjs/routing/swap-transactions.js +6 -4
- package/dist/cjs/swap-venues.d.ts +43 -0
- package/dist/cjs/swap-venues.js +29 -0
- package/dist/cjs/types.d.ts +8 -0
- package/dist/config.d.ts +18 -3
- package/dist/config.js +48 -16
- package/dist/consolidated-quote.js +3 -0
- package/dist/execution.d.ts +17 -4
- package/dist/execution.js +41 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/near-intents-route.d.ts +13 -0
- package/dist/near-intents-route.js +17 -2
- package/dist/prices.d.ts +10 -0
- package/dist/prices.js +52 -1
- package/dist/routing/candidate-route.d.ts +46 -1
- package/dist/routing/candidate-route.js +45 -1
- package/dist/routing/carrier-provider-key.d.ts +31 -0
- package/dist/routing/carrier-provider-key.js +37 -0
- package/dist/routing/carriers/pulsex.d.ts +50 -25
- package/dist/routing/carriers/pulsex.js +133 -84
- package/dist/routing/index.d.ts +7 -3
- package/dist/routing/index.js +4 -2
- package/dist/routing/route-data.d.ts +47 -5
- package/dist/routing/search/plan-route-data.d.ts +17 -1
- package/dist/routing/search/plan-route-data.js +40 -14
- package/dist/routing/swap-transactions.d.ts +7 -3
- package/dist/routing/swap-transactions.js +7 -5
- package/dist/swap-venues.d.ts +43 -0
- package/dist/swap-venues.js +24 -0
- package/dist/types.d.ts +8 -0
- package/package.json +3 -3
|
@@ -2,8 +2,9 @@ import { multicallRead } from '@gibs/common/multicall';
|
|
|
2
2
|
import { getAddress, isAddress, parseAbi, zeroAddress } from 'viem';
|
|
3
3
|
import * as abis from '../../abis.js';
|
|
4
4
|
import { chainsMetadata } from '../../chains.js';
|
|
5
|
-
import {
|
|
5
|
+
import { defaultSwapVenues, nativeAssetOut, toChain } from '../../config.js';
|
|
6
6
|
import { sameAddress } from '../../ecosystems.js';
|
|
7
|
+
import { findSwapVenue, resolveSwapVenues } from '../../swap-venues.js';
|
|
7
8
|
import { pulseXConversionSwapPath } from '../providers.js';
|
|
8
9
|
import { PULSEX_MARGINAL_REFERENCE_DIVISOR, pulsechainChainId } from '../producers.js';
|
|
9
10
|
import { assetNodeKey } from '../search/graph.js';
|
|
@@ -18,57 +19,73 @@ import { bestPulseXPathQuote, candidatePulseXPaths, pulseXHubTokens } from './pu
|
|
|
18
19
|
* See `omnibridge.ts`'s head doc for why this returns a plain object shaped
|
|
19
20
|
* like `Carrier` rather than importing that type.
|
|
20
21
|
*/
|
|
21
|
-
/**
|
|
22
|
-
const wplsAddress = nativeAssetOut[Chains.PLS];
|
|
23
|
-
/** The hub addresses every candidate path is built from — see {@link pulseXHubTokens}. */
|
|
22
|
+
/** The hub addresses every candidate path on PulseChain is built from — see {@link pulseXHubTokens}. */
|
|
24
23
|
const hubAddresses = pulseXHubTokens.map((hub) => hub.address);
|
|
25
24
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
25
|
+
* The wrapped-native token a chain's swaps route through, or undefined when
|
|
26
|
+
* this package does not know one for the chain. Without it a path on that
|
|
27
|
+
* chain can only be direct.
|
|
28
|
+
*
|
|
29
|
+
* @param chainId - the numeric chain id
|
|
31
30
|
*/
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
return
|
|
35
|
-
}
|
|
31
|
+
const wrappedNativeFor = (chainId) => {
|
|
32
|
+
const wrapped = nativeAssetOut[toChain(chainId)];
|
|
33
|
+
return wrapped === undefined ? undefined : getAddress(wrapped);
|
|
34
|
+
};
|
|
36
35
|
/**
|
|
37
|
-
* The
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* meaning rather than guessing a new one.
|
|
36
|
+
* The hub tokens a path on `chainId` may pass through. PulseChain has the
|
|
37
|
+
* full list; any other chain has only its wrapped-native token, because this
|
|
38
|
+
* package knows no other hubs.
|
|
41
39
|
*/
|
|
42
|
-
const
|
|
40
|
+
const hubsFor = (chainId) => {
|
|
41
|
+
if (chainId === pulsechainChainId)
|
|
42
|
+
return hubAddresses;
|
|
43
|
+
const wrapped = wrappedNativeFor(chainId);
|
|
44
|
+
return wrapped === undefined ? [] : [wrapped];
|
|
45
|
+
};
|
|
43
46
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @param edge - the edge to sign
|
|
49
|
-
* @returns the router, or null when the edge is not a PulseX edge or names a venue that is not a known PulseX router
|
|
47
|
+
* Every PulseX deployment on PulseChain, V1 first: the PulseChain entry of
|
|
48
|
+
* {@link defaultSwapVenues}. Frozen. It lists the DEFAULTS only — a carrier
|
|
49
|
+
* built with its own `venues` offers those instead.
|
|
50
50
|
*/
|
|
51
|
-
export const
|
|
51
|
+
export const pulseXVenues = defaultSwapVenues[pulsechainChainId] ?? [];
|
|
52
52
|
/**
|
|
53
|
-
* The {@link
|
|
53
|
+
* The {@link SwapVenue} a swap edge runs on: the one its figure was quoted
|
|
54
|
+
* against. Reads the edge's own {@link HopEdge.venue}; an edge with none runs
|
|
55
|
+
* on the FIRST venue of its chain (V1 for PulseX) — every swap edge built
|
|
56
|
+
* before venues existed was quoted and signed there, and the same-chain swap
|
|
57
|
+
* sender's own hand-built edge still is.
|
|
54
58
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
59
|
+
* NEVER FALLS BACK TO ANOTHER CHAIN OR ANOTHER ROUTER. An edge that names a
|
|
60
|
+
* router `venues` does not list gets null, so the caller can refuse it.
|
|
61
|
+
*
|
|
62
|
+
* @param venues - the venues the caller allows
|
|
63
|
+
* @param edge - the edge to sign; `from` names the chain, and defaults to PulseChain when absent
|
|
64
|
+
* @returns the venue, or null when the edge is not a swap edge or names a router that is not in `venues`
|
|
57
65
|
*/
|
|
58
|
-
const
|
|
66
|
+
export const venueForEdge = (venues, edge) => {
|
|
59
67
|
if (edge.carrier !== 'PulseX')
|
|
60
68
|
return null;
|
|
69
|
+
const chainId = edge.from?.chainId ?? pulsechainChainId;
|
|
61
70
|
if (edge.venue === undefined)
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
return pulseXVenues.find((candidate) => sameAddress(candidate.router, venue, 'evm')) ?? null;
|
|
71
|
+
return venues[chainId]?.[0] ?? null;
|
|
72
|
+
return findSwapVenue(venues, chainId, edge.venue);
|
|
65
73
|
};
|
|
66
74
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
75
|
+
* The router a PulseX edge must be signed on, judged against the DEFAULT
|
|
76
|
+
* venues only. Prefer {@link venueForEdge} with the venues your host passes.
|
|
77
|
+
*
|
|
78
|
+
* @param edge - the edge to sign
|
|
79
|
+
* @returns the router, or null when the edge is not a swap edge or names a router that is not a default
|
|
80
|
+
*/
|
|
81
|
+
export const pulseXRouterForEdge = (edge) => venueForEdge(defaultSwapVenues, edge)?.router ?? null;
|
|
82
|
+
/**
|
|
83
|
+
* A node's own address for a pool lookup: native (the zero address) is not a
|
|
84
|
+
* token the router or its factory ever holds a pool for — only the chain's
|
|
85
|
+
* wrapped-native token is — so a native node resolves to that wrapped token
|
|
70
86
|
* before it ever reaches {@link pulseXConversionSwapPath}. Every other node
|
|
71
|
-
* is unchanged.
|
|
87
|
+
* is unchanged. A chain with no known wrapped-native token leaves a native
|
|
88
|
+
* node as it is; it has no pool, so no path prices.
|
|
72
89
|
*
|
|
73
90
|
* MIRRORS `useRouteSearch.ts`'s `quotePathAddress` (the UI's async `ask`
|
|
74
91
|
* already resolves native this way through that function) — this is the
|
|
@@ -76,9 +93,9 @@ const pulseXVenueForEdge = (edge) => {
|
|
|
76
93
|
* UI's `readAmountOut` at all; see {@link pulseXCandidatePaths}'s own doc.
|
|
77
94
|
*
|
|
78
95
|
* @param node - the node to resolve
|
|
79
|
-
* @returns the node's own address, or
|
|
96
|
+
* @returns the node's own address, or its chain's wrapped-native address for a native node
|
|
80
97
|
*/
|
|
81
|
-
const poolTokenAddress = (node) =>
|
|
98
|
+
const poolTokenAddress = (node) => sameAddress(node.address, zeroAddress, 'evm') ? (wrappedNativeFor(node.chainId) ?? zeroAddress) : node.address;
|
|
82
99
|
/**
|
|
83
100
|
* The fixed Wrapped-PLS path from `from` to `to` — `[from, WPLS, to]`, or
|
|
84
101
|
* `[from, to]` when one side is WPLS — or null when both ends resolve to the
|
|
@@ -103,7 +120,8 @@ export const pulseXWrappedNativePath = (from, to) => {
|
|
|
103
120
|
const toAddress = poolTokenAddress(to);
|
|
104
121
|
if (sameAddress(fromAddress, toAddress, 'evm'))
|
|
105
122
|
return null;
|
|
106
|
-
|
|
123
|
+
const wrappedNative = wrappedNativeFor(from.chainId);
|
|
124
|
+
return wrappedNative === undefined ? [fromAddress, toAddress] : pulseXConversionSwapPath(fromAddress, toAddress, wrappedNative);
|
|
107
125
|
};
|
|
108
126
|
/**
|
|
109
127
|
* Every path a PulseX hop from `from` to `to` may be priced along, or none
|
|
@@ -122,21 +140,27 @@ const pulseXCandidatePaths = (from, to) => {
|
|
|
122
140
|
const toAddress = poolTokenAddress(to);
|
|
123
141
|
if (sameAddress(fromAddress, toAddress, 'evm'))
|
|
124
142
|
return [];
|
|
125
|
-
|
|
143
|
+
const wrappedNative = wrappedNativeFor(from.chainId);
|
|
144
|
+
// No known wrapped-native token: the direct pool is the only path.
|
|
145
|
+
if (wrappedNative === undefined)
|
|
146
|
+
return [[fromAddress, toAddress]];
|
|
147
|
+
return candidatePulseXPaths({ from: fromAddress, to: toAddress, wrappedNative, hubs: hubsFor(from.chainId) });
|
|
126
148
|
};
|
|
127
149
|
/**
|
|
128
|
-
* Whether
|
|
129
|
-
* Ethereum-Virtual-Machine tokens on
|
|
130
|
-
*
|
|
131
|
-
* tokens, so there is at least one path to price.
|
|
150
|
+
* Whether a swap venue in `venues` can carry funds directly from `from` to
|
|
151
|
+
* `to`: both must be Ethereum-Virtual-Machine tokens on the SAME chain, that
|
|
152
|
+
* chain must have at least one venue, and the two must resolve to different
|
|
153
|
+
* pool tokens, so there is at least one path to price.
|
|
132
154
|
*
|
|
133
155
|
* NO TOKEN ALLOWLIST IS CONSULTED, on purpose: whether a pool exists is the
|
|
134
156
|
* reserve read's question, answered in `prepare`, not this one's.
|
|
135
157
|
*/
|
|
136
|
-
const pulseXCarries = (from, to) => {
|
|
158
|
+
const pulseXCarries = (venues, from, to) => {
|
|
137
159
|
if (from.ecosystem !== 'evm' || to.ecosystem !== 'evm')
|
|
138
160
|
return false;
|
|
139
|
-
if (from.chainId !==
|
|
161
|
+
if (from.chainId !== to.chainId)
|
|
162
|
+
return false;
|
|
163
|
+
if ((venues[from.chainId] ?? []).length === 0)
|
|
140
164
|
return false;
|
|
141
165
|
return pulseXCandidatePaths(from, to).length > 0;
|
|
142
166
|
};
|
|
@@ -173,8 +197,9 @@ export const pulseXSwapPathForHop = (hop) => {
|
|
|
173
197
|
return path;
|
|
174
198
|
};
|
|
175
199
|
/**
|
|
176
|
-
* PulseX's own constant-product swap fee
|
|
177
|
-
*
|
|
200
|
+
* PulseX's own constant-product swap fee in basis points (29 of 10000, a
|
|
201
|
+
* numerator of 9971) — the default for {@link amountOutAlongPath}; a
|
|
202
|
+
* venue carries its own `feeBasisPoints`. The SAME `getAmountOut` formula every
|
|
178
203
|
* Uniswap-V2-style router uses: `amountOut = floor(amountIn * feeNumerator *
|
|
179
204
|
* reserveOut / (reserveIn * feeDenominator + amountIn * feeNumerator))`.
|
|
180
205
|
*
|
|
@@ -187,16 +212,16 @@ export const pulseXSwapPathForHop = (hop) => {
|
|
|
187
212
|
* this claim against live chain data rather than trusting the arithmetic
|
|
188
213
|
* alone.
|
|
189
214
|
*/
|
|
190
|
-
const
|
|
191
|
-
/**
|
|
192
|
-
const
|
|
215
|
+
const PULSEX_FEE_BASIS_POINTS = 29;
|
|
216
|
+
/** Basis points in a whole: the denominator of every venue's fee. */
|
|
217
|
+
const BASIS_POINTS_DENOMINATOR = 10000n;
|
|
193
218
|
/** The minimal read-only factory ABI `prepare` needs — just enough to resolve a pool's address from its two tokens. */
|
|
194
219
|
const univ2FactoryAbi = parseAbi([
|
|
195
220
|
'function getPair(address tokenA, address tokenB) external view returns (address pair)',
|
|
196
221
|
]);
|
|
197
222
|
/**
|
|
198
223
|
* The Uniswap-V2-style constant-product `getAmountOut`, applied with
|
|
199
|
-
*
|
|
224
|
+
* the venue's fee. Reproduces the router's own on-chain formula
|
|
200
225
|
* exactly — see `pulsex-carrier.fork.test.ts` — so PRICE IMPACT IS ALREADY
|
|
201
226
|
* IN HERE: this is the same nonlinear function the router evaluates, not a
|
|
202
227
|
* flat-fee approximation with an impact correction bolted on afterward.
|
|
@@ -204,14 +229,15 @@ const univ2FactoryAbi = parseAbi([
|
|
|
204
229
|
* @param amountIn - the input amount, in `reserveIn`'s token's base units
|
|
205
230
|
* @param reserveIn - the pool's reserve of the input token
|
|
206
231
|
* @param reserveOut - the pool's reserve of the output token
|
|
232
|
+
* @param feeBasisPoints - the venue's swap fee, in basis points
|
|
207
233
|
* @returns the output amount, in `reserveOut`'s token's base units; 0 when either reserve is 0
|
|
208
234
|
*/
|
|
209
|
-
const constantProductAmountOut = (amountIn, reserveIn, reserveOut) => {
|
|
235
|
+
const constantProductAmountOut = (amountIn, reserveIn, reserveOut, feeBasisPoints) => {
|
|
210
236
|
if (reserveIn <= 0n || reserveOut <= 0n || amountIn <= 0n)
|
|
211
237
|
return 0n;
|
|
212
|
-
const amountInWithFee = amountIn *
|
|
238
|
+
const amountInWithFee = amountIn * (BASIS_POINTS_DENOMINATOR - BigInt(feeBasisPoints));
|
|
213
239
|
const numerator = amountInWithFee * reserveOut;
|
|
214
|
-
const denominator = reserveIn *
|
|
240
|
+
const denominator = reserveIn * BASIS_POINTS_DENOMINATOR + amountInWithFee;
|
|
215
241
|
return numerator / denominator;
|
|
216
242
|
};
|
|
217
243
|
/**
|
|
@@ -220,9 +246,10 @@ const constantProductAmountOut = (amountIn, reserveIn, reserveOut) => {
|
|
|
220
246
|
*
|
|
221
247
|
* @param amountIn - the amount entering the first pool
|
|
222
248
|
* @param steps - the pools in order of travel
|
|
249
|
+
* @param feeBasisPoints - the venue's swap fee in basis points; PulseX's 29 when omitted
|
|
223
250
|
* @returns the amount leaving the last pool; 0 when any pool cannot pay out
|
|
224
251
|
*/
|
|
225
|
-
export const amountOutAlongPath = (amountIn, steps) => steps.reduce((runningAmount, step) => constantProductAmountOut(runningAmount, step.reserveIn, step.reserveOut), amountIn);
|
|
252
|
+
export const amountOutAlongPath = (amountIn, steps, feeBasisPoints = PULSEX_FEE_BASIS_POINTS) => steps.reduce((runningAmount, step) => constantProductAmountOut(runningAmount, step.reserveIn, step.reserveOut, feeBasisPoints), amountIn);
|
|
226
253
|
/**
|
|
227
254
|
* How far a trade's executed rate falls below the marginal (near-spot) rate,
|
|
228
255
|
* in percent. The marginal rate is a tiny reference trade through the same
|
|
@@ -258,7 +285,7 @@ const poolKey = (tokenA, tokenB) => {
|
|
|
258
285
|
return `${lower}|${higher}`;
|
|
259
286
|
};
|
|
260
287
|
/** The key one venue's pool is stored under: the same two tokens on V1 and on V2 are two different pools with two different reserves. */
|
|
261
|
-
const venuePoolKey = (venue, tokenA, tokenB) => `${venue.factory.toLowerCase()}|${poolKey(tokenA, tokenB)}`;
|
|
288
|
+
const venuePoolKey = (venue, tokenA, tokenB) => `${venue.chainId}|${venue.factory.toLowerCase()}|${poolKey(tokenA, tokenB)}`;
|
|
262
289
|
/** Every consecutive (tokenIn, tokenOut) hop a PulseX swap path implies. */
|
|
263
290
|
const hopsAlongPath = (path) => path.slice(0, -1).map((tokenIn, index) => [tokenIn, path[index + 1]]);
|
|
264
291
|
/**
|
|
@@ -318,16 +345,36 @@ const stepsAlongPath = (options) => {
|
|
|
318
345
|
*/
|
|
319
346
|
const preparePulseXReserves = async ({ nodes, venues, clientForChain, }) => {
|
|
320
347
|
const reservesByPoolKey = new Map();
|
|
321
|
-
const
|
|
322
|
-
|
|
348
|
+
const chainIds = Object.keys(venues)
|
|
349
|
+
.map(Number)
|
|
350
|
+
.filter((chainId) => (venues[chainId] ?? []).length > 0);
|
|
351
|
+
for (const chainId of chainIds) {
|
|
352
|
+
const chainReserves = await preparePulseXReservesOnChain({ nodes, chainId, venues, clientForChain });
|
|
353
|
+
for (const [key, reserves] of chainReserves)
|
|
354
|
+
reservesByPoolKey.set(key, reserves);
|
|
355
|
+
}
|
|
356
|
+
return reservesByPoolKey;
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* One chain's share of {@link preparePulseXReserves}: two multicalls, the
|
|
360
|
+
* `getPair` reads and then the `getReserves` reads, over every venue of the
|
|
361
|
+
* chain. A chain with no client, or with no chain description to multicall
|
|
362
|
+
* against, reads nothing.
|
|
363
|
+
*/
|
|
364
|
+
const preparePulseXReservesOnChain = async ({ nodes, chainId, venues, clientForChain, }) => {
|
|
365
|
+
const reservesByPoolKey = new Map();
|
|
366
|
+
const client = clientForChain(chainId);
|
|
367
|
+
const knownChain = chainsMetadata[toChain(chainId)];
|
|
368
|
+
const chain = knownChain ?? client?.chain;
|
|
369
|
+
if (client === null || chain === undefined)
|
|
323
370
|
return reservesByPoolKey;
|
|
324
|
-
const
|
|
371
|
+
const chainNodes = nodes.filter((node) => node.ecosystem === 'evm' && node.chainId === chainId);
|
|
325
372
|
const poolTokenPairs = new Map();
|
|
326
|
-
for (const from of
|
|
327
|
-
for (const to of
|
|
373
|
+
for (const from of chainNodes) {
|
|
374
|
+
for (const to of chainNodes) {
|
|
328
375
|
if (assetNodeKey(from) === assetNodeKey(to))
|
|
329
376
|
continue;
|
|
330
|
-
if (!pulseXCarries(from, to))
|
|
377
|
+
if (!pulseXCarries(venues, from, to))
|
|
331
378
|
continue;
|
|
332
379
|
for (const path of pulseXCandidatePaths(from, to)) {
|
|
333
380
|
for (const [tokenIn, tokenOut] of hopsAlongPath(path)) {
|
|
@@ -338,14 +385,14 @@ const preparePulseXReserves = async ({ nodes, venues, clientForChain, }) => {
|
|
|
338
385
|
}
|
|
339
386
|
if (poolTokenPairs.size === 0)
|
|
340
387
|
return reservesByPoolKey;
|
|
341
|
-
const poolQueries = venues.flatMap((venue) => Array.from(poolTokenPairs.values()).map(([tokenIn, tokenOut]) => ({
|
|
388
|
+
const poolQueries = (venues[chainId] ?? []).flatMap((venue) => Array.from(poolTokenPairs.values()).map(([tokenIn, tokenOut]) => ({
|
|
342
389
|
key: venuePoolKey(venue, tokenIn, tokenOut),
|
|
343
390
|
factory: venue.factory,
|
|
344
391
|
tokenIn,
|
|
345
392
|
tokenOut,
|
|
346
393
|
})));
|
|
347
394
|
const factoryResults = await multicallRead({
|
|
348
|
-
chain
|
|
395
|
+
chain,
|
|
349
396
|
client,
|
|
350
397
|
abi: univ2FactoryAbi,
|
|
351
398
|
calls: poolQueries.map((query) => ({
|
|
@@ -370,7 +417,7 @@ const preparePulseXReserves = async ({ nodes, venues, clientForChain, }) => {
|
|
|
370
417
|
return reservesByPoolKey;
|
|
371
418
|
const reservePoolKeys = Array.from(pairAddressByPoolKey.keys());
|
|
372
419
|
const reserveResults = await multicallRead({
|
|
373
|
-
chain
|
|
420
|
+
chain,
|
|
374
421
|
client,
|
|
375
422
|
abi: abis.pair,
|
|
376
423
|
calls: reservePoolKeys.map((key) => ({
|
|
@@ -395,22 +442,24 @@ const preparePulseXReserves = async ({ nodes, venues, clientForChain, }) => {
|
|
|
395
442
|
return reservesByPoolKey;
|
|
396
443
|
};
|
|
397
444
|
/**
|
|
398
|
-
* The venues a carrier offers: every
|
|
399
|
-
* host names. A named router that is
|
|
400
|
-
*
|
|
445
|
+
* The venues a carrier offers: every venue in `venues`, or only the routers
|
|
446
|
+
* the host names. A named router that is in no venue is a configuration
|
|
447
|
+
* error, thrown at construction rather than offered silently.
|
|
401
448
|
*
|
|
449
|
+
* @param venues - the resolved venues
|
|
402
450
|
* @param routers - the routers the host can sign on, or undefined for all
|
|
403
|
-
* @returns the venues, in
|
|
451
|
+
* @returns the venues, in their original order
|
|
404
452
|
*/
|
|
405
|
-
const selectPulseXVenues = (routers) => {
|
|
453
|
+
const selectPulseXVenues = (venues, routers) => {
|
|
406
454
|
if (routers === undefined)
|
|
407
|
-
return
|
|
455
|
+
return venues;
|
|
456
|
+
const named = (venue) => routers.some((router) => sameAddress(venue.router, router, 'evm'));
|
|
408
457
|
for (const router of routers) {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
458
|
+
const offered = Object.values(venues).some((list) => list.some((venue) => sameAddress(venue.router, router, 'evm')));
|
|
459
|
+
if (!offered)
|
|
460
|
+
throw new Error(`createPulseXCarrier: ${router} is not a known PulseX router in the offered swap venues`);
|
|
412
461
|
}
|
|
413
|
-
return
|
|
462
|
+
return Object.freeze(Object.fromEntries(Object.entries(venues).map(([chainId, list]) => [chainId, list.filter(named)])));
|
|
414
463
|
};
|
|
415
464
|
/**
|
|
416
465
|
* Builds the PulseX conversion swap as a plug-in carrier.
|
|
@@ -420,16 +469,16 @@ const selectPulseXVenues = (routers) => {
|
|
|
420
469
|
*/
|
|
421
470
|
export const createPulseXCarrier = (options) => {
|
|
422
471
|
const { readAmountOut, clientForChain } = options;
|
|
423
|
-
const venues = selectPulseXVenues(options.routers);
|
|
472
|
+
const venues = selectPulseXVenues(resolveSwapVenues(options.venues), options.routers);
|
|
424
473
|
// ONE EDGE PER VENUE. Each names its router as its `venue`, so the search
|
|
425
474
|
// quotes and ranks V1 and V2 as two separate hops and the better one wins
|
|
426
475
|
// on its own figure — and the winner is signed on the router it names.
|
|
427
476
|
const edgesFrom = (from, to) => {
|
|
428
477
|
if (assetNodeKey(from) === assetNodeKey(to))
|
|
429
478
|
return [];
|
|
430
|
-
if (!pulseXCarries(from, to))
|
|
479
|
+
if (!pulseXCarries(venues, from, to))
|
|
431
480
|
return [];
|
|
432
|
-
return venues.map((venue) => ({
|
|
481
|
+
return (venues[from.chainId] ?? []).map((venue) => ({
|
|
433
482
|
carrier: 'PulseX',
|
|
434
483
|
from,
|
|
435
484
|
to,
|
|
@@ -465,19 +514,19 @@ export const createPulseXCarrier = (options) => {
|
|
|
465
514
|
reservesByPoolKey = await preparePulseXReserves({ nodes, venues, clientForChain });
|
|
466
515
|
};
|
|
467
516
|
const exact = (edge, amountIn) => {
|
|
468
|
-
if (!pulseXCarries(edge.from, edge.to))
|
|
517
|
+
if (!pulseXCarries(venues, edge.from, edge.to))
|
|
469
518
|
return null;
|
|
470
519
|
// Quoted on the edge's OWN venue — the router it will be signed on — and
|
|
471
520
|
// only on a venue this carrier offers.
|
|
472
|
-
const venue =
|
|
473
|
-
if (venue === null
|
|
521
|
+
const venue = venueForEdge(venues, edge);
|
|
522
|
+
if (venue === null)
|
|
474
523
|
return null;
|
|
475
524
|
// EVERY CANDIDATE PATH IS PRICED, AND THE BEST ONE WINS. A path with a
|
|
476
525
|
// pool `prepare` never found is left out — the same as a router call
|
|
477
526
|
// that would revert — and a path that pays out nothing is never picked.
|
|
478
527
|
const quotes = pulseXCandidatePaths(edge.from, edge.to).flatMap((path) => {
|
|
479
528
|
const steps = stepsAlongPath({ venue, path, reservesByPoolKey });
|
|
480
|
-
return steps === null ? [] : [{ path, steps, deliveredAmount: amountOutAlongPath(amountIn, steps) }];
|
|
529
|
+
return steps === null ? [] : [{ path, steps, deliveredAmount: amountOutAlongPath(amountIn, steps, venue.feeBasisPoints) }];
|
|
481
530
|
});
|
|
482
531
|
// No path had every pool read — a structural non-answer, not a refusal
|
|
483
532
|
// (`exact`'s own doc: `null` means "nothing to say"). NOTE THIS DOES NOT
|
|
@@ -497,7 +546,7 @@ export const createPulseXCarrier = (options) => {
|
|
|
497
546
|
amountIn,
|
|
498
547
|
amountOut: best.deliveredAmount,
|
|
499
548
|
referenceAmountIn,
|
|
500
|
-
referenceAmountOut: amountOutAlongPath(referenceAmountIn, best.steps),
|
|
549
|
+
referenceAmountOut: amountOutAlongPath(referenceAmountIn, best.steps, venue.feeBasisPoints),
|
|
501
550
|
});
|
|
502
551
|
// The path rides on the answer, so the signer signs exactly what was
|
|
503
552
|
// priced (`pulseXSwapPathForHop`). Impact is left off (not zero) when the
|
package/dist/routing/index.d.ts
CHANGED
|
@@ -8,12 +8,12 @@ export { netDeliveredAmount, restateInDecimals, valueEquivalentAmount } from './
|
|
|
8
8
|
export { omnibridgeProviderForEntryChain, pulseXConversionSwapPath } from './providers.js';
|
|
9
9
|
export { buildDirectCrossingCandidate } from './candidate.js';
|
|
10
10
|
export type { RouteCandidate, DeferredCrossing, DirectCrossingCandidateInputs } from './candidate.js';
|
|
11
|
-
export { buildRouteDataForCandidate, routeSignatureCount } from './candidate-route.js';
|
|
11
|
+
export { buildRouteDataForCandidate, routeSignatureCount, routeSignatureCountForAccount, type RouteSignatureCount, } from './candidate-route.js';
|
|
12
12
|
export { COMPOSED_ROUTE_MAX_PRICE_IMPACT_PERCENT, COMPOSED_ROUTE_MAX_VALUE_GAIN_PERCENT, COMPOSED_ROUTE_MAX_VALUE_LOSS_PERCENT, assessComposedRoute, composedRouteMayBeOffered, } from './composed-route-quality.js';
|
|
13
13
|
export type { ComposedRouteVerdict } from './composed-route-quality.js';
|
|
14
14
|
export { entryChainAnchorsForPair } from './entry-chain-anchor.js';
|
|
15
15
|
export type { EntryChainAnchor, EntryChainCrossingCall } from './entry-chain-anchor.js';
|
|
16
|
-
export type { EstimateBasis, RouteData, RouteHopData, RouteKind, RouteOutputData, RouteSectionData, RouteTokenRef, } from './route-data.js';
|
|
16
|
+
export type { EstimateBasis, RouteData, RouteGasByChain, RouteHopData, RouteKind, RouteOutputData, RouteSectionData, RouteTokenRef, } from './route-data.js';
|
|
17
17
|
export { usdValueOfAmount } from './usd-value.js';
|
|
18
18
|
export { formatUsd, formatUsdNullable } from './format.js';
|
|
19
19
|
export { BRIDGE_SETTLEMENT_ETA_MINUTES, PULSEX_MARGINAL_REFERENCE_DIVISOR, pulsechainChainId, addUsdValues, providerDisplayName, resolveEntryChainName, buildCandidateRouteData, buildConversionRouteData, buildDirectRouteData, buildPulseXSwapEstimateData, buildPulseXSwapSectionData, buildOutboundRouteData, buildSameChainSwapRouteData, candidateDeliveredUsd, candidateNetValueUsd, candidateOutsideFeesUsd, candidatePaidUsd, } from './producers.js';
|
|
@@ -24,14 +24,18 @@ export { composableHopBasis, composeRouteDelivery, hopOutputAmount, } from './se
|
|
|
24
24
|
export type { ComposableHop, ComposableHopFigure, ComposeRefusalReason, ComposedRouteDelivery, ExchangeRate, } from './search/compose.js';
|
|
25
25
|
export { GAS_TOPUP_PENALTY_FLOOR_USD, GAS_TOPUP_PENALTY_PPM, SIGNATURE_PENALTY_FLOOR_USD, SIGNATURE_PENALTY_PPM, compareRoutePlansByGasAdjustedDeliveredAmount, compareRoutePlansByScoreAdjustedDeliveredAmount, gasAdjustedDeliveredAmount, scoreRoutePlan, sectionIsFundedByLanding, waitPenaltyPpm, zeroGasCostFor, } from './search/score.js';
|
|
26
26
|
export type { GasCostFor, GasCostQuote, RouteScoreInputs } from './search/score.js';
|
|
27
|
+
export { WRAP_CARRIER_ID, carrierProviderKey, carrierStepKind } from './carrier-provider-key.js';
|
|
28
|
+
export type { CarrierStepKind } from './carrier-provider-key.js';
|
|
27
29
|
export { buildRouteCandidateFromPlan, buildRouteDataFromPlan, buildRouteScoreInputsFromPlan, deriveDeferredCrossingFromPlan, deriveEntryChainIdFromPlan, deriveOmnibridgeProviderFromPlan, deriveViaChainIdsFromPlan, derivePlanKind, } from './search/plan-route-data.js';
|
|
28
30
|
export type { PlanCandidateInputs, PlanRouteDataInputs, PlanSectionPricing, PlanValuation, ResolveNodeToken, } from './search/plan-route-data.js';
|
|
29
31
|
export { createOmnibridgeCarrier, withOmnibridgeEntryFusing, } from './carriers/omnibridge.js';
|
|
30
32
|
export type { BridgeablePair, CreateOmnibridgeCarrierOptions, } from './carriers/omnibridge.js';
|
|
31
|
-
export { createPulseXCarrier, pulseXRouterForEdge, pulseXSwapPathForHop, pulseXVenues, pulseXWrappedNativePath, } from './carriers/pulsex.js';
|
|
33
|
+
export { createPulseXCarrier, pulseXRouterForEdge, venueForEdge, pulseXSwapPathForHop, pulseXVenues, pulseXWrappedNativePath, } from './carriers/pulsex.js';
|
|
32
34
|
export type { CreatePulseXCarrierOptions, PulseXVenue } from './carriers/pulsex.js';
|
|
33
35
|
export { bestPulseXPathQuote, candidatePulseXPaths, pulseXHubTokens } from './carriers/pulsex-paths.js';
|
|
34
36
|
export type { PulseXHubToken, PulseXPathQuote } from './carriers/pulsex-paths.js';
|
|
37
|
+
export { findSwapVenue, resolveSwapVenues } from '../swap-venues.js';
|
|
38
|
+
export type { SwapVenue, SwapVenues } from '../swap-venues.js';
|
|
35
39
|
export { createWrapCarrier } from './carriers/wrap.js';
|
|
36
40
|
export type { CarrierAskAnswer, CarrierExactResult } from './carriers/ask-answer.js';
|
|
37
41
|
export { buildPulseXSwapTransaction, buildWrapTransaction, swapMinimumOut } from './swap-transactions.js';
|
package/dist/routing/index.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export { netDeliveredAmount, restateInDecimals, valueEquivalentAmount } from './amounts.js';
|
|
8
8
|
export { omnibridgeProviderForEntryChain, pulseXConversionSwapPath } from './providers.js';
|
|
9
9
|
export { buildDirectCrossingCandidate } from './candidate.js';
|
|
10
|
-
export { buildRouteDataForCandidate, routeSignatureCount } from './candidate-route.js';
|
|
10
|
+
export { buildRouteDataForCandidate, routeSignatureCount, routeSignatureCountForAccount, } from './candidate-route.js';
|
|
11
11
|
export { COMPOSED_ROUTE_MAX_PRICE_IMPACT_PERCENT, COMPOSED_ROUTE_MAX_VALUE_GAIN_PERCENT, COMPOSED_ROUTE_MAX_VALUE_LOSS_PERCENT, assessComposedRoute, composedRouteMayBeOffered, } from './composed-route-quality.js';
|
|
12
12
|
export { entryChainAnchorsForPair } from './entry-chain-anchor.js';
|
|
13
13
|
export { usdValueOfAmount } from './usd-value.js';
|
|
@@ -26,6 +26,7 @@ export { BRIDGE_SETTLEMENT_ETA_MINUTES, PULSEX_MARGINAL_REFERENCE_DIVISOR, pulse
|
|
|
26
26
|
export { RANKABLE_ESTIMATE_BASES, assetNodeKey, combineComposedPathBasis, compareRoutePlansByDeliveredAmount, groupHopsBySignature, hopComposedBasis, hopEdgeKey, isConfirmedBasis, isRankableBasis, isRateLimitedCarrier, planComposedBasis, planIsConfirmed, planIsRankable, routePlanPathKey, } from './search/graph.js';
|
|
27
27
|
export { composableHopBasis, composeRouteDelivery, hopOutputAmount, } from './search/compose.js';
|
|
28
28
|
export { GAS_TOPUP_PENALTY_FLOOR_USD, GAS_TOPUP_PENALTY_PPM, SIGNATURE_PENALTY_FLOOR_USD, SIGNATURE_PENALTY_PPM, compareRoutePlansByGasAdjustedDeliveredAmount, compareRoutePlansByScoreAdjustedDeliveredAmount, gasAdjustedDeliveredAmount, scoreRoutePlan, sectionIsFundedByLanding, waitPenaltyPpm, zeroGasCostFor, } from './search/score.js';
|
|
29
|
+
export { WRAP_CARRIER_ID, carrierProviderKey, carrierStepKind } from './carrier-provider-key.js';
|
|
29
30
|
// General route search — Phase 1: plan-route-data.ts. Turns a priced
|
|
30
31
|
// RoutePlan into the same RouteData/RouteCandidate/RouteScoreInputs shapes
|
|
31
32
|
// today's four hand-written producers emit — see that module's head doc.
|
|
@@ -38,8 +39,9 @@ export { buildRouteCandidateFromPlan, buildRouteDataFromPlan, buildRouteScoreInp
|
|
|
38
39
|
// `searchRouteWaves` and their types from `@gibs/quotes/search`. Gibs's own
|
|
39
40
|
// carriers (the omnibridge crossing, PulseX) live in `./carriers/`, below.
|
|
40
41
|
export { createOmnibridgeCarrier, withOmnibridgeEntryFusing, } from './carriers/omnibridge.js';
|
|
41
|
-
export { createPulseXCarrier, pulseXRouterForEdge, pulseXSwapPathForHop, pulseXVenues, pulseXWrappedNativePath, } from './carriers/pulsex.js';
|
|
42
|
+
export { createPulseXCarrier, pulseXRouterForEdge, venueForEdge, pulseXSwapPathForHop, pulseXVenues, pulseXWrappedNativePath, } from './carriers/pulsex.js';
|
|
42
43
|
export { bestPulseXPathQuote, candidatePulseXPaths, pulseXHubTokens } from './carriers/pulsex-paths.js';
|
|
44
|
+
export { findSwapVenue, resolveSwapVenues } from '../swap-venues.js';
|
|
43
45
|
export { createWrapCarrier } from './carriers/wrap.js';
|
|
44
46
|
// The same-chain swap and wrap builders. The interface's section signing and
|
|
45
47
|
// the SDK's execution planner (`../execution.ts`) share them.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Hex } from 'viem';
|
|
2
2
|
import type { QuoteFee } from '../quote-fees.js';
|
|
3
3
|
import type { ProviderKey } from '../providers.js';
|
|
4
|
+
import type { CarrierStepKind } from './carrier-provider-key.js';
|
|
4
5
|
/**
|
|
5
6
|
* The executing engine family a route runs through.
|
|
6
7
|
*
|
|
@@ -91,7 +92,12 @@ export type RouteHopData = {
|
|
|
91
92
|
/** Display name for the hop's provider, e.g. "LI.FI", "PulseChain Bridge". */
|
|
92
93
|
providerName: string;
|
|
93
94
|
/** Raw provider key for logo resolution when no `providerLogoUri` is supplied. */
|
|
94
|
-
providerKey?:
|
|
95
|
+
providerKey?: ProviderKey | null;
|
|
96
|
+
/**
|
|
97
|
+
* What the hop does when no provider performs it (a native wrap). Such a hop
|
|
98
|
+
* has a null `providerKey`; the adapter draws its mark from this kind.
|
|
99
|
+
*/
|
|
100
|
+
stepKind?: CarrierStepKind | null;
|
|
95
101
|
/** Quote-supplied provider logo url (aggregator legs); preferred when present. */
|
|
96
102
|
providerLogoUri?: string | null;
|
|
97
103
|
/** Human-readable hop title, e.g. "Bridge to PulseChain". */
|
|
@@ -110,11 +116,27 @@ export type RouteHopData = {
|
|
|
110
116
|
* completes. Null/undefined when the provider named no output token.
|
|
111
117
|
*/
|
|
112
118
|
toToken?: RouteTokenRef | null;
|
|
113
|
-
/** Per-hop fee in United States dollars as a NUMBER, or null when unknown. */
|
|
119
|
+
/** Per-hop fee in United States dollars as a NUMBER, or null when unknown. A search route's figure INCLUDES the signature's network gas (carried on the section's first hop). */
|
|
114
120
|
feeUsdValue?: number | null;
|
|
121
|
+
/** The part of {@link feeUsdValue} that is not network gas: what the hop costs in value. Absent when the producer states no gas split. */
|
|
122
|
+
feeExcludingGasUsdValue?: number | null;
|
|
123
|
+
/** The network gas of the signature this hop opens, in dollars; null or absent on every hop that opens none, and when gas is unknown. */
|
|
124
|
+
gasUsdValue?: number | null;
|
|
115
125
|
/** True when this hop runs automatically inside the section's single signature. */
|
|
116
126
|
automatic?: boolean;
|
|
117
127
|
};
|
|
128
|
+
/**
|
|
129
|
+
* The network gas a route needs on one signing chain, summed across the
|
|
130
|
+
* signatures it signs there.
|
|
131
|
+
*/
|
|
132
|
+
export type RouteGasByChain = {
|
|
133
|
+
/** The chain the signatures broadcast on. */
|
|
134
|
+
chainId: number;
|
|
135
|
+
/** The native coin they burn, in base units (wei), or null when the chain's gas price is unknown. */
|
|
136
|
+
amountWei: bigint | null;
|
|
137
|
+
/** The same gas in dollars, or null when the amount or the native price is unknown. */
|
|
138
|
+
usdValue: number | null;
|
|
139
|
+
};
|
|
118
140
|
/**
|
|
119
141
|
* What a signature section's funds LAND IN when that step completes — the stop
|
|
120
142
|
* the money actually comes to rest at, named in tokens rather than only drawn as
|
|
@@ -181,7 +203,9 @@ export type RouteSectionData = {
|
|
|
181
203
|
/** Short label naming what this signature does, e.g. "Bridge to PulseChain". */
|
|
182
204
|
label: string;
|
|
183
205
|
/** Raw provider key for the service executing this signature, or null. */
|
|
184
|
-
providerKey?:
|
|
206
|
+
providerKey?: ProviderKey | null;
|
|
207
|
+
/** What the signature does when no provider performs it (a native wrap); see {@link RouteHopData.stepKind}. */
|
|
208
|
+
stepKind?: CarrierStepKind | null;
|
|
185
209
|
/**
|
|
186
210
|
* The token-icon flow this signature walks, in raw references: the source, then
|
|
187
211
|
* every INTERMEDIATE stop the funds pass through, then the destination. A
|
|
@@ -202,8 +226,12 @@ export type RouteSectionData = {
|
|
|
202
226
|
* a cost.
|
|
203
227
|
*/
|
|
204
228
|
unspent?: RouteUnspentData | null;
|
|
205
|
-
/** Section total fee in United States dollars as a NUMBER, or null. */
|
|
229
|
+
/** Section total fee in United States dollars as a NUMBER, or null. A search route's figure INCLUDES this signature's network gas. */
|
|
206
230
|
feeUsdValue?: number | null;
|
|
231
|
+
/** The part of {@link feeUsdValue} that is not network gas. Absent when the producer states no gas split. */
|
|
232
|
+
feeExcludingGasUsdValue?: number | null;
|
|
233
|
+
/** This signature's network gas in dollars, or null/absent when unknown. */
|
|
234
|
+
gasUsdValue?: number | null;
|
|
207
235
|
/** Numeric inputs for an optional fee breakdown line (conversion mode). */
|
|
208
236
|
feePercent?: number | null;
|
|
209
237
|
/** Price-impact percentage for an optional fee breakdown line (conversion mode). */
|
|
@@ -316,8 +344,22 @@ export type RouteData = {
|
|
|
316
344
|
sections: RouteSectionData[];
|
|
317
345
|
/** What the route delivers — used for ranking and the output row. */
|
|
318
346
|
output: RouteOutputData;
|
|
319
|
-
/**
|
|
347
|
+
/**
|
|
348
|
+
* Aggregate ALL-IN cost in United States dollars as a NUMBER, or null:
|
|
349
|
+
* value lost plus network gas. The ranking reads this figure. For the
|
|
350
|
+
* figure without gas, read {@link costExcludingGasUsdValue}.
|
|
351
|
+
*/
|
|
320
352
|
totalCostUsdValue?: number | null;
|
|
353
|
+
/** {@link totalCostUsdValue} without network gas: the value the reader gives up. Absent when the producer states no gas split. */
|
|
354
|
+
costExcludingGasUsdValue?: number | null;
|
|
355
|
+
/**
|
|
356
|
+
* The network gas the reader pays across every signature, in dollars, or
|
|
357
|
+
* null/absent when no signing chain has a gas reading. Never zero for
|
|
358
|
+
* "unknown".
|
|
359
|
+
*/
|
|
360
|
+
gasCostUsdValue?: number | null;
|
|
361
|
+
/** The gas by signing chain, in signing order: what to hold, and in which coin. */
|
|
362
|
+
gasByChain?: RouteGasByChain[];
|
|
321
363
|
/** The user's net United States dollar outcome; the figure routes are ranked on. */
|
|
322
364
|
netValueUsd?: number | null;
|
|
323
365
|
/** Estimated end-to-end duration in minutes, or null when unknown. */
|
|
@@ -3,7 +3,7 @@ import type { Provider } from '../../config.js';
|
|
|
3
3
|
import type { QuoteFee } from '../../quote-fees.js';
|
|
4
4
|
import type { Token } from '../../types.js';
|
|
5
5
|
import type { DeferredCrossing, RouteCandidate } from '../candidate.js';
|
|
6
|
-
import type { RouteData, RouteKind } from '../route-data.js';
|
|
6
|
+
import type { RouteData, RouteGasByChain, RouteKind } from '../route-data.js';
|
|
7
7
|
import type { RouteScoreInputs } from './score.js';
|
|
8
8
|
import { type AssetNode, type RoutePlan } from './graph.js';
|
|
9
9
|
/**
|
|
@@ -141,6 +141,16 @@ export type PlanSectionPricing = {
|
|
|
141
141
|
* caller passes shares that add up to `feeUsdValue`, or nothing.
|
|
142
142
|
*/
|
|
143
143
|
hopFeeUsdValues?: readonly (number | null)[];
|
|
144
|
+
/**
|
|
145
|
+
* The gas split of `feeUsdValue`, from a producer that prices network gas
|
|
146
|
+
* apart: `feeExcludingGasUsdValue` is the cost without gas, `gasUsdValue` the
|
|
147
|
+
* signature's gas (null when unknown). `hopFeeExcludingGasUsdValues` splits
|
|
148
|
+
* the first the way `hopFeeUsdValues` splits the all-in figure. The gas sits
|
|
149
|
+
* on the section's first hop.
|
|
150
|
+
*/
|
|
151
|
+
feeExcludingGasUsdValue?: number | null;
|
|
152
|
+
gasUsdValue?: number | null;
|
|
153
|
+
hopFeeExcludingGasUsdValues?: readonly (number | null)[];
|
|
144
154
|
/** The itemized charges behind `feeUsdValue`, passed straight through to `RouteSectionData.fees`. */
|
|
145
155
|
fees?: readonly QuoteFee[];
|
|
146
156
|
/** Estimated duration for this signature in minutes, or null/undefined to omit. */
|
|
@@ -175,6 +185,12 @@ export type PlanRouteDataInputs = {
|
|
|
175
185
|
sections: readonly PlanSectionPricing[];
|
|
176
186
|
/** The route's aggregate all-in cost in United States dollars, or null/undefined. */
|
|
177
187
|
totalCostUsdValue?: number | null;
|
|
188
|
+
/** The all-in cost without network gas, or null/undefined. */
|
|
189
|
+
costExcludingGasUsdValue?: number | null;
|
|
190
|
+
/** The route's network gas in dollars, or null/undefined when unknown. */
|
|
191
|
+
gasCostUsdValue?: number | null;
|
|
192
|
+
/** The gas by signing chain, in signing order. */
|
|
193
|
+
gasByChain?: readonly RouteGasByChain[];
|
|
178
194
|
/** The route's net United States dollar outcome — the figure routes are ranked on. */
|
|
179
195
|
netValueUsd?: number | null;
|
|
180
196
|
/** Estimated end-to-end duration in minutes, or null/undefined. */
|