@continuumdao/ctm-mpc-defi 0.2.1 → 0.2.2

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.
Files changed (57) hide show
  1. package/dist/agent/catalog.cjs +62 -11
  2. package/dist/agent/catalog.cjs.map +1 -1
  3. package/dist/agent/catalog.d.ts +27 -1
  4. package/dist/agent/catalog.js +61 -12
  5. package/dist/agent/catalog.js.map +1 -1
  6. package/dist/agent/skills/curve-dao/SKILL.md +2 -1
  7. package/dist/chains/evm/index.cjs +54 -0
  8. package/dist/chains/evm/index.cjs.map +1 -1
  9. package/dist/chains/evm/index.d.ts +13 -1
  10. package/dist/chains/evm/index.js +52 -2
  11. package/dist/chains/evm/index.js.map +1 -1
  12. package/dist/core/index.cjs +64 -0
  13. package/dist/core/index.cjs.map +1 -1
  14. package/dist/core/index.d.ts +20 -1
  15. package/dist/core/index.js +56 -1
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/index.cjs +131 -0
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +120 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/protocols/evm/aave-v4/index.cjs +766 -6
  23. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  24. package/dist/protocols/evm/aave-v4/index.d.ts +417 -1
  25. package/dist/protocols/evm/aave-v4/index.js +741 -8
  26. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  27. package/dist/protocols/evm/curve-dao/index.cjs +233 -7
  28. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  29. package/dist/protocols/evm/curve-dao/index.d.ts +66 -1
  30. package/dist/protocols/evm/curve-dao/index.js +227 -9
  31. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  32. package/dist/protocols/evm/ethena/index.cjs +104 -0
  33. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  34. package/dist/protocols/evm/ethena/index.d.ts +46 -1
  35. package/dist/protocols/evm/ethena/index.js +99 -1
  36. package/dist/protocols/evm/ethena/index.js.map +1 -1
  37. package/dist/protocols/evm/euler-v2/index.cjs +2334 -37
  38. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  39. package/dist/protocols/evm/euler-v2/index.d.ts +464 -1
  40. package/dist/protocols/evm/euler-v2/index.js +2286 -39
  41. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  42. package/dist/protocols/evm/lido/index.cjs +110 -0
  43. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  44. package/dist/protocols/evm/lido/index.d.ts +33 -2
  45. package/dist/protocols/evm/lido/index.js +107 -2
  46. package/dist/protocols/evm/lido/index.js.map +1 -1
  47. package/dist/protocols/evm/maple/index.cjs +83 -0
  48. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  49. package/dist/protocols/evm/maple/index.d.ts +22 -1
  50. package/dist/protocols/evm/maple/index.js +82 -1
  51. package/dist/protocols/evm/maple/index.js.map +1 -1
  52. package/dist/protocols/evm/sky/index.cjs +217 -0
  53. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  54. package/dist/protocols/evm/sky/index.d.ts +56 -1
  55. package/dist/protocols/evm/sky/index.js +210 -2
  56. package/dist/protocols/evm/sky/index.js.map +1 -1
  57. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { isAddress, getAddress, parseUnits, formatUnits, defineChain, createPublicClient, http, parseAbi, encodeFunctionData, parseGwei, serializeTransaction, keccak256 } from 'viem';
1
+ import { parseAbi, isAddress, getAddress, defineChain, createPublicClient, http, parseUnits, encodeFunctionData, formatUnits, parseGwei, serializeTransaction, keccak256, zeroAddress } from 'viem';
2
2
  import { fetchChainFeeParams, gasLimitFromEstimateAndChainConfig, gweiToDecimalString, proposalTxParamsToFeeSnapshot, alignEip1559FeesWithLatestBase, getClientIdFromKeyGenResult } from '@continuumdao/continuum-node-sdk';
3
3
 
4
4
  // src/core/registry.ts
@@ -63,6 +63,17 @@ function isCurveApiChainSupported(chainId) {
63
63
  if (Number.isNaN(n) || n < 0) return false;
64
64
  return CURVE_FULL_NETWORK_CONSTANTS_CHAIN_IDS.has(n);
65
65
  }
66
+ function normalizeHumanDecimalAmount(raw, tokenDecimals) {
67
+ const t = raw.trim().replace(/,/g, "");
68
+ if (!t) return "";
69
+ if (!Number.isInteger(tokenDecimals) || tokenDecimals < 0 || tokenDecimals > 18) {
70
+ throw new Error("Invalid token decimals for amount normalization.");
71
+ }
72
+ const wei = parseUnits(t, tokenDecimals);
73
+ return formatUnits(wei, tokenDecimals);
74
+ }
75
+
76
+ // src/protocols/evm/curve-dao/swapDestinations.ts
66
77
  var CURVE_NATIVE_PLACEHOLDER = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
67
78
  var ETH_PLACEHOLDER = CURVE_NATIVE_PLACEHOLDER;
68
79
  function normalizeAddr(a) {
@@ -95,13 +106,7 @@ function toCurveRouterTokenId(tokenAddress, wrappedNative) {
95
106
  }
96
107
  }
97
108
  function normalizeCurveRouterAmountString(raw, tokenInDecimals) {
98
- const t = raw.trim().replace(/,/g, "");
99
- if (!t) return "";
100
- if (!Number.isInteger(tokenInDecimals) || tokenInDecimals < 0 || tokenInDecimals > 18) {
101
- throw new Error("Invalid token-in decimals for amount normalization.");
102
- }
103
- const wei = parseUnits(t, tokenInDecimals);
104
- return formatUnits(wei, tokenInDecimals);
109
+ return normalizeHumanDecimalAmount(raw, tokenInDecimals);
105
110
  }
106
111
  function addEdge(adj, a, b) {
107
112
  if (a === b) return;
@@ -207,6 +212,36 @@ async function loadFullCurveSessionForRpc(rpcUrl) {
207
212
  return null;
208
213
  }
209
214
  }
215
+ async function loadCurveSessionSnapshotForRpc(rpcUrl) {
216
+ const session = await loadFullCurveSessionForRpc(rpcUrl);
217
+ if (!session) return null;
218
+ const adj = {};
219
+ for (const [key, neighbors] of session.adj) {
220
+ adj[key] = [...neighbors];
221
+ }
222
+ return {
223
+ wrappedNative: session.wrappedNative,
224
+ swappableNodeKeys: [...session.swappableNodeKeys],
225
+ routerReady: Boolean(session.curve?.hasRouter?.() && session.curve.hasRouter()),
226
+ adj
227
+ };
228
+ }
229
+ async function fetchCurveCoinsDataForRpc(rpcUrl, addresses) {
230
+ const session = await loadFullCurveSessionForRpc(rpcUrl);
231
+ if (!session?.curve?.getCoinsData) return [];
232
+ const coins = await session.curve.getCoinsData(addresses);
233
+ return addresses.map((addr, i) => {
234
+ const c = coins[i];
235
+ const dec = c?.decimals;
236
+ const decimals = typeof dec === "number" && Number.isInteger(dec) && dec >= 0 && dec <= 18 ? dec : null;
237
+ return {
238
+ address: addr,
239
+ name: c?.name && String(c.name).trim() || "\u2014",
240
+ symbol: c?.symbol && String(c.symbol).trim() || addr.slice(0, 6),
241
+ decimals
242
+ };
243
+ });
244
+ }
210
245
 
211
246
  // src/protocols/evm/curve-dao/purpose.ts
212
247
  function buildCurveDaoPurposePrefill(args) {
@@ -704,6 +739,176 @@ async function buildEvmMultisignBodyCurveDaoBatch(args) {
704
739
  }
705
740
  });
706
741
  }
742
+ var erc20DecimalsAbi = parseAbi(["function decimals() view returns (uint8)"]);
743
+ function normalizeNativeTokenIn(tokenIn) {
744
+ const trimmed = tokenIn.trim();
745
+ if (!trimmed) return tokenIn;
746
+ const lower = trimmed.toLowerCase();
747
+ if (lower === "eth" || lower === "native" || lower === "native_eth" || lower === zeroAddress.toLowerCase() || lower === CURVE_NATIVE_PLACEHOLDER.toLowerCase()) {
748
+ return CURVE_NATIVE_PLACEHOLDER;
749
+ }
750
+ return trimmed;
751
+ }
752
+ async function resolveTokenInDecimals(args) {
753
+ if (args.tokenInDecimals != null && Number.isInteger(args.tokenInDecimals) && args.tokenInDecimals >= 0 && args.tokenInDecimals <= 18) {
754
+ return args.tokenInDecimals;
755
+ }
756
+ const normalized = normalizeNativeTokenIn(args.tokenIn);
757
+ if (normalized.toLowerCase() === CURVE_NATIVE_PLACEHOLDER.toLowerCase()) {
758
+ return 18;
759
+ }
760
+ const addr = getAddress(
761
+ normalized.startsWith("0x") ? normalized : `0x${normalized}`
762
+ );
763
+ const ch = defineChain({
764
+ id: args.chainId,
765
+ name: "CurveQuote",
766
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
767
+ rpcUrls: { default: { http: [args.rpcUrl] } }
768
+ });
769
+ const publicClient = createPublicClient({ chain: ch, transport: http(args.rpcUrl) });
770
+ const decimalsN = await publicClient.readContract({
771
+ address: addr,
772
+ abi: erc20DecimalsAbi,
773
+ functionName: "decimals"
774
+ });
775
+ return Number(decimalsN);
776
+ }
777
+ async function curveDaoQuote(args) {
778
+ const rpcUrl = (args.rpcUrl ?? "").trim();
779
+ if (!rpcUrl) {
780
+ throw new Error("rpcUrl is required.");
781
+ }
782
+ if (!Number.isFinite(args.chainId) || args.chainId <= 0) {
783
+ throw new Error("chainId must be a positive integer.");
784
+ }
785
+ if (!isCurveApiChainSupported(args.chainId)) {
786
+ throw new Error(`Chain ${args.chainId} is not supported by Curve Router NG.`);
787
+ }
788
+ const tokenInDecimals = await resolveTokenInDecimals({
789
+ rpcUrl,
790
+ chainId: args.chainId,
791
+ tokenIn: args.tokenIn,
792
+ tokenInDecimals: args.tokenInDecimals
793
+ });
794
+ const amountForRouter = normalizeCurveRouterAmountString(
795
+ args.amountHuman,
796
+ tokenInDecimals
797
+ );
798
+ if (!amountForRouter) {
799
+ throw new Error("amountHuman must be a positive decimal string.");
800
+ }
801
+ const session = await loadFullCurveSessionForRpc(rpcUrl);
802
+ if (!session?.curve?.router?.getBestRouteAndOutput) {
803
+ throw new Error("Curve router is not available (session load failed or chain has no router).");
804
+ }
805
+ const { curve, wrappedNative: wn } = session;
806
+ const tokenInRouterId = toCurveRouterTokenId(normalizeNativeTokenIn(args.tokenIn), wn);
807
+ const tokenOutTrim = (args.tokenOut ?? "").trim();
808
+ const tokenOutRouterId = toCurveRouterTokenId(
809
+ tokenOutTrim.toLowerCase() === CURVE_NATIVE_PLACEHOLDER.toLowerCase() ? CURVE_NATIVE_PLACEHOLDER : getAddress(
810
+ tokenOutTrim.startsWith("0x") ? tokenOutTrim : `0x${tokenOutTrim}`
811
+ ),
812
+ wn
813
+ );
814
+ const res = await curve.router.getBestRouteAndOutput(
815
+ tokenInRouterId,
816
+ tokenOutRouterId,
817
+ amountForRouter
818
+ );
819
+ const route = res?.route;
820
+ if (!route || Array.isArray(route) && route.length === 0) {
821
+ throw new Error(
822
+ "Curve router could not find a pool route for this pair and size."
823
+ );
824
+ }
825
+ const outStr = String(res?.output ?? "0");
826
+ let priceImpactPercent = null;
827
+ try {
828
+ const pi = await curve.router.swapPriceImpact(
829
+ tokenInRouterId,
830
+ tokenOutRouterId,
831
+ amountForRouter
832
+ );
833
+ if (typeof pi === "number" && Number.isFinite(pi)) {
834
+ priceImpactPercent = pi;
835
+ }
836
+ } catch {
837
+ }
838
+ return {
839
+ inputAmount: amountForRouter,
840
+ output: outStr,
841
+ route,
842
+ priceImpactPercent,
843
+ tokenInRouterId,
844
+ tokenOutRouterId
845
+ };
846
+ }
847
+ function curveProbeInAmountString(fullNormalizedHuman, tokenInDecimals) {
848
+ const t = (fullNormalizedHuman ?? "").trim();
849
+ if (!t) return null;
850
+ if (!Number.isInteger(tokenInDecimals) || tokenInDecimals < 0 || tokenInDecimals > 18) return null;
851
+ let wei;
852
+ try {
853
+ wei = parseUnits(t, tokenInDecimals);
854
+ } catch {
855
+ return null;
856
+ }
857
+ if (wei <= 1n) return null;
858
+ let p = wei / 10000n;
859
+ if (p < 1n) p = 1n;
860
+ if (p >= wei) p = wei - 1n;
861
+ return formatUnits(p, tokenInDecimals);
862
+ }
863
+ function computeCurveExecutionSlippagePercent(args) {
864
+ const aIn = parseFloat((args.fullInHuman ?? "").replace(/,/g, "").trim());
865
+ const aOut = parseFloat((args.fullOutHuman ?? "").replace(/,/g, "").trim());
866
+ const pIn = parseFloat((args.probeInHuman ?? "").replace(/,/g, "").trim());
867
+ const pOut = parseFloat((args.probeOutHuman ?? "").replace(/,/g, "").trim());
868
+ if (!(aIn > 0) || !(aOut >= 0) || !(pIn > 0) || !Number.isFinite(pOut) || pOut < 0) return null;
869
+ const marginal = pOut / pIn;
870
+ const avg = aOut / aIn;
871
+ if (!Number.isFinite(marginal) || marginal <= 0 || !Number.isFinite(avg)) return null;
872
+ const pct = (1 - avg / marginal) * 100;
873
+ if (!Number.isFinite(pct)) return null;
874
+ return Math.max(0, pct);
875
+ }
876
+ function formatCurveExchangeLine(amountIn, amountOut, tokenInSymbol, tokenOutSymbol) {
877
+ const a = parseFloat((amountIn ?? "").replace(/,/g, "").trim());
878
+ const b = parseFloat((amountOut ?? "").replace(/,/g, "").trim());
879
+ const sIn = (tokenInSymbol || "").trim() || "in";
880
+ const sOut = (tokenOutSymbol || "").trim() || "out";
881
+ if (!(a > 0) || !Number.isFinite(b)) return "\u2014";
882
+ const r = b / a;
883
+ let rate;
884
+ if (r >= 1e-4) {
885
+ rate = r.toFixed(8).replace(/0+$/, "").replace(/\.$/, "");
886
+ } else if (r > 0) {
887
+ rate = r.toPrecision(6);
888
+ } else {
889
+ rate = "0";
890
+ }
891
+ if (!rate) rate = "0";
892
+ return `1 ${sIn} \u2248 ${rate} ${sOut}`;
893
+ }
894
+ function formatCurvePriceImpact(percent0to100) {
895
+ if (percent0to100 == null || !Number.isFinite(percent0to100) || percent0to100 < 0) return "\u2014";
896
+ if (percent0to100 === 0) return "0%";
897
+ if (percent0to100 < 1e-4) return "<0.0001%";
898
+ const t = percent0to100 < 0.01 ? percent0to100.toFixed(4) : percent0to100 < 1 ? percent0to100.toFixed(3) : percent0to100 < 10 ? percent0to100.toFixed(2) : percent0to100.toFixed(1);
899
+ return `${t.replace(/(\.\d*?[1-9])0+$/g, "$1").replace(/\.0$/, "")}%`;
900
+ }
901
+ function formatMinOutAtUserSlippage(quoteOutDecimal, userSlippagePercentInput, tokenOutSymbol) {
902
+ const q = parseFloat((quoteOutDecimal ?? "").replace(/,/g, "").trim());
903
+ const rawS = (userSlippagePercentInput ?? "0.5").trim().replace(/,/g, "");
904
+ const slip = Number.parseFloat(rawS);
905
+ const s = Number.isFinite(slip) && slip >= 0 && slip < 100 ? slip : 0.5;
906
+ if (!Number.isFinite(q) || q < 0) return "\u2014";
907
+ const min = q * ((100 - s) / 100);
908
+ const sOut = (tokenOutSymbol || "").trim() || "out";
909
+ const t = min.toFixed(8).replace(/\.?0+$/, "").replace(/(\.\d*?[1-9])0+$/, "$1");
910
+ return `${t} ${sOut}`.trim();
911
+ }
707
912
 
708
913
  // src/protocols/evm/curve-dao/index.ts
709
914
  var CURVE_DAO_PROTOCOL_ID = "curve-dao";
@@ -719,6 +924,19 @@ var curveDaoProtocolModule = {
719
924
  return token.kind === "native" || token.kind === "erc20";
720
925
  },
721
926
  actions: [
927
+ {
928
+ id: "curve-dao.quote",
929
+ protocolId: CURVE_DAO_PROTOCOL_ID,
930
+ chainCategory: "evm",
931
+ description: "Quote swap via Curve Router NG (getBestRouteAndOutput)",
932
+ commonParams: [],
933
+ params: {
934
+ chainId: { type: "number", required: true, description: "EVM chain id" },
935
+ tokenIn: { type: "address", required: true, description: "Token in or native placeholder" },
936
+ tokenOut: { type: "address", required: true, description: "Token out or native placeholder" },
937
+ amountHuman: { type: "string", required: true, description: "Human-readable input amount" }
938
+ }
939
+ },
722
940
  {
723
941
  id: "curve-dao.swap",
724
942
  protocolId: CURVE_DAO_PROTOCOL_ID,
@@ -741,6 +959,6 @@ var curveDao = {
741
959
  loadSession: loadFullCurveSessionForRpc
742
960
  };
743
961
 
744
- export { CURVE_DAO_PROTOCOL_ID, CURVE_NATIVE_PLACEHOLDER, CURVE_ROUTER_EXCHANGE_DEFAULT_GAS_UNITS, addNativeWethBridge, bfsCurveSwapDestinations, buildCurveDaoPurposePrefill, buildCurveLiquidityGraphFromApi, buildEvmMultisignBodyCurveDaoBatch, curveDao, curveDaoProtocolModule, fetchAllCurvePools, isCurveApiChainSupported, isCurveApiChainSupported as isCurveDaoChainSupported, isCurveDaoErc20ApproveEvmSignRequest, isCurveDaoSwapEvmSignRequest, isCurveTokenKeySwappable, loadFullCurveSessionForRpc, normalizeCurveRouterAmountString, resolveCurveDaoRouterGasUnitsFromSignRequest, swappableCurveGraphNodeKeys, toCurveRouterTokenId, toCurveTokenKey };
962
+ export { CURVE_DAO_PROTOCOL_ID, CURVE_NATIVE_PLACEHOLDER, CURVE_ROUTER_EXCHANGE_DEFAULT_GAS_UNITS, addNativeWethBridge, bfsCurveSwapDestinations, buildCurveDaoPurposePrefill, buildCurveLiquidityGraphFromApi, buildEvmMultisignBodyCurveDaoBatch, computeCurveExecutionSlippagePercent, curveDao, curveDaoProtocolModule, curveDaoQuote, curveProbeInAmountString, fetchAllCurvePools, fetchCurveCoinsDataForRpc, formatCurveExchangeLine, formatCurvePriceImpact, formatMinOutAtUserSlippage, isCurveApiChainSupported, isCurveApiChainSupported as isCurveDaoChainSupported, isCurveDaoErc20ApproveEvmSignRequest, isCurveDaoSwapEvmSignRequest, isCurveTokenKeySwappable, loadCurveSessionSnapshotForRpc, loadFullCurveSessionForRpc, normalizeCurveRouterAmountString, resolveCurveDaoRouterGasUnitsFromSignRequest, swappableCurveGraphNodeKeys, toCurveRouterTokenId, toCurveTokenKey };
745
963
  //# sourceMappingURL=index.js.map
746
964
  //# sourceMappingURL=index.js.map