@anywalletkit/protocol-swap2-curve 0.1.0 → 0.1.1

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/protocol.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CurveSwap2Protocol
3
- } from "./chunk-IIPLIHNY.js";
4
- import "./chunk-FICPW2P2.js";
3
+ } from "./chunk-JCWXGKPJ.js";
4
+ import "./chunk-IFREGXMV.js";
5
5
  import "./chunk-RVBZFCRR.js";
6
6
  export {
7
7
  CurveSwap2Protocol
package/dist/provider.cjs CHANGED
@@ -599,25 +599,56 @@ function checkRoute(chainId, deployment, table, args, tokenIn, tokenOut) {
599
599
  // src/rpc.ts
600
600
  var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
601
601
  var RPC_BATCH_MAX = 10;
602
+ var RPC_RATE_LIMIT_PAUSE_MS = 1e3;
603
+ function isExecutionError(error) {
604
+ if (!error || typeof error !== "object") return false;
605
+ const { code, message } = error;
606
+ return code === 3 || typeof message === "string" && /revert|invalid opcode|out of gas/i.test(message);
607
+ }
608
+ function isRateLimit(error) {
609
+ if (!error || typeof error !== "object") return false;
610
+ const { code, message } = error;
611
+ return code === -32005 || code === -32007 || code === 429 || typeof message === "string" && /rate|limit|too many/i.test(message);
612
+ }
613
+ var errorText = (error) => {
614
+ const m = error && typeof error === "object" ? error.message : void 0;
615
+ return (0, import_util2.redactUrls)(typeof m === "string" ? m : JSON.stringify(error) ?? String(error)).slice(0, 160);
616
+ };
602
617
  function rpcClient(rpcUrls) {
618
+ async function once(url, calls, signal) {
619
+ const res = await fetch(url, {
620
+ method: "POST",
621
+ headers: { "content-type": "application/json" },
622
+ body: JSON.stringify(calls.map((c, id) => ({ jsonrpc: "2.0", id, ...c }))),
623
+ signal: signal ?? (0, import_util2.timeoutSignal)(12e3)
624
+ });
625
+ if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { limited: res.status === 429 });
626
+ const body = await res.json();
627
+ if (!Array.isArray(body)) throw Object.assign(new Error(body.error?.message ?? "batch refused"), { limited: isRateLimit(body.error) });
628
+ const out = calls.map(() => null);
629
+ const answered = /* @__PURE__ */ new Set();
630
+ for (const r of body) {
631
+ if (typeof r.id !== "number" || r.id < 0 || r.id >= out.length) continue;
632
+ if (r.error !== void 0 && r.error !== null && !isExecutionError(r.error)) throw Object.assign(new Error(errorText(r.error)), { limited: isRateLimit(r.error) });
633
+ answered.add(r.id);
634
+ if (r.error === void 0 || r.error === null) out[r.id] = r.result ?? null;
635
+ }
636
+ if (answered.size !== calls.length) throw new Error(`answered ${answered.size} of ${calls.length} calls`);
637
+ return out;
638
+ }
603
639
  async function batch(chainId, calls, signal) {
604
640
  let lastErr;
605
- for (const url of rpcUrls[chainId] ?? []) {
606
- try {
607
- const res = await fetch(url, {
608
- method: "POST",
609
- headers: { "content-type": "application/json" },
610
- body: JSON.stringify(calls.map((c, id) => ({ jsonrpc: "2.0", id, ...c }))),
611
- signal: signal ?? (0, import_util2.timeoutSignal)(12e3)
612
- });
613
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
614
- const body = await res.json();
615
- if (!Array.isArray(body)) throw new Error(body.error?.message ?? "batch refused");
616
- const out = calls.map(() => null);
617
- for (const r of body) if (typeof r.id === "number" && r.id >= 0 && r.id < out.length && r.error === void 0) out[r.id] = r.result ?? null;
618
- return out;
619
- } catch (e) {
620
- lastErr = e;
641
+ for (let pass = 0; pass < 2; pass++) {
642
+ if (pass > 0) {
643
+ if (!lastErr?.limited || signal?.aborted) break;
644
+ await new Promise((r) => setTimeout(r, RPC_RATE_LIMIT_PAUSE_MS));
645
+ }
646
+ for (const url of rpcUrls[chainId] ?? []) {
647
+ try {
648
+ return await once(url, calls, signal);
649
+ } catch (e) {
650
+ lastErr = e;
651
+ }
621
652
  }
622
653
  }
623
654
  throw new Error(`curve: no RPC answered on chain ${chainId} (${lastErr instanceof Error ? lastErr.message : String(lastErr)})`);
@@ -630,11 +661,16 @@ function rpcClient(rpcUrls) {
630
661
  };
631
662
  }
632
663
  var ethCall = (to, data) => ({ method: "eth_call", params: [{ to, data }, "latest"] });
664
+ function firstWord(raw) {
665
+ return typeof raw === "string" && raw.length >= 66 && /^0x(?:[0-9a-fA-F]{64})+$/.test(raw) ? raw.slice(2, 66).toLowerCase() : null;
666
+ }
633
667
  function wordAddress(raw) {
634
- return typeof raw === "string" && /^0x[0-9a-fA-F]{64}$/.test(raw) ? `0x${raw.slice(-40)}`.toLowerCase() : null;
668
+ const w = firstWord(raw);
669
+ return w !== null && /^0{24}/.test(w) ? `0x${w.slice(24)}` : null;
635
670
  }
636
671
  function wordUint(raw) {
637
- return typeof raw === "string" && /^0x[0-9a-fA-F]{64}$/.test(raw) ? BigInt(raw) : null;
672
+ const w = firstWord(raw);
673
+ return w === null ? null : BigInt(`0x${w}`);
638
674
  }
639
675
 
640
676
  // src/slippage.ts
@@ -792,20 +828,32 @@ function curveOnChain(opts) {
792
828
  await verifyDeployment(chainId);
793
829
  const index = poolIndex(chainId, d2, own(pools, chainId));
794
830
  const hops = routePools(call).map((a) => index.get(lc2(a)));
795
- const calls = [ethCall(d2.router, encodeGetDy(d2.family, call, call.amount))];
796
- for (const pool of hops) {
797
- calls.push({ method: "eth_getCode", params: [pool.address, "latest"] });
798
- pool.coins.forEach((_, k) => calls.push(ethCall(pool.address, `${COINS_UINT}${k.toString(16).padStart(64, "0")}`)));
799
- }
831
+ const reads = poolCalls(hops);
832
+ const calls = [ethCall(d2.router, encodeGetDy(d2.family, call, call.amount)), ...reads];
800
833
  const probeIn = call.amount / 1000n;
801
834
  const probeAt = calls.length;
802
835
  if (probe && probeIn > 0n) calls.push(ethCall(d2.router, encodeGetDy(d2.family, call, probeIn)));
803
836
  const res = await rpc(chainId, calls);
804
- let at = 1;
837
+ const poolReason = await poolsReason(chainId, hops, res.slice(1, 1 + reads.length));
838
+ if (poolReason) return poolReason;
839
+ const out = wordUint(res[0]);
840
+ if (out === null) return "the router no longer quotes this route";
841
+ if (out < call.minDy) return `price moved \u2014 the pools now pay ${out}, under your minimum ${call.minDy}`;
842
+ return { out, probeOut: probe && probeIn > 0n ? wordUint(res[probeAt]) : null, amount: call.amount, minDy: call.minDy };
843
+ }
844
+ function poolCalls(list) {
845
+ return list.flatMap((pool) => [
846
+ { method: "eth_getCode", params: [pool.address, "latest"] },
847
+ ...pool.coins.map((_, k) => ethCall(pool.address, `${COINS_UINT}${k.toString(16).padStart(64, "0")}`))
848
+ ]);
849
+ }
850
+ async function poolsReason(chainId, list, res) {
851
+ let at = 0;
805
852
  const retry = [];
806
- for (const pool of hops) {
853
+ for (const pool of list) {
807
854
  const code = res[at++];
808
- if (typeof code !== "string" || code.length <= 2 || lc2((0, import_viem3.keccak256)(code)) !== lc2(pool.codeHash)) return `pool ${pool.name} (${pool.address}) is not the pinned code`;
855
+ if (typeof code !== "string") return `could not read pool ${pool.name} (${pool.address}) over RPC`;
856
+ if (code.length <= 2 || lc2((0, import_viem3.keccak256)(code)) !== lc2(pool.codeHash)) return `pool ${pool.name} (${pool.address}) is not the pinned code`;
809
857
  for (let k = 0; k < pool.coins.length; k++) {
810
858
  const coin = wordAddress(res[at++]);
811
859
  if (coin === null) retry.push({ pool, k });
@@ -819,12 +867,12 @@ function curveOnChain(opts) {
819
867
  if (coin !== lc2(pool.coins[k])) return `pool ${pool.name} does not report its pinned coin ${k}`;
820
868
  }
821
869
  }
822
- const out = wordUint(res[0]);
823
- if (out === null) return "the router no longer quotes this route";
824
- if (out < call.minDy) return `price moved \u2014 the pools now pay ${out}, under your minimum ${call.minDy}`;
825
- return { out, probeOut: probe && probeIn > 0n ? wordUint(res[probeAt]) : null, amount: call.amount, minDy: call.minDy };
870
+ return null;
871
+ }
872
+ async function checkPools(chainId, list) {
873
+ return list.length ? poolsReason(chainId, list, await rpc(chainId, poolCalls(list))) : null;
826
874
  }
827
- return { rpc, verifyDeployment, checkSealed, inspectSealed };
875
+ return { rpc, verifyDeployment, checkSealed, inspectSealed, checkPools };
828
876
  }
829
877
  function lastToken(call) {
830
878
  let k = 0;