@peachprojects/aggregator-sdk 0.1.2 → 0.1.4
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 +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.ts +183 -12
- package/dist/index.mjs +738 -484
- package/package.json +5 -3
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import { ethers as
|
|
2
|
-
const
|
|
3
|
-
function
|
|
4
|
-
return
|
|
1
|
+
import { ethers as m } from "ethers";
|
|
2
|
+
const J = "https://api.peach.ag", Se = 50, _ = 10000n, U = 500, Ie = 5e3, N = 1200, G = 6e4, M = [50, 100, 200, 400, 800, 1200], q = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
3
|
+
function T(f) {
|
|
4
|
+
return f.toLowerCase() === q.toLowerCase();
|
|
5
5
|
}
|
|
6
|
-
const
|
|
7
|
-
var
|
|
8
|
-
const
|
|
6
|
+
const Pe = 4001;
|
|
7
|
+
var d = /* @__PURE__ */ ((f) => (f.PancakeV1 = "PancakeV1", f.PancakeV2 = "PancakeV2", f.PancakeV3 = "PancakeV3", f.PancakeInfinityCl = "Pancake_Infinity_Cl", f.PancakeInfinityLb = "Pancake_Infinity_Lb", f.UniswapV2 = "UniswapV2", f.UniswapV3 = "UniswapV3", f.UniswapV4 = "UniswapV4", f.Dodo = "Dodo", f.ThenaV3 = "ThenaV3", f.ThenaFusion = "Thena_Fusion", f.NomiswapStable = "Nomiswap_Stable", f.Biswap = "Biswap", f.Apeswap = "Apeswap", f.BabyDogeSwap = "BabyDogeSwap", f.BabySwap = "BabySwap", f.BakerySwap = "BakerySwap", f.PancakeStable = "Pancake_Stable", f.ListaStable = "Lista_Stable", f.SquadSwapV3 = "SquadSwap_V3", f.SquadSwapV2 = "SquadSwap_V2", f.Wombat = "Wombat", f.SushiSwapV2 = "SushiSwap_V2", f.SushiSwapV3 = "SushiSwap_V3", f))(d || {});
|
|
8
|
+
const ke = {
|
|
9
9
|
chainId: 56,
|
|
10
10
|
rpcUrl: "https://bsc-dataseed.binance.org",
|
|
11
11
|
weth: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
|
|
12
12
|
// WBNB
|
|
13
13
|
adapters: []
|
|
14
|
-
},
|
|
14
|
+
}, Ee = {
|
|
15
15
|
chainId: 97,
|
|
16
16
|
rpcUrl: "https://bsc-testnet-rpc.publicnode.com",
|
|
17
17
|
weth: "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd",
|
|
18
18
|
// WBNB Testnet
|
|
19
19
|
adapters: []
|
|
20
20
|
};
|
|
21
|
-
class
|
|
21
|
+
class B extends Error {
|
|
22
22
|
constructor(e) {
|
|
23
23
|
super(e), this.name = "CustomFeeError";
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
class
|
|
27
|
-
constructor(e, t,
|
|
28
|
-
super(e), this.name = "ExecuteTimeoutError", this.stage = t, this.txHash =
|
|
26
|
+
class Q extends Error {
|
|
27
|
+
constructor(e, t, n) {
|
|
28
|
+
super(e), this.name = "ExecuteTimeoutError", this.stage = t, this.txHash = n;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
const
|
|
31
|
+
const O = "0x000000000022D473030F116dDEE9F6B43aC78BA3", $ = (1n << 160n) - 1n, E = {
|
|
32
32
|
/** Default route search depth */
|
|
33
33
|
depth: 3,
|
|
34
34
|
/** Default trade split count */
|
|
35
35
|
splitCount: 20,
|
|
36
36
|
/** Default DEX providers */
|
|
37
|
-
providers: ["PANCAKEV2", "PANCAKEV3", "PANCAKE_INFINITY_CL", "UNISWAPV3", "UNISWAPV4", "DODO", "
|
|
37
|
+
providers: ["PANCAKEV1", "PANCAKEV2", "PANCAKEV3", "PANCAKE_INFINITY_CL", "PANCAKE_INFINITY_LB", "UNISWAPV2", "UNISWAPV3", "UNISWAPV4", "DODO", "THENAV3", "NOMISWAP_STABLE", "BISWAP", "APESWAP", "BABYDOGESWAP", "BABYSWAP", "BAKERYSWAP", "PANCAKE_STABLE", "LISTA_STABLE", "SQUADSWAP_V3", "SQUADSWAP_V2", "WOMBAT", "THENA_FUSION", "SUSHISWAP_V2", "SUSHISWAP_V3"],
|
|
38
38
|
/** Default client version for V3 API */
|
|
39
39
|
clientVersion: 1001500
|
|
40
|
-
},
|
|
41
|
-
function
|
|
40
|
+
}, ee = 1e4;
|
|
41
|
+
function te(f) {
|
|
42
42
|
const e = {};
|
|
43
|
-
return
|
|
44
|
-
e[
|
|
43
|
+
return f.forEach((t, n) => {
|
|
44
|
+
e[n] = t;
|
|
45
45
|
}), e;
|
|
46
46
|
}
|
|
47
|
-
class
|
|
47
|
+
class ne {
|
|
48
48
|
constructor(e = {}) {
|
|
49
|
-
this.baseUrl = e.baseUrl ||
|
|
49
|
+
this.baseUrl = e.baseUrl || J, this.timeout = e.timeout || ee, this.extraHeaders = e.headers ? { ...e.headers } : {};
|
|
50
50
|
}
|
|
51
51
|
async findRoutes(e) {
|
|
52
52
|
const {
|
|
53
53
|
from: t,
|
|
54
|
-
target:
|
|
55
|
-
amount:
|
|
56
|
-
byAmountIn:
|
|
57
|
-
depth: r =
|
|
58
|
-
splitCount: a =
|
|
59
|
-
providers: i =
|
|
54
|
+
target: n,
|
|
55
|
+
amount: s,
|
|
56
|
+
byAmountIn: o = !0,
|
|
57
|
+
depth: r = E.depth,
|
|
58
|
+
splitCount: a = E.splitCount,
|
|
59
|
+
providers: i = E.providers,
|
|
60
60
|
includeResponseHeaders: c = !1
|
|
61
61
|
} = e, u = new URLSearchParams({
|
|
62
62
|
from: t,
|
|
63
|
-
target:
|
|
64
|
-
amount:
|
|
65
|
-
by_amount_in:
|
|
63
|
+
target: n,
|
|
64
|
+
amount: s.toString(),
|
|
65
|
+
by_amount_in: o.toString(),
|
|
66
66
|
depth: r.toString(),
|
|
67
67
|
split_count: a.toString(),
|
|
68
68
|
providers: i.join(","),
|
|
69
|
-
v:
|
|
70
|
-
}),
|
|
69
|
+
v: E.clientVersion.toString()
|
|
70
|
+
}), l = `${this.baseUrl}/router/find_routes?${u}`, p = new AbortController(), A = setTimeout(() => p.abort(), this.timeout);
|
|
71
71
|
try {
|
|
72
|
-
const
|
|
72
|
+
const w = await fetch(l, {
|
|
73
73
|
method: "GET",
|
|
74
74
|
headers: {
|
|
75
75
|
Accept: "application/json",
|
|
@@ -77,31 +77,31 @@ class X {
|
|
|
77
77
|
},
|
|
78
78
|
signal: p.signal
|
|
79
79
|
});
|
|
80
|
-
if (clearTimeout(
|
|
81
|
-
throw new
|
|
82
|
-
`API request failed: ${
|
|
83
|
-
|
|
80
|
+
if (clearTimeout(A), !w.ok)
|
|
81
|
+
throw new S(
|
|
82
|
+
`API request failed: ${w.status} ${w.statusText}`,
|
|
83
|
+
w.status
|
|
84
84
|
);
|
|
85
|
-
const v = await
|
|
85
|
+
const v = await w.json();
|
|
86
86
|
if (v.code !== 200)
|
|
87
|
-
throw new
|
|
87
|
+
throw new S(v.msg || "Route not found", v.code);
|
|
88
88
|
if (!v.data || !v.data.paths || v.data.paths.length === 0)
|
|
89
|
-
throw new
|
|
89
|
+
throw new S("No routes found", 404);
|
|
90
90
|
return c ? {
|
|
91
91
|
data: v.data,
|
|
92
|
-
responseHeaders:
|
|
92
|
+
responseHeaders: te(w.headers)
|
|
93
93
|
} : v.data;
|
|
94
|
-
} catch (
|
|
95
|
-
throw clearTimeout(
|
|
94
|
+
} catch (w) {
|
|
95
|
+
throw clearTimeout(A), w instanceof S ? w : w instanceof Error ? w.name === "AbortError" ? new S("API request timeout", 408) : new S(`API request failed: ${w.message}`, 0) : new S("Unknown API error", 0);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
99
|
* Get service status including available providers
|
|
100
100
|
*/
|
|
101
101
|
async getStatus() {
|
|
102
|
-
const e = `${this.baseUrl}/router/status`, t = new AbortController(),
|
|
102
|
+
const e = `${this.baseUrl}/router/status`, t = new AbortController(), n = setTimeout(() => t.abort(), this.timeout);
|
|
103
103
|
try {
|
|
104
|
-
const
|
|
104
|
+
const s = await fetch(e, {
|
|
105
105
|
method: "GET",
|
|
106
106
|
headers: {
|
|
107
107
|
Accept: "application/json",
|
|
@@ -109,17 +109,17 @@ class X {
|
|
|
109
109
|
},
|
|
110
110
|
signal: t.signal
|
|
111
111
|
});
|
|
112
|
-
if (clearTimeout(
|
|
113
|
-
throw new
|
|
114
|
-
`API request failed: ${
|
|
115
|
-
|
|
112
|
+
if (clearTimeout(n), !s.ok)
|
|
113
|
+
throw new S(
|
|
114
|
+
`API request failed: ${s.status} ${s.statusText}`,
|
|
115
|
+
s.status
|
|
116
116
|
);
|
|
117
|
-
const
|
|
118
|
-
if (
|
|
119
|
-
throw new
|
|
120
|
-
return
|
|
121
|
-
} catch (
|
|
122
|
-
throw clearTimeout(
|
|
117
|
+
const o = await s.json();
|
|
118
|
+
if (o.code !== 200)
|
|
119
|
+
throw new S(o.msg || "Failed to get status", o.code);
|
|
120
|
+
return o.data;
|
|
121
|
+
} catch (s) {
|
|
122
|
+
throw clearTimeout(n), s instanceof S ? s : s instanceof Error ? s.name === "AbortError" ? new S("API request timeout", 408) : new S(`API request failed: ${s.message}`, 0) : new S("Unknown API error", 0);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
@@ -141,22 +141,22 @@ class X {
|
|
|
141
141
|
return this.baseUrl;
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
class
|
|
144
|
+
class S extends Error {
|
|
145
145
|
constructor(e, t) {
|
|
146
146
|
super(e), this.name = "ApiError", this.code = t;
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
-
async function
|
|
149
|
+
async function W(f, e = G) {
|
|
150
150
|
if (e <= 0)
|
|
151
|
-
return
|
|
151
|
+
return f;
|
|
152
152
|
let t;
|
|
153
153
|
try {
|
|
154
154
|
return await Promise.race([
|
|
155
|
-
|
|
156
|
-
new Promise((
|
|
155
|
+
f,
|
|
156
|
+
new Promise((n, s) => {
|
|
157
157
|
t = setTimeout(() => {
|
|
158
|
-
|
|
159
|
-
new
|
|
158
|
+
s(
|
|
159
|
+
new Q(
|
|
160
160
|
`Wallet did not settle sendTransaction within ${e}ms.`,
|
|
161
161
|
"wallet_send"
|
|
162
162
|
)
|
|
@@ -168,9 +168,13 @@ async function U(w, e = W) {
|
|
|
168
168
|
t && clearTimeout(t);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
const
|
|
171
|
+
const R = [
|
|
172
172
|
"function swap((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external returns (uint256 amountOut)",
|
|
173
173
|
"function swapETH((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params) external payable returns (uint256 amountOut)",
|
|
174
|
+
// Permit2 (AllowanceTransfer) entrypoints. Second arg is the Permit2Sig tuple:
|
|
175
|
+
// ((PermitDetails details, address spender, uint256 sigDeadline) permitSingle, bytes signature)
|
|
176
|
+
"function swapWithPermit2((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params, (((address token, uint160 amount, uint48 expiration, uint48 nonce) details, address spender, uint256 sigDeadline) permitSingle, bytes signature) p2) external returns (uint256 amountOut)",
|
|
177
|
+
"function swapETHWithPermit2((address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, (address adapter, address pool, address tokenIn, address tokenOut, uint256 amountIn, bytes extraData)[] steps, address[] intermediateTokens, uint256 deadline, bytes32 quoteId, uint256 expectAmountOut, address feeReceiver, uint16 feeBps) params, (((address token, uint160 amount, uint48 expiration, uint48 nonce) details, address spender, uint256 sigDeadline) permitSingle, bytes signature) p2) external returns (uint256 amountOut)",
|
|
174
178
|
"function isAdapterRegistered(address adapter) external view returns (bool)",
|
|
175
179
|
"function getAdapterProtocolId(address adapter) external view returns (bytes32)",
|
|
176
180
|
"function WETH() external view returns (address)",
|
|
@@ -181,40 +185,65 @@ const B = [
|
|
|
181
185
|
"function maxProtocolCutBps() external view returns (uint16)",
|
|
182
186
|
"function protocolFeeReceiver() external view returns (address)",
|
|
183
187
|
"function protocolCutBps() external view returns (uint16)"
|
|
184
|
-
],
|
|
188
|
+
], b = [
|
|
185
189
|
"function approve(address spender, uint256 amount) external returns (bool)",
|
|
186
190
|
"function allowance(address owner, address spender) external view returns (uint256)",
|
|
187
191
|
"function balanceOf(address account) external view returns (uint256)",
|
|
188
192
|
"function decimals() external view returns (uint8)",
|
|
189
193
|
"function symbol() external view returns (string)"
|
|
190
|
-
],
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
194
|
+
], se = [
|
|
195
|
+
"function allowance(address user, address token, address spender) external view returns (uint160 amount, uint48 expiration, uint48 nonce)"
|
|
196
|
+
], re = {
|
|
197
|
+
PermitDetails: [
|
|
198
|
+
{ name: "token", type: "address" },
|
|
199
|
+
{ name: "amount", type: "uint160" },
|
|
200
|
+
{ name: "expiration", type: "uint48" },
|
|
201
|
+
{ name: "nonce", type: "uint48" }
|
|
202
|
+
],
|
|
203
|
+
PermitSingle: [
|
|
204
|
+
{ name: "details", type: "PermitDetails" },
|
|
205
|
+
{ name: "spender", type: "address" },
|
|
206
|
+
{ name: "sigDeadline", type: "uint256" }
|
|
207
|
+
]
|
|
208
|
+
}, oe = "0xa0FfB9c1CE1Fe56963B0321B32E7A0302114058b", ae = "0xC697d2898e0D09264376196696c51D7aBbbAA4a9", ie = "0x28e2ea090877bf75740558f6bfb36a5ffee9e9df", H = {
|
|
209
|
+
PANCAKEV3: d.PancakeV3,
|
|
210
|
+
PANCAKEV2: d.PancakeV2,
|
|
211
|
+
PANCAKEV1: d.PancakeV1,
|
|
212
|
+
PANCAKE_INFINITY_CL: d.PancakeInfinityCl,
|
|
213
|
+
PANCAKE_INFINITY_LB: d.PancakeInfinityLb,
|
|
214
|
+
UNISWAPV2: d.UniswapV2,
|
|
215
|
+
UNISWAPV3: d.UniswapV3,
|
|
216
|
+
UNISWAPV4: d.UniswapV4,
|
|
217
|
+
DODO: d.Dodo,
|
|
218
|
+
THENAV3: d.ThenaV3,
|
|
219
|
+
NOMISWAP_STABLE: d.NomiswapStable,
|
|
220
|
+
BISWAP: d.Biswap,
|
|
221
|
+
APESWAP: d.Apeswap,
|
|
222
|
+
BABYDOGESWAP: d.BabyDogeSwap,
|
|
223
|
+
BABYSWAP: d.BabySwap,
|
|
224
|
+
BAKERYSWAP: d.BakerySwap,
|
|
225
|
+
PANCAKE_STABLE: d.PancakeStable,
|
|
226
|
+
LISTA_STABLE: d.ListaStable,
|
|
227
|
+
SQUADSWAP_V3: d.SquadSwapV3,
|
|
228
|
+
SQUADSWAP_V2: d.SquadSwapV2,
|
|
229
|
+
WOMBAT: d.Wombat,
|
|
230
|
+
THENA_FUSION: d.ThenaFusion,
|
|
231
|
+
SUSHISWAP_V2: d.SushiSwapV2,
|
|
232
|
+
SUSHISWAP_V3: d.SushiSwapV3
|
|
233
|
+
}, C = class C {
|
|
234
|
+
constructor(e, t, n) {
|
|
235
|
+
this.config = e, this.provider = t || new m.JsonRpcProvider(e.rpcUrl), this.routerContract = new m.Contract(
|
|
236
|
+
e.routerAddress || m.ZeroAddress,
|
|
237
|
+
R,
|
|
209
238
|
this.provider
|
|
210
|
-
), this.apiClient = new
|
|
239
|
+
), this.apiClient = new ne(n?.api);
|
|
211
240
|
}
|
|
212
241
|
/**
|
|
213
242
|
* Get the effective router address for a quote.
|
|
214
243
|
*/
|
|
215
244
|
getRouterAddress(e) {
|
|
216
245
|
const t = e.routerAddress || this.config.routerAddress;
|
|
217
|
-
if (!t || t ===
|
|
246
|
+
if (!t || t === m.ZeroAddress)
|
|
218
247
|
throw new Error("No router address available. Provide routerAddress in config or use API-based getQuote.");
|
|
219
248
|
return t;
|
|
220
249
|
}
|
|
@@ -224,25 +253,25 @@ class K {
|
|
|
224
253
|
applySlippage(e, t) {
|
|
225
254
|
if (t < 0 || t > 1e4)
|
|
226
255
|
throw new Error("slippageBps must be between 0 and 10000");
|
|
227
|
-
const
|
|
228
|
-
return { ...e, amountOutMin:
|
|
256
|
+
const n = e.amountOutMin * (_ - BigInt(t)) / _;
|
|
257
|
+
return { ...e, amountOutMin: n };
|
|
229
258
|
}
|
|
230
259
|
/**
|
|
231
260
|
* Build transaction requests for an approval (if needed) and the swap itself.
|
|
232
261
|
*/
|
|
233
|
-
async swap(e, t,
|
|
234
|
-
const
|
|
262
|
+
async swap(e, t, n) {
|
|
263
|
+
const s = this.getRouterAddress(e), { tx: o, method: r } = this.buildSwapTransactionRequest(e, n);
|
|
235
264
|
let a;
|
|
236
265
|
return e.srcNative || (a = await this.buildApprovalRequest(
|
|
237
266
|
e.srcToken,
|
|
238
267
|
t,
|
|
239
268
|
e.amountIn,
|
|
240
|
-
|
|
241
|
-
|
|
269
|
+
s,
|
|
270
|
+
n
|
|
242
271
|
)), {
|
|
243
|
-
routerAddress:
|
|
272
|
+
routerAddress: s,
|
|
244
273
|
method: r,
|
|
245
|
-
tx:
|
|
274
|
+
tx: o,
|
|
246
275
|
approval: a
|
|
247
276
|
};
|
|
248
277
|
}
|
|
@@ -251,19 +280,19 @@ class K {
|
|
|
251
280
|
*
|
|
252
281
|
* @deprecated Prefer swap(), then send the returned tx request with your wallet/client.
|
|
253
282
|
*/
|
|
254
|
-
async execute(e, t,
|
|
255
|
-
const
|
|
283
|
+
async execute(e, t, n) {
|
|
284
|
+
const s = await t.getAddress(), o = await this.swap(e, s, n);
|
|
256
285
|
try {
|
|
257
|
-
return
|
|
286
|
+
return o.approval && await (await this.sendTransactionWithTimeout(
|
|
258
287
|
t,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
)).wait(), await this.sendTransactionWithTimeout(t,
|
|
288
|
+
o.approval.tx,
|
|
289
|
+
n
|
|
290
|
+
)).wait(), await this.sendTransactionWithTimeout(t, o.tx, n);
|
|
262
291
|
} catch (r) {
|
|
263
292
|
const a = r instanceof Error ? r.message : String(r), i = /estimateGas/i.test(a), c = /missing revert data/i.test(a) || a.includes("reason=null") && a.includes("data=null");
|
|
264
293
|
if (i && (c || /reason=null|data=null/.test(a))) {
|
|
265
|
-
const u = "Transaction reverted during gas estimation and the RPC did not return a revert reason. Try: 1) Get a fresh quote and confirm immediately 2) Switch network or RPC 3) Increase slippage.",
|
|
266
|
-
throw
|
|
294
|
+
const u = "Transaction reverted during gas estimation and the RPC did not return a revert reason. Try: 1) Get a fresh quote and confirm immediately 2) Switch network or RPC 3) Increase slippage.", l = new Error(`${u} (estimateGas/missing revert data)`);
|
|
295
|
+
throw l.cause = r, l;
|
|
267
296
|
}
|
|
268
297
|
throw r;
|
|
269
298
|
}
|
|
@@ -294,8 +323,8 @@ class K {
|
|
|
294
323
|
};
|
|
295
324
|
}
|
|
296
325
|
getProtocolForProvider(e) {
|
|
297
|
-
if (e in
|
|
298
|
-
return
|
|
326
|
+
if (e in H)
|
|
327
|
+
return H[e];
|
|
299
328
|
throw new Error(`Unsupported provider: ${e}`);
|
|
300
329
|
}
|
|
301
330
|
/**
|
|
@@ -307,11 +336,11 @@ class K {
|
|
|
307
336
|
* @returns Encoded calldata and transaction info (to address, value)
|
|
308
337
|
*/
|
|
309
338
|
encodeSwapCalldata(e, t) {
|
|
310
|
-
const
|
|
311
|
-
if (
|
|
339
|
+
const n = e.routerAddress ?? this.config.routerAddress ?? this.routerContract.target, s = this.applySlippage(e.params, t), o = e.srcNative === !0 || e.dstNative === !0, r = this.encodeParams(s);
|
|
340
|
+
if (o) {
|
|
312
341
|
const a = this.routerContract.interface.encodeFunctionData("swapETH", [r]);
|
|
313
342
|
return {
|
|
314
|
-
to:
|
|
343
|
+
to: n,
|
|
315
344
|
data: a,
|
|
316
345
|
value: e.srcNative ? e.amountIn : 0n,
|
|
317
346
|
method: "swapETH"
|
|
@@ -319,7 +348,7 @@ class K {
|
|
|
319
348
|
} else {
|
|
320
349
|
const a = this.routerContract.interface.encodeFunctionData("swap", [r]);
|
|
321
350
|
return {
|
|
322
|
-
to:
|
|
351
|
+
to: n,
|
|
323
352
|
data: a,
|
|
324
353
|
value: 0n,
|
|
325
354
|
method: "swap"
|
|
@@ -327,66 +356,187 @@ class K {
|
|
|
327
356
|
}
|
|
328
357
|
}
|
|
329
358
|
buildSwapTransactionRequest(e, t) {
|
|
330
|
-
const { to:
|
|
359
|
+
const { to: n, data: s, value: o, method: r } = this.encodeSwapCalldata(e, t.slippageBps);
|
|
331
360
|
return {
|
|
332
361
|
method: r,
|
|
333
|
-
tx: this.applyTxOverrides({ to:
|
|
362
|
+
tx: this.applyTxOverrides({ to: n, data: s, value: o }, t, !0)
|
|
334
363
|
};
|
|
335
364
|
}
|
|
336
|
-
async buildApprovalRequest(e, t,
|
|
337
|
-
const r = await this.getAllowance(e, t,
|
|
338
|
-
if (!(r >=
|
|
365
|
+
async buildApprovalRequest(e, t, n, s, o) {
|
|
366
|
+
const r = await this.getAllowance(e, t, s);
|
|
367
|
+
if (!(r >= n))
|
|
339
368
|
return {
|
|
340
369
|
token: e,
|
|
341
370
|
owner: t,
|
|
342
|
-
spender:
|
|
371
|
+
spender: s,
|
|
343
372
|
currentAllowance: r,
|
|
344
|
-
requiredAmount:
|
|
345
|
-
approveAmount:
|
|
346
|
-
tx: this.buildApprovalTransactionRequest(e,
|
|
373
|
+
requiredAmount: n,
|
|
374
|
+
approveAmount: m.MaxUint256,
|
|
375
|
+
tx: this.buildApprovalTransactionRequest(e, s, o)
|
|
347
376
|
};
|
|
348
377
|
}
|
|
349
|
-
buildApprovalTransactionRequest(e, t,
|
|
350
|
-
const
|
|
351
|
-
return this.applyTxOverrides({ to: e, data:
|
|
378
|
+
buildApprovalTransactionRequest(e, t, n) {
|
|
379
|
+
const o = new m.Interface(b).encodeFunctionData("approve", [t, m.MaxUint256]);
|
|
380
|
+
return this.applyTxOverrides({ to: e, data: o, value: 0n }, n, !1);
|
|
381
|
+
}
|
|
382
|
+
async getAllowance(e, t, n) {
|
|
383
|
+
return new m.Contract(e, b, this.provider).allowance(t, n);
|
|
384
|
+
}
|
|
385
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
386
|
+
// Permit2 (AllowanceTransfer)
|
|
387
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
388
|
+
/**
|
|
389
|
+
* Read the current Permit2 AllowanceTransfer state for (owner, token, spender).
|
|
390
|
+
* `spender` defaults to the router address. The returned `nonce` feeds the next PermitSingle;
|
|
391
|
+
* `amount` / `expiration` decide whether a fresh signature is needed.
|
|
392
|
+
*/
|
|
393
|
+
async getPermit2Allowance(e, t, n) {
|
|
394
|
+
const s = new m.Contract(O, se, this.provider), o = n ?? this.resolveRouterAddress(), [r, a, i] = await s.allowance(t, e, o);
|
|
395
|
+
return { amount: BigInt(r), expiration: Number(a), nonce: Number(i) };
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Build the ONE-TIME `token.approve(PERMIT2, max)` tx, or undefined when the token's existing
|
|
399
|
+
* Permit2 allowance already covers `amount`. This is the only on-chain approval Permit2 needs;
|
|
400
|
+
* once set, every future swap of this token is signature-only.
|
|
401
|
+
*/
|
|
402
|
+
async buildPermit2TokenApproval(e, t, n, s = {}) {
|
|
403
|
+
if (await this.getAllowance(e, t, O) >= n)
|
|
404
|
+
return;
|
|
405
|
+
const a = new m.Interface(b).encodeFunctionData("approve", [O, m.MaxUint256]), i = { to: e, data: a, value: 0n };
|
|
406
|
+
return s.gasPrice && (i.gasPrice = s.gasPrice), i;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Build the EIP-712 PermitSingle the user signs to grant the router a Permit2 allowance.
|
|
410
|
+
* Reads the current sequential nonce from Permit2; `permitSingle.spender` is the router.
|
|
411
|
+
* Pass the result straight into `signer.signTypedData(domain, types, values)`.
|
|
412
|
+
*/
|
|
413
|
+
async buildPermit2TypedData(e, t, n = {}) {
|
|
414
|
+
if (e.srcNative)
|
|
415
|
+
throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");
|
|
416
|
+
const s = this.getRouterAddress(e);
|
|
417
|
+
this.assertUint160(e.amountIn);
|
|
418
|
+
const { nonce: o } = await this.getPermit2Allowance(e.srcToken, t, s), r = Math.floor(Date.now() / 1e3), a = n.permitAmount ?? $;
|
|
419
|
+
this.assertUint160(a);
|
|
420
|
+
const i = {
|
|
421
|
+
details: {
|
|
422
|
+
token: e.srcToken,
|
|
423
|
+
amount: a,
|
|
424
|
+
expiration: n.expiration ?? r + 720 * 60 * 60,
|
|
425
|
+
// 30 days
|
|
426
|
+
nonce: o
|
|
427
|
+
},
|
|
428
|
+
spender: s,
|
|
429
|
+
sigDeadline: n.sigDeadline ?? BigInt(r + 1800)
|
|
430
|
+
// 30 min
|
|
431
|
+
};
|
|
432
|
+
return {
|
|
433
|
+
domain: { name: "Permit2", chainId: this.config.chainId, verifyingContract: O },
|
|
434
|
+
types: re,
|
|
435
|
+
values: i
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Encode calldata for swapWithPermit2 / swapETHWithPermit2. Routes to swapETHWithPermit2
|
|
440
|
+
* when the quote's dstToken is native. Pass `"0x"` as `signature` to reuse an existing
|
|
441
|
+
* on-chain Permit2 allowance (the router then skips the permit() call).
|
|
442
|
+
*/
|
|
443
|
+
encodeSwapWithPermit2Calldata(e, t, n, s) {
|
|
444
|
+
if (e.srcNative)
|
|
445
|
+
throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");
|
|
446
|
+
const o = this.getRouterAddress(e), r = this.applySlippage(e.params, t), a = this.encodeParams(r), i = { permitSingle: n, signature: s }, c = e.dstNative ? "swapETHWithPermit2" : "swapWithPermit2", u = this.routerContract.interface.encodeFunctionData(c, [a, i]);
|
|
447
|
+
return { to: o, data: u, value: 0n, method: c };
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Prepare a single-transaction Permit2 swap. Returns the optional one-time token->Permit2
|
|
451
|
+
* approval, the EIP-712 payload to sign (or undefined when an existing allowance can be
|
|
452
|
+
* reused), and a `buildSwapTx(signature)` closure for the final swap tx.
|
|
453
|
+
*
|
|
454
|
+
* Integrator flow:
|
|
455
|
+
* const req = await client.swapWithPermit2(quote, owner, { slippageBps: 50 });
|
|
456
|
+
* if (req.permit2Approval) await signer.sendTransaction(req.permit2Approval); // once per token
|
|
457
|
+
* const sig = req.typedData
|
|
458
|
+
* ? await signer.signTypedData(req.typedData.domain, req.typedData.types, req.typedData.values)
|
|
459
|
+
* : "0x";
|
|
460
|
+
* await signer.sendTransaction(req.buildSwapTx(sig));
|
|
461
|
+
*/
|
|
462
|
+
async swapWithPermit2(e, t, n) {
|
|
463
|
+
if (e.srcNative)
|
|
464
|
+
throw new Error("Permit2 cannot be used for native-token input; use swapETH instead.");
|
|
465
|
+
const s = this.getRouterAddress(e);
|
|
466
|
+
this.assertUint160(e.amountIn);
|
|
467
|
+
const o = await this.buildPermit2TokenApproval(
|
|
468
|
+
e.srcToken,
|
|
469
|
+
t,
|
|
470
|
+
e.amountIn,
|
|
471
|
+
n
|
|
472
|
+
), r = await this.getPermit2Allowance(e.srcToken, t, s), a = Math.floor(Date.now() / 1e3), i = !o && r.amount >= e.amountIn && r.expiration > a;
|
|
473
|
+
let c, u;
|
|
474
|
+
i ? u = {
|
|
475
|
+
details: {
|
|
476
|
+
token: e.srcToken,
|
|
477
|
+
amount: r.amount,
|
|
478
|
+
expiration: r.expiration,
|
|
479
|
+
nonce: r.nonce
|
|
480
|
+
},
|
|
481
|
+
spender: s,
|
|
482
|
+
sigDeadline: 0n
|
|
483
|
+
} : (c = await this.buildPermit2TypedData(e, t, n), u = c.values);
|
|
484
|
+
const l = e.dstNative ? "swapETHWithPermit2" : "swapWithPermit2";
|
|
485
|
+
return {
|
|
486
|
+
routerAddress: s,
|
|
487
|
+
method: l,
|
|
488
|
+
permit2Approval: o,
|
|
489
|
+
typedData: c,
|
|
490
|
+
permitSingle: u,
|
|
491
|
+
buildSwapTx: (p) => {
|
|
492
|
+
const { to: A, data: w, value: v } = this.encodeSwapWithPermit2Calldata(
|
|
493
|
+
e,
|
|
494
|
+
n.slippageBps,
|
|
495
|
+
u,
|
|
496
|
+
p
|
|
497
|
+
);
|
|
498
|
+
return this.applyTxOverrides({ to: A, data: w, value: v }, n, !0);
|
|
499
|
+
}
|
|
500
|
+
};
|
|
352
501
|
}
|
|
353
|
-
|
|
354
|
-
|
|
502
|
+
assertUint160(e) {
|
|
503
|
+
if (e > $)
|
|
504
|
+
throw new Error(`amount ${e} exceeds Permit2 uint160 max`);
|
|
355
505
|
}
|
|
356
|
-
applyTxOverrides(e, t,
|
|
357
|
-
const
|
|
358
|
-
return t.gasPrice && (
|
|
506
|
+
applyTxOverrides(e, t, n) {
|
|
507
|
+
const s = { ...e };
|
|
508
|
+
return t.gasPrice && (s.gasPrice = t.gasPrice), n && t.gasLimit && (s.gasLimit = t.gasLimit), s;
|
|
359
509
|
}
|
|
360
|
-
async sendTransactionWithTimeout(e, t,
|
|
361
|
-
const
|
|
362
|
-
if (
|
|
510
|
+
async sendTransactionWithTimeout(e, t, n) {
|
|
511
|
+
const s = n.timeoutMs ?? G;
|
|
512
|
+
if (s <= 0)
|
|
363
513
|
return e.sendTransaction(t);
|
|
364
|
-
const
|
|
365
|
-
if (typeof
|
|
366
|
-
const r = await
|
|
367
|
-
|
|
368
|
-
|
|
514
|
+
const o = e;
|
|
515
|
+
if (typeof o.sendUncheckedTransaction == "function" && o.provider) {
|
|
516
|
+
const r = await W(
|
|
517
|
+
o.sendUncheckedTransaction(t),
|
|
518
|
+
s
|
|
369
519
|
), a = await this.waitForTransactionResponse(
|
|
370
|
-
|
|
520
|
+
o.provider,
|
|
371
521
|
r,
|
|
372
|
-
|
|
373
|
-
|
|
522
|
+
s,
|
|
523
|
+
n.transactionResponsePollingIntervalsMs
|
|
374
524
|
);
|
|
375
525
|
if (a.response)
|
|
376
526
|
return a.response;
|
|
377
527
|
const i = a.rpcErrors > 0 ? `${a.rpcErrors} transient provider error(s) and ${a.nullResponses} null response(s)` : `${a.nullResponses} null response(s)`;
|
|
378
|
-
throw new
|
|
379
|
-
`Transaction was broadcast but provider did not return TransactionResponse within ${
|
|
528
|
+
throw new Q(
|
|
529
|
+
`Transaction was broadcast but provider did not return TransactionResponse within ${s}ms (${i}).`,
|
|
380
530
|
"provider_index",
|
|
381
531
|
r
|
|
382
532
|
);
|
|
383
533
|
}
|
|
384
|
-
return
|
|
534
|
+
return W(e.sendTransaction(t), s);
|
|
385
535
|
}
|
|
386
|
-
async waitForTransactionResponse(e, t,
|
|
387
|
-
const
|
|
536
|
+
async waitForTransactionResponse(e, t, n, s = M) {
|
|
537
|
+
const o = Date.now() + n;
|
|
388
538
|
let r = 0, a = 0, i = 0;
|
|
389
|
-
for (; Date.now() <
|
|
539
|
+
for (; Date.now() < o; ) {
|
|
390
540
|
try {
|
|
391
541
|
const u = await e.getTransaction(t);
|
|
392
542
|
if (u)
|
|
@@ -395,8 +545,8 @@ class K {
|
|
|
395
545
|
} catch {
|
|
396
546
|
i++;
|
|
397
547
|
}
|
|
398
|
-
const c = this.getNextPollingDelay(
|
|
399
|
-
r++, await this.delay(Math.min(c, Math.max(25,
|
|
548
|
+
const c = this.getNextPollingDelay(s, r);
|
|
549
|
+
r++, await this.delay(Math.min(c, Math.max(25, o - Date.now())));
|
|
400
550
|
}
|
|
401
551
|
return { response: null, nullResponses: a, rpcErrors: i };
|
|
402
552
|
}
|
|
@@ -406,24 +556,24 @@ class K {
|
|
|
406
556
|
});
|
|
407
557
|
}
|
|
408
558
|
getNextPollingDelay(e, t) {
|
|
409
|
-
return e.length === 0 ?
|
|
559
|
+
return e.length === 0 ? M.at(-1) ?? 1200 : e[Math.min(t, e.length - 1)] ?? 1200;
|
|
410
560
|
}
|
|
411
561
|
/**
|
|
412
562
|
* Get token metadata and, optionally, the balance for a specific owner.
|
|
413
563
|
*/
|
|
414
564
|
async getTokenInfo(e, t) {
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
t ?
|
|
565
|
+
const n = new m.Contract(e, b, this.provider), [s, o, r] = await Promise.all([
|
|
566
|
+
n.symbol(),
|
|
567
|
+
n.decimals(),
|
|
568
|
+
t ? n.balanceOf(t) : Promise.resolve(void 0)
|
|
419
569
|
]);
|
|
420
|
-
return r === void 0 ? { symbol:
|
|
570
|
+
return r === void 0 ? { symbol: s, decimals: o } : { symbol: s, decimals: o, balance: r };
|
|
421
571
|
}
|
|
422
572
|
/**
|
|
423
573
|
* Get user token balance
|
|
424
574
|
*/
|
|
425
575
|
async getBalance(e, t) {
|
|
426
|
-
return new
|
|
576
|
+
return new m.Contract(e, b, this.provider).balanceOf(t);
|
|
427
577
|
}
|
|
428
578
|
/**
|
|
429
579
|
* Get quote via API
|
|
@@ -431,22 +581,22 @@ class K {
|
|
|
431
581
|
* @throws CustomFeeError if `options.customFee` is malformed
|
|
432
582
|
*/
|
|
433
583
|
async getQuote(e) {
|
|
434
|
-
const { srcToken: t, dstToken:
|
|
584
|
+
const { srcToken: t, dstToken: n, amountIn: s, options: o = {} } = e, {
|
|
435
585
|
byAmountIn: r = !0,
|
|
436
|
-
depth: a =
|
|
437
|
-
splitCount: i =
|
|
438
|
-
providers: c =
|
|
439
|
-
deadlineSeconds: u =
|
|
440
|
-
includeResponseHeaders:
|
|
586
|
+
depth: a = E.depth,
|
|
587
|
+
splitCount: i = E.splitCount,
|
|
588
|
+
providers: c = E.providers,
|
|
589
|
+
deadlineSeconds: u = N,
|
|
590
|
+
includeResponseHeaders: l = !1,
|
|
441
591
|
customFee: p
|
|
442
|
-
} =
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
if (
|
|
446
|
-
const { data:
|
|
592
|
+
} = o;
|
|
593
|
+
C.validateCustomFee(p);
|
|
594
|
+
const A = T(t), w = T(n), v = A ? this.config.weth : t, g = w ? this.config.weth : n;
|
|
595
|
+
if (l) {
|
|
596
|
+
const { data: k, responseHeaders: x } = await this.apiClient.findRoutes({
|
|
447
597
|
from: v,
|
|
448
|
-
target:
|
|
449
|
-
amount:
|
|
598
|
+
target: g,
|
|
599
|
+
amount: s,
|
|
450
600
|
byAmountIn: r,
|
|
451
601
|
depth: a,
|
|
452
602
|
splitCount: i,
|
|
@@ -454,34 +604,34 @@ class K {
|
|
|
454
604
|
includeResponseHeaders: !0
|
|
455
605
|
});
|
|
456
606
|
return this.buildQuoteFromApi(
|
|
457
|
-
|
|
607
|
+
k,
|
|
458
608
|
v,
|
|
459
|
-
|
|
609
|
+
g,
|
|
460
610
|
u,
|
|
461
611
|
c,
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
612
|
+
A,
|
|
613
|
+
w,
|
|
614
|
+
x,
|
|
465
615
|
p
|
|
466
616
|
);
|
|
467
617
|
}
|
|
468
|
-
const
|
|
618
|
+
const P = await this.apiClient.findRoutes({
|
|
469
619
|
from: v,
|
|
470
|
-
target:
|
|
471
|
-
amount:
|
|
620
|
+
target: g,
|
|
621
|
+
amount: s,
|
|
472
622
|
byAmountIn: r,
|
|
473
623
|
depth: a,
|
|
474
624
|
splitCount: i,
|
|
475
625
|
providers: c
|
|
476
626
|
});
|
|
477
627
|
return this.buildQuoteFromApi(
|
|
478
|
-
|
|
628
|
+
P,
|
|
479
629
|
v,
|
|
480
|
-
|
|
630
|
+
g,
|
|
481
631
|
u,
|
|
482
632
|
c,
|
|
483
|
-
|
|
484
|
-
|
|
633
|
+
A,
|
|
634
|
+
w,
|
|
485
635
|
void 0,
|
|
486
636
|
p
|
|
487
637
|
);
|
|
@@ -492,17 +642,17 @@ class K {
|
|
|
492
642
|
*/
|
|
493
643
|
static validateCustomFee(e) {
|
|
494
644
|
if (!e) return;
|
|
495
|
-
const { feeAccount: t, feeBps:
|
|
496
|
-
if (!Number.isInteger(
|
|
497
|
-
throw new
|
|
498
|
-
`customFee.feeBps must be an integer in [1, ${
|
|
645
|
+
const { feeAccount: t, feeBps: n } = e;
|
|
646
|
+
if (!Number.isInteger(n) || n < 1 || n > U)
|
|
647
|
+
throw new B(
|
|
648
|
+
`customFee.feeBps must be an integer in [1, ${U}] (5%), got ${n}`
|
|
499
649
|
);
|
|
500
|
-
if (!t || !
|
|
501
|
-
throw new
|
|
650
|
+
if (!t || !m.isAddress(t))
|
|
651
|
+
throw new B(
|
|
502
652
|
`customFee.feeAccount must be a valid address, got ${t}`
|
|
503
653
|
);
|
|
504
|
-
if (t ===
|
|
505
|
-
throw new
|
|
654
|
+
if (t === m.ZeroAddress)
|
|
655
|
+
throw new B("customFee.feeAccount must not be the zero address");
|
|
506
656
|
}
|
|
507
657
|
/**
|
|
508
658
|
* Resolve the router address for read methods: argument → quote.routerAddress →
|
|
@@ -511,7 +661,7 @@ class K {
|
|
|
511
661
|
*/
|
|
512
662
|
resolveRouterAddress(e) {
|
|
513
663
|
const t = e ?? this.config.routerAddress;
|
|
514
|
-
if (!t || t ===
|
|
664
|
+
if (!t || t === m.ZeroAddress)
|
|
515
665
|
throw new Error(
|
|
516
666
|
"No router address available. Pass one explicitly or set config.routerAddress."
|
|
517
667
|
);
|
|
@@ -529,13 +679,13 @@ class K {
|
|
|
529
679
|
* Pass an explicit address when reading from a different deployment.
|
|
530
680
|
*/
|
|
531
681
|
async getProtocolFeeConfig(e) {
|
|
532
|
-
const t = this.resolveRouterAddress(e),
|
|
533
|
-
|
|
534
|
-
|
|
682
|
+
const t = this.resolveRouterAddress(e), n = new m.Contract(t, R, this.provider), [s, o] = await Promise.all([
|
|
683
|
+
n.protocolFeeReceiver(),
|
|
684
|
+
n.protocolCutBps()
|
|
535
685
|
]);
|
|
536
686
|
return {
|
|
537
|
-
protocolFeeReceiver:
|
|
538
|
-
protocolCutBps: Number(
|
|
687
|
+
protocolFeeReceiver: s,
|
|
688
|
+
protocolCutBps: Number(o)
|
|
539
689
|
};
|
|
540
690
|
}
|
|
541
691
|
/**
|
|
@@ -564,36 +714,36 @@ class K {
|
|
|
564
714
|
* @param routerAddress Optional router address. Defaults to `config.routerAddress`.
|
|
565
715
|
*/
|
|
566
716
|
async getRouterConfig(e) {
|
|
567
|
-
const t = this.resolveRouterAddress(e),
|
|
568
|
-
n,
|
|
717
|
+
const t = this.resolveRouterAddress(e), n = new m.Contract(t, R, this.provider), [
|
|
569
718
|
s,
|
|
719
|
+
o,
|
|
570
720
|
r,
|
|
571
721
|
a,
|
|
572
722
|
i,
|
|
573
723
|
c,
|
|
574
724
|
u,
|
|
575
|
-
|
|
725
|
+
l
|
|
576
726
|
] = await Promise.all([
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
727
|
+
n.WETH(),
|
|
728
|
+
n.owner(),
|
|
729
|
+
n.pendingOwner(),
|
|
730
|
+
n.paused(),
|
|
731
|
+
n.maxCustomFeeBps(),
|
|
732
|
+
n.maxProtocolCutBps(),
|
|
733
|
+
n.protocolFeeReceiver(),
|
|
734
|
+
n.protocolCutBps()
|
|
585
735
|
]);
|
|
586
736
|
return {
|
|
587
737
|
address: t,
|
|
588
|
-
weth:
|
|
589
|
-
owner:
|
|
738
|
+
weth: s,
|
|
739
|
+
owner: o,
|
|
590
740
|
pendingOwner: r,
|
|
591
741
|
paused: !!a,
|
|
592
742
|
maxCustomFeeBps: Number(i),
|
|
593
743
|
maxProtocolCutBps: Number(c),
|
|
594
744
|
protocolFee: {
|
|
595
745
|
protocolFeeReceiver: u,
|
|
596
|
-
protocolCutBps: Number(
|
|
746
|
+
protocolCutBps: Number(l)
|
|
597
747
|
}
|
|
598
748
|
};
|
|
599
749
|
}
|
|
@@ -601,12 +751,12 @@ class K {
|
|
|
601
751
|
* Filter paths by allowed providers, removing paths with disallowed providers
|
|
602
752
|
* and cascade-removing orphaned paths that depend on removed paths.
|
|
603
753
|
*/
|
|
604
|
-
filterPathsByProviders(e, t,
|
|
605
|
-
const
|
|
606
|
-
let r = e.filter((p) =>
|
|
754
|
+
filterPathsByProviders(e, t, n, s) {
|
|
755
|
+
const o = new Set(t.map((p) => p.toUpperCase()));
|
|
756
|
+
let r = e.filter((p) => o.has(p.provider.toUpperCase()));
|
|
607
757
|
if (r.length === e.length)
|
|
608
758
|
return r;
|
|
609
|
-
const a =
|
|
759
|
+
const a = n.toLowerCase(), i = s.toLowerCase(), c = /* @__PURE__ */ new Set();
|
|
610
760
|
c.add(a);
|
|
611
761
|
let u = !0;
|
|
612
762
|
for (; u; ) {
|
|
@@ -614,14 +764,14 @@ class K {
|
|
|
614
764
|
for (const p of r)
|
|
615
765
|
c.has(p.token_in.toLowerCase()) && !c.has(p.token_out.toLowerCase()) && (c.add(p.token_out.toLowerCase()), u = !0);
|
|
616
766
|
}
|
|
617
|
-
const
|
|
618
|
-
for (
|
|
767
|
+
const l = /* @__PURE__ */ new Set();
|
|
768
|
+
for (l.add(i), u = !0; u; ) {
|
|
619
769
|
u = !1;
|
|
620
770
|
for (const p of r)
|
|
621
|
-
|
|
771
|
+
l.has(p.token_out.toLowerCase()) && !l.has(p.token_in.toLowerCase()) && (l.add(p.token_in.toLowerCase()), u = !0);
|
|
622
772
|
}
|
|
623
773
|
return r.length, r = r.filter(
|
|
624
|
-
(p) => c.has(p.token_in.toLowerCase()) &&
|
|
774
|
+
(p) => c.has(p.token_in.toLowerCase()) && l.has(p.token_out.toLowerCase())
|
|
625
775
|
), r;
|
|
626
776
|
}
|
|
627
777
|
/**
|
|
@@ -633,77 +783,77 @@ class K {
|
|
|
633
783
|
* @param dstToken - Destination token address (last path token_out)
|
|
634
784
|
* @param deadlineSeconds - Optional deadline in seconds from now (default: 20 min)
|
|
635
785
|
*/
|
|
636
|
-
buildQuoteFromRouteData(e, t,
|
|
786
|
+
buildQuoteFromRouteData(e, t, n, s, o) {
|
|
637
787
|
const r = this.buildQuoteFromRouteDataInternal(
|
|
638
788
|
e,
|
|
639
789
|
t,
|
|
640
|
-
|
|
641
|
-
|
|
790
|
+
n,
|
|
791
|
+
s ?? N,
|
|
642
792
|
void 0
|
|
643
793
|
);
|
|
644
|
-
return
|
|
794
|
+
return o?.srcNative && (r.srcNative = !0), o?.dstNative && (r.dstNative = !0), r;
|
|
645
795
|
}
|
|
646
796
|
/**
|
|
647
797
|
* Build Quote from API response
|
|
648
798
|
*/
|
|
649
|
-
buildQuoteFromApi(e, t,
|
|
799
|
+
buildQuoteFromApi(e, t, n, s, o, r, a, i, c) {
|
|
650
800
|
const u = this.buildQuoteFromRouteDataInternal(
|
|
651
801
|
e,
|
|
652
802
|
t,
|
|
653
|
-
o,
|
|
654
803
|
n,
|
|
655
804
|
s,
|
|
805
|
+
o,
|
|
656
806
|
c
|
|
657
807
|
);
|
|
658
808
|
return r && (u.srcNative = !0), a && (u.dstNative = !0), i && (u.responseHeaders = i), u;
|
|
659
809
|
}
|
|
660
|
-
buildQuoteFromRouteDataInternal(e, t,
|
|
810
|
+
buildQuoteFromRouteDataInternal(e, t, n, s, o, r) {
|
|
661
811
|
const a = t.toLowerCase();
|
|
662
812
|
e.paths.length;
|
|
663
813
|
let i = e.paths.filter((h) => !(!(h.token_in.toLowerCase() === a) && BigInt(h.amount_in) === 0n && BigInt(h.amount_out) === 0n));
|
|
664
814
|
if (i.length === 0)
|
|
665
|
-
throw new
|
|
666
|
-
if (
|
|
667
|
-
throw new
|
|
668
|
-
const c =
|
|
669
|
-
let u = 0n,
|
|
815
|
+
throw new S("All route paths have zero amounts", 4001);
|
|
816
|
+
if (o && o.length > 0 && (i = this.filterPathsByProviders(i, o, t, n), i.length === 0))
|
|
817
|
+
throw new S("No valid route paths remaining after provider filtering", 4001);
|
|
818
|
+
const c = n.toLowerCase();
|
|
819
|
+
let u = 0n, l = 0n;
|
|
670
820
|
for (const h of i)
|
|
671
|
-
h.token_in.toLowerCase() === a && (u += BigInt(h.amount_in)), h.token_out.toLowerCase() === c && (
|
|
821
|
+
h.token_in.toLowerCase() === a && (u += BigInt(h.amount_in)), h.token_out.toLowerCase() === c && (l += BigInt(h.amount_out));
|
|
672
822
|
const p = BigInt(
|
|
673
|
-
Math.floor(Date.now() / 1e3) +
|
|
674
|
-
),
|
|
823
|
+
Math.floor(Date.now() / 1e3) + s
|
|
824
|
+
), A = /* @__PURE__ */ new Map();
|
|
675
825
|
for (const h of i) {
|
|
676
826
|
const I = h.token_in.toLowerCase();
|
|
677
|
-
|
|
827
|
+
A.set(I, (A.get(I) ?? 0) + 1);
|
|
678
828
|
}
|
|
679
|
-
const
|
|
680
|
-
const I = h.token_in.toLowerCase(),
|
|
681
|
-
|
|
682
|
-
const
|
|
829
|
+
const w = /* @__PURE__ */ new Map(), v = i.map((h) => {
|
|
830
|
+
const I = h.token_in.toLowerCase(), V = (w.get(I) ?? 0) + 1;
|
|
831
|
+
w.set(I, V);
|
|
832
|
+
const L = A.get(I), z = L > 1 && V < L, X = I === a;
|
|
683
833
|
return {
|
|
684
834
|
adapter: h.adapter,
|
|
685
|
-
pool: h.provider.toUpperCase() === "PANCAKE_INFINITY_CL" ?
|
|
835
|
+
pool: h.provider.toUpperCase() === "PANCAKE_INFINITY_CL" ? oe : h.provider.toUpperCase() === "PANCAKE_INFINITY_LB" ? ae : h.provider.toUpperCase() === "UNISWAPV4" ? ie : h.pool,
|
|
686
836
|
tokenIn: h.token_in,
|
|
687
837
|
tokenOut: h.token_out,
|
|
688
|
-
amountIn:
|
|
838
|
+
amountIn: X || z ? BigInt(h.amount_in) : 0n,
|
|
689
839
|
extraData: h.extra_data || "0x"
|
|
690
840
|
};
|
|
691
|
-
}),
|
|
841
|
+
}), g = /* @__PURE__ */ new Set();
|
|
692
842
|
for (const h of i)
|
|
693
|
-
h.token_out.toLowerCase() !== c &&
|
|
694
|
-
const
|
|
843
|
+
h.token_out.toLowerCase() !== c && g.add(h.token_out);
|
|
844
|
+
const P = Array.from(g), k = r?.feeBps ?? 0, x = r?.feeAccount ?? m.ZeroAddress, D = l, F = k > 0 ? D * BigInt(k) / _ : 0n, y = D - F, Z = {
|
|
695
845
|
srcToken: t,
|
|
696
|
-
dstToken:
|
|
846
|
+
dstToken: n,
|
|
697
847
|
amountIn: u,
|
|
698
|
-
amountOutMin:
|
|
848
|
+
amountOutMin: y,
|
|
699
849
|
steps: v,
|
|
700
|
-
intermediateTokens:
|
|
850
|
+
intermediateTokens: P,
|
|
701
851
|
deadline: p,
|
|
702
|
-
quoteId: e.request_id ?
|
|
703
|
-
expectAmountOut:
|
|
704
|
-
feeReceiver:
|
|
705
|
-
feeBps:
|
|
706
|
-
},
|
|
852
|
+
quoteId: e.request_id ? m.id(e.request_id).slice(0, 66) : m.ZeroHash,
|
|
853
|
+
expectAmountOut: y,
|
|
854
|
+
feeReceiver: x,
|
|
855
|
+
feeBps: k
|
|
856
|
+
}, j = {
|
|
707
857
|
routes: [
|
|
708
858
|
{
|
|
709
859
|
steps: i.map((h) => ({
|
|
@@ -720,32 +870,32 @@ class K {
|
|
|
720
870
|
amountOut: BigInt(h.amount_out)
|
|
721
871
|
})),
|
|
722
872
|
amountIn: u,
|
|
723
|
-
amountOut:
|
|
873
|
+
amountOut: l,
|
|
724
874
|
gasEstimate: BigInt(e.gas)
|
|
725
875
|
}
|
|
726
876
|
],
|
|
727
877
|
percentages: [1e4],
|
|
728
878
|
totalAmountIn: u,
|
|
729
|
-
totalAmountOut:
|
|
879
|
+
totalAmountOut: l,
|
|
730
880
|
totalGasEstimate: BigInt(e.gas)
|
|
731
881
|
};
|
|
732
882
|
if (!e.contracts?.router)
|
|
733
|
-
throw new
|
|
883
|
+
throw new S("API response missing contracts.router address", 4002);
|
|
734
884
|
return {
|
|
735
885
|
srcToken: t,
|
|
736
|
-
dstToken:
|
|
886
|
+
dstToken: n,
|
|
737
887
|
amountIn: u,
|
|
738
888
|
// Quote.amountOut reflects the user-perceived output (post custom fee).
|
|
739
889
|
// Wallets / UIs should display this number; the gross figure is at route.totalAmountOut.
|
|
740
|
-
amountOut:
|
|
890
|
+
amountOut: y,
|
|
741
891
|
priceImpact: parseFloat(e.deviation_ratio || "0"),
|
|
742
|
-
route:
|
|
743
|
-
params:
|
|
892
|
+
route: j,
|
|
893
|
+
params: Z,
|
|
744
894
|
gasEstimate: BigInt(e.gas),
|
|
745
895
|
routerAddress: e.contracts?.router,
|
|
746
|
-
customFee:
|
|
747
|
-
feeAccount:
|
|
748
|
-
feeBps:
|
|
896
|
+
customFee: k > 0 ? {
|
|
897
|
+
feeAccount: x,
|
|
898
|
+
feeBps: k,
|
|
749
899
|
feeAmount: F
|
|
750
900
|
} : void 0
|
|
751
901
|
};
|
|
@@ -767,23 +917,23 @@ class K {
|
|
|
767
917
|
* @param stateOverrides - Optional state overrides for ERC20 balance/allowance
|
|
768
918
|
* @returns Simulated amountOut and method used
|
|
769
919
|
*/
|
|
770
|
-
async simulate(e, t,
|
|
771
|
-
const
|
|
772
|
-
if (
|
|
773
|
-
const u = this.getJsonRpcProviderForStateOverrides(),
|
|
774
|
-
{ from:
|
|
920
|
+
async simulate(e, t, n, s) {
|
|
921
|
+
const o = n || m.ZeroAddress, { to: r, data: a, value: i, method: c } = this.encodeSwapCalldata(e, t);
|
|
922
|
+
if (s) {
|
|
923
|
+
const u = this.getJsonRpcProviderForStateOverrides(), l = i > 0n ? "0x" + i.toString(16) : void 0, p = await u.send("eth_call", [
|
|
924
|
+
{ from: o, to: r, data: a, value: l },
|
|
775
925
|
"latest",
|
|
776
|
-
|
|
777
|
-
]), [
|
|
778
|
-
return { amountOut:
|
|
926
|
+
s
|
|
927
|
+
]), [A] = this.routerContract.interface.decodeFunctionResult(c, p);
|
|
928
|
+
return { amountOut: A, method: c };
|
|
779
929
|
} else {
|
|
780
930
|
const u = await this.provider.call({
|
|
781
|
-
from:
|
|
931
|
+
from: o,
|
|
782
932
|
to: r,
|
|
783
933
|
data: a,
|
|
784
934
|
value: i > 0n ? i : void 0
|
|
785
|
-
}), [
|
|
786
|
-
return { amountOut:
|
|
935
|
+
}), [l] = this.routerContract.interface.decodeFunctionResult(c, u);
|
|
936
|
+
return { amountOut: l, method: c };
|
|
787
937
|
}
|
|
788
938
|
}
|
|
789
939
|
getJsonRpcProviderForStateOverrides() {
|
|
@@ -796,92 +946,167 @@ class K {
|
|
|
796
946
|
/**
|
|
797
947
|
* Format simulate error with human-readable details
|
|
798
948
|
*/
|
|
799
|
-
formatSimulateError(e, t,
|
|
800
|
-
const
|
|
949
|
+
formatSimulateError(e, t, n, s) {
|
|
950
|
+
const o = e instanceof Error ? e : new Error(String(e)), r = e;
|
|
801
951
|
let a = "unknown";
|
|
802
952
|
if (r.reason && typeof r.reason == "string")
|
|
803
953
|
a = r.reason;
|
|
804
954
|
else if (r.revert && typeof r.revert == "object") {
|
|
805
|
-
const
|
|
806
|
-
|
|
807
|
-
} else
|
|
955
|
+
const l = r.revert;
|
|
956
|
+
l.args && Array.isArray(l.args) && (a = l.args.join(", "));
|
|
957
|
+
} else o.message && (a = o.message);
|
|
808
958
|
const i = t.params.steps.map(
|
|
809
|
-
(
|
|
959
|
+
(l, p) => ` Step ${p}: ${l.tokenIn.slice(0, 10)}→${l.tokenOut.slice(0, 10)} via adapter ${l.adapter.slice(0, 10)} pool ${l.pool.slice(0, 10)}`
|
|
810
960
|
).join(`
|
|
811
961
|
`), c = [
|
|
812
|
-
`Simulate ${
|
|
962
|
+
`Simulate ${n} failed: ${a}`,
|
|
813
963
|
` Route: ${t.srcToken} → ${t.dstToken}`,
|
|
814
964
|
` AmountIn: ${t.amountIn}`,
|
|
815
965
|
` AmountOutMin: ${t.params.amountOutMin}`,
|
|
816
966
|
` Router: ${t.routerAddress}`,
|
|
817
|
-
` Caller: ${
|
|
967
|
+
` Caller: ${s}`,
|
|
818
968
|
` Steps (${t.params.steps.length}):`,
|
|
819
969
|
i
|
|
820
970
|
].join(`
|
|
821
971
|
`), u = new Error(c);
|
|
822
|
-
return u.cause =
|
|
972
|
+
return u.cause = o, u.reason = a, u;
|
|
823
973
|
}
|
|
824
974
|
/**
|
|
825
|
-
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
975
|
+
* Pinpoint the first problematic step in a route.
|
|
976
|
+
*
|
|
977
|
+
* For each prefix [0..n), builds a rebased truncated quote (dstToken = last
|
|
978
|
+
* step's tokenOut, amountOutMin/expectAmountOut/customFee zeroed) and simulates it:
|
|
979
|
+
*
|
|
980
|
+
* - If the prefix REVERTS, that prefix's final step is the culprit. When a
|
|
981
|
+
* `fullRouteError` is supplied we only return when the prefix's revert
|
|
982
|
+
* matches the full-route reason; otherwise any revert qualifies.
|
|
983
|
+
* - If the prefix succeeds but its output is materially smaller than the
|
|
984
|
+
* aggregator's per-hop quoted amountOut, that step is flagged as the
|
|
985
|
+
* first deviator. This catches silent failures like transfer-tax tokens
|
|
986
|
+
* where simulation doesn't revert mid-route but cumulative shortfall
|
|
987
|
+
* eventually trips the final InsufficientOutput check.
|
|
828
988
|
*
|
|
829
989
|
* @param quote - Full quote from getQuote (the one that fails when simulated)
|
|
830
990
|
* @param slippageBps - Same as for simulate
|
|
831
991
|
* @param fromAddress - Same as for simulate
|
|
832
992
|
* @param stateOverrides - Same as for simulate (use when simulating ERC20 sell with arbitrary address)
|
|
833
|
-
* @param fullRouteError -
|
|
834
|
-
* @
|
|
993
|
+
* @param fullRouteError - Optional: the error from simulating the full route. If provided, prefix reverts whose reason differs are skipped (useful for MUL_ERROR-style targeted matching).
|
|
994
|
+
* @param deviationThresholdBps - Maximum tolerated per-step shortfall vs quoted amountOut before flagging the step (default 50 = 0.5%).
|
|
995
|
+
* @returns The first step matching the criteria above, or null if every prefix simulates within tolerance.
|
|
835
996
|
*/
|
|
836
|
-
async findFailingStep(e, t,
|
|
837
|
-
const
|
|
838
|
-
if (!
|
|
839
|
-
const
|
|
840
|
-
for (let
|
|
841
|
-
const
|
|
997
|
+
async findFailingStep(e, t, n, s, o, r = 50) {
|
|
998
|
+
const a = e.params.steps;
|
|
999
|
+
if (!a.length) return null;
|
|
1000
|
+
const i = o != null ? this.normalizeRevertReason(o) : void 0;
|
|
1001
|
+
for (let c = 1; c <= a.length; c++) {
|
|
1002
|
+
const u = this.buildTruncatedQuote(e, c);
|
|
1003
|
+
let l, p;
|
|
842
1004
|
try {
|
|
843
|
-
await this.simulate(
|
|
844
|
-
} catch (
|
|
845
|
-
|
|
846
|
-
|
|
1005
|
+
l = (await this.simulate(u, t, n, s)).amountOut;
|
|
1006
|
+
} catch (g) {
|
|
1007
|
+
p = g;
|
|
1008
|
+
}
|
|
1009
|
+
if (p !== void 0) {
|
|
1010
|
+
const g = this.normalizeRevertReason(p), P = p?.shortMessage ?? p?.reason ?? p?.message;
|
|
1011
|
+
if (i == null || g === i)
|
|
847
1012
|
return {
|
|
848
|
-
stepIndex:
|
|
849
|
-
step:
|
|
850
|
-
error:
|
|
851
|
-
revertMessage: typeof
|
|
852
|
-
fullRouteRevertMessage:
|
|
1013
|
+
stepIndex: c - 1,
|
|
1014
|
+
step: a[c - 1],
|
|
1015
|
+
error: p,
|
|
1016
|
+
revertMessage: typeof P == "string" ? P : g,
|
|
1017
|
+
fullRouteRevertMessage: i
|
|
853
1018
|
};
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
if (l === void 0) continue;
|
|
1022
|
+
const A = this.getQuotedStepAmountOut(e, c - 1);
|
|
1023
|
+
if (A === void 0 || A === 0n) continue;
|
|
1024
|
+
const w = A > l ? A - l : 0n;
|
|
1025
|
+
if (w === 0n) continue;
|
|
1026
|
+
const v = w * _ / A;
|
|
1027
|
+
if (v > BigInt(r)) {
|
|
1028
|
+
const g = `Step ${c - 1} deviates: quoted=${A} simulated=${l} shortfall=${w} (${v}bps, threshold=${r}bps). Likely cause: transfer-tax on ${a[c - 1].tokenOut}, stale pool data, or dynamic-fee drift.`;
|
|
1029
|
+
return {
|
|
1030
|
+
stepIndex: c - 1,
|
|
1031
|
+
step: a[c - 1],
|
|
1032
|
+
error: new Error(g),
|
|
1033
|
+
revertMessage: g,
|
|
1034
|
+
fullRouteRevertMessage: i
|
|
1035
|
+
};
|
|
854
1036
|
}
|
|
855
1037
|
}
|
|
856
1038
|
return null;
|
|
857
1039
|
}
|
|
858
|
-
/** Extract a comparable revert reason (e.g. "MUL_ERROR") from an error
|
|
1040
|
+
/** Extract a comparable revert reason (e.g. "MUL_ERROR", "InsufficientOutput", "0xc956d868") from an error. */
|
|
859
1041
|
normalizeRevertReason(e) {
|
|
860
1042
|
if (e == null) return;
|
|
861
1043
|
const t = e;
|
|
862
1044
|
if (typeof t.reason == "string" && t.reason.length > 0) return t.reason;
|
|
863
|
-
const
|
|
864
|
-
if (
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1045
|
+
const n = this.extractRevertData(e);
|
|
1046
|
+
if (n && n.length >= 10) {
|
|
1047
|
+
const c = n.slice(0, 10).toLowerCase();
|
|
1048
|
+
return C.KNOWN_ERROR_SELECTORS[c] ?? c;
|
|
1049
|
+
}
|
|
1050
|
+
const s = t.shortMessage ?? t.message;
|
|
1051
|
+
if (typeof s != "string") return;
|
|
1052
|
+
const o = s.match(/reason="([^"]+)"/);
|
|
1053
|
+
if (o) return o[1];
|
|
1054
|
+
const r = s.match(/reverted:\s*"([^"]+)"/);
|
|
870
1055
|
if (r) return r[1];
|
|
1056
|
+
const a = s.match(/execution reverted:\s*"([^"]+)"/);
|
|
1057
|
+
if (a) return a[1];
|
|
1058
|
+
const i = s.match(/\b0x[0-9a-fA-F]{8}\b/);
|
|
1059
|
+
if (i) {
|
|
1060
|
+
const c = i[0].toLowerCase();
|
|
1061
|
+
return C.KNOWN_ERROR_SELECTORS[c] ?? c;
|
|
1062
|
+
}
|
|
871
1063
|
}
|
|
872
|
-
/**
|
|
873
|
-
|
|
874
|
-
const
|
|
875
|
-
for (
|
|
876
|
-
const
|
|
877
|
-
|
|
1064
|
+
/** Walk an error object (including nested `info`/`error`/`cause`/`revert`) for the first hex revert-data blob. */
|
|
1065
|
+
extractRevertData(e) {
|
|
1066
|
+
const t = /* @__PURE__ */ new Set(), n = [e];
|
|
1067
|
+
for (; n.length; ) {
|
|
1068
|
+
const s = n.shift();
|
|
1069
|
+
if (s == null || typeof s != "object" || t.has(s)) continue;
|
|
1070
|
+
t.add(s);
|
|
1071
|
+
const o = s, r = o.data;
|
|
1072
|
+
if (typeof r == "string" && /^0x[0-9a-fA-F]{8,}$/.test(r)) return r;
|
|
1073
|
+
for (const a of ["info", "error", "cause", "revert", "originalError"])
|
|
1074
|
+
o[a] && n.push(o[a]);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
/** Read the aggregator's quoted per-step amountOut from the quote's flattened route. */
|
|
1078
|
+
getQuotedStepAmountOut(e, t) {
|
|
1079
|
+
return e.route?.routes?.[0]?.steps?.[t]?.amountOut;
|
|
1080
|
+
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Build a quote that simulates only the first `stepCount` steps by rebasing
|
|
1083
|
+
* dstToken to the last included step's tokenOut and zeroing all output
|
|
1084
|
+
* constraints (amountOutMin/expectAmountOut/customFee). Without this rebase
|
|
1085
|
+
* the truncated call would always revert — the router would expect the
|
|
1086
|
+
* original dstToken to arrive, which never happens for an intermediate prefix.
|
|
1087
|
+
*/
|
|
1088
|
+
buildTruncatedQuote(e, t) {
|
|
1089
|
+
const n = e.params.steps.slice(0, t), o = n[n.length - 1].tokenOut, r = o.toLowerCase(), a = e.srcToken.toLowerCase(), i = t === e.params.steps.length, c = /* @__PURE__ */ new Set(), u = [];
|
|
1090
|
+
for (const l of n) {
|
|
1091
|
+
const p = l.tokenOut.toLowerCase();
|
|
1092
|
+
p === r || p === a || c.has(p) || (c.add(p), u.push(l.tokenOut));
|
|
878
1093
|
}
|
|
879
1094
|
return {
|
|
880
1095
|
...e,
|
|
1096
|
+
dstToken: o,
|
|
1097
|
+
// Native unwrap only makes sense when we're simulating the true dstToken.
|
|
1098
|
+
dstNative: i ? e.dstNative : !1,
|
|
1099
|
+
amountOut: i ? e.amountOut : 0n,
|
|
1100
|
+
customFee: i ? e.customFee : void 0,
|
|
881
1101
|
params: {
|
|
882
1102
|
...e.params,
|
|
883
|
-
|
|
884
|
-
|
|
1103
|
+
dstToken: o,
|
|
1104
|
+
amountOutMin: i ? e.params.amountOutMin : 0n,
|
|
1105
|
+
expectAmountOut: i ? e.params.expectAmountOut : 0n,
|
|
1106
|
+
feeReceiver: i ? e.params.feeReceiver : m.ZeroAddress,
|
|
1107
|
+
feeBps: i ? e.params.feeBps : 0,
|
|
1108
|
+
steps: n,
|
|
1109
|
+
intermediateTokens: u
|
|
885
1110
|
}
|
|
886
1111
|
};
|
|
887
1112
|
}
|
|
@@ -902,68 +1127,72 @@ class K {
|
|
|
902
1127
|
* @param balance - Balance to inject (default: 1M tokens with 18 decimals)
|
|
903
1128
|
* @param spenderAddress - Spender to approve (default: routerAddress). Pass quote.routerAddress when simulating API quotes.
|
|
904
1129
|
*/
|
|
905
|
-
buildStateOverrides(e, t,
|
|
906
|
-
if (r?.isNative ||
|
|
1130
|
+
buildStateOverrides(e, t, n, s, o, r) {
|
|
1131
|
+
if (r?.isNative || T(e))
|
|
907
1132
|
return {};
|
|
908
|
-
if (!
|
|
1133
|
+
if (!n || n === m.ZeroAddress)
|
|
909
1134
|
throw new Error("buildStateOverrides requires a non-zero routerAddress.");
|
|
910
|
-
const a =
|
|
911
|
-
for (const
|
|
912
|
-
const v =
|
|
1135
|
+
const a = m.AbiCoder.defaultAbiCoder(), i = s || m.parseUnits("1000000", 18), c = o ?? n, u = m.zeroPadValue(m.toBeHex(i), 32), l = m.zeroPadValue(m.toBeHex(m.MaxUint256), 32), p = {}, A = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 50, 51, 52, 100, 101, 102];
|
|
1136
|
+
for (const w of A) {
|
|
1137
|
+
const v = m.keccak256(a.encode(["address", "uint256"], [t, w]));
|
|
913
1138
|
p[v] = u;
|
|
914
|
-
const
|
|
915
|
-
p[
|
|
1139
|
+
const g = m.keccak256(a.encode(["address", "uint256"], [t, w])), P = m.keccak256(a.encode(["address", "bytes32"], [c, g]));
|
|
1140
|
+
p[P] = l;
|
|
916
1141
|
}
|
|
917
1142
|
return {
|
|
918
1143
|
[e.toLowerCase()]: { stateDiff: p }
|
|
919
1144
|
};
|
|
920
1145
|
}
|
|
921
|
-
}
|
|
922
|
-
|
|
1146
|
+
};
|
|
1147
|
+
C.KNOWN_ERROR_SELECTORS = {
|
|
1148
|
+
"0x2c19b8b8": "InsufficientOutput"
|
|
1149
|
+
};
|
|
1150
|
+
let K = C;
|
|
1151
|
+
const Y = [
|
|
923
1152
|
"function token0() external view returns (address)",
|
|
924
1153
|
"function token1() external view returns (address)",
|
|
925
1154
|
"function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)"
|
|
926
|
-
],
|
|
1155
|
+
], ce = [
|
|
927
1156
|
"function token0() external view returns (address)",
|
|
928
1157
|
"function token1() external view returns (address)",
|
|
929
1158
|
"function fee() external view returns (uint24)",
|
|
930
1159
|
"function liquidity() external view returns (uint128)",
|
|
931
1160
|
"function slot0() external view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint32 feeProtocol, bool unlocked)"
|
|
932
|
-
],
|
|
1161
|
+
], ue = "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", de = [
|
|
933
1162
|
"function getPair(address tokenA, address tokenB) external view returns (address pair)"
|
|
934
|
-
],
|
|
1163
|
+
], le = "0x86407bEa2078ea5f5EB5A52B2caA963bC1F889Da", pe = [
|
|
935
1164
|
"function getPair(address tokenA, address tokenB) external view returns (address pair)"
|
|
936
|
-
],
|
|
1165
|
+
], me = "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865", fe = [
|
|
937
1166
|
"function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool)"
|
|
938
|
-
],
|
|
939
|
-
class
|
|
1167
|
+
], he = [100, 500, 2500, 1e4], we = 60000n, Ae = 120000n, ve = 100000n;
|
|
1168
|
+
class Ce {
|
|
940
1169
|
constructor(e, t) {
|
|
941
|
-
this.poolCache = /* @__PURE__ */ new Map(), this.provider = e, this.v2Factory = new
|
|
942
|
-
|
|
943
|
-
|
|
1170
|
+
this.poolCache = /* @__PURE__ */ new Map(), this.provider = e, this.v2Factory = new m.Contract(
|
|
1171
|
+
ue,
|
|
1172
|
+
de,
|
|
944
1173
|
e
|
|
945
|
-
), this.v3Factory = new
|
|
946
|
-
|
|
947
|
-
|
|
1174
|
+
), this.v3Factory = new m.Contract(
|
|
1175
|
+
me,
|
|
1176
|
+
fe,
|
|
948
1177
|
e
|
|
949
|
-
), this.babySwapFactory = new
|
|
950
|
-
|
|
951
|
-
|
|
1178
|
+
), this.babySwapFactory = new m.Contract(
|
|
1179
|
+
le,
|
|
1180
|
+
pe,
|
|
952
1181
|
e
|
|
953
1182
|
);
|
|
954
1183
|
}
|
|
955
1184
|
/**
|
|
956
1185
|
* Discover optimal route
|
|
957
1186
|
*/
|
|
958
|
-
async findBestRoute(e, t,
|
|
959
|
-
const
|
|
960
|
-
if (
|
|
1187
|
+
async findBestRoute(e, t, n) {
|
|
1188
|
+
const s = await this.discoverPools(e, t);
|
|
1189
|
+
if (s.length === 0)
|
|
961
1190
|
throw new Error(`No pools found for ${e} -> ${t}`);
|
|
962
1191
|
const r = (await this.calculateRoutes(
|
|
963
|
-
|
|
1192
|
+
s,
|
|
964
1193
|
e,
|
|
965
1194
|
t,
|
|
966
|
-
|
|
1195
|
+
n
|
|
967
1196
|
)).reduce(
|
|
968
1197
|
(a, i) => i.amountOut > a.amountOut ? i : a
|
|
969
1198
|
);
|
|
@@ -971,7 +1200,7 @@ class Ae {
|
|
|
971
1200
|
routes: [r],
|
|
972
1201
|
percentages: [1e4],
|
|
973
1202
|
// 100%
|
|
974
|
-
totalAmountIn:
|
|
1203
|
+
totalAmountIn: n,
|
|
975
1204
|
totalAmountOut: r.amountOut,
|
|
976
1205
|
totalGasEstimate: r.gasEstimate
|
|
977
1206
|
};
|
|
@@ -980,60 +1209,60 @@ class Ae {
|
|
|
980
1209
|
* Discover available pools (direct path)
|
|
981
1210
|
*/
|
|
982
1211
|
async discoverPools(e, t) {
|
|
983
|
-
const
|
|
1212
|
+
const n = [];
|
|
984
1213
|
try {
|
|
985
|
-
const
|
|
986
|
-
|
|
1214
|
+
const s = await this.findV2Pool(e, t);
|
|
1215
|
+
s && n.push(s);
|
|
987
1216
|
} catch {
|
|
988
1217
|
}
|
|
989
|
-
for (const
|
|
1218
|
+
for (const s of he)
|
|
990
1219
|
try {
|
|
991
|
-
const
|
|
992
|
-
|
|
1220
|
+
const o = await this.findV3Pool(e, t, s);
|
|
1221
|
+
o && n.push(o);
|
|
993
1222
|
} catch {
|
|
994
1223
|
}
|
|
995
1224
|
try {
|
|
996
|
-
const
|
|
997
|
-
|
|
1225
|
+
const s = await this.findBabySwapPool(e, t);
|
|
1226
|
+
s && n.push(s);
|
|
998
1227
|
} catch {
|
|
999
1228
|
}
|
|
1000
|
-
return
|
|
1229
|
+
return n;
|
|
1001
1230
|
}
|
|
1002
1231
|
/**
|
|
1003
1232
|
* Find V2 pool
|
|
1004
1233
|
*/
|
|
1005
1234
|
async findV2Pool(e, t) {
|
|
1006
|
-
const
|
|
1007
|
-
if (this.poolCache.has(
|
|
1008
|
-
return this.poolCache.get(
|
|
1009
|
-
const
|
|
1010
|
-
if (
|
|
1235
|
+
const n = `v2-${e}-${t}`;
|
|
1236
|
+
if (this.poolCache.has(n))
|
|
1237
|
+
return this.poolCache.get(n);
|
|
1238
|
+
const s = await this.v2Factory.getPair(e, t);
|
|
1239
|
+
if (s === m.ZeroAddress)
|
|
1011
1240
|
return null;
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1241
|
+
const o = new m.Contract(s, Y, this.provider), [r, a, i] = await Promise.all([
|
|
1242
|
+
o.token0(),
|
|
1243
|
+
o.token1(),
|
|
1244
|
+
o.getReserves()
|
|
1016
1245
|
]), c = {
|
|
1017
|
-
address:
|
|
1246
|
+
address: s,
|
|
1018
1247
|
token0: r,
|
|
1019
1248
|
token1: a,
|
|
1020
|
-
protocol:
|
|
1249
|
+
protocol: d.PancakeV2,
|
|
1021
1250
|
reserve0: i.reserve0,
|
|
1022
1251
|
reserve1: i.reserve1
|
|
1023
1252
|
};
|
|
1024
|
-
return this.poolCache.set(
|
|
1253
|
+
return this.poolCache.set(n, c), c;
|
|
1025
1254
|
}
|
|
1026
1255
|
/**
|
|
1027
1256
|
* Find V3 pool
|
|
1028
1257
|
*/
|
|
1029
|
-
async findV3Pool(e, t,
|
|
1030
|
-
const
|
|
1031
|
-
if (this.poolCache.has(
|
|
1032
|
-
return this.poolCache.get(
|
|
1033
|
-
const
|
|
1034
|
-
if (
|
|
1258
|
+
async findV3Pool(e, t, n) {
|
|
1259
|
+
const s = `v3-${e}-${t}-${n}`;
|
|
1260
|
+
if (this.poolCache.has(s))
|
|
1261
|
+
return this.poolCache.get(s);
|
|
1262
|
+
const o = await this.v3Factory.getPool(e, t, n);
|
|
1263
|
+
if (o === m.ZeroAddress)
|
|
1035
1264
|
return null;
|
|
1036
|
-
const r = new
|
|
1265
|
+
const r = new m.Contract(o, ce, this.provider), [a, i, c] = await Promise.all([
|
|
1037
1266
|
r.token0(),
|
|
1038
1267
|
r.token1(),
|
|
1039
1268
|
r.liquidity()
|
|
@@ -1041,102 +1270,102 @@ class Ae {
|
|
|
1041
1270
|
if (c === 0n)
|
|
1042
1271
|
return null;
|
|
1043
1272
|
const u = {
|
|
1044
|
-
address:
|
|
1273
|
+
address: o,
|
|
1045
1274
|
token0: a,
|
|
1046
1275
|
token1: i,
|
|
1047
|
-
protocol:
|
|
1048
|
-
fee:
|
|
1276
|
+
protocol: d.PancakeV3,
|
|
1277
|
+
fee: n,
|
|
1049
1278
|
liquidity: c
|
|
1050
1279
|
};
|
|
1051
|
-
return this.poolCache.set(
|
|
1280
|
+
return this.poolCache.set(s, u), u;
|
|
1052
1281
|
}
|
|
1053
1282
|
/**
|
|
1054
1283
|
* Find BabySwap pool (V2 fork, 0.2% fee)
|
|
1055
1284
|
*/
|
|
1056
1285
|
async findBabySwapPool(e, t) {
|
|
1057
|
-
const
|
|
1058
|
-
if (this.poolCache.has(
|
|
1059
|
-
return this.poolCache.get(
|
|
1060
|
-
const
|
|
1061
|
-
if (
|
|
1286
|
+
const n = `babyswap-${e}-${t}`;
|
|
1287
|
+
if (this.poolCache.has(n))
|
|
1288
|
+
return this.poolCache.get(n);
|
|
1289
|
+
const s = await this.babySwapFactory.getPair(e, t);
|
|
1290
|
+
if (s === m.ZeroAddress)
|
|
1062
1291
|
return null;
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1292
|
+
const o = new m.Contract(s, Y, this.provider), [r, a, i] = await Promise.all([
|
|
1293
|
+
o.token0(),
|
|
1294
|
+
o.token1(),
|
|
1295
|
+
o.getReserves()
|
|
1067
1296
|
]), c = {
|
|
1068
|
-
address:
|
|
1297
|
+
address: s,
|
|
1069
1298
|
token0: r,
|
|
1070
1299
|
token1: a,
|
|
1071
|
-
protocol:
|
|
1300
|
+
protocol: d.BabySwap,
|
|
1072
1301
|
reserve0: i.reserve0,
|
|
1073
1302
|
reserve1: i.reserve1
|
|
1074
1303
|
};
|
|
1075
|
-
return this.poolCache.set(
|
|
1304
|
+
return this.poolCache.set(n, c), c;
|
|
1076
1305
|
}
|
|
1077
1306
|
/**
|
|
1078
1307
|
* Calculate route quotes
|
|
1079
1308
|
*/
|
|
1080
|
-
async calculateRoutes(e, t,
|
|
1081
|
-
const
|
|
1309
|
+
async calculateRoutes(e, t, n, s) {
|
|
1310
|
+
const o = [];
|
|
1082
1311
|
for (const r of e)
|
|
1083
1312
|
try {
|
|
1084
1313
|
const a = await this.getAmountOut(
|
|
1085
1314
|
r,
|
|
1086
1315
|
t,
|
|
1087
|
-
|
|
1088
|
-
|
|
1316
|
+
n,
|
|
1317
|
+
s
|
|
1089
1318
|
);
|
|
1090
|
-
a > 0n &&
|
|
1319
|
+
a > 0n && o.push({
|
|
1091
1320
|
steps: [
|
|
1092
1321
|
{
|
|
1093
1322
|
pool: r,
|
|
1094
1323
|
tokenIn: t,
|
|
1095
|
-
tokenOut:
|
|
1096
|
-
amountIn:
|
|
1324
|
+
tokenOut: n,
|
|
1325
|
+
amountIn: s,
|
|
1097
1326
|
amountOut: a
|
|
1098
1327
|
}
|
|
1099
1328
|
],
|
|
1100
|
-
amountIn:
|
|
1329
|
+
amountIn: s,
|
|
1101
1330
|
amountOut: a,
|
|
1102
|
-
gasEstimate: r.protocol ===
|
|
1331
|
+
gasEstimate: r.protocol === d.PancakeV2 || r.protocol === d.BabySwap ? we : r.protocol === d.Dodo ? ve : Ae
|
|
1103
1332
|
});
|
|
1104
1333
|
} catch {
|
|
1105
1334
|
}
|
|
1106
|
-
return
|
|
1335
|
+
return o;
|
|
1107
1336
|
}
|
|
1108
1337
|
/**
|
|
1109
1338
|
* Get output for a single pool
|
|
1110
1339
|
*/
|
|
1111
|
-
async getAmountOut(e, t,
|
|
1112
|
-
if (e.protocol ===
|
|
1113
|
-
return this.getV2AmountOut(e, t,
|
|
1114
|
-
if (e.protocol ===
|
|
1115
|
-
return this.getBabySwapAmountOut(e, t,
|
|
1116
|
-
if (e.protocol ===
|
|
1340
|
+
async getAmountOut(e, t, n, s) {
|
|
1341
|
+
if (e.protocol === d.PancakeV2)
|
|
1342
|
+
return this.getV2AmountOut(e, t, s);
|
|
1343
|
+
if (e.protocol === d.BabySwap)
|
|
1344
|
+
return this.getBabySwapAmountOut(e, t, s);
|
|
1345
|
+
if (e.protocol === d.Dodo)
|
|
1117
1346
|
throw new Error("DODO amount out not supported in local route discovery");
|
|
1118
|
-
return this.estimateV3AmountOut(e, t,
|
|
1347
|
+
return this.estimateV3AmountOut(e, t, s);
|
|
1119
1348
|
}
|
|
1120
1349
|
/**
|
|
1121
1350
|
* V2 output calculation
|
|
1122
1351
|
*/
|
|
1123
|
-
getV2AmountOut(e, t,
|
|
1124
|
-
const
|
|
1352
|
+
getV2AmountOut(e, t, n) {
|
|
1353
|
+
const s = t.toLowerCase() === e.token0.toLowerCase(), [o, r] = s ? [e.reserve0, e.reserve1] : [e.reserve1, e.reserve0], a = n * 9975n, i = a * r, c = o * 10000n + a;
|
|
1125
1354
|
return i / c;
|
|
1126
1355
|
}
|
|
1127
1356
|
/**
|
|
1128
1357
|
* BabySwap output calculation (V2 fork, 0.2% fee — coefficient 2 in 1000-scale)
|
|
1129
1358
|
*/
|
|
1130
|
-
getBabySwapAmountOut(e, t,
|
|
1131
|
-
const
|
|
1359
|
+
getBabySwapAmountOut(e, t, n) {
|
|
1360
|
+
const s = t.toLowerCase() === e.token0.toLowerCase(), [o, r] = s ? [e.reserve0, e.reserve1] : [e.reserve1, e.reserve0], a = n * 998n, i = a * r, c = o * 1000n + a;
|
|
1132
1361
|
return i / c;
|
|
1133
1362
|
}
|
|
1134
1363
|
/**
|
|
1135
1364
|
* V3 output estimation (simplified)
|
|
1136
1365
|
*/
|
|
1137
|
-
estimateV3AmountOut(e, t,
|
|
1138
|
-
const
|
|
1139
|
-
return
|
|
1366
|
+
estimateV3AmountOut(e, t, n) {
|
|
1367
|
+
const o = 1000000n - BigInt(e.fee || 2500);
|
|
1368
|
+
return n * o / 1000000n;
|
|
1140
1369
|
}
|
|
1141
1370
|
/**
|
|
1142
1371
|
* Clear cache
|
|
@@ -1145,33 +1374,33 @@ class Ae {
|
|
|
1145
1374
|
this.poolCache.clear();
|
|
1146
1375
|
}
|
|
1147
1376
|
}
|
|
1148
|
-
class
|
|
1377
|
+
class be {
|
|
1149
1378
|
constructor(e) {
|
|
1150
1379
|
this.adapters = e;
|
|
1151
1380
|
}
|
|
1152
1381
|
/**
|
|
1153
1382
|
* Build SwapParams from split route
|
|
1154
1383
|
*/
|
|
1155
|
-
build(e, t,
|
|
1384
|
+
build(e, t, n, s, o = N) {
|
|
1156
1385
|
const r = this.flattenRoutes(e), a = this.mergeIdenticalPools(r), i = this.topologicalSort(a, t), c = this.convertToSwapSteps(i), u = this.extractIntermediates(
|
|
1157
1386
|
i,
|
|
1158
1387
|
t,
|
|
1159
|
-
|
|
1160
|
-
),
|
|
1388
|
+
n
|
|
1389
|
+
), l = BigInt(Math.floor(Date.now() / 1e3) + o);
|
|
1161
1390
|
return {
|
|
1162
1391
|
srcToken: t,
|
|
1163
|
-
dstToken:
|
|
1392
|
+
dstToken: n,
|
|
1164
1393
|
amountIn: e.totalAmountIn,
|
|
1165
|
-
amountOutMin:
|
|
1394
|
+
amountOutMin: s,
|
|
1166
1395
|
steps: c,
|
|
1167
1396
|
intermediateTokens: u,
|
|
1168
|
-
deadline:
|
|
1169
|
-
quoteId:
|
|
1397
|
+
deadline: l,
|
|
1398
|
+
quoteId: m.ZeroHash,
|
|
1170
1399
|
expectAmountOut: e.totalAmountOut,
|
|
1171
1400
|
// SwapBuilder is the legacy direct-build path that does not know about custom fees.
|
|
1172
1401
|
// Integrators that want custom fees should use PeachClient.getQuote with options.customFee
|
|
1173
1402
|
// instead, which sets these fields and adjusts amountOutMin accordingly.
|
|
1174
|
-
feeReceiver:
|
|
1403
|
+
feeReceiver: m.ZeroAddress,
|
|
1175
1404
|
feeBps: 0
|
|
1176
1405
|
};
|
|
1177
1406
|
}
|
|
@@ -1180,17 +1409,17 @@ class ge {
|
|
|
1180
1409
|
*/
|
|
1181
1410
|
flattenRoutes(e) {
|
|
1182
1411
|
const t = [];
|
|
1183
|
-
for (let
|
|
1184
|
-
const
|
|
1185
|
-
for (let a = 0; a <
|
|
1186
|
-
const i =
|
|
1412
|
+
for (let n = 0; n < e.routes.length; n++) {
|
|
1413
|
+
const s = e.routes[n], o = e.percentages[n], r = e.totalAmountIn * BigInt(o) / _;
|
|
1414
|
+
for (let a = 0; a < s.steps.length; a++) {
|
|
1415
|
+
const i = s.steps[a];
|
|
1187
1416
|
t.push({
|
|
1188
1417
|
pool: i.pool,
|
|
1189
1418
|
tokenIn: i.tokenIn,
|
|
1190
1419
|
tokenOut: i.tokenOut,
|
|
1191
1420
|
// Only first step has fixed amount, subsequent steps depend on previous output
|
|
1192
1421
|
amountIn: a === 0 ? r : 0n,
|
|
1193
|
-
routeIndex:
|
|
1422
|
+
routeIndex: n,
|
|
1194
1423
|
stepIndex: a
|
|
1195
1424
|
});
|
|
1196
1425
|
}
|
|
@@ -1202,54 +1431,54 @@ class ge {
|
|
|
1202
1431
|
* Key: pool + tokenIn + tokenOut
|
|
1203
1432
|
*/
|
|
1204
1433
|
mergeIdenticalPools(e) {
|
|
1205
|
-
const t = /* @__PURE__ */ new Map(),
|
|
1206
|
-
for (const
|
|
1207
|
-
const
|
|
1208
|
-
if (t.has(
|
|
1209
|
-
const r = t.get(
|
|
1210
|
-
|
|
1434
|
+
const t = /* @__PURE__ */ new Map(), n = [];
|
|
1435
|
+
for (const s of e) {
|
|
1436
|
+
const o = `${s.pool.address}-${s.tokenIn}-${s.tokenOut}`;
|
|
1437
|
+
if (t.has(o)) {
|
|
1438
|
+
const r = t.get(o);
|
|
1439
|
+
s.amountIn > 0n && r.amountIn > 0n && (r.amountIn = 0n);
|
|
1211
1440
|
} else {
|
|
1212
|
-
const r = { ...
|
|
1213
|
-
t.set(
|
|
1441
|
+
const r = { ...s };
|
|
1442
|
+
t.set(o, r), n.push(r);
|
|
1214
1443
|
}
|
|
1215
1444
|
}
|
|
1216
|
-
for (const
|
|
1217
|
-
const
|
|
1445
|
+
for (const s of n) {
|
|
1446
|
+
const o = `${s.pool.address}-${s.tokenIn}-${s.tokenOut}`;
|
|
1218
1447
|
e.filter(
|
|
1219
|
-
(a) => `${a.pool.address}-${a.tokenIn}-${a.tokenOut}` ===
|
|
1220
|
-
).length > 1 && (
|
|
1448
|
+
(a) => `${a.pool.address}-${a.tokenIn}-${a.tokenOut}` === o
|
|
1449
|
+
).length > 1 && (s.amountIn = 0n);
|
|
1221
1450
|
}
|
|
1222
|
-
return
|
|
1451
|
+
return n;
|
|
1223
1452
|
}
|
|
1224
1453
|
/**
|
|
1225
1454
|
* Topological sort (Kahn's Algorithm)
|
|
1226
1455
|
*/
|
|
1227
1456
|
topologicalSort(e, t) {
|
|
1228
|
-
const
|
|
1457
|
+
const n = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
1229
1458
|
for (const i of e) {
|
|
1230
1459
|
const c = this.stepKey(i);
|
|
1231
|
-
|
|
1460
|
+
s.set(c, i), n.set(c, 0), o.set(c, []);
|
|
1232
1461
|
}
|
|
1233
1462
|
for (const i of e) {
|
|
1234
1463
|
const c = this.stepKey(i);
|
|
1235
1464
|
if (i.tokenIn !== t) {
|
|
1236
1465
|
for (const u of e)
|
|
1237
1466
|
if (u.tokenOut === i.tokenIn) {
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1467
|
+
const l = this.stepKey(u);
|
|
1468
|
+
l !== c && (o.get(l).push(c), n.set(c, (n.get(c) || 0) + 1));
|
|
1240
1469
|
}
|
|
1241
1470
|
}
|
|
1242
1471
|
}
|
|
1243
1472
|
const r = [];
|
|
1244
|
-
for (const [i, c] of
|
|
1473
|
+
for (const [i, c] of n)
|
|
1245
1474
|
c === 0 && r.push(i);
|
|
1246
1475
|
const a = [];
|
|
1247
1476
|
for (; r.length > 0; ) {
|
|
1248
|
-
const i = r.shift(), c =
|
|
1477
|
+
const i = r.shift(), c = s.get(i);
|
|
1249
1478
|
a.push(c);
|
|
1250
|
-
for (const u of
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1479
|
+
for (const u of o.get(i) || []) {
|
|
1480
|
+
const l = (n.get(u) || 0) - 1;
|
|
1481
|
+
n.set(u, l), l === 0 && r.push(u);
|
|
1253
1482
|
}
|
|
1254
1483
|
}
|
|
1255
1484
|
if (a.length !== e.length)
|
|
@@ -1261,11 +1490,11 @@ class ge {
|
|
|
1261
1490
|
*/
|
|
1262
1491
|
convertToSwapSteps(e) {
|
|
1263
1492
|
return e.map((t) => {
|
|
1264
|
-
const
|
|
1265
|
-
if (!
|
|
1493
|
+
const n = this.adapters.get(t.pool.protocol);
|
|
1494
|
+
if (!n)
|
|
1266
1495
|
throw new Error(`No adapter for protocol: ${t.pool.protocol}`);
|
|
1267
1496
|
return {
|
|
1268
|
-
adapter:
|
|
1497
|
+
adapter: n,
|
|
1269
1498
|
pool: t.pool.address,
|
|
1270
1499
|
tokenIn: t.tokenIn,
|
|
1271
1500
|
tokenOut: t.tokenOut,
|
|
@@ -1279,24 +1508,47 @@ class ge {
|
|
|
1279
1508
|
*/
|
|
1280
1509
|
encodeExtraData(e) {
|
|
1281
1510
|
switch (e.protocol) {
|
|
1282
|
-
case
|
|
1511
|
+
case d.PancakeV1:
|
|
1512
|
+
return "0x";
|
|
1513
|
+
case d.PancakeV2:
|
|
1283
1514
|
return "0x";
|
|
1284
1515
|
// V2 doesn't need extra parameters
|
|
1285
|
-
case
|
|
1286
|
-
|
|
1287
|
-
case
|
|
1516
|
+
case d.UniswapV2:
|
|
1517
|
+
return "0x";
|
|
1518
|
+
case d.PancakeV3:
|
|
1519
|
+
case d.UniswapV3:
|
|
1520
|
+
case d.UniswapV4:
|
|
1521
|
+
case d.SquadSwapV3:
|
|
1522
|
+
case d.ThenaFusion:
|
|
1523
|
+
return "0x";
|
|
1524
|
+
case d.PancakeInfinityCl:
|
|
1525
|
+
case d.PancakeInfinityLb:
|
|
1526
|
+
return "0x";
|
|
1527
|
+
case d.Dodo:
|
|
1528
|
+
return "0x";
|
|
1529
|
+
case d.NomiswapStable:
|
|
1530
|
+
return "0x";
|
|
1531
|
+
case d.Biswap:
|
|
1532
|
+
return "0x";
|
|
1533
|
+
case d.Apeswap:
|
|
1534
|
+
return "0x";
|
|
1535
|
+
case d.BabyDogeSwap:
|
|
1536
|
+
return "0x";
|
|
1537
|
+
case d.BabySwap:
|
|
1538
|
+
return "0x";
|
|
1539
|
+
case d.BakerySwap:
|
|
1288
1540
|
return "0x";
|
|
1289
|
-
case
|
|
1541
|
+
case d.SquadSwapV2:
|
|
1290
1542
|
return "0x";
|
|
1291
|
-
case
|
|
1543
|
+
case d.SushiSwapV2:
|
|
1292
1544
|
return "0x";
|
|
1293
|
-
case
|
|
1545
|
+
case d.SushiSwapV3:
|
|
1294
1546
|
return "0x";
|
|
1295
|
-
case
|
|
1547
|
+
case d.PancakeStable:
|
|
1296
1548
|
return "0x";
|
|
1297
|
-
case
|
|
1549
|
+
case d.ListaStable:
|
|
1298
1550
|
return "0x";
|
|
1299
|
-
case
|
|
1551
|
+
case d.Wombat:
|
|
1300
1552
|
return "0x";
|
|
1301
1553
|
default:
|
|
1302
1554
|
return "0x";
|
|
@@ -1305,11 +1557,11 @@ class ge {
|
|
|
1305
1557
|
/**
|
|
1306
1558
|
* Extract intermediate tokens
|
|
1307
1559
|
*/
|
|
1308
|
-
extractIntermediates(e, t,
|
|
1309
|
-
const
|
|
1310
|
-
for (const
|
|
1311
|
-
|
|
1312
|
-
return
|
|
1560
|
+
extractIntermediates(e, t, n) {
|
|
1561
|
+
const s = /* @__PURE__ */ new Set();
|
|
1562
|
+
for (const o of e)
|
|
1563
|
+
o.tokenOut !== n && s.add(o.tokenOut);
|
|
1564
|
+
return s.delete(t), s.delete(n), Array.from(s);
|
|
1313
1565
|
}
|
|
1314
1566
|
/**
|
|
1315
1567
|
* Generate unique step key
|
|
@@ -1319,28 +1571,30 @@ class ge {
|
|
|
1319
1571
|
}
|
|
1320
1572
|
}
|
|
1321
1573
|
export {
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1574
|
+
E as API_DEFAULTS,
|
|
1575
|
+
ne as ApiClient,
|
|
1576
|
+
S as ApiError,
|
|
1577
|
+
_ as BPS_DENOMINATOR,
|
|
1578
|
+
ke as BSC_MAINNET_CONFIG,
|
|
1579
|
+
Ee as BSC_TESTNET_CONFIG,
|
|
1580
|
+
B as CustomFeeError,
|
|
1581
|
+
J as DEFAULT_API_URL,
|
|
1582
|
+
N as DEFAULT_DEADLINE_SECONDS,
|
|
1583
|
+
G as DEFAULT_EXECUTE_TIMEOUT_MS,
|
|
1584
|
+
Se as DEFAULT_SLIPPAGE_BPS,
|
|
1585
|
+
M as DEFAULT_TRANSACTION_RESPONSE_POLL_INTERVALS_MS,
|
|
1586
|
+
Pe as ERR_ZERO_AMOUNT_PATHS,
|
|
1587
|
+
Q as ExecuteTimeoutError,
|
|
1588
|
+
U as MAX_FEE_BPS,
|
|
1589
|
+
Ie as MAX_PLATFORM_CUT_BPS,
|
|
1590
|
+
q as NATIVE_TOKEN_ADDRESS,
|
|
1591
|
+
O as PERMIT2_ADDRESS,
|
|
1592
|
+
$ as PERMIT2_MAX_AMOUNT,
|
|
1339
1593
|
K as PeachClient,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1594
|
+
d as ProtocolType,
|
|
1595
|
+
Ce as RouteDiscovery,
|
|
1596
|
+
be as SwapBuilder,
|
|
1597
|
+
T as isNativeTokenAddress,
|
|
1598
|
+
W as withWalletSendTimeout
|
|
1345
1599
|
};
|
|
1346
1600
|
//# sourceMappingURL=index.mjs.map
|