@gibs/bridge-sdk 1.13.1 → 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 +295 -18
- package/abis/package.json +6 -0
- package/bridge-limits/package.json +6 -0
- package/chain-info/package.json +6 -0
- package/chain-names/package.json +6 -0
- package/chains/package.json +6 -0
- package/claims/package.json +6 -0
- package/config/package.json +6 -0
- package/consolidated-quote/package.json +6 -0
- package/destination-calldata/package.json +6 -0
- package/dist/chain-info.d.ts +1 -1
- package/dist/chain-info.js +11 -12
- package/dist/chains.d.ts +25 -0
- package/dist/chains.js +55 -20
- package/dist/cjs/abis.d.ts +1 -0
- package/dist/cjs/abis.js +19 -0
- package/dist/cjs/bridge-limits.d.ts +103 -0
- package/dist/cjs/bridge-limits.js +89 -0
- package/dist/cjs/chain-info.d.ts +169 -0
- package/dist/cjs/chain-info.js +452 -0
- package/dist/cjs/chain-names.d.ts +160 -0
- package/dist/cjs/chain-names.js +207 -0
- package/dist/cjs/chains.d.ts +90 -0
- package/dist/cjs/chains.js +357 -0
- package/dist/cjs/claims.d.ts +198 -0
- package/dist/cjs/claims.js +182 -0
- package/dist/cjs/config.d.ts +255 -0
- package/dist/cjs/config.js +569 -0
- package/dist/cjs/consolidated-quote.d.ts +648 -0
- package/dist/cjs/consolidated-quote.js +1048 -0
- package/dist/cjs/destination-calldata.d.ts +118 -0
- package/dist/cjs/destination-calldata.js +156 -0
- package/dist/cjs/ecosystems.d.ts +217 -0
- package/dist/cjs/ecosystems.js +298 -0
- package/dist/cjs/execution.d.ts +359 -0
- package/dist/cjs/execution.js +495 -0
- package/dist/cjs/fee-type.d.ts +10 -0
- package/dist/cjs/fee-type.js +10 -0
- package/dist/cjs/hyperliquid-execution.d.ts +152 -0
- package/dist/cjs/hyperliquid-execution.js +175 -0
- package/dist/cjs/image-links.d.ts +117 -0
- package/dist/cjs/image-links.js +153 -0
- package/dist/cjs/index.d.ts +24 -0
- package/dist/cjs/index.js +40 -0
- package/dist/cjs/lifi-execution-guard.d.ts +210 -0
- package/dist/cjs/lifi-execution-guard.js +409 -0
- package/dist/cjs/near-intents-conformance.d.ts +85 -0
- package/dist/cjs/near-intents-conformance.js +337 -0
- package/dist/cjs/near-intents-route.d.ts +47 -0
- package/dist/cjs/near-intents-route.js +303 -0
- package/dist/cjs/near-intents.d.ts +524 -0
- package/dist/cjs/near-intents.js +1071 -0
- package/dist/cjs/origin-deposit.d.ts +326 -0
- package/dist/cjs/origin-deposit.js +82 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/pre-quote.d.ts +198 -0
- package/dist/cjs/pre-quote.js +180 -0
- package/dist/cjs/prices.d.ts +117 -0
- package/dist/cjs/prices.js +224 -0
- package/dist/cjs/providers.d.ts +238 -0
- package/dist/cjs/providers.js +171 -0
- package/dist/cjs/quote-fees.d.ts +102 -0
- package/dist/cjs/quote-fees.js +201 -0
- package/dist/cjs/referral.d.ts +85 -0
- package/dist/cjs/referral.js +85 -0
- package/dist/cjs/relay-currencies.d.ts +47 -0
- package/dist/cjs/relay-currencies.js +95 -0
- package/dist/cjs/relay-depository.d.ts +2 -0
- package/dist/cjs/relay-depository.js +85 -0
- package/dist/cjs/relay-quote.d.ts +301 -0
- package/dist/cjs/relay-quote.js +996 -0
- package/dist/cjs/route-steps.d.ts +138 -0
- package/dist/cjs/route-steps.js +310 -0
- package/dist/cjs/routing/amounts.d.ts +80 -0
- package/dist/cjs/routing/amounts.js +126 -0
- package/dist/cjs/routing/candidate-route.d.ts +43 -0
- package/dist/cjs/routing/candidate-route.js +50 -0
- package/dist/cjs/routing/candidate.d.ts +237 -0
- package/dist/cjs/routing/candidate.js +100 -0
- 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/ask-answer.d.ts +77 -0
- package/dist/cjs/routing/carriers/ask-answer.js +2 -0
- package/dist/cjs/routing/carriers/omnibridge.d.ts +137 -0
- package/dist/cjs/routing/carriers/omnibridge.js +459 -0
- package/dist/cjs/routing/carriers/pulsex-paths.d.ts +80 -0
- package/dist/cjs/routing/carriers/pulsex-paths.js +97 -0
- package/dist/cjs/routing/carriers/pulsex-split.d.ts +175 -0
- package/dist/cjs/routing/carriers/pulsex-split.js +193 -0
- package/dist/cjs/routing/carriers/pulsex.d.ts +184 -0
- package/dist/cjs/routing/carriers/pulsex.js +615 -0
- package/dist/cjs/routing/carriers/wrap.d.ts +25 -0
- package/dist/cjs/routing/carriers/wrap.js +119 -0
- package/dist/cjs/routing/composed-route-quality.d.ts +125 -0
- package/dist/cjs/routing/composed-route-quality.js +144 -0
- package/dist/cjs/routing/entry-chain-anchor.d.ts +88 -0
- package/dist/cjs/routing/entry-chain-anchor.js +59 -0
- package/dist/cjs/routing/format.d.ts +31 -0
- package/dist/cjs/routing/format.js +64 -0
- package/dist/cjs/routing/index.d.ts +42 -0
- package/dist/cjs/routing/index.js +142 -0
- package/dist/cjs/routing/producers.d.ts +770 -0
- package/dist/cjs/routing/producers.js +1617 -0
- package/dist/cjs/routing/providers.d.ts +31 -0
- package/dist/cjs/routing/providers.js +48 -0
- package/dist/cjs/routing/route-data.d.ts +397 -0
- package/dist/cjs/routing/route-data.js +2 -0
- package/dist/cjs/routing/search/compose.d.ts +168 -0
- package/dist/cjs/routing/search/compose.js +104 -0
- package/dist/cjs/routing/search/graph.d.ts +668 -0
- package/dist/cjs/routing/search/graph.js +461 -0
- package/dist/cjs/routing/search/plan-route-data.d.ts +285 -0
- package/dist/cjs/routing/search/plan-route-data.js +871 -0
- package/dist/cjs/routing/search/score.d.ts +356 -0
- package/dist/cjs/routing/search/score.js +445 -0
- package/dist/cjs/routing/swap-transactions.d.ts +95 -0
- package/dist/cjs/routing/swap-transactions.js +133 -0
- package/dist/cjs/routing/usd-value.d.ts +17 -0
- package/dist/cjs/routing/usd-value.js +29 -0
- package/dist/cjs/settings.d.ts +785 -0
- package/dist/cjs/settings.js +1074 -0
- package/dist/cjs/swap-venues.d.ts +43 -0
- package/dist/cjs/swap-venues.js +29 -0
- package/dist/cjs/ton-connect.d.ts +98 -0
- package/dist/cjs/ton-connect.js +206 -0
- package/dist/cjs/ton-execution.d.ts +7 -0
- package/dist/cjs/ton-execution.js +23 -0
- package/dist/cjs/ton.d.ts +37 -0
- package/dist/cjs/ton.js +83 -0
- package/dist/cjs/tron-execution.d.ts +146 -0
- package/dist/cjs/tron-execution.js +248 -0
- package/dist/cjs/types.d.ts +51 -0
- package/dist/cjs/types.js +2 -0
- package/dist/claims.d.ts +198 -0
- package/dist/claims.js +140 -0
- package/dist/config.d.ts +42 -3
- package/dist/config.js +87 -21
- package/dist/consolidated-quote.d.ts +109 -15
- package/dist/consolidated-quote.js +310 -52
- package/dist/execution.d.ts +359 -0
- package/dist/execution.js +455 -0
- package/dist/hyperliquid-execution.js +2 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/lifi-execution-guard.d.ts +13 -2
- package/dist/lifi-execution-guard.js +4 -0
- package/dist/near-intents.js +2 -3
- package/dist/pre-quote.d.ts +6 -6
- package/dist/pre-quote.js +10 -14
- package/dist/prices.d.ts +10 -0
- package/dist/prices.js +52 -1
- package/dist/providers.d.ts +17 -0
- package/dist/providers.js +6 -0
- package/dist/referral.d.ts +12 -4
- package/dist/referral.js +12 -4
- package/dist/relay-depository.d.ts +2 -0
- package/dist/relay-depository.js +82 -0
- package/dist/relay-quote.js +2 -3
- package/dist/routing/candidate.d.ts +3 -3
- package/dist/routing/candidate.js +3 -3
- package/dist/routing/carrier-provider-key.d.ts +31 -0
- package/dist/routing/carrier-provider-key.js +37 -0
- package/dist/routing/carriers/ask-answer.d.ts +17 -0
- package/dist/routing/carriers/omnibridge.js +23 -21
- package/dist/routing/carriers/pulsex-paths.d.ts +80 -0
- package/dist/routing/carriers/pulsex-paths.js +92 -0
- package/dist/routing/carriers/pulsex-split.d.ts +175 -0
- package/dist/routing/carriers/pulsex-split.js +185 -0
- package/dist/routing/carriers/pulsex.d.ts +81 -46
- package/dist/routing/carriers/pulsex.js +267 -148
- package/dist/routing/composed-route-quality.d.ts +28 -6
- package/dist/routing/composed-route-quality.js +36 -5
- package/dist/routing/entry-chain-anchor.d.ts +1 -1
- package/dist/routing/entry-chain-anchor.js +1 -1
- package/dist/routing/index.d.ts +11 -3
- package/dist/routing/index.js +8 -2
- package/dist/routing/producers.js +1 -1
- package/dist/routing/providers.d.ts +5 -0
- package/dist/routing/providers.js +5 -0
- package/dist/routing/route-data.d.ts +47 -5
- package/dist/routing/search/graph.d.ts +15 -0
- package/dist/routing/search/plan-route-data.d.ts +42 -1
- package/dist/routing/search/plan-route-data.js +68 -9
- package/dist/routing/search/score.d.ts +3 -0
- package/dist/routing/search/score.js +11 -3
- package/dist/routing/swap-transactions.d.ts +95 -0
- package/dist/routing/swap-transactions.js +127 -0
- package/dist/settings.d.ts +94 -1
- package/dist/settings.js +95 -3
- package/dist/swap-venues.d.ts +43 -0
- package/dist/swap-venues.js +24 -0
- package/dist/ton-connect.d.ts +98 -0
- package/dist/ton-connect.js +200 -0
- package/dist/ton-execution.d.ts +4 -114
- package/dist/ton-execution.js +4 -244
- package/dist/ton.d.ts +37 -0
- package/dist/ton.js +65 -0
- package/docs/examples/example-a-ether-to-pulse.ts +300 -0
- package/docs/examples/example-b-token-pulsechain-to-ethereum.ts +270 -0
- package/docs/examples/shared.ts +261 -0
- package/docs/examples/tsconfig.json +18 -0
- package/docs/integration-guide.md +617 -0
- package/ecosystems/package.json +6 -0
- package/execution/package.json +6 -0
- package/fee-type/package.json +6 -0
- package/hyperliquid-execution/package.json +6 -0
- package/image-links/package.json +6 -0
- package/lifi-execution-guard/package.json +6 -0
- package/llms.txt +75 -10
- package/near-intents/package.json +6 -0
- package/near-intents-route/package.json +6 -0
- package/origin-deposit/package.json +6 -0
- package/package.json +817 -10
- package/pre-quote/package.json +6 -0
- package/prices/package.json +6 -0
- package/providers/package.json +6 -0
- package/quote-fees/package.json +6 -0
- package/referral/package.json +6 -0
- package/relay-currencies/package.json +6 -0
- package/relay-quote/package.json +6 -0
- package/route-steps/package.json +6 -0
- package/routing/package.json +6 -0
- package/settings/package.json +6 -0
- package/ton/package.json +6 -0
- package/ton-connect/package.json +6 -0
- package/ton-execution/package.json +6 -0
- package/tron-execution/package.json +6 -0
- package/types/package.json +6 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { zeroAddress } from 'viem';
|
|
2
|
+
import * as abis from './abis.js';
|
|
3
|
+
import { Providers, toChain } from './config.js';
|
|
4
|
+
import { resolveSwapVenues } from './swap-venues.js';
|
|
5
|
+
import { aggregatorOriginCalls, } from './consolidated-quote.js';
|
|
6
|
+
import { pulseXSwapPathForHop, venueForEdge } from './routing/carriers/pulsex.js';
|
|
7
|
+
import { buildPulseXSwapTransaction, buildWrapTransaction, swapMinimumOut } from './routing/swap-transactions.js';
|
|
8
|
+
import { approvalAmounts, approveCall, bridgePathway, destinationDataParam, feeDirectorStructEncoded, feeTypeSettings, omnibridgeApproval, transactionInputs, } from './settings.js';
|
|
9
|
+
/**
|
|
10
|
+
* An {@link AllowanceReader} that reports no allowance anywhere, so the plan
|
|
11
|
+
* includes every approval. For a caller that reads allowances itself at send
|
|
12
|
+
* time.
|
|
13
|
+
*/
|
|
14
|
+
export const assumeNoAllowance = async () => 0n;
|
|
15
|
+
const refusal = (value) => ({ kind: 'refused', refusal: value });
|
|
16
|
+
/** The fee director a delivery choice encodes, or null when the reader buys no delivery. */
|
|
17
|
+
const encodeDelivery = ({ leg, pathway, }) => {
|
|
18
|
+
const { delivery } = leg;
|
|
19
|
+
if (!delivery.shouldDeliver)
|
|
20
|
+
return { kind: 'encoded', feeDirector: null };
|
|
21
|
+
if (!pathway.requiresDelivery)
|
|
22
|
+
return refusal({ reason: 'delivery-not-offered' });
|
|
23
|
+
// A zero fee pays no relayer, so the transfer would wait for a delivery that never comes.
|
|
24
|
+
if (delivery.fee.maximumFee <= 0n)
|
|
25
|
+
return refusal({ reason: 'delivery-fee-missing' });
|
|
26
|
+
const feeDirector = feeDirectorStructEncoded({
|
|
27
|
+
recipient: leg.recipient,
|
|
28
|
+
bridgePathway: pathway,
|
|
29
|
+
feeType: delivery.fee.feeType,
|
|
30
|
+
priceCorrective: delivery.fee.priceCorrective,
|
|
31
|
+
gasTipFee: delivery.fee.gasTipFee,
|
|
32
|
+
percentFee: delivery.fee.percentFee,
|
|
33
|
+
feeTypeSettings: feeTypeSettings({ feeType: delivery.fee.feeType, unwrap: leg.unwrap }),
|
|
34
|
+
limit: delivery.fee.maximumFee,
|
|
35
|
+
assetOut: delivery.fee.assetOut,
|
|
36
|
+
});
|
|
37
|
+
if (feeDirector === null)
|
|
38
|
+
return refusal({ reason: 'delivery-fee-unencodable' });
|
|
39
|
+
return { kind: 'encoded', feeDirector };
|
|
40
|
+
};
|
|
41
|
+
const deliveryTermsOf = (delivery) => {
|
|
42
|
+
if (!delivery.shouldDeliver)
|
|
43
|
+
return { status: 'not-requested' };
|
|
44
|
+
return {
|
|
45
|
+
status: 'requested',
|
|
46
|
+
feeType: delivery.fee.feeType,
|
|
47
|
+
maximumFee: delivery.fee.maximumFee,
|
|
48
|
+
feeToken: delivery.fee.assetOut,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
const omnibridgeCalls = (leg, account) => {
|
|
52
|
+
if (leg.amountIn <= 0n)
|
|
53
|
+
return refusal({ reason: 'amount-not-positive' });
|
|
54
|
+
const pathway = bridgePathway({ bridgeKey: leg.bridgeKey, isProd: leg.isProd, assetIn: leg.assetIn });
|
|
55
|
+
if (pathway === null)
|
|
56
|
+
return refusal({ reason: 'no-pathway' });
|
|
57
|
+
const encoded = encodeDelivery({ leg, pathway });
|
|
58
|
+
if (encoded.kind !== 'encoded')
|
|
59
|
+
return encoded;
|
|
60
|
+
const { feeDirector } = encoded;
|
|
61
|
+
const dataParam = destinationDataParam({
|
|
62
|
+
recipient: leg.recipient,
|
|
63
|
+
bridgePathway: pathway,
|
|
64
|
+
assetIn: leg.assetIn,
|
|
65
|
+
destinationRouter: pathway.destinationRouter,
|
|
66
|
+
feeDirectorStructEncoded: feeDirector,
|
|
67
|
+
assetLink: leg.assetLink,
|
|
68
|
+
shouldDeliver: leg.delivery.shouldDeliver,
|
|
69
|
+
unwrap: leg.unwrap,
|
|
70
|
+
});
|
|
71
|
+
const call = transactionInputs({
|
|
72
|
+
bridgeKey: leg.bridgeKey,
|
|
73
|
+
signedCrossing: { originChainId: Number(leg.bridgeKey[1]), destinationChainId: Number(leg.bridgeKey[2]) },
|
|
74
|
+
bridgePathway: pathway,
|
|
75
|
+
assetIn: leg.assetIn,
|
|
76
|
+
recipient: leg.recipient,
|
|
77
|
+
account,
|
|
78
|
+
assetLink: leg.assetLink,
|
|
79
|
+
destinationDataParam: dataParam,
|
|
80
|
+
amountToBridge: leg.amountIn,
|
|
81
|
+
feeDirectorStructEncoded: feeDirector,
|
|
82
|
+
shouldDeliver: leg.delivery.shouldDeliver,
|
|
83
|
+
});
|
|
84
|
+
if (call === null)
|
|
85
|
+
return refusal({ reason: 'bridge-call-refused' });
|
|
86
|
+
return {
|
|
87
|
+
kind: 'calls',
|
|
88
|
+
approval: omnibridgeApproval({
|
|
89
|
+
bridgePathway: pathway,
|
|
90
|
+
assetIn: leg.assetIn,
|
|
91
|
+
assetLink: leg.assetLink,
|
|
92
|
+
amountToBridge: leg.amountIn,
|
|
93
|
+
}),
|
|
94
|
+
action: { chainId: Number(leg.bridgeKey[1]), kind: 'bridge', ...call, gasLimit: null },
|
|
95
|
+
delivery: deliveryTermsOf(leg.delivery),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* The venue a swap edge was priced on, from the venues execution was given.
|
|
100
|
+
* A router that is not in those venues THROWS: signing on another router, on
|
|
101
|
+
* PulseX most of all, would trade against pools the reader was never shown.
|
|
102
|
+
*
|
|
103
|
+
* @param venues - the venues passed to execution
|
|
104
|
+
* @param edge - the swap edge
|
|
105
|
+
* @returns the venue
|
|
106
|
+
* @throws when the edge's router is not in `venues`, or its chain has no venue
|
|
107
|
+
*/
|
|
108
|
+
const requireSwapVenue = (venues, edge) => {
|
|
109
|
+
const venue = venueForEdge(venues, edge);
|
|
110
|
+
if (venue !== null)
|
|
111
|
+
return venue;
|
|
112
|
+
const router = edge.venue ?? 'the default router';
|
|
113
|
+
throw new Error(`The swap was priced on ${router} on chain ${edge.from.chainId}, but that router is not in the swap venues passed to execution. ` +
|
|
114
|
+
'Pass the same swapVenues the route search used.');
|
|
115
|
+
};
|
|
116
|
+
const pulseXSwapCalls = (leg, venues) => {
|
|
117
|
+
const { edge } = leg.hop;
|
|
118
|
+
const chainId = edge.from.chainId;
|
|
119
|
+
if (edge.carrier !== 'PulseX')
|
|
120
|
+
return refusal({ reason: 'swap-refused' });
|
|
121
|
+
const routerAddress = requireSwapVenue(venues, edge).router;
|
|
122
|
+
// The builder refuses a hop that records no priced path, a router other
|
|
123
|
+
// than the edge's own, and a leg on screen that disagrees.
|
|
124
|
+
const call = buildPulseXSwapTransaction({
|
|
125
|
+
hop: leg.hop,
|
|
126
|
+
amountIn: leg.amountIn,
|
|
127
|
+
minAmountOut: leg.minAmountOut,
|
|
128
|
+
recipient: leg.recipient,
|
|
129
|
+
deadline: leg.deadline,
|
|
130
|
+
signedLeg: { kind: 'swap', chainId },
|
|
131
|
+
chainId,
|
|
132
|
+
routerAddress,
|
|
133
|
+
venues,
|
|
134
|
+
});
|
|
135
|
+
if (call === null)
|
|
136
|
+
return refusal({ reason: 'swap-refused' });
|
|
137
|
+
const spendsNative = edge.from.address.toLowerCase() === zeroAddress;
|
|
138
|
+
return {
|
|
139
|
+
kind: 'calls',
|
|
140
|
+
approval: spendsNative
|
|
141
|
+
? null
|
|
142
|
+
: { chainId, token: edge.from.address, spender: routerAddress, minimum: leg.amountIn },
|
|
143
|
+
action: { chainId, kind: 'swap', ...call, gasLimit: null },
|
|
144
|
+
delivery: null,
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
const wrapCalls = (leg) => {
|
|
148
|
+
const call = buildWrapTransaction({ edge: leg.edge, amountIn: leg.amountIn });
|
|
149
|
+
if (call === null)
|
|
150
|
+
return refusal({ reason: 'wrap-refused' });
|
|
151
|
+
const wraps = leg.edge.from.address.toLowerCase() === zeroAddress;
|
|
152
|
+
return {
|
|
153
|
+
kind: 'calls',
|
|
154
|
+
approval: null,
|
|
155
|
+
action: { chainId: leg.edge.from.chainId, kind: wraps ? 'wrap' : 'unwrap', ...call, gasLimit: null },
|
|
156
|
+
delivery: null,
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
const aggregatorCalls = (leg) => {
|
|
160
|
+
const origin = aggregatorOriginCalls({ quote: leg.quote, request: leg.request });
|
|
161
|
+
if (origin.kind === 'refused')
|
|
162
|
+
return refusal({ reason: 'aggregator-origin-refused', origin: origin.refusal });
|
|
163
|
+
const { approval, deposit } = origin;
|
|
164
|
+
const staysOnChain = leg.request.toChainId === leg.request.fromChainId;
|
|
165
|
+
return {
|
|
166
|
+
kind: 'calls',
|
|
167
|
+
approval,
|
|
168
|
+
action: {
|
|
169
|
+
chainId: leg.request.fromChainId,
|
|
170
|
+
kind: staysOnChain ? 'swap' : 'bridge',
|
|
171
|
+
to: deposit.to,
|
|
172
|
+
data: deposit.data,
|
|
173
|
+
value: deposit.value,
|
|
174
|
+
gasLimit: deposit.gasLimit,
|
|
175
|
+
},
|
|
176
|
+
delivery: null,
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
const legCalls = (leg, account, venues) => {
|
|
180
|
+
if (leg.kind === 'omnibridge')
|
|
181
|
+
return omnibridgeCalls(leg, account);
|
|
182
|
+
if (leg.kind === 'pulsex-swap')
|
|
183
|
+
return pulseXSwapCalls(leg, venues);
|
|
184
|
+
if (leg.kind === 'wrap')
|
|
185
|
+
return wrapCalls(leg);
|
|
186
|
+
return aggregatorCalls(leg);
|
|
187
|
+
};
|
|
188
|
+
/** The approve transactions an approval needs now: none when the allowance on chain covers it. */
|
|
189
|
+
const approvalTransactions = async ({ approval, account, readAllowance, }) => {
|
|
190
|
+
const allowance = await readAllowance(approval.chainId, approval.token, account, approval.spender);
|
|
191
|
+
return approvalAmounts({ allowance, minimum: approval.minimum }).map((amount) => ({
|
|
192
|
+
chainId: approval.chainId,
|
|
193
|
+
kind: 'approve',
|
|
194
|
+
...approveCall({ token: approval.token, spender: approval.spender, amount }),
|
|
195
|
+
gasLimit: null,
|
|
196
|
+
}));
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Plans the transactions for a list of legs, in order.
|
|
200
|
+
*
|
|
201
|
+
* Each leg contributes the exact approval it needs when the allowance on
|
|
202
|
+
* chain does not cover it (a reset to zero first when a smaller allowance
|
|
203
|
+
* remains), then its own call. Nothing is sent.
|
|
204
|
+
*
|
|
205
|
+
* @param options.account - the account that signs every transaction
|
|
206
|
+
* @param options.legs - the legs, in the order the wallet signs them
|
|
207
|
+
* @param options.readAllowance - reads an allowance on chain; see {@link AllowanceReader}
|
|
208
|
+
* @param options.swapVenues - the routers swaps may sign on, merged over the defaults; a swap whose router is in none of them throws
|
|
209
|
+
* @returns the ordered transactions, or the first leg that cannot be planned
|
|
210
|
+
* @throws when a swap leg's router is not in the swap venues
|
|
211
|
+
*/
|
|
212
|
+
export const planExecution = async ({ account, legs, readAllowance, swapVenues, }) => {
|
|
213
|
+
const venues = resolveSwapVenues(swapVenues);
|
|
214
|
+
const calls = legs.map((leg) => legCalls(leg, account, venues));
|
|
215
|
+
const refusedIndex = calls.findIndex((entry) => entry.kind === 'refused');
|
|
216
|
+
const refused = calls[refusedIndex];
|
|
217
|
+
if (refused !== undefined && refused.kind === 'refused') {
|
|
218
|
+
return { kind: 'refused', legIndex: refusedIndex, refusal: refused.refusal };
|
|
219
|
+
}
|
|
220
|
+
const planned = calls.flatMap((entry) => (entry.kind === 'calls' ? [entry] : []));
|
|
221
|
+
const perLeg = await Promise.all(planned.map(async (entry) => {
|
|
222
|
+
const approvals = entry.approval === null
|
|
223
|
+
? []
|
|
224
|
+
: await approvalTransactions({ approval: entry.approval, account, readAllowance });
|
|
225
|
+
return [...approvals, entry.action];
|
|
226
|
+
}));
|
|
227
|
+
const ordered = perLeg.flat();
|
|
228
|
+
const transactions = ordered.map((action, index) => ({ ...action, waitForReceipt: index < ordered.length - 1 }));
|
|
229
|
+
const deliveries = planned.flatMap((entry, legIndex) => entry.delivery === null ? [] : [{ ...entry.delivery, legIndex }]);
|
|
230
|
+
return { kind: 'planned', transactions, deliveries };
|
|
231
|
+
};
|
|
232
|
+
const OMNIBRIDGE_CARRIERS = new Set(Object.values(Providers));
|
|
233
|
+
const isOmnibridgeCarrier = (carrier) => OMNIBRIDGE_CARRIERS.has(carrier);
|
|
234
|
+
const missing = (needs) => ({
|
|
235
|
+
kind: 'refused',
|
|
236
|
+
refusal: { reason: 'section-inputs-missing', needs },
|
|
237
|
+
});
|
|
238
|
+
const shape = (detail) => ({ kind: 'refused', refusal: { reason: 'section-shape', detail } });
|
|
239
|
+
const omnibridgeSectionLeg = ({ carrier, from, to, inputs, assetIn, }) => {
|
|
240
|
+
if (inputs.omnibridge === undefined)
|
|
241
|
+
return missing('omnibridge');
|
|
242
|
+
return {
|
|
243
|
+
kind: 'leg',
|
|
244
|
+
leg: {
|
|
245
|
+
kind: 'omnibridge',
|
|
246
|
+
bridgeKey: [carrier, toChain(from.chainId), toChain(to.chainId)],
|
|
247
|
+
isProd: inputs.omnibridge.isProd,
|
|
248
|
+
assetIn,
|
|
249
|
+
assetLink: inputs.omnibridge.assetLink,
|
|
250
|
+
amountIn: inputs.amountIn,
|
|
251
|
+
recipient: inputs.recipient,
|
|
252
|
+
delivery: inputs.omnibridge.delivery,
|
|
253
|
+
unwrap: inputs.omnibridge.unwrap,
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
const liveQuoteRequired = { kind: 'refused', refusal: { reason: 'live-quote-required' } };
|
|
258
|
+
const aggregatorSectionLeg = (carrier, inputs) => {
|
|
259
|
+
if (inputs.aggregator === undefined)
|
|
260
|
+
return liveQuoteRequired;
|
|
261
|
+
const { quote, request } = inputs.aggregator;
|
|
262
|
+
if (quote.provider !== carrier) {
|
|
263
|
+
return {
|
|
264
|
+
kind: 'refused',
|
|
265
|
+
refusal: { reason: 'quote-provider-mismatch', quoteProvider: quote.provider, sectionCarrier: carrier },
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return { kind: 'leg', leg: { kind: 'aggregator', quote, request } };
|
|
269
|
+
};
|
|
270
|
+
const pulseXSectionLeg = (hop, inputs) => {
|
|
271
|
+
if (inputs.swap === undefined)
|
|
272
|
+
return missing('swap');
|
|
273
|
+
const { quotedAmountOut } = inputs.swap;
|
|
274
|
+
if (quotedAmountOut !== undefined && quotedAmountOut <= 0n) {
|
|
275
|
+
return { kind: 'refused', refusal: { reason: 'swap-quote-not-positive' } };
|
|
276
|
+
}
|
|
277
|
+
// Without a fresh quote the floor comes from the hop's own figure, so it must be a real quote.
|
|
278
|
+
if (quotedAmountOut === undefined && hop.outcome.kind !== 'quote') {
|
|
279
|
+
return { kind: 'refused', refusal: { reason: 'swap-estimate-only' } };
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
kind: 'leg',
|
|
283
|
+
leg: {
|
|
284
|
+
kind: 'pulsex-swap',
|
|
285
|
+
hop,
|
|
286
|
+
amountIn: inputs.amountIn,
|
|
287
|
+
minAmountOut: swapMinimumOut({
|
|
288
|
+
quotedAmount: quotedAmountOut ?? hop.outcome.deliveredAmount,
|
|
289
|
+
slippageBasisPoints: inputs.swap.slippageBasisPoints,
|
|
290
|
+
}),
|
|
291
|
+
recipient: inputs.recipient,
|
|
292
|
+
deadline: inputs.swap.deadline,
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
/** Turns one section of an engine plan into its leg, dispatching on the first hop's carrier. */
|
|
297
|
+
const planSectionLeg = ({ hops, inputs, resolveToken, }) => {
|
|
298
|
+
const firstHop = hops[0];
|
|
299
|
+
if (firstHop === undefined)
|
|
300
|
+
return shape('the section has no hops');
|
|
301
|
+
const { carrier, origin, from, to } = firstHop.edge;
|
|
302
|
+
if (origin === 'by-hand')
|
|
303
|
+
return { kind: 'refused', refusal: { reason: 'paid-by-hand' } };
|
|
304
|
+
// An aggregator section may run several hops inside one signature (a fused
|
|
305
|
+
// omnibridge entry); every other carrier signs exactly one hop.
|
|
306
|
+
const singleHop = hops.length === 1;
|
|
307
|
+
if (isOmnibridgeCarrier(carrier)) {
|
|
308
|
+
if (!singleHop)
|
|
309
|
+
return shape('an omnibridge section is exactly one hop');
|
|
310
|
+
return omnibridgeSectionLeg({ carrier, from, to, inputs, assetIn: resolveToken(from) });
|
|
311
|
+
}
|
|
312
|
+
if (carrier === 'PulseX') {
|
|
313
|
+
if (!singleHop)
|
|
314
|
+
return shape('a swap section is exactly one hop');
|
|
315
|
+
return pulseXSectionLeg(firstHop, inputs);
|
|
316
|
+
}
|
|
317
|
+
if (carrier === 'wrap') {
|
|
318
|
+
if (!singleHop)
|
|
319
|
+
return shape('a wrap section is exactly one hop');
|
|
320
|
+
return { kind: 'leg', leg: { kind: 'wrap', edge: firstHop.edge, amountIn: inputs.amountIn } };
|
|
321
|
+
}
|
|
322
|
+
return aggregatorSectionLeg(carrier, inputs);
|
|
323
|
+
};
|
|
324
|
+
/** The sections of a plan, each as its hops. */
|
|
325
|
+
const planSections = (plan) => plan.signatures.map((group) => group.flatMap((hopIndex) => plan.hops[hopIndex] ?? []));
|
|
326
|
+
/**
|
|
327
|
+
* A candidate built without an engine plan is one signature: either a
|
|
328
|
+
* same-chain omnibridge crossing (`buildDirectCrossingCandidate`, whose quote
|
|
329
|
+
* names the bridge) or an aggregator quote.
|
|
330
|
+
*
|
|
331
|
+
* THE CANDIDATE'S OWN QUOTE IS NEVER SIGNED. It priced the route on screen
|
|
332
|
+
* and may be stale or a dry probe; only the live quote in
|
|
333
|
+
* `inputs.aggregator` is. Without one the section is refused with
|
|
334
|
+
* `live-quote-required`.
|
|
335
|
+
*/
|
|
336
|
+
const planlessSectionLeg = (candidate, inputs) => {
|
|
337
|
+
const provider = candidate.quote.provider;
|
|
338
|
+
if (isOmnibridgeCarrier(provider)) {
|
|
339
|
+
return omnibridgeSectionLeg({
|
|
340
|
+
carrier: provider,
|
|
341
|
+
from: candidate.originToken,
|
|
342
|
+
to: candidate.destinationToken,
|
|
343
|
+
inputs,
|
|
344
|
+
assetIn: candidate.originToken,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return aggregatorSectionLeg(provider, inputs);
|
|
348
|
+
};
|
|
349
|
+
/**
|
|
350
|
+
* What is wrong with the requested window of sections, or null when it fits.
|
|
351
|
+
* A window starts at `firstSectionIndex` and spans `plannedCount` sections.
|
|
352
|
+
*/
|
|
353
|
+
const sectionWindowProblem = ({ firstSectionIndex, plannedCount, sectionCount, }) => {
|
|
354
|
+
if (!Number.isSafeInteger(firstSectionIndex) || firstSectionIndex < 0) {
|
|
355
|
+
return `firstSectionIndex must be a non-negative safe integer, received ${firstSectionIndex}`;
|
|
356
|
+
}
|
|
357
|
+
if (plannedCount < 1)
|
|
358
|
+
return `pass at least 1 section input, received ${plannedCount}`;
|
|
359
|
+
if (firstSectionIndex + plannedCount > sectionCount) {
|
|
360
|
+
return `sections ${firstSectionIndex} to ${firstSectionIndex + plannedCount - 1} do not fit a route of ${sectionCount} section${sectionCount === 1 ? '' : 's'}`;
|
|
361
|
+
}
|
|
362
|
+
return null;
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* Plans the transactions for a chosen route candidate: the candidate
|
|
366
|
+
* `buildRouteCandidateFromPlan` returns for an engine plan (the interface's
|
|
367
|
+
* `buildCandidateFromEnginePlan`), or a candidate built without a plan.
|
|
368
|
+
*
|
|
369
|
+
* ONE SECTION IS ONE SIGNATURE. A plan's `signatures` groups its hops into
|
|
370
|
+
* sections; the section's first hop names its carrier. An omnibridge section
|
|
371
|
+
* becomes a crossing, a PulseX section a swap signed on its recorded path, a
|
|
372
|
+
* wrap section a wrap or unwrap, and any other wallet-signed carrier an
|
|
373
|
+
* aggregator deposit from the live quote the caller supplies. A section paid
|
|
374
|
+
* by hand has nothing to sign and is refused.
|
|
375
|
+
*
|
|
376
|
+
* A LATER SECTION CAN BE PLANNED ALONE. Pass `firstSectionIndex` to skip the
|
|
377
|
+
* sections that already landed. The wallet then plans the swap after the
|
|
378
|
+
* crossing arrived, from the amount that arrived, with a fresh
|
|
379
|
+
* `swap.quotedAmountOut` and a fresh `swap.deadline`. The slippage floor and the
|
|
380
|
+
* deadline are not fixed minutes before the swap is signed. Every safety check
|
|
381
|
+
* still applies to the later section: verified spenders, live quotes for
|
|
382
|
+
* aggregator sections, exact approvals.
|
|
383
|
+
*
|
|
384
|
+
* Every `sectionIndex` in a refusal and every `legIndex` in `deliveries` is
|
|
385
|
+
* the absolute section index.
|
|
386
|
+
*
|
|
387
|
+
* @param inputs - see {@link CandidateExecutionInputs}
|
|
388
|
+
* @returns the ordered transactions with the deliveries they buy, or the first section that cannot be planned
|
|
389
|
+
*/
|
|
390
|
+
export const planCandidateExecution = async (inputs) => {
|
|
391
|
+
const { candidate, account, readAllowance, resolveToken, sections, swapVenues } = inputs;
|
|
392
|
+
const firstSectionIndex = inputs.firstSectionIndex ?? 0;
|
|
393
|
+
const plan = candidate.plan;
|
|
394
|
+
const allSections = plan === undefined ? null : planSections(plan);
|
|
395
|
+
const sectionCount = allSections === null ? 1 : allSections.length;
|
|
396
|
+
const problem = sectionWindowProblem({ firstSectionIndex, plannedCount: sections.length, sectionCount });
|
|
397
|
+
if (problem !== null) {
|
|
398
|
+
const validIndex = Number.isSafeInteger(firstSectionIndex) && firstSectionIndex >= 0;
|
|
399
|
+
return {
|
|
400
|
+
kind: 'refused',
|
|
401
|
+
sectionIndex: validIndex ? firstSectionIndex : 0,
|
|
402
|
+
refusal: { reason: 'section-shape', detail: problem },
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const sectionLegs = sections.map((sectionInputs, index) => allSections === null
|
|
406
|
+
? planlessSectionLeg(candidate, sectionInputs)
|
|
407
|
+
: planSectionLeg({ hops: allSections[firstSectionIndex + index] ?? [], inputs: sectionInputs, resolveToken }));
|
|
408
|
+
const refusedIndex = sectionLegs.findIndex((entry) => entry.kind === 'refused');
|
|
409
|
+
const refused = sectionLegs[refusedIndex];
|
|
410
|
+
if (refused !== undefined && refused.kind === 'refused') {
|
|
411
|
+
return { kind: 'refused', sectionIndex: firstSectionIndex + refusedIndex, refusal: refused.refusal };
|
|
412
|
+
}
|
|
413
|
+
const legs = sectionLegs.flatMap((entry) => (entry.kind === 'leg' ? [entry.leg] : []));
|
|
414
|
+
const planned = await planExecution({ account, legs, readAllowance, ...(swapVenues === undefined ? {} : { swapVenues }) });
|
|
415
|
+
if (planned.kind === 'refused') {
|
|
416
|
+
return { kind: 'refused', sectionIndex: firstSectionIndex + planned.legIndex, refusal: planned.refusal };
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
kind: 'planned',
|
|
420
|
+
transactions: planned.transactions,
|
|
421
|
+
deliveries: planned.deliveries.map((delivery) => ({ ...delivery, legIndex: firstSectionIndex + delivery.legIndex })),
|
|
422
|
+
remainingSectionCount: sectionCount - firstSectionIndex - sections.length,
|
|
423
|
+
};
|
|
424
|
+
};
|
|
425
|
+
/**
|
|
426
|
+
* Reads a fresh quote for a PulseX section: what the router's `getAmountsOut`
|
|
427
|
+
* says the swap delivers for `amountIn`, along the exact path the swap signs
|
|
428
|
+
* ({@link pulseXSwapPathForHop}) on the edge's own router. A wallet passes the
|
|
429
|
+
* result as `swap.quotedAmountOut` just before it signs.
|
|
430
|
+
*
|
|
431
|
+
* @param options.hop - the swap hop; its recorded path and edge name what to read
|
|
432
|
+
* @param options.amountIn - the amount the swap spends, in base units
|
|
433
|
+
* @param options.client - a client that can call `readContract`
|
|
434
|
+
* @param options.swapVenues - the routers swaps may sign on, merged over the defaults
|
|
435
|
+
* @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
|
|
436
|
+
* @throws when the hop records a path but its router is not in the swap venues
|
|
437
|
+
*/
|
|
438
|
+
export const readPulseXSectionQuote = async ({ hop, amountIn, client, swapVenues, }) => {
|
|
439
|
+
const path = pulseXSwapPathForHop(hop);
|
|
440
|
+
if (path === null || amountIn <= 0n)
|
|
441
|
+
return null;
|
|
442
|
+
const router = requireSwapVenue(resolveSwapVenues(swapVenues), hop.edge).router;
|
|
443
|
+
try {
|
|
444
|
+
const amounts = await client.readContract({
|
|
445
|
+
address: router,
|
|
446
|
+
abi: abis.univ2Router,
|
|
447
|
+
functionName: 'getAmountsOut',
|
|
448
|
+
args: [amountIn, path],
|
|
449
|
+
});
|
|
450
|
+
return amounts.at(-1) ?? null;
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildUrl } from '@gibs/common/url';
|
|
1
2
|
import { parseSignature } from 'viem';
|
|
2
3
|
import { relayApiBaseUrl } from './relay-quote.js';
|
|
3
4
|
/**
|
|
@@ -158,10 +159,8 @@ export const buildHyperliquidAuthorizationRequest = ({ authorization, signature,
|
|
|
158
159
|
if (!endpoint.startsWith('/')) {
|
|
159
160
|
return null;
|
|
160
161
|
}
|
|
161
|
-
const url = new URL(`${baseUrl}${endpoint}`);
|
|
162
|
-
url.searchParams.set('signature', signature);
|
|
163
162
|
return {
|
|
164
|
-
url:
|
|
163
|
+
url: buildUrl(`${baseUrl}${endpoint}`, { signature }),
|
|
165
164
|
method,
|
|
166
165
|
body: { ...body, signatureChainId },
|
|
167
166
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -17,4 +17,8 @@ export * from './referral.js';
|
|
|
17
17
|
export * from './route-steps.js';
|
|
18
18
|
export * from './routing/index.js';
|
|
19
19
|
export * from './settings.js';
|
|
20
|
+
export * from './swap-venues.js';
|
|
20
21
|
export * from './types.js';
|
|
22
|
+
export * from './claims.js';
|
|
23
|
+
export * from './execution.js';
|
|
24
|
+
export * from './relay-depository.js';
|
package/dist/index.js
CHANGED
|
@@ -17,4 +17,8 @@ export * from './referral.js';
|
|
|
17
17
|
export * from './route-steps.js';
|
|
18
18
|
export * from './routing/index.js';
|
|
19
19
|
export * from './settings.js';
|
|
20
|
+
export * from './swap-venues.js';
|
|
20
21
|
export * from './types.js';
|
|
22
|
+
export * from './claims.js';
|
|
23
|
+
export * from './execution.js';
|
|
24
|
+
export * from './relay-depository.js';
|
|
@@ -77,12 +77,13 @@ import { type Hex } from 'viem';
|
|
|
77
77
|
* `receiver-mismatch`, `destination-chain-mismatch`, `sending-asset-mismatch`,
|
|
78
78
|
* `destination-call-flag-mismatch` and `minimum-amount-below-requested`
|
|
79
79
|
* distrust `data`'s DECODED fields against what this application asked for;
|
|
80
|
-
* `
|
|
80
|
+
* `origin-amount-mismatch` distrusts the decoded amount pulled from the
|
|
81
|
+
* depositor; `native-value-mismatch` distrusts `value`. `missing-request-context` is
|
|
81
82
|
* different in kind: it means the CALLER never supplied what this
|
|
82
83
|
* application expected, so none of the above could even be checked — see
|
|
83
84
|
* `parseLifiContractCallsQuote` and `parseLifiQuote` in `consolidated-quote.ts`.
|
|
84
85
|
*/
|
|
85
|
-
export type LifiExecutionRefusalReason = 'unknown-chain' | 'router-mismatch' | 'approval-address-mismatch' | 'unknown-selector' | 'calldata-undecodable' | 'receiver-mismatch' | 'destination-chain-mismatch' | 'sending-asset-mismatch' | 'destination-call-flag-mismatch' | 'minimum-amount-below-requested' | 'native-value-mismatch' | 'missing-request-context';
|
|
86
|
+
export type LifiExecutionRefusalReason = 'unknown-chain' | 'router-mismatch' | 'approval-address-mismatch' | 'unknown-selector' | 'calldata-undecodable' | 'receiver-mismatch' | 'destination-chain-mismatch' | 'sending-asset-mismatch' | 'destination-call-flag-mismatch' | 'minimum-amount-below-requested' | 'origin-amount-mismatch' | 'native-value-mismatch' | 'missing-request-context';
|
|
86
87
|
/** Why a LI.FI execution transaction was refused before signing. */
|
|
87
88
|
export type LifiExecutionRefusal = {
|
|
88
89
|
readonly reason: LifiExecutionRefusalReason;
|
|
@@ -174,6 +175,16 @@ export type LifiExecutionExpectation = {
|
|
|
174
175
|
* of constrained by the request. See `ConsolidatedQuote.toAmount`.
|
|
175
176
|
*/
|
|
176
177
|
readonly minimumAmount: bigint | null;
|
|
178
|
+
/**
|
|
179
|
+
* The exact amount of the origin token this application sends, in base units,
|
|
180
|
+
* or `null` when the request names none.
|
|
181
|
+
*
|
|
182
|
+
* Compared with the decoded `swapData[0].fromAmount`, the amount pulled from
|
|
183
|
+
* the depositor. Without it a response could keep every other field honest and
|
|
184
|
+
* still pull more than the reader chose. The request, never the response,
|
|
185
|
+
* supplies this figure.
|
|
186
|
+
*/
|
|
187
|
+
readonly originAmount: bigint | null;
|
|
177
188
|
};
|
|
178
189
|
/** The transaction fields {@link verifyLifiEvmExecution} reads off the raw response. */
|
|
179
190
|
export type LifiExecutionTransactionRequest = {
|
|
@@ -389,6 +389,10 @@ export const verifyLifiEvmExecution = (transactionRequest, approvalAddress, expe
|
|
|
389
389
|
return;
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
+
if (expectation.originAmount !== null && decoded.originAmount !== expectation.originAmount) {
|
|
393
|
+
refuse('origin-amount-mismatch', `decoded origin amount (${decoded.originAmount}) does not equal the amount to send (${expectation.originAmount})`);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
392
396
|
const nativeOriginComponent = sameAddress(decoded.originSendingAssetId, zeroAddress)
|
|
393
397
|
? decoded.originAmount
|
|
394
398
|
: 0n;
|
package/dist/near-intents.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildUrl } from '@gibs/common/url';
|
|
1
2
|
import { arbitrum, avalanche, base, bsc, gnosis, mainnet, optimism, polygon, scroll, } from 'viem/chains';
|
|
2
3
|
import { encodeFunctionData, erc20Abi, isAddress } from 'viem';
|
|
3
4
|
import { depositAddressChainIds, isDepositAddressChain, relayChainIds, } from './chain-names.js';
|
|
@@ -102,9 +103,7 @@ export const nearIntentsAuthenticatedStablecoinFeeBasisPoints = 1;
|
|
|
102
103
|
* @returns the fully-formed status address
|
|
103
104
|
*/
|
|
104
105
|
export const nearIntentsStatusUrl = ({ quoteId }) => {
|
|
105
|
-
|
|
106
|
-
url.searchParams.set('depositAddress', quoteId);
|
|
107
|
-
return url.toString();
|
|
106
|
+
return buildUrl(`${nearIntentsApiBaseUrl}/v0/status`, { depositAddress: quoteId });
|
|
108
107
|
};
|
|
109
108
|
/**
|
|
110
109
|
* What this repository calls itself when it asks the one-click service.
|
package/dist/pre-quote.d.ts
CHANGED
|
@@ -82,12 +82,12 @@ export type PreQuoteRequest = {
|
|
|
82
82
|
*/
|
|
83
83
|
relayReferrer?: string | null;
|
|
84
84
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
85
|
+
* The `integrator` sent to LI.FI. Left out or `null`, the query parameter is
|
|
86
|
+
* OMITTED entirely (it is optional per LI.FI's own `/v1/quote` schema —
|
|
87
|
+
* verified 2026-09-23 — and an empty string would be a literal empty
|
|
88
|
+
* integrator, not an absent one). A string is sent as-is. Gibs Finance's own
|
|
89
|
+
* label is `lifiIntegrator` in `consolidated-quote.ts`; it is never sent
|
|
90
|
+
* unless you pass it.
|
|
91
91
|
*/
|
|
92
92
|
lifiIntegrator?: string | null;
|
|
93
93
|
};
|
package/dist/pre-quote.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildQuery } from '@gibs/common/url';
|
|
2
|
+
import { isNonEthereumVirtualMachineOrigin, } from './consolidated-quote.js';
|
|
2
3
|
import { resolveAttribution } from './referral.js';
|
|
3
4
|
import { relayReferrerField, slippageToBasisPoints, } from './relay-quote.js';
|
|
4
5
|
/**
|
|
@@ -84,26 +85,21 @@ export const buildLifiPreQuoteRequest = (request) => {
|
|
|
84
85
|
if (isNonEthereumVirtualMachineOrigin(request)) {
|
|
85
86
|
return null;
|
|
86
87
|
}
|
|
87
|
-
|
|
88
|
+
// Left out or `null` OMITS the query parameter (LI.FI's own schema marks it
|
|
89
|
+
// optional); a string is sent as-is. No package default: attribution is the
|
|
90
|
+
// caller's to choose. See `PreQuoteRequest.lifiIntegrator`'s doc.
|
|
91
|
+
const integrator = resolveAttribution(request.lifiIntegrator, undefined);
|
|
92
|
+
return buildQuery({
|
|
88
93
|
fromChain: request.fromChainId.toString(),
|
|
89
94
|
toChain: request.toChainId.toString(),
|
|
90
95
|
fromToken: request.fromTokenAddress,
|
|
91
96
|
toToken: request.toTokenAddress,
|
|
92
97
|
fromAmount: request.amount.toString(),
|
|
93
98
|
fromAddress: request.fromAddress,
|
|
99
|
+
// Each optional parameter is left out when it is undefined.
|
|
100
|
+
integrator,
|
|
101
|
+
slippage: request.slippage?.toString(),
|
|
94
102
|
});
|
|
95
|
-
// `null` means "no integrator of this caller's own" and OMITS the query
|
|
96
|
-
// parameter (LI.FI's own schema marks it optional); `undefined` means
|
|
97
|
-
// "this repository's own default"; a string is sent as-is. See
|
|
98
|
-
// `PreQuoteRequest.lifiIntegrator`'s doc.
|
|
99
|
-
const integrator = resolveAttribution(request.lifiIntegrator, lifiIntegrator);
|
|
100
|
-
if (integrator !== undefined) {
|
|
101
|
-
params.set('integrator', integrator);
|
|
102
|
-
}
|
|
103
|
-
if (request.slippage !== undefined) {
|
|
104
|
-
params.set('slippage', request.slippage.toString());
|
|
105
|
-
}
|
|
106
|
-
return params.toString();
|
|
107
103
|
};
|
|
108
104
|
const asRecord = (value) => {
|
|
109
105
|
if (typeof value !== 'object' || value === null) {
|
package/dist/prices.d.ts
CHANGED
|
@@ -105,3 +105,13 @@ export declare const resolveTokenPriceUsd: (token: Token, { pulsexPrices, lifiPr
|
|
|
105
105
|
pulsexPrices: Map<string, number>;
|
|
106
106
|
lifiPrices: Map<string, number>;
|
|
107
107
|
}) => number | null;
|
|
108
|
+
/**
|
|
109
|
+
* The chain's canonical wrapped native address when `token` is the native
|
|
110
|
+
* coin (zero address) or that wrapper itself, and null for every other token.
|
|
111
|
+
* Only the SAME chain's pair is returned: a bridged copy of a wrapper on
|
|
112
|
+
* another chain is a different token and keeps its own price.
|
|
113
|
+
*
|
|
114
|
+
* @param token - the token to test
|
|
115
|
+
* @returns the wrapped native address on the token's own chain, or null
|
|
116
|
+
*/
|
|
117
|
+
export declare const sameChainWrappedNative: (token: Token) => Hex | null;
|