@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/README.md +4 -3
- package/dist/{chunk-FICPW2P2.js → chunk-IFREGXMV.js} +81 -33
- package/dist/{chunk-FICPW2P2.js.map → chunk-IFREGXMV.js.map} +1 -1
- package/dist/{chunk-IIPLIHNY.js → chunk-JCWXGKPJ.js} +2 -2
- package/dist/index.cjs +79 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/protocol.cjs +79 -31
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +2 -2
- package/dist/provider.cjs +79 -31
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.js +1 -1
- package/package.json +1 -1
- /package/dist/{chunk-IIPLIHNY.js.map → chunk-JCWXGKPJ.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CURVE_POOLS,
|
|
3
3
|
curveProvider
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IFREGXMV.js";
|
|
5
5
|
import {
|
|
6
6
|
CURVE_DEPLOYMENTS,
|
|
7
7
|
deploymentOf
|
|
@@ -35,4 +35,4 @@ var CurveSwap2Protocol = class extends SingleProviderSwap2 {
|
|
|
35
35
|
export {
|
|
36
36
|
CurveSwap2Protocol
|
|
37
37
|
};
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
38
|
+
//# sourceMappingURL=chunk-JCWXGKPJ.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -644,25 +644,56 @@ var CURVE_POOLS = Object.freeze({
|
|
|
644
644
|
// src/rpc.ts
|
|
645
645
|
var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
|
|
646
646
|
var RPC_BATCH_MAX = 10;
|
|
647
|
+
var RPC_RATE_LIMIT_PAUSE_MS = 1e3;
|
|
648
|
+
function isExecutionError(error) {
|
|
649
|
+
if (!error || typeof error !== "object") return false;
|
|
650
|
+
const { code, message } = error;
|
|
651
|
+
return code === 3 || typeof message === "string" && /revert|invalid opcode|out of gas/i.test(message);
|
|
652
|
+
}
|
|
653
|
+
function isRateLimit(error) {
|
|
654
|
+
if (!error || typeof error !== "object") return false;
|
|
655
|
+
const { code, message } = error;
|
|
656
|
+
return code === -32005 || code === -32007 || code === 429 || typeof message === "string" && /rate|limit|too many/i.test(message);
|
|
657
|
+
}
|
|
658
|
+
var errorText = (error) => {
|
|
659
|
+
const m = error && typeof error === "object" ? error.message : void 0;
|
|
660
|
+
return (0, import_util2.redactUrls)(typeof m === "string" ? m : JSON.stringify(error) ?? String(error)).slice(0, 160);
|
|
661
|
+
};
|
|
647
662
|
function rpcClient(rpcUrls) {
|
|
663
|
+
async function once(url, calls, signal) {
|
|
664
|
+
const res = await fetch(url, {
|
|
665
|
+
method: "POST",
|
|
666
|
+
headers: { "content-type": "application/json" },
|
|
667
|
+
body: JSON.stringify(calls.map((c, id) => ({ jsonrpc: "2.0", id, ...c }))),
|
|
668
|
+
signal: signal ?? (0, import_util2.timeoutSignal)(12e3)
|
|
669
|
+
});
|
|
670
|
+
if (!res.ok) throw Object.assign(new Error(`HTTP ${res.status}`), { limited: res.status === 429 });
|
|
671
|
+
const body = await res.json();
|
|
672
|
+
if (!Array.isArray(body)) throw Object.assign(new Error(body.error?.message ?? "batch refused"), { limited: isRateLimit(body.error) });
|
|
673
|
+
const out = calls.map(() => null);
|
|
674
|
+
const answered = /* @__PURE__ */ new Set();
|
|
675
|
+
for (const r of body) {
|
|
676
|
+
if (typeof r.id !== "number" || r.id < 0 || r.id >= out.length) continue;
|
|
677
|
+
if (r.error !== void 0 && r.error !== null && !isExecutionError(r.error)) throw Object.assign(new Error(errorText(r.error)), { limited: isRateLimit(r.error) });
|
|
678
|
+
answered.add(r.id);
|
|
679
|
+
if (r.error === void 0 || r.error === null) out[r.id] = r.result ?? null;
|
|
680
|
+
}
|
|
681
|
+
if (answered.size !== calls.length) throw new Error(`answered ${answered.size} of ${calls.length} calls`);
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
648
684
|
async function batch(chainId, calls, signal) {
|
|
649
685
|
let lastErr;
|
|
650
|
-
for (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
const out = calls.map(() => null);
|
|
662
|
-
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;
|
|
663
|
-
return out;
|
|
664
|
-
} catch (e) {
|
|
665
|
-
lastErr = e;
|
|
686
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
687
|
+
if (pass > 0) {
|
|
688
|
+
if (!lastErr?.limited || signal?.aborted) break;
|
|
689
|
+
await new Promise((r) => setTimeout(r, RPC_RATE_LIMIT_PAUSE_MS));
|
|
690
|
+
}
|
|
691
|
+
for (const url of rpcUrls[chainId] ?? []) {
|
|
692
|
+
try {
|
|
693
|
+
return await once(url, calls, signal);
|
|
694
|
+
} catch (e) {
|
|
695
|
+
lastErr = e;
|
|
696
|
+
}
|
|
666
697
|
}
|
|
667
698
|
}
|
|
668
699
|
throw new Error(`curve: no RPC answered on chain ${chainId} (${lastErr instanceof Error ? lastErr.message : String(lastErr)})`);
|
|
@@ -675,11 +706,16 @@ function rpcClient(rpcUrls) {
|
|
|
675
706
|
};
|
|
676
707
|
}
|
|
677
708
|
var ethCall = (to, data) => ({ method: "eth_call", params: [{ to, data }, "latest"] });
|
|
709
|
+
function firstWord(raw) {
|
|
710
|
+
return typeof raw === "string" && raw.length >= 66 && /^0x(?:[0-9a-fA-F]{64})+$/.test(raw) ? raw.slice(2, 66).toLowerCase() : null;
|
|
711
|
+
}
|
|
678
712
|
function wordAddress(raw) {
|
|
679
|
-
|
|
713
|
+
const w = firstWord(raw);
|
|
714
|
+
return w !== null && /^0{24}/.test(w) ? `0x${w.slice(24)}` : null;
|
|
680
715
|
}
|
|
681
716
|
function wordUint(raw) {
|
|
682
|
-
|
|
717
|
+
const w = firstWord(raw);
|
|
718
|
+
return w === null ? null : BigInt(`0x${w}`);
|
|
683
719
|
}
|
|
684
720
|
|
|
685
721
|
// src/slippage.ts
|
|
@@ -837,20 +873,32 @@ function curveOnChain(opts) {
|
|
|
837
873
|
await verifyDeployment(chainId);
|
|
838
874
|
const index = poolIndex(chainId, d2, own(pools, chainId));
|
|
839
875
|
const hops = routePools(call).map((a) => index.get(lc2(a)));
|
|
840
|
-
const
|
|
841
|
-
|
|
842
|
-
calls.push({ method: "eth_getCode", params: [pool.address, "latest"] });
|
|
843
|
-
pool.coins.forEach((_, k) => calls.push(ethCall(pool.address, `${COINS_UINT}${k.toString(16).padStart(64, "0")}`)));
|
|
844
|
-
}
|
|
876
|
+
const reads = poolCalls(hops);
|
|
877
|
+
const calls = [ethCall(d2.router, encodeGetDy(d2.family, call, call.amount)), ...reads];
|
|
845
878
|
const probeIn = call.amount / 1000n;
|
|
846
879
|
const probeAt = calls.length;
|
|
847
880
|
if (probe && probeIn > 0n) calls.push(ethCall(d2.router, encodeGetDy(d2.family, call, probeIn)));
|
|
848
881
|
const res = await rpc(chainId, calls);
|
|
849
|
-
|
|
882
|
+
const poolReason = await poolsReason(chainId, hops, res.slice(1, 1 + reads.length));
|
|
883
|
+
if (poolReason) return poolReason;
|
|
884
|
+
const out = wordUint(res[0]);
|
|
885
|
+
if (out === null) return "the router no longer quotes this route";
|
|
886
|
+
if (out < call.minDy) return `price moved \u2014 the pools now pay ${out}, under your minimum ${call.minDy}`;
|
|
887
|
+
return { out, probeOut: probe && probeIn > 0n ? wordUint(res[probeAt]) : null, amount: call.amount, minDy: call.minDy };
|
|
888
|
+
}
|
|
889
|
+
function poolCalls(list) {
|
|
890
|
+
return list.flatMap((pool) => [
|
|
891
|
+
{ method: "eth_getCode", params: [pool.address, "latest"] },
|
|
892
|
+
...pool.coins.map((_, k) => ethCall(pool.address, `${COINS_UINT}${k.toString(16).padStart(64, "0")}`))
|
|
893
|
+
]);
|
|
894
|
+
}
|
|
895
|
+
async function poolsReason(chainId, list, res) {
|
|
896
|
+
let at = 0;
|
|
850
897
|
const retry = [];
|
|
851
|
-
for (const pool of
|
|
898
|
+
for (const pool of list) {
|
|
852
899
|
const code = res[at++];
|
|
853
|
-
if (typeof code !== "string"
|
|
900
|
+
if (typeof code !== "string") return `could not read pool ${pool.name} (${pool.address}) over RPC`;
|
|
901
|
+
if (code.length <= 2 || lc2((0, import_viem3.keccak256)(code)) !== lc2(pool.codeHash)) return `pool ${pool.name} (${pool.address}) is not the pinned code`;
|
|
854
902
|
for (let k = 0; k < pool.coins.length; k++) {
|
|
855
903
|
const coin = wordAddress(res[at++]);
|
|
856
904
|
if (coin === null) retry.push({ pool, k });
|
|
@@ -864,12 +912,12 @@ function curveOnChain(opts) {
|
|
|
864
912
|
if (coin !== lc2(pool.coins[k])) return `pool ${pool.name} does not report its pinned coin ${k}`;
|
|
865
913
|
}
|
|
866
914
|
}
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
return
|
|
915
|
+
return null;
|
|
916
|
+
}
|
|
917
|
+
async function checkPools(chainId, list) {
|
|
918
|
+
return list.length ? poolsReason(chainId, list, await rpc(chainId, poolCalls(list))) : null;
|
|
871
919
|
}
|
|
872
|
-
return { rpc, verifyDeployment, checkSealed, inspectSealed };
|
|
920
|
+
return { rpc, verifyDeployment, checkSealed, inspectSealed, checkPools };
|
|
873
921
|
}
|
|
874
922
|
function lastToken(call) {
|
|
875
923
|
let k = 0;
|