@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.cjs ADDED
@@ -0,0 +1,564 @@
1
+ 'use strict';
2
+
3
+ // src/constants.ts
4
+ var API_BASE = "https://blazephoenix.xyz";
5
+ var CHAINS = {
6
+ 1: {
7
+ chainId: 1,
8
+ name: "Ethereum",
9
+ explorer: "https://etherscan.io",
10
+ weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
11
+ usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
12
+ contracts: {
13
+ hub: "0xc4FA9a5720fe3294D3AA9fc427E2a760591E57ae",
14
+ solver: "0xc124d91258db0C14bf13b826CF64E16bfEA8a73e",
15
+ router: "0xE1aE5f49013920CF71De8CED4043e14C4d63416b",
16
+ quoter: "0x4a20AA0912388ff7A9221Ab6BFC224cc20Baa0c3"
17
+ }
18
+ },
19
+ 8453: {
20
+ chainId: 8453,
21
+ name: "Base",
22
+ explorer: "https://basescan.org",
23
+ weth: "0x4200000000000000000000000000000000000006",
24
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
25
+ bzpx: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
26
+ contracts: {
27
+ hub: "0x428554DEe93A1B8B5Bc6Fd19adDAfe55106fc04C",
28
+ solver: "0xB1902990260975dD4C89ad74B1f317bc100CB830",
29
+ router: "0x2a779f9Be49aac57495A8B6467Cc325a8a47Eb9f",
30
+ quoter: "0x4cEF0615614B212895F45Aa1D4833B16666E18d3"
31
+ }
32
+ },
33
+ 10: {
34
+ chainId: 10,
35
+ name: "Optimism",
36
+ explorer: "https://optimistic.etherscan.io",
37
+ weth: "0x4200000000000000000000000000000000000006",
38
+ usdc: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
39
+ contracts: {
40
+ hub: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
41
+ solver: "0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f",
42
+ router: "0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A",
43
+ quoter: "0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2"
44
+ }
45
+ },
46
+ 42161: {
47
+ chainId: 42161,
48
+ name: "Arbitrum",
49
+ explorer: "https://arbiscan.io",
50
+ weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
51
+ usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
52
+ contracts: {
53
+ hub: "0x23113e72165a034265Ab8Bf2277CCB7a85Cb7483",
54
+ solver: "0x0c0d96B237FABa8FE5e8aE77754Ef29109D2B33f",
55
+ router: "0x7262e7483ab6f0db7b8f90eC3a9de3B02Ab36F6A",
56
+ quoter: "0xfB18EF6f62A0278A273Af4b7A46b454F9E482dc2"
57
+ }
58
+ }
59
+ };
60
+ function resolveChain(chain) {
61
+ const aliases = {
62
+ "1": 1,
63
+ eth: 1,
64
+ ethereum: 1,
65
+ mainnet: 1,
66
+ "8453": 8453,
67
+ base: 8453,
68
+ "10": 10,
69
+ op: 10,
70
+ optimism: 10,
71
+ "42161": 42161,
72
+ arb: 42161,
73
+ arbitrum: 42161,
74
+ "arbitrum-one": 42161
75
+ };
76
+ const id = aliases[String(chain).trim().toLowerCase()];
77
+ if (!id) {
78
+ throw new Error(
79
+ `Unsupported chain "${chain}" \u2014 use 8453/base, 1/eth, 10/optimism or 42161/arbitrum`
80
+ );
81
+ }
82
+ return id;
83
+ }
84
+ var PUBLIC_RPCS = {
85
+ 1: [
86
+ "https://ethereum-rpc.publicnode.com",
87
+ "https://cloudflare-eth.com",
88
+ "https://1rpc.io/eth"
89
+ ],
90
+ 8453: [
91
+ "https://mainnet.base.org",
92
+ "https://base-rpc.publicnode.com",
93
+ "https://1rpc.io/base"
94
+ ],
95
+ 10: [
96
+ "https://optimism-rpc.publicnode.com",
97
+ "https://mainnet.optimism.io",
98
+ "https://1rpc.io/op"
99
+ ],
100
+ 42161: [
101
+ "https://arbitrum-one-rpc.publicnode.com",
102
+ "https://arb1.arbitrum.io/rpc",
103
+ "https://1rpc.io/arb"
104
+ ]
105
+ };
106
+ var FEE_BPS = 28;
107
+ var SWAP_TOPIC0 = "0xd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf7760413";
108
+ var SURPLUS_TOPIC0 = "0x1a3afef0f067eb51a6bfec6ab3625a4408dd8c3571b72836483e68feb70d1026";
109
+
110
+ // src/resilience.ts
111
+ var INFLIGHT = /* @__PURE__ */ new Map();
112
+ var MEM = /* @__PURE__ */ new Map();
113
+ async function singleflight(key, fn) {
114
+ const existing = INFLIGHT.get(key);
115
+ if (existing) return existing;
116
+ const flight = fn();
117
+ INFLIGHT.set(key, flight);
118
+ try {
119
+ return await flight;
120
+ } finally {
121
+ INFLIGHT.delete(key);
122
+ }
123
+ }
124
+ function memGet(key, ttlMs, now = Date.now()) {
125
+ if (ttlMs <= 0) return void 0;
126
+ const hit = MEM.get(key);
127
+ return hit && now - hit.at < ttlMs ? hit.data : void 0;
128
+ }
129
+ function memPut(key, data, now = Date.now()) {
130
+ MEM.set(key, { at: now, data });
131
+ if (MEM.size > 500) {
132
+ const oldest = MEM.keys().next().value;
133
+ if (oldest !== void 0) MEM.delete(oldest);
134
+ }
135
+ }
136
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
137
+ function retryDelayMs(res, attempt, base) {
138
+ const ra = Number(res?.headers.get("retry-after"));
139
+ if (Number.isFinite(ra) && ra > 0) return Math.min(1e4, ra * 1e3);
140
+ return base * 3 ** attempt + Math.floor(Math.random() * base);
141
+ }
142
+ function isTransient(res) {
143
+ return !res || res.status === 429 || res.status === 502 || res.status === 503 || res.status === 504;
144
+ }
145
+ async function resilientFetch(fetchFn, url, init, opts = {}) {
146
+ const { retries = 2, backoffMs = 250, timeoutMs = 15e3 } = opts;
147
+ let lastErr;
148
+ for (let attempt = 0; attempt <= retries; attempt++) {
149
+ let res;
150
+ try {
151
+ res = await fetchFn(url, { ...init, signal: AbortSignal.timeout(timeoutMs) });
152
+ if (!isTransient(res)) return res;
153
+ if (attempt === retries) return res;
154
+ } catch (e) {
155
+ lastErr = e;
156
+ if (attempt === retries) throw e;
157
+ }
158
+ await sleep(retryDelayMs(res, attempt, backoffMs));
159
+ }
160
+ throw lastErr instanceof Error ? lastErr : new Error("request failed");
161
+ }
162
+
163
+ // src/client.ts
164
+ var BlazeApiError = class extends Error {
165
+ code;
166
+ status;
167
+ constructor(code, message, status) {
168
+ super(message);
169
+ this.name = "BlazeApiError";
170
+ this.code = code;
171
+ this.status = status;
172
+ }
173
+ };
174
+ function toSearch(req) {
175
+ const sp = new URLSearchParams();
176
+ sp.set("chain", String(resolveChain(req.chain)));
177
+ sp.set("in", req.tokenIn.trim());
178
+ sp.set("out", req.tokenOut.trim());
179
+ sp.set("amountIn", typeof req.amountIn === "bigint" ? req.amountIn.toString() : String(req.amountIn).trim());
180
+ if (req.recipient) sp.set("recipient", req.recipient);
181
+ if (req.slippageBps !== void 0) sp.set("slippageBps", String(req.slippageBps));
182
+ if (req.deadlineSec !== void 0) sp.set("deadlineSec", String(req.deadlineSec));
183
+ if (req.exact) sp.set("exact", "1");
184
+ return sp;
185
+ }
186
+ var BlazePhoenix = class {
187
+ base;
188
+ fetchFn;
189
+ timeoutMs;
190
+ retries;
191
+ cacheTtlMs;
192
+ constructor(opts = {}) {
193
+ this.base = (opts.baseUrl ?? API_BASE).replace(/\/+$/, "");
194
+ this.fetchFn = opts.fetchFn ?? globalThis.fetch;
195
+ this.timeoutMs = opts.timeoutMs ?? 15e3;
196
+ this.retries = opts.retries ?? 2;
197
+ this.cacheTtlMs = opts.cacheTtlMs ?? 1e3;
198
+ if (!this.fetchFn) throw new Error("No fetch available \u2014 Node >= 18 required (or pass fetchFn)");
199
+ }
200
+ /** Build the GET /api/quote URL for a request (useful for logging/debugging). */
201
+ quoteUrl(req) {
202
+ return `${this.base}/api/quote?${toSearch(req).toString()}`;
203
+ }
204
+ async call(path, init) {
205
+ const res = await resilientFetch(this.fetchFn, `${this.base}${path}`, init, {
206
+ retries: this.retries,
207
+ timeoutMs: this.timeoutMs
208
+ });
209
+ const body = await res.json().catch(() => null);
210
+ if (!body || typeof body !== "object") {
211
+ throw new BlazeApiError("bad_response", `non-JSON response (HTTP ${res.status})`, res.status);
212
+ }
213
+ if ("ok" in body && body.ok === false) {
214
+ throw new BlazeApiError(body.code ?? "error", body.error ?? "request failed", res.status);
215
+ }
216
+ return body;
217
+ }
218
+ /** One quote — previewPlan computed on-chain. Throws BlazeApiError on failure.
219
+ * Identical concurrent calls share one request; preview quotes ride a tiny
220
+ * micro-cache (cacheTtlMs) so hot loops never hammer the wire. */
221
+ async quote(req) {
222
+ const qs = toSearch(req).toString();
223
+ const key = `Q ${this.base}?${qs}`;
224
+ const cacheable = !req.recipient && !req.exact && this.cacheTtlMs > 0;
225
+ if (cacheable) {
226
+ const hit = memGet(key, this.cacheTtlMs);
227
+ if (hit) return hit;
228
+ }
229
+ const q = await singleflight(key, () => this.call(`/api/quote?${qs}`));
230
+ if (cacheable) memPut(key, q);
231
+ return q;
232
+ }
233
+ /** Up to 10 quotes in one round-trip (screeners / arb loops).
234
+ * Per-item failures come back inline — the batch itself only throws on
235
+ * transport/validation errors. Identical concurrent batches coalesce. */
236
+ quoteBatch(reqs) {
237
+ const body = JSON.stringify({
238
+ requests: reqs.map((r) => Object.fromEntries(toSearch(r).entries()))
239
+ });
240
+ return singleflight(`B ${this.base} ${body}`, () => this.call("/api/quote/batch", {
241
+ method: "POST",
242
+ headers: { "content-type": "application/json" },
243
+ body
244
+ }));
245
+ }
246
+ /** Service health + per-chain live flags. Zero upstream cost server-side —
247
+ * poll it from your monitor as often as you like. */
248
+ health() {
249
+ return this.call("/api/health");
250
+ }
251
+ /** Machine-readable protocol manifest — near-static, cached for 1h. */
252
+ async manifest() {
253
+ const key = `M ${this.base}`;
254
+ const hit = memGet(key, 36e5);
255
+ if (hit) return hit;
256
+ const m = await singleflight(key, () => this.call("/api/manifest"));
257
+ memPut(key, m);
258
+ return m;
259
+ }
260
+ };
261
+ function pollQuote(client, req, onQuote, opts = {}) {
262
+ const interval = Math.max(500, opts.intervalMs ?? 4e3);
263
+ let stopped = false;
264
+ let busy = false;
265
+ const tick = async () => {
266
+ if (stopped || busy) return;
267
+ busy = true;
268
+ try {
269
+ const q = await client.quote(req);
270
+ if (!stopped) onQuote(q);
271
+ } catch (e) {
272
+ if (!stopped) opts.onError?.(e);
273
+ } finally {
274
+ busy = false;
275
+ }
276
+ };
277
+ void tick();
278
+ const timer = setInterval(() => {
279
+ void tick();
280
+ }, interval);
281
+ return () => {
282
+ stopped = true;
283
+ clearInterval(timer);
284
+ };
285
+ }
286
+ function buildSwapTx(q) {
287
+ if (q.tx) return q.tx;
288
+ if (q.wrapRequired) {
289
+ throw new Error("native ETH input: wrap to WETH first (WETH.deposit), then re-quote with in=WETH");
290
+ }
291
+ throw new Error("no tx in quote \u2014 pass `recipient` in the request (and check quote.canExecute)");
292
+ }
293
+ function deepLink(opts = {}) {
294
+ const base = (opts.baseUrl ?? API_BASE).replace(/\/+$/, "");
295
+ const sp = new URLSearchParams();
296
+ sp.set("tab", opts.tab ?? "swap");
297
+ if (opts.chain !== void 0) sp.set("chain", String(resolveChain(opts.chain)));
298
+ if (opts.tokenIn) sp.set("in", opts.tokenIn);
299
+ if (opts.tokenOut) sp.set("out", opts.tokenOut);
300
+ if (opts.amount) sp.set("amt", opts.amount);
301
+ return `${base}/?${sp.toString()}`;
302
+ }
303
+
304
+ // src/abis.ts
305
+ var LEG_COMPONENTS = [
306
+ { name: "pool", type: "address" },
307
+ { name: "hooks", type: "address" },
308
+ { name: "kind", type: "uint8" },
309
+ { name: "fee", type: "uint24" },
310
+ { name: "tickSpacing", type: "int24" },
311
+ { name: "zeroForOne", type: "bool" },
312
+ { name: "stable", type: "bool" },
313
+ { name: "amountIn", type: "uint256" },
314
+ { name: "expectedOut", type: "uint256" },
315
+ { name: "auxId", type: "bytes32" }
316
+ ];
317
+ var HOP_COMPONENTS = [
318
+ { name: "tokenIn", type: "address" },
319
+ { name: "tokenOut", type: "address" },
320
+ { name: "amountIn", type: "uint256" },
321
+ { name: "expectedOut", type: "uint256" },
322
+ { name: "legs", type: "tuple[]", components: LEG_COMPONENTS }
323
+ ];
324
+ var ROUTE_COMPONENTS = [
325
+ { name: "hops", type: "tuple[]", components: HOP_COMPONENTS },
326
+ { name: "totalOut", type: "uint256" },
327
+ { name: "singleOut", type: "uint256" },
328
+ { name: "singleOutFloor", type: "uint256" },
329
+ { name: "expectedImpactBps", type: "uint256" },
330
+ { name: "confidenceWad", type: "uint256" },
331
+ { name: "estGas", type: "uint256" },
332
+ { name: "hasSurplus", type: "bool" },
333
+ { name: "isV4Bundle", type: "bool" }
334
+ ];
335
+ var PREVIEW_COMPONENTS = [
336
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
337
+ { name: "grossOut", type: "uint256" },
338
+ { name: "protocolFee", type: "uint256" },
339
+ { name: "safetyBuffer", type: "uint256" },
340
+ { name: "netOut", type: "uint256" },
341
+ { name: "ironFloor", type: "uint256" },
342
+ { name: "userMinOut", type: "uint256" },
343
+ { name: "effectiveMinOut", type: "uint256" },
344
+ { name: "estGas", type: "uint256" },
345
+ { name: "hops", type: "uint256" },
346
+ { name: "legs", type: "uint256" },
347
+ { name: "topology", type: "uint8" },
348
+ { name: "bridgeUsed", type: "address" },
349
+ { name: "canExecute", type: "bool" }
350
+ ];
351
+ var QUOTER_ABI = [
352
+ {
353
+ type: "function",
354
+ name: "previewPlan",
355
+ stateMutability: "view",
356
+ inputs: [
357
+ { name: "tIn", type: "address" },
358
+ { name: "tOut", type: "address" },
359
+ { name: "amountIn", type: "uint256" }
360
+ ],
361
+ outputs: [
362
+ { name: "pv", type: "tuple", components: PREVIEW_COMPONENTS },
363
+ { name: "fallbackRoute", type: "tuple", components: ROUTE_COMPONENTS },
364
+ { name: "hasFallback", type: "bool" }
365
+ ]
366
+ },
367
+ {
368
+ type: "function",
369
+ name: "previewPlanExact",
370
+ stateMutability: "view",
371
+ inputs: [
372
+ { name: "tIn", type: "address" },
373
+ { name: "tOut", type: "address" },
374
+ { name: "amountIn", type: "uint256" }
375
+ ],
376
+ outputs: [
377
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
378
+ { name: "exactOut", type: "uint256" }
379
+ ]
380
+ }
381
+ ];
382
+ var ROUTER_ABI = [
383
+ {
384
+ type: "function",
385
+ name: "swapExactIn",
386
+ stateMutability: "nonpayable",
387
+ inputs: [
388
+ { name: "route", type: "tuple", components: ROUTE_COMPONENTS },
389
+ { name: "amountIn", type: "uint256" },
390
+ { name: "userMinOut", type: "uint256" },
391
+ { name: "recipient", type: "address" },
392
+ { name: "deadline", type: "uint256" }
393
+ ],
394
+ outputs: [{ name: "amountOut", type: "uint256" }]
395
+ },
396
+ {
397
+ type: "event",
398
+ name: "Swap",
399
+ inputs: [
400
+ { name: "user", type: "address", indexed: true },
401
+ { name: "tokenIn", type: "address", indexed: true },
402
+ { name: "tokenOut", type: "address", indexed: true },
403
+ { name: "amountIn", type: "uint256", indexed: false },
404
+ { name: "amountOut", type: "uint256", indexed: false },
405
+ { name: "legs", type: "uint256", indexed: false }
406
+ ]
407
+ },
408
+ {
409
+ type: "event",
410
+ name: "Surplus",
411
+ inputs: [
412
+ { name: "token", type: "address", indexed: true },
413
+ { name: "amount", type: "uint256", indexed: false }
414
+ ]
415
+ }
416
+ ];
417
+
418
+ // src/erc20.ts
419
+ var MAX_UINT256 = (1n << 256n) - 1n;
420
+ var HEX_ADDR = /^0x[0-9a-fA-F]{40}$/;
421
+ var APPROVE_SELECTOR = "0x095ea7b3";
422
+ function pad32(hexNo0x) {
423
+ return hexNo0x.padStart(64, "0");
424
+ }
425
+ function buildApproveTx(opts) {
426
+ const chainId = resolveChain(opts.chain);
427
+ const spender = opts.spender ?? CHAINS[chainId].contracts.router;
428
+ if (!HEX_ADDR.test(opts.token)) throw new Error(`invalid token address: ${opts.token}`);
429
+ if (!HEX_ADDR.test(spender)) throw new Error(`invalid spender address: ${spender}`);
430
+ if (opts.amount < 0n || opts.amount > MAX_UINT256) throw new Error("amount out of uint256 range");
431
+ const data = APPROVE_SELECTOR + pad32(spender.slice(2).toLowerCase()) + pad32(opts.amount.toString(16));
432
+ return { to: opts.token, data, value: "0" };
433
+ }
434
+ function toBaseUnits(amount, decimals) {
435
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {
436
+ throw new Error(`invalid decimals: ${decimals}`);
437
+ }
438
+ const s = amount.trim();
439
+ const m = /^(\d+)(?:\.(\d+))?$/.exec(s);
440
+ if (!m) throw new Error(`invalid amount: "${amount}" (use e.g. "1.5")`);
441
+ const [, whole, frac = ""] = m;
442
+ if (frac.length > decimals) {
443
+ throw new Error(`"${amount}" has ${frac.length} fractional digits \u2014 token only carries ${decimals}`);
444
+ }
445
+ return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(frac.padEnd(decimals, "0") || "0");
446
+ }
447
+ function fromBaseUnits(v, decimals, maxDp) {
448
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 77) {
449
+ throw new Error(`invalid decimals: ${decimals}`);
450
+ }
451
+ const n = typeof v === "bigint" ? v : BigInt(v);
452
+ const neg = n < 0n;
453
+ const abs = neg ? -n : n;
454
+ const base = 10n ** BigInt(decimals);
455
+ const whole = abs / base;
456
+ let frac = (abs % base).toString().padStart(decimals, "0");
457
+ if (maxDp !== void 0) frac = frac.slice(0, Math.max(0, maxDp));
458
+ frac = frac.replace(/0+$/, "");
459
+ return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
460
+ }
461
+
462
+ // src/onchain.ts
463
+ async function loadViem() {
464
+ try {
465
+ return await import('viem');
466
+ } catch {
467
+ throw new Error("this feature needs the optional peer dependency 'viem' \u2014 npm i viem");
468
+ }
469
+ }
470
+ async function transportFor(chainId, rpcUrl) {
471
+ const { http, fallback } = await loadViem();
472
+ return rpcUrl ? http(rpcUrl) : fallback(PUBLIC_RPCS[chainId].map((u) => http(u)));
473
+ }
474
+ async function quoteOnChain(opts) {
475
+ const { createPublicClient } = await loadViem();
476
+ const chainId = resolveChain(opts.chain);
477
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
478
+ const [pv, , hasFallback] = await client.readContract({
479
+ address: CHAINS[chainId].contracts.quoter,
480
+ abi: QUOTER_ABI,
481
+ functionName: "previewPlan",
482
+ args: [opts.tokenIn, opts.tokenOut, opts.amountIn]
483
+ });
484
+ return { preview: pv, hasFallback, chainId };
485
+ }
486
+ async function watchFills(opts) {
487
+ const { createPublicClient, parseAbiItem } = await loadViem();
488
+ const chainId = resolveChain(opts.chain);
489
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
490
+ return client.watchEvent({
491
+ address: CHAINS[chainId].contracts.router,
492
+ event: parseAbiItem(
493
+ "event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)"
494
+ ),
495
+ pollingInterval: opts.pollMs ?? 4e3,
496
+ onLogs: (logs) => {
497
+ for (const log of logs) {
498
+ const a = log.args;
499
+ opts.onFill({
500
+ txHash: log.transactionHash,
501
+ blockNumber: log.blockNumber ?? 0n,
502
+ user: a.user,
503
+ tokenIn: a.tokenIn,
504
+ tokenOut: a.tokenOut,
505
+ amountIn: a.amountIn,
506
+ amountOut: a.amountOut,
507
+ legs: a.legs
508
+ });
509
+ }
510
+ }
511
+ });
512
+ }
513
+ async function getFills(opts) {
514
+ const { createPublicClient, parseAbiItem } = await loadViem();
515
+ const chainId = resolveChain(opts.chain);
516
+ const client = createPublicClient({ transport: await transportFor(chainId, opts.rpcUrl) });
517
+ const logs = await client.getLogs({
518
+ address: CHAINS[chainId].contracts.router,
519
+ event: parseAbiItem(
520
+ "event Swap(address indexed user, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, uint256 legs)"
521
+ ),
522
+ fromBlock: opts.fromBlock,
523
+ toBlock: opts.toBlock
524
+ });
525
+ return logs.map((log) => {
526
+ const a = log.args;
527
+ return {
528
+ txHash: log.transactionHash,
529
+ blockNumber: log.blockNumber ?? 0n,
530
+ user: a.user,
531
+ tokenIn: a.tokenIn,
532
+ tokenOut: a.tokenOut,
533
+ amountIn: a.amountIn,
534
+ amountOut: a.amountOut,
535
+ legs: a.legs
536
+ };
537
+ });
538
+ }
539
+
540
+ exports.API_BASE = API_BASE;
541
+ exports.BlazeApiError = BlazeApiError;
542
+ exports.BlazePhoenix = BlazePhoenix;
543
+ exports.CHAINS = CHAINS;
544
+ exports.FEE_BPS = FEE_BPS;
545
+ exports.MAX_UINT256 = MAX_UINT256;
546
+ exports.PUBLIC_RPCS = PUBLIC_RPCS;
547
+ exports.QUOTER_ABI = QUOTER_ABI;
548
+ exports.ROUTER_ABI = ROUTER_ABI;
549
+ exports.SURPLUS_TOPIC0 = SURPLUS_TOPIC0;
550
+ exports.SWAP_TOPIC0 = SWAP_TOPIC0;
551
+ exports.buildApproveTx = buildApproveTx;
552
+ exports.buildSwapTx = buildSwapTx;
553
+ exports.deepLink = deepLink;
554
+ exports.fromBaseUnits = fromBaseUnits;
555
+ exports.getFills = getFills;
556
+ exports.pollQuote = pollQuote;
557
+ exports.quoteOnChain = quoteOnChain;
558
+ exports.resilientFetch = resilientFetch;
559
+ exports.resolveChain = resolveChain;
560
+ exports.singleflight = singleflight;
561
+ exports.toBaseUnits = toBaseUnits;
562
+ exports.watchFills = watchFills;
563
+ //# sourceMappingURL=index.cjs.map
564
+ //# sourceMappingURL=index.cjs.map