@gibs/bridge-sdk 1.13.1 → 1.17.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 +244 -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 +240 -0
- package/dist/cjs/config.js +537 -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 +346 -0
- package/dist/cjs/execution.js +468 -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 +23 -0
- package/dist/cjs/index.js +39 -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 +107 -0
- package/dist/cjs/prices.js +172 -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/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 +159 -0
- package/dist/cjs/routing/carriers/pulsex.js +565 -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 +38 -0
- package/dist/cjs/routing/index.js +134 -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 +355 -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 +269 -0
- package/dist/cjs/routing/search/plan-route-data.js +848 -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 +91 -0
- package/dist/cjs/routing/swap-transactions.js +131 -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/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 +24 -0
- package/dist/config.js +39 -5
- package/dist/consolidated-quote.d.ts +109 -15
- package/dist/consolidated-quote.js +310 -52
- package/dist/execution.d.ts +346 -0
- package/dist/execution.js +428 -0
- package/dist/hyperliquid-execution.js +2 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -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/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/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 +31 -21
- package/dist/routing/carriers/pulsex.js +141 -71
- 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 +6 -2
- package/dist/routing/index.js +6 -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/search/graph.d.ts +15 -0
- package/dist/routing/search/plan-route-data.d.ts +25 -0
- package/dist/routing/search/plan-route-data.js +43 -7
- package/dist/routing/search/score.d.ts +3 -0
- package/dist/routing/search/score.js +11 -3
- package/dist/routing/swap-transactions.d.ts +91 -0
- package/dist/routing/swap-transactions.js +125 -0
- package/dist/settings.d.ts +94 -1
- package/dist/settings.js +95 -3
- 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,428 @@
|
|
|
1
|
+
import { zeroAddress } from 'viem';
|
|
2
|
+
import * as abis from './abis.js';
|
|
3
|
+
import { Providers, toChain } from './config.js';
|
|
4
|
+
import { aggregatorOriginCalls, } from './consolidated-quote.js';
|
|
5
|
+
import { pulseXRouterForEdge, pulseXSwapPathForHop } from './routing/carriers/pulsex.js';
|
|
6
|
+
import { buildPulseXSwapTransaction, buildWrapTransaction, swapMinimumOut } from './routing/swap-transactions.js';
|
|
7
|
+
import { approvalAmounts, approveCall, bridgePathway, destinationDataParam, feeDirectorStructEncoded, feeTypeSettings, omnibridgeApproval, transactionInputs, } from './settings.js';
|
|
8
|
+
/**
|
|
9
|
+
* An {@link AllowanceReader} that reports no allowance anywhere, so the plan
|
|
10
|
+
* includes every approval. For a caller that reads allowances itself at send
|
|
11
|
+
* time.
|
|
12
|
+
*/
|
|
13
|
+
export const assumeNoAllowance = async () => 0n;
|
|
14
|
+
const refusal = (value) => ({ kind: 'refused', refusal: value });
|
|
15
|
+
/** The fee director a delivery choice encodes, or null when the reader buys no delivery. */
|
|
16
|
+
const encodeDelivery = ({ leg, pathway, }) => {
|
|
17
|
+
const { delivery } = leg;
|
|
18
|
+
if (!delivery.shouldDeliver)
|
|
19
|
+
return { kind: 'encoded', feeDirector: null };
|
|
20
|
+
if (!pathway.requiresDelivery)
|
|
21
|
+
return refusal({ reason: 'delivery-not-offered' });
|
|
22
|
+
// A zero fee pays no relayer, so the transfer would wait for a delivery that never comes.
|
|
23
|
+
if (delivery.fee.maximumFee <= 0n)
|
|
24
|
+
return refusal({ reason: 'delivery-fee-missing' });
|
|
25
|
+
const feeDirector = feeDirectorStructEncoded({
|
|
26
|
+
recipient: leg.recipient,
|
|
27
|
+
bridgePathway: pathway,
|
|
28
|
+
feeType: delivery.fee.feeType,
|
|
29
|
+
priceCorrective: delivery.fee.priceCorrective,
|
|
30
|
+
gasTipFee: delivery.fee.gasTipFee,
|
|
31
|
+
percentFee: delivery.fee.percentFee,
|
|
32
|
+
feeTypeSettings: feeTypeSettings({ feeType: delivery.fee.feeType, unwrap: leg.unwrap }),
|
|
33
|
+
limit: delivery.fee.maximumFee,
|
|
34
|
+
assetOut: delivery.fee.assetOut,
|
|
35
|
+
});
|
|
36
|
+
if (feeDirector === null)
|
|
37
|
+
return refusal({ reason: 'delivery-fee-unencodable' });
|
|
38
|
+
return { kind: 'encoded', feeDirector };
|
|
39
|
+
};
|
|
40
|
+
const deliveryTermsOf = (delivery) => {
|
|
41
|
+
if (!delivery.shouldDeliver)
|
|
42
|
+
return { status: 'not-requested' };
|
|
43
|
+
return {
|
|
44
|
+
status: 'requested',
|
|
45
|
+
feeType: delivery.fee.feeType,
|
|
46
|
+
maximumFee: delivery.fee.maximumFee,
|
|
47
|
+
feeToken: delivery.fee.assetOut,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const omnibridgeCalls = (leg, account) => {
|
|
51
|
+
if (leg.amountIn <= 0n)
|
|
52
|
+
return refusal({ reason: 'amount-not-positive' });
|
|
53
|
+
const pathway = bridgePathway({ bridgeKey: leg.bridgeKey, isProd: leg.isProd, assetIn: leg.assetIn });
|
|
54
|
+
if (pathway === null)
|
|
55
|
+
return refusal({ reason: 'no-pathway' });
|
|
56
|
+
const encoded = encodeDelivery({ leg, pathway });
|
|
57
|
+
if (encoded.kind !== 'encoded')
|
|
58
|
+
return encoded;
|
|
59
|
+
const { feeDirector } = encoded;
|
|
60
|
+
const dataParam = destinationDataParam({
|
|
61
|
+
recipient: leg.recipient,
|
|
62
|
+
bridgePathway: pathway,
|
|
63
|
+
assetIn: leg.assetIn,
|
|
64
|
+
destinationRouter: pathway.destinationRouter,
|
|
65
|
+
feeDirectorStructEncoded: feeDirector,
|
|
66
|
+
assetLink: leg.assetLink,
|
|
67
|
+
shouldDeliver: leg.delivery.shouldDeliver,
|
|
68
|
+
unwrap: leg.unwrap,
|
|
69
|
+
});
|
|
70
|
+
const call = transactionInputs({
|
|
71
|
+
bridgeKey: leg.bridgeKey,
|
|
72
|
+
signedCrossing: { originChainId: Number(leg.bridgeKey[1]), destinationChainId: Number(leg.bridgeKey[2]) },
|
|
73
|
+
bridgePathway: pathway,
|
|
74
|
+
assetIn: leg.assetIn,
|
|
75
|
+
recipient: leg.recipient,
|
|
76
|
+
account,
|
|
77
|
+
assetLink: leg.assetLink,
|
|
78
|
+
destinationDataParam: dataParam,
|
|
79
|
+
amountToBridge: leg.amountIn,
|
|
80
|
+
feeDirectorStructEncoded: feeDirector,
|
|
81
|
+
shouldDeliver: leg.delivery.shouldDeliver,
|
|
82
|
+
});
|
|
83
|
+
if (call === null)
|
|
84
|
+
return refusal({ reason: 'bridge-call-refused' });
|
|
85
|
+
return {
|
|
86
|
+
kind: 'calls',
|
|
87
|
+
approval: omnibridgeApproval({
|
|
88
|
+
bridgePathway: pathway,
|
|
89
|
+
assetIn: leg.assetIn,
|
|
90
|
+
assetLink: leg.assetLink,
|
|
91
|
+
amountToBridge: leg.amountIn,
|
|
92
|
+
}),
|
|
93
|
+
action: { chainId: Number(leg.bridgeKey[1]), kind: 'bridge', ...call, gasLimit: null },
|
|
94
|
+
delivery: deliveryTermsOf(leg.delivery),
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const pulseXSwapCalls = (leg) => {
|
|
98
|
+
const { edge } = leg.hop;
|
|
99
|
+
const chainId = edge.from.chainId;
|
|
100
|
+
const routerAddress = pulseXRouterForEdge(edge);
|
|
101
|
+
// The builder refuses a hop that records no priced path, a router other
|
|
102
|
+
// than the edge's own, and a leg on screen that disagrees.
|
|
103
|
+
const call = buildPulseXSwapTransaction({
|
|
104
|
+
hop: leg.hop,
|
|
105
|
+
amountIn: leg.amountIn,
|
|
106
|
+
minAmountOut: leg.minAmountOut,
|
|
107
|
+
recipient: leg.recipient,
|
|
108
|
+
deadline: leg.deadline,
|
|
109
|
+
signedLeg: { kind: 'swap', chainId },
|
|
110
|
+
chainId,
|
|
111
|
+
routerAddress,
|
|
112
|
+
});
|
|
113
|
+
if (call === null || routerAddress === null)
|
|
114
|
+
return refusal({ reason: 'swap-refused' });
|
|
115
|
+
const spendsNative = edge.from.address.toLowerCase() === zeroAddress;
|
|
116
|
+
return {
|
|
117
|
+
kind: 'calls',
|
|
118
|
+
approval: spendsNative
|
|
119
|
+
? null
|
|
120
|
+
: { chainId, token: edge.from.address, spender: routerAddress, minimum: leg.amountIn },
|
|
121
|
+
action: { chainId, kind: 'swap', ...call, gasLimit: null },
|
|
122
|
+
delivery: null,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const wrapCalls = (leg) => {
|
|
126
|
+
const call = buildWrapTransaction({ edge: leg.edge, amountIn: leg.amountIn });
|
|
127
|
+
if (call === null)
|
|
128
|
+
return refusal({ reason: 'wrap-refused' });
|
|
129
|
+
const wraps = leg.edge.from.address.toLowerCase() === zeroAddress;
|
|
130
|
+
return {
|
|
131
|
+
kind: 'calls',
|
|
132
|
+
approval: null,
|
|
133
|
+
action: { chainId: leg.edge.from.chainId, kind: wraps ? 'wrap' : 'unwrap', ...call, gasLimit: null },
|
|
134
|
+
delivery: null,
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const aggregatorCalls = (leg) => {
|
|
138
|
+
const origin = aggregatorOriginCalls({ quote: leg.quote, request: leg.request });
|
|
139
|
+
if (origin.kind === 'refused')
|
|
140
|
+
return refusal({ reason: 'aggregator-origin-refused', origin: origin.refusal });
|
|
141
|
+
const { approval, deposit } = origin;
|
|
142
|
+
const staysOnChain = leg.request.toChainId === leg.request.fromChainId;
|
|
143
|
+
return {
|
|
144
|
+
kind: 'calls',
|
|
145
|
+
approval,
|
|
146
|
+
action: {
|
|
147
|
+
chainId: leg.request.fromChainId,
|
|
148
|
+
kind: staysOnChain ? 'swap' : 'bridge',
|
|
149
|
+
to: deposit.to,
|
|
150
|
+
data: deposit.data,
|
|
151
|
+
value: deposit.value,
|
|
152
|
+
gasLimit: deposit.gasLimit,
|
|
153
|
+
},
|
|
154
|
+
delivery: null,
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
const legCalls = (leg, account) => {
|
|
158
|
+
if (leg.kind === 'omnibridge')
|
|
159
|
+
return omnibridgeCalls(leg, account);
|
|
160
|
+
if (leg.kind === 'pulsex-swap')
|
|
161
|
+
return pulseXSwapCalls(leg);
|
|
162
|
+
if (leg.kind === 'wrap')
|
|
163
|
+
return wrapCalls(leg);
|
|
164
|
+
return aggregatorCalls(leg);
|
|
165
|
+
};
|
|
166
|
+
/** The approve transactions an approval needs now: none when the allowance on chain covers it. */
|
|
167
|
+
const approvalTransactions = async ({ approval, account, readAllowance, }) => {
|
|
168
|
+
const allowance = await readAllowance(approval.chainId, approval.token, account, approval.spender);
|
|
169
|
+
return approvalAmounts({ allowance, minimum: approval.minimum }).map((amount) => ({
|
|
170
|
+
chainId: approval.chainId,
|
|
171
|
+
kind: 'approve',
|
|
172
|
+
...approveCall({ token: approval.token, spender: approval.spender, amount }),
|
|
173
|
+
gasLimit: null,
|
|
174
|
+
}));
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Plans the transactions for a list of legs, in order.
|
|
178
|
+
*
|
|
179
|
+
* Each leg contributes the exact approval it needs when the allowance on
|
|
180
|
+
* chain does not cover it (a reset to zero first when a smaller allowance
|
|
181
|
+
* remains), then its own call. Nothing is sent.
|
|
182
|
+
*
|
|
183
|
+
* @param options.account - the account that signs every transaction
|
|
184
|
+
* @param options.legs - the legs, in the order the wallet signs them
|
|
185
|
+
* @param options.readAllowance - reads an allowance on chain; see {@link AllowanceReader}
|
|
186
|
+
* @returns the ordered transactions, or the first leg that cannot be planned
|
|
187
|
+
*/
|
|
188
|
+
export const planExecution = async ({ account, legs, readAllowance, }) => {
|
|
189
|
+
const calls = legs.map((leg) => legCalls(leg, account));
|
|
190
|
+
const refusedIndex = calls.findIndex((entry) => entry.kind === 'refused');
|
|
191
|
+
const refused = calls[refusedIndex];
|
|
192
|
+
if (refused !== undefined && refused.kind === 'refused') {
|
|
193
|
+
return { kind: 'refused', legIndex: refusedIndex, refusal: refused.refusal };
|
|
194
|
+
}
|
|
195
|
+
const planned = calls.flatMap((entry) => (entry.kind === 'calls' ? [entry] : []));
|
|
196
|
+
const perLeg = await Promise.all(planned.map(async (entry) => {
|
|
197
|
+
const approvals = entry.approval === null
|
|
198
|
+
? []
|
|
199
|
+
: await approvalTransactions({ approval: entry.approval, account, readAllowance });
|
|
200
|
+
return [...approvals, entry.action];
|
|
201
|
+
}));
|
|
202
|
+
const ordered = perLeg.flat();
|
|
203
|
+
const transactions = ordered.map((action, index) => ({ ...action, waitForReceipt: index < ordered.length - 1 }));
|
|
204
|
+
const deliveries = planned.flatMap((entry, legIndex) => entry.delivery === null ? [] : [{ ...entry.delivery, legIndex }]);
|
|
205
|
+
return { kind: 'planned', transactions, deliveries };
|
|
206
|
+
};
|
|
207
|
+
const OMNIBRIDGE_CARRIERS = new Set(Object.values(Providers));
|
|
208
|
+
const isOmnibridgeCarrier = (carrier) => OMNIBRIDGE_CARRIERS.has(carrier);
|
|
209
|
+
const missing = (needs) => ({
|
|
210
|
+
kind: 'refused',
|
|
211
|
+
refusal: { reason: 'section-inputs-missing', needs },
|
|
212
|
+
});
|
|
213
|
+
const shape = (detail) => ({ kind: 'refused', refusal: { reason: 'section-shape', detail } });
|
|
214
|
+
const omnibridgeSectionLeg = ({ carrier, from, to, inputs, assetIn, }) => {
|
|
215
|
+
if (inputs.omnibridge === undefined)
|
|
216
|
+
return missing('omnibridge');
|
|
217
|
+
return {
|
|
218
|
+
kind: 'leg',
|
|
219
|
+
leg: {
|
|
220
|
+
kind: 'omnibridge',
|
|
221
|
+
bridgeKey: [carrier, toChain(from.chainId), toChain(to.chainId)],
|
|
222
|
+
isProd: inputs.omnibridge.isProd,
|
|
223
|
+
assetIn,
|
|
224
|
+
assetLink: inputs.omnibridge.assetLink,
|
|
225
|
+
amountIn: inputs.amountIn,
|
|
226
|
+
recipient: inputs.recipient,
|
|
227
|
+
delivery: inputs.omnibridge.delivery,
|
|
228
|
+
unwrap: inputs.omnibridge.unwrap,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
const liveQuoteRequired = { kind: 'refused', refusal: { reason: 'live-quote-required' } };
|
|
233
|
+
const aggregatorSectionLeg = (carrier, inputs) => {
|
|
234
|
+
if (inputs.aggregator === undefined)
|
|
235
|
+
return liveQuoteRequired;
|
|
236
|
+
const { quote, request } = inputs.aggregator;
|
|
237
|
+
if (quote.provider !== carrier) {
|
|
238
|
+
return {
|
|
239
|
+
kind: 'refused',
|
|
240
|
+
refusal: { reason: 'quote-provider-mismatch', quoteProvider: quote.provider, sectionCarrier: carrier },
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return { kind: 'leg', leg: { kind: 'aggregator', quote, request } };
|
|
244
|
+
};
|
|
245
|
+
const pulseXSectionLeg = (hop, inputs) => {
|
|
246
|
+
if (inputs.swap === undefined)
|
|
247
|
+
return missing('swap');
|
|
248
|
+
const { quotedAmountOut } = inputs.swap;
|
|
249
|
+
if (quotedAmountOut !== undefined && quotedAmountOut <= 0n) {
|
|
250
|
+
return { kind: 'refused', refusal: { reason: 'swap-quote-not-positive' } };
|
|
251
|
+
}
|
|
252
|
+
// Without a fresh quote the floor comes from the hop's own figure, so it must be a real quote.
|
|
253
|
+
if (quotedAmountOut === undefined && hop.outcome.kind !== 'quote') {
|
|
254
|
+
return { kind: 'refused', refusal: { reason: 'swap-estimate-only' } };
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
kind: 'leg',
|
|
258
|
+
leg: {
|
|
259
|
+
kind: 'pulsex-swap',
|
|
260
|
+
hop,
|
|
261
|
+
amountIn: inputs.amountIn,
|
|
262
|
+
minAmountOut: swapMinimumOut({
|
|
263
|
+
quotedAmount: quotedAmountOut ?? hop.outcome.deliveredAmount,
|
|
264
|
+
slippageBasisPoints: inputs.swap.slippageBasisPoints,
|
|
265
|
+
}),
|
|
266
|
+
recipient: inputs.recipient,
|
|
267
|
+
deadline: inputs.swap.deadline,
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
};
|
|
271
|
+
/** Turns one section of an engine plan into its leg, dispatching on the first hop's carrier. */
|
|
272
|
+
const planSectionLeg = ({ hops, inputs, resolveToken, }) => {
|
|
273
|
+
const firstHop = hops[0];
|
|
274
|
+
if (firstHop === undefined)
|
|
275
|
+
return shape('the section has no hops');
|
|
276
|
+
const { carrier, origin, from, to } = firstHop.edge;
|
|
277
|
+
if (origin === 'by-hand')
|
|
278
|
+
return { kind: 'refused', refusal: { reason: 'paid-by-hand' } };
|
|
279
|
+
// An aggregator section may run several hops inside one signature (a fused
|
|
280
|
+
// omnibridge entry); every other carrier signs exactly one hop.
|
|
281
|
+
const singleHop = hops.length === 1;
|
|
282
|
+
if (isOmnibridgeCarrier(carrier)) {
|
|
283
|
+
if (!singleHop)
|
|
284
|
+
return shape('an omnibridge section is exactly one hop');
|
|
285
|
+
return omnibridgeSectionLeg({ carrier, from, to, inputs, assetIn: resolveToken(from) });
|
|
286
|
+
}
|
|
287
|
+
if (carrier === 'PulseX') {
|
|
288
|
+
if (!singleHop)
|
|
289
|
+
return shape('a swap section is exactly one hop');
|
|
290
|
+
return pulseXSectionLeg(firstHop, inputs);
|
|
291
|
+
}
|
|
292
|
+
if (carrier === 'wrap') {
|
|
293
|
+
if (!singleHop)
|
|
294
|
+
return shape('a wrap section is exactly one hop');
|
|
295
|
+
return { kind: 'leg', leg: { kind: 'wrap', edge: firstHop.edge, amountIn: inputs.amountIn } };
|
|
296
|
+
}
|
|
297
|
+
return aggregatorSectionLeg(carrier, inputs);
|
|
298
|
+
};
|
|
299
|
+
/** The sections of a plan, each as its hops. */
|
|
300
|
+
const planSections = (plan) => plan.signatures.map((group) => group.flatMap((hopIndex) => plan.hops[hopIndex] ?? []));
|
|
301
|
+
/**
|
|
302
|
+
* A candidate built without an engine plan is one signature: either a
|
|
303
|
+
* same-chain omnibridge crossing (`buildDirectCrossingCandidate`, whose quote
|
|
304
|
+
* names the bridge) or an aggregator quote.
|
|
305
|
+
*
|
|
306
|
+
* THE CANDIDATE'S OWN QUOTE IS NEVER SIGNED. It priced the route on screen
|
|
307
|
+
* and may be stale or a dry probe; only the live quote in
|
|
308
|
+
* `inputs.aggregator` is. Without one the section is refused with
|
|
309
|
+
* `live-quote-required`.
|
|
310
|
+
*/
|
|
311
|
+
const planlessSectionLeg = (candidate, inputs) => {
|
|
312
|
+
const provider = candidate.quote.provider;
|
|
313
|
+
if (isOmnibridgeCarrier(provider)) {
|
|
314
|
+
return omnibridgeSectionLeg({
|
|
315
|
+
carrier: provider,
|
|
316
|
+
from: candidate.originToken,
|
|
317
|
+
to: candidate.destinationToken,
|
|
318
|
+
inputs,
|
|
319
|
+
assetIn: candidate.originToken,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
return aggregatorSectionLeg(provider, inputs);
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* What is wrong with the requested window of sections, or null when it fits.
|
|
326
|
+
* A window starts at `firstSectionIndex` and spans `plannedCount` sections.
|
|
327
|
+
*/
|
|
328
|
+
const sectionWindowProblem = ({ firstSectionIndex, plannedCount, sectionCount, }) => {
|
|
329
|
+
if (!Number.isSafeInteger(firstSectionIndex) || firstSectionIndex < 0) {
|
|
330
|
+
return `firstSectionIndex must be a non-negative safe integer, received ${firstSectionIndex}`;
|
|
331
|
+
}
|
|
332
|
+
if (plannedCount < 1)
|
|
333
|
+
return `pass at least 1 section input, received ${plannedCount}`;
|
|
334
|
+
if (firstSectionIndex + plannedCount > sectionCount) {
|
|
335
|
+
return `sections ${firstSectionIndex} to ${firstSectionIndex + plannedCount - 1} do not fit a route of ${sectionCount} section${sectionCount === 1 ? '' : 's'}`;
|
|
336
|
+
}
|
|
337
|
+
return null;
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* Plans the transactions for a chosen route candidate: the candidate
|
|
341
|
+
* `buildRouteCandidateFromPlan` returns for an engine plan (the interface's
|
|
342
|
+
* `buildCandidateFromEnginePlan`), or a candidate built without a plan.
|
|
343
|
+
*
|
|
344
|
+
* ONE SECTION IS ONE SIGNATURE. A plan's `signatures` groups its hops into
|
|
345
|
+
* sections; the section's first hop names its carrier. An omnibridge section
|
|
346
|
+
* becomes a crossing, a PulseX section a swap signed on its recorded path, a
|
|
347
|
+
* wrap section a wrap or unwrap, and any other wallet-signed carrier an
|
|
348
|
+
* aggregator deposit from the live quote the caller supplies. A section paid
|
|
349
|
+
* by hand has nothing to sign and is refused.
|
|
350
|
+
*
|
|
351
|
+
* A LATER SECTION CAN BE PLANNED ALONE. Pass `firstSectionIndex` to skip the
|
|
352
|
+
* sections that already landed. The wallet then plans the swap after the
|
|
353
|
+
* crossing arrived, from the amount that arrived, with a fresh
|
|
354
|
+
* `swap.quotedAmountOut` and a fresh `swap.deadline`. The slippage floor and the
|
|
355
|
+
* deadline are not fixed minutes before the swap is signed. Every safety check
|
|
356
|
+
* still applies to the later section: verified spenders, live quotes for
|
|
357
|
+
* aggregator sections, exact approvals.
|
|
358
|
+
*
|
|
359
|
+
* Every `sectionIndex` in a refusal and every `legIndex` in `deliveries` is
|
|
360
|
+
* the absolute section index.
|
|
361
|
+
*
|
|
362
|
+
* @param inputs - see {@link CandidateExecutionInputs}
|
|
363
|
+
* @returns the ordered transactions with the deliveries they buy, or the first section that cannot be planned
|
|
364
|
+
*/
|
|
365
|
+
export const planCandidateExecution = async (inputs) => {
|
|
366
|
+
const { candidate, account, readAllowance, resolveToken, sections } = inputs;
|
|
367
|
+
const firstSectionIndex = inputs.firstSectionIndex ?? 0;
|
|
368
|
+
const plan = candidate.plan;
|
|
369
|
+
const allSections = plan === undefined ? null : planSections(plan);
|
|
370
|
+
const sectionCount = allSections === null ? 1 : allSections.length;
|
|
371
|
+
const problem = sectionWindowProblem({ firstSectionIndex, plannedCount: sections.length, sectionCount });
|
|
372
|
+
if (problem !== null) {
|
|
373
|
+
const validIndex = Number.isSafeInteger(firstSectionIndex) && firstSectionIndex >= 0;
|
|
374
|
+
return {
|
|
375
|
+
kind: 'refused',
|
|
376
|
+
sectionIndex: validIndex ? firstSectionIndex : 0,
|
|
377
|
+
refusal: { reason: 'section-shape', detail: problem },
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const sectionLegs = sections.map((sectionInputs, index) => allSections === null
|
|
381
|
+
? planlessSectionLeg(candidate, sectionInputs)
|
|
382
|
+
: planSectionLeg({ hops: allSections[firstSectionIndex + index] ?? [], inputs: sectionInputs, resolveToken }));
|
|
383
|
+
const refusedIndex = sectionLegs.findIndex((entry) => entry.kind === 'refused');
|
|
384
|
+
const refused = sectionLegs[refusedIndex];
|
|
385
|
+
if (refused !== undefined && refused.kind === 'refused') {
|
|
386
|
+
return { kind: 'refused', sectionIndex: firstSectionIndex + refusedIndex, refusal: refused.refusal };
|
|
387
|
+
}
|
|
388
|
+
const legs = sectionLegs.flatMap((entry) => (entry.kind === 'leg' ? [entry.leg] : []));
|
|
389
|
+
const planned = await planExecution({ account, legs, readAllowance });
|
|
390
|
+
if (planned.kind === 'refused') {
|
|
391
|
+
return { kind: 'refused', sectionIndex: firstSectionIndex + planned.legIndex, refusal: planned.refusal };
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
kind: 'planned',
|
|
395
|
+
transactions: planned.transactions,
|
|
396
|
+
deliveries: planned.deliveries.map((delivery) => ({ ...delivery, legIndex: firstSectionIndex + delivery.legIndex })),
|
|
397
|
+
remainingSectionCount: sectionCount - firstSectionIndex - sections.length,
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Reads a fresh quote for a PulseX section: what the router's `getAmountsOut`
|
|
402
|
+
* says the swap delivers for `amountIn`, along the exact path the swap signs
|
|
403
|
+
* ({@link pulseXSwapPathForHop}) on the edge's own router. A wallet passes the
|
|
404
|
+
* result as `swap.quotedAmountOut` just before it signs.
|
|
405
|
+
*
|
|
406
|
+
* @param options.hop - the swap hop; its recorded path and edge name what to read
|
|
407
|
+
* @param options.amountIn - the amount the swap spends, in base units
|
|
408
|
+
* @param options.client - a client that can call `readContract`
|
|
409
|
+
* @returns the amount the last token of the path delivers, or null when the hop records no path, names no known router, the amount is not positive, or the read fails or returns nothing
|
|
410
|
+
*/
|
|
411
|
+
export const readPulseXSectionQuote = async ({ hop, amountIn, client, }) => {
|
|
412
|
+
const path = pulseXSwapPathForHop(hop);
|
|
413
|
+
const router = pulseXRouterForEdge(hop.edge);
|
|
414
|
+
if (path === null || router === null || amountIn <= 0n)
|
|
415
|
+
return null;
|
|
416
|
+
try {
|
|
417
|
+
const amounts = await client.readContract({
|
|
418
|
+
address: router,
|
|
419
|
+
abi: abis.univ2Router,
|
|
420
|
+
functionName: 'getAmountsOut',
|
|
421
|
+
args: [amountIn, path],
|
|
422
|
+
});
|
|
423
|
+
return amounts.at(-1) ?? null;
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
@@ -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
package/dist/index.js
CHANGED
|
@@ -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/providers.d.ts
CHANGED
|
@@ -132,6 +132,23 @@ export type ProviderDescriptor = {
|
|
|
132
132
|
* `providers.test.ts`).
|
|
133
133
|
*/
|
|
134
134
|
destinationCallCarriesNativeValue: boolean;
|
|
135
|
+
/**
|
|
136
|
+
* How this provider takes an Ethereum token from the reader's wallet.
|
|
137
|
+
*
|
|
138
|
+
* - `'allowance'` — the provider's contract pulls the token, so the wallet
|
|
139
|
+
* must first approve that contract as a spender. The execution quote names
|
|
140
|
+
* the spender (`ConsolidatedQuote.approvalAddress`), and the executor
|
|
141
|
+
* raises the allowance before it sends.
|
|
142
|
+
* - `'transfer'` — the reader sends the token to an address the provider
|
|
143
|
+
* gives. A plain transfer needs no approval, and the parser leaves
|
|
144
|
+
* `approvalAddress` null.
|
|
145
|
+
*
|
|
146
|
+
* A DISPLAY FACT, NEVER A SIGNING ONE. The press reads the live quote's own
|
|
147
|
+
* `approvalAddress` and the live allowance. This field lets a route say, BEFORE
|
|
148
|
+
* any live quote exists, that its wallet may ask for an approval first.
|
|
149
|
+
* The native coin never needs one, whatever this says.
|
|
150
|
+
*/
|
|
151
|
+
originTokenSpend: 'allowance' | 'transfer';
|
|
135
152
|
/**
|
|
136
153
|
* Phase one: the plain forward-solving origin-to-anchor swap pre-quote.
|
|
137
154
|
*
|
package/dist/providers.js
CHANGED
|
@@ -11,6 +11,8 @@ const lifiDescriptor = {
|
|
|
11
11
|
executesDestinationCalls: true,
|
|
12
12
|
destinationCallOriginChainIds: [Number(Chains.ETH)],
|
|
13
13
|
destinationCallCarriesNativeValue: false,
|
|
14
|
+
// Its quote names the Diamond as `estimate.approvalAddress`.
|
|
15
|
+
originTokenSpend: 'allowance',
|
|
14
16
|
preQuote: {
|
|
15
17
|
method: 'GET',
|
|
16
18
|
build: buildLifiPreQuoteRequest,
|
|
@@ -33,6 +35,8 @@ const relayDescriptor = {
|
|
|
33
35
|
executesDestinationCalls: true,
|
|
34
36
|
destinationCallOriginChainIds: 'any',
|
|
35
37
|
destinationCallCarriesNativeValue: true,
|
|
38
|
+
// Its quote carries an approve step; the parser lifts its spender.
|
|
39
|
+
originTokenSpend: 'allowance',
|
|
36
40
|
preQuote: {
|
|
37
41
|
method: 'POST',
|
|
38
42
|
build: buildRelayPreQuoteRequest,
|
|
@@ -61,6 +65,8 @@ const nearIntentsDescriptor = {
|
|
|
61
65
|
executesDestinationCalls: false,
|
|
62
66
|
destinationCallOriginChainIds: [],
|
|
63
67
|
destinationCallCarriesNativeValue: false,
|
|
68
|
+
// The reader sends the token to a deposit address.
|
|
69
|
+
originTokenSpend: 'transfer',
|
|
64
70
|
preQuote: {
|
|
65
71
|
method: 'POST',
|
|
66
72
|
build: buildNearIntentsPreQuoteRequest,
|
package/dist/referral.d.ts
CHANGED
|
@@ -34,7 +34,11 @@ export declare const referralIntegrator = "gibs.finance";
|
|
|
34
34
|
*/
|
|
35
35
|
export declare const resolveAttribution: (override: string | null | undefined, packageDefault: string | undefined) => string | undefined;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Gibs Finance's payout address for Relay application fees.
|
|
38
|
+
*
|
|
39
|
+
* NO BUILDER APPLIES IT. A Relay request carries an `appFees` entry only when
|
|
40
|
+
* the caller passes `relayAppFee`. The Gibs interface passes this address
|
|
41
|
+
* explicitly; any other caller passes its own, or nothing.
|
|
38
42
|
*
|
|
39
43
|
* Set to the owner's receiving wallet. Setting it back to `null` is a working
|
|
40
44
|
* state rather than a broken one, and is the way to stop collecting: Relay
|
|
@@ -53,9 +57,13 @@ export declare const resolveAttribution: (override: string | null | undefined, p
|
|
|
53
57
|
*/
|
|
54
58
|
export declare const relayReferralRecipient: Hex | null;
|
|
55
59
|
/**
|
|
56
|
-
*
|
|
57
|
-
* percent. The interface can override it per
|
|
58
|
-
* is the value a reader who has never touched
|
|
60
|
+
* The application fee the Gibs interface charges, in basis points. Ten basis
|
|
61
|
+
* points is one tenth of one percent. The interface can override it per
|
|
62
|
+
* provider in stored settings; this is the value a reader who has never touched
|
|
63
|
+
* the setting gets.
|
|
64
|
+
*
|
|
65
|
+
* NO BUILDER APPLIES IT. It reaches a request only when a caller passes it as
|
|
66
|
+
* `relayAppFee.basisPoints` (Relay) or converts it to `lifiFee` (LI.FI).
|
|
59
67
|
*/
|
|
60
68
|
export declare const defaultReferralFeeBasisPoints = 10n;
|
|
61
69
|
/**
|