@blazephoenix/sdk 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,540 @@
1
+ // src/constants.ts
2
+ var API_BASE = "https://blazephoenix.xyz";
3
+ var CHAINS = {
4
+ 1: {
5
+ chainId: 1,
6
+ name: "Ethereum",
7
+ explorer: "https://etherscan.io",
8
+ weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
9
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
10
+ contracts: {
11
+ hub: "0xc4FA9a5720fe3294D3AA9fc427E2a760591E57ae",
12
+ solver: "0xc124d91258db0C14bf13b826CF64E16bfEA8a73e",
13
+ router: "0xE1aE5f49013920CF71De8CED4043e14C4d63416b",
14
+ quoter: "0x4a20AA0912388ff7A9221Ab6BFC224cc20Baa0c3"
15
+ }
16
+ },
17
+ 8453: {
18
+ chainId: 8453,
19
+ name: "Base",
20
+ explorer: "https://basescan.org",
21
+ weth: "0x4200000000000000000000000000000000000006",
22
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
23
+ bzpx: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
24
+ contracts: {
25
+ hub: "0x428554DEe93A1B8B5Bc6Fd19adDAfe55106fc04C",
26
+ solver: "0xB1902990260975dD4C89ad74B1f317bc100CB830",
27
+ router: "0x2a779f9Be49aac57495A8B6467Cc325a8a47Eb9f",
28
+ quoter: "0x4cEF0615614B212895F45Aa1D4833B16666E18d3"
29
+ }
30
+ },
31
+ 10: {
32
+ chainId: 10,
33
+ name: "Optimism",
34
+ explorer: "https://optimistic.etherscan.io",
35
+ weth: "0x4200000000000000000000000000000000000006",
36
+ usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
37
+ contracts: {
38
+ hub: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
39
+ solver: "0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f",
40
+ router: "0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A",
41
+ quoter: "0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2"
42
+ }
43
+ },
44
+ 42161: {
45
+ chainId: 42161,
46
+ name: "Arbitrum",
47
+ explorer: "https://arbiscan.io",
48
+ weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
49
+ usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
50
+ contracts: {
51
+ hub: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
52
+ solver: "0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f",
53
+ router: "0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A",
54
+ quoter: "0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2"
55
+ }
56
+ }
57
+ };
58
+ function resolveChain(chain) {
59
+ const aliases = {
60
+ "1": 1,
61
+ eth: 1,
62
+ ethereum: 1,
63
+ mainnet: 1,
64
+ "8453": 8453,
65
+ base: 8453,
66
+ "10": 10,
67
+ op: 10,
68
+ optimism: 10,
69
+ "42161": 42161,
70
+ arb: 42161,
71
+ arbitrum: 42161,
72
+ "arbitrum-one": 42161
73
+ };
74
+ const id = aliases[String(chain).trim().toLowerCase()];
75
+ if (!id) {
76
+ throw new Error(
77
+ `Unsupported chain "${chain}" \u2014 use 8453/base, 1/eth, 10/optimism or 42161/arbitrum`
78
+ );
79
+ }
80
+ return id;
81
+ }
82
+ var PUBLIC_RPCS = {
83
+ 1: [
84
+ "https://ethereum-rpc.publicnode.com",
85
+ "https://cloudflare-eth.com",
86
+ "https://1rpc.io/eth"
87
+ ],
88
+ 8453: [
89
+ "https://mainnet.base.org",
90
+ "https://base-rpc.publicnode.com",
91
+ "https://1rpc.io/base"
92
+ ],
93
+ 10: [
94
+ "https://optimism-rpc.publicnode.com",
95
+ "https://mainnet.optimism.io",
96
+ "https://1rpc.io/op"
97
+ ],
98
+ 42161: [
99
+ "https://arbitrum-one-rpc.publicnode.com",
100
+ "https://arb1.arbitrum.io/rpc",
101
+ "https://1rpc.io/arb"
102
+ ]
103
+ };
104
+ var FEE_BPS = 28;
105
+ var SWAP_TOPIC0 = "0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413";
106
+ var SURPLUS_TOPIC0 = "0x1a3afef0f067eb51a6bfec6ab3625a4408dd8c3571b72836483e68feb70d1026";
107
+
108
+ // src/resilience.ts
109
+ var INFLIGHT = /* @__PURE__ */ new Map();
110
+ var MEM = /* @__PURE__ */ new Map();
111
+ async function singleflight(key, fn) {
112
+ const existing = INFLIGHT.get(key);
113
+ if (existing) return existing;
114
+ const flight = fn();
115
+ INFLIGHT.set(key, flight);
116
+ try {
117
+ return await flight;
118
+ } finally {
119
+ INFLIGHT.delete(key);
120
+ }
121
+ }
122
+ function memGet(key, ttlMs, now = Date.now()) {
123
+ if (ttlMs <= 0) return void 0;
124
+ const hit = MEM.get(key);
125
+ return hit && now - hit.at < ttlMs ? hit.data : void 0;
126
+ }
127
+ function memPut(key, data, now = Date.now()) {
128
+ MEM.set(key, { at: now, data });
129
+ if (MEM.size > 500) {
130
+ const oldest = MEM.keys().next().value;
131
+ if (oldest !== void 0) MEM.delete(oldest);
132
+ }
133
+ }
134
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
135
+ function retryDelayMs(res, attempt, base) {
136
+ const ra = Number(res?.headers.get("retry-after"));
137
+ if (Number.isFinite(ra) && ra > 0) return Math.min(1e4, ra * 1e3);
138
+ return base * 3 ** attempt + Math.floor(Math.random() * base);
139
+ }
140
+ function isTransient(res) {
141
+ return !res || res.status === 429 || res.status === 502 || res.status === 503 || res.status === 504;
142
+ }
143
+ async function resilientFetch(fetchFn, url, init, opts = {}) {
144
+ const { retries = 2, backoffMs = 250, timeoutMs = 15e3 } = opts;
145
+ let lastErr;
146
+ for (let attempt = 0; attempt <= retries; attempt++) {
147
+ let res;
148
+ try {
149
+ res = await fetchFn(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
150
+ if (!isTransient(res)) return res;
151
+ if (attempt === retries) return res;
152
+ } catch (e) {
153
+ lastErr = e;
154
+ if (attempt === retries) throw e;
155
+ }
156
+ await sleep(retryDelayMs(res, attempt, backoffMs));
157
+ }
158
+ throw lastErr instanceof Error ? lastErr : new Error("request failed");
159
+ }
160
+
161
+ // src/client.ts
162
+ var BlazeApiError = class extends Error {
163
+ code;
164
+ status;
165
+ constructor(code, message, status) {
166
+ super(message);
167
+ this.name = "BlazeApiError";
168
+ this.code = code;
169
+ this.status = status;
170
+ }
171
+ };
172
+ function toSearch(req) {
173
+ const sp = new URLSearchParams();
174
+ sp.set("chain", String(resolveChain(req.chain)));
175
+ sp.set("in", req.tokenIn.trim());
176
+ sp.set("out", req.tokenOut.trim());
177
+ sp.set("amountIn", typeof req.amountIn === "bigint" ? req.amountIn.toString() : String(req.amountIn).trim());
178
+ if (req.recipient) sp.set("recipient", req.recipient);
179
+ if (req.slippageBps !== void 0) sp.set("slippageBps", String(req.slippageBps));
180
+ if (req.deadlineSec !== void 0) sp.set("deadlineSec", String(req.deadlineSec));
181
+ if (req.exact) sp.set("exact", "1");
182
+ return sp;
183
+ }
184
+ var BlazePhoenix = class {
185
+ base;
186
+ fetchFn;
187
+ timeoutMs;
188
+ retries;
189
+ cacheTtlMs;
190
+ constructor(opts = {}) {
191
+ this.base = (opts.baseUrl ?? API_BASE).replace(/\/+$/, "");
192
+ this.fetchFn = opts.fetchFn ?? globalThis.fetch;
193
+ this.timeoutMs = opts.timeoutMs ?? 15e3;
194
+ this.retries = opts.retries ?? 2;
195
+ this.cacheTtlMs = opts.cacheTtlMs ?? 1e3;
196
+ if (!this.fetchFn) throw new Error("No fetch available \u2014 Node >= 18 required (or pass fetchFn)");
197
+ }
198
+ /** Build the GET /api/quote URL for a request (useful for logging/debugging). */
199
+ quoteUrl(req) {
200
+ return `${this.base}/api/quote?${toSearch(req).toString()}`;
201
+ }
202
+ async call(path, init) {
203
+ const res = await resilientFetch(this.fetchFn, `${this.base}${path}`, init, {
204
+ retries: this.retries,
205
+ timeoutMs: this.timeoutMs
206
+ });
207
+ const body = await res.json().catch(() => null);
208
+ if (!body || typeof body !== "object") {
209
+ throw new BlazeApiError("bad_response", `non-JSON response (HTTP ${res.status})`, res.status);
210
+ }
211
+ if ("ok" in body && body.ok === false) {
212
+ throw new BlazeApiError(body.code ?? "error", body.error ?? "request failed", res.status);
213
+ }
214
+ return body;
215
+ }
216
+ /** One quote — previewPlan computed on-chain. Throws BlazeApiError on failure.
217
+ * Identical concurrent calls share one request; preview quotes ride a tiny
218
+ * micro-cache (cacheTtlMs) so hot loops never hammer the wire. */
219
+ async quote(req) {
220
+ const qs = toSearch(req).toString();
221
+ const key = `Q ${this.base}?${qs}`;
222
+ const cacheable = !req.recipient && !req.exact && this.cacheTtlMs > 0;
223
+ if (cacheable) {
224
+ const hit = memGet(key, this.cacheTtlMs);
225
+ if (hit) return hit;
226
+ }
227
+ const q = await singleflight(key, () => this.call(`/api/quote?${qs}`));
228
+ if (cacheable) memPut(key, q);
229
+ return q;
230
+ }
231
+ /** Up to 10 quotes in one round-trip (screeners / arb loops).
232
+ * Per-item failures come back inline — the batch itself only throws on
233
+ * transport/validation errors. Identical concurrent batches coalesce. */
234
+ quoteBatch(reqs) {
235
+ const body = JSON.stringify({
236
+ requests: reqs.map((r) => Object.fromEntries(toSearch(r).entries()))
237
+ });
238
+ return singleflight(`B ${this.base} ${body}`, () => this.call("/api/quote/batch", {
239
+ method: "POST",
240
+ headers: { "content-type": "application/json" },
241
+ body
242
+ }));
243
+ }
244
+ /** Service health + per-chain live flags. Zero upstream cost server-side —
245
+ * poll it from your monitor as often as you like. */
246
+ health() {
247
+ return this.call("/api/health");
248
+ }
249
+ /** Machine-readable protocol manifest — near-static, cached for 1h. */
250
+ async manifest() {
251
+ const key = `M ${this.base}`;
252
+ const hit = memGet(key, 36e5);
253
+ if (hit) return hit;
254
+ const m = await singleflight(key, () => this.call("/api/manifest"));
255
+ memPut(key, m);
256
+ return m;
257
+ }
258
+ };
259
+ function pollQuote(client, req, onQuote, opts = {}) {
260
+ const interval = Math.max(500, opts.intervalMs ?? 4e3);
261
+ let stopped = false;
262
+ let busy = false;
263
+ const tick = async () => {
264
+ if (stopped || busy) return;
265
+ busy = true;
266
+ try {
267
+ const q = await client.quote(req);
268
+ if (!stopped) onQuote(q);
269
+ } catch (e) {
270
+ if (!stopped) opts.onError?.(e);
271
+ } finally {
272
+ busy = false;
273
+ }
274
+ };
275
+ void tick();
276
+ const timer = setInterval(() => {
277
+ void tick();
278
+ }, interval);
279
+ return () => {
280
+ stopped = true;
281
+ clearInterval(timer);
282
+ };
283
+ }
284
+ function buildSwapTx(q) {
285
+ if (q.tx) return q.tx;
286
+ if (q.wrapRequired) {
287
+ throw new Error("native ETH input: wrap to WETH first (WETH.deposit), then re-quote with in=WETH");
288
+ }
289
+ throw new Error("no tx in quote \u2014 pass `recipient` in the request (and check quote.canExecute)");
290
+ }
291
+ function deepLink(opts = {}) {
292
+ const base = (opts.baseUrl ?? API_BASE).replace(/\/+$/, "");
293
+ const sp = new URLSearchParams();
294
+ sp.set("tab", opts.tab ?? "swap");
295
+ if (opts.chain !== void 0) sp.set("chain", String(resolveChain(opts.chain)));
296
+ if (opts.tokenIn) sp.set("in", opts.tokenIn);
297
+ if (opts.tokenOut) sp.set("out", opts.tokenOut);
298
+ if (opts.amount) sp.set("amt", opts.amount);
299
+ return `${base}/?${sp.toString()}`;
300
+ }
301
+
302
+ // src/abis.ts
303
+ var LEG_COMPONENTS = [
304
+ { name: "pool", type: "address" },
305
+ { name: "hooks", type: "address" },
306
+ { name: "kind", type: "uint8" },
307
+ { name: "fee", type: "uint24" },
308
+ { name: "tickSpacing", type: "int24" },
309
+ { name: "zeroForOne", type: "bool" },
310
+ { name: "stable", type: "bool" },
311
+ { name: "amountIn", type: "uint256" },
312
+ { name: "expectedOut", type: "uint256" },
313
+ { name: "auxId", type: "bytes32" }
314
+ ];
315
+ var HOP_COMPONENTS = [
316
+ { name: "tokenIn", type: "address" },
317
+ { name: "tokenOut", type: "address" },
318
+ { name: "amountIn", type: "uint256" },
319
+ { name: "expectedOut", type: "uint256" },
320
+ { name: "legs", type: "tuple[]", components: LEG_COMPONENTS }
321
+ ];
322
+ var ROUTE_COMPONENTS = [
323
+ { name: "hops", type: "tuple[]", components: HOP_COMPONENTS },
324
+ { name: "totalOut", type: "uint256" },
325
+ { name: "singleOut", type: "uint256" },
326
+ { name: "singleOutFloor", type: "uint256" },
327
+ { name: "expectedImpactBps", type: "uint256" },
328
+ { name: "confidenceWad", type: "uint256" },
329
+ { name: "estGas", type: "uint256" },
330
+ { name: "hasSurplus", type: "bool" },
331
+ { name: "isV4Bundle", type: "bool" }
332
+ ];
333
+ var PREVIEW_COMPONENTS = [
334
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
335
+ { name: "grossOut", type: "uint256" },
336
+ { name: "protocolFee", type: "uint256" },
337
+ { name: "safetyBuffer", type: "uint256" },
338
+ { name: "netOut", type: "uint256" },
339
+ { name: "ironFloor", type: "uint256" },
340
+ { name: "userMinOut", type: "uint256" },
341
+ { name: "effectiveMinOut", type: "uint256" },
342
+ { name: "estGas", type: "uint256" },
343
+ { name: "hops", type: "uint256" },
344
+ { name: "legs", type: "uint256" },
345
+ { name: "topology", type: "uint8" },
346
+ { name: "bridgeUsed", type: "address" },
347
+ { name: "canExecute", type: "bool" }
348
+ ];
349
+ var QUOTER_ABI = [
350
+ {
351
+ type: "function",
352
+ name: "previewPlan",
353
+ stateMutability: "view",
354
+ inputs: [
355
+ { name: "tIn", type: "address" },
356
+ { name: "tOut", type: "address" },
357
+ { name: "amountIn", type: "uint256" }
358
+ ],
359
+ outputs: [
360
+ { name: "pv", type: "tuple", components: PREVIEW_COMPONENTS },
361
+ { name: "fallbackRoute", type: "tuple", components: ROUTE_COMPONENTS },
362
+ { name: "hasFallback", type: "bool" }
363
+ ]
364
+ },
365
+ {
366
+ type: "function",
367
+ name: "previewPlanExact",
368
+ stateMutability: "view",
369
+ inputs: [
370
+ { name: "tIn", type: "address" },
371
+ { name: "tOut", type: "address" },
372
+ { name: "amountIn", type: "uint256" }
373
+ ],
374
+ outputs: [
375
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
376
+ { name: "exactOut", type: "uint256" }
377
+ ]
378
+ }
379
+ ];
380
+ var ROUTER_ABI = [
381
+ {
382
+ type: "function",
383
+ name: "swapExactIn",
384
+ stateMutability: "nonpayable",
385
+ inputs: [
386
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
387
+ { name: "amountIn", type: "uint256" },
388
+ { name: "userMinOut", type: "uint256" },
389
+ { name: "recipient", type: "address" },
390
+ { name: "deadline", type: "uint256" }
391
+ ],
392
+ outputs: [{ name: "amountOut", type: "uint256" }]
393
+ },
394
+ {
395
+ type: "event",
396
+ name: "Swap",
397
+ inputs: [
398
+ { name: "user", type: "address", indexed: true },
399
+ { name: "tokenIn", type: "address", indexed: true },
400
+ { name: "tokenOut", type: "address", indexed: true },
401
+ { name: "amountIn", type: "uint256", indexed: false },
402
+ { name: "amountOut", type: "uint256", indexed: false },
403
+ { name: "legs", type: "uint256", indexed: false }
404
+ ]
405
+ },
406
+ {
407
+ type: "event",
408
+ name: "Surplus",
409
+ inputs: [
410
+ { name: "token", type: "address", indexed: true },
411
+ { name: "amount", type: "uint256", indexed: false }
412
+ ]
413
+ }
414
+ ];
415
+
416
+ // src/erc20.ts
417
+ var MAX_UINT256 = (1n << 256n) - 1n;
418
+ var HEX_ADDR = /^0x[0-9a-fA-F]{40}$/;
419
+ var APPROVE_SELECTOR = "0x095ea7b3";
420
+ function pad32(hexNo0x) {
421
+ return hexNo0x.padStart(64, "0");
422
+ }
423
+ function buildApproveTx(opts) {
424
+ const chainId = resolveChain(opts.chain);
425
+ const spender = opts.spender ?? CHAINS[chainId].contracts.router;
426
+ if (!HEX_ADDR.test(opts.token)) throw new Error(`invalid token address: ${opts.token}`);
427
+ if (!HEX_ADDR.test(spender)) throw new Error(`invalid spender address: ${spender}`);
428
+ if (opts.amount < 0n || opts.amount > MAX_UINT256) throw new Error("amount out of uint256 range");
429
+ const data = APPROVE_SELECTOR + pad32(spender.slice(2).toLowerCase()) + pad32(opts.amount.toString(16));
430
+ return { to: opts.token, data, value: "0" };
431
+ }
432
+ function toBaseUnits(amount, decimals) {
433
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {
434
+ throw new Error(`invalid decimals: ${decimals}`);
435
+ }
436
+ const s = amount.trim();
437
+ const m = /^(\d+)(?:\.(\d+))?$/.exec(s);
438
+ if (!m) throw new Error(`invalid amount: "${amount}" (use e.g. "1.5")`);
439
+ const [, whole, frac = ""] = m;
440
+ if (frac.length > decimals) {
441
+ throw new Error(`"${amount}" has ${frac.length} fractional digits \u2014 token only carries ${decimals}`);
442
+ }
443
+ return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(frac.padEnd(decimals, "0") || "0");
444
+ }
445
+ function fromBaseUnits(v, decimals, maxDp) {
446
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {
447
+ throw new Error(`invalid decimals: ${decimals}`);
448
+ }
449
+ const n = typeof v === "bigint" ? v : BigInt(v);
450
+ const neg = n < 0n;
451
+ const abs = neg ? -n : n;
452
+ const base = 10n ** BigInt(decimals);
453
+ const whole = abs / base;
454
+ let frac = (abs % base).toString().padStart(decimals, "0");
455
+ if (maxDp !== void 0) frac = frac.slice(0, Math.max(0, maxDp));
456
+ frac = frac.replace(/0+$/, "");
457
+ return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
458
+ }
459
+
460
+ // src/onchain.ts
461
+ async function loadViem() {
462
+ try {
463
+ return await import('viem');
464
+ } catch {
465
+ throw new Error("this feature needs the optional peer dependency 'viem' \u2014 npm i viem");
466
+ }
467
+ }
468
+ async function transportFor(chainId, rpcUrl) {
469
+ const { http, fallback } = await loadViem();
470
+ return rpcUrl ? http(rpcUrl) : fallback(PUBLIC_RPCS[chainId].map((u) => http(u)));
471
+ }
472
+ async function quoteOnChain(opts) {
473
+ const { createPublicClient } = await loadViem();
474
+ const chainId = resolveChain(opts.chain);
475
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
476
+ const [pv, , hasFallback] = await client.readContract({
477
+ address: CHAINS[chainId].contracts.quoter,
478
+ abi: QUOTER_ABI,
479
+ functionName: "previewPlan",
480
+ args: [opts.tokenIn, opts.tokenOut, opts.amountIn]
481
+ });
482
+ return { preview: pv, hasFallback, chainId };
483
+ }
484
+ async function watchFills(opts) {
485
+ const { createPublicClient, parseAbiItem } = await loadViem();
486
+ const chainId = resolveChain(opts.chain);
487
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
488
+ return client.watchEvent({
489
+ address: CHAINS[chainId].contracts.router,
490
+ event: parseAbiItem(
491
+ "event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)"
492
+ ),
493
+ pollingInterval: opts.pollMs ?? 4e3,
494
+ onLogs: (logs) => {
495
+ for (const log of logs) {
496
+ const a = log.args;
497
+ opts.onFill({
498
+ txHash: log.transactionHash,
499
+ blockNumber: log.blockNumber ?? 0n,
500
+ user: a.user,
501
+ tokenIn: a.tokenIn,
502
+ tokenOut: a.tokenOut,
503
+ amountIn: a.amountIn,
504
+ amountOut: a.amountOut,
505
+ legs: a.legs
506
+ });
507
+ }
508
+ }
509
+ });
510
+ }
511
+ async function getFills(opts) {
512
+ const { createPublicClient, parseAbiItem } = await loadViem();
513
+ const chainId = resolveChain(opts.chain);
514
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
515
+ const logs = await client.getLogs({
516
+ address: CHAINS[chainId].contracts.router,
517
+ event: parseAbiItem(
518
+ "event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)"
519
+ ),
520
+ fromBlock: opts.fromBlock,
521
+ toBlock: opts.toBlock
522
+ });
523
+ return logs.map((log) => {
524
+ const a = log.args;
525
+ return {
526
+ txHash: log.transactionHash,
527
+ blockNumber: log.blockNumber ?? 0n,
528
+ user: a.user,
529
+ tokenIn: a.tokenIn,
530
+ tokenOut: a.tokenOut,
531
+ amountIn: a.amountIn,
532
+ amountOut: a.amountOut,
533
+ legs: a.legs
534
+ };
535
+ });
536
+ }
537
+
538
+ export { API_BASE, BlazeApiError, BlazePhoenix, CHAINS, FEE_BPS, MAX_UINT256, PUBLIC_RPCS, QUOTER_ABI, ROUTER_ABI, SURPLUS_TOPIC0, SWAP_TOPIC0, buildApproveTx, buildSwapTx, deepLink, fromBaseUnits, getFills, pollQuote, quoteOnChain, resilientFetch, resolveChain, singleflight, toBaseUnits, watchFills };
539
+ //# sourceMappingURL=index.js.map
540
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/resilience.ts","../src/client.ts","../src/abis.ts","../src/erc20.ts","../src/onchain.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// =============================================================================\n// Protocol constants — BlazePhoenix v1.0.0 deployments.\n// Source of truth at runtime: GET https://blazephoenix.xyz/api/manifest\n// (these statics let the SDK work fully offline / on-chain-only).\n// =============================================================================\n\nexport const API_BASE = 'https://blazephoenix.xyz';\n\nexport type SupportedChainId = 1 | 8453 | 10 | 42161;\n\nexport interface ChainInfo {\n chainId: SupportedChainId;\n name: string;\n explorer: string;\n weth: `0x${string}`;\n usdc: `0x${string}`;\n bzpx?: `0x${string}`;\n contracts: {\n hub: `0x${string}`;\n solver: `0x${string}`;\n router: `0x${string}`;\n quoter: `0x${string}`;\n };\n}\n\nexport const CHAINS: Record<SupportedChainId, ChainInfo> = {\n 1: {\n chainId: 1,\n name: 'Ethereum',\n explorer: 'https://etherscan.io',\n weth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n contracts: {\n hub: '0xc4FA9a5720fe3294D3AA9fc427E2a760591E57ae',\n solver: '0xc124d91258db0C14bf13b826CF64E16bfEA8a73e',\n router: '0xE1aE5f49013920CF71De8CED4043e14C4d63416b',\n quoter: '0x4a20AA0912388ff7A9221Ab6BFC224cc20Baa0c3',\n },\n },\n 8453: {\n chainId: 8453,\n name: 'Base',\n explorer: 'https://basescan.org',\n weth: '0x4200000000000000000000000000000000000006',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n bzpx: '0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483',\n contracts: {\n hub: '0x428554DEe93A1B8B5Bc6Fd19adDAfe55106fc04C',\n solver: '0xB1902990260975dD4C89ad74B1f317bc100CB830',\n router: '0x2a779f9Be49aac57495A8B6467Cc325a8a47Eb9f',\n quoter: '0x4cEF0615614B212895F45Aa1D4833B16666E18d3',\n },\n },\n 10: {\n chainId: 10,\n name: 'Optimism',\n explorer: 'https://optimistic.etherscan.io',\n weth: '0x4200000000000000000000000000000000000006',\n usdc: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n contracts: {\n hub: '0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483',\n solver: '0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f',\n router: '0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A',\n quoter: '0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2',\n },\n },\n 42161: {\n chainId: 42161,\n name: 'Arbitrum',\n explorer: 'https://arbiscan.io',\n weth: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',\n usdc: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n contracts: {\n hub: '0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483',\n solver: '0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f',\n router: '0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A',\n quoter: '0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2',\n },\n },\n};\n\n/** Accepts a chain id (number or numeric string) or a human alias. */\nexport function resolveChain(chain: number | string): SupportedChainId {\n const aliases: Record<string, SupportedChainId> = {\n '1': 1, eth: 1, ethereum: 1, mainnet: 1,\n '8453': 8453, base: 8453,\n '10': 10, op: 10, optimism: 10,\n '42161': 42161, arb: 42161, arbitrum: 42161, 'arbitrum-one': 42161,\n };\n const id = aliases[String(chain).trim().toLowerCase()];\n if (!id) {\n throw new Error(\n `Unsupported chain \"${chain}\" — use 8453/base, 1/eth, 10/optimism or 42161/arbitrum`,\n );\n }\n return id;\n}\n\n/** Public, KEYLESS RPC endpoints per chain — community infrastructure, no\n * providers, no keys (enforced by tests). They make the on-chain module work\n * with ZERO configuration; production integrations should still bring their\n * own `rpcUrl` for guaranteed throughput. */\nexport const PUBLIC_RPCS: Record<SupportedChainId, string[]> = {\n 1: [\n 'https://ethereum-rpc.publicnode.com',\n 'https://cloudflare-eth.com',\n 'https://1rpc.io/eth',\n ],\n 8453: [\n 'https://mainnet.base.org',\n 'https://base-rpc.publicnode.com',\n 'https://1rpc.io/base',\n ],\n 10: [\n 'https://optimism-rpc.publicnode.com',\n 'https://mainnet.optimism.io',\n 'https://1rpc.io/op',\n ],\n 42161: [\n 'https://arbitrum-one-rpc.publicnode.com',\n 'https://arb1.arbitrum.io/rpc',\n 'https://1rpc.io/arb',\n ],\n};\n\n/** Protocol fee (bps) applied to quoted output; execution surplus is fee-exempt. */\nexport const FEE_BPS = 28;\n\n/** Router event topic0 hashes (one `Swap` per fill — index everything with them).\n * Verified against the ABIs by `npm test` (viem toEventSelector). */\nexport const SWAP_TOPIC0 =\n '0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413' as const;\nexport const SURPLUS_TOPIC0 =\n '0x1a3afef0f067eb51a6bfec6ab3625a4408dd8c3571b72836483e68feb70d1026' as const;\n","// =============================================================================\n// Resilience core — the SDK ships the same meta-patterns the BlazePhoenix\n// edge runs, so every integration is polite and outage-proof by default:\n//\n// • singleflight — identical concurrent calls share ONE request\n// • micro-TTL — a tiny preview cache (default 1s ≈ intra-block) absorbs\n// hot loops without ever serving stale execution data\n// • retry — transient failures (network, 429, 502/503) retry with\n// backoff and RESPECT the server's retry-after header\n//\n// Execution-grade requests (recipient / exact=1) are never TTL-cached here,\n// mirroring the server's own red line.\n// =============================================================================\n\nconst INFLIGHT = new Map<string, Promise<unknown>>();\nconst MEM = new Map<string, { at: number; data: unknown }>();\n\n/** Coalesce concurrent identical work — leader runs, followers share. */\nexport async function singleflight<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const existing = INFLIGHT.get(key) as Promise<T> | undefined;\n if (existing) return existing;\n const flight = fn();\n INFLIGHT.set(key, flight as Promise<unknown>);\n try {\n return await flight;\n } finally {\n INFLIGHT.delete(key);\n }\n}\n\nexport function memGet(key: string, ttlMs: number, now = Date.now()): unknown | undefined {\n if (ttlMs <= 0) return undefined;\n const hit = MEM.get(key);\n return hit && now - hit.at < ttlMs ? hit.data : undefined;\n}\n\nexport function memPut(key: string, data: unknown, now = Date.now()): void {\n MEM.set(key, { at: now, data });\n // Bound the cache — a long-running bot must never leak memory here.\n if (MEM.size > 500) {\n const oldest = MEM.keys().next().value;\n if (oldest !== undefined) MEM.delete(oldest);\n }\n}\n\nexport interface RetryOptions {\n /** Extra attempts after the first (default 2). */\n retries?: number;\n /** Base backoff in ms; grows ×3 per attempt with jitter (default 250). */\n backoffMs?: number;\n timeoutMs?: number;\n}\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));\n\nfunction retryDelayMs(res: Response | undefined, attempt: number, base: number): number {\n const ra = Number(res?.headers.get('retry-after'));\n if (Number.isFinite(ra) && ra > 0) return Math.min(10_000, ra * 1000);\n return base * 3 ** attempt + Math.floor(Math.random() * base);\n}\n\n/** Quote reads are idempotent — transient failures deserve another shot. */\nfunction isTransient(res: Response | undefined): boolean {\n return !res || res.status === 429 || res.status === 502 || res.status === 503 || res.status === 504;\n}\n\n/** fetch with timeout + polite retries. Returns the final Response (which may\n * still be an error status — non-transient statuses are never retried). */\nexport async function resilientFetch(\n fetchFn: typeof fetch,\n url: string,\n init: RequestInit | undefined,\n opts: RetryOptions = {},\n): Promise<Response> {\n const { retries = 2, backoffMs = 250, timeoutMs = 15_000 } = opts;\n let lastErr: unknown;\n for (let attempt = 0; attempt <= retries; attempt++) {\n let res: Response | undefined;\n try {\n res = await fetchFn(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });\n if (!isTransient(res)) return res;\n if (attempt === retries) return res;\n } catch (e) {\n lastErr = e;\n if (attempt === retries) throw e;\n }\n await sleep(retryDelayMs(res, attempt, backoffMs));\n }\n /* istanbul ignore next -- loop always returns or throws */\n throw lastErr instanceof Error ? lastErr : new Error('request failed');\n}\n\n/** Test hook. */\nexport function __resetResilience(): void {\n INFLIGHT.clear();\n MEM.clear();\n}\n","// =============================================================================\n// HTTP client — zero dependencies (native fetch). Every quote is computed\n// on-chain by the BlazePhoenix Quoter; the API is a thin mirror of the chain.\n// No API key. Open CORS. https://blazephoenix.xyz/?tab=api\n// =============================================================================\n\nimport { API_BASE, resolveChain } from './constants.js';\nimport { memGet, memPut, resilientFetch, singleflight } from './resilience.js';\nimport type {\n BatchResponse, HealthResponse, ManifestResponse, QuoteRequest, QuoteResponse, QuoteTx,\n} from './types.js';\n\nexport class BlazeApiError extends Error {\n readonly code: string;\n readonly status: number;\n constructor(code: string, message: string, status: number) {\n super(message);\n this.name = 'BlazeApiError';\n this.code = code;\n this.status = status;\n }\n}\n\nexport interface ClientOptions {\n /** Override the API origin (e.g. a mirror). Default: https://blazephoenix.xyz */\n baseUrl?: string;\n /** Custom fetch (tests, proxies). Default: globalThis.fetch. */\n fetchFn?: typeof fetch;\n /** Per-request timeout in ms. Default 15000. */\n timeoutMs?: number;\n /** Extra attempts on transient failures (network, 429, 502-504), honouring\n * the server's retry-after. Default 2. Set 0 to disable. */\n retries?: number;\n /** Micro-cache for PREVIEW quotes (no recipient, no exact) — absorbs hot\n * loops without serving stale execution data. Default 1000ms; 0 disables. */\n cacheTtlMs?: number;\n}\n\nfunction toSearch(req: QuoteRequest): URLSearchParams {\n const sp = new URLSearchParams();\n sp.set('chain', String(resolveChain(req.chain)));\n sp.set('in', req.tokenIn.trim());\n sp.set('out', req.tokenOut.trim());\n sp.set('amountIn', typeof req.amountIn === 'bigint' ? req.amountIn.toString() : String(req.amountIn).trim());\n if (req.recipient) sp.set('recipient', req.recipient);\n if (req.slippageBps !== undefined) sp.set('slippageBps', String(req.slippageBps));\n if (req.deadlineSec !== undefined) sp.set('deadlineSec', String(req.deadlineSec));\n if (req.exact) sp.set('exact', '1');\n return sp;\n}\n\nexport class BlazePhoenix {\n private readonly base: string;\n private readonly fetchFn: typeof fetch;\n private readonly timeoutMs: number;\n private readonly retries: number;\n private readonly cacheTtlMs: number;\n\n constructor(opts: ClientOptions = {}) {\n this.base = (opts.baseUrl ?? API_BASE).replace(/\\/+$/, '');\n this.fetchFn = opts.fetchFn ?? globalThis.fetch;\n this.timeoutMs = opts.timeoutMs ?? 15_000;\n this.retries = opts.retries ?? 2;\n this.cacheTtlMs = opts.cacheTtlMs ?? 1_000;\n if (!this.fetchFn) throw new Error('No fetch available — Node >= 18 required (or pass fetchFn)');\n }\n\n /** Build the GET /api/quote URL for a request (useful for logging/debugging). */\n quoteUrl(req: QuoteRequest): string {\n return `${this.base}/api/quote?${toSearch(req).toString()}`;\n }\n\n private async call<T>(path: string, init?: RequestInit): Promise<T> {\n const res = await resilientFetch(this.fetchFn, `${this.base}${path}`, init, {\n retries: this.retries,\n timeoutMs: this.timeoutMs,\n });\n const body = (await res.json().catch(() => null)) as\n | (T & { ok: true })\n | { ok: false; code?: string; error?: string }\n | null;\n if (!body || typeof body !== 'object') {\n throw new BlazeApiError('bad_response', `non-JSON response (HTTP ${res.status})`, res.status);\n }\n if ('ok' in body && body.ok === false) {\n throw new BlazeApiError(body.code ?? 'error', body.error ?? 'request failed', res.status);\n }\n return body as T;\n }\n\n /** One quote — previewPlan computed on-chain. Throws BlazeApiError on failure.\n * Identical concurrent calls share one request; preview quotes ride a tiny\n * micro-cache (cacheTtlMs) so hot loops never hammer the wire. */\n async quote(req: QuoteRequest): Promise<QuoteResponse> {\n const qs = toSearch(req).toString();\n const key = `Q ${this.base}?${qs}`;\n const cacheable = !req.recipient && !req.exact && this.cacheTtlMs > 0;\n if (cacheable) {\n const hit = memGet(key, this.cacheTtlMs);\n if (hit) return hit as QuoteResponse;\n }\n const q = await singleflight(key, () => this.call<QuoteResponse>(`/api/quote?${qs}`));\n if (cacheable) memPut(key, q);\n return q;\n }\n\n /** Up to 10 quotes in one round-trip (screeners / arb loops).\n * Per-item failures come back inline — the batch itself only throws on\n * transport/validation errors. Identical concurrent batches coalesce. */\n quoteBatch(reqs: QuoteRequest[]): Promise<BatchResponse> {\n const body = JSON.stringify({\n requests: reqs.map((r) => Object.fromEntries(toSearch(r).entries())),\n });\n return singleflight(`B ${this.base} ${body}`, () =>\n this.call<BatchResponse>('/api/quote/batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body,\n }));\n }\n\n /** Service health + per-chain live flags. Zero upstream cost server-side —\n * poll it from your monitor as often as you like. */\n health(): Promise<HealthResponse> {\n return this.call<HealthResponse>('/api/health');\n }\n\n /** Machine-readable protocol manifest — near-static, cached for 1h. */\n async manifest(): Promise<ManifestResponse> {\n const key = `M ${this.base}`;\n const hit = memGet(key, 3_600_000);\n if (hit) return hit as ManifestResponse;\n const m = await singleflight(key, () => this.call<ManifestResponse>('/api/manifest'));\n memPut(key, m);\n return m;\n }\n}\n\nexport interface PollOptions {\n /** Tick interval in ms (min 500, default 4000). */\n intervalMs?: number;\n onError?: (e: unknown) => void;\n}\n\n/** Poll a pair and get called back with each fresh quote — the heartbeat of a\n * price bot in one line. Overlap-safe (a slow tick is skipped, not stacked).\n * Returns a stop function. */\nexport function pollQuote(\n client: BlazePhoenix,\n req: QuoteRequest,\n onQuote: (q: QuoteResponse) => void,\n opts: PollOptions = {},\n): () => void {\n const interval = Math.max(500, opts.intervalMs ?? 4_000);\n let stopped = false;\n let busy = false;\n const tick = async () => {\n if (stopped || busy) return;\n busy = true;\n try {\n const q = await client.quote(req);\n if (!stopped) onQuote(q);\n } catch (e) {\n if (!stopped) opts.onError?.(e);\n } finally {\n busy = false;\n }\n };\n void tick();\n const timer = setInterval(() => { void tick(); }, interval);\n return () => { stopped = true; clearInterval(timer); };\n}\n\n/** The ready-to-broadcast transaction from a quote (requires `recipient` in the\n * request and an ERC-20 input). Throws with a precise reason otherwise. */\nexport function buildSwapTx(q: QuoteResponse): QuoteTx {\n if (q.tx) return q.tx;\n if (q.wrapRequired) {\n throw new Error('native ETH input: wrap to WETH first (WETH.deposit), then re-quote with in=WETH');\n }\n throw new Error('no tx in quote — pass `recipient` in the request (and check quote.canExecute)');\n}\n\nexport interface DeepLinkOptions {\n chain?: number | string;\n tokenIn?: string;\n tokenOut?: string;\n /** Human units for the pay field (e.g. \"0.5\"). */\n amount?: string;\n tab?: 'home' | 'swap' | 'staking' | 'airdrop' | 'api';\n baseUrl?: string;\n}\n\n/** A shareable link that opens the site pre-filled — bot buttons, referral posts. */\nexport function deepLink(opts: DeepLinkOptions = {}): string {\n const base = (opts.baseUrl ?? API_BASE).replace(/\\/+$/, '');\n const sp = new URLSearchParams();\n sp.set('tab', opts.tab ?? 'swap');\n if (opts.chain !== undefined) sp.set('chain', String(resolveChain(opts.chain)));\n if (opts.tokenIn) sp.set('in', opts.tokenIn);\n if (opts.tokenOut) sp.set('out', opts.tokenOut);\n if (opts.amount) sp.set('amt', opts.amount);\n return `${base}/?${sp.toString()}`;\n}\n","// =============================================================================\n// BlazePhoenix Router + Quoter ABI fragments (match the v1.0.0 deployments).\n// The Route/Hop/Leg tuple mirrors BlazePhoenixCore.sol — a decoded route from\n// `previewPlan` round-trips verbatim into `swapExactIn`.\n// =============================================================================\n\nconst LEG_COMPONENTS = [\n { name: 'pool', type: 'address' },\n { name: 'hooks', type: 'address' },\n { name: 'kind', type: 'uint8' },\n { name: 'fee', type: 'uint24' },\n { name: 'tickSpacing', type: 'int24' },\n { name: 'zeroForOne', type: 'bool' },\n { name: 'stable', type: 'bool' },\n { name: 'amountIn', type: 'uint256' },\n { name: 'expectedOut', type: 'uint256' },\n { name: 'auxId', type: 'bytes32' },\n] as const;\n\nconst HOP_COMPONENTS = [\n { name: 'tokenIn', type: 'address' },\n { name: 'tokenOut', type: 'address' },\n { name: 'amountIn', type: 'uint256' },\n { name: 'expectedOut', type: 'uint256' },\n { name: 'legs', type: 'tuple[]', components: LEG_COMPONENTS },\n] as const;\n\nconst ROUTE_COMPONENTS = [\n { name: 'hops', type: 'tuple[]', components: HOP_COMPONENTS },\n { name: 'totalOut', type: 'uint256' },\n { name: 'singleOut', type: 'uint256' },\n { name: 'singleOutFloor', type: 'uint256' },\n { name: 'expectedImpactBps', type: 'uint256' },\n { name: 'confidenceWad', type: 'uint256' },\n { name: 'estGas', type: 'uint256' },\n { name: 'hasSurplus', type: 'bool' },\n { name: 'isV4Bundle', type: 'bool' },\n] as const;\n\nconst PREVIEW_COMPONENTS = [\n { name: 'route', type: 'tuple', components: ROUTE_COMPONENTS },\n { name: 'grossOut', type: 'uint256' },\n { name: 'protocolFee', type: 'uint256' },\n { name: 'safetyBuffer', type: 'uint256' },\n { name: 'netOut', type: 'uint256' },\n { name: 'ironFloor', type: 'uint256' },\n { name: 'userMinOut', type: 'uint256' },\n { name: 'effectiveMinOut', type: 'uint256' },\n { name: 'estGas', type: 'uint256' },\n { name: 'hops', type: 'uint256' },\n { name: 'legs', type: 'uint256' },\n { name: 'topology', type: 'uint8' },\n { name: 'bridgeUsed', type: 'address' },\n { name: 'canExecute', type: 'bool' },\n] as const;\n\nexport const QUOTER_ABI = [\n {\n type: 'function',\n name: 'previewPlan',\n stateMutability: 'view',\n inputs: [\n { name: 'tIn', type: 'address' },\n { name: 'tOut', type: 'address' },\n { name: 'amountIn', type: 'uint256' },\n ],\n outputs: [\n { name: 'pv', type: 'tuple', components: PREVIEW_COMPONENTS },\n { name: 'fallbackRoute', type: 'tuple', components: ROUTE_COMPONENTS },\n { name: 'hasFallback', type: 'bool' },\n ],\n },\n {\n type: 'function',\n name: 'previewPlanExact',\n stateMutability: 'view',\n inputs: [\n { name: 'tIn', type: 'address' },\n { name: 'tOut', type: 'address' },\n { name: 'amountIn', type: 'uint256' },\n ],\n outputs: [\n { name: 'route', type: 'tuple', components: ROUTE_COMPONENTS },\n { name: 'exactOut', type: 'uint256' },\n ],\n },\n] as const;\n\nexport const ROUTER_ABI = [\n {\n type: 'function',\n name: 'swapExactIn',\n stateMutability: 'nonpayable',\n inputs: [\n { name: 'route', type: 'tuple', components: ROUTE_COMPONENTS },\n { name: 'amountIn', type: 'uint256' },\n { name: 'userMinOut', type: 'uint256' },\n { name: 'recipient', type: 'address' },\n { name: 'deadline', type: 'uint256' },\n ],\n outputs: [{ name: 'amountOut', type: 'uint256' }],\n },\n {\n type: 'event',\n name: 'Swap',\n inputs: [\n { name: 'user', type: 'address', indexed: true },\n { name: 'tokenIn', type: 'address', indexed: true },\n { name: 'tokenOut', type: 'address', indexed: true },\n { name: 'amountIn', type: 'uint256', indexed: false },\n { name: 'amountOut', type: 'uint256', indexed: false },\n { name: 'legs', type: 'uint256', indexed: false },\n ],\n },\n {\n type: 'event',\n name: 'Surplus',\n inputs: [\n { name: 'token', type: 'address', indexed: true },\n { name: 'amount', type: 'uint256', indexed: false },\n ],\n },\n] as const;\n","// =============================================================================\n// ERC-20 helpers — zero dependencies. Completes the integration loop:\n// quote → buildApproveTx (once per token) → buildSwapTx → send.\n// Plus human-amount conversion so callers never hand-count decimals.\n// =============================================================================\n\nimport { CHAINS, resolveChain } from './constants.js';\nimport type { Address, ChainRef, Hex, QuoteTx } from './types.js';\n\n/** Unlimited allowance (2^256 − 1). Prefer EXACT amounts — pass the amount you\n * are about to swap; use MAX_UINT256 only when you consciously want one\n * approval forever (bots with their own key management). */\nexport const MAX_UINT256 = (1n << 256n) - 1n;\n\nconst HEX_ADDR = /^0x[0-9a-fA-F]{40}$/;\n\n// approve(address,uint256)\nconst APPROVE_SELECTOR = '0x095ea7b3';\n\nfunction pad32(hexNo0x: string): string {\n return hexNo0x.padStart(64, '0');\n}\n\nexport interface ApproveOptions {\n /** ERC-20 token to approve (the swap's tokenIn). */\n token: Address;\n /** Chain id or name — picks the Router as the default spender. */\n chain: ChainRef;\n /** Allowance in base units. Be exact; MAX_UINT256 opts into unlimited. */\n amount: bigint;\n /** Override the spender (defaults to the BlazePhoenix Router). */\n spender?: Address;\n}\n\n/** Ready-to-send `approve` transaction for the Router (or a custom spender).\n * Send it once per token before the first swap; then swap freely. */\nexport function buildApproveTx(opts: ApproveOptions): QuoteTx {\n const chainId = resolveChain(opts.chain);\n const spender = opts.spender ?? CHAINS[chainId].contracts.router;\n if (!HEX_ADDR.test(opts.token)) throw new Error(`invalid token address: ${opts.token}`);\n if (!HEX_ADDR.test(spender)) throw new Error(`invalid spender address: ${spender}`);\n if (opts.amount < 0n || opts.amount > MAX_UINT256) throw new Error('amount out of uint256 range');\n const data = (APPROVE_SELECTOR\n + pad32(spender.slice(2).toLowerCase())\n + pad32(opts.amount.toString(16))) as Hex;\n return { to: opts.token, data, value: '0' };\n}\n\n/** \"1.5\" + 18 decimals → 1500000000000000000n. Pure string math — no floats,\n * no precision loss. Rejects more fractional digits than the token carries. */\nexport function toBaseUnits(amount: string, decimals: number): bigint {\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {\n throw new Error(`invalid decimals: ${decimals}`);\n }\n const s = amount.trim();\n const m = /^(\\d+)(?:\\.(\\d+))?$/.exec(s);\n if (!m) throw new Error(`invalid amount: \"${amount}\" (use e.g. \"1.5\")`);\n const [, whole, frac = ''] = m;\n if (frac.length > decimals) {\n throw new Error(`\"${amount}\" has ${frac.length} fractional digits — token only carries ${decimals}`);\n }\n return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(frac.padEnd(decimals, '0') || '0');\n}\n\n/** 1500000000000000000n + 18 decimals → \"1.5\" (trailing zeros trimmed).\n * `maxDp` optionally truncates the fractional part for display. */\nexport function fromBaseUnits(v: bigint | string, decimals: number, maxDp?: number): string {\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {\n throw new Error(`invalid decimals: ${decimals}`);\n }\n const n = typeof v === 'bigint' ? v : BigInt(v);\n const neg = n < 0n;\n const abs = neg ? -n : n;\n const base = 10n ** BigInt(decimals);\n const whole = abs / base;\n let frac = (abs % base).toString().padStart(decimals, '0');\n if (maxDp !== undefined) frac = frac.slice(0, Math.max(0, maxDp));\n frac = frac.replace(/0+$/, '');\n return `${neg ? '-' : ''}${whole}${frac ? `.${frac}` : ''}`;\n}\n","// =============================================================================\n// On-chain module — skip HTTP entirely: quote on the Quoter from your own\n// node and watch the Router's fills. Needs the optional `viem` peer:\n// npm i viem\n// You supply the RPC URL — the SDK ships no keys and no default endpoints.\n// =============================================================================\n\nimport { QUOTER_ABI, ROUTER_ABI } from './abis.js';\nimport { CHAINS, PUBLIC_RPCS, resolveChain, type SupportedChainId } from './constants.js';\nimport type { Address, Fill } from './types.js';\n\nasync function loadViem() {\n try {\n return await import('viem');\n } catch {\n throw new Error(\"this feature needs the optional peer dependency 'viem' — npm i viem\");\n }\n}\n\nexport interface OnChainOptions {\n chain: number | string;\n /** Your RPC endpoint. OPTIONAL since v0.4.0 — omitted, the SDK falls back\n * across public keyless endpoints (fine for dev/bots; bring your own node\n * for production throughput). The SDK still ships no providers and no keys. */\n rpcUrl?: string;\n}\n\n/** viem transport: caller's RPC when given, else public-endpoint fallback. */\nasync function transportFor(chainId: SupportedChainId, rpcUrl?: string) {\n const { http, fallback } = await loadViem();\n return rpcUrl ? http(rpcUrl) : fallback(PUBLIC_RPCS[chainId].map((u) => http(u)));\n}\n\n/** previewPlan straight from the chain — the exact numbers the API serves. */\nexport async function quoteOnChain(\n opts: OnChainOptions & { tokenIn: Address; tokenOut: Address; amountIn: bigint },\n) {\n const { createPublicClient } = await loadViem();\n const chainId = resolveChain(opts.chain);\n const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });\n const [pv, , hasFallback] = (await client.readContract({\n address: CHAINS[chainId].contracts.quoter,\n abi: QUOTER_ABI,\n functionName: 'previewPlan',\n args: [opts.tokenIn, opts.tokenOut, opts.amountIn],\n })) as readonly [Record<string, unknown>, unknown, boolean];\n return { preview: pv, hasFallback, chainId };\n}\n\nexport interface WatchFillsOptions extends OnChainOptions {\n onFill: (fill: Fill) => void;\n /** Poll interval in ms (default 4000). */\n pollMs?: number;\n}\n\n/** Stream every BlazePhoenix fill on a chain (one Router `Swap` event per\n * swap). Returns an unwatch function. */\nexport async function watchFills(opts: WatchFillsOptions): Promise<() => void> {\n const { createPublicClient, parseAbiItem } = await loadViem();\n const chainId = resolveChain(opts.chain);\n const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });\n return client.watchEvent({\n address: CHAINS[chainId].contracts.router,\n event: parseAbiItem(\n 'event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)',\n ),\n pollingInterval: opts.pollMs ?? 4_000,\n onLogs: (logs) => {\n for (const log of logs) {\n const a = log.args as {\n user: Address; tokenIn: Address; tokenOut: Address;\n amountIn: bigint; amountOut: bigint; legs: bigint;\n };\n opts.onFill({\n txHash: log.transactionHash as `0x${string}`,\n blockNumber: log.blockNumber ?? 0n,\n user: a.user, tokenIn: a.tokenIn, tokenOut: a.tokenOut,\n amountIn: a.amountIn, amountOut: a.amountOut, legs: a.legs,\n });\n }\n },\n });\n}\n\n/** Historic fills over a block range (for indexing / the quoted-vs-executed\n * verification pattern documented at https://blazephoenix.xyz/?tab=api). */\nexport async function getFills(\n opts: OnChainOptions & { fromBlock: bigint; toBlock: bigint },\n): Promise<Fill[]> {\n const { createPublicClient, parseAbiItem } = await loadViem();\n const chainId = resolveChain(opts.chain);\n const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });\n const logs = await client.getLogs({\n address: CHAINS[chainId].contracts.router,\n event: parseAbiItem(\n 'event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)',\n ),\n fromBlock: opts.fromBlock,\n toBlock: opts.toBlock,\n });\n return logs.map((log) => {\n const a = log.args as {\n user: Address; tokenIn: Address; tokenOut: Address;\n amountIn: bigint; amountOut: bigint; legs: bigint;\n };\n return {\n txHash: log.transactionHash as `0x${string}`,\n blockNumber: log.blockNumber ?? 0n,\n user: a.user, tokenIn: a.tokenIn, tokenOut: a.tokenOut,\n amountIn: a.amountIn, amountOut: a.amountOut, legs: a.legs,\n };\n });\n}\n\nexport { ROUTER_ABI, QUOTER_ABI };\n"]}