@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/dist/index.mjs CHANGED
@@ -1,111 +1,125 @@
1
- import { ethers as h } from "ethers";
2
- const V = "https://api.peach.ag", et = 50, O = 10000n, y = 1200, D = 6e4, x = [50, 100, 200, 400, 800, 1200], $ = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
3
- function _(m) {
4
- return m.toLowerCase() === $.toLowerCase();
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 nt = 4001;
7
- var w = /* @__PURE__ */ ((m) => (m.PancakeV2 = "PancakeV2", m.PancakeV3 = "PancakeV3", m.PancakeInfinityCl = "Pancake_Infinity_Cl", m.UniswapV3 = "UniswapV3", m.UniswapV4 = "UniswapV4", m.Dodo = "Dodo", m.Thena = "Thena", m))(w || {});
8
- const ot = {
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
- }, rt = {
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 N extends Error {
22
- constructor(t, e, n) {
23
- super(t), this.name = "ExecuteTimeoutError", this.stage = e, this.txHash = n;
21
+ class B extends Error {
22
+ constructor(e) {
23
+ super(e), this.name = "CustomFeeError";
24
24
  }
25
25
  }
26
- const I = {
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", "THENA"],
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
- }, B = 1e4;
36
- class M {
37
- constructor(t = {}) {
38
- this.baseUrl = t.baseUrl || V, this.timeout = t.timeout || B;
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: e,
53
+ from: t,
46
54
  target: n,
47
55
  amount: o,
48
- byAmountIn: s = !0,
49
- depth: r = I.depth,
50
- splitCount: a = I.splitCount,
51
- providers: i = I.providers
52
- } = t, c = new URLSearchParams({
53
- from: e,
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: s.toString(),
57
- depth: r.toString(),
65
+ by_amount_in: r.toString(),
66
+ depth: s.toString(),
58
67
  split_count: a.toString(),
59
68
  providers: i.join(","),
60
- v: I.clientVersion.toString()
61
- }), u = `${this.baseUrl}/router/find_routes?${c}`, d = new AbortController(), l = setTimeout(() => d.abort(), this.timeout);
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 f = await fetch(u, {
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: d.signal
78
+ signal: p.signal
69
79
  });
70
- if (clearTimeout(l), !f.ok)
71
- throw new v(
72
- `API request failed: ${f.status} ${f.statusText}`,
73
- f.status
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 g = await f.json();
76
- if (g.code !== 200)
77
- throw new v(g.msg || "Route not found", g.code);
78
- if (!g.data || !g.data.paths || g.data.paths.length === 0)
79
- throw new v("No routes found", 404);
80
- return g.data;
81
- } catch (f) {
82
- throw clearTimeout(l), f instanceof v ? f : f instanceof Error ? f.name === "AbortError" ? new v("API request timeout", 408) : new v(`API request failed: ${f.message}`, 0) : new v("Unknown API error", 0);
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 t = `${this.baseUrl}/router/status`, e = new AbortController(), n = setTimeout(() => e.abort(), this.timeout);
102
+ const e = `${this.baseUrl}/router/status`, t = new AbortController(), n = setTimeout(() => t.abort(), this.timeout);
90
103
  try {
91
- const o = await fetch(t, {
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: e.signal
110
+ signal: t.signal
97
111
  });
98
112
  if (clearTimeout(n), !o.ok)
99
- throw new v(
113
+ throw new g(
100
114
  `API request failed: ${o.status} ${o.statusText}`,
101
115
  o.status
102
116
  );
103
- const s = await o.json();
104
- if (s.code !== 200)
105
- throw new v(s.msg || "Failed to get status", s.code);
106
- return s.data;
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 v ? o : o instanceof Error ? o.name === "AbortError" ? new v("API request timeout", 408) : new v(`API request failed: ${o.message}`, 0) : new v("Unknown API error", 0);
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(t) {
121
- this.baseUrl = t;
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 v extends Error {
131
- constructor(t, e) {
132
- super(t), this.name = "ApiError", this.code = e;
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 b(m, t = D) {
136
- if (t <= 0)
137
- return m;
138
- let e;
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
- m,
155
+ h,
142
156
  new Promise((n, o) => {
143
- e = setTimeout(() => {
157
+ t = setTimeout(() => {
144
158
  o(
145
- new N(
146
- `Wallet did not settle sendTransaction within ${t}ms.`,
159
+ new Y(
160
+ `Wallet did not settle sendTransaction within ${e}ms.`,
147
161
  "wallet_send"
148
162
  )
149
163
  );
150
- }, t);
164
+ }, e);
151
165
  })
152
166
  ]);
153
167
  } finally {
154
- e && clearTimeout(e);
168
+ t && clearTimeout(t);
155
169
  }
156
170
  }
157
- const K = [
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 WETH() external view returns (address)"
162
- ], C = [
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
- ], W = "0xa0FfB9c1CE1Fe56963B0321B32E7A0302114058b", R = {
169
- PANCAKEV3: w.PancakeV3,
170
- PANCAKEV2: w.PancakeV2,
171
- PANCAKE_INFINITY_CL: w.PancakeInfinityCl,
172
- UNISWAPV3: w.UniswapV3,
173
- UNISWAPV4: w.UniswapV4,
174
- DODO: w.Dodo,
175
- THENA: w.Thena
176
- };
177
- class st {
178
- constructor(t, e, n) {
179
- this.config = t, this.provider = e || new h.JsonRpcProvider(t.rpcUrl), this.routerContract = new h.Contract(
180
- t.routerAddress || h.ZeroAddress,
181
- K,
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 M(n?.api);
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(t) {
189
- const e = t.routerAddress || this.config.routerAddress;
190
- if (!e || e === h.ZeroAddress)
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 e;
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(t, e) {
198
- if (e < 0 || e > 1e4)
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 = t.amountOutMin * (O - BigInt(e)) / O;
201
- return { ...t, amountOutMin: n };
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(t, e, n) {
207
- const o = this.getRouterAddress(t), { tx: s, method: r } = this.buildSwapTransactionRequest(t, n);
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 t.srcNative || (a = await this.buildApprovalRequest(
210
- t.srcToken,
211
- e,
212
- t.amountIn,
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: r,
218
- tx: s,
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(t, e, n) {
228
- const o = await e.getAddress(), s = await this.swap(t, o, n);
262
+ async execute(e, t, n) {
263
+ const o = await t.getAddress(), r = await this.swap(e, o, n);
229
264
  try {
230
- return s.approval && await (await this.sendTransactionWithTimeout(
231
- e,
232
- s.approval.tx,
265
+ return r.approval && await (await this.sendTransactionWithTimeout(
266
+ t,
267
+ r.approval.tx,
233
268
  n
234
- )).wait(), await this.sendTransactionWithTimeout(e, s.tx, n);
235
- } catch (r) {
236
- 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");
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 = r, d;
274
+ throw d.cause = s, d;
240
275
  }
241
- throw r;
276
+ throw s;
242
277
  }
243
278
  }
244
279
  /**
245
280
  * Encode parameters to contract format
246
281
  */
247
- encodeParams(t) {
282
+ encodeParams(e) {
248
283
  return {
249
- srcToken: t.srcToken,
250
- dstToken: t.dstToken,
251
- amountIn: t.amountIn,
252
- amountOutMin: t.amountOutMin,
253
- steps: t.steps.map((e) => ({
254
- adapter: e.adapter,
255
- pool: e.pool,
256
- tokenIn: e.tokenIn,
257
- tokenOut: e.tokenOut,
258
- amountIn: e.amountIn,
259
- extraData: e.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: t.intermediateTokens,
262
- deadline: t.deadline,
263
- quoteId: t.quoteId,
264
- expectAmountOut: t.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(t) {
268
- if (t in R)
269
- return R[t];
270
- throw new Error(`Unsupported provider: ${t}`);
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(t, e) {
281
- const n = t.routerAddress ?? this.config.routerAddress ?? this.routerContract.target, o = this.applySlippage(t.params, e), s = t.srcNative === !0 || t.dstNative === !0, r = this.encodeParams(o);
282
- if (s) {
283
- const a = this.routerContract.interface.encodeFunctionData("swapETH", [r]);
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: t.srcNative ? t.amountIn : 0n,
324
+ value: e.srcNative ? e.amountIn : 0n,
288
325
  method: "swapETH"
289
326
  };
290
327
  } else {
291
- const a = this.routerContract.interface.encodeFunctionData("swap", [r]);
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(t, e) {
301
- const { to: n, data: o, value: s, method: r } = this.encodeSwapCalldata(t, e.slippageBps);
337
+ buildSwapTransactionRequest(e, t) {
338
+ const { to: n, data: o, value: r, method: s } = this.encodeSwapCalldata(e, t.slippageBps);
302
339
  return {
303
- method: r,
304
- tx: this.applyTxOverrides({ to: n, data: o, value: s }, e, !0)
340
+ method: s,
341
+ tx: this.applyTxOverrides({ to: n, data: o, value: r }, t, !0)
305
342
  };
306
343
  }
307
- async buildApprovalRequest(t, e, n, o, s) {
308
- const r = await this.getAllowance(t, e, o);
309
- if (!(r >= n))
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: t,
312
- owner: e,
348
+ token: e,
349
+ owner: t,
313
350
  spender: o,
314
- currentAllowance: r,
351
+ currentAllowance: s,
315
352
  requiredAmount: n,
316
- approveAmount: h.MaxUint256,
317
- tx: this.buildApprovalTransactionRequest(t, o, s)
353
+ approveAmount: f.MaxUint256,
354
+ tx: this.buildApprovalTransactionRequest(e, o, r)
318
355
  };
319
356
  }
320
- buildApprovalTransactionRequest(t, e, n) {
321
- const s = new h.Interface(C).encodeFunctionData("approve", [e, h.MaxUint256]);
322
- return this.applyTxOverrides({ to: t, data: s, value: 0n }, n, !1);
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(t, e, n) {
325
- return new h.Contract(t, C, this.provider).allowance(e, n);
361
+ async getAllowance(e, t, n) {
362
+ return new f.Contract(e, b, this.provider).allowance(t, n);
326
363
  }
327
- applyTxOverrides(t, e, n) {
328
- const o = { ...t };
329
- return e.gasPrice && (o.gasPrice = e.gasPrice), n && e.gasLimit && (o.gasLimit = e.gasLimit), o;
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(t, e, n) {
332
- const o = n.timeoutMs ?? D;
368
+ async sendTransactionWithTimeout(e, t, n) {
369
+ const o = n.timeoutMs ?? K;
333
370
  if (o <= 0)
334
- return t.sendTransaction(e);
335
- const s = t;
336
- if (typeof s.sendUncheckedTransaction == "function" && s.provider) {
337
- const r = await b(
338
- s.sendUncheckedTransaction(e),
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
- s.provider,
342
- r,
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 N(
386
+ throw new Y(
350
387
  `Transaction was broadcast but provider did not return TransactionResponse within ${o}ms (${i}).`,
351
388
  "provider_index",
352
- r
389
+ s
353
390
  );
354
391
  }
355
- return b(t.sendTransaction(e), o);
392
+ return $(e.sendTransaction(t), o);
356
393
  }
357
- async waitForTransactionResponse(t, e, n, o = x) {
358
- const s = Date.now() + n;
359
- let r = 0, a = 0, i = 0;
360
- for (; Date.now() < s; ) {
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 t.getTransaction(e);
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, r);
370
- r++, await this.delay(Math.min(c, Math.max(25, s - Date.now())));
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(t) {
375
- t <= 0 || await new Promise((e) => {
376
- setTimeout(e, t);
411
+ async delay(e) {
412
+ e <= 0 || await new Promise((t) => {
413
+ setTimeout(t, e);
377
414
  });
378
415
  }
379
- getNextPollingDelay(t, e) {
380
- return t.length === 0 ? x.at(-1) ?? 1200 : t[Math.min(e, t.length - 1)] ?? 1200;
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(t, e) {
386
- const n = new h.Contract(t, C, this.provider), [o, s, r] = await Promise.all([
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
- e ? n.balanceOf(e) : Promise.resolve(void 0)
426
+ t ? n.balanceOf(t) : Promise.resolve(void 0)
390
427
  ]);
391
- return r === void 0 ? { symbol: o, decimals: s } : { symbol: o, decimals: s, balance: r };
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(t, e) {
397
- return new h.Contract(t, C, this.provider).balanceOf(e);
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(t) {
404
- const { srcToken: e, dstToken: n, amountIn: o, options: s = {} } = t, {
405
- byAmountIn: r = !0,
406
- depth: a = I.depth,
407
- splitCount: i = I.splitCount,
408
- providers: c = I.providers,
409
- deadlineSeconds: u = y
410
- } = s, d = _(e), l = _(n), f = d ? this.config.weth : e, g = l ? this.config.weth : n, k = await this.apiClient.findRoutes({
411
- from: f,
412
- target: g,
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: r,
480
+ byAmountIn: s,
415
481
  depth: a,
416
482
  splitCount: i,
417
483
  providers: c
418
484
  });
419
- return this.buildQuoteFromApi(k, f, g, u, c, d, l);
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(t, e, n, o) {
426
- const s = new Set(e.map((l) => l.toUpperCase()));
427
- let r = t.filter((l) => s.has(l.provider.toUpperCase()));
428
- if (r.length === t.length)
429
- return r;
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 l of r)
436
- c.has(l.token_in.toLowerCase()) && !c.has(l.token_out.toLowerCase()) && (c.add(l.token_out.toLowerCase()), u = !0);
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 l of r)
442
- d.has(l.token_out.toLowerCase()) && !d.has(l.token_in.toLowerCase()) && (d.add(l.token_in.toLowerCase()), u = !0);
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 r.length, r = r.filter(
445
- (l) => c.has(l.token_in.toLowerCase()) && d.has(l.token_out.toLowerCase())
446
- ), r;
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(t, e, n, o, s) {
458
- const r = this.buildQuoteFromRouteDataInternal(
459
- t,
644
+ buildQuoteFromRouteData(e, t, n, o, r) {
645
+ const s = this.buildQuoteFromRouteDataInternal(
460
646
  e,
647
+ t,
461
648
  n,
462
- o ?? y,
649
+ o ?? T,
463
650
  void 0
464
651
  );
465
- return s?.srcNative && (r.srcNative = !0), s?.dstNative && (r.dstNative = !0), r;
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(t, e, n, o, s, r, a) {
471
- const i = this.buildQuoteFromRouteDataInternal(
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
- s
663
+ r,
664
+ c
477
665
  );
478
- return r && (i.srcNative = !0), a && (i.dstNative = !0), i;
479
- }
480
- buildQuoteFromRouteDataInternal(t, e, n, o, s) {
481
- const r = e.toLowerCase();
482
- t.paths.length;
483
- let a = t.paths.filter((p) => !(!(p.token_in.toLowerCase() === r) && BigInt(p.amount_in) === 0n && BigInt(p.amount_out) === 0n));
484
- if (a.length === 0)
485
- throw new v("All route paths have zero amounts", 4001);
486
- if (s && s.length > 0 && (a = this.filterPathsByProviders(a, s, e, n), a.length === 0))
487
- throw new v("No valid route paths remaining after provider filtering", 4001);
488
- const i = n.toLowerCase();
489
- let c = 0n, u = 0n;
490
- for (const p of a)
491
- p.token_in.toLowerCase() === r && (c += BigInt(p.amount_in)), p.token_out.toLowerCase() === i && (u += BigInt(p.amount_out));
492
- const d = BigInt(
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
- ), l = /* @__PURE__ */ new Map();
495
- for (const p of a) {
496
- const A = p.token_in.toLowerCase();
497
- l.set(A, (l.get(A) ?? 0) + 1);
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 f = /* @__PURE__ */ new Map(), g = a.map((p) => {
500
- const A = p.token_in.toLowerCase(), T = (f.get(A) ?? 0) + 1;
501
- f.set(A, T);
502
- const S = l.get(A), L = S > 1 && T < S, U = A === r;
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: p.adapter,
505
- pool: p.provider.toUpperCase() === "PANCAKE_INFINITY_CL" ? W : p.provider.toUpperCase() === "UNISWAPV4" ? h.ZeroAddress : p.pool,
506
- tokenIn: p.token_in,
507
- tokenOut: p.token_out,
508
- amountIn: U || L ? BigInt(p.amount_in) : 0n,
509
- extraData: p.extra_data || "0x"
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
- }), k = /* @__PURE__ */ new Set();
512
- for (const p of a)
513
- p.token_out.toLowerCase() !== i && k.add(p.token_out);
514
- const E = Array.from(k), P = {
515
- srcToken: e,
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: c,
518
- amountOutMin: u,
519
- steps: g,
520
- intermediateTokens: E,
521
- deadline: d,
522
- quoteId: t.request_id ? h.id(t.request_id).slice(0, 66) : h.ZeroHash,
523
- expectAmountOut: u
524
- }, F = {
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: a.map((p) => ({
717
+ steps: i.map((w) => ({
528
718
  pool: {
529
- address: p.pool,
530
- token0: p.token_in,
531
- token1: p.token_out,
532
- protocol: this.getProtocolForProvider(p.provider),
533
- fee: p.fee_rate ? Math.round(parseFloat(p.fee_rate) * 1e6) : void 0
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: p.token_in,
536
- tokenOut: p.token_out,
537
- amountIn: BigInt(p.amount_in),
538
- amountOut: BigInt(p.amount_out)
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: c,
541
- amountOut: u,
542
- gasEstimate: BigInt(t.gas)
730
+ amountIn: u,
731
+ amountOut: d,
732
+ gasEstimate: BigInt(e.gas)
543
733
  }
544
734
  ],
545
735
  percentages: [1e4],
546
- totalAmountIn: c,
547
- totalAmountOut: u,
548
- totalGasEstimate: BigInt(t.gas)
736
+ totalAmountIn: u,
737
+ totalAmountOut: d,
738
+ totalGasEstimate: BigInt(e.gas)
549
739
  };
550
- if (!t.contracts?.router)
551
- throw new v("API response missing contracts.router address", 4002);
740
+ if (!e.contracts?.router)
741
+ throw new g("API response missing contracts.router address", 4002);
552
742
  return {
553
- srcToken: e,
743
+ srcToken: t,
554
744
  dstToken: n,
555
- amountIn: c,
556
- amountOut: u,
557
- priceImpact: parseFloat(t.deviation_ratio || "0"),
558
- route: F,
559
- params: P,
560
- gasEstimate: BigInt(t.gas),
561
- routerAddress: t.contracts?.router
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(t, e, n, o) {
582
- const s = n || h.ZeroAddress, { to: r, data: a, value: i, method: c } = this.encodeSwapCalldata(t, e);
583
- if (console.log("[PeachClient] simulate using router:", r), o) {
584
- const u = this.getJsonRpcProviderForStateOverrides(), d = i > 0n ? "0x" + i.toString(16) : void 0, l = await u.send("eth_call", [
585
- { from: s, to: r, data: a, value: d },
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
- ]), [f] = this.routerContract.interface.decodeFunctionResult(c, l);
589
- return { amountOut: f, method: c };
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: s,
593
- to: r,
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(t, e, n, o) {
611
- const s = t instanceof Error ? t : new Error(String(t)), r = t;
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 (r.reason && typeof r.reason == "string")
614
- a = r.reason;
615
- else if (r.revert && typeof r.revert == "object") {
616
- const d = r.revert;
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 s.message && (a = s.message);
619
- const i = e.params.steps.map(
620
- (d, l) => ` Step ${l}: ${d.tokenIn.slice(0, 10)}→${d.tokenOut.slice(0, 10)} via adapter ${d.adapter.slice(0, 10)} pool ${d.pool.slice(0, 10)}`
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: ${e.srcToken} → ${e.dstToken}`,
625
- ` AmountIn: ${e.amountIn}`,
626
- ` AmountOutMin: ${e.params.amountOutMin}`,
627
- ` Router: ${e.routerAddress}`,
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 (${e.params.steps.length}):`,
826
+ ` Steps (${t.params.steps.length}):`,
630
827
  i
631
828
  ].join(`
632
829
  `), u = new Error(c);
633
- return u.cause = s, u.reason = a, u;
830
+ return u.cause = r, u.reason = a, u;
634
831
  }
635
832
  /**
636
- * Find which step in the route causes the same revert as the full route (e.g. MUL_ERROR).
637
- * Simulates with steps [0..1], [0..2], ... and returns the first step whose revert
638
- * matches fullRouteError. Ignores steps that revert with a different reason (e.g. unknown custom error).
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 - 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
- * @returns The step index and step details whose revert matches fullRouteError, or null if none match or full route succeeds
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(t, e, n, o, s) {
648
- const r = t.params.steps;
649
- if (!r.length) return null;
650
- const a = s != null ? this.normalizeRevertReason(s) : void 0;
651
- for (let i = 1; i <= r.length; i++) {
652
- const c = this.quoteWithFirstNSteps(t, i);
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(c, e, n, o);
655
- } catch (u) {
656
- const d = this.normalizeRevertReason(u), l = u?.message ?? u?.reason ?? u?.shortMessage;
657
- if (a != null ? d === a : !0)
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: i - 1,
660
- step: r[i - 1],
661
- error: u,
662
- revertMessage: typeof l == "string" ? l : void 0,
663
- fullRouteRevertMessage: a ?? void 0
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 for findFailingStep matching. */
670
- normalizeRevertReason(t) {
671
- if (t == null) return;
672
- const e = t;
673
- if (typeof e.reason == "string" && e.reason.length > 0) return e.reason;
674
- const n = e.shortMessage ?? e.message;
675
- if (typeof n != "string") return;
676
- const o = n.match(/reason="([^"]+)"/);
677
- if (o) return o[1];
678
- const s = n.match(/reverted:\s*"([^"]+)"/);
679
- if (s) return s[1];
680
- const r = n.match(/execution reverted:\s*"([^"]+)"/);
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
- /** Build a quote that only includes the first stepCount steps (for findFailingStep). */
684
- quoteWithFirstNSteps(t, e) {
685
- const n = t.params.steps.slice(0, e), o = t.dstToken.toLowerCase(), s = /* @__PURE__ */ new Set(), r = [];
686
- for (const a of n) {
687
- const i = a.tokenOut.toLowerCase();
688
- i !== o && !s.has(i) && (s.add(i), r.push(a.tokenOut));
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
- ...t,
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
- ...t.params,
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: r
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(t, e, n, o, s, r) {
717
- if (r?.isNative || _(t))
988
+ buildStateOverrides(e, t, n, o, r, s) {
989
+ if (s?.isNative || y(e))
718
990
  return {};
719
- if (!n || n === h.ZeroAddress)
991
+ if (!n || n === f.ZeroAddress)
720
992
  throw new Error("buildStateOverrides requires a non-zero routerAddress.");
721
- const a = h.AbiCoder.defaultAbiCoder(), i = o || h.parseUnits("1000000", 18), c = s ?? n, u = h.zeroPadValue(h.toBeHex(i), 32), d = h.zeroPadValue(h.toBeHex(h.MaxUint256), 32), l = {}, f = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 50, 51, 52, 100, 101, 102];
722
- for (const g of f) {
723
- const k = h.keccak256(a.encode(["address", "uint256"], [e, g]));
724
- l[k] = u;
725
- const E = h.keccak256(a.encode(["address", "uint256"], [e, g])), P = h.keccak256(a.encode(["address", "bytes32"], [c, E]));
726
- l[P] = d;
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
- [t.toLowerCase()]: { stateDiff: l }
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
- ], G = [
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
- ], j = "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", q = [
1019
+ ], se = "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73", ae = [
744
1020
  "function getPair(address tokenA, address tokenB) external view returns (address pair)"
745
- ], Z = "0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865", Q = [
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
- ], Y = [100, 500, 2500, 1e4], z = 60000n, J = 120000n, X = 100000n;
748
- class at {
749
- constructor(t, e) {
750
- this.poolCache = /* @__PURE__ */ new Map(), this.provider = t, this.config = e, this.v2Factory = new h.Contract(
751
- j,
752
- q,
753
- t
754
- ), this.v3Factory = new h.Contract(
755
- Z,
756
- Q,
757
- t
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(t, e, n) {
764
- const o = await this.discoverPools(t, e);
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 ${t} -> ${e}`);
767
- const r = (await this.calculateRoutes(
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: [r],
1058
+ routes: [s],
777
1059
  percentages: [1e4],
778
1060
  // 100%
779
1061
  totalAmountIn: n,
780
- totalAmountOut: r.amountOut,
781
- totalGasEstimate: r.gasEstimate
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(t, e) {
1069
+ async discoverPools(e, t) {
788
1070
  const n = [];
789
1071
  try {
790
- const o = await this.findV2Pool(t, e);
1072
+ const o = await this.findV2Pool(e, t);
791
1073
  o && n.push(o);
792
1074
  } catch {
793
1075
  }
794
- for (const o of Y)
1076
+ for (const o of le)
795
1077
  try {
796
- const s = await this.findV3Pool(t, e, o);
797
- s && n.push(s);
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(t, e) {
806
- const n = `v2-${t}-${e}`;
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(t, e);
810
- if (o === h.ZeroAddress)
1096
+ const o = await this.v2Factory.getPair(e, t);
1097
+ if (o === f.ZeroAddress)
811
1098
  return null;
812
- const s = new h.Contract(o, H, this.provider), [r, a, i] = await Promise.all([
813
- s.token0(),
814
- s.token1(),
815
- s.getReserves()
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: r,
1105
+ token0: s,
819
1106
  token1: a,
820
- protocol: w.PancakeV2,
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(t, e, n) {
830
- const o = `v3-${t}-${e}-${n}`;
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 s = await this.v3Factory.getPool(t, e, n);
834
- if (s === h.ZeroAddress)
1120
+ const r = await this.v3Factory.getPool(e, t, n);
1121
+ if (r === f.ZeroAddress)
835
1122
  return null;
836
- const r = new h.Contract(s, G, this.provider), [a, i, c] = await Promise.all([
837
- r.token0(),
838
- r.token1(),
839
- r.liquidity()
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: s,
1131
+ address: r,
845
1132
  token0: a,
846
1133
  token1: i,
847
- protocol: w.PancakeV3,
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(t, e, n, o) {
857
- const s = [];
858
- for (const r of t)
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
- r,
862
- e,
1172
+ s,
1173
+ t,
863
1174
  n,
864
1175
  o
865
1176
  );
866
- a > 0n && s.push({
1177
+ a > 0n && r.push({
867
1178
  steps: [
868
1179
  {
869
- pool: r,
870
- tokenIn: e,
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: r.protocol === w.PancakeV2 ? z : r.protocol === w.Dodo ? X : J
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 s;
1193
+ return r;
883
1194
  }
884
1195
  /**
885
1196
  * Get output for a single pool
886
1197
  */
887
- async getAmountOut(t, e, n, o) {
888
- if (t.protocol === w.PancakeV2)
889
- return this.getV2AmountOut(t, e, o);
890
- if (t.protocol === w.Dodo)
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(t, e, o);
1205
+ return this.estimateV3AmountOut(e, t, o);
893
1206
  }
894
1207
  /**
895
1208
  * V2 output calculation
896
1209
  */
897
- getV2AmountOut(t, e, n) {
898
- const o = e.toLowerCase() === t.token0.toLowerCase(), [s, r] = o ? [t.reserve0, t.reserve1] : [t.reserve1, t.reserve0], a = n * 9975n, i = a * r, c = s * 10000n + a;
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(t, e, n) {
905
- const s = 1000000n - BigInt(t.fee || 2500);
906
- return n * s / 1000000n;
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 it {
916
- constructor(t) {
917
- this.adapters = t;
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(t, e, n, o, s = y) {
923
- const r = this.flattenRoutes(t), a = this.mergeIdenticalPools(r), i = this.topologicalSort(a, e), c = this.convertToSwapSteps(i), u = this.extractIntermediates(
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
- e,
1245
+ t,
926
1246
  n
927
- ), d = BigInt(Math.floor(Date.now() / 1e3) + s);
1247
+ ), d = BigInt(Math.floor(Date.now() / 1e3) + r);
928
1248
  return {
929
- srcToken: e,
1249
+ srcToken: t,
930
1250
  dstToken: n,
931
- amountIn: t.totalAmountIn,
1251
+ amountIn: e.totalAmountIn,
932
1252
  amountOutMin: o,
933
1253
  steps: c,
934
1254
  intermediateTokens: u,
935
1255
  deadline: d,
936
- quoteId: h.ZeroHash,
937
- expectAmountOut: t.totalAmountOut
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(t) {
944
- const e = [];
945
- for (let n = 0; n < t.routes.length; n++) {
946
- const o = t.routes[n], s = t.percentages[n], r = t.totalAmountIn * BigInt(s) / 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
- e.push({
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 ? r : 0n,
1279
+ amountIn: a === 0 ? s : 0n,
955
1280
  routeIndex: n,
956
1281
  stepIndex: a
957
1282
  });
958
1283
  }
959
1284
  }
960
- return e;
1285
+ return t;
961
1286
  }
962
1287
  /**
963
1288
  * Merge identical pools
964
1289
  * Key: pool + tokenIn + tokenOut
965
1290
  */
966
- mergeIdenticalPools(t) {
967
- const e = /* @__PURE__ */ new Map(), n = [];
968
- for (const o of t) {
969
- const s = `${o.pool.address}-${o.tokenIn}-${o.tokenOut}`;
970
- if (e.has(s)) {
971
- const r = e.get(s);
972
- o.amountIn > 0n && r.amountIn > 0n && (r.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 r = { ...o };
975
- e.set(s, r), n.push(r);
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 s = `${o.pool.address}-${o.tokenIn}-${o.tokenOut}`;
980
- t.filter(
981
- (a) => `${a.pool.address}-${a.tokenIn}-${a.tokenOut}` === s
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(t, e) {
990
- const n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map();
991
- for (const i of t) {
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), s.set(c, []);
1318
+ o.set(c, i), n.set(c, 0), r.set(c, []);
994
1319
  }
995
- for (const i of t) {
1320
+ for (const i of e) {
996
1321
  const c = this.stepKey(i);
997
- if (i.tokenIn !== e) {
998
- for (const u of t)
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 && (s.get(d).push(c), n.set(c, (n.get(c) || 0) + 1));
1326
+ d !== c && (r.get(d).push(c), n.set(c, (n.get(c) || 0) + 1));
1002
1327
  }
1003
1328
  }
1004
1329
  }
1005
- const r = [];
1330
+ const s = [];
1006
1331
  for (const [i, c] of n)
1007
- c === 0 && r.push(i);
1332
+ c === 0 && s.push(i);
1008
1333
  const a = [];
1009
- for (; r.length > 0; ) {
1010
- const i = r.shift(), c = o.get(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 s.get(i) || []) {
1337
+ for (const u of r.get(i) || []) {
1013
1338
  const d = (n.get(u) || 0) - 1;
1014
- n.set(u, d), d === 0 && r.push(u);
1339
+ n.set(u, d), d === 0 && s.push(u);
1015
1340
  }
1016
1341
  }
1017
- if (a.length !== t.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(t) {
1025
- return t.map((e) => {
1026
- const n = this.adapters.get(e.pool.protocol);
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: ${e.pool.protocol}`);
1353
+ throw new Error(`No adapter for protocol: ${t.pool.protocol}`);
1029
1354
  return {
1030
1355
  adapter: n,
1031
- pool: e.pool.address,
1032
- tokenIn: e.tokenIn,
1033
- tokenOut: e.tokenOut,
1034
- amountIn: e.amountIn,
1035
- extraData: this.encodeExtraData(e.pool)
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(t) {
1043
- switch (t.protocol) {
1044
- case w.PancakeV2:
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 w.PancakeV3:
1048
- case w.UniswapV3:
1049
- case w.UniswapV4:
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 w.Dodo:
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(t, e, n) {
1412
+ extractIntermediates(e, t, n) {
1061
1413
  const o = /* @__PURE__ */ new Set();
1062
- for (const s of t)
1063
- s.tokenOut !== n && o.add(s.tokenOut);
1064
- return o.delete(e), o.delete(n), Array.from(o);
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(t) {
1070
- return `${t.pool.address}-${t.tokenIn}-${t.tokenOut}`;
1421
+ stepKey(e) {
1422
+ return `${e.pool.address}-${e.tokenIn}-${e.tokenOut}`;
1071
1423
  }
1072
1424
  }
1073
1425
  export {
1074
- I as API_DEFAULTS,
1075
- M as ApiClient,
1076
- v as ApiError,
1077
- O as BPS_DENOMINATOR,
1078
- ot as BSC_MAINNET_CONFIG,
1079
- rt as BSC_TESTNET_CONFIG,
1080
- V as DEFAULT_API_URL,
1081
- y as DEFAULT_DEADLINE_SECONDS,
1082
- D as DEFAULT_EXECUTE_TIMEOUT_MS,
1083
- et as DEFAULT_SLIPPAGE_BPS,
1084
- x as DEFAULT_TRANSACTION_RESPONSE_POLL_INTERVALS_MS,
1085
- nt as ERR_ZERO_AMOUNT_PATHS,
1086
- N as ExecuteTimeoutError,
1087
- $ as NATIVE_TOKEN_ADDRESS,
1088
- st as PeachClient,
1089
- w as ProtocolType,
1090
- at as RouteDiscovery,
1091
- it as SwapBuilder,
1092
- _ as isNativeTokenAddress,
1093
- b as withWalletSendTimeout
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