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