@continuumdao/ctm-mpc-defi 0.2.0 → 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 (100) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +563 -5
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +166 -20
  5. package/dist/agent/catalog.js +551 -7
  6. package/dist/agent/catalog.js.map +1 -1
  7. package/dist/agent/skills/aave-v4/SKILL.md +43 -0
  8. package/dist/agent/skills/curve-dao/SKILL.md +13 -0
  9. package/dist/agent/skills/ethena/SKILL.md +10 -0
  10. package/dist/agent/skills/euler-v2/SKILL.md +10 -0
  11. package/dist/agent/skills/lido/SKILL.md +22 -0
  12. package/dist/agent/skills/maple-syrup/SKILL.md +10 -0
  13. package/dist/agent/skills/sky/SKILL.md +10 -0
  14. package/dist/agent/skills/uniswap-v4/SKILL.md +22 -0
  15. package/dist/chains/evm/index.cjs +79 -224
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +26 -26
  18. package/dist/chains/evm/index.js +69 -209
  19. package/dist/chains/evm/index.js.map +1 -1
  20. package/dist/chains/near/index.d.ts +1 -1
  21. package/dist/chains/solana/index.d.ts +1 -1
  22. package/dist/core/index.cjs +68 -106
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.ts +21 -36
  25. package/dist/core/index.js +57 -96
  26. package/dist/core/index.js.map +1 -1
  27. package/dist/{envelope-CcE5Cz_q.d.ts → envelope-CpBUh9eP.d.ts} +1 -1
  28. package/dist/index.cjs +356 -1855
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -11
  31. package/dist/index.js +332 -1826
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +1152 -669
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/aave-v4/index.d.ts +418 -3
  36. package/dist/protocols/evm/aave-v4/index.js +1126 -670
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  38. package/dist/protocols/evm/curve-dao/index.cjs +257 -131
  39. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  40. package/dist/protocols/evm/curve-dao/index.d.ts +69 -5
  41. package/dist/protocols/evm/curve-dao/index.js +242 -124
  42. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  43. package/dist/protocols/evm/ethena/index.cjs +394 -402
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  45. package/dist/protocols/evm/ethena/index.d.ts +47 -3
  46. package/dist/protocols/evm/ethena/index.js +390 -404
  47. package/dist/protocols/evm/ethena/index.js.map +1 -1
  48. package/dist/protocols/evm/euler-v2/index.cjs +2810 -1191
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  50. package/dist/protocols/evm/euler-v2/index.d.ts +465 -3
  51. package/dist/protocols/evm/euler-v2/index.js +2761 -1192
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  53. package/dist/protocols/evm/lido/index.cjs +351 -236
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  55. package/dist/protocols/evm/lido/index.d.ts +34 -4
  56. package/dist/protocols/evm/lido/index.js +348 -238
  57. package/dist/protocols/evm/lido/index.js.map +1 -1
  58. package/dist/protocols/evm/maple/index.cjs +390 -395
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  60. package/dist/protocols/evm/maple/index.d.ts +23 -3
  61. package/dist/protocols/evm/maple/index.js +390 -397
  62. package/dist/protocols/evm/maple/index.js.map +1 -1
  63. package/dist/protocols/evm/sky/index.cjs +454 -232
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  65. package/dist/protocols/evm/sky/index.d.ts +57 -3
  66. package/dist/protocols/evm/sky/index.js +444 -231
  67. package/dist/protocols/evm/sky/index.js.map +1 -1
  68. package/dist/protocols/evm/uniswap-v4/index.cjs +423 -658
  69. package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
  70. package/dist/protocols/evm/uniswap-v4/index.d.ts +3 -4
  71. package/dist/protocols/evm/uniswap-v4/index.js +422 -657
  72. package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
  73. package/dist/{registry-oMKlO_5z.d.ts → registry-Bv5o37_w.d.ts} +1 -1
  74. package/dist/{types-Ce2qNHai.d.cts → types-BfjWdw1j.d.ts} +3 -1
  75. package/dist/{types-5u863Fd9.d.ts → types-DUeNJLr9.d.ts} +1 -1
  76. package/package.json +7 -6
  77. package/dist/agent/catalog.d.cts +0 -939
  78. package/dist/chains/evm/index.d.cts +0 -64
  79. package/dist/chains/near/index.d.cts +0 -37
  80. package/dist/chains/solana/index.d.cts +0 -40
  81. package/dist/core/index.d.cts +0 -43
  82. package/dist/envelope-DYDPnrHZ.d.cts +0 -35
  83. package/dist/index.d.cts +0 -16
  84. package/dist/keygen-CfNp8yKJ.d.cts +0 -9
  85. package/dist/keygen-DsINazx8.d.ts +0 -9
  86. package/dist/nodeRead-BnmSaMGO.d.cts +0 -8
  87. package/dist/nodeRead-BnmSaMGO.d.ts +0 -8
  88. package/dist/protocols/evm/aave-v4/index.d.cts +0 -500
  89. package/dist/protocols/evm/curve-dao/index.d.cts +0 -147
  90. package/dist/protocols/evm/ethena/index.d.cts +0 -161
  91. package/dist/protocols/evm/euler-v2/index.d.cts +0 -317
  92. package/dist/protocols/evm/lido/index.d.cts +0 -120
  93. package/dist/protocols/evm/maple/index.d.cts +0 -109
  94. package/dist/protocols/evm/sky/index.d.cts +0 -218
  95. package/dist/protocols/evm/uniswap-v4/index.d.cts +0 -324
  96. package/dist/registry-BwZoE668.d.cts +0 -8
  97. package/dist/txParams-BC7ogvdR.d.cts +0 -19
  98. package/dist/txParams-BC7ogvdR.d.ts +0 -19
  99. package/dist/types-B8idm_gu.d.cts +0 -34
  100. package/dist/types-Ce2qNHai.d.ts +0 -57
@@ -1,4 +1,5 @@
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
+ import { fetchChainFeeParams, gasLimitFromEstimateAndChainConfig, gweiToDecimalString, proposalTxParamsToFeeSnapshot, alignEip1559FeesWithLatestBase, getClientIdFromKeyGenResult } from '@continuumdao/continuum-node-sdk';
2
3
 
3
4
  // src/core/registry.ts
4
5
  var modules = [];
@@ -62,6 +63,17 @@ function isCurveApiChainSupported(chainId) {
62
63
  if (Number.isNaN(n) || n < 0) return false;
63
64
  return CURVE_FULL_NETWORK_CONSTANTS_CHAIN_IDS.has(n);
64
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
65
77
  var CURVE_NATIVE_PLACEHOLDER = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
66
78
  var ETH_PLACEHOLDER = CURVE_NATIVE_PLACEHOLDER;
67
79
  function normalizeAddr(a) {
@@ -94,13 +106,7 @@ function toCurveRouterTokenId(tokenAddress, wrappedNative) {
94
106
  }
95
107
  }
96
108
  function normalizeCurveRouterAmountString(raw, tokenInDecimals) {
97
- const t = raw.trim().replace(/,/g, "");
98
- if (!t) return "";
99
- if (!Number.isInteger(tokenInDecimals) || tokenInDecimals < 0 || tokenInDecimals > 18) {
100
- throw new Error("Invalid token-in decimals for amount normalization.");
101
- }
102
- const wei = parseUnits(t, tokenInDecimals);
103
- return formatUnits(wei, tokenInDecimals);
109
+ return normalizeHumanDecimalAmount(raw, tokenInDecimals);
104
110
  }
105
111
  function addEdge(adj, a, b) {
106
112
  if (a === b) return;
@@ -206,6 +212,36 @@ async function loadFullCurveSessionForRpc(rpcUrl) {
206
212
  return null;
207
213
  }
208
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
+ }
209
245
 
210
246
  // src/protocols/evm/curve-dao/purpose.ts
211
247
  function buildCurveDaoPurposePrefill(args) {
@@ -313,16 +349,6 @@ function resolveCurveDaoRouterGasUnitsFromSignRequest(detail, batchIndex) {
313
349
  return null;
314
350
  }
315
351
 
316
- // src/core/keygen.ts
317
- function firstClientIdFromKeyGen(data) {
318
- const map = data?.ClientKeys;
319
- if (!map || typeof map !== "object") return null;
320
- for (const v of Object.values(map)) {
321
- if (typeof v === "string" && v.trim()) return v.trim();
322
- }
323
- return null;
324
- }
325
-
326
352
  // src/core/purpose.ts
327
353
  function mergePurposeText(purposeText, purposeSuffix) {
328
354
  const t = purposeText.trim();
@@ -342,7 +368,7 @@ function finalizeMultisign(input) {
342
368
  const ph = (keyGen.pubkeyhex ?? "").trim();
343
369
  if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
344
370
  const keyList = keyGen.keylist ?? [];
345
- const clientId = firstClientIdFromKeyGen(keyGen);
371
+ const clientId = getClientIdFromKeyGenResult(keyGen);
346
372
  const first = legs[0];
347
373
  const messageHashes = legs.map((l) => l.msgHash);
348
374
  const messageRawBatch = legs.map((l) => l.msgRaw);
@@ -383,107 +409,12 @@ function finalizeMultisign(input) {
383
409
  if (clientId) bodyForSign.clientId = clientId;
384
410
  return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
385
411
  }
386
- async function fetchChainFeeParams(rpcUrl, chainId) {
387
- const url = rpcUrl.trim();
388
- if (!url) return { isEip1559: false };
389
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
390
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
391
- const chain = defineChain({
392
- id: chainIdNum,
393
- name: "Discovery",
394
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
395
- rpcUrls: { default: { http: [url] } }
396
- });
397
- const publicClient = createPublicClient({
398
- chain,
399
- transport: http(url)
400
- });
401
- const getGasPriceGwei = async () => {
402
- const gasPriceWei = await publicClient.getGasPrice();
403
- return parseFloat(formatUnits(gasPriceWei, 9));
404
- };
405
- try {
406
- const block = await publicClient.getBlock({ blockTag: "latest" });
407
- const baseFeePerGas = block?.baseFeePerGas;
408
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
409
- const gasPriceGwei2 = await getGasPriceGwei();
410
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
411
- }
412
- const baseFeeGwei = parseFloat(formatUnits(baseFeePerGas, 9));
413
- let priorityFeeGwei;
414
- try {
415
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
416
- priorityFeeGwei = parseFloat(formatUnits(priorityWei, 9));
417
- } catch {
418
- }
419
- const gasPriceGwei = await getGasPriceGwei();
420
- return {
421
- isEip1559: true,
422
- baseFeeGwei,
423
- priorityFeeGwei,
424
- gasPriceGwei
425
- };
426
- } catch {
427
- try {
428
- const gasPriceWei = await publicClient.getGasPrice();
429
- const gasPriceGwei = parseFloat(formatUnits(gasPriceWei, 9));
430
- return { isEip1559: false, gasPriceGwei };
431
- } catch {
432
- return { isEip1559: false };
433
- }
434
- }
435
- }
436
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
437
- let maxP = maxPriorityFeePerGas;
438
- let maxF = maxFeePerGas;
439
- if (baseWei > 0n && maxF < baseWei + maxP) {
440
- maxF = baseWei + maxP + parseGwei("0.001");
441
- }
442
- if (maxF < maxP) {
443
- maxF = baseWei > 0n ? baseWei + maxP + parseGwei("0.001") : maxP * 2n;
444
- }
445
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
446
- }
447
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
448
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
449
- }
450
- function gweiToDecimalString(n) {
451
- if (!Number.isFinite(n)) return "0";
452
- if (n === 0) return "0";
453
- const s = String(n);
454
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
455
- return s;
456
- }
457
-
458
- // src/chains/evm/txParams.ts
459
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
460
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
461
- return estimatedGas;
462
- }
463
- const cfg = BigInt(Math.floor(chainGasLimit));
464
- return cfg > estimatedGas ? cfg : estimatedGas;
465
- }
466
412
  function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
467
413
  if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
468
414
  return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
469
415
  }
470
416
  return (estimatedGas * 12n + 9n) / 10n;
471
417
  }
472
- function proposalTxParamsToFeeSnapshot(params) {
473
- if (params.txType === "legacy") {
474
- return {
475
- txNonce: params.nonce,
476
- txGasLimit: params.gasLimit,
477
- txGasPrice: params.gasPrice ?? "0"
478
- };
479
- }
480
- return {
481
- txNonce: params.nonce,
482
- txGasLimit: params.gasLimit,
483
- txMaxFeePerGas: params.maxFeePerGas ?? "",
484
- txMaxPriorityFeePerGas: params.maxPriorityFeePerGas ?? ""
485
- };
486
- }
487
418
 
488
419
  // src/chains/evm/buildBatch.ts
489
420
  async function buildEvmMultisignBatch(args) {
@@ -519,15 +450,19 @@ async function buildEvmMultisignBatch(args) {
519
450
  const step = steps[i];
520
451
  const currentNonce = baseNonce + i;
521
452
  let estimatedGas;
522
- try {
523
- estimatedGas = await publicClient.estimateGas({
524
- to: step.to,
525
- data: step.data,
526
- value: step.value,
527
- account: executor
528
- });
529
- } catch {
530
- estimatedGas = step.fallbackGas ?? 100000n;
453
+ if (args.estimateGasForStep) {
454
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
455
+ } else {
456
+ try {
457
+ estimatedGas = await publicClient.estimateGas({
458
+ to: step.to,
459
+ data: step.data,
460
+ value: step.value,
461
+ account: executor
462
+ });
463
+ } catch {
464
+ estimatedGas = step.fallbackGas ?? 100000n;
465
+ }
531
466
  }
532
467
  let gasLimitI;
533
468
  if (args.resolveGasLimit) {
@@ -804,6 +739,176 @@ async function buildEvmMultisignBodyCurveDaoBatch(args) {
804
739
  }
805
740
  });
806
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
+ }
807
912
 
808
913
  // src/protocols/evm/curve-dao/index.ts
809
914
  var CURVE_DAO_PROTOCOL_ID = "curve-dao";
@@ -819,6 +924,19 @@ var curveDaoProtocolModule = {
819
924
  return token.kind === "native" || token.kind === "erc20";
820
925
  },
821
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
+ },
822
940
  {
823
941
  id: "curve-dao.swap",
824
942
  protocolId: CURVE_DAO_PROTOCOL_ID,
@@ -841,6 +959,6 @@ var curveDao = {
841
959
  loadSession: loadFullCurveSessionForRpc
842
960
  };
843
961
 
844
- 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 };
845
963
  //# sourceMappingURL=index.js.map
846
964
  //# sourceMappingURL=index.js.map