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