@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
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: aave-v4
3
+ description: Aave v4 Spoke supply, withdraw, borrow, and repay via Continuum MPC multiSignRequest tools.
4
+ ---
5
+
6
+ # Aave v4 (MCP)
7
+
8
+ ## Before any action
9
+
10
+ 1. `load_defi_protocol({ protocolId: "aave-v4" })`
11
+ 2. `get_defi_protocol_supported_chains` — intersect with `get_chain_registry` (node must have RPC)
12
+ 3. `get_defi_protocol_supported_tokens({ protocolId: "aave-v4", chainId })` — market underlyings
13
+ 4. `get_token_registry` — map symbols (USDC, stETH, WETH) to addresses
14
+
15
+ ## Tool selection
16
+
17
+ | User intent | MCP tool |
18
+ |-------------|----------|
19
+ | Supply / deposit asset | `ctm_aave_v4_build_deposit_multisign` |
20
+ | Withdraw supplied asset | `ctm_aave_v4_build_withdraw_multisign` |
21
+ | Borrow against collateral | `ctm_aave_v4_build_borrow_multisign` |
22
+ | Repay debt | `ctm_aave_v4_build_repay_multisign` |
23
+
24
+ Example: **borrow USDC against stETH** → deposit/wrap collateral first if needed, then `ctm_aave_v4_build_borrow_multisign` with `underlying` = USDC address, `marketId` from Aave UI/API.
25
+
26
+ ## Required inputs (per action)
27
+
28
+ - `keyGenId`, `chainId`, `purposeText`
29
+ - `spoke`, `underlying`, `amountHuman`, `marketId` (hub/market segment)
30
+
31
+ ## After submit (`{ requestId }`)
32
+
33
+ Use base MCP lifecycle:
34
+
35
+ 1. `wait_for_sign_request_ready` (if needed)
36
+ 2. `sign_request_agree` (multi-agree)
37
+ 3. `trigger_sign_result`
38
+ 4. `broadcast_sign_result`
39
+
40
+ ## Notes
41
+
42
+ - Native ETH supply uses wrapped native from Aave API on that chain.
43
+ - Token filter: `api_underlyings` — only listed underlyings are valid per chain.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: curve-dao
3
+ description: Curve Router NG swaps via @curvefi/api session and multisign batch.
4
+ ---
5
+
6
+ # Curve DAO (MCP)
7
+
8
+ 1. Confirm chain via `get_defi_protocol_supported_chains` and `isCurveApiChainSupported`.
9
+ 2. `get_defi_protocol_supported_tokens` with `rpcUrl` from chain registry loads pool-graph swappable tokens.
10
+ 3. `ctm_curve_dao_quote` — `chainId`, `tokenIn`, `tokenOut`, `amountHuman` (optional `tokenInDecimals`). Server resolves `rpcUrl` from chain registry.
11
+ 4. `ctm_curve_dao_build_swap_multisign` — `keyGenId`, `chainId`, `purposeText`, `tokenIn`, `tokenOut`, `amountHuman`, `slippagePercent`.
12
+
13
+ Base MCP lifecycle after `{ requestId }`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: ethena
3
+ description: Ethena USDe stake, redeem, cooldown, and claim on Ethereum mainnet.
4
+ ---
5
+
6
+ # Ethena (MCP)
7
+
8
+ Stake/redeem MCP tools target **mainnet (chainId 1)**. Use `get_defi_protocol_supported_tokens` for USDe/sUSDe addresses.
9
+
10
+ Tools: `ctm_ethena_build_stake_multisign`, `_redeem_`, `_cooldown_`, `_claim_`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: euler-v2
3
+ description: Euler v2 isolated lend/borrow, vault withdraw, and collateral operations.
4
+ ---
5
+
6
+ # Euler v2 (MCP)
7
+
8
+ Supported chains from `get_defi_protocol_supported_chains` (subgraph map). Pass `vault` and asset addresses from Euler UI.
9
+
10
+ Tools include isolated lend/borrow, collateral deposit/withdraw, vault withdraw, borrow repay.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: lido
3
+ description: Lido ETH staking, withdrawals, and wstETH wrap/unwrap on Ethereum mainnet.
4
+ ---
5
+
6
+ # Lido (MCP)
7
+
8
+ ## Chains
9
+
10
+ Mainnet only (`chainId: 1`). Use `get_defi_protocol_supported_chains` and confirm node has chain 1 in `get_chain_registry`.
11
+
12
+ ## Tools
13
+
14
+ | Intent | Tool |
15
+ |--------|------|
16
+ | Stake ETH | `ctm_lido_build_submit_multisign` |
17
+ | Queue stETH withdrawal | `ctm_lido_build_request_withdrawals_multisign` |
18
+ | Claim withdrawal | `ctm_lido_build_claim_withdrawal_multisign` |
19
+ | Wrap stETH → wstETH | `ctm_lido_build_wrap_steth_multisign` |
20
+ | Unwrap wstETH | `ctm_lido_build_unwrap_wsteth_multisign` |
21
+
22
+ Complete flow with base MCP: `trigger_sign_result` → `broadcast_sign_result`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: maple-syrup
3
+ description: Maple Syrup pool deposit and redeem request flows.
4
+ ---
5
+
6
+ # Maple Syrup (MCP)
7
+
8
+ Chains: mainnet and Sepolia. Pass `syrupRouter`, `pool`, and `asset` from Maple UI/GraphQL.
9
+
10
+ Tools: `ctm_maple_build_deposit_multisign`, `ctm_maple_build_request_redeem_multisign`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: sky
3
+ description: Sky Lockstake and sUSDS deposit/redeem on Ethereum mainnet.
4
+ ---
5
+
6
+ # Sky (MCP)
7
+
8
+ Mainnet only. Tools for Lockstake stake/draw/wipe/close/reward and sUSDS deposit/redeem.
9
+
10
+ Use `get_defi_protocol_supported_chains` and base registry for USDS/SKY addresses.
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: uniswap-v4
3
+ description: Uniswap V4 swaps via Trade API quote, swap calldata, and multisign submit.
4
+ ---
5
+
6
+ # Uniswap v4 (MCP)
7
+
8
+ ## Multi-step swap flow
9
+
10
+ 1. `ctm_uniswap_v4_quote` — requires `UNISWAP_API_KEY` env on MCP server
11
+ 2. `ctm_uniswap_v4_create_swap` — Universal Router calldata
12
+ 3. `ctm_uniswap_v4_build_swap_multisign` — submits sign request → `{ requestId }`
13
+
14
+ ## Chains / tokens
15
+
16
+ - Chains: `get_defi_protocol_supported_chains` (Universal Router map)
17
+ - Tokens: any ERC-20 on supported chain; use `get_token_registry` for wallet tokens
18
+ - `tokenOut` may be any address on same chain
19
+
20
+ ## After submit
21
+
22
+ Base MCP: `trigger_sign_result` → `broadcast_sign_result`.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var viem = require('viem');
4
+ var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
4
5
 
5
6
  // src/chains/evm/types.ts
6
7
  function isEvmNativeToken(address) {
@@ -18,100 +19,6 @@ function matchEvmTokenKind(kind, address) {
18
19
  return true;
19
20
  }
20
21
 
21
- // src/chains/evm/txParams.ts
22
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
23
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
24
- return estimatedGas;
25
- }
26
- const cfg = BigInt(Math.floor(chainGasLimit));
27
- return cfg > estimatedGas ? cfg : estimatedGas;
28
- }
29
- function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
30
- if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
31
- return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
32
- }
33
- return (estimatedGas * 12n + 9n) / 10n;
34
- }
35
- function composeFeePayloadToTxParams(p, legacy) {
36
- const gl = p.txGasLimit ?? p.txgaslimit;
37
- if (gl == null || String(gl).trim() === "") return void 0;
38
- const n = p.txNonce ?? p.txnonce;
39
- let nonce = 0;
40
- if (typeof n === "bigint") nonce = Number(n);
41
- else if (typeof n === "number") nonce = n;
42
- else if (n != null) nonce = parseInt(String(n), 10);
43
- if (!Number.isFinite(nonce)) nonce = 0;
44
- const gasLimit = String(gl);
45
- if (legacy) {
46
- const gp = p.txGasPrice ?? p.txgasprice;
47
- return {
48
- nonce,
49
- gasLimit,
50
- txType: "legacy",
51
- gasPrice: gp != null ? String(gp) : "0"
52
- };
53
- }
54
- return {
55
- nonce,
56
- gasLimit,
57
- txType: "eip1559",
58
- maxFeePerGas: String(p.txMaxFeePerGas ?? ""),
59
- maxPriorityFeePerGas: String(p.txMaxPriorityFeePerGas ?? "")
60
- };
61
- }
62
- function triggerTxParamsFromComposeBody(body) {
63
- const existing = body.txParams;
64
- if (existing && typeof existing === "object" && !Array.isArray(existing)) {
65
- const o = existing;
66
- if (String(o.gasLimit ?? "").trim() !== "") {
67
- return { ...o };
68
- }
69
- }
70
- const pb = body.proposalTxParams;
71
- if (Array.isArray(pb) && pb.length > 0 && typeof pb[0] === "object" && pb[0] !== null) {
72
- const first = pb[0];
73
- if (String(first.gasLimit ?? "").trim() !== "") {
74
- return { ...first };
75
- }
76
- }
77
- const fromSnapshot = composeFeePayloadToTxParams(
78
- body,
79
- body.txMaxFeePerGas == null && body.txMaxPriorityFeePerGas == null
80
- );
81
- if (fromSnapshot) return fromSnapshot;
82
- return {
83
- nonce: 0,
84
- gasLimit: "",
85
- txType: "legacy",
86
- gasPrice: "0"
87
- };
88
- }
89
- function proposalTxParamsToFeeSnapshot(params) {
90
- if (params.txType === "legacy") {
91
- return {
92
- txNonce: params.nonce,
93
- txGasLimit: params.gasLimit,
94
- txGasPrice: params.gasPrice ?? "0"
95
- };
96
- }
97
- return {
98
- txNonce: params.nonce,
99
- txGasLimit: params.gasLimit,
100
- txMaxFeePerGas: params.maxFeePerGas ?? "",
101
- txMaxPriorityFeePerGas: params.maxPriorityFeePerGas ?? ""
102
- };
103
- }
104
-
105
- // src/core/keygen.ts
106
- function firstClientIdFromKeyGen(data) {
107
- const map = data?.ClientKeys;
108
- if (!map || typeof map !== "object") return null;
109
- for (const v of Object.values(map)) {
110
- if (typeof v === "string" && v.trim()) return v.trim();
111
- }
112
- return null;
113
- }
114
-
115
22
  // src/core/purpose.ts
116
23
  function mergePurposeText(purposeText, purposeSuffix) {
117
24
  const t = purposeText.trim();
@@ -131,7 +38,7 @@ function finalizeMultisign(input) {
131
38
  const ph = (keyGen.pubkeyhex ?? "").trim();
132
39
  if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
133
40
  const keyList = keyGen.keylist ?? [];
134
- const clientId = firstClientIdFromKeyGen(keyGen);
41
+ const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
135
42
  const first = legs[0];
136
43
  const messageHashes = legs.map((l) => l.msgHash);
137
44
  const messageRawBatch = legs.map((l) => l.msgRaw);
@@ -172,76 +79,11 @@ function finalizeMultisign(input) {
172
79
  if (clientId) bodyForSign.clientId = clientId;
173
80
  return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
174
81
  }
175
- async function fetchChainFeeParams(rpcUrl, chainId) {
176
- const url = rpcUrl.trim();
177
- if (!url) return { isEip1559: false };
178
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
179
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
180
- const chain = viem.defineChain({
181
- id: chainIdNum,
182
- name: "Discovery",
183
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
184
- rpcUrls: { default: { http: [url] } }
185
- });
186
- const publicClient = viem.createPublicClient({
187
- chain,
188
- transport: viem.http(url)
189
- });
190
- const getGasPriceGwei = async () => {
191
- const gasPriceWei = await publicClient.getGasPrice();
192
- return parseFloat(viem.formatUnits(gasPriceWei, 9));
193
- };
194
- try {
195
- const block = await publicClient.getBlock({ blockTag: "latest" });
196
- const baseFeePerGas = block?.baseFeePerGas;
197
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
198
- const gasPriceGwei2 = await getGasPriceGwei();
199
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
200
- }
201
- const baseFeeGwei = parseFloat(viem.formatUnits(baseFeePerGas, 9));
202
- let priorityFeeGwei;
203
- try {
204
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
205
- priorityFeeGwei = parseFloat(viem.formatUnits(priorityWei, 9));
206
- } catch {
207
- }
208
- const gasPriceGwei = await getGasPriceGwei();
209
- return {
210
- isEip1559: true,
211
- baseFeeGwei,
212
- priorityFeeGwei,
213
- gasPriceGwei
214
- };
215
- } catch {
216
- try {
217
- const gasPriceWei = await publicClient.getGasPrice();
218
- const gasPriceGwei = parseFloat(viem.formatUnits(gasPriceWei, 9));
219
- return { isEip1559: false, gasPriceGwei };
220
- } catch {
221
- return { isEip1559: false };
222
- }
223
- }
224
- }
225
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
226
- let maxP = maxPriorityFeePerGas;
227
- let maxF = maxFeePerGas;
228
- if (baseWei > 0n && maxF < baseWei + maxP) {
229
- maxF = baseWei + maxP + viem.parseGwei("0.001");
230
- }
231
- if (maxF < maxP) {
232
- maxF = baseWei > 0n ? baseWei + maxP + viem.parseGwei("0.001") : maxP * 2n;
82
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
83
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
84
+ return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
233
85
  }
234
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
235
- }
236
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
237
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
238
- }
239
- function gweiToDecimalString(n) {
240
- if (!Number.isFinite(n)) return "0";
241
- if (n === 0) return "0";
242
- const s = String(n);
243
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
244
- return s;
86
+ return (estimatedGas * 12n + 9n) / 10n;
245
87
  }
246
88
 
247
89
  // src/chains/evm/buildBatch.ts
@@ -265,7 +107,7 @@ async function buildEvmMultisignBatch(args) {
265
107
  rpcUrls: { default: { http: [rpcUrl] } }
266
108
  });
267
109
  const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
268
- const feeParams = await fetchChainFeeParams(rpcUrl, chainId);
110
+ const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
269
111
  const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
270
112
  const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
271
113
  const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
@@ -278,15 +120,19 @@ async function buildEvmMultisignBatch(args) {
278
120
  const step = steps[i];
279
121
  const currentNonce = baseNonce + i;
280
122
  let estimatedGas;
281
- try {
282
- estimatedGas = await publicClient.estimateGas({
283
- to: step.to,
284
- data: step.data,
285
- value: step.value,
286
- account: executor
287
- });
288
- } catch {
289
- estimatedGas = step.fallbackGas ?? 100000n;
123
+ if (args.estimateGasForStep) {
124
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
125
+ } else {
126
+ try {
127
+ estimatedGas = await publicClient.estimateGas({
128
+ to: step.to,
129
+ data: step.data,
130
+ value: step.value,
131
+ account: executor
132
+ });
133
+ } catch {
134
+ estimatedGas = step.fallbackGas ?? 100000n;
135
+ }
290
136
  }
291
137
  let gasLimitI;
292
138
  if (args.resolveGasLimit) {
@@ -294,7 +140,7 @@ async function buildEvmMultisignBatch(args) {
294
140
  } else if (step.routerSwap) {
295
141
  gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
296
142
  } else {
297
- gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
143
+ gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
298
144
  }
299
145
  let proposalTxParams;
300
146
  let feeSnapshot;
@@ -305,7 +151,7 @@ async function buildEvmMultisignBatch(args) {
305
151
  gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
306
152
  }
307
153
  if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
308
- const configured = viem.parseGwei(gweiToDecimalString(Number(chainDetail.gasPrice)));
154
+ const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
309
155
  if (configured > gasPriceWei) gasPriceWei = configured;
310
156
  }
311
157
  serialized = viem.serializeTransaction({
@@ -324,7 +170,7 @@ async function buildEvmMultisignBatch(args) {
324
170
  txType: "legacy",
325
171
  gasPrice: gasPriceWei.toString()
326
172
  };
327
- feeSnapshot = proposalTxParamsToFeeSnapshot(proposalTxParams);
173
+ feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
328
174
  } else {
329
175
  const fetchedBase = feeParams.baseFeeGwei ?? 0;
330
176
  const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
@@ -335,13 +181,13 @@ async function buildEvmMultisignBatch(args) {
335
181
  const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
336
182
  const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
337
183
  const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
338
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
339
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
184
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
185
+ let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
340
186
  if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
341
187
  maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
342
188
  maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
343
189
  }
344
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
190
+ ({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
345
191
  maxFeePerGas,
346
192
  maxPriorityFeePerGas,
347
193
  latestBaseFeeWei
@@ -364,7 +210,7 @@ async function buildEvmMultisignBatch(args) {
364
210
  maxFeePerGas: maxFeePerGas.toString(),
365
211
  maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
366
212
  };
367
- feeSnapshot = i === 0 ? proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
213
+ feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
368
214
  }
369
215
  const h = viem.keccak256(serialized);
370
216
  const msgHash = h.startsWith("0x") ? h.slice(2) : h;
@@ -408,30 +254,6 @@ var evmChainCategoryModule = {
408
254
  buildEvmMultisignBatch
409
255
  };
410
256
 
411
- // src/chains/evm/fees/customGas.ts
412
- function chainSnapshotForCustomGasExtraJSON(chainDetail) {
413
- const lr = chainDetail.legacy;
414
- const legacy = lr === true || typeof lr === "string" && lr.toLowerCase() === "true";
415
- const push = (o, key, v) => {
416
- if (v === void 0 || v === null) return;
417
- if (typeof v === "string" && v.trim() === "") return;
418
- o[key] = v;
419
- };
420
- const fields = {};
421
- push(fields, "gasLimit", chainDetail.gasLimit);
422
- if (legacy) {
423
- push(fields, "gasMultiplier", chainDetail.gasMultiplier);
424
- push(fields, "gasPrice", chainDetail.gasPrice);
425
- } else {
426
- push(fields, "gasMultiplier", chainDetail.gasMultiplier);
427
- push(fields, "baseFee", chainDetail.baseFee);
428
- push(fields, "priorityFee", chainDetail.priorityFee);
429
- push(fields, "baseFeeMultiplier", chainDetail.baseFeeMultiplier);
430
- }
431
- push(fields, "legacy", legacy);
432
- return fields;
433
- }
434
-
435
257
  // src/chains/evm/chainIdParse.ts
436
258
  function parseEvmChainIdToNumber(chainId) {
437
259
  if (chainId == null) return Number.NaN;
@@ -455,33 +277,66 @@ function parseEvmChainIdToNumber(chainId) {
455
277
  }
456
278
  return Number.parseInt(t, 10);
457
279
  }
458
-
459
- // src/chains/evm/rpcUrl.ts
460
- function isValidRpcUrl(url) {
461
- const t = url.trim();
462
- if (!t) return false;
463
- try {
464
- const u = new URL(t);
465
- return u.protocol === "http:" || u.protocol === "https:";
466
- } catch {
467
- return false;
280
+ function normalizeHumanDecimalAmount(raw, tokenDecimals) {
281
+ const t = raw.trim().replace(/,/g, "");
282
+ if (!t) return "";
283
+ if (!Number.isInteger(tokenDecimals) || tokenDecimals < 0 || tokenDecimals > 18) {
284
+ throw new Error("Invalid token decimals for amount normalization.");
468
285
  }
286
+ const wei = viem.parseUnits(t, tokenDecimals);
287
+ return viem.formatUnits(wei, tokenDecimals);
288
+ }
289
+ var normalizeCurveRouterAmountString = normalizeHumanDecimalAmount;
290
+
291
+ // src/chains/evm/coingecko.ts
292
+ var COINGECKO_PLATFORM_BY_CHAIN_ID = {
293
+ "1": "ethereum",
294
+ "56": "binance-smart-chain",
295
+ "137": "polygon-pos",
296
+ "42161": "arbitrum-one",
297
+ "10": "optimistic-ethereum",
298
+ "43114": "avalanche",
299
+ "8453": "base",
300
+ "324": "zk-sync-era",
301
+ "42220": "celo",
302
+ "250": "fantom",
303
+ "100": "gnosis",
304
+ "204": "op-bnb",
305
+ "534352": "scroll",
306
+ "5000": "mantle",
307
+ "169": "manta-pacific",
308
+ "1116": "core",
309
+ "30": "rootstock",
310
+ "288": "boba",
311
+ "1088": "metis-andromeda",
312
+ "34443": "mode",
313
+ "80084": "berachain",
314
+ "146": "sonic",
315
+ "60808": "bob-network",
316
+ "80094": "berachain",
317
+ "130": "unichain",
318
+ "57073": "ink",
319
+ "999": "hyperevm",
320
+ "239": "tac",
321
+ "9745": "plasma",
322
+ "1923": "swellchain",
323
+ "59144": "linea",
324
+ "81457": "blast",
325
+ "7777777": "zora"
326
+ };
327
+ function coingeckoPlatformForChainId(chainId) {
328
+ return COINGECKO_PLATFORM_BY_CHAIN_ID[String(chainId).trim()];
469
329
  }
470
330
 
471
- exports.alignEip1559FeesWithLatestBase = alignEip1559FeesWithLatestBase;
331
+ exports.COINGECKO_PLATFORM_BY_CHAIN_ID = COINGECKO_PLATFORM_BY_CHAIN_ID;
472
332
  exports.buildEvmMultisignBatch = buildEvmMultisignBatch;
473
- exports.chainSnapshotForCustomGasExtraJSON = chainSnapshotForCustomGasExtraJSON;
474
- exports.composeFeePayloadToTxParams = composeFeePayloadToTxParams;
333
+ exports.coingeckoPlatformForChainId = coingeckoPlatformForChainId;
475
334
  exports.evmChainCategoryModule = evmChainCategoryModule;
476
- exports.fetchChainFeeParams = fetchChainFeeParams;
477
- exports.gasLimitFromEstimateAndChainConfig = gasLimitFromEstimateAndChainConfig;
478
- exports.gweiToDecimalString = gweiToDecimalString;
479
335
  exports.isEvmNativeToken = isEvmNativeToken;
480
- exports.isValidRpcUrl = isValidRpcUrl;
481
336
  exports.matchEvmTokenKind = matchEvmTokenKind;
337
+ exports.normalizeCurveRouterAmountString = normalizeCurveRouterAmountString;
338
+ exports.normalizeHumanDecimalAmount = normalizeHumanDecimalAmount;
482
339
  exports.parseEvmChainIdToNumber = parseEvmChainIdToNumber;
483
- exports.proposalTxParamsToFeeSnapshot = proposalTxParamsToFeeSnapshot;
484
340
  exports.routerSwapGasLimitFromEstimate = routerSwapGasLimitFromEstimate;
485
- exports.triggerTxParamsFromComposeBody = triggerTxParamsFromComposeBody;
486
341
  //# sourceMappingURL=index.cjs.map
487
342
  //# sourceMappingURL=index.cjs.map