@gibs/bridge-sdk 1.17.0 → 1.18.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 +52 -1
- package/dist/cjs/config.d.ts +18 -3
- package/dist/cjs/config.js +49 -17
- 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/prices.d.ts +10 -0
- package/dist/cjs/prices.js +54 -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 +6 -2
- package/dist/cjs/routing/index.js +9 -1
- 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 +30 -7
- 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/config.d.ts +18 -3
- package/dist/config.js +48 -16
- 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/prices.d.ts +10 -0
- package/dist/prices.js +52 -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 +6 -2
- package/dist/routing/index.js +3 -1
- 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 +30 -7
- 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/package.json +3 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as imageLinks from '../../image-links.js';
|
|
2
2
|
import { chainDisplayName } from '../../chain-names.js';
|
|
3
3
|
import { findProviderById } from '../../providers.js';
|
|
4
|
+
import { WRAP_CARRIER_ID, carrierProviderKey, carrierStepKind } from '../carrier-provider-key.js';
|
|
4
5
|
import { describeDeferredCrossing } from '../../near-intents-route.js';
|
|
5
6
|
import { candidateDeliveredUsd, candidateOutsideFeesUsd, candidatePaidUsd, pulsechainChainId, providerDisplayName, } from '../producers.js';
|
|
6
7
|
import { assetNodeKey, planComposedBasis, } from './graph.js';
|
|
@@ -229,6 +230,8 @@ const hopProviderName = (carrier) => {
|
|
|
229
230
|
return providerDisplayName(carrier);
|
|
230
231
|
if (carrier === 'PulseX')
|
|
231
232
|
return 'PulseX';
|
|
233
|
+
if (carrierStepKind(carrier) === 'wrap')
|
|
234
|
+
return 'Wrap';
|
|
232
235
|
// TOTAL OVER EVERY CARRIER. The engine plans hops for carriers the provider
|
|
233
236
|
// registry does not hold (a local wrap, a host's own plug-in). Casting such
|
|
234
237
|
// an id to a provider id and asking the throwing lookup crashed the whole
|
|
@@ -350,11 +353,13 @@ const hopIsAutomatic = (hopIndex, plan) => {
|
|
|
350
353
|
* @param plan - the plan the hop belongs to
|
|
351
354
|
* @param resolveToken - resolves a graph node to its full display token
|
|
352
355
|
* @param feeUsdValue - the hop's own share of its section's cost, or null
|
|
356
|
+
* @param gas - the hop's gas split, or null when the producer states none
|
|
353
357
|
* @returns the raw hop data
|
|
354
358
|
*/
|
|
355
|
-
const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue) => ({
|
|
359
|
+
const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue, gas) => ({
|
|
356
360
|
providerName: hopProviderName(hop.edge.carrier),
|
|
357
|
-
providerKey: hop.edge.carrier,
|
|
361
|
+
providerKey: carrierProviderKey(hop.edge.carrier),
|
|
362
|
+
stepKind: carrierStepKind(hop.edge.carrier),
|
|
358
363
|
title: hopTitle(hop, hopIndex, plan, resolveToken),
|
|
359
364
|
conversion: hopConversion(hop, hopIndex, plan, resolveToken),
|
|
360
365
|
fromToken: toRouteTokenRef(hop.edge.from, resolveToken),
|
|
@@ -362,6 +367,7 @@ const toRouteHopData = (hop, hopIndex, plan, resolveToken, feeUsdValue) => ({
|
|
|
362
367
|
// The per-hop dollar figure is a caller-supplied input (see this module's
|
|
363
368
|
// head doc); the caller passes it in, never derived here.
|
|
364
369
|
feeUsdValue,
|
|
370
|
+
...(gas === null ? {} : gas),
|
|
365
371
|
automatic: hopIsAutomatic(hopIndex, plan),
|
|
366
372
|
});
|
|
367
373
|
/**
|
|
@@ -502,8 +508,6 @@ export const derivePlanKind = (plan) => {
|
|
|
502
508
|
* @param carrier - the plan's headline carrier
|
|
503
509
|
* @returns the same value, typed as `ProviderKey`
|
|
504
510
|
*/
|
|
505
|
-
/** The carrier id of the native-coin wrap step (`routing/carriers/wrap.ts`). */
|
|
506
|
-
const WRAP_CARRIER = 'wrap';
|
|
507
511
|
const toHeadlineProviderKey = (carrier) => {
|
|
508
512
|
if (isBridgeCarrier(carrier))
|
|
509
513
|
return carrier;
|
|
@@ -535,7 +539,7 @@ export const deriveHeadlineProviderKeyFromPlan = (plan) => toHeadlineProviderKey
|
|
|
535
539
|
* @param plan - the plan to read
|
|
536
540
|
* @returns the carrier to headline
|
|
537
541
|
*/
|
|
538
|
-
const firstHeadlineCarrier = (plan) => plan.hops.find((hop) => hop.edge.carrier !==
|
|
542
|
+
const firstHeadlineCarrier = (plan) => plan.hops.find((hop) => hop.edge.carrier !== WRAP_CARRIER_ID)?.edge.carrier ?? 'PulseX';
|
|
539
543
|
/**
|
|
540
544
|
* The anchor a two-signature plan leaves the reader holding between its
|
|
541
545
|
* first and second groups — `RouteCandidate.plan`'s own TSDoc: "the anchor
|
|
@@ -654,10 +658,13 @@ export const buildRouteDataFromPlan = (inputs) => {
|
|
|
654
658
|
const landing = resolveNodeWithAssertedDecimals(lastHop.edge.to, resolveToken);
|
|
655
659
|
const landingIsUnpriced = hopOutcomeIsUnpriced(lastHop);
|
|
656
660
|
const hopFeeUsdValues = groupHopFeeUsdValues(pricing, group, groupIndex);
|
|
661
|
+
const statesGasSplit = pricing.feeExcludingGasUsdValue !== undefined;
|
|
662
|
+
const hopFeeExcludingGasUsdValues = pricing.hopFeeExcludingGasUsdValues;
|
|
657
663
|
return {
|
|
658
664
|
id: `${routeId}-signature-${groupIndex + 1}`,
|
|
659
665
|
label: sectionLabel(group, groupIndex, plan),
|
|
660
|
-
providerKey: hops[0].edge.carrier,
|
|
666
|
+
providerKey: carrierProviderKey(hops[0].edge.carrier),
|
|
667
|
+
stepKind: carrierStepKind(hops[0].edge.carrier),
|
|
661
668
|
tokenFlow: buildGroupTokenFlow(hops, resolveToken),
|
|
662
669
|
landing: {
|
|
663
670
|
amount: sectionLandingAmount(pricing, lastHop),
|
|
@@ -667,10 +674,19 @@ export const buildRouteDataFromPlan = (inputs) => {
|
|
|
667
674
|
estimateBasis: hopEstimateBasis(lastHop),
|
|
668
675
|
},
|
|
669
676
|
feeUsdValue: pricing.feeUsdValue,
|
|
677
|
+
...(statesGasSplit
|
|
678
|
+
? { feeExcludingGasUsdValue: pricing.feeExcludingGasUsdValue, gasUsdValue: pricing.gasUsdValue ?? null }
|
|
679
|
+
: {}),
|
|
670
680
|
fees: pricing.fees ? [...pricing.fees] : undefined,
|
|
671
681
|
etaMinutes: pricing.etaMinutes,
|
|
672
682
|
etaSeconds: pricing.etaSeconds,
|
|
673
|
-
hops: group.map((hopIndex, positionInGroup) => toRouteHopData(plan.hops[hopIndex], hopIndex, plan, resolveToken, hopFeeUsdValues[positionInGroup] ?? null
|
|
683
|
+
hops: group.map((hopIndex, positionInGroup) => toRouteHopData(plan.hops[hopIndex], hopIndex, plan, resolveToken, hopFeeUsdValues[positionInGroup] ?? null, statesGasSplit
|
|
684
|
+
? {
|
|
685
|
+
feeExcludingGasUsdValue: hopFeeExcludingGasUsdValues?.[positionInGroup] ??
|
|
686
|
+
(group.length === 1 ? (pricing.feeExcludingGasUsdValue ?? null) : null),
|
|
687
|
+
gasUsdValue: positionInGroup === 0 ? (pricing.gasUsdValue ?? null) : null,
|
|
688
|
+
}
|
|
689
|
+
: null)),
|
|
674
690
|
deferred: groupIndex > 0 ? true : undefined,
|
|
675
691
|
deferredNote: pricing.deferredNote,
|
|
676
692
|
};
|
|
@@ -689,6 +705,13 @@ export const buildRouteDataFromPlan = (inputs) => {
|
|
|
689
705
|
estimateBasis: lastSection.landing?.estimateBasis ?? null,
|
|
690
706
|
},
|
|
691
707
|
totalCostUsdValue,
|
|
708
|
+
...(inputs.costExcludingGasUsdValue === undefined
|
|
709
|
+
? {}
|
|
710
|
+
: {
|
|
711
|
+
costExcludingGasUsdValue: inputs.costExcludingGasUsdValue,
|
|
712
|
+
gasCostUsdValue: inputs.gasCostUsdValue ?? null,
|
|
713
|
+
gasByChain: [...(inputs.gasByChain ?? [])],
|
|
714
|
+
}),
|
|
692
715
|
netValueUsd,
|
|
693
716
|
etaMinutes,
|
|
694
717
|
// 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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { encodeFunctionData, isAddressEqual, parseAbi, zeroAddress } from 'viem';
|
|
2
2
|
import { pulseXSwapTransactionInputs } from '../settings.js';
|
|
3
|
-
import {
|
|
3
|
+
import { defaultSwapVenues } from '../config.js';
|
|
4
|
+
import { pulseXSwapPathForHop, venueForEdge } from './carriers/pulsex.js';
|
|
4
5
|
/**
|
|
5
6
|
* The minimal WETH9-style wrap/unwrap interface: `deposit()` mints the
|
|
6
7
|
* wrapped token for the native coin sent with the call, `withdraw(uint256)`
|
|
@@ -29,7 +30,7 @@ const wrapAbi = parseAbi(['function deposit() payable', 'function withdraw(uint2
|
|
|
29
30
|
* looking at) and the native-in/native-out/token-token branching.
|
|
30
31
|
*
|
|
31
32
|
* SIGNS ON THE EDGE'S OWN ROUTER. A PulseX edge names the deployment it was
|
|
32
|
-
* quoted on (`
|
|
33
|
+
* quoted on (`venueForEdge`: V1 or V2, each with its own pools). The
|
|
33
34
|
* caller's `routerAddress` must be that same router — it is also the router
|
|
34
35
|
* the caller approved to spend the input token — or nothing is built. A V2
|
|
35
36
|
* quote signed on V1 would trade against a different pool than the one the
|
|
@@ -37,8 +38,9 @@ const wrapAbi = parseAbi(['function deposit() payable', 'function withdraw(uint2
|
|
|
37
38
|
*
|
|
38
39
|
* @param options - the hop to swap, the amount and slippage-adjusted
|
|
39
40
|
* minimum, who receives the output, the signing deadline, what the caller
|
|
40
|
-
* believes this signature does (`signedLeg`), the chain it executes on,
|
|
41
|
-
* the
|
|
41
|
+
* believes this signature does (`signedLeg`), the chain it executes on, the
|
|
42
|
+
* resolved router address, and the swap venues the router must belong to
|
|
43
|
+
* (the defaults when omitted)
|
|
42
44
|
* @returns the swap transaction inputs, or null when the hop records no
|
|
43
45
|
* PulseX swap path, names no known router, `routerAddress` is not the
|
|
44
46
|
* edge's own router, the leg on screen disagrees, or any of
|
|
@@ -51,7 +53,7 @@ export const buildPulseXSwapTransaction = (options) => {
|
|
|
51
53
|
if (swapPath === null) {
|
|
52
54
|
return null;
|
|
53
55
|
}
|
|
54
|
-
const quotedRouter =
|
|
56
|
+
const quotedRouter = venueForEdge(options.venues ?? defaultSwapVenues, edge)?.router ?? null;
|
|
55
57
|
if (quotedRouter === null || routerAddress === null || !isAddressEqual(quotedRouter, routerAddress)) {
|
|
56
58
|
return null;
|
|
57
59
|
}
|
|
@@ -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,24 @@
|
|
|
1
|
+
import { defaultSwapVenues } from './config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Merges caller venues over {@link defaultSwapVenues}. A chain present in
|
|
4
|
+
* `overrides` replaces the default list for that chain. A chain absent from
|
|
5
|
+
* `overrides` keeps its default list. An empty list switches swaps off on
|
|
6
|
+
* that chain. Neither input is changed; the result is frozen.
|
|
7
|
+
*
|
|
8
|
+
* @param overrides - the caller's venues, or undefined for the defaults
|
|
9
|
+
* @returns the venues to use
|
|
10
|
+
*/
|
|
11
|
+
export const resolveSwapVenues = (overrides) => {
|
|
12
|
+
if (overrides === undefined)
|
|
13
|
+
return defaultSwapVenues;
|
|
14
|
+
return Object.freeze({ ...defaultSwapVenues, ...overrides });
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Finds the venue on a chain that has the given router.
|
|
18
|
+
*
|
|
19
|
+
* @param venues - the venues to search
|
|
20
|
+
* @param chainId - the numeric chain id
|
|
21
|
+
* @param router - the router address, in any letter case
|
|
22
|
+
* @returns the venue, or null when the chain has no venue with that router
|
|
23
|
+
*/
|
|
24
|
+
export const findSwapVenue = (venues, chainId, router) => venues[chainId]?.find((venue) => venue.router.toLowerCase() === router.toLowerCase()) ?? null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gibs/bridge-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Build and price cross-chain transfers between PulseChain, Ethereum, and Binance Smart Chain.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ethereum",
|
|
@@ -1007,8 +1007,8 @@
|
|
|
1007
1007
|
"test:live:near-intents": "../../scripts/near-intents-live.sh"
|
|
1008
1008
|
},
|
|
1009
1009
|
"dependencies": {
|
|
1010
|
-
"@gibs/abis": "^1.
|
|
1011
|
-
"@gibs/common": "^1.
|
|
1010
|
+
"@gibs/abis": "^1.18.0",
|
|
1011
|
+
"@gibs/common": "^1.18.0",
|
|
1012
1012
|
"@ton/core": "^0.63.1",
|
|
1013
1013
|
"@ton/crypto": "^3.3.0"
|
|
1014
1014
|
},
|