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