@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
|
@@ -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. */
|
|
@@ -37,6 +37,7 @@ exports.buildRouteScoreInputsFromPlan = exports.buildRouteCandidateFromPlan = ex
|
|
|
37
37
|
const imageLinks = __importStar(require("../../image-links.js"));
|
|
38
38
|
const chain_names_js_1 = require("../../chain-names.js");
|
|
39
39
|
const providers_js_1 = require("../../providers.js");
|
|
40
|
+
const carrier_provider_key_js_1 = require("../carrier-provider-key.js");
|
|
40
41
|
const near_intents_route_js_1 = require("../../near-intents-route.js");
|
|
41
42
|
const producers_js_1 = require("../producers.js");
|
|
42
43
|
const graph_js_1 = require("./graph.js");
|
|
@@ -214,6 +215,8 @@ const groupEndsWithBridgeHop = (hops) => isBridgeCarrier(hops[hops.length - 1].e
|
|
|
214
215
|
* section, in BOTH its shapes (the entry-chain swap and the onward
|
|
215
216
|
* aggregator hop) — the section label names where the journey finishes
|
|
216
217
|
* regardless of which service carries the last leg.
|
|
218
|
+
* - **"Swap on {X}"** — a group of the "Send to" shape whose first hop starts
|
|
219
|
+
* on the chain its last hop ends on: nothing is sent anywhere.
|
|
217
220
|
* - **"Send to {X}"** — every other case: a non-final, non-bridge-ending
|
|
218
221
|
* group. Matches `buildNearIntentsTwoStepRouteData`'s first section.
|
|
219
222
|
*
|
|
@@ -235,7 +238,7 @@ const sectionLabel = (group, groupIndex, plan) => {
|
|
|
235
238
|
if (isFinalGroup) {
|
|
236
239
|
return `Complete at ${(0, chain_names_js_1.chainDisplayName)(destinationChainId)}`;
|
|
237
240
|
}
|
|
238
|
-
return
|
|
241
|
+
return (0, near_intents_route_js_1.sendOrSwapLabel)(hops[0].edge.from.chainId, destinationChainId);
|
|
239
242
|
};
|
|
240
243
|
// ---------------------------------------------------------------------------
|
|
241
244
|
// Hop-level rendering
|
|
@@ -265,6 +268,8 @@ const hopProviderName = (carrier) => {
|
|
|
265
268
|
return (0, producers_js_1.providerDisplayName)(carrier);
|
|
266
269
|
if (carrier === 'PulseX')
|
|
267
270
|
return 'PulseX';
|
|
271
|
+
if ((0, carrier_provider_key_js_1.carrierStepKind)(carrier) === 'wrap')
|
|
272
|
+
return 'Wrap';
|
|
268
273
|
// TOTAL OVER EVERY CARRIER. The engine plans hops for carriers the provider
|
|
269
274
|
// registry does not hold (a local wrap, a host's own plug-in). Casting such
|
|
270
275
|
// an id to a provider id and asking the throwing lookup crashed the whole
|
|
@@ -288,7 +293,8 @@ const hopProviderName = (carrier) => {
|
|
|
288
293
|
* `"Bridge to {toChainName}"` (matches `buildOutboundRouteData`'s onward
|
|
289
294
|
* hop, which names the chain it finishes on even though an aggregator,
|
|
290
295
|
* not the omnibridge, carries it);
|
|
291
|
-
* - any other aggregator hop (something follows it) → `"Send to {toChainName}"
|
|
296
|
+
* - any other aggregator hop (something follows it) → `"Send to {toChainName}"`,
|
|
297
|
+
* or `"Swap on {chainName}"` when the hop starts and ends on one chain
|
|
292
298
|
* (matches `buildNearIntentsTwoStepRouteData`'s aggregator hop).
|
|
293
299
|
*
|
|
294
300
|
* @param hop - the hop to title
|
|
@@ -307,10 +313,10 @@ const hopTitle = (hop, hopIndex, plan, resolveToken) => {
|
|
|
307
313
|
if (carrier === 'PulseX') {
|
|
308
314
|
return `Swap to ${resolveToken(hop.edge.to).symbol}`;
|
|
309
315
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
316
|
+
if (isFinalHopOfPlan(hopIndex, plan)) {
|
|
317
|
+
return `Bridge to ${(0, chain_names_js_1.chainDisplayName)(hop.edge.to.chainId)}`;
|
|
318
|
+
}
|
|
319
|
+
return (0, near_intents_route_js_1.sendOrSwapLabel)(hop.edge.from.chainId, hop.edge.to.chainId);
|
|
314
320
|
};
|
|
315
321
|
/**
|
|
316
322
|
* A hop's conversion subtitle.
|
|
@@ -386,11 +392,13 @@ const hopIsAutomatic = (hopIndex, plan) => {
|
|
|
386
392
|
* @param plan - the plan the hop belongs to
|
|
387
393
|
* @param resolveToken - resolves a graph node to its full display token
|
|
388
394
|
* @param feeUsdValue - the hop's own share of its section's cost, or null
|
|
395
|
+
* @param gas - the hop's gas split, or null when the producer states none
|
|
389
396
|
* @returns the raw hop data
|
|
390
397
|
*/
|
|
391
|
-
const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue) => ({
|
|
398
|
+
const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue, gas) => ({
|
|
392
399
|
providerName: hopProviderName(hop.edge.carrier),
|
|
393
|
-
providerKey: hop.edge.carrier,
|
|
400
|
+
providerKey: (0, carrier_provider_key_js_1.carrierProviderKey)(hop.edge.carrier),
|
|
401
|
+
stepKind: (0, carrier_provider_key_js_1.carrierStepKind)(hop.edge.carrier),
|
|
394
402
|
title: hopTitle(hop, hopIndex, plan, resolveToken),
|
|
395
403
|
conversion: hopConversion(hop, hopIndex, plan, resolveToken),
|
|
396
404
|
fromToken: toRouteTokenRef(hop.edge.from, resolveToken),
|
|
@@ -398,6 +406,7 @@ const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue) => ({
|
|
|
398
406
|
// The per-hop dollar figure is a caller-supplied input (see this module's
|
|
399
407
|
// head doc); the caller passes it in, never derived here.
|
|
400
408
|
feeUsdValue,
|
|
409
|
+
...(gas === null ? {} : gas),
|
|
401
410
|
automatic: hopIsAutomatic(hopIndex, plan),
|
|
402
411
|
});
|
|
403
412
|
/**
|
|
@@ -542,8 +551,6 @@ exports.derivePlanKind = derivePlanKind;
|
|
|
542
551
|
* @param carrier - the plan's headline carrier
|
|
543
552
|
* @returns the same value, typed as `ProviderKey`
|
|
544
553
|
*/
|
|
545
|
-
/** The carrier id of the native-coin wrap step (`routing/carriers/wrap.ts`). */
|
|
546
|
-
const WRAP_CARRIER = 'wrap';
|
|
547
554
|
const toHeadlineProviderKey = (carrier) => {
|
|
548
555
|
if (isBridgeCarrier(carrier))
|
|
549
556
|
return carrier;
|
|
@@ -576,7 +583,7 @@ exports.deriveHeadlineProviderKeyFromPlan = deriveHeadlineProviderKeyFromPlan;
|
|
|
576
583
|
* @param plan - the plan to read
|
|
577
584
|
* @returns the carrier to headline
|
|
578
585
|
*/
|
|
579
|
-
const firstHeadlineCarrier = (plan) => plan.hops.find((hop) => hop.edge.carrier !==
|
|
586
|
+
const firstHeadlineCarrier = (plan) => plan.hops.find((hop) => hop.edge.carrier !== carrier_provider_key_js_1.WRAP_CARRIER_ID)?.edge.carrier ?? 'PulseX';
|
|
580
587
|
/**
|
|
581
588
|
* The anchor a two-signature plan leaves the reader holding between its
|
|
582
589
|
* first and second groups — `RouteCandidate.plan`'s own TSDoc: "the anchor
|
|
@@ -696,10 +703,13 @@ const buildRouteDataFromPlan = (inputs) => {
|
|
|
696
703
|
const landing = resolveNodeWithAssertedDecimals(lastHop.edge.to, resolveToken);
|
|
697
704
|
const landingIsUnpriced = hopOutcomeIsUnpriced(lastHop);
|
|
698
705
|
const hopFeeUsdValues = groupHopFeeUsdValues(pricing, group, groupIndex);
|
|
706
|
+
const statesGasSplit = pricing.feeExcludingGasUsdValue !== undefined;
|
|
707
|
+
const hopFeeExcludingGasUsdValues = pricing.hopFeeExcludingGasUsdValues;
|
|
699
708
|
return {
|
|
700
709
|
id: `${routeId}-signature-${groupIndex + 1}`,
|
|
701
710
|
label: sectionLabel(group, groupIndex, plan),
|
|
702
|
-
providerKey: hops[0].edge.carrier,
|
|
711
|
+
providerKey: (0, carrier_provider_key_js_1.carrierProviderKey)(hops[0].edge.carrier),
|
|
712
|
+
stepKind: (0, carrier_provider_key_js_1.carrierStepKind)(hops[0].edge.carrier),
|
|
703
713
|
tokenFlow: buildGroupTokenFlow(hops, resolveToken),
|
|
704
714
|
landing: {
|
|
705
715
|
amount: sectionLandingAmount(pricing, lastHop),
|
|
@@ -709,10 +719,19 @@ const buildRouteDataFromPlan = (inputs) => {
|
|
|
709
719
|
estimateBasis: hopEstimateBasis(lastHop),
|
|
710
720
|
},
|
|
711
721
|
feeUsdValue: pricing.feeUsdValue,
|
|
722
|
+
...(statesGasSplit
|
|
723
|
+
? { feeExcludingGasUsdValue: pricing.feeExcludingGasUsdValue, gasUsdValue: pricing.gasUsdValue ?? null }
|
|
724
|
+
: {}),
|
|
712
725
|
fees: pricing.fees ? [...pricing.fees] : undefined,
|
|
713
726
|
etaMinutes: pricing.etaMinutes,
|
|
714
727
|
etaSeconds: pricing.etaSeconds,
|
|
715
|
-
hops: group.map((hopIndex, positionInGroup) => toRouteHopData(plan.hops[hopIndex], hopIndex, plan, resolveToken, hopFeeUsdValues[positionInGroup] ?? null
|
|
728
|
+
hops: group.map((hopIndex, positionInGroup) => toRouteHopData(plan.hops[hopIndex], hopIndex, plan, resolveToken, hopFeeUsdValues[positionInGroup] ?? null, statesGasSplit
|
|
729
|
+
? {
|
|
730
|
+
feeExcludingGasUsdValue: hopFeeExcludingGasUsdValues?.[positionInGroup] ??
|
|
731
|
+
(group.length === 1 ? (pricing.feeExcludingGasUsdValue ?? null) : null),
|
|
732
|
+
gasUsdValue: positionInGroup === 0 ? (pricing.gasUsdValue ?? null) : null,
|
|
733
|
+
}
|
|
734
|
+
: null)),
|
|
716
735
|
deferred: groupIndex > 0 ? true : undefined,
|
|
717
736
|
deferredNote: pricing.deferredNote,
|
|
718
737
|
};
|
|
@@ -731,6 +750,13 @@ const buildRouteDataFromPlan = (inputs) => {
|
|
|
731
750
|
estimateBasis: lastSection.landing?.estimateBasis ?? null,
|
|
732
751
|
},
|
|
733
752
|
totalCostUsdValue,
|
|
753
|
+
...(inputs.costExcludingGasUsdValue === undefined
|
|
754
|
+
? {}
|
|
755
|
+
: {
|
|
756
|
+
costExcludingGasUsdValue: inputs.costExcludingGasUsdValue,
|
|
757
|
+
gasCostUsdValue: inputs.gasCostUsdValue ?? null,
|
|
758
|
+
gasByChain: [...(inputs.gasByChain ?? [])],
|
|
759
|
+
}),
|
|
734
760
|
netValueUsd,
|
|
735
761
|
etaMinutes,
|
|
736
762
|
// The single legacy `viaChainId` a not-yet-migrated consumer may still
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Hex } from 'viem';
|
|
2
2
|
import { type SignedLeg } from '../settings.js';
|
|
3
|
+
import type { SwapVenues } from '../swap-venues.js';
|
|
3
4
|
import type { HopEdge, PlannedHop } from './search/graph.js';
|
|
4
5
|
/**
|
|
5
6
|
* The same-chain, one-signature transaction shape every sender in this file
|
|
@@ -27,7 +28,7 @@ export type SwapCallInputs = {
|
|
|
27
28
|
* looking at) and the native-in/native-out/token-token branching.
|
|
28
29
|
*
|
|
29
30
|
* SIGNS ON THE EDGE'S OWN ROUTER. A PulseX edge names the deployment it was
|
|
30
|
-
* quoted on (`
|
|
31
|
+
* quoted on (`venueForEdge`: V1 or V2, each with its own pools). The
|
|
31
32
|
* caller's `routerAddress` must be that same router — it is also the router
|
|
32
33
|
* the caller approved to spend the input token — or nothing is built. A V2
|
|
33
34
|
* quote signed on V1 would trade against a different pool than the one the
|
|
@@ -35,8 +36,9 @@ export type SwapCallInputs = {
|
|
|
35
36
|
*
|
|
36
37
|
* @param options - the hop to swap, the amount and slippage-adjusted
|
|
37
38
|
* minimum, who receives the output, the signing deadline, what the caller
|
|
38
|
-
* believes this signature does (`signedLeg`), the chain it executes on,
|
|
39
|
-
* the
|
|
39
|
+
* believes this signature does (`signedLeg`), the chain it executes on, the
|
|
40
|
+
* resolved router address, and the swap venues the router must belong to
|
|
41
|
+
* (the defaults when omitted)
|
|
40
42
|
* @returns the swap transaction inputs, or null when the hop records no
|
|
41
43
|
* PulseX swap path, names no known router, `routerAddress` is not the
|
|
42
44
|
* edge's own router, the leg on screen disagrees, or any of
|
|
@@ -51,6 +53,8 @@ export declare const buildPulseXSwapTransaction: (options: {
|
|
|
51
53
|
readonly signedLeg: SignedLeg | null;
|
|
52
54
|
readonly chainId: number | null;
|
|
53
55
|
readonly routerAddress: Hex | null;
|
|
56
|
+
/** The venues the edge's router must belong to. Omitted means the defaults. */
|
|
57
|
+
readonly venues?: SwapVenues;
|
|
54
58
|
}) => SwapCallInputs | null;
|
|
55
59
|
/**
|
|
56
60
|
* Builds a native-coin wrap/unwrap transaction for one route-search graph
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.swapMinimumOut = exports.buildWrapTransaction = exports.buildPulseXSwapTransaction = void 0;
|
|
4
4
|
const viem_1 = require("viem");
|
|
5
5
|
const settings_js_1 = require("../settings.js");
|
|
6
|
+
const config_js_1 = require("../config.js");
|
|
6
7
|
const pulsex_js_1 = require("./carriers/pulsex.js");
|
|
7
8
|
/**
|
|
8
9
|
* The minimal WETH9-style wrap/unwrap interface: `deposit()` mints the
|
|
@@ -32,7 +33,7 @@ const wrapAbi = (0, viem_1.parseAbi)(['function deposit() payable', 'function wi
|
|
|
32
33
|
* looking at) and the native-in/native-out/token-token branching.
|
|
33
34
|
*
|
|
34
35
|
* SIGNS ON THE EDGE'S OWN ROUTER. A PulseX edge names the deployment it was
|
|
35
|
-
* quoted on (`
|
|
36
|
+
* quoted on (`venueForEdge`: V1 or V2, each with its own pools). The
|
|
36
37
|
* caller's `routerAddress` must be that same router — it is also the router
|
|
37
38
|
* the caller approved to spend the input token — or nothing is built. A V2
|
|
38
39
|
* quote signed on V1 would trade against a different pool than the one the
|
|
@@ -40,8 +41,9 @@ const wrapAbi = (0, viem_1.parseAbi)(['function deposit() payable', 'function wi
|
|
|
40
41
|
*
|
|
41
42
|
* @param options - the hop to swap, the amount and slippage-adjusted
|
|
42
43
|
* minimum, who receives the output, the signing deadline, what the caller
|
|
43
|
-
* believes this signature does (`signedLeg`), the chain it executes on,
|
|
44
|
-
* the
|
|
44
|
+
* believes this signature does (`signedLeg`), the chain it executes on, the
|
|
45
|
+
* resolved router address, and the swap venues the router must belong to
|
|
46
|
+
* (the defaults when omitted)
|
|
45
47
|
* @returns the swap transaction inputs, or null when the hop records no
|
|
46
48
|
* PulseX swap path, names no known router, `routerAddress` is not the
|
|
47
49
|
* edge's own router, the leg on screen disagrees, or any of
|
|
@@ -54,7 +56,7 @@ const buildPulseXSwapTransaction = (options) => {
|
|
|
54
56
|
if (swapPath === null) {
|
|
55
57
|
return null;
|
|
56
58
|
}
|
|
57
|
-
const quotedRouter = (0, pulsex_js_1.
|
|
59
|
+
const quotedRouter = (0, pulsex_js_1.venueForEdge)(options.venues ?? config_js_1.defaultSwapVenues, edge)?.router ?? null;
|
|
58
60
|
if (quotedRouter === null || routerAddress === null || !(0, viem_1.isAddressEqual)(quotedRouter, routerAddress)) {
|
|
59
61
|
return null;
|
|
60
62
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Hex } from 'viem';
|
|
2
|
+
/**
|
|
3
|
+
* A place a same-chain token swap can execute. Today only Uniswap-V2-shaped
|
|
4
|
+
* routers exist: `getAmountsOut`, `swapExactTokensForTokens`,
|
|
5
|
+
* `swapExactETHForTokens`, `swapExactTokensForETH`, a factory with
|
|
6
|
+
* `getPair`, and pairs with `getReserves`. The `kind` field leaves room for
|
|
7
|
+
* other shapes (for example `'uniswap-v3'`) without breaking callers.
|
|
8
|
+
*/
|
|
9
|
+
export type SwapVenue = {
|
|
10
|
+
/** The router shape. Only `'uniswap-v2'` is supported. */
|
|
11
|
+
readonly kind: 'uniswap-v2';
|
|
12
|
+
/** The numeric chain id the router lives on. */
|
|
13
|
+
readonly chainId: number;
|
|
14
|
+
/** The router a swap is signed on. It is also the token approval spender. */
|
|
15
|
+
readonly router: Hex;
|
|
16
|
+
/** The factory whose pools the router trades against. */
|
|
17
|
+
readonly factory: Hex;
|
|
18
|
+
/** The swap fee in basis points: 29 for PulseX, 30 for Uniswap V2 forks. */
|
|
19
|
+
readonly feeBasisPoints: number;
|
|
20
|
+
/** A name for logs and displays. */
|
|
21
|
+
readonly label?: string;
|
|
22
|
+
};
|
|
23
|
+
/** The venues on each chain, keyed by numeric chain id. The first venue of a chain is its default. */
|
|
24
|
+
export type SwapVenues = Readonly<Record<number, readonly SwapVenue[]>>;
|
|
25
|
+
/**
|
|
26
|
+
* Merges caller venues over {@link defaultSwapVenues}. A chain present in
|
|
27
|
+
* `overrides` replaces the default list for that chain. A chain absent from
|
|
28
|
+
* `overrides` keeps its default list. An empty list switches swaps off on
|
|
29
|
+
* that chain. Neither input is changed; the result is frozen.
|
|
30
|
+
*
|
|
31
|
+
* @param overrides - the caller's venues, or undefined for the defaults
|
|
32
|
+
* @returns the venues to use
|
|
33
|
+
*/
|
|
34
|
+
export declare const resolveSwapVenues: (overrides?: SwapVenues) => SwapVenues;
|
|
35
|
+
/**
|
|
36
|
+
* Finds the venue on a chain that has the given router.
|
|
37
|
+
*
|
|
38
|
+
* @param venues - the venues to search
|
|
39
|
+
* @param chainId - the numeric chain id
|
|
40
|
+
* @param router - the router address, in any letter case
|
|
41
|
+
* @returns the venue, or null when the chain has no venue with that router
|
|
42
|
+
*/
|
|
43
|
+
export declare const findSwapVenue: (venues: SwapVenues, chainId: number, router: Hex) => SwapVenue | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findSwapVenue = exports.resolveSwapVenues = void 0;
|
|
4
|
+
const config_js_1 = require("./config.js");
|
|
5
|
+
/**
|
|
6
|
+
* Merges caller venues over {@link defaultSwapVenues}. A chain present in
|
|
7
|
+
* `overrides` replaces the default list for that chain. A chain absent from
|
|
8
|
+
* `overrides` keeps its default list. An empty list switches swaps off on
|
|
9
|
+
* that chain. Neither input is changed; the result is frozen.
|
|
10
|
+
*
|
|
11
|
+
* @param overrides - the caller's venues, or undefined for the defaults
|
|
12
|
+
* @returns the venues to use
|
|
13
|
+
*/
|
|
14
|
+
const resolveSwapVenues = (overrides) => {
|
|
15
|
+
if (overrides === undefined)
|
|
16
|
+
return config_js_1.defaultSwapVenues;
|
|
17
|
+
return Object.freeze({ ...config_js_1.defaultSwapVenues, ...overrides });
|
|
18
|
+
};
|
|
19
|
+
exports.resolveSwapVenues = resolveSwapVenues;
|
|
20
|
+
/**
|
|
21
|
+
* Finds the venue on a chain that has the given router.
|
|
22
|
+
*
|
|
23
|
+
* @param venues - the venues to search
|
|
24
|
+
* @param chainId - the numeric chain id
|
|
25
|
+
* @param router - the router address, in any letter case
|
|
26
|
+
* @returns the venue, or null when the chain has no venue with that router
|
|
27
|
+
*/
|
|
28
|
+
const findSwapVenue = (venues, chainId, router) => venues[chainId]?.find((venue) => venue.router.toLowerCase() === router.toLowerCase()) ?? null;
|
|
29
|
+
exports.findSwapVenue = findSwapVenue;
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ export type Token = TokenMetadata & {
|
|
|
30
30
|
* that carry no price (e.g. the dapp image lists).
|
|
31
31
|
*/
|
|
32
32
|
priceUSD?: string | null;
|
|
33
|
+
/**
|
|
34
|
+
* LI.FI's `coinKey`: a short key naming the asset across chains (for example
|
|
35
|
+
* "USDC"). Present only on tokens parsed from a LI.FI list that carries one.
|
|
36
|
+
* LI.FI repeats some keys within one chain, so a key alone is not an identity.
|
|
37
|
+
*/
|
|
38
|
+
coinKey?: string;
|
|
39
|
+
/** LI.FI's `verificationStatus` (for example "verified"). Present only on tokens parsed from a LI.FI list that carries one. */
|
|
40
|
+
verificationStatus?: string;
|
|
33
41
|
};
|
|
34
42
|
/** The token out for a given asset */
|
|
35
43
|
export type TokenOut = Omit<Token, 'address'> & {
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Hex } from 'viem';
|
|
2
|
+
import type { SwapVenues } from './swap-venues.js';
|
|
2
3
|
import type { BridgeKey, Token, TokenOut } from './types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Add here your chain id as hex, be sure to add your chain in the chainsMetadata object too
|
|
@@ -59,8 +60,22 @@ export declare const pulsechainTokenAddresses: Readonly<{
|
|
|
59
60
|
}>;
|
|
60
61
|
/** A map of chains to deprecated native asset out addresses */
|
|
61
62
|
export declare const deprecatedNativeAssetOut: Partial<Record<Chains, Set<Hex>>>;
|
|
62
|
-
/**
|
|
63
|
-
|
|
63
|
+
/**
|
|
64
|
+
* The swap venues the package ships with: PulseX V1 then V2 on PulseChain.
|
|
65
|
+
* Frozen. A caller who wants other routers passes its own
|
|
66
|
+
* {@link SwapVenues} (see `resolveSwapVenues`); this table is never mutated.
|
|
67
|
+
*
|
|
68
|
+
* Each factory is the router's own `router.factory()` read on chain — see
|
|
69
|
+
* {@link uniV2Factories}'s doc. The fee is 29 basis points for both
|
|
70
|
+
* deployments (measured, same doc).
|
|
71
|
+
*/
|
|
72
|
+
export declare const defaultSwapVenues: SwapVenues;
|
|
73
|
+
/**
|
|
74
|
+
* A map of chains to uni v2 router addresses. Frozen. PulseChain's entries
|
|
75
|
+
* derive from {@link defaultSwapVenues}, so the two cannot drift. Kept for
|
|
76
|
+
* compatibility; to swap on other routers pass `swapVenues` instead.
|
|
77
|
+
*/
|
|
78
|
+
export declare const uniV2Routers: Readonly<Record<Chains, readonly Hex[]>>;
|
|
64
79
|
/**
|
|
65
80
|
* Each {@link uniV2Routers} entry's OWN factory address, same index, same
|
|
66
81
|
* chain — `router.factory()` read live from `one.valve.city` on 2026-09-24.
|
|
@@ -85,7 +100,7 @@ export declare const uniV2Routers: Record<Chains, Hex[]>;
|
|
|
85
100
|
* salt collision) and worth this note so a future reader does not assume a
|
|
86
101
|
* transcription error and "fix" it back to something wrong.
|
|
87
102
|
*/
|
|
88
|
-
export declare const uniV2Factories: Record<Chains, Hex[]
|
|
103
|
+
export declare const uniV2Factories: Readonly<Record<Chains, readonly Hex[]>>;
|
|
89
104
|
/** A map of chains to native token symbols */
|
|
90
105
|
export declare const nativeTokenSymbol: Record<Chains, string>;
|
|
91
106
|
/** A map of chains to native token names */
|
package/dist/config.js
CHANGED
|
@@ -71,12 +71,13 @@ export const pulsechainTokenAddresses = Object.freeze({
|
|
|
71
71
|
export const deprecatedNativeAssetOut = {
|
|
72
72
|
[Chains.PLS]: new Set(['0x97Ac4a2439A47c07ad535bb1188c989dae755341']),
|
|
73
73
|
};
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Routers on chains where this package knows the router but has not verified
|
|
76
|
+
* a factory, so no {@link SwapVenue} can be built for them. They stay in
|
|
77
|
+
* {@link uniV2Routers} for the native-price reads (`chain-info.ts`,
|
|
78
|
+
* `readAmountOut`) that need only a router.
|
|
79
|
+
*/
|
|
80
|
+
const routersWithoutVenue = {
|
|
80
81
|
[Chains.ETH]: ['0x7a250d5630b4cf539739df2c5dacb4c659f2488d'],
|
|
81
82
|
[Chains.BNB]: ['0x05fF2B0DB69458A0750badebc4f9e13aDd608C7F'],
|
|
82
83
|
[Chains.SEP]: ['0xeE567Fe1712Faf6149d80dA1E6934E354124CfE3'],
|
|
@@ -85,6 +86,43 @@ export const uniV2Routers = {
|
|
|
85
86
|
'0x636f6407B90661b73b1C0F7e24F4C79f624d0738',
|
|
86
87
|
],
|
|
87
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* The swap venues the package ships with: PulseX V1 then V2 on PulseChain.
|
|
91
|
+
* Frozen. A caller who wants other routers passes its own
|
|
92
|
+
* {@link SwapVenues} (see `resolveSwapVenues`); this table is never mutated.
|
|
93
|
+
*
|
|
94
|
+
* Each factory is the router's own `router.factory()` read on chain — see
|
|
95
|
+
* {@link uniV2Factories}'s doc. The fee is 29 basis points for both
|
|
96
|
+
* deployments (measured, same doc).
|
|
97
|
+
*/
|
|
98
|
+
export const defaultSwapVenues = Object.freeze({
|
|
99
|
+
[Number(Chains.PLS)]: Object.freeze([
|
|
100
|
+
Object.freeze({
|
|
101
|
+
kind: 'uniswap-v2',
|
|
102
|
+
chainId: Number(Chains.PLS),
|
|
103
|
+
router: '0x98bf93ebf5c380C0e6Ae8e192A7e2AE08edAcc02',
|
|
104
|
+
factory: '0x1715a3E4A142d8b698131108995174F37aEBA10D',
|
|
105
|
+
feeBasisPoints: 29,
|
|
106
|
+
label: 'PulseX V1',
|
|
107
|
+
}),
|
|
108
|
+
Object.freeze({
|
|
109
|
+
kind: 'uniswap-v2',
|
|
110
|
+
chainId: Number(Chains.PLS),
|
|
111
|
+
router: '0x165C3410fC91EF562C50559f7d2289fEbed552d9',
|
|
112
|
+
factory: '0x29eA7545DEf87022BAdc76323F373EA1e707C523',
|
|
113
|
+
feeBasisPoints: 29,
|
|
114
|
+
label: 'PulseX V2',
|
|
115
|
+
}),
|
|
116
|
+
]),
|
|
117
|
+
});
|
|
118
|
+
/** One chain's routers: its default venues' routers, else the router-only entries. */
|
|
119
|
+
const defaultRoutersFor = (chain) => defaultSwapVenues[Number(chain)]?.map((venue) => venue.router) ?? routersWithoutVenue[chain] ?? [];
|
|
120
|
+
/**
|
|
121
|
+
* A map of chains to uni v2 router addresses. Frozen. PulseChain's entries
|
|
122
|
+
* derive from {@link defaultSwapVenues}, so the two cannot drift. Kept for
|
|
123
|
+
* compatibility; to swap on other routers pass `swapVenues` instead.
|
|
124
|
+
*/
|
|
125
|
+
export const uniV2Routers = Object.freeze(Object.fromEntries(Object.values(Chains).map((chain) => [chain, Object.freeze([...defaultRoutersFor(chain)])])));
|
|
88
126
|
/**
|
|
89
127
|
* Each {@link uniV2Routers} entry's OWN factory address, same index, same
|
|
90
128
|
* chain — `router.factory()` read live from `one.valve.city` on 2026-09-24.
|
|
@@ -109,16 +147,10 @@ export const uniV2Routers = {
|
|
|
109
147
|
* salt collision) and worth this note so a future reader does not assume a
|
|
110
148
|
* transcription error and "fix" it back to something wrong.
|
|
111
149
|
*/
|
|
112
|
-
export const uniV2Factories =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
],
|
|
117
|
-
[Chains.ETH]: [],
|
|
118
|
-
[Chains.BNB]: [],
|
|
119
|
-
[Chains.SEP]: [],
|
|
120
|
-
[Chains.V4PLS]: [],
|
|
121
|
-
};
|
|
150
|
+
export const uniV2Factories = Object.freeze(Object.fromEntries(Object.values(Chains).map((chain) => [
|
|
151
|
+
chain,
|
|
152
|
+
Object.freeze((defaultSwapVenues[Number(chain)] ?? []).map((venue) => venue.factory)),
|
|
153
|
+
])));
|
|
122
154
|
/** A map of chains to native token symbols */
|
|
123
155
|
export const nativeTokenSymbol = {
|
|
124
156
|
[Chains.PLS]: 'PLS',
|
|
@@ -1025,6 +1025,9 @@ export const parseLifiTokens = (payload, chainId) => {
|
|
|
1025
1025
|
// Preserve the inline spot price the LI.FI list carries — it is the USD
|
|
1026
1026
|
// price source for aggregator chains (the dapp image lists carry none).
|
|
1027
1027
|
priceUSD: typeof entry.priceUSD === 'string' ? entry.priceUSD : null,
|
|
1028
|
+
// Additive: kept only when LI.FI sends them, so a token without them has the same shape as before.
|
|
1029
|
+
...(typeof entry.coinKey === 'string' ? { coinKey: entry.coinKey } : {}),
|
|
1030
|
+
...(typeof entry.verificationStatus === 'string' ? { verificationStatus: entry.verificationStatus } : {}),
|
|
1028
1031
|
});
|
|
1029
1032
|
}
|
|
1030
1033
|
return parsed;
|
package/dist/execution.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Hex, type PublicClient } from 'viem';
|
|
2
2
|
import type { TokenBridgeInfo } from './chain-info.js';
|
|
3
|
+
import { type SwapVenues } from './swap-venues.js';
|
|
3
4
|
import { type AggregatorOriginRefusal, type ConsolidatedQuote, type ConsolidatedQuoteRequest } from './consolidated-quote.js';
|
|
4
5
|
import type { FeeType } from './fee-type.js';
|
|
5
6
|
import type { RouteCandidate } from './routing/candidate.js';
|
|
@@ -20,7 +21,7 @@ import type { BridgeKey, Token } from './types.js';
|
|
|
20
21
|
* EVERY SPENDER IS ONE THIS CODE ALREADY KNOWS. Approvals are for the exact
|
|
21
22
|
* amount spent, never unlimited, and go only to:
|
|
22
23
|
* - the omnibridge pathway's `from` mediator, read from `config.ts`;
|
|
23
|
-
* - the
|
|
24
|
+
* - the swap router the edge was quoted on, found in the swap venues (the defaults in `config.ts` unless the caller passes its own);
|
|
24
25
|
* - an aggregator spender that `aggregatorOriginCalls` checked against a
|
|
25
26
|
* fixed table for its provider and chain (LI.FI's Diamond, Relay's
|
|
26
27
|
* depository). A quote cannot name its own spender.
|
|
@@ -212,12 +213,15 @@ export type ExecutionPlan = {
|
|
|
212
213
|
* @param options.account - the account that signs every transaction
|
|
213
214
|
* @param options.legs - the legs, in the order the wallet signs them
|
|
214
215
|
* @param options.readAllowance - reads an allowance on chain; see {@link AllowanceReader}
|
|
216
|
+
* @param options.swapVenues - the routers swaps may sign on, merged over the defaults; a swap whose router is in none of them throws
|
|
215
217
|
* @returns the ordered transactions, or the first leg that cannot be planned
|
|
218
|
+
* @throws when a swap leg's router is not in the swap venues
|
|
216
219
|
*/
|
|
217
|
-
export declare const planExecution: ({ account, legs, readAllowance, }: {
|
|
220
|
+
export declare const planExecution: ({ account, legs, readAllowance, swapVenues, }: {
|
|
218
221
|
readonly account: Hex;
|
|
219
222
|
readonly legs: readonly ExecutionLeg[];
|
|
220
223
|
readonly readAllowance: AllowanceReader;
|
|
224
|
+
readonly swapVenues?: SwapVenues;
|
|
221
225
|
}) => Promise<ExecutionPlan>;
|
|
222
226
|
/**
|
|
223
227
|
* What the caller supplies for one signature section of a candidate. Each
|
|
@@ -270,6 +274,12 @@ export type CandidateExecutionInputs = {
|
|
|
270
274
|
readonly readAllowance: AllowanceReader;
|
|
271
275
|
/** The resolver the candidate was built with; turns a plan's graph node into its token. */
|
|
272
276
|
readonly resolveToken: ResolveNodeToken;
|
|
277
|
+
/**
|
|
278
|
+
* The routers swaps may sign on, merged over the defaults: a chain named
|
|
279
|
+
* here replaces that chain's default list. Pass the SAME venues the route
|
|
280
|
+
* search used. A swap whose router is in none of them throws.
|
|
281
|
+
*/
|
|
282
|
+
readonly swapVenues?: SwapVenues;
|
|
273
283
|
/**
|
|
274
284
|
* The index of the section that `sections[0]` plans. It defaults to 0.
|
|
275
285
|
* Pass it to plan a later section after the earlier ones landed, with the
|
|
@@ -337,10 +347,13 @@ export declare const planCandidateExecution: (inputs: CandidateExecutionInputs)
|
|
|
337
347
|
* @param options.hop - the swap hop; its recorded path and edge name what to read
|
|
338
348
|
* @param options.amountIn - the amount the swap spends, in base units
|
|
339
349
|
* @param options.client - a client that can call `readContract`
|
|
340
|
-
* @
|
|
350
|
+
* @param options.swapVenues - the routers swaps may sign on, merged over the defaults
|
|
351
|
+
* @returns the amount the last token of the path delivers, or null when the hop records no path, the amount is not positive, or the read fails or returns nothing
|
|
352
|
+
* @throws when the hop records a path but its router is not in the swap venues
|
|
341
353
|
*/
|
|
342
|
-
export declare const readPulseXSectionQuote: ({ hop, amountIn, client, }: {
|
|
354
|
+
export declare const readPulseXSectionQuote: ({ hop, amountIn, client, swapVenues, }: {
|
|
343
355
|
readonly hop: Pick<PlannedHop, "edge" | "outcome">;
|
|
344
356
|
readonly amountIn: bigint;
|
|
345
357
|
readonly client: Pick<PublicClient, "readContract">;
|
|
358
|
+
readonly swapVenues?: SwapVenues;
|
|
346
359
|
}) => Promise<bigint | null>;
|