@continuumdao/ctm-mpc-defi 0.2.0 → 0.2.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.
Files changed (100) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +511 -4
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +140 -20
  5. package/dist/agent/catalog.js +501 -6
  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 +12 -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 +27 -226
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +14 -26
  18. package/dist/chains/evm/index.js +21 -211
  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 +8 -110
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.ts +5 -39
  25. package/dist/core/index.js +6 -100
  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 +238 -1868
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -11
  31. package/dist/index.js +227 -1839
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +385 -662
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/aave-v4/index.d.ts +1 -2
  36. package/dist/protocols/evm/aave-v4/index.js +385 -662
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  38. package/dist/protocols/evm/curve-dao/index.cjs +24 -124
  39. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  40. package/dist/protocols/evm/curve-dao/index.d.ts +3 -4
  41. package/dist/protocols/evm/curve-dao/index.js +15 -115
  42. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  43. package/dist/protocols/evm/ethena/index.cjs +290 -402
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  45. package/dist/protocols/evm/ethena/index.d.ts +1 -2
  46. package/dist/protocols/evm/ethena/index.js +291 -403
  47. package/dist/protocols/evm/ethena/index.js.map +1 -1
  48. package/dist/protocols/evm/euler-v2/index.cjs +485 -1163
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  50. package/dist/protocols/evm/euler-v2/index.d.ts +1 -2
  51. package/dist/protocols/evm/euler-v2/index.js +486 -1164
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  53. package/dist/protocols/evm/lido/index.cjs +241 -236
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  55. package/dist/protocols/evm/lido/index.d.ts +1 -2
  56. package/dist/protocols/evm/lido/index.js +242 -237
  57. package/dist/protocols/evm/lido/index.js.map +1 -1
  58. package/dist/protocols/evm/maple/index.cjs +310 -398
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  60. package/dist/protocols/evm/maple/index.d.ts +1 -2
  61. package/dist/protocols/evm/maple/index.js +311 -399
  62. package/dist/protocols/evm/maple/index.js.map +1 -1
  63. package/dist/protocols/evm/sky/index.cjs +238 -233
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  65. package/dist/protocols/evm/sky/index.d.ts +1 -2
  66. package/dist/protocols/evm/sky/index.js +236 -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
package/dist/index.js CHANGED
@@ -1,24 +1,8 @@
1
- import { getAddress, zeroAddress, defineChain, createPublicClient, http, formatUnits, parseGwei, serializeTransaction, keccak256, encodeFunctionData, erc20Abi, parseAbi, parseUnits, decodeFunctionData, isAddress } from 'viem';
2
- import { zodToJsonSchema } from 'zod-to-json-schema';
3
- import { z } from 'zod';
1
+ import { getClientIdFromKeyGenResult, gasLimitFromEstimateAndChainConfig, fetchChainFeeParams, gweiToDecimalString, proposalTxParamsToFeeSnapshot, alignEip1559FeesWithLatestBase, nodeFetchWithReadAuth } from '@continuumdao/continuum-node-sdk';
2
+ export { getClientIdFromKeyGenResult as firstClientIdFromKeyGen } from '@continuumdao/continuum-node-sdk';
3
+ import { getAddress, zeroAddress, defineChain, createPublicClient, http, parseGwei, serializeTransaction, keccak256, encodeFunctionData, erc20Abi, parseAbi, parseUnits, decodeFunctionData, isAddress } from 'viem';
4
4
 
5
- // src/core/keygen.ts
6
- function firstClientIdFromKeyGen(data) {
7
- const map = data?.ClientKeys;
8
- if (!map || typeof map !== "object") return null;
9
- for (const v of Object.values(map)) {
10
- if (typeof v === "string" && v.trim()) return v.trim();
11
- }
12
- return null;
13
- }
14
- function requirePubKeyHex(keyGen) {
15
- const ph = (keyGen.pubkeyhex ?? "").trim();
16
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
17
- return ph;
18
- }
19
- function keyListFromKeyGen(keyGen) {
20
- return keyGen.keylist ?? [];
21
- }
5
+ // src/core/index.ts
22
6
 
23
7
  // src/core/purpose.ts
24
8
  function mergePurposeText(purposeText, purposeSuffix) {
@@ -29,8 +13,6 @@ function mergePurposeText(purposeText, purposeSuffix) {
29
13
 
30
14
  ${suffix}` : suffix;
31
15
  }
32
-
33
- // src/core/envelope.ts
34
16
  function finalizeMultisign(input) {
35
17
  const { keyGen, destinationChainID, legs } = input;
36
18
  if (legs.length === 0) {
@@ -39,7 +21,7 @@ function finalizeMultisign(input) {
39
21
  const ph = (keyGen.pubkeyhex ?? "").trim();
40
22
  if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
41
23
  const keyList = keyGen.keylist ?? [];
42
- const clientId = firstClientIdFromKeyGen(keyGen);
24
+ const clientId = getClientIdFromKeyGenResult(keyGen);
43
25
  const first = legs[0];
44
26
  const messageHashes = legs.map((l) => l.msgHash);
45
27
  const messageRawBatch = legs.map((l) => l.msgRaw);
@@ -104,85 +86,6 @@ function getProtocolModule(id) {
104
86
  function getActionsByChainCategory(category) {
105
87
  return modules.filter((m) => m.chainCategory === category).flatMap((m) => m.actions);
106
88
  }
107
-
108
- // src/core/nodeRead.ts
109
- function nodeFetchWithReadAuth(url, init, auth) {
110
- const method = (init?.method ?? "GET").toUpperCase();
111
- const headers = new Headers(init?.headers);
112
- if (auth.bearerOnGet && method === "GET" && auth.jwt && auth.jwt.trim()) {
113
- headers.set("Authorization", `Bearer ${auth.jwt.trim()}`);
114
- }
115
- return fetch(url, { ...init, headers });
116
- }
117
-
118
- // src/core/managementPostSig.ts
119
- function normalizeManagementNodeKey(nodeKey) {
120
- const nk = nodeKey?.trim().replace(/^0x/i, "");
121
- if (!nk || !/^[0-9a-fA-F]{128}$/.test(nk)) {
122
- throw new Error("nodeKey is required (128 hex from GET /getNodeKey).");
123
- }
124
- return nk.toLowerCase();
125
- }
126
- function managementSigFields(nonce, nodeKey) {
127
- return { nonce, clientSig: "", nodeKey: normalizeManagementNodeKey(nodeKey) };
128
- }
129
- function buildManagementPostBody(nonce, nodeKey, fields = {}) {
130
- return { ...managementSigFields(nonce, nodeKey), ...fields };
131
- }
132
- function messageToSignManagementBody(body) {
133
- return JSON.stringify({ ...body, clientSig: "" });
134
- }
135
- function withManagementClientSig(body, clientSig) {
136
- return { ...body, clientSig: clientSig.trim().replace(/^0x/i, "") };
137
- }
138
-
139
- // src/core/managementNonce.ts
140
- function mpcAuthData(raw) {
141
- const code = raw.Code ?? raw.code;
142
- if (code !== 0 && code !== void 0) return void 0;
143
- return raw.Data ?? raw.data;
144
- }
145
- async function fetchNodeKey(nodeUrl, readAuth = { bearerOnGet: false, jwt: null }) {
146
- const base = nodeUrl.trim().replace(/\/$/, "");
147
- const res = await nodeFetchWithReadAuth(`${base}/getNodeKey`, { cache: "no-store" }, readAuth);
148
- const text = await res.text();
149
- let raw;
150
- try {
151
- raw = JSON.parse(text);
152
- } catch {
153
- return { nodeKey: "", ok: false };
154
- }
155
- const data = mpcAuthData(raw);
156
- const nk = typeof data === "string" ? data : data != null && typeof data === "object" && !Array.isArray(data) ? String(data.nodeKey ?? data.NodeKey ?? "") : data != null ? String(data) : "";
157
- const trimmed = nk.trim().replace(/^0x/i, "");
158
- if (!/^[0-9a-fA-F]{128}$/.test(trimmed)) {
159
- return { nodeKey: "", ok: false };
160
- }
161
- return { nodeKey: trimmed.toLowerCase(), ok: res.ok };
162
- }
163
- async function fetchManagementNonce(nodeUrl, useEd25519, ed25519PublicKey, readAuth = { bearerOnGet: false, jwt: null }) {
164
- const base = nodeUrl.trim().replace(/\/$/, "");
165
- const path = useEd25519 ? "/getPublicMgtKeyNonce" : "/getNodeMgtKeyNonce";
166
- const url = useEd25519 && ed25519PublicKey && /^[0-9a-fA-F]{64}$/.test(ed25519PublicKey.trim()) ? `${base}${path}?publicKey=${encodeURIComponent(ed25519PublicKey.trim())}` : `${base}${path}`;
167
- const res = await nodeFetchWithReadAuth(url, { cache: "no-store" }, readAuth);
168
- const text = await res.text();
169
- let raw;
170
- try {
171
- raw = JSON.parse(text);
172
- } catch {
173
- return { nonce: 0, ok: false, code: -1 };
174
- }
175
- const code = raw.Code ?? raw.code;
176
- const payload = mpcAuthData(raw) ?? raw.Data ?? raw.data;
177
- let nonce = 0;
178
- if (typeof payload === "number" && !Number.isNaN(payload)) {
179
- nonce = payload;
180
- } else if (payload && typeof payload === "object") {
181
- const n = payload.nonce ?? payload.Nonce;
182
- nonce = typeof n === "number" && !Number.isNaN(n) ? n : Number(n) || 0;
183
- }
184
- return { nonce, ok: res.ok && (code === 0 || code === void 0), code: code ?? -1 };
185
- }
186
89
  function isEvmNativeToken(address) {
187
90
  try {
188
91
  return getAddress(address) === zeroAddress;
@@ -197,161 +100,12 @@ function matchEvmTokenKind(kind, address) {
197
100
  }
198
101
  return true;
199
102
  }
200
-
201
- // src/chains/evm/txParams.ts
202
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
203
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
204
- return estimatedGas;
205
- }
206
- const cfg = BigInt(Math.floor(chainGasLimit));
207
- return cfg > estimatedGas ? cfg : estimatedGas;
208
- }
209
103
  function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
210
104
  if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
211
105
  return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
212
106
  }
213
107
  return (estimatedGas * 12n + 9n) / 10n;
214
108
  }
215
- function composeFeePayloadToTxParams(p, legacy) {
216
- const gl = p.txGasLimit ?? p.txgaslimit;
217
- if (gl == null || String(gl).trim() === "") return void 0;
218
- const n = p.txNonce ?? p.txnonce;
219
- let nonce = 0;
220
- if (typeof n === "bigint") nonce = Number(n);
221
- else if (typeof n === "number") nonce = n;
222
- else if (n != null) nonce = parseInt(String(n), 10);
223
- if (!Number.isFinite(nonce)) nonce = 0;
224
- const gasLimit = String(gl);
225
- if (legacy) {
226
- const gp = p.txGasPrice ?? p.txgasprice;
227
- return {
228
- nonce,
229
- gasLimit,
230
- txType: "legacy",
231
- gasPrice: gp != null ? String(gp) : "0"
232
- };
233
- }
234
- return {
235
- nonce,
236
- gasLimit,
237
- txType: "eip1559",
238
- maxFeePerGas: String(p.txMaxFeePerGas ?? ""),
239
- maxPriorityFeePerGas: String(p.txMaxPriorityFeePerGas ?? "")
240
- };
241
- }
242
- function triggerTxParamsFromComposeBody(body) {
243
- const existing = body.txParams;
244
- if (existing && typeof existing === "object" && !Array.isArray(existing)) {
245
- const o = existing;
246
- if (String(o.gasLimit ?? "").trim() !== "") {
247
- return { ...o };
248
- }
249
- }
250
- const pb = body.proposalTxParams;
251
- if (Array.isArray(pb) && pb.length > 0 && typeof pb[0] === "object" && pb[0] !== null) {
252
- const first = pb[0];
253
- if (String(first.gasLimit ?? "").trim() !== "") {
254
- return { ...first };
255
- }
256
- }
257
- const fromSnapshot = composeFeePayloadToTxParams(
258
- body,
259
- body.txMaxFeePerGas == null && body.txMaxPriorityFeePerGas == null
260
- );
261
- if (fromSnapshot) return fromSnapshot;
262
- return {
263
- nonce: 0,
264
- gasLimit: "",
265
- txType: "legacy",
266
- gasPrice: "0"
267
- };
268
- }
269
- function proposalTxParamsToFeeSnapshot(params) {
270
- if (params.txType === "legacy") {
271
- return {
272
- txNonce: params.nonce,
273
- txGasLimit: params.gasLimit,
274
- txGasPrice: params.gasPrice ?? "0"
275
- };
276
- }
277
- return {
278
- txNonce: params.nonce,
279
- txGasLimit: params.gasLimit,
280
- txMaxFeePerGas: params.maxFeePerGas ?? "",
281
- txMaxPriorityFeePerGas: params.maxPriorityFeePerGas ?? ""
282
- };
283
- }
284
- async function fetchChainFeeParams(rpcUrl, chainId) {
285
- const url = rpcUrl.trim();
286
- if (!url) return { isEip1559: false };
287
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
288
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
289
- const chain = defineChain({
290
- id: chainIdNum,
291
- name: "Discovery",
292
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
293
- rpcUrls: { default: { http: [url] } }
294
- });
295
- const publicClient = createPublicClient({
296
- chain,
297
- transport: http(url)
298
- });
299
- const getGasPriceGwei = async () => {
300
- const gasPriceWei = await publicClient.getGasPrice();
301
- return parseFloat(formatUnits(gasPriceWei, 9));
302
- };
303
- try {
304
- const block = await publicClient.getBlock({ blockTag: "latest" });
305
- const baseFeePerGas = block?.baseFeePerGas;
306
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
307
- const gasPriceGwei2 = await getGasPriceGwei();
308
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
309
- }
310
- const baseFeeGwei = parseFloat(formatUnits(baseFeePerGas, 9));
311
- let priorityFeeGwei;
312
- try {
313
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
314
- priorityFeeGwei = parseFloat(formatUnits(priorityWei, 9));
315
- } catch {
316
- }
317
- const gasPriceGwei = await getGasPriceGwei();
318
- return {
319
- isEip1559: true,
320
- baseFeeGwei,
321
- priorityFeeGwei,
322
- gasPriceGwei
323
- };
324
- } catch {
325
- try {
326
- const gasPriceWei = await publicClient.getGasPrice();
327
- const gasPriceGwei = parseFloat(formatUnits(gasPriceWei, 9));
328
- return { isEip1559: false, gasPriceGwei };
329
- } catch {
330
- return { isEip1559: false };
331
- }
332
- }
333
- }
334
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
335
- let maxP = maxPriorityFeePerGas;
336
- let maxF = maxFeePerGas;
337
- if (baseWei > 0n && maxF < baseWei + maxP) {
338
- maxF = baseWei + maxP + parseGwei("0.001");
339
- }
340
- if (maxF < maxP) {
341
- maxF = baseWei > 0n ? baseWei + maxP + parseGwei("0.001") : maxP * 2n;
342
- }
343
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
344
- }
345
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
346
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
347
- }
348
- function gweiToDecimalString(n) {
349
- if (!Number.isFinite(n)) return "0";
350
- if (n === 0) return "0";
351
- const s = String(n);
352
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
353
- return s;
354
- }
355
109
 
356
110
  // src/chains/evm/buildBatch.ts
357
111
  async function buildEvmMultisignBatch(args) {
@@ -387,15 +141,19 @@ async function buildEvmMultisignBatch(args) {
387
141
  const step = steps[i];
388
142
  const currentNonce = baseNonce + i;
389
143
  let estimatedGas;
390
- try {
391
- estimatedGas = await publicClient.estimateGas({
392
- to: step.to,
393
- data: step.data,
394
- value: step.value,
395
- account: executor
396
- });
397
- } catch {
398
- estimatedGas = step.fallbackGas ?? 100000n;
144
+ if (args.estimateGasForStep) {
145
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
146
+ } else {
147
+ try {
148
+ estimatedGas = await publicClient.estimateGas({
149
+ to: step.to,
150
+ data: step.data,
151
+ value: step.value,
152
+ account: executor
153
+ });
154
+ } catch {
155
+ estimatedGas = step.fallbackGas ?? 100000n;
156
+ }
399
157
  }
400
158
  let gasLimitI;
401
159
  if (args.resolveGasLimit) {
@@ -517,30 +275,6 @@ var evmChainCategoryModule = {
517
275
  buildEvmMultisignBatch
518
276
  };
519
277
 
520
- // src/chains/evm/fees/customGas.ts
521
- function chainSnapshotForCustomGasExtraJSON(chainDetail) {
522
- const lr = chainDetail.legacy;
523
- const legacy = lr === true || typeof lr === "string" && lr.toLowerCase() === "true";
524
- const push = (o, key, v) => {
525
- if (v === void 0 || v === null) return;
526
- if (typeof v === "string" && v.trim() === "") return;
527
- o[key] = v;
528
- };
529
- const fields = {};
530
- push(fields, "gasLimit", chainDetail.gasLimit);
531
- if (legacy) {
532
- push(fields, "gasMultiplier", chainDetail.gasMultiplier);
533
- push(fields, "gasPrice", chainDetail.gasPrice);
534
- } else {
535
- push(fields, "gasMultiplier", chainDetail.gasMultiplier);
536
- push(fields, "baseFee", chainDetail.baseFee);
537
- push(fields, "priorityFee", chainDetail.priorityFee);
538
- push(fields, "baseFeeMultiplier", chainDetail.baseFeeMultiplier);
539
- }
540
- push(fields, "legacy", legacy);
541
- return fields;
542
- }
543
-
544
278
  // src/chains/evm/chainIdParse.ts
545
279
  function parseEvmChainIdToNumber(chainId) {
546
280
  if (chainId == null) return Number.NaN;
@@ -565,18 +299,6 @@ function parseEvmChainIdToNumber(chainId) {
565
299
  return Number.parseInt(t, 10);
566
300
  }
567
301
 
568
- // src/chains/evm/rpcUrl.ts
569
- function isValidRpcUrl(url) {
570
- const t = url.trim();
571
- if (!t) return false;
572
- try {
573
- const u = new URL(t);
574
- return u.protocol === "http:" || u.protocol === "https:";
575
- } catch {
576
- return false;
577
- }
578
- }
579
-
580
302
  // src/chains/solana/types.ts
581
303
  var solanaChainCategoryModule = {
582
304
  category: "solana"
@@ -1000,6 +722,35 @@ async function uniswapCreateSwap(args) {
1000
722
  }
1001
723
  return parsed;
1002
724
  }
725
+ async function estimateUniswapRouterSwapGas(args) {
726
+ const fromTradeApi = parseOptionalGasLimitString(args.swapRecord.gasLimit) ?? parseOptionalGasLimitString(args.swapRecord.gas);
727
+ if (fromTradeApi != null && fromTradeApi > 0n) {
728
+ return { baseGasUnits: fromTradeApi, source: "tradeApi" };
729
+ }
730
+ try {
731
+ const est = await args.publicClient.estimateGas({
732
+ to: args.to,
733
+ data: args.data,
734
+ value: args.value,
735
+ account: args.executor
736
+ });
737
+ return { baseGasUnits: est, source: "rpcEstimate" };
738
+ } catch (e) {
739
+ const estimateGasError = e instanceof Error ? e.message : String(e);
740
+ const minRouterGas = 500000n;
741
+ if (args.useCustomGas) {
742
+ const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
743
+ if (cfg != null && cfg >= minRouterGas) {
744
+ return { baseGasUnits: cfg, source: "estimateFailedFallback", estimateGasError };
745
+ }
746
+ }
747
+ return {
748
+ baseGasUnits: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK,
749
+ source: "estimateFailedFallback",
750
+ estimateGasError
751
+ };
752
+ }
753
+ }
1003
754
  var permit2ApproveRouterAbi = [
1004
755
  {
1005
756
  name: "approve",
@@ -1100,10 +851,6 @@ function permit2SpenderAndApproveWeiFromSwapCalldata(dataHex, tokenIn, quoteInpu
1100
851
  }
1101
852
  }
1102
853
  async function buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei) {
1103
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1104
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1105
- const keyList = args.keyGen.keylist ?? [];
1106
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1107
854
  const toRouter = getAddress(
1108
855
  (args.swap.to ?? "").trim().startsWith("0x") ? args.swap.to.trim() : `0x${args.swap.to.trim()}`
1109
856
  );
@@ -1121,214 +868,90 @@ async function buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei) {
1121
868
  "Native (ETH) in swap: could not determine payable value (no `swap.value`, no `execute` amount in calldata, and quote input is zero). Refresh the quote and request /swap again."
1122
869
  );
1123
870
  }
1124
- const ch = defineChain({
1125
- id: args.chainId,
1126
- name: "Destination",
1127
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1128
- rpcUrls: { default: { http: [args.rpcUrl] } }
1129
- });
1130
- const publicClient = createPublicClient({ chain: ch, transport: http(args.rpcUrl) });
1131
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1132
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1133
- const latestBaseFeeWeiNativeIn = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1134
- const useCustomGas = args.useCustomGas;
1135
- const chainGasLimitRouter = args.chainDetail?.gasLimit != null && Number.isFinite(Number(args.chainDetail.gasLimit)) && Number(args.chainDetail.gasLimit) > 0 ? Number(args.chainDetail.gasLimit) : void 0;
1136
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1137
- const nonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
1138
- const proposalTxParamsBatch = [];
1139
- const messageHashes = [];
1140
- const messageRawBatch = [];
1141
871
  const swapRecord = args.swap;
1142
- const fromTradeApi = parseOptionalGasLimitString(swapRecord.gasLimit) ?? parseOptionalGasLimitString(swapRecord.gas);
1143
872
  let gasBuildSource = "rpcEstimate";
1144
873
  let estimateGasError;
1145
- let baseGasUnits1;
1146
- if (fromTradeApi != null && fromTradeApi > 0n) {
1147
- baseGasUnits1 = fromTradeApi;
1148
- gasBuildSource = "tradeApi";
1149
- } else {
1150
- try {
1151
- baseGasUnits1 = await publicClient.estimateGas({
874
+ let swapBaseGasUnits = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
875
+ const dataNo0x = dataHex.startsWith("0x") ? dataHex.slice(2) : dataHex;
876
+ const purposeSuffix = "Uniswap V4: 1-tx batch \u2014 native gas token in (no ERC-20 approve) \u2014 single payable swap (Trade /swap).";
877
+ return buildEvmMultisignBatch({
878
+ context: {
879
+ chainCategory: "evm",
880
+ keyGen: args.keyGen,
881
+ purposeText: args.purposeText,
882
+ chainId: args.chainId,
883
+ rpcUrl: args.rpcUrl,
884
+ executorAddress: args.executorAddress,
885
+ chainDetail: args.chainDetail,
886
+ useCustomGas: args.useCustomGas,
887
+ customGasChainDetails: args.customGasChainDetails
888
+ },
889
+ steps: [
890
+ {
1152
891
  to: toRouter,
1153
892
  data: dataHex,
1154
893
  value: valueWei,
1155
- account: args.executorAddress
1156
- });
1157
- gasBuildSource = "rpcEstimate";
1158
- } catch (e) {
1159
- estimateGasError = e instanceof Error ? e.message : String(e);
1160
- const minRouterGas = 500000n;
1161
- if (useCustomGas) {
1162
- const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
1163
- if (cfg != null && cfg >= minRouterGas) {
1164
- baseGasUnits1 = cfg;
1165
- } else {
1166
- baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
1167
- }
1168
- } else {
1169
- baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
1170
- }
1171
- gasBuildSource = "estimateFailedFallback";
1172
- }
1173
- }
1174
- const gasLimit1 = routerSwapGasLimitFromEstimate(baseGasUnits1, chainGasLimitRouter);
1175
- const currentNonce0 = nonce;
1176
- let firstTxFeePayload = {};
1177
- if (legacy) {
1178
- let gasPriceWei1 = await publicClient.getGasPrice();
1179
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1180
- gasPriceWei1 = gasPriceWei1 * BigInt(100 + gasFeeMultiplier) / 100n;
1181
- }
1182
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1183
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1184
- if (configured > gasPriceWei1) gasPriceWei1 = configured;
1185
- }
1186
- firstTxFeePayload = { txNonce: nonce, txGasLimit: gasLimit1.toString(), txGasPrice: gasPriceWei1.toString() };
1187
- const ser0 = serializeTransaction({
1188
- type: "legacy",
1189
- to: toRouter,
1190
- data: dataHex,
1191
- value: valueWei,
1192
- gas: gasLimit1,
1193
- gasPrice: gasPriceWei1,
1194
- nonce: currentNonce0,
1195
- chainId: args.chainId
1196
- });
1197
- const h0 = keccak256(ser0);
1198
- messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
1199
- messageRawBatch.push(ser0);
1200
- proposalTxParamsBatch.push({
1201
- nonce: currentNonce0,
1202
- gasLimit: gasLimit1.toString(),
1203
- txType: "legacy",
1204
- gasPrice: gasPriceWei1.toString()
1205
- });
1206
- } else {
1207
- const fetchedBase1 = feeParams.baseFeeGwei ?? 0;
1208
- const fetchedPriority1 = feeParams.priorityFeeGwei ?? 0;
1209
- const configuredBase1 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1210
- const configuredPriority1 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1211
- const effectiveBaseFeeGwei1 = Math.max(fetchedBase1, configuredBase1);
1212
- const effectivePriorityFeeGwei1 = Math.max(fetchedPriority1, configuredPriority1);
1213
- const baseFeeMultiplierPct1 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1214
- const baseComponentGwei1 = effectiveBaseFeeGwei1 * baseFeeMultiplierPct1 / 100;
1215
- const maxFeePerGasGwei1 = baseComponentGwei1 + effectivePriorityFeeGwei1;
1216
- let maxPriorityFeePerGas1 = effectivePriorityFeeGwei1 > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei1)) : parseGwei("1");
1217
- let maxFeePerGas1 = parseGwei(gweiToDecimalString(maxFeePerGasGwei1));
1218
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1219
- maxPriorityFeePerGas1 = maxPriorityFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
1220
- maxFeePerGas1 = maxFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
1221
- }
1222
- ({ maxFeePerGas: maxFeePerGas1, maxPriorityFeePerGas: maxPriorityFeePerGas1 } = alignEip1559FeesWithLatestBase(maxFeePerGas1, maxPriorityFeePerGas1, latestBaseFeeWeiNativeIn));
1223
- firstTxFeePayload = {
1224
- txNonce: nonce,
1225
- txGasLimit: gasLimit1.toString(),
1226
- txMaxFeePerGas: maxFeePerGas1.toString(),
1227
- txMaxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
1228
- };
1229
- const ser0 = serializeTransaction({
1230
- type: "eip1559",
1231
- to: toRouter,
1232
- data: dataHex,
1233
- value: valueWei,
1234
- gas: gasLimit1,
1235
- maxFeePerGas: maxFeePerGas1,
1236
- maxPriorityFeePerGas: maxPriorityFeePerGas1,
1237
- nonce: currentNonce0,
1238
- chainId: args.chainId
1239
- });
1240
- const h0 = keccak256(ser0);
1241
- messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
1242
- messageRawBatch.push(ser0);
1243
- proposalTxParamsBatch.push({
1244
- nonce: currentNonce0,
1245
- gasLimit: gasLimit1.toString(),
1246
- txType: "eip1559",
1247
- maxFeePerGas: maxFeePerGas1.toString(),
1248
- maxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
1249
- });
1250
- }
1251
- const dataNo0x = dataHex.startsWith("0x") ? dataHex.slice(2) : dataHex;
1252
- const audit = {
1253
- skipPermit2Batch: true,
1254
- inputKind: "native_eth",
1255
- noErc20Approve: true,
1256
- quoteInputWei: quoteInputWei.toString(),
1257
- swapValueWei: valueWei.toString(),
1258
- uniswapCreateSwap: {
1259
- requestId: args.createSwapResponse.requestId,
1260
- gasFee: args.createSwapResponse.gasFee,
1261
- gasBuildSwap: {
1262
- useCustomGas,
1263
- source: gasBuildSource,
1264
- baseGasUnits: baseGasUnits1.toString(),
1265
- ...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
1266
- },
1267
- swap: {
1268
- to: args.createSwapResponse.swap.to,
1269
- value: args.createSwapResponse.swap.value,
1270
- dataNibbles: (() => {
1271
- const t = (args.createSwapResponse.swap.data ?? "").toString().trim();
1272
- return t.startsWith("0x") ? t.length - 2 : t.length;
1273
- })()
894
+ routerSwap: true,
895
+ fallbackGas: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK
1274
896
  }
897
+ ],
898
+ purposeSuffix,
899
+ firstMsgRawNo0x: dataNo0x,
900
+ destinationAddress: toRouter,
901
+ estimateGasForStep: async ({ publicClient, executor }) => {
902
+ const r = await estimateUniswapRouterSwapGas({
903
+ publicClient,
904
+ executor,
905
+ to: toRouter,
906
+ data: dataHex,
907
+ value: valueWei,
908
+ swapRecord,
909
+ useCustomGas: args.useCustomGas,
910
+ chainDetail: args.chainDetail
911
+ });
912
+ gasBuildSource = r.source;
913
+ estimateGasError = r.estimateGasError;
914
+ swapBaseGasUnits = r.baseGasUnits;
915
+ return r.baseGasUnits;
1275
916
  },
1276
- fullQuoteFromPermitSnapshot: args.fullQuoteSnapshot,
1277
- originalPurpose: args.purposeText
1278
- };
1279
- const batchMeta = [
1280
- {
1281
- destinationAddress: toRouter,
917
+ buildBatchMeta: () => ({
1282
918
  signatureText: JSON.stringify({
1283
919
  kind: "UniswapV4",
1284
920
  name: "UniversalRouter (payable, native in)",
1285
921
  note: "Single tx from Trade POST /swap; no ERC-20 approve. Calldata in messageHashes[0] / messageRawBatch[0]."
1286
922
  }),
1287
923
  evm: { type: "uniswap_v4_swap_tx", version: 1, chainId: String(args.chainId) },
1288
- uniswapV4: audit
1289
- }
1290
- ];
1291
- const extraPayload = { batchMeta };
1292
- if (useCustomGas) {
1293
- const snap = args.customGasChainDetails;
1294
- if (snap && typeof snap === "object" && !Array.isArray(snap) && Object.keys(snap).length > 0) {
1295
- extraPayload.customGasChainDetails = snap;
1296
- }
1297
- }
1298
- const extraJSON = JSON.stringify(extraPayload);
1299
- const firstSigText = batchMeta[0].signatureText;
1300
- const bodyForSign = {
1301
- keyList,
1302
- pubKey: ph,
1303
- msgHash: messageHashes[0],
1304
- msgRaw: dataNo0x,
1305
- messageHashes,
1306
- messageRawBatch,
1307
- destinationChainID: String(args.chainId),
1308
- destinationAddress: toRouter,
1309
- extraJSON,
1310
- signatureText: firstSigText,
1311
- purpose: (() => {
1312
- const t = args.purposeText.trim();
1313
- const batchDesc = "Uniswap V4: 1-tx batch \u2014 native gas token in (no ERC-20 approve) \u2014 single payable swap (Trade /swap).";
1314
- return (t ? `${t}
1315
-
1316
- ` : "") + batchDesc;
1317
- })(),
1318
- ...firstTxFeePayload,
1319
- proposalTxParams: proposalTxParamsBatch
1320
- };
1321
- if (valueWei > 0n) {
1322
- bodyForSign.value = valueWei.toString();
1323
- }
1324
- if (clientId) bodyForSign.clientId = clientId;
1325
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
924
+ uniswapV4: {
925
+ skipPermit2Batch: true,
926
+ inputKind: "native_eth",
927
+ noErc20Approve: true,
928
+ quoteInputWei: quoteInputWei.toString(),
929
+ swapValueWei: valueWei.toString(),
930
+ uniswapCreateSwap: {
931
+ requestId: args.createSwapResponse.requestId,
932
+ gasFee: args.createSwapResponse.gasFee,
933
+ gasBuildSwap: {
934
+ useCustomGas: args.useCustomGas,
935
+ source: gasBuildSource,
936
+ baseGasUnits: swapBaseGasUnits.toString(),
937
+ ...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
938
+ },
939
+ swap: {
940
+ to: args.createSwapResponse.swap.to,
941
+ value: args.createSwapResponse.swap.value,
942
+ dataNibbles: (() => {
943
+ const t = (args.createSwapResponse.swap.data ?? "").toString().trim();
944
+ return t.startsWith("0x") ? t.length - 2 : t.length;
945
+ })()
946
+ }
947
+ },
948
+ fullQuoteFromPermitSnapshot: args.fullQuoteSnapshot,
949
+ originalPurpose: args.purposeText
950
+ }
951
+ })
952
+ });
1326
953
  }
1327
954
  async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
1328
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1329
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1330
- const keyList = args.keyGen.keylist ?? [];
1331
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1332
955
  const tokenIn = getAddress(args.tokenIn);
1333
956
  const parsedInOut = parseUniswapQuoteClassicInOut(args.fullQuoteSnapshot);
1334
957
  const quoteInputWei = parsedInOut?.inputWei;
@@ -1383,298 +1006,33 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
1383
1006
  return 0n;
1384
1007
  }
1385
1008
  })();
1386
- const ch = defineChain({
1387
- id: args.chainId,
1388
- name: "Destination",
1389
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1390
- rpcUrls: { default: { http: [args.rpcUrl] } }
1391
- });
1392
- const publicClient = createPublicClient({ chain: ch, transport: http(args.rpcUrl) });
1393
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1394
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1395
- const latestBaseFeeWeiSkipBatch = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1396
- const useCustomGas = args.useCustomGas;
1397
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1398
- const chainGasLimitRouter = args.chainDetail?.gasLimit != null && Number.isFinite(Number(args.chainDetail.gasLimit)) && Number(args.chainDetail.gasLimit) > 0 ? Number(args.chainDetail.gasLimit) : void 0;
1399
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1400
- const nonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
1401
- const proposalTxParamsBatch = [];
1402
- const messageHashes = [];
1403
- const messageRawBatch = [];
1404
- const approveMsgRawNo0x = approveData.startsWith("0x") ? approveData.slice(2) : approveData;
1405
- let firstTxFeePayload = {};
1406
- const approveGas = await publicClient.estimateGas({
1407
- to: tokenIn,
1408
- data: approveData,
1409
- value: 0n,
1410
- account: args.executorAddress
1411
- });
1412
- const gasLimit0 = useCustomGas ? gasLimitFromEstimateAndChainConfig(approveGas, gasLimitConfig) : approveGas;
1413
- const currentNonce0 = nonce;
1414
- if (legacy) {
1415
- let gasPriceWei = await publicClient.getGasPrice();
1416
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1417
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1418
- }
1419
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1420
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1421
- if (configured > gasPriceWei) gasPriceWei = configured;
1422
- }
1423
- firstTxFeePayload = { txNonce: nonce, txGasLimit: gasLimit0.toString(), txGasPrice: gasPriceWei.toString() };
1424
- const ser0 = serializeTransaction({
1425
- type: "legacy",
1426
- to: tokenIn,
1427
- data: approveData,
1428
- value: 0n,
1429
- gas: gasLimit0,
1430
- gasPrice: gasPriceWei,
1431
- nonce: currentNonce0,
1432
- chainId: args.chainId
1433
- });
1434
- const h0 = keccak256(ser0);
1435
- messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
1436
- messageRawBatch.push(ser0);
1437
- proposalTxParamsBatch.push({
1438
- nonce: currentNonce0,
1439
- gasLimit: gasLimit0.toString(),
1440
- txType: "legacy",
1441
- gasPrice: gasPriceWei.toString()
1442
- });
1443
- } else {
1444
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1445
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1446
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1447
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1448
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1449
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1450
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1451
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1452
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1453
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
1454
- let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
1455
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1456
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1457
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1458
- }
1459
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1460
- maxFeePerGas,
1461
- maxPriorityFeePerGas,
1462
- latestBaseFeeWeiSkipBatch
1463
- ));
1464
- firstTxFeePayload = {
1465
- txNonce: nonce,
1466
- txGasLimit: gasLimit0.toString(),
1467
- txMaxFeePerGas: maxFeePerGas.toString(),
1468
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1469
- };
1470
- const ser0 = serializeTransaction({
1471
- type: "eip1559",
1472
- to: tokenIn,
1473
- data: approveData,
1474
- value: 0n,
1475
- gas: gasLimit0,
1476
- maxFeePerGas,
1477
- maxPriorityFeePerGas,
1478
- nonce: currentNonce0,
1479
- chainId: args.chainId
1480
- });
1481
- const h0 = keccak256(ser0);
1482
- messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
1483
- messageRawBatch.push(ser0);
1484
- proposalTxParamsBatch.push({
1485
- nonce: currentNonce0,
1486
- gasLimit: gasLimit0.toString(),
1487
- txType: "eip1559",
1488
- maxFeePerGas: maxFeePerGas.toString(),
1489
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1490
- });
1491
- }
1009
+ const swapRecord = args.swap;
1010
+ const swapMsgIndex = usePermit2Triple ? 2 : 1;
1011
+ let gasBuildSource = "rpcEstimate";
1012
+ let estimateGasError;
1013
+ let swapBaseGasUnits = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
1014
+ const steps = [
1015
+ { to: tokenIn, data: approveData, value: 0n, fallbackGas: 100000n }
1016
+ ];
1492
1017
  if (usePermit2Triple) {
1493
1018
  const permit2ApproveData = encodeFunctionData({
1494
1019
  abi: permit2ApproveRouterAbi,
1495
1020
  functionName: "approve",
1496
1021
  args: [tokenIn, permit2Spender, approveAmountWei, Number(expiration48)]
1497
1022
  });
1498
- const approveP2Gas = await publicClient.estimateGas({
1499
- to: PERMIT2_ADDRESS,
1500
- data: permit2ApproveData,
1501
- value: 0n,
1502
- account: args.executorAddress
1503
- });
1504
- const gasLimitP2 = useCustomGas ? gasLimitFromEstimateAndChainConfig(approveP2Gas, gasLimitConfig) : approveP2Gas;
1505
- const currentNonceP2 = nonce + 1;
1506
- if (legacy) {
1507
- let gasPriceWeiP2 = await publicClient.getGasPrice();
1508
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1509
- gasPriceWeiP2 = gasPriceWeiP2 * BigInt(100 + gasFeeMultiplier) / 100n;
1510
- }
1511
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1512
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1513
- if (configured > gasPriceWeiP2) gasPriceWeiP2 = configured;
1514
- }
1515
- const serP2 = serializeTransaction({
1516
- type: "legacy",
1517
- to: PERMIT2_ADDRESS,
1518
- data: permit2ApproveData,
1519
- value: 0n,
1520
- gas: gasLimitP2,
1521
- gasPrice: gasPriceWeiP2,
1522
- nonce: currentNonceP2,
1523
- chainId: args.chainId
1524
- });
1525
- const hP2 = keccak256(serP2);
1526
- messageHashes.push(hP2.startsWith("0x") ? hP2.slice(2) : hP2);
1527
- messageRawBatch.push(serP2);
1528
- proposalTxParamsBatch.push({
1529
- nonce: currentNonceP2,
1530
- gasLimit: gasLimitP2.toString(),
1531
- txType: "legacy",
1532
- gasPrice: gasPriceWeiP2.toString()
1533
- });
1534
- } else {
1535
- const fetchedBaseP2 = feeParams.baseFeeGwei ?? 0;
1536
- const fetchedPriorityP2 = feeParams.priorityFeeGwei ?? 0;
1537
- const configuredBaseP2 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1538
- const configuredPriorityP2 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1539
- const effectiveBaseFeeGweiP2 = Math.max(fetchedBaseP2, configuredBaseP2);
1540
- const effectivePriorityFeeGweiP2 = Math.max(fetchedPriorityP2, configuredPriorityP2);
1541
- const baseFeeMultiplierPctP2 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1542
- const baseComponentGweiP2 = effectiveBaseFeeGweiP2 * baseFeeMultiplierPctP2 / 100;
1543
- const maxFeePerGasGweiP2 = baseComponentGweiP2 + effectivePriorityFeeGweiP2;
1544
- let maxPriorityFeePerGasP2 = effectivePriorityFeeGweiP2 > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGweiP2)) : parseGwei("1");
1545
- let maxFeePerGasP2 = parseGwei(gweiToDecimalString(maxFeePerGasGweiP2));
1546
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1547
- maxPriorityFeePerGasP2 = maxPriorityFeePerGasP2 * BigInt(100 + gasFeeMultiplier) / 100n;
1548
- maxFeePerGasP2 = maxFeePerGasP2 * BigInt(100 + gasFeeMultiplier) / 100n;
1549
- }
1550
- ({ maxFeePerGas: maxFeePerGasP2, maxPriorityFeePerGas: maxPriorityFeePerGasP2 } = alignEip1559FeesWithLatestBase(maxFeePerGasP2, maxPriorityFeePerGasP2, latestBaseFeeWeiSkipBatch));
1551
- const serP2 = serializeTransaction({
1552
- type: "eip1559",
1553
- to: PERMIT2_ADDRESS,
1554
- data: permit2ApproveData,
1555
- value: 0n,
1556
- gas: gasLimitP2,
1557
- maxFeePerGas: maxFeePerGasP2,
1558
- maxPriorityFeePerGas: maxPriorityFeePerGasP2,
1559
- nonce: currentNonceP2,
1560
- chainId: args.chainId
1561
- });
1562
- const hP2 = keccak256(serP2);
1563
- messageHashes.push(hP2.startsWith("0x") ? hP2.slice(2) : hP2);
1564
- messageRawBatch.push(serP2);
1565
- proposalTxParamsBatch.push({
1566
- nonce: currentNonceP2,
1567
- gasLimit: gasLimitP2.toString(),
1568
- txType: "eip1559",
1569
- maxFeePerGas: maxFeePerGasP2.toString(),
1570
- maxPriorityFeePerGas: maxPriorityFeePerGasP2.toString()
1571
- });
1572
- }
1573
- }
1574
- const swapRecord = args.swap;
1575
- const fromTradeApi = parseOptionalGasLimitString(swapRecord.gasLimit) ?? parseOptionalGasLimitString(swapRecord.gas);
1576
- let gasBuildSource = "rpcEstimate";
1577
- let estimateGasError;
1578
- let baseGasUnits1;
1579
- if (fromTradeApi != null && fromTradeApi > 0n) {
1580
- baseGasUnits1 = fromTradeApi;
1581
- gasBuildSource = "tradeApi";
1582
- } else {
1583
- try {
1584
- baseGasUnits1 = await publicClient.estimateGas({
1585
- to: toRouter,
1586
- data: dataHex,
1587
- value: valueWei,
1588
- account: args.executorAddress
1589
- });
1590
- gasBuildSource = "rpcEstimate";
1591
- } catch (e) {
1592
- estimateGasError = e instanceof Error ? e.message : String(e);
1593
- const minRouterGas = 500000n;
1594
- if (useCustomGas) {
1595
- const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
1596
- if (cfg != null && cfg >= minRouterGas) {
1597
- baseGasUnits1 = cfg;
1598
- } else {
1599
- baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
1600
- }
1601
- } else {
1602
- baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
1603
- }
1604
- gasBuildSource = "estimateFailedFallback";
1605
- }
1606
- }
1607
- const gasLimit1 = routerSwapGasLimitFromEstimate(baseGasUnits1, chainGasLimitRouter);
1608
- const currentNonce1 = nonce + (usePermit2Triple ? 2 : 1);
1609
- if (legacy) {
1610
- let gasPriceWei1 = await publicClient.getGasPrice();
1611
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1612
- gasPriceWei1 = gasPriceWei1 * BigInt(100 + gasFeeMultiplier) / 100n;
1613
- }
1614
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1615
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1616
- if (configured > gasPriceWei1) gasPriceWei1 = configured;
1617
- }
1618
- const ser1 = serializeTransaction({
1619
- type: "legacy",
1620
- to: toRouter,
1621
- data: dataHex,
1622
- value: valueWei,
1623
- gas: gasLimit1,
1624
- gasPrice: gasPriceWei1,
1625
- nonce: currentNonce1,
1626
- chainId: args.chainId
1627
- });
1628
- const h1 = keccak256(ser1);
1629
- messageHashes.push(h1.startsWith("0x") ? h1.slice(2) : h1);
1630
- messageRawBatch.push(ser1);
1631
- proposalTxParamsBatch.push({
1632
- nonce: currentNonce1,
1633
- gasLimit: gasLimit1.toString(),
1634
- txType: "legacy",
1635
- gasPrice: gasPriceWei1.toString()
1636
- });
1637
- } else {
1638
- const fetchedBase1 = feeParams.baseFeeGwei ?? 0;
1639
- const fetchedPriority1 = feeParams.priorityFeeGwei ?? 0;
1640
- const configuredBase1 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1641
- const configuredPriority1 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1642
- const effectiveBaseFeeGwei1 = Math.max(fetchedBase1, configuredBase1);
1643
- const effectivePriorityFeeGwei1 = Math.max(fetchedPriority1, configuredPriority1);
1644
- const baseFeeMultiplierPct1 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1645
- const baseComponentGwei1 = effectiveBaseFeeGwei1 * baseFeeMultiplierPct1 / 100;
1646
- const maxFeePerGasGwei1 = baseComponentGwei1 + effectivePriorityFeeGwei1;
1647
- let maxPriorityFeePerGas1 = effectivePriorityFeeGwei1 > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei1)) : parseGwei("1");
1648
- let maxFeePerGas1 = parseGwei(gweiToDecimalString(maxFeePerGasGwei1));
1649
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1650
- maxPriorityFeePerGas1 = maxPriorityFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
1651
- maxFeePerGas1 = maxFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
1652
- }
1653
- ({ maxFeePerGas: maxFeePerGas1, maxPriorityFeePerGas: maxPriorityFeePerGas1 } = alignEip1559FeesWithLatestBase(maxFeePerGas1, maxPriorityFeePerGas1, latestBaseFeeWeiSkipBatch));
1654
- const ser1 = serializeTransaction({
1655
- type: "eip1559",
1656
- to: toRouter,
1657
- data: dataHex,
1658
- value: valueWei,
1659
- gas: gasLimit1,
1660
- maxFeePerGas: maxFeePerGas1,
1661
- maxPriorityFeePerGas: maxPriorityFeePerGas1,
1662
- nonce: currentNonce1,
1663
- chainId: args.chainId
1664
- });
1665
- const h1 = keccak256(ser1);
1666
- messageHashes.push(h1.startsWith("0x") ? h1.slice(2) : h1);
1667
- messageRawBatch.push(ser1);
1668
- proposalTxParamsBatch.push({
1669
- nonce: currentNonce1,
1670
- gasLimit: gasLimit1.toString(),
1671
- txType: "eip1559",
1672
- maxFeePerGas: maxFeePerGas1.toString(),
1673
- maxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
1674
- });
1023
+ steps.push({ to: PERMIT2_ADDRESS, data: permit2ApproveData, value: 0n, fallbackGas: 100000n });
1675
1024
  }
1676
- const swapMsgIndex = usePermit2Triple ? 2 : 1;
1677
- const audit = {
1025
+ steps.push({
1026
+ to: toRouter,
1027
+ data: dataHex,
1028
+ value: valueWei,
1029
+ routerSwap: true,
1030
+ fallbackGas: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK
1031
+ });
1032
+ const swapStepIndex = steps.length - 1;
1033
+ const approveMsgRawNo0x = approveData.startsWith("0x") ? approveData.slice(2) : approveData;
1034
+ const purposeSuffix = usePermit2Triple ? "Uniswap V4: 3-tx batch (classic allowance) \u2014 (1) ERC-20 approve allowance hub, (2) hub approve(Universal Router), (3) swap (Trade /swap)." : "Uniswap V4: 2-tx batch (classic allowance, dispatcher) \u2014 (1) ERC-20 approve swap.to (dispatcher pulls tokens), (2) swap (Trade /swap).";
1035
+ const buildSwapAudit = () => ({
1678
1036
  skipPermit2Batch: true,
1679
1037
  approvalPath: usePermit2Triple ? "permit2_triple" : "dispatcher",
1680
1038
  approveAmount: {
@@ -1688,9 +1046,9 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
1688
1046
  requestId: args.createSwapResponse.requestId,
1689
1047
  gasFee: args.createSwapResponse.gasFee,
1690
1048
  gasBuildSwap: {
1691
- useCustomGas,
1049
+ useCustomGas: args.useCustomGas,
1692
1050
  source: gasBuildSource,
1693
- baseGasUnits: baseGasUnits1.toString(),
1051
+ baseGasUnits: swapBaseGasUnits.toString(),
1694
1052
  ...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
1695
1053
  },
1696
1054
  swap: {
@@ -1732,92 +1090,98 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
1732
1090
  note: "Dispatcher pulls via ERC20.transferFrom(user, universalRouter, amount); allowance must be on swap.to (see cast trace TRANSFER_FROM_FAILED when only the hub is approved)."
1733
1091
  }
1734
1092
  }
1735
- };
1736
- const batchMeta = [
1737
- {
1738
- destinationAddress: tokenIn,
1739
- signatureText: JSON.stringify({
1740
- kind: "UniswapV4",
1741
- name: "ERC20.approve",
1742
- to: usePermit2Triple ? "allowance hub" : "dispatcher(swap.to)",
1743
- function: "approve(address spender, uint256 amount)",
1744
- spender: erc20ApproveSpender,
1745
- amountWei: approveAmountWei.toString()
1746
- }),
1747
- evm: {
1748
- type: usePermit2Triple ? "uniswap_v4_skip_permit2_approve" : "uniswap_v4_skip_permit2_dispatcher_approve",
1749
- version: 1,
1750
- chainId: String(args.chainId),
1751
- ...usePermit2Triple ? { permit2: PERMIT2_ADDRESS } : { dispatcher: toRouter }
1093
+ });
1094
+ return buildEvmMultisignBatch({
1095
+ context: {
1096
+ chainCategory: "evm",
1097
+ keyGen: args.keyGen,
1098
+ purposeText: args.purposeText,
1099
+ chainId: args.chainId,
1100
+ rpcUrl: args.rpcUrl,
1101
+ executorAddress: args.executorAddress,
1102
+ chainDetail: args.chainDetail,
1103
+ useCustomGas: args.useCustomGas,
1104
+ customGasChainDetails: args.customGasChainDetails
1105
+ },
1106
+ steps,
1107
+ purposeSuffix,
1108
+ firstMsgRawNo0x: approveMsgRawNo0x,
1109
+ destinationAddress: tokenIn,
1110
+ payableValueWei: valueWei > 0n ? valueWei : void 0,
1111
+ estimateGasForStep: async ({ step, index, publicClient, executor }) => {
1112
+ if (index !== swapStepIndex) {
1113
+ return publicClient.estimateGas({
1114
+ to: step.to,
1115
+ data: step.data,
1116
+ value: step.value,
1117
+ account: executor
1118
+ });
1752
1119
  }
1753
- }
1754
- ];
1755
- if (usePermit2Triple) {
1756
- batchMeta.push({
1757
- destinationAddress: PERMIT2_ADDRESS,
1758
- signatureText: JSON.stringify({
1759
- kind: "UniswapV4",
1760
- name: "AllowanceHub.approve",
1761
- function: "approve(address token, address spender, uint160 amount, uint48 expiration)",
1762
- token: tokenIn,
1763
- spender: permit2Spender,
1764
- amountWei: approveAmountWei.toString(),
1765
- expiration: expiration48.toString()
1766
- }),
1767
- evm: {
1768
- type: "uniswap_v4_skip_permit2_permit2_approve",
1769
- version: 1,
1770
- chainId: String(args.chainId),
1771
- permit2: PERMIT2_ADDRESS,
1772
- permit2Spender
1120
+ const r = await estimateUniswapRouterSwapGas({
1121
+ publicClient,
1122
+ executor,
1123
+ to: toRouter,
1124
+ data: dataHex,
1125
+ value: valueWei,
1126
+ swapRecord,
1127
+ useCustomGas: args.useCustomGas,
1128
+ chainDetail: args.chainDetail
1129
+ });
1130
+ gasBuildSource = r.source;
1131
+ estimateGasError = r.estimateGasError;
1132
+ swapBaseGasUnits = r.baseGasUnits;
1133
+ return r.baseGasUnits;
1134
+ },
1135
+ buildBatchMeta: ({ index }) => {
1136
+ if (index === 0) {
1137
+ return {
1138
+ signatureText: JSON.stringify({
1139
+ kind: "UniswapV4",
1140
+ name: "ERC20.approve",
1141
+ to: usePermit2Triple ? "allowance hub" : "dispatcher(swap.to)",
1142
+ function: "approve(address spender, uint256 amount)",
1143
+ spender: erc20ApproveSpender,
1144
+ amountWei: approveAmountWei.toString()
1145
+ }),
1146
+ evm: {
1147
+ type: usePermit2Triple ? "uniswap_v4_skip_permit2_approve" : "uniswap_v4_skip_permit2_dispatcher_approve",
1148
+ version: 1,
1149
+ chainId: String(args.chainId),
1150
+ ...usePermit2Triple ? { permit2: PERMIT2_ADDRESS } : { dispatcher: toRouter }
1151
+ }
1152
+ };
1773
1153
  }
1774
- });
1775
- }
1776
- batchMeta.push({
1777
- destinationAddress: toRouter,
1778
- signatureText: JSON.stringify({
1779
- kind: "UniswapV4",
1780
- name: "UniversalRouter.execute",
1781
- note: `Calldata from Trade API POST /swap; signed tx hash in messageHashes[${swapMsgIndex}].`
1782
- }),
1783
- evm: { type: "uniswap_v4_swap_tx", version: 1, chainId: String(args.chainId) },
1784
- uniswapV4: audit
1785
- });
1786
- const extraPayload = { batchMeta };
1787
- if (useCustomGas) {
1788
- const snap = args.customGasChainDetails;
1789
- if (snap && typeof snap === "object" && !Array.isArray(snap) && Object.keys(snap).length > 0) {
1790
- extraPayload.customGasChainDetails = snap;
1154
+ if (usePermit2Triple && index === 1) {
1155
+ return {
1156
+ signatureText: JSON.stringify({
1157
+ kind: "UniswapV4",
1158
+ name: "AllowanceHub.approve",
1159
+ function: "approve(address token, address spender, uint160 amount, uint48 expiration)",
1160
+ token: tokenIn,
1161
+ spender: permit2Spender,
1162
+ amountWei: approveAmountWei.toString(),
1163
+ expiration: expiration48.toString()
1164
+ }),
1165
+ evm: {
1166
+ type: "uniswap_v4_skip_permit2_permit2_approve",
1167
+ version: 1,
1168
+ chainId: String(args.chainId),
1169
+ permit2: PERMIT2_ADDRESS,
1170
+ permit2Spender
1171
+ }
1172
+ };
1173
+ }
1174
+ return {
1175
+ signatureText: JSON.stringify({
1176
+ kind: "UniswapV4",
1177
+ name: "UniversalRouter.execute",
1178
+ note: `Calldata from Trade API POST /swap; signed tx hash in messageHashes[${swapMsgIndex}].`
1179
+ }),
1180
+ evm: { type: "uniswap_v4_swap_tx", version: 1, chainId: String(args.chainId) },
1181
+ uniswapV4: buildSwapAudit()
1182
+ };
1791
1183
  }
1792
- }
1793
- const extraJSON = JSON.stringify(extraPayload);
1794
- const firstSigText = batchMeta[0].signatureText;
1795
- const bodyForSign = {
1796
- keyList,
1797
- pubKey: ph,
1798
- msgHash: messageHashes[0],
1799
- msgRaw: approveMsgRawNo0x,
1800
- messageHashes,
1801
- messageRawBatch,
1802
- destinationChainID: String(args.chainId),
1803
- destinationAddress: tokenIn,
1804
- extraJSON,
1805
- signatureText: firstSigText,
1806
- purpose: (() => {
1807
- const t = args.purposeText.trim();
1808
- const batchDesc = usePermit2Triple ? "Uniswap V4: 3-tx batch (classic allowance) \u2014 (1) ERC-20 approve allowance hub, (2) hub approve(Universal Router), (3) swap (Trade /swap)." : "Uniswap V4: 2-tx batch (classic allowance, dispatcher) \u2014 (1) ERC-20 approve swap.to (dispatcher pulls tokens), (2) swap (Trade /swap).";
1809
- return (t ? `${t}
1810
-
1811
- ` : "") + batchDesc;
1812
- })(),
1813
- ...firstTxFeePayload,
1814
- proposalTxParams: proposalTxParamsBatch
1815
- };
1816
- if (valueWei > 0n) {
1817
- bodyForSign.value = valueWei.toString();
1818
- }
1819
- if (clientId) bodyForSign.clientId = clientId;
1820
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1184
+ });
1821
1185
  }
1822
1186
 
1823
1187
  // src/protocols/evm/uniswap-v4/swap.ts
@@ -2246,986 +1610,10 @@ var curveDao = {
2246
1610
  loadSession: loadFullCurveSessionForRpc
2247
1611
  };
2248
1612
 
2249
- // src/agent/commonParamDocs.ts
2250
- var EVM_COMMON_PARAM_DOCS = {
2251
- keyGen: {
2252
- type: "object",
2253
- required: true,
2254
- description: "MPC key slice: { pubkeyhex: string (required), keylist: string[], ClientKeys?: Record<string,string> }. Used for pubKey/keyList on POST /multiSignRequest."
2255
- },
2256
- purposeText: {
2257
- type: "string",
2258
- required: true,
2259
- description: "Human-readable purpose for the sign request. Stored in bodyForSign.purpose (may be appended with an automatic batch suffix)."
2260
- },
2261
- useCustomGas: {
2262
- type: "boolean",
2263
- required: true,
2264
- description: "When true, apply chain gas settings from chainDetail / customGasChainDetails instead of raw RPC estimates only."
2265
- },
2266
- chainId: {
2267
- type: "number",
2268
- required: true,
2269
- description: "EVM chain id (decimal). Becomes destinationChainID on the sign request."
2270
- },
2271
- rpcUrl: {
2272
- type: "string",
2273
- required: true,
2274
- description: "HTTPS JSON-RPC URL for gas estimation, nonce, and allowance reads."
2275
- },
2276
- executorAddress: {
2277
- type: "address",
2278
- required: true,
2279
- description: "MPC wallet address (from keyGen ethereumaddress) \u2014 tx sender for estimates and approvals."
2280
- },
2281
- chainDetail: {
2282
- type: "object",
2283
- required: true,
2284
- description: "Optional gas config: { legacy?, gasLimit?, gasMultiplier?, gasPrice?, baseFee?, priorityFee?, baseFeeMultiplier? }."
2285
- },
2286
- customGasChainDetails: {
2287
- type: "object",
2288
- required: false,
2289
- description: "Snapshot written to extraJSON.customGasChainDetails when useCustomGas is true."
2290
- }
2291
- };
2292
- var MULTISIGN_OUTPUT_DOC = {
2293
- description: "Unsigned mpc-auth multiSignRequest payload. The caller must sign messageToSign (MetaMask personal_sign or Ed25519) and POST { ...bodyForSign, clientSig, signedMessage: messageToSign } to /multiSignRequest.",
2294
- fields: {
2295
- bodyForSign: {
2296
- type: "object",
2297
- description: "POST body fields without clientSig: keyList, pubKey, msgHash, msgRaw, destinationChainID, purpose, extraJSON, proposalTxParams (batch), messageHashes/messageRawBatch when N>1 txs."
2298
- },
2299
- messageToSign: {
2300
- type: "string",
2301
- description: "JSON.stringify(bodyForSign) \u2014 exact string to sign before adding clientSig."
2302
- }
2303
- }
2304
- };
2305
- var MANAGEMENT_SIG_DOC = {
2306
- description: "Management POST bodies embed NodeMgtKeySig: { nonce, clientSig, nodeKey }. Sign JSON with clientSig cleared; POST with clientSig set to the Ed25519 128-hex or EIP-191 signature. Legacy Nonce/Sig/sig field names are not accepted.",
2307
- fields: {
2308
- nonce: {
2309
- type: "number",
2310
- description: "From GET /getPublicMgtKeyNonce (Ed25519) or GET /getNodeMgtKeyNonce (Ethereum NodeMgtKey)."
2311
- },
2312
- clientSig: {
2313
- type: "string",
2314
- description: "Management signature; empty string in the message to sign."
2315
- },
2316
- nodeKey: {
2317
- type: "string",
2318
- description: "Required. 128-hex MPC node id from GET /getNodeKey (no 0x prefix)."
2319
- }
2320
- },
2321
- helpers: {
2322
- managementSigFields: "Base envelope with clientSig cleared.",
2323
- buildManagementPostBody: "Spread managementSigFields then endpoint fields.",
2324
- messageToSignManagementBody: "Canonical JSON string to sign.",
2325
- withManagementClientSig: "Attach signature to POST body.",
2326
- fetchNodeKey: "GET /getNodeKey via nodeFetchWithReadAuth.",
2327
- fetchManagementNonce: "GET nonce for Ed25519 or Ethereum management key."
2328
- }
2329
- };
2330
- function zodSchemaToMcpJsonSchema(schema) {
2331
- const raw = zodToJsonSchema(schema, {
2332
- target: "openApi3",
2333
- $refStrategy: "none"
2334
- });
2335
- if (raw.type === "object" || raw.type === "array" || raw.type === "string") {
2336
- const { $schema: _s, ...rest } = raw;
2337
- return rest;
2338
- }
2339
- const defs = raw.definitions;
2340
- if (defs) {
2341
- const first = Object.values(defs)[0];
2342
- if (first?.type) {
2343
- const { $schema: _s, ...rest } = first;
2344
- return rest;
2345
- }
2346
- }
2347
- return raw;
2348
- }
2349
- var evmAddressSchema = z.string().min(1).describe("EVM address (0x-prefixed, 40 hex nibbles)");
2350
- var keyGenSchema = z.object({
2351
- pubkeyhex: z.string().min(1).describe("MPC secp256k1 public key hex (required for multiSignRequest pubKey)"),
2352
- keylist: z.array(z.string()).optional().describe("Key list on the sign request"),
2353
- ClientKeys: z.record(z.string()).optional().describe("Optional client key map from keyGen")
2354
- }).describe(
2355
- "MPC key slice: { pubkeyhex, keylist?, ClientKeys? }. Used for pubKey/keyList on POST /multiSignRequest."
2356
- );
2357
- var chainDetailSchema = z.object({
2358
- legacy: z.boolean().optional(),
2359
- gasLimit: z.number().optional(),
2360
- gasMultiplier: z.number().optional(),
2361
- gasPrice: z.number().optional(),
2362
- baseFee: z.number().optional(),
2363
- priorityFee: z.number().optional(),
2364
- baseFeeMultiplier: z.number().optional()
2365
- }).passthrough().describe(
2366
- "Optional gas config: { legacy?, gasLimit?, gasMultiplier?, gasPrice?, baseFee?, priorityFee?, baseFeeMultiplier? }."
2367
- );
2368
- var evmMultisignCommonInputSchema = z.object({
2369
- keyGen: keyGenSchema,
2370
- purposeText: z.string().min(1).describe(
2371
- "Human-readable purpose for the sign request. Stored in bodyForSign.purpose (may be appended with an automatic batch suffix)."
2372
- ),
2373
- useCustomGas: z.boolean().describe(
2374
- "When true, apply chain gas settings from chainDetail / customGasChainDetails instead of raw RPC estimates only."
2375
- ),
2376
- chainId: z.number().int().positive().describe("EVM chain id (decimal). Becomes destinationChainID on the sign request."),
2377
- rpcUrl: z.string().min(1).describe("HTTPS JSON-RPC URL for gas estimation, nonce, and allowance reads."),
2378
- executorAddress: evmAddressSchema.describe(
2379
- "MPC wallet address (from keyGen ethereumaddress) \u2014 tx sender for estimates and approvals."
2380
- ),
2381
- chainDetail: chainDetailSchema,
2382
- customGasChainDetails: z.record(z.unknown()).optional().describe("Snapshot written to extraJSON.customGasChainDetails when useCustomGas is true.")
2383
- });
2384
- var multisignOutputSchema = z.object({
2385
- bodyForSign: z.record(z.unknown()).describe(
2386
- "POST body fields without clientSig: keyList, pubKey, msgHash, msgRaw, destinationChainID, purpose, extraJSON, proposalTxParams (batch), messageHashes/messageRawBatch when N>1 txs."
2387
- ),
2388
- messageToSign: z.string().describe("JSON.stringify(bodyForSign) \u2014 exact string to sign before adding clientSig.")
2389
- }).describe(
2390
- "Unsigned mpc-auth multiSignRequest payload. Sign messageToSign and POST { ...bodyForSign, clientSig, signedMessage } to /multiSignRequest."
2391
- );
2392
- var jsonObjectSchema = z.record(z.unknown());
2393
- var uniswapQuoteTradeTypeSchema = z.enum(["EXACT_INPUT", "EXACT_OUTPUT"]);
2394
- var mcpUniswapV4QuoteInputSchema = z.object({
2395
- type: uniswapQuoteTradeTypeSchema.describe("EXACT_INPUT or EXACT_OUTPUT"),
2396
- amount: z.string().min(1).describe("Amount in token-in base units (wei string for ERC-20)"),
2397
- tokenIn: z.string().min(1).describe("Input token; 0x0 for native ETH"),
2398
- tokenOut: z.string().min(1).describe("Output token address"),
2399
- chainId: z.union([z.number().int().positive(), z.string().min(1)]).describe("tokenInChainId / same-chain default"),
2400
- uniswapApiKey: z.string().min(1).describe("Uniswap Trade API x-api-key"),
2401
- swapper: evmAddressSchema.optional().describe("MPC executor; omit if keyGen + managementNodeUrl provided"),
2402
- slippage: z.union([z.number(), z.string()]).optional().describe("Slippage percent; omit for API auto slippage"),
2403
- keyGen: z.string().optional().describe("KeyGen id \u2014 resolves swapper via GET /getKeyGenResultById when swapper omitted"),
2404
- managementNodeUrl: z.string().min(1).optional().describe("MPC node base URL; required with keyGen when swapper is omitted"),
2405
- tokenInChainId: z.union([z.number(), z.string()]).optional(),
2406
- tokenOutChainId: z.union([z.number(), z.string()]).optional(),
2407
- permit2Disabled: z.boolean().optional(),
2408
- baseUrl: z.string().optional(),
2409
- universalRouterVersion: z.string().optional()
2410
- });
2411
- var mcpUniswapV4QuoteOutputSchema = jsonObjectSchema.describe(
2412
- "Full Uniswap POST /quote JSON (includes nested quote object with input/output amounts)."
2413
- );
2414
- var mcpUniswapV4CreateSwapInputSchema = z.object({
2415
- uniswapApiKey: z.string().min(1).describe("Uniswap Trade API key"),
2416
- fullQuoteFromPermit: jsonObjectSchema.describe("Full quote JSON from ctm_uniswap_v4_quote"),
2417
- swapTransactionDeadlineUnix: z.number().int().positive().optional().describe("On-chain deadline unix seconds; default ~30 min from now"),
2418
- useServerProxy: z.boolean().optional().describe("Set false in Node/agents; true only in browser via Next API route"),
2419
- baseUrl: z.string().optional(),
2420
- universalRouterVersion: z.string().optional()
2421
- });
2422
- var mcpUniswapV4CreateSwapOutputSchema = z.object({
2423
- swap: jsonObjectSchema.describe("Universal Router tx: { to, data, value, gasLimit? }"),
2424
- requestId: z.string().optional(),
2425
- gasFee: z.string().optional()
2426
- }).passthrough().describe("{ swap: TransactionRequest, requestId?, gasFee? }");
2427
- var swapTxRequestSchema = jsonObjectSchema.describe("swap field from create_swap response (to, data, value)");
2428
- var mcpUniswapV4BuildSwapMultisignInputSchema = evmMultisignCommonInputSchema.extend({
2429
- tokenIn: evmAddressSchema.describe("Token in; 0x0 for native ETH"),
2430
- swap: swapTxRequestSchema,
2431
- createSwapResponse: z.object({
2432
- swap: swapTxRequestSchema,
2433
- requestId: z.string().optional(),
2434
- gasFee: z.string().optional()
2435
- }).passthrough().describe("Full create_swap response"),
2436
- fullQuoteSnapshot: jsonObjectSchema.describe("Quote JSON used for the swap"),
2437
- swapDeadlineUnix: z.number().describe("Same deadline passed to create_swap"),
2438
- slippagePercent: z.number().optional().describe("Extra approve headroom for EXACT_OUTPUT")
2439
- });
2440
- var mcpCurveDaoBuildSwapMultisignInputSchema = evmMultisignCommonInputSchema.extend({
2441
- tokenIn: evmAddressSchema.describe("ERC-20 sold (native in uses WETH path in UI)"),
2442
- tokenOut: z.string().min(1).describe("Output token or 0xeeee\u2026 native placeholder"),
2443
- amountHuman: z.string().min(1).describe("Human-readable amount of tokenIn"),
2444
- slippagePercent: z.number().gt(0).lt(100).describe("Slippage 0\u2013100 exclusive")
2445
- });
2446
- function mcpMultisignInput(fields) {
2447
- return evmMultisignCommonInputSchema.extend(fields);
2448
- }
2449
- var mcpLidoSubmitInputSchema = mcpMultisignInput({
2450
- valueWei: z.string().min(1).describe("ETH to stake (wei decimal string)"),
2451
- referral: evmAddressSchema.optional()
2452
- });
2453
- var mcpLidoRequestWithdrawalsInputSchema = mcpMultisignInput({
2454
- stEthAmountsWei: z.array(z.string()).min(1).describe("stETH amounts per withdrawal request (wei strings)")
2455
- });
2456
- var mcpLidoClaimWithdrawalInputSchema = mcpMultisignInput({
2457
- requestId: z.union([z.string(), z.number()]).describe("Withdrawal queue request id")
2458
- });
2459
- var mcpLidoWrapStEthInputSchema = mcpMultisignInput({
2460
- stEthAmountWei: z.string().min(1)
2461
- });
2462
- var mcpLidoUnwrapWstEthInputSchema = mcpMultisignInput({
2463
- wstEthAmountWei: z.string().min(1)
2464
- });
2465
- var mcpEthenaStakeInputSchema = mcpMultisignInput({
2466
- usdeAmountHuman: z.string().min(1),
2467
- susdeVault: evmAddressSchema.optional()
2468
- });
2469
- var mcpEthenaRedeemInputSchema = mcpMultisignInput({
2470
- susdeSharesHuman: z.string().min(1),
2471
- susdeVault: evmAddressSchema.optional()
2472
- });
2473
- var mcpEthenaCooldownInputSchema = mcpMultisignInput({
2474
- susdeSharesHuman: z.string().min(1),
2475
- susdeVault: evmAddressSchema.optional()
2476
- });
2477
- var mcpEthenaClaimInputSchema = mcpMultisignInput({
2478
- susdeVault: evmAddressSchema.optional()
2479
- });
2480
- var mcpMapleDepositInputSchema = mcpMultisignInput({
2481
- syrupRouter: evmAddressSchema,
2482
- pool: evmAddressSchema,
2483
- asset: evmAddressSchema,
2484
- amountHuman: z.string().min(1),
2485
- authorizeSig: jsonObjectSchema.optional()
2486
- });
2487
- var mcpMapleRequestRedeemInputSchema = mcpMultisignInput({
2488
- pool: evmAddressSchema,
2489
- sharesHuman: z.string().min(1),
2490
- receiver: evmAddressSchema
2491
- });
2492
- var mcpSkyLockstakeStakeInputSchema = mcpMultisignInput({
2493
- skyAmountHuman: z.string().min(1),
2494
- usdsDrawHuman: z.string().optional(),
2495
- farmRef: z.string().optional()
2496
- });
2497
- var mcpSkyLockstakeDrawInputSchema = mcpMultisignInput({
2498
- usdsAmountHuman: z.string().min(1),
2499
- urnIndex: z.number().int().nonnegative()
2500
- });
2501
- var mcpSkyLockstakeWipeInputSchema = mcpMultisignInput({
2502
- usdsAmountHuman: z.string().min(1),
2503
- urnIndex: z.number().int().nonnegative()
2504
- });
2505
- var mcpSkyLockstakeCloseInputSchema = mcpMultisignInput({
2506
- urnIndex: z.number().int().nonnegative()
2507
- });
2508
- var mcpSkyLockstakeGetRewardInputSchema = mcpMultisignInput({
2509
- urnIndex: z.number().int().nonnegative()
2510
- });
2511
- var mcpSkySusdsDepositInputSchema = mcpMultisignInput({
2512
- usdsAmountHuman: z.string().min(1)
2513
- });
2514
- var mcpSkySusdsRedeemInputSchema = mcpMultisignInput({
2515
- sharesHuman: z.string().min(1)
2516
- });
2517
- var mcpAaveV4DepositInputSchema = mcpMultisignInput({
2518
- spoke: evmAddressSchema,
2519
- underlying: evmAddressSchema,
2520
- amountHuman: z.string().min(1),
2521
- marketId: z.string().min(1)
2522
- });
2523
- var mcpAaveV4WithdrawInputSchema = mcpMultisignInput({
2524
- spoke: evmAddressSchema,
2525
- underlying: evmAddressSchema,
2526
- amountHuman: z.string().min(1),
2527
- marketId: z.string().min(1)
2528
- });
2529
- var mcpAaveV4BorrowInputSchema = mcpMultisignInput({
2530
- spoke: evmAddressSchema,
2531
- underlying: evmAddressSchema,
2532
- amountHuman: z.string().min(1),
2533
- marketId: z.string().min(1)
2534
- });
2535
- var mcpAaveV4RepayInputSchema = mcpMultisignInput({
2536
- spoke: evmAddressSchema,
2537
- underlying: evmAddressSchema,
2538
- amountHuman: z.string().min(1),
2539
- marketId: z.string().min(1)
2540
- });
2541
- var mcpEulerV2IsolatedLendInputSchema = mcpMultisignInput({
2542
- vault: evmAddressSchema,
2543
- assetAmountHuman: z.string().min(1)
2544
- });
2545
- var mcpEulerV2IsolatedBorrowInputSchema = mcpMultisignInput({
2546
- vault: evmAddressSchema,
2547
- collateralAsset: evmAddressSchema,
2548
- borrowAsset: evmAddressSchema,
2549
- collateralAmountHuman: z.string().min(1),
2550
- loopBorrowWeis: z.array(z.string()).min(1)
2551
- });
2552
- var mcpEulerV2VaultWithdrawInputSchema = mcpMultisignInput({
2553
- vault: evmAddressSchema,
2554
- sharesHuman: z.string().min(1)
2555
- });
2556
- var mcpEulerV2BorrowRepayInputSchema = mcpMultisignInput({
2557
- vault: evmAddressSchema,
2558
- amountHuman: z.string().min(1)
2559
- });
2560
- var mcpEulerV2CollateralDepositInputSchema = mcpMultisignInput({
2561
- vault: evmAddressSchema,
2562
- collateralAsset: evmAddressSchema,
2563
- amountHuman: z.string().min(1)
2564
- });
2565
- var mcpEulerV2CollateralWithdrawInputSchema = mcpMultisignInput({
2566
- vault: evmAddressSchema,
2567
- collateralAsset: evmAddressSchema,
2568
- amountHuman: z.string().min(1)
2569
- });
2570
-
2571
- // src/agent/mcpProtocolTools.ts
2572
- function defineProtocolMcpTool(def) {
2573
- return {
2574
- ...def,
2575
- outputZod: multisignOutputSchema,
2576
- inputSchema: zodSchemaToMcpJsonSchema(def.inputZod),
2577
- outputSchema: zodSchemaToMcpJsonSchema(multisignOutputSchema),
2578
- parseInput: (data) => def.inputZod.parse(data),
2579
- parseOutput: (data) => multisignOutputSchema.parse(data)
2580
- };
2581
- }
2582
- var MCP_PROTOCOL_TOOL_DEFINITIONS = [
2583
- defineProtocolMcpTool({
2584
- name: "ctm_lido_build_submit_multisign",
2585
- actionId: "lido.submit",
2586
- protocolId: "lido",
2587
- chainCategory: "evm",
2588
- description: "Build mpc-auth multiSignRequest for Lido ETH stake (submit).",
2589
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2590
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2591
- handler: { importPath: "protocols/evm/lido", exportName: "buildEvmMultisignBodyLidoSubmit" },
2592
- inputZod: mcpLidoSubmitInputSchema
2593
- }),
2594
- defineProtocolMcpTool({
2595
- name: "ctm_lido_build_request_withdrawals_multisign",
2596
- actionId: "lido.request-withdrawals",
2597
- protocolId: "lido",
2598
- chainCategory: "evm",
2599
- description: "Build batch for Lido withdrawal queue (approve + requestWithdrawals).",
2600
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2601
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2602
- handler: { importPath: "protocols/evm/lido", exportName: "buildEvmMultisignBodyLidoRequestWithdrawals" },
2603
- inputZod: mcpLidoRequestWithdrawalsInputSchema
2604
- }),
2605
- defineProtocolMcpTool({
2606
- name: "ctm_lido_build_claim_withdrawal_multisign",
2607
- actionId: "lido.claim-withdrawal",
2608
- protocolId: "lido",
2609
- chainCategory: "evm",
2610
- description: "Build tx for Lido claimWithdrawal.",
2611
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2612
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2613
- handler: { importPath: "protocols/evm/lido", exportName: "buildEvmMultisignBodyLidoClaimWithdrawal" },
2614
- inputZod: mcpLidoClaimWithdrawalInputSchema
2615
- }),
2616
- defineProtocolMcpTool({
2617
- name: "ctm_lido_build_wrap_steth_multisign",
2618
- actionId: "lido.wrap-steth",
2619
- protocolId: "lido",
2620
- chainCategory: "evm",
2621
- description: "Build batch for wstETH wrap.",
2622
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2623
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2624
- handler: { importPath: "protocols/evm/lido", exportName: "buildEvmMultisignBodyLidoWrapStEth" },
2625
- inputZod: mcpLidoWrapStEthInputSchema
2626
- }),
2627
- defineProtocolMcpTool({
2628
- name: "ctm_lido_build_unwrap_wsteth_multisign",
2629
- actionId: "lido.unwrap-wsteth",
2630
- protocolId: "lido",
2631
- chainCategory: "evm",
2632
- description: "Build tx for wstETH unwrap.",
2633
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2634
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2635
- handler: { importPath: "protocols/evm/lido", exportName: "buildEvmMultisignBodyLidoUnwrapWstEth" },
2636
- inputZod: mcpLidoUnwrapWstEthInputSchema
2637
- }),
2638
- defineProtocolMcpTool({
2639
- name: "ctm_ethena_build_stake_multisign",
2640
- actionId: "ethena.stake-usde",
2641
- protocolId: "ethena",
2642
- chainCategory: "evm",
2643
- description: "Build batch: USDe approve + sUSDe deposit.",
2644
- prerequisites: ["keyGen", "executorAddress", "Ethereum mainnet RPC"],
2645
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2646
- handler: { importPath: "protocols/evm/ethena", exportName: "buildEvmMultisignBodyEthenaUsdeStakeToSusde" },
2647
- inputZod: mcpEthenaStakeInputSchema
2648
- }),
2649
- defineProtocolMcpTool({
2650
- name: "ctm_ethena_build_redeem_multisign",
2651
- actionId: "ethena.redeem-susde",
2652
- protocolId: "ethena",
2653
- chainCategory: "evm",
2654
- description: "Build sUSDe redeem when cooldown is off.",
2655
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2656
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2657
- handler: { importPath: "protocols/evm/ethena", exportName: "buildEvmMultisignBodyEthenaSusdeRedeemToUsde" },
2658
- inputZod: mcpEthenaRedeemInputSchema
2659
- }),
2660
- defineProtocolMcpTool({
2661
- name: "ctm_ethena_build_cooldown_multisign",
2662
- actionId: "ethena.cooldown-shares",
2663
- protocolId: "ethena",
2664
- chainCategory: "evm",
2665
- description: "Build sUSDe cooldownShares batch step.",
2666
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2667
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2668
- handler: { importPath: "protocols/evm/ethena", exportName: "buildEvmMultisignBodyEthenaSusdeCooldownShares" },
2669
- inputZod: mcpEthenaCooldownInputSchema
2670
- }),
2671
- defineProtocolMcpTool({
2672
- name: "ctm_ethena_build_claim_multisign",
2673
- actionId: "ethena.claim-unstake",
2674
- protocolId: "ethena",
2675
- chainCategory: "evm",
2676
- description: "Build unstake claim after cooldown.",
2677
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2678
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2679
- handler: { importPath: "protocols/evm/ethena", exportName: "buildEvmMultisignBodyEthenaUnstakeClaim" },
2680
- inputZod: mcpEthenaClaimInputSchema
2681
- }),
2682
- defineProtocolMcpTool({
2683
- name: "ctm_maple_build_deposit_multisign",
2684
- actionId: "maple-syrup.deposit",
2685
- protocolId: "maple-syrup",
2686
- chainCategory: "evm",
2687
- description: "Build Maple Syrup router deposit batch.",
2688
- prerequisites: ["keyGen", "executorAddress", "router + pool addresses"],
2689
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2690
- handler: { importPath: "protocols/evm/maple", exportName: "buildEvmMultisignBodyMapleSyrupDeposit" },
2691
- inputZod: mcpMapleDepositInputSchema
2692
- }),
2693
- defineProtocolMcpTool({
2694
- name: "ctm_maple_build_request_redeem_multisign",
2695
- actionId: "maple-syrup.request-redeem",
2696
- protocolId: "maple-syrup",
2697
- chainCategory: "evm",
2698
- description: "Build Maple PoolV2 requestRedeem batch.",
2699
- prerequisites: ["keyGen", "executorAddress", "pool address"],
2700
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2701
- handler: { importPath: "protocols/evm/maple", exportName: "buildEvmMultisignBodyMaplePoolRequestRedeem" },
2702
- inputZod: mcpMapleRequestRedeemInputSchema
2703
- }),
2704
- defineProtocolMcpTool({
2705
- name: "ctm_sky_build_lockstake_stake_multisign",
2706
- actionId: "sky.lockstake-stake",
2707
- protocolId: "sky",
2708
- chainCategory: "evm",
2709
- description: "Build Sky Lockstake open/stake batch.",
2710
- prerequisites: ["keyGen", "executorAddress", "Ethereum mainnet RPC"],
2711
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2712
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkyLockstakeStakePositionBatch" },
2713
- inputZod: mcpSkyLockstakeStakeInputSchema
2714
- }),
2715
- defineProtocolMcpTool({
2716
- name: "ctm_sky_build_lockstake_draw_multisign",
2717
- actionId: "sky.lockstake-draw",
2718
- protocolId: "sky",
2719
- chainCategory: "evm",
2720
- description: "Build Lockstake draw (borrow USDS).",
2721
- prerequisites: ["keyGen", "executorAddress", "open urn"],
2722
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2723
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkyLockstakeDrawBatch" },
2724
- inputZod: mcpSkyLockstakeDrawInputSchema
2725
- }),
2726
- defineProtocolMcpTool({
2727
- name: "ctm_sky_build_lockstake_wipe_multisign",
2728
- actionId: "sky.lockstake-wipe",
2729
- protocolId: "sky",
2730
- chainCategory: "evm",
2731
- description: "Build Lockstake repay/wipe batch.",
2732
- prerequisites: ["keyGen", "executorAddress", "urn index"],
2733
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2734
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkyLockstakeWipeBatch" },
2735
- inputZod: mcpSkyLockstakeWipeInputSchema
2736
- }),
2737
- defineProtocolMcpTool({
2738
- name: "ctm_sky_build_lockstake_close_multisign",
2739
- actionId: "sky.lockstake-close",
2740
- protocolId: "sky",
2741
- chainCategory: "evm",
2742
- description: "Build Lockstake close position batch.",
2743
- prerequisites: ["keyGen", "executorAddress", "urn index"],
2744
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2745
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkyLockstakeCloseBatch" },
2746
- inputZod: mcpSkyLockstakeCloseInputSchema
2747
- }),
2748
- defineProtocolMcpTool({
2749
- name: "ctm_sky_build_lockstake_get_reward_multisign",
2750
- actionId: "sky.lockstake-get-reward",
2751
- protocolId: "sky",
2752
- chainCategory: "evm",
2753
- description: "Build Lockstake getReward batch.",
2754
- prerequisites: ["keyGen", "executorAddress", "urn index"],
2755
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2756
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkyLockstakeGetRewardBatch" },
2757
- inputZod: mcpSkyLockstakeGetRewardInputSchema
2758
- }),
2759
- defineProtocolMcpTool({
2760
- name: "ctm_sky_build_susds_deposit_multisign",
2761
- actionId: "sky.susds-deposit",
2762
- protocolId: "sky",
2763
- chainCategory: "evm",
2764
- description: "Build USDS \u2192 sUSDS ERC-4626 deposit batch.",
2765
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2766
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2767
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkySusdsDepositFromUsdsBatch" },
2768
- inputZod: mcpSkySusdsDepositInputSchema
2769
- }),
2770
- defineProtocolMcpTool({
2771
- name: "ctm_sky_build_susds_redeem_multisign",
2772
- actionId: "sky.susds-redeem",
2773
- protocolId: "sky",
2774
- chainCategory: "evm",
2775
- description: "Build sUSDS redeem to USDS batch.",
2776
- prerequisites: ["keyGen", "executorAddress", "RPC URL"],
2777
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2778
- handler: { importPath: "protocols/evm/sky", exportName: "buildSkySusdsRedeemToUsdsBatch" },
2779
- inputZod: mcpSkySusdsRedeemInputSchema
2780
- }),
2781
- defineProtocolMcpTool({
2782
- name: "ctm_aave_v4_build_deposit_multisign",
2783
- actionId: "aave-v4.deposit",
2784
- protocolId: "aave-v4",
2785
- chainCategory: "evm",
2786
- description: "Build Aave v4 Spoke supply/deposit batch.",
2787
- prerequisites: ["keyGen", "executorAddress", "spoke + underlying"],
2788
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2789
- handler: { importPath: "protocols/evm/aave-v4", exportName: "buildEvmMultisignBodyAaveV4DepositBatch" },
2790
- inputZod: mcpAaveV4DepositInputSchema
2791
- }),
2792
- defineProtocolMcpTool({
2793
- name: "ctm_aave_v4_build_withdraw_multisign",
2794
- actionId: "aave-v4.withdraw",
2795
- protocolId: "aave-v4",
2796
- chainCategory: "evm",
2797
- description: "Build Aave v4 Spoke withdraw batch.",
2798
- prerequisites: ["keyGen", "executorAddress", "spoke + underlying"],
2799
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2800
- handler: { importPath: "protocols/evm/aave-v4", exportName: "buildEvmMultisignBodyAaveV4SpokeWithdraw" },
2801
- inputZod: mcpAaveV4WithdrawInputSchema
2802
- }),
2803
- defineProtocolMcpTool({
2804
- name: "ctm_aave_v4_build_borrow_multisign",
2805
- actionId: "aave-v4.borrow",
2806
- protocolId: "aave-v4",
2807
- chainCategory: "evm",
2808
- description: "Build Aave v4 Spoke borrow batch.",
2809
- prerequisites: ["keyGen", "executorAddress", "spoke + underlying"],
2810
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2811
- handler: { importPath: "protocols/evm/aave-v4", exportName: "buildEvmMultisignBodyAaveV4SpokeBorrow" },
2812
- inputZod: mcpAaveV4BorrowInputSchema
2813
- }),
2814
- defineProtocolMcpTool({
2815
- name: "ctm_aave_v4_build_repay_multisign",
2816
- actionId: "aave-v4.repay",
2817
- protocolId: "aave-v4",
2818
- chainCategory: "evm",
2819
- description: "Build Aave v4 Spoke repay batch.",
2820
- prerequisites: ["keyGen", "executorAddress", "spoke + underlying"],
2821
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2822
- handler: { importPath: "protocols/evm/aave-v4", exportName: "buildEvmMultisignBodyAaveV4SpokeRepay" },
2823
- inputZod: mcpAaveV4RepayInputSchema
2824
- }),
2825
- defineProtocolMcpTool({
2826
- name: "ctm_euler_v2_build_isolated_lend_multisign",
2827
- actionId: "euler-v2.isolated-lend",
2828
- protocolId: "euler-v2",
2829
- chainCategory: "evm",
2830
- description: "Build Euler v2 vault deposit/lend batch.",
2831
- prerequisites: ["keyGen", "executorAddress", "vault address"],
2832
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2833
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch" },
2834
- inputZod: mcpEulerV2IsolatedLendInputSchema
2835
- }),
2836
- defineProtocolMcpTool({
2837
- name: "ctm_euler_v2_build_isolated_borrow_multisign",
2838
- actionId: "euler-v2.isolated-borrow",
2839
- protocolId: "euler-v2",
2840
- chainCategory: "evm",
2841
- description: "Build Euler v2 isolated borrow loop batch.",
2842
- prerequisites: ["keyGen", "executorAddress", "vault + collateral"],
2843
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2844
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2IsolatedBorrowBatch" },
2845
- inputZod: mcpEulerV2IsolatedBorrowInputSchema
2846
- }),
2847
- defineProtocolMcpTool({
2848
- name: "ctm_euler_v2_build_vault_withdraw_multisign",
2849
- actionId: "euler-v2.vault-withdraw",
2850
- protocolId: "euler-v2",
2851
- chainCategory: "evm",
2852
- description: "Build Euler v2 vault withdraw/redeem batch.",
2853
- prerequisites: ["keyGen", "executorAddress", "vault address"],
2854
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2855
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2VaultWithdrawBatch" },
2856
- inputZod: mcpEulerV2VaultWithdrawInputSchema
2857
- }),
2858
- defineProtocolMcpTool({
2859
- name: "ctm_euler_v2_build_borrow_repay_multisign",
2860
- actionId: "euler-v2.borrow-repay",
2861
- protocolId: "euler-v2",
2862
- chainCategory: "evm",
2863
- description: "Build Euler v2 borrow repay batch.",
2864
- prerequisites: ["keyGen", "executorAddress", "vault address"],
2865
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2866
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2BorrowRepayBatch" },
2867
- inputZod: mcpEulerV2BorrowRepayInputSchema
2868
- }),
2869
- defineProtocolMcpTool({
2870
- name: "ctm_euler_v2_build_collateral_deposit_multisign",
2871
- actionId: "euler-v2.collateral-deposit",
2872
- protocolId: "euler-v2",
2873
- chainCategory: "evm",
2874
- description: "Build Euler v2 borrow collateral deposit batch.",
2875
- prerequisites: ["keyGen", "executorAddress", "vault + collateral asset"],
2876
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2877
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch" },
2878
- inputZod: mcpEulerV2CollateralDepositInputSchema
2879
- }),
2880
- defineProtocolMcpTool({
2881
- name: "ctm_euler_v2_build_collateral_withdraw_multisign",
2882
- actionId: "euler-v2.collateral-withdraw",
2883
- protocolId: "euler-v2",
2884
- chainCategory: "evm",
2885
- description: "Build Euler v2 borrow collateral withdraw batch.",
2886
- prerequisites: ["keyGen", "executorAddress", "vault + collateral asset"],
2887
- followUp: ["Sign messageToSign", "POST /multiSignRequest"],
2888
- handler: { importPath: "protocols/evm/euler-v2", exportName: "buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch" },
2889
- inputZod: mcpEulerV2CollateralWithdrawInputSchema
2890
- })
2891
- ];
2892
-
2893
- // src/agent/mcpTools.ts
2894
- function defineMcpTool(def) {
2895
- return {
2896
- ...def,
2897
- inputSchema: zodSchemaToMcpJsonSchema(def.inputZod),
2898
- outputSchema: zodSchemaToMcpJsonSchema(def.outputZod),
2899
- parseInput: (data) => def.inputZod.parse(data),
2900
- parseOutput: (data) => def.outputZod.parse(data)
2901
- };
2902
- }
2903
- var CORE_MCP_TOOL_DEFINITIONS = [
2904
- defineMcpTool({
2905
- name: "ctm_uniswap_v4_quote",
2906
- actionId: "uniswap-v4.quote",
2907
- protocolId: "uniswap-v4",
2908
- chainCategory: "evm",
2909
- description: "Fetch a Uniswap V4 Trade API quote (POST /v1/quote). Returns classic quote JSON including quote.input/output amounts and routing. Does NOT create a sign request \u2014 use ctm_uniswap_v4_create_swap and ctm_uniswap_v4_build_swap_multisign after quoting. Requires uniswapApiKey and swapper (MPC executor address) or keyGen + managementNodeUrl to resolve swapper.",
2910
- prerequisites: ["Chain must be supported by Uniswap V4 (Universal Router map)."],
2911
- followUp: ["ctm_uniswap_v4_create_swap", "ctm_uniswap_v4_build_swap_multisign"],
2912
- handler: { importPath: "protocols/evm/uniswap-v4", exportName: "uniswapTradeQuote" },
2913
- inputZod: mcpUniswapV4QuoteInputSchema,
2914
- outputZod: mcpUniswapV4QuoteOutputSchema
2915
- }),
2916
- defineMcpTool({
2917
- name: "ctm_uniswap_v4_create_swap",
2918
- actionId: "uniswap-v4.create-swap",
2919
- protocolId: "uniswap-v4",
2920
- chainCategory: "evm",
2921
- description: "Call Uniswap Trade API POST /v1/swap to build Universal Router calldata from a prior quote. Returns { swap: { to, data, value, gasLimit? }, requestId? }. Does NOT produce a multiSignRequest \u2014 call ctm_uniswap_v4_build_swap_multisign next.",
2922
- prerequisites: ["ctm_uniswap_v4_quote output (fullQuoteFromPermit)"],
2923
- followUp: ["ctm_uniswap_v4_build_swap_multisign"],
2924
- handler: { importPath: "protocols/evm/uniswap-v4", exportName: "uniswapCreateSwap" },
2925
- inputZod: mcpUniswapV4CreateSwapInputSchema,
2926
- outputZod: mcpUniswapV4CreateSwapOutputSchema
2927
- }),
2928
- defineMcpTool({
2929
- name: "ctm_uniswap_v4_build_swap_multisign",
2930
- actionId: "uniswap-v4.swap-exact-input",
2931
- protocolId: "uniswap-v4",
2932
- chainCategory: "evm",
2933
- description: "Build mpc-auth multiSignRequest body for a Uniswap V4 swap. May batch 1\u20133 EVM txs: ERC-20 approve(s) to Permit2/router path + Universal Router swap (or 1 tx for native-in). Estimates gas, serializes unsigned txs, sets proposalTxParams. Output must be signed and POSTed to /multiSignRequest by the caller.",
2934
- prerequisites: [
2935
- "ctm_uniswap_v4_create_swap output",
2936
- "keyGen with pubkeyhex",
2937
- "executorAddress matching MPC wallet",
2938
- "RPC URL and chainDetail from node chain config"
2939
- ],
2940
- followUp: ["Sign messageToSign", "POST /multiSignRequest with clientSig and signedMessage"],
2941
- handler: { importPath: "protocols/evm/uniswap-v4", exportName: "buildEvmMultisignBodyUniswapV4SkipPermit2Batch" },
2942
- inputZod: mcpUniswapV4BuildSwapMultisignInputSchema,
2943
- outputZod: multisignOutputSchema
2944
- }),
2945
- defineMcpTool({
2946
- name: "ctm_curve_dao_build_swap_multisign",
2947
- actionId: "curve-dao.swap",
2948
- protocolId: "curve-dao",
2949
- chainCategory: "evm",
2950
- description: "Build mpc-auth multiSignRequest for a Curve Router NG swap via @curvefi/api populateSwap. Optionally batches ERC-20 approve txs when allowance is insufficient, then exchange. Requires JSON-RPC and Curve-supported chain.",
2951
- prerequisites: ["keyGen", "executorAddress", "tokenIn/tokenOut/amountHuman/slippage", "RPC URL"],
2952
- followUp: ["Sign messageToSign", "POST /multiSignRequest with clientSig and signedMessage"],
2953
- handler: { importPath: "protocols/evm/curve-dao", exportName: "buildEvmMultisignBodyCurveDaoBatch" },
2954
- inputZod: mcpCurveDaoBuildSwapMultisignInputSchema,
2955
- outputZod: multisignOutputSchema
2956
- })
2957
- ];
2958
- var MCP_TOOL_DEFINITIONS = [
2959
- ...CORE_MCP_TOOL_DEFINITIONS,
2960
- ...MCP_PROTOCOL_TOOL_DEFINITIONS
2961
- ];
2962
- function buildToolSchemaMap(kind) {
2963
- const out = {};
2964
- for (const tool of MCP_TOOL_DEFINITIONS) {
2965
- out[tool.name] = kind === "input" ? tool.inputZod : tool.outputZod;
2966
- }
2967
- return out;
2968
- }
2969
- var MCP_TOOL_INPUT_SCHEMAS = buildToolSchemaMap("input");
2970
- var MCP_TOOL_OUTPUT_SCHEMAS = buildToolSchemaMap("output");
2971
- function getAgentCatalogForMcp() {
2972
- return {
2973
- tools: MCP_TOOL_DEFINITIONS,
2974
- protocols: getProtocolModules(),
2975
- commonParams: EVM_COMMON_PARAM_DOCS,
2976
- multisignOutput: MULTISIGN_OUTPUT_DOC,
2977
- managementSig: MANAGEMENT_SIG_DOC,
2978
- /** Zod schemas for MCP tool I/O — source of truth for continuum-mcp-server validation. */
2979
- inputSchemas: MCP_TOOL_INPUT_SCHEMAS,
2980
- outputSchemas: MCP_TOOL_OUTPUT_SCHEMAS,
2981
- workflow: {
2982
- evmSwapTypical: [
2983
- "1. Quote (protocol-specific API if needed)",
2984
- "2. Build protocol calldata (e.g. create_swap)",
2985
- "3. build_*_multisign \u2192 { bodyForSign, messageToSign }",
2986
- "4. Sign messageToSign (MetaMask or Ed25519)",
2987
- "5. POST /multiSignRequest with clientSig and signedMessage"
2988
- ],
2989
- managementPostTypical: [
2990
- "1. GET /getNodeKey \u2192 nodeKey (128 hex)",
2991
- "2. GET /getPublicMgtKeyNonce or /getNodeMgtKeyNonce \u2192 nonce",
2992
- "3. buildManagementPostBody(nonce, nodeKey, { \u2026endpoint fields })",
2993
- "4. messageToSignManagementBody(body) \u2192 sign \u2192 withManagementClientSig(body, sig)",
2994
- "5. POST management route with signed body"
2995
- ]
2996
- }
2997
- };
2998
- }
2999
- getAddress(
3000
- "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84"
3001
- );
3002
- getAddress(
3003
- "0x7f39C581F595B853cBbF37C12FfeeA971C5a5bEa"
3004
- );
3005
- getAddress("0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1");
3006
- var LIDO_ETHEREUM_MAINNET_CHAIN_ID = 1;
3007
-
3008
- // src/protocols/evm/lido/index.ts
3009
- var LIDO_PROTOCOL_ID = "lido";
3010
- var lidoProtocolModule = {
3011
- id: LIDO_PROTOCOL_ID,
3012
- chainCategory: "evm",
3013
- isChainSupported(ctx) {
3014
- if (ctx.chainCategory !== "evm") return false;
3015
- return Number(ctx.chainId) === LIDO_ETHEREUM_MAINNET_CHAIN_ID;
3016
- },
3017
- isTokenSupported(token) {
3018
- return token.category === "evm" && (token.kind === "native" || token.kind === "erc20");
3019
- },
3020
- actions: [
3021
- { id: "lido.submit", protocolId: LIDO_PROTOCOL_ID, chainCategory: "evm", description: "Stake ETH via Lido submit()", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { valueWei: { type: "string", required: true, description: "ETH to stake (wei string)" } } },
3022
- { id: "lido.request-withdrawals", protocolId: LIDO_PROTOCOL_ID, chainCategory: "evm", description: "Queue stETH withdrawal", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3023
- { id: "lido.claim-withdrawal", protocolId: LIDO_PROTOCOL_ID, chainCategory: "evm", description: "Claim finalized withdrawal", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3024
- { id: "lido.wrap-steth", protocolId: LIDO_PROTOCOL_ID, chainCategory: "evm", description: "Wrap stETH to wstETH", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3025
- { id: "lido.unwrap-wsteth", protocolId: LIDO_PROTOCOL_ID, chainCategory: "evm", description: "Unwrap wstETH to stETH", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3026
- ]
3027
- };
3028
- registerProtocolModule(lidoProtocolModule);
3029
- var USDE_ETHEREUM_MAINNET = "0x4c9edd5852cd905f086c759e8383e09bff1e68b3";
3030
- var USDE_MOST_L2S = "0x5d3a1Ff2b6BAb83b63cd9AD0787074081a52ef34";
3031
- var USDE_ZKSYNC_ERA = "0x39Fe7a0DACcE31Bd90418e3e659fb0b5f0B3Db0d";
3032
- var L2_SAME_ADDRESS_CHAIN_IDS = /* @__PURE__ */ new Set([
3033
- 42161,
3034
- // Arbitrum One
3035
- 10,
3036
- // Optimism
3037
- 8453,
3038
- // Base
3039
- 56,
3040
- // BNB Chain
3041
- 59144,
3042
- // Linea
3043
- 5e3,
3044
- // Mantle
3045
- 81457,
3046
- // Blast
3047
- 169,
3048
- // Manta Pacific
3049
- 534352,
3050
- // Scroll
3051
- 252,
3052
- // Fraxtal
3053
- 34443,
3054
- // Mode
3055
- 196,
3056
- // X Layer
3057
- 1088,
3058
- // Metis
3059
- 80084,
3060
- // Berachain
3061
- 2222,
3062
- // Kava
3063
- 2818,
3064
- // Morph
3065
- 1923,
3066
- // Swell
3067
- 48900
3068
- // Zircuit
3069
- ]);
3070
- function usdeTokenAddressOnEvmChain(chainId) {
3071
- if (chainId === 1) return USDE_ETHEREUM_MAINNET;
3072
- if (chainId === 324) return USDE_ZKSYNC_ERA;
3073
- if (L2_SAME_ADDRESS_CHAIN_IDS.has(chainId)) return USDE_MOST_L2S;
3074
- return null;
3075
- }
3076
- function isEvmChainInEthenaUsdeList(chainId) {
3077
- return usdeTokenAddressOnEvmChain(chainId) != null;
3078
- }
3079
-
3080
- // src/protocols/evm/ethena/index.ts
3081
- var ETHENA_PROTOCOL_ID = "ethena";
3082
- var ethenaProtocolModule = {
3083
- id: ETHENA_PROTOCOL_ID,
3084
- chainCategory: "evm",
3085
- isChainSupported(ctx) {
3086
- if (ctx.chainCategory !== "evm") return false;
3087
- const n = typeof ctx.chainId === "number" ? ctx.chainId : Number.parseInt(String(ctx.chainId), 10);
3088
- return isEvmChainInEthenaUsdeList(n);
3089
- },
3090
- isTokenSupported(token) {
3091
- return token.category === "evm" && token.kind === "erc20";
3092
- },
3093
- actions: [
3094
- { id: "ethena.stake-usde", protocolId: ETHENA_PROTOCOL_ID, chainCategory: "evm", description: "Stake USDe \u2192 sUSDe", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: { amountHuman: { type: "string", required: true, description: "USDe amount" } } },
3095
- { id: "ethena.redeem-susde", protocolId: ETHENA_PROTOCOL_ID, chainCategory: "evm", description: "Redeem sUSDe \u2192 USDe (no cooldown)", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3096
- { id: "ethena.cooldown-shares", protocolId: ETHENA_PROTOCOL_ID, chainCategory: "evm", description: "Start sUSDe cooldown", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3097
- { id: "ethena.claim-unstake", protocolId: ETHENA_PROTOCOL_ID, chainCategory: "evm", description: "Claim after cooldown", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3098
- ]
3099
- };
3100
- registerProtocolModule(ethenaProtocolModule);
3101
-
3102
- // src/protocols/evm/maple/constants.ts
3103
- function isMapleSyrupSupportedChain(chainId) {
3104
- return chainId === 1 || chainId === 11155111;
3105
- }
3106
-
3107
- // src/protocols/evm/maple/index.ts
3108
- var MAPLE_PROTOCOL_ID = "maple-syrup";
3109
- var mapleProtocolModule = {
3110
- id: MAPLE_PROTOCOL_ID,
3111
- chainCategory: "evm",
3112
- isChainSupported(ctx) {
3113
- if (ctx.chainCategory !== "evm") return false;
3114
- const n = typeof ctx.chainId === "number" ? ctx.chainId : Number.parseInt(String(ctx.chainId), 10);
3115
- return isMapleSyrupSupportedChain(n);
3116
- },
3117
- isTokenSupported(token) {
3118
- return token.category === "evm" && token.kind === "erc20";
3119
- },
3120
- actions: [
3121
- { id: "maple-syrup.deposit", protocolId: MAPLE_PROTOCOL_ID, chainCategory: "evm", description: "Deposit into Maple Syrup pool", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3122
- { id: "maple-syrup.request-redeem", protocolId: MAPLE_PROTOCOL_ID, chainCategory: "evm", description: "Request redeem from pool", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3123
- ]
3124
- };
3125
- registerProtocolModule(mapleProtocolModule);
3126
-
3127
- // src/protocols/evm/sky/mainnet.ts
3128
- var SKY_ETHEREUM_MAINNET_CHAIN_ID = 1;
3129
-
3130
- // src/protocols/evm/sky/index.ts
3131
- var SKY_PROTOCOL_ID = "sky";
3132
- var skyProtocolModule = {
3133
- id: SKY_PROTOCOL_ID,
3134
- chainCategory: "evm",
3135
- isChainSupported(ctx) {
3136
- if (ctx.chainCategory !== "evm") return false;
3137
- return Number(ctx.chainId) === SKY_ETHEREUM_MAINNET_CHAIN_ID;
3138
- },
3139
- isTokenSupported(token) {
3140
- return token.category === "evm" && token.kind === "erc20";
3141
- },
3142
- actions: [
3143
- { id: "sky.lockstake-stake", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Open Lockstake position", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3144
- { id: "sky.lockstake-draw", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Borrow USDS from Lockstake", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3145
- { id: "sky.lockstake-wipe", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Repay Lockstake debt", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3146
- { id: "sky.lockstake-close", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Close Lockstake position", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3147
- { id: "sky.susds-deposit", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Deposit USDS into sUSDS vault", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3148
- { id: "sky.susds-redeem", protocolId: SKY_PROTOCOL_ID, chainCategory: "evm", description: "Redeem sUSDS to USDS", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3149
- ]
3150
- };
3151
- registerProtocolModule(skyProtocolModule);
3152
-
3153
- // src/protocols/evm/aave-v4/index.ts
3154
- var AAVE_V4_PROTOCOL_ID = "aave-v4";
3155
- var aaveV4ProtocolModule = {
3156
- id: AAVE_V4_PROTOCOL_ID,
3157
- chainCategory: "evm",
3158
- isChainSupported(ctx) {
3159
- return ctx.chainCategory === "evm";
3160
- },
3161
- isTokenSupported(token) {
3162
- return token.category === "evm" && (token.kind === "native" || token.kind === "erc20");
3163
- },
3164
- actions: [
3165
- { id: "aave-v4.deposit", protocolId: AAVE_V4_PROTOCOL_ID, chainCategory: "evm", description: "Supply to Aave v4 Spoke", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3166
- { id: "aave-v4.withdraw", protocolId: AAVE_V4_PROTOCOL_ID, chainCategory: "evm", description: "Withdraw from Spoke", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3167
- { id: "aave-v4.borrow", protocolId: AAVE_V4_PROTOCOL_ID, chainCategory: "evm", description: "Borrow from Spoke", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3168
- { id: "aave-v4.repay", protocolId: AAVE_V4_PROTOCOL_ID, chainCategory: "evm", description: "Repay Spoke debt", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3169
- ]
3170
- };
3171
- registerProtocolModule(aaveV4ProtocolModule);
3172
-
3173
- // src/protocols/evm/euler-v2/index.ts
3174
- var EULER_V2_PROTOCOL_ID = "euler-v2";
3175
- var eulerV2ProtocolModule = {
3176
- id: EULER_V2_PROTOCOL_ID,
3177
- chainCategory: "evm",
3178
- isChainSupported(ctx) {
3179
- return ctx.chainCategory === "evm";
3180
- },
3181
- isTokenSupported(token) {
3182
- return token.category === "evm" && (token.kind === "native" || token.kind === "erc20");
3183
- },
3184
- actions: [
3185
- { id: "euler-v2.isolated-lend", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Deposit into Euler vault", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3186
- { id: "euler-v2.isolated-borrow", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Borrow from Euler vault", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3187
- { id: "euler-v2.vault-withdraw", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Withdraw from Euler vault", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3188
- { id: "euler-v2.borrow-repay", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Repay Euler borrow", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3189
- { id: "euler-v2.collateral-deposit", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Deposit borrow collateral", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
3190
- { id: "euler-v2.collateral-withdraw", protocolId: EULER_V2_PROTOCOL_ID, chainCategory: "evm", description: "Withdraw borrow collateral", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
3191
- ]
3192
- };
3193
- registerProtocolModule(eulerV2ProtocolModule);
3194
-
3195
- // src/agent/catalog.ts
3196
- registerProtocolModule(uniswapV4ProtocolModule);
3197
- registerProtocolModule(curveDaoProtocolModule);
3198
- registerProtocolModule(lidoProtocolModule);
3199
- registerProtocolModule(ethenaProtocolModule);
3200
- registerProtocolModule(mapleProtocolModule);
3201
- registerProtocolModule(skyProtocolModule);
3202
- registerProtocolModule(aaveV4ProtocolModule);
3203
- registerProtocolModule(eulerV2ProtocolModule);
3204
- function getAgentCatalog() {
3205
- return {
3206
- protocols: getProtocolModules(),
3207
- byCategory: {
3208
- evm: getActionsByChainCategory("evm"),
3209
- solana: getActionsByChainCategory("solana"),
3210
- near: getActionsByChainCategory("near")
3211
- },
3212
- uniswapV4: uniswapV4ProtocolModule,
3213
- curveDao: curveDaoProtocolModule,
3214
- lido: lidoProtocolModule,
3215
- ethena: ethenaProtocolModule,
3216
- maple: mapleProtocolModule,
3217
- sky: skyProtocolModule,
3218
- aaveV4: aaveV4ProtocolModule,
3219
- eulerV2: eulerV2ProtocolModule,
3220
- /** Prefer getAgentCatalogForMcp() or getMcpToolDefinitions() for MCP servers. */
3221
- mcp: getAgentCatalogForMcp()
3222
- };
3223
- }
3224
-
3225
1613
  // src/index.ts
3226
1614
  registerProtocolModule(uniswapV4ProtocolModule);
3227
1615
  registerProtocolModule(curveDaoProtocolModule);
3228
1616
 
3229
- export { NEAR_CHAIN_CATEGORY, SOLANA_CHAIN_CATEGORY, alignEip1559FeesWithLatestBase, buildEvmMultisignBatch, buildManagementPostBody, chainSnapshotForCustomGasExtraJSON, composeFeePayloadToTxParams, coreChainCategoryModule, curveDao, curveDaoProtocolModule, evmChainCategoryModule, fetchChainFeeParams, fetchManagementNonce, fetchNodeKey, finalizeMultisign, firstClientIdFromKeyGen, gasLimitFromEstimateAndChainConfig, getActionsByChainCategory, getAgentCatalog, getProtocolModule, getProtocolModules, gweiToDecimalString, isEvmNativeToken, isValidRpcUrl, keyListFromKeyGen, managementSigFields, matchEvmTokenKind, mergePurposeText, messageToSignManagementBody, nearChainCategoryModule, nodeFetchWithReadAuth, normalizeManagementNodeKey, parseEvmChainIdToNumber, proposalTxParamsToFeeSnapshot, registerProtocolModule, requirePubKeyHex, routerSwapGasLimitFromEstimate, solanaChainCategoryModule, triggerTxParamsFromComposeBody, uniswapV4, uniswapV4ProtocolModule, withManagementClientSig };
1617
+ export { NEAR_CHAIN_CATEGORY, SOLANA_CHAIN_CATEGORY, buildEvmMultisignBatch, coreChainCategoryModule, curveDao, curveDaoProtocolModule, evmChainCategoryModule, finalizeMultisign, getActionsByChainCategory, getProtocolModule, getProtocolModules, isEvmNativeToken, matchEvmTokenKind, mergePurposeText, nearChainCategoryModule, parseEvmChainIdToNumber, registerProtocolModule, routerSwapGasLimitFromEstimate, solanaChainCategoryModule, uniswapV4, uniswapV4ProtocolModule };
3230
1618
  //# sourceMappingURL=index.js.map
3231
1619
  //# sourceMappingURL=index.js.map