@continuumdao/ctm-mpc-defi 0.1.4 → 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.
- package/README.md +20 -78
- package/dist/agent/catalog.cjs +1388 -144
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +881 -17
- package/dist/agent/catalog.js +1327 -145
- package/dist/agent/catalog.js.map +1 -1
- package/dist/agent/skills/aave-v4/SKILL.md +43 -0
- package/dist/agent/skills/curve-dao/SKILL.md +12 -0
- package/dist/agent/skills/ethena/SKILL.md +10 -0
- package/dist/agent/skills/euler-v2/SKILL.md +10 -0
- package/dist/agent/skills/lido/SKILL.md +22 -0
- package/dist/agent/skills/maple-syrup/SKILL.md +10 -0
- package/dist/agent/skills/sky/SKILL.md +10 -0
- package/dist/agent/skills/uniswap-v4/SKILL.md +22 -0
- package/dist/chains/evm/index.cjs +27 -213
- package/dist/chains/evm/index.cjs.map +1 -1
- package/dist/chains/evm/index.d.ts +15 -25
- package/dist/chains/evm/index.js +21 -199
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/near/index.d.ts +1 -1
- package/dist/chains/solana/index.d.ts +1 -1
- package/dist/core/index.cjs +8 -110
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +5 -39
- package/dist/core/index.js +6 -100
- package/dist/core/index.js.map +1 -1
- package/dist/{envelope-CcE5Cz_q.d.ts → envelope-CpBUh9eP.d.ts} +1 -1
- package/dist/index.cjs +238 -1184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -10
- package/dist/index.js +227 -1156
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aave-v4/index.cjs +1710 -0
- package/dist/protocols/evm/aave-v4/index.cjs.map +1 -0
- package/dist/protocols/evm/aave-v4/index.d.ts +499 -0
- package/dist/protocols/evm/aave-v4/index.js +1666 -0
- package/dist/protocols/evm/aave-v4/index.js.map +1 -0
- package/dist/protocols/evm/curve-dao/index.cjs +24 -124
- package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
- package/dist/protocols/evm/curve-dao/index.d.ts +3 -4
- package/dist/protocols/evm/curve-dao/index.js +15 -115
- package/dist/protocols/evm/curve-dao/index.js.map +1 -1
- package/dist/protocols/evm/ethena/index.cjs +853 -0
- package/dist/protocols/evm/ethena/index.cjs.map +1 -0
- package/dist/protocols/evm/ethena/index.d.ts +160 -0
- package/dist/protocols/evm/ethena/index.js +831 -0
- package/dist/protocols/evm/ethena/index.js.map +1 -0
- package/dist/protocols/evm/euler-v2/index.cjs +1585 -0
- package/dist/protocols/evm/euler-v2/index.cjs.map +1 -0
- package/dist/protocols/evm/euler-v2/index.d.ts +316 -0
- package/dist/protocols/evm/euler-v2/index.js +1560 -0
- package/dist/protocols/evm/euler-v2/index.js.map +1 -0
- package/dist/protocols/evm/lido/index.cjs +839 -0
- package/dist/protocols/evm/lido/index.cjs.map +1 -0
- package/dist/protocols/evm/lido/index.d.ts +119 -0
- package/dist/protocols/evm/lido/index.js +814 -0
- package/dist/protocols/evm/lido/index.js.map +1 -0
- package/dist/protocols/evm/maple/index.cjs +619 -0
- package/dist/protocols/evm/maple/index.cjs.map +1 -0
- package/dist/protocols/evm/maple/index.d.ts +108 -0
- package/dist/protocols/evm/maple/index.js +605 -0
- package/dist/protocols/evm/maple/index.js.map +1 -0
- package/dist/protocols/evm/sky/index.cjs +1259 -0
- package/dist/protocols/evm/sky/index.cjs.map +1 -0
- package/dist/protocols/evm/sky/index.d.ts +217 -0
- package/dist/protocols/evm/sky/index.js +1234 -0
- package/dist/protocols/evm/sky/index.js.map +1 -0
- package/dist/protocols/evm/uniswap-v4/index.cjs +423 -658
- package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/uniswap-v4/index.d.ts +3 -4
- package/dist/protocols/evm/uniswap-v4/index.js +422 -657
- package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
- package/dist/{registry-oMKlO_5z.d.ts → registry-Bv5o37_w.d.ts} +1 -1
- package/dist/{types-Ce2qNHai.d.cts → types-BfjWdw1j.d.ts} +3 -1
- package/dist/{types-5u863Fd9.d.ts → types-DUeNJLr9.d.ts} +1 -1
- package/package.json +43 -8
- package/dist/agent/catalog.d.cts +0 -195
- package/dist/chains/evm/index.d.cts +0 -62
- package/dist/chains/near/index.d.cts +0 -37
- package/dist/chains/solana/index.d.cts +0 -40
- package/dist/core/index.d.cts +0 -43
- package/dist/envelope-DYDPnrHZ.d.cts +0 -35
- package/dist/index.d.cts +0 -15
- package/dist/keygen-CfNp8yKJ.d.cts +0 -9
- package/dist/keygen-DsINazx8.d.ts +0 -9
- package/dist/nodeRead-BnmSaMGO.d.cts +0 -8
- package/dist/nodeRead-BnmSaMGO.d.ts +0 -8
- package/dist/protocols/evm/curve-dao/index.d.cts +0 -147
- package/dist/protocols/evm/uniswap-v4/index.d.cts +0 -324
- package/dist/registry-BwZoE668.d.cts +0 -8
- package/dist/txParams-BC7ogvdR.d.cts +0 -19
- package/dist/txParams-BC7ogvdR.d.ts +0 -19
- package/dist/types-B8idm_gu.d.cts +0 -34
- package/dist/types-Ce2qNHai.d.ts +0 -57
package/dist/index.cjs
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
|
|
3
4
|
var viem = require('viem');
|
|
4
5
|
|
|
5
|
-
// src/core/
|
|
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
|
-
}
|
|
6
|
+
// src/core/index.ts
|
|
22
7
|
|
|
23
8
|
// src/core/purpose.ts
|
|
24
9
|
function mergePurposeText(purposeText, purposeSuffix) {
|
|
@@ -29,8 +14,6 @@ function mergePurposeText(purposeText, purposeSuffix) {
|
|
|
29
14
|
|
|
30
15
|
${suffix}` : suffix;
|
|
31
16
|
}
|
|
32
|
-
|
|
33
|
-
// src/core/envelope.ts
|
|
34
17
|
function finalizeMultisign(input) {
|
|
35
18
|
const { keyGen, destinationChainID, legs } = input;
|
|
36
19
|
if (legs.length === 0) {
|
|
@@ -39,7 +22,7 @@ function finalizeMultisign(input) {
|
|
|
39
22
|
const ph = (keyGen.pubkeyhex ?? "").trim();
|
|
40
23
|
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
41
24
|
const keyList = keyGen.keylist ?? [];
|
|
42
|
-
const clientId =
|
|
25
|
+
const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
|
|
43
26
|
const first = legs[0];
|
|
44
27
|
const messageHashes = legs.map((l) => l.msgHash);
|
|
45
28
|
const messageRawBatch = legs.map((l) => l.msgRaw);
|
|
@@ -104,85 +87,6 @@ function getProtocolModule(id) {
|
|
|
104
87
|
function getActionsByChainCategory(category) {
|
|
105
88
|
return modules.filter((m) => m.chainCategory === category).flatMap((m) => m.actions);
|
|
106
89
|
}
|
|
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
90
|
function isEvmNativeToken(address) {
|
|
187
91
|
try {
|
|
188
92
|
return viem.getAddress(address) === viem.zeroAddress;
|
|
@@ -197,161 +101,12 @@ function matchEvmTokenKind(kind, address) {
|
|
|
197
101
|
}
|
|
198
102
|
return true;
|
|
199
103
|
}
|
|
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
104
|
function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
|
|
210
105
|
if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
|
|
211
|
-
return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
|
|
106
|
+
return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
|
|
212
107
|
}
|
|
213
108
|
return (estimatedGas * 12n + 9n) / 10n;
|
|
214
109
|
}
|
|
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 = viem.defineChain({
|
|
290
|
-
id: chainIdNum,
|
|
291
|
-
name: "Discovery",
|
|
292
|
-
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
293
|
-
rpcUrls: { default: { http: [url] } }
|
|
294
|
-
});
|
|
295
|
-
const publicClient = viem.createPublicClient({
|
|
296
|
-
chain,
|
|
297
|
-
transport: viem.http(url)
|
|
298
|
-
});
|
|
299
|
-
const getGasPriceGwei = async () => {
|
|
300
|
-
const gasPriceWei = await publicClient.getGasPrice();
|
|
301
|
-
return parseFloat(viem.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(viem.formatUnits(baseFeePerGas, 9));
|
|
311
|
-
let priorityFeeGwei;
|
|
312
|
-
try {
|
|
313
|
-
const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
|
|
314
|
-
priorityFeeGwei = parseFloat(viem.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(viem.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 + viem.parseGwei("0.001");
|
|
339
|
-
}
|
|
340
|
-
if (maxF < maxP) {
|
|
341
|
-
maxF = baseWei > 0n ? baseWei + maxP + viem.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
110
|
|
|
356
111
|
// src/chains/evm/buildBatch.ts
|
|
357
112
|
async function buildEvmMultisignBatch(args) {
|
|
@@ -374,7 +129,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
374
129
|
rpcUrls: { default: { http: [rpcUrl] } }
|
|
375
130
|
});
|
|
376
131
|
const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
|
|
377
|
-
const feeParams = await fetchChainFeeParams(rpcUrl, chainId);
|
|
132
|
+
const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
|
|
378
133
|
const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
|
|
379
134
|
const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
380
135
|
const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
|
|
@@ -387,15 +142,19 @@ async function buildEvmMultisignBatch(args) {
|
|
|
387
142
|
const step = steps[i];
|
|
388
143
|
const currentNonce = baseNonce + i;
|
|
389
144
|
let estimatedGas;
|
|
390
|
-
|
|
391
|
-
estimatedGas = await
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
145
|
+
if (args.estimateGasForStep) {
|
|
146
|
+
estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
|
|
147
|
+
} else {
|
|
148
|
+
try {
|
|
149
|
+
estimatedGas = await publicClient.estimateGas({
|
|
150
|
+
to: step.to,
|
|
151
|
+
data: step.data,
|
|
152
|
+
value: step.value,
|
|
153
|
+
account: executor
|
|
154
|
+
});
|
|
155
|
+
} catch {
|
|
156
|
+
estimatedGas = step.fallbackGas ?? 100000n;
|
|
157
|
+
}
|
|
399
158
|
}
|
|
400
159
|
let gasLimitI;
|
|
401
160
|
if (args.resolveGasLimit) {
|
|
@@ -403,7 +162,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
403
162
|
} else if (step.routerSwap) {
|
|
404
163
|
gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
|
|
405
164
|
} else {
|
|
406
|
-
gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
165
|
+
gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
407
166
|
}
|
|
408
167
|
let proposalTxParams;
|
|
409
168
|
let feeSnapshot;
|
|
@@ -414,7 +173,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
414
173
|
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
415
174
|
}
|
|
416
175
|
if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
|
|
417
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(chainDetail.gasPrice)));
|
|
176
|
+
const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
|
|
418
177
|
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
419
178
|
}
|
|
420
179
|
serialized = viem.serializeTransaction({
|
|
@@ -433,7 +192,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
433
192
|
txType: "legacy",
|
|
434
193
|
gasPrice: gasPriceWei.toString()
|
|
435
194
|
};
|
|
436
|
-
feeSnapshot = proposalTxParamsToFeeSnapshot(proposalTxParams);
|
|
195
|
+
feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
|
|
437
196
|
} else {
|
|
438
197
|
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
439
198
|
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
@@ -444,13 +203,13 @@ async function buildEvmMultisignBatch(args) {
|
|
|
444
203
|
const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
|
|
445
204
|
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
446
205
|
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
447
|
-
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
448
|
-
let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
|
|
206
|
+
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
207
|
+
let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
|
|
449
208
|
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
450
209
|
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
451
210
|
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
452
211
|
}
|
|
453
|
-
({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
|
|
212
|
+
({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
|
|
454
213
|
maxFeePerGas,
|
|
455
214
|
maxPriorityFeePerGas,
|
|
456
215
|
latestBaseFeeWei
|
|
@@ -473,7 +232,7 @@ async function buildEvmMultisignBatch(args) {
|
|
|
473
232
|
maxFeePerGas: maxFeePerGas.toString(),
|
|
474
233
|
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
475
234
|
};
|
|
476
|
-
feeSnapshot = i === 0 ? proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
|
|
235
|
+
feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
|
|
477
236
|
}
|
|
478
237
|
const h = viem.keccak256(serialized);
|
|
479
238
|
const msgHash = h.startsWith("0x") ? h.slice(2) : h;
|
|
@@ -517,30 +276,6 @@ var evmChainCategoryModule = {
|
|
|
517
276
|
buildEvmMultisignBatch
|
|
518
277
|
};
|
|
519
278
|
|
|
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
279
|
// src/chains/evm/chainIdParse.ts
|
|
545
280
|
function parseEvmChainIdToNumber(chainId) {
|
|
546
281
|
if (chainId == null) return Number.NaN;
|
|
@@ -682,7 +417,7 @@ async function fetchEthereumAddressForKeyGen(managementNodeUrl, keyGenId, readAu
|
|
|
682
417
|
throw new Error("keyGen is required");
|
|
683
418
|
}
|
|
684
419
|
const url = `${base}/getKeyGenResultById?id=${encodeURIComponent(id)}`;
|
|
685
|
-
const res = await nodeFetchWithReadAuth(url, { ...init, method: "GET", cache: "no-store" }, readAuth);
|
|
420
|
+
const res = await continuumNodeSdk.nodeFetchWithReadAuth(url, { ...init, method: "GET", cache: "no-store" }, readAuth);
|
|
686
421
|
if (!res.ok) {
|
|
687
422
|
const t = await res.text().catch(() => "");
|
|
688
423
|
throw new Error(
|
|
@@ -988,6 +723,35 @@ async function uniswapCreateSwap(args) {
|
|
|
988
723
|
}
|
|
989
724
|
return parsed;
|
|
990
725
|
}
|
|
726
|
+
async function estimateUniswapRouterSwapGas(args) {
|
|
727
|
+
const fromTradeApi = parseOptionalGasLimitString(args.swapRecord.gasLimit) ?? parseOptionalGasLimitString(args.swapRecord.gas);
|
|
728
|
+
if (fromTradeApi != null && fromTradeApi > 0n) {
|
|
729
|
+
return { baseGasUnits: fromTradeApi, source: "tradeApi" };
|
|
730
|
+
}
|
|
731
|
+
try {
|
|
732
|
+
const est = await args.publicClient.estimateGas({
|
|
733
|
+
to: args.to,
|
|
734
|
+
data: args.data,
|
|
735
|
+
value: args.value,
|
|
736
|
+
account: args.executor
|
|
737
|
+
});
|
|
738
|
+
return { baseGasUnits: est, source: "rpcEstimate" };
|
|
739
|
+
} catch (e) {
|
|
740
|
+
const estimateGasError = e instanceof Error ? e.message : String(e);
|
|
741
|
+
const minRouterGas = 500000n;
|
|
742
|
+
if (args.useCustomGas) {
|
|
743
|
+
const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
|
|
744
|
+
if (cfg != null && cfg >= minRouterGas) {
|
|
745
|
+
return { baseGasUnits: cfg, source: "estimateFailedFallback", estimateGasError };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return {
|
|
749
|
+
baseGasUnits: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK,
|
|
750
|
+
source: "estimateFailedFallback",
|
|
751
|
+
estimateGasError
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
}
|
|
991
755
|
var permit2ApproveRouterAbi = [
|
|
992
756
|
{
|
|
993
757
|
name: "approve",
|
|
@@ -1088,10 +852,6 @@ function permit2SpenderAndApproveWeiFromSwapCalldata(dataHex, tokenIn, quoteInpu
|
|
|
1088
852
|
}
|
|
1089
853
|
}
|
|
1090
854
|
async function buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei) {
|
|
1091
|
-
const ph = (args.keyGen.pubkeyhex ?? "").trim();
|
|
1092
|
-
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
1093
|
-
const keyList = args.keyGen.keylist ?? [];
|
|
1094
|
-
const clientId = firstClientIdFromKeyGen(args.keyGen);
|
|
1095
855
|
const toRouter = viem.getAddress(
|
|
1096
856
|
(args.swap.to ?? "").trim().startsWith("0x") ? args.swap.to.trim() : `0x${args.swap.to.trim()}`
|
|
1097
857
|
);
|
|
@@ -1109,214 +869,90 @@ async function buildEvmMultisignBodyUniswapV4NativeInOnly(args, quoteInputWei) {
|
|
|
1109
869
|
"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."
|
|
1110
870
|
);
|
|
1111
871
|
}
|
|
1112
|
-
const ch = viem.defineChain({
|
|
1113
|
-
id: args.chainId,
|
|
1114
|
-
name: "Destination",
|
|
1115
|
-
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
1116
|
-
rpcUrls: { default: { http: [args.rpcUrl] } }
|
|
1117
|
-
});
|
|
1118
|
-
const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
|
|
1119
|
-
const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
|
|
1120
|
-
const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
|
|
1121
|
-
const latestBaseFeeWeiNativeIn = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
1122
|
-
const useCustomGas = args.useCustomGas;
|
|
1123
|
-
const chainGasLimitRouter = args.chainDetail?.gasLimit != null && Number.isFinite(Number(args.chainDetail.gasLimit)) && Number(args.chainDetail.gasLimit) > 0 ? Number(args.chainDetail.gasLimit) : void 0;
|
|
1124
|
-
const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
|
|
1125
|
-
const nonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
|
|
1126
|
-
const proposalTxParamsBatch = [];
|
|
1127
|
-
const messageHashes = [];
|
|
1128
|
-
const messageRawBatch = [];
|
|
1129
872
|
const swapRecord = args.swap;
|
|
1130
|
-
const fromTradeApi = parseOptionalGasLimitString(swapRecord.gasLimit) ?? parseOptionalGasLimitString(swapRecord.gas);
|
|
1131
873
|
let gasBuildSource = "rpcEstimate";
|
|
1132
874
|
let estimateGasError;
|
|
1133
|
-
let
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
875
|
+
let swapBaseGasUnits = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
876
|
+
const dataNo0x = dataHex.startsWith("0x") ? dataHex.slice(2) : dataHex;
|
|
877
|
+
const purposeSuffix = "Uniswap V4: 1-tx batch \u2014 native gas token in (no ERC-20 approve) \u2014 single payable swap (Trade /swap).";
|
|
878
|
+
return buildEvmMultisignBatch({
|
|
879
|
+
context: {
|
|
880
|
+
chainCategory: "evm",
|
|
881
|
+
keyGen: args.keyGen,
|
|
882
|
+
purposeText: args.purposeText,
|
|
883
|
+
chainId: args.chainId,
|
|
884
|
+
rpcUrl: args.rpcUrl,
|
|
885
|
+
executorAddress: args.executorAddress,
|
|
886
|
+
chainDetail: args.chainDetail,
|
|
887
|
+
useCustomGas: args.useCustomGas,
|
|
888
|
+
customGasChainDetails: args.customGasChainDetails
|
|
889
|
+
},
|
|
890
|
+
steps: [
|
|
891
|
+
{
|
|
1140
892
|
to: toRouter,
|
|
1141
893
|
data: dataHex,
|
|
1142
894
|
value: valueWei,
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
gasBuildSource = "rpcEstimate";
|
|
1146
|
-
} catch (e) {
|
|
1147
|
-
estimateGasError = e instanceof Error ? e.message : String(e);
|
|
1148
|
-
const minRouterGas = 500000n;
|
|
1149
|
-
if (useCustomGas) {
|
|
1150
|
-
const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
|
|
1151
|
-
if (cfg != null && cfg >= minRouterGas) {
|
|
1152
|
-
baseGasUnits1 = cfg;
|
|
1153
|
-
} else {
|
|
1154
|
-
baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
1155
|
-
}
|
|
1156
|
-
} else {
|
|
1157
|
-
baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
1158
|
-
}
|
|
1159
|
-
gasBuildSource = "estimateFailedFallback";
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
const gasLimit1 = routerSwapGasLimitFromEstimate(baseGasUnits1, chainGasLimitRouter);
|
|
1163
|
-
const currentNonce0 = nonce;
|
|
1164
|
-
let firstTxFeePayload = {};
|
|
1165
|
-
if (legacy) {
|
|
1166
|
-
let gasPriceWei1 = await publicClient.getGasPrice();
|
|
1167
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1168
|
-
gasPriceWei1 = gasPriceWei1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1169
|
-
}
|
|
1170
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
1171
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
1172
|
-
if (configured > gasPriceWei1) gasPriceWei1 = configured;
|
|
1173
|
-
}
|
|
1174
|
-
firstTxFeePayload = { txNonce: nonce, txGasLimit: gasLimit1.toString(), txGasPrice: gasPriceWei1.toString() };
|
|
1175
|
-
const ser0 = viem.serializeTransaction({
|
|
1176
|
-
type: "legacy",
|
|
1177
|
-
to: toRouter,
|
|
1178
|
-
data: dataHex,
|
|
1179
|
-
value: valueWei,
|
|
1180
|
-
gas: gasLimit1,
|
|
1181
|
-
gasPrice: gasPriceWei1,
|
|
1182
|
-
nonce: currentNonce0,
|
|
1183
|
-
chainId: args.chainId
|
|
1184
|
-
});
|
|
1185
|
-
const h0 = viem.keccak256(ser0);
|
|
1186
|
-
messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
|
|
1187
|
-
messageRawBatch.push(ser0);
|
|
1188
|
-
proposalTxParamsBatch.push({
|
|
1189
|
-
nonce: currentNonce0,
|
|
1190
|
-
gasLimit: gasLimit1.toString(),
|
|
1191
|
-
txType: "legacy",
|
|
1192
|
-
gasPrice: gasPriceWei1.toString()
|
|
1193
|
-
});
|
|
1194
|
-
} else {
|
|
1195
|
-
const fetchedBase1 = feeParams.baseFeeGwei ?? 0;
|
|
1196
|
-
const fetchedPriority1 = feeParams.priorityFeeGwei ?? 0;
|
|
1197
|
-
const configuredBase1 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
1198
|
-
const configuredPriority1 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
1199
|
-
const effectiveBaseFeeGwei1 = Math.max(fetchedBase1, configuredBase1);
|
|
1200
|
-
const effectivePriorityFeeGwei1 = Math.max(fetchedPriority1, configuredPriority1);
|
|
1201
|
-
const baseFeeMultiplierPct1 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
1202
|
-
const baseComponentGwei1 = effectiveBaseFeeGwei1 * baseFeeMultiplierPct1 / 100;
|
|
1203
|
-
const maxFeePerGasGwei1 = baseComponentGwei1 + effectivePriorityFeeGwei1;
|
|
1204
|
-
let maxPriorityFeePerGas1 = effectivePriorityFeeGwei1 > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei1)) : viem.parseGwei("1");
|
|
1205
|
-
let maxFeePerGas1 = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei1));
|
|
1206
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1207
|
-
maxPriorityFeePerGas1 = maxPriorityFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1208
|
-
maxFeePerGas1 = maxFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1209
|
-
}
|
|
1210
|
-
({ maxFeePerGas: maxFeePerGas1, maxPriorityFeePerGas: maxPriorityFeePerGas1 } = alignEip1559FeesWithLatestBase(maxFeePerGas1, maxPriorityFeePerGas1, latestBaseFeeWeiNativeIn));
|
|
1211
|
-
firstTxFeePayload = {
|
|
1212
|
-
txNonce: nonce,
|
|
1213
|
-
txGasLimit: gasLimit1.toString(),
|
|
1214
|
-
txMaxFeePerGas: maxFeePerGas1.toString(),
|
|
1215
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
|
|
1216
|
-
};
|
|
1217
|
-
const ser0 = viem.serializeTransaction({
|
|
1218
|
-
type: "eip1559",
|
|
1219
|
-
to: toRouter,
|
|
1220
|
-
data: dataHex,
|
|
1221
|
-
value: valueWei,
|
|
1222
|
-
gas: gasLimit1,
|
|
1223
|
-
maxFeePerGas: maxFeePerGas1,
|
|
1224
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas1,
|
|
1225
|
-
nonce: currentNonce0,
|
|
1226
|
-
chainId: args.chainId
|
|
1227
|
-
});
|
|
1228
|
-
const h0 = viem.keccak256(ser0);
|
|
1229
|
-
messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
|
|
1230
|
-
messageRawBatch.push(ser0);
|
|
1231
|
-
proposalTxParamsBatch.push({
|
|
1232
|
-
nonce: currentNonce0,
|
|
1233
|
-
gasLimit: gasLimit1.toString(),
|
|
1234
|
-
txType: "eip1559",
|
|
1235
|
-
maxFeePerGas: maxFeePerGas1.toString(),
|
|
1236
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
const dataNo0x = dataHex.startsWith("0x") ? dataHex.slice(2) : dataHex;
|
|
1240
|
-
const audit = {
|
|
1241
|
-
skipPermit2Batch: true,
|
|
1242
|
-
inputKind: "native_eth",
|
|
1243
|
-
noErc20Approve: true,
|
|
1244
|
-
quoteInputWei: quoteInputWei.toString(),
|
|
1245
|
-
swapValueWei: valueWei.toString(),
|
|
1246
|
-
uniswapCreateSwap: {
|
|
1247
|
-
requestId: args.createSwapResponse.requestId,
|
|
1248
|
-
gasFee: args.createSwapResponse.gasFee,
|
|
1249
|
-
gasBuildSwap: {
|
|
1250
|
-
useCustomGas,
|
|
1251
|
-
source: gasBuildSource,
|
|
1252
|
-
baseGasUnits: baseGasUnits1.toString(),
|
|
1253
|
-
...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
|
|
1254
|
-
},
|
|
1255
|
-
swap: {
|
|
1256
|
-
to: args.createSwapResponse.swap.to,
|
|
1257
|
-
value: args.createSwapResponse.swap.value,
|
|
1258
|
-
dataNibbles: (() => {
|
|
1259
|
-
const t = (args.createSwapResponse.swap.data ?? "").toString().trim();
|
|
1260
|
-
return t.startsWith("0x") ? t.length - 2 : t.length;
|
|
1261
|
-
})()
|
|
895
|
+
routerSwap: true,
|
|
896
|
+
fallbackGas: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK
|
|
1262
897
|
}
|
|
898
|
+
],
|
|
899
|
+
purposeSuffix,
|
|
900
|
+
firstMsgRawNo0x: dataNo0x,
|
|
901
|
+
destinationAddress: toRouter,
|
|
902
|
+
estimateGasForStep: async ({ publicClient, executor }) => {
|
|
903
|
+
const r = await estimateUniswapRouterSwapGas({
|
|
904
|
+
publicClient,
|
|
905
|
+
executor,
|
|
906
|
+
to: toRouter,
|
|
907
|
+
data: dataHex,
|
|
908
|
+
value: valueWei,
|
|
909
|
+
swapRecord,
|
|
910
|
+
useCustomGas: args.useCustomGas,
|
|
911
|
+
chainDetail: args.chainDetail
|
|
912
|
+
});
|
|
913
|
+
gasBuildSource = r.source;
|
|
914
|
+
estimateGasError = r.estimateGasError;
|
|
915
|
+
swapBaseGasUnits = r.baseGasUnits;
|
|
916
|
+
return r.baseGasUnits;
|
|
1263
917
|
},
|
|
1264
|
-
|
|
1265
|
-
originalPurpose: args.purposeText
|
|
1266
|
-
};
|
|
1267
|
-
const batchMeta = [
|
|
1268
|
-
{
|
|
1269
|
-
destinationAddress: toRouter,
|
|
918
|
+
buildBatchMeta: () => ({
|
|
1270
919
|
signatureText: JSON.stringify({
|
|
1271
920
|
kind: "UniswapV4",
|
|
1272
921
|
name: "UniversalRouter (payable, native in)",
|
|
1273
922
|
note: "Single tx from Trade POST /swap; no ERC-20 approve. Calldata in messageHashes[0] / messageRawBatch[0]."
|
|
1274
923
|
}),
|
|
1275
924
|
evm: { type: "uniswap_v4_swap_tx", version: 1, chainId: String(args.chainId) },
|
|
1276
|
-
uniswapV4:
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
})(),
|
|
1306
|
-
...firstTxFeePayload,
|
|
1307
|
-
proposalTxParams: proposalTxParamsBatch
|
|
1308
|
-
};
|
|
1309
|
-
if (valueWei > 0n) {
|
|
1310
|
-
bodyForSign.value = valueWei.toString();
|
|
1311
|
-
}
|
|
1312
|
-
if (clientId) bodyForSign.clientId = clientId;
|
|
1313
|
-
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
925
|
+
uniswapV4: {
|
|
926
|
+
skipPermit2Batch: true,
|
|
927
|
+
inputKind: "native_eth",
|
|
928
|
+
noErc20Approve: true,
|
|
929
|
+
quoteInputWei: quoteInputWei.toString(),
|
|
930
|
+
swapValueWei: valueWei.toString(),
|
|
931
|
+
uniswapCreateSwap: {
|
|
932
|
+
requestId: args.createSwapResponse.requestId,
|
|
933
|
+
gasFee: args.createSwapResponse.gasFee,
|
|
934
|
+
gasBuildSwap: {
|
|
935
|
+
useCustomGas: args.useCustomGas,
|
|
936
|
+
source: gasBuildSource,
|
|
937
|
+
baseGasUnits: swapBaseGasUnits.toString(),
|
|
938
|
+
...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
|
|
939
|
+
},
|
|
940
|
+
swap: {
|
|
941
|
+
to: args.createSwapResponse.swap.to,
|
|
942
|
+
value: args.createSwapResponse.swap.value,
|
|
943
|
+
dataNibbles: (() => {
|
|
944
|
+
const t = (args.createSwapResponse.swap.data ?? "").toString().trim();
|
|
945
|
+
return t.startsWith("0x") ? t.length - 2 : t.length;
|
|
946
|
+
})()
|
|
947
|
+
}
|
|
948
|
+
},
|
|
949
|
+
fullQuoteFromPermitSnapshot: args.fullQuoteSnapshot,
|
|
950
|
+
originalPurpose: args.purposeText
|
|
951
|
+
}
|
|
952
|
+
})
|
|
953
|
+
});
|
|
1314
954
|
}
|
|
1315
955
|
async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
1316
|
-
const ph = (args.keyGen.pubkeyhex ?? "").trim();
|
|
1317
|
-
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
1318
|
-
const keyList = args.keyGen.keylist ?? [];
|
|
1319
|
-
const clientId = firstClientIdFromKeyGen(args.keyGen);
|
|
1320
956
|
const tokenIn = viem.getAddress(args.tokenIn);
|
|
1321
957
|
const parsedInOut = parseUniswapQuoteClassicInOut(args.fullQuoteSnapshot);
|
|
1322
958
|
const quoteInputWei = parsedInOut?.inputWei;
|
|
@@ -1371,298 +1007,33 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
|
1371
1007
|
return 0n;
|
|
1372
1008
|
}
|
|
1373
1009
|
})();
|
|
1374
|
-
const
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
|
|
1383
|
-
const latestBaseFeeWeiSkipBatch = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
1384
|
-
const useCustomGas = args.useCustomGas;
|
|
1385
|
-
const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
|
|
1386
|
-
const chainGasLimitRouter = args.chainDetail?.gasLimit != null && Number.isFinite(Number(args.chainDetail.gasLimit)) && Number(args.chainDetail.gasLimit) > 0 ? Number(args.chainDetail.gasLimit) : void 0;
|
|
1387
|
-
const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
|
|
1388
|
-
const nonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
|
|
1389
|
-
const proposalTxParamsBatch = [];
|
|
1390
|
-
const messageHashes = [];
|
|
1391
|
-
const messageRawBatch = [];
|
|
1392
|
-
const approveMsgRawNo0x = approveData.startsWith("0x") ? approveData.slice(2) : approveData;
|
|
1393
|
-
let firstTxFeePayload = {};
|
|
1394
|
-
const approveGas = await publicClient.estimateGas({
|
|
1395
|
-
to: tokenIn,
|
|
1396
|
-
data: approveData,
|
|
1397
|
-
value: 0n,
|
|
1398
|
-
account: args.executorAddress
|
|
1399
|
-
});
|
|
1400
|
-
const gasLimit0 = useCustomGas ? gasLimitFromEstimateAndChainConfig(approveGas, gasLimitConfig) : approveGas;
|
|
1401
|
-
const currentNonce0 = nonce;
|
|
1402
|
-
if (legacy) {
|
|
1403
|
-
let gasPriceWei = await publicClient.getGasPrice();
|
|
1404
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1405
|
-
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1406
|
-
}
|
|
1407
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
1408
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
1409
|
-
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
1410
|
-
}
|
|
1411
|
-
firstTxFeePayload = { txNonce: nonce, txGasLimit: gasLimit0.toString(), txGasPrice: gasPriceWei.toString() };
|
|
1412
|
-
const ser0 = viem.serializeTransaction({
|
|
1413
|
-
type: "legacy",
|
|
1414
|
-
to: tokenIn,
|
|
1415
|
-
data: approveData,
|
|
1416
|
-
value: 0n,
|
|
1417
|
-
gas: gasLimit0,
|
|
1418
|
-
gasPrice: gasPriceWei,
|
|
1419
|
-
nonce: currentNonce0,
|
|
1420
|
-
chainId: args.chainId
|
|
1421
|
-
});
|
|
1422
|
-
const h0 = viem.keccak256(ser0);
|
|
1423
|
-
messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
|
|
1424
|
-
messageRawBatch.push(ser0);
|
|
1425
|
-
proposalTxParamsBatch.push({
|
|
1426
|
-
nonce: currentNonce0,
|
|
1427
|
-
gasLimit: gasLimit0.toString(),
|
|
1428
|
-
txType: "legacy",
|
|
1429
|
-
gasPrice: gasPriceWei.toString()
|
|
1430
|
-
});
|
|
1431
|
-
} else {
|
|
1432
|
-
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
1433
|
-
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
1434
|
-
const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
1435
|
-
const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
1436
|
-
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
1437
|
-
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
1438
|
-
const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
1439
|
-
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
1440
|
-
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
1441
|
-
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
1442
|
-
let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
|
|
1443
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1444
|
-
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1445
|
-
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1446
|
-
}
|
|
1447
|
-
({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
|
|
1448
|
-
maxFeePerGas,
|
|
1449
|
-
maxPriorityFeePerGas,
|
|
1450
|
-
latestBaseFeeWeiSkipBatch
|
|
1451
|
-
));
|
|
1452
|
-
firstTxFeePayload = {
|
|
1453
|
-
txNonce: nonce,
|
|
1454
|
-
txGasLimit: gasLimit0.toString(),
|
|
1455
|
-
txMaxFeePerGas: maxFeePerGas.toString(),
|
|
1456
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
1457
|
-
};
|
|
1458
|
-
const ser0 = viem.serializeTransaction({
|
|
1459
|
-
type: "eip1559",
|
|
1460
|
-
to: tokenIn,
|
|
1461
|
-
data: approveData,
|
|
1462
|
-
value: 0n,
|
|
1463
|
-
gas: gasLimit0,
|
|
1464
|
-
maxFeePerGas,
|
|
1465
|
-
maxPriorityFeePerGas,
|
|
1466
|
-
nonce: currentNonce0,
|
|
1467
|
-
chainId: args.chainId
|
|
1468
|
-
});
|
|
1469
|
-
const h0 = viem.keccak256(ser0);
|
|
1470
|
-
messageHashes.push(h0.startsWith("0x") ? h0.slice(2) : h0);
|
|
1471
|
-
messageRawBatch.push(ser0);
|
|
1472
|
-
proposalTxParamsBatch.push({
|
|
1473
|
-
nonce: currentNonce0,
|
|
1474
|
-
gasLimit: gasLimit0.toString(),
|
|
1475
|
-
txType: "eip1559",
|
|
1476
|
-
maxFeePerGas: maxFeePerGas.toString(),
|
|
1477
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
1478
|
-
});
|
|
1479
|
-
}
|
|
1010
|
+
const swapRecord = args.swap;
|
|
1011
|
+
const swapMsgIndex = usePermit2Triple ? 2 : 1;
|
|
1012
|
+
let gasBuildSource = "rpcEstimate";
|
|
1013
|
+
let estimateGasError;
|
|
1014
|
+
let swapBaseGasUnits = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
1015
|
+
const steps = [
|
|
1016
|
+
{ to: tokenIn, data: approveData, value: 0n, fallbackGas: 100000n }
|
|
1017
|
+
];
|
|
1480
1018
|
if (usePermit2Triple) {
|
|
1481
1019
|
const permit2ApproveData = viem.encodeFunctionData({
|
|
1482
1020
|
abi: permit2ApproveRouterAbi,
|
|
1483
1021
|
functionName: "approve",
|
|
1484
1022
|
args: [tokenIn, permit2Spender, approveAmountWei, Number(expiration48)]
|
|
1485
1023
|
});
|
|
1486
|
-
|
|
1487
|
-
to: PERMIT2_ADDRESS,
|
|
1488
|
-
data: permit2ApproveData,
|
|
1489
|
-
value: 0n,
|
|
1490
|
-
account: args.executorAddress
|
|
1491
|
-
});
|
|
1492
|
-
const gasLimitP2 = useCustomGas ? gasLimitFromEstimateAndChainConfig(approveP2Gas, gasLimitConfig) : approveP2Gas;
|
|
1493
|
-
const currentNonceP2 = nonce + 1;
|
|
1494
|
-
if (legacy) {
|
|
1495
|
-
let gasPriceWeiP2 = await publicClient.getGasPrice();
|
|
1496
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1497
|
-
gasPriceWeiP2 = gasPriceWeiP2 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1498
|
-
}
|
|
1499
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
1500
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
1501
|
-
if (configured > gasPriceWeiP2) gasPriceWeiP2 = configured;
|
|
1502
|
-
}
|
|
1503
|
-
const serP2 = viem.serializeTransaction({
|
|
1504
|
-
type: "legacy",
|
|
1505
|
-
to: PERMIT2_ADDRESS,
|
|
1506
|
-
data: permit2ApproveData,
|
|
1507
|
-
value: 0n,
|
|
1508
|
-
gas: gasLimitP2,
|
|
1509
|
-
gasPrice: gasPriceWeiP2,
|
|
1510
|
-
nonce: currentNonceP2,
|
|
1511
|
-
chainId: args.chainId
|
|
1512
|
-
});
|
|
1513
|
-
const hP2 = viem.keccak256(serP2);
|
|
1514
|
-
messageHashes.push(hP2.startsWith("0x") ? hP2.slice(2) : hP2);
|
|
1515
|
-
messageRawBatch.push(serP2);
|
|
1516
|
-
proposalTxParamsBatch.push({
|
|
1517
|
-
nonce: currentNonceP2,
|
|
1518
|
-
gasLimit: gasLimitP2.toString(),
|
|
1519
|
-
txType: "legacy",
|
|
1520
|
-
gasPrice: gasPriceWeiP2.toString()
|
|
1521
|
-
});
|
|
1522
|
-
} else {
|
|
1523
|
-
const fetchedBaseP2 = feeParams.baseFeeGwei ?? 0;
|
|
1524
|
-
const fetchedPriorityP2 = feeParams.priorityFeeGwei ?? 0;
|
|
1525
|
-
const configuredBaseP2 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
1526
|
-
const configuredPriorityP2 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
1527
|
-
const effectiveBaseFeeGweiP2 = Math.max(fetchedBaseP2, configuredBaseP2);
|
|
1528
|
-
const effectivePriorityFeeGweiP2 = Math.max(fetchedPriorityP2, configuredPriorityP2);
|
|
1529
|
-
const baseFeeMultiplierPctP2 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
1530
|
-
const baseComponentGweiP2 = effectiveBaseFeeGweiP2 * baseFeeMultiplierPctP2 / 100;
|
|
1531
|
-
const maxFeePerGasGweiP2 = baseComponentGweiP2 + effectivePriorityFeeGweiP2;
|
|
1532
|
-
let maxPriorityFeePerGasP2 = effectivePriorityFeeGweiP2 > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGweiP2)) : viem.parseGwei("1");
|
|
1533
|
-
let maxFeePerGasP2 = viem.parseGwei(gweiToDecimalString(maxFeePerGasGweiP2));
|
|
1534
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1535
|
-
maxPriorityFeePerGasP2 = maxPriorityFeePerGasP2 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1536
|
-
maxFeePerGasP2 = maxFeePerGasP2 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1537
|
-
}
|
|
1538
|
-
({ maxFeePerGas: maxFeePerGasP2, maxPriorityFeePerGas: maxPriorityFeePerGasP2 } = alignEip1559FeesWithLatestBase(maxFeePerGasP2, maxPriorityFeePerGasP2, latestBaseFeeWeiSkipBatch));
|
|
1539
|
-
const serP2 = viem.serializeTransaction({
|
|
1540
|
-
type: "eip1559",
|
|
1541
|
-
to: PERMIT2_ADDRESS,
|
|
1542
|
-
data: permit2ApproveData,
|
|
1543
|
-
value: 0n,
|
|
1544
|
-
gas: gasLimitP2,
|
|
1545
|
-
maxFeePerGas: maxFeePerGasP2,
|
|
1546
|
-
maxPriorityFeePerGas: maxPriorityFeePerGasP2,
|
|
1547
|
-
nonce: currentNonceP2,
|
|
1548
|
-
chainId: args.chainId
|
|
1549
|
-
});
|
|
1550
|
-
const hP2 = viem.keccak256(serP2);
|
|
1551
|
-
messageHashes.push(hP2.startsWith("0x") ? hP2.slice(2) : hP2);
|
|
1552
|
-
messageRawBatch.push(serP2);
|
|
1553
|
-
proposalTxParamsBatch.push({
|
|
1554
|
-
nonce: currentNonceP2,
|
|
1555
|
-
gasLimit: gasLimitP2.toString(),
|
|
1556
|
-
txType: "eip1559",
|
|
1557
|
-
maxFeePerGas: maxFeePerGasP2.toString(),
|
|
1558
|
-
maxPriorityFeePerGas: maxPriorityFeePerGasP2.toString()
|
|
1559
|
-
});
|
|
1560
|
-
}
|
|
1024
|
+
steps.push({ to: PERMIT2_ADDRESS, data: permit2ApproveData, value: 0n, fallbackGas: 100000n });
|
|
1561
1025
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
to: toRouter,
|
|
1574
|
-
data: dataHex,
|
|
1575
|
-
value: valueWei,
|
|
1576
|
-
account: args.executorAddress
|
|
1577
|
-
});
|
|
1578
|
-
gasBuildSource = "rpcEstimate";
|
|
1579
|
-
} catch (e) {
|
|
1580
|
-
estimateGasError = e instanceof Error ? e.message : String(e);
|
|
1581
|
-
const minRouterGas = 500000n;
|
|
1582
|
-
if (useCustomGas) {
|
|
1583
|
-
const cfg = args.chainDetail?.gasLimit != null ? parseOptionalGasLimitString(String(args.chainDetail.gasLimit)) : null;
|
|
1584
|
-
if (cfg != null && cfg >= minRouterGas) {
|
|
1585
|
-
baseGasUnits1 = cfg;
|
|
1586
|
-
} else {
|
|
1587
|
-
baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
1588
|
-
}
|
|
1589
|
-
} else {
|
|
1590
|
-
baseGasUnits1 = DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK;
|
|
1591
|
-
}
|
|
1592
|
-
gasBuildSource = "estimateFailedFallback";
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
const gasLimit1 = routerSwapGasLimitFromEstimate(baseGasUnits1, chainGasLimitRouter);
|
|
1596
|
-
const currentNonce1 = nonce + (usePermit2Triple ? 2 : 1);
|
|
1597
|
-
if (legacy) {
|
|
1598
|
-
let gasPriceWei1 = await publicClient.getGasPrice();
|
|
1599
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1600
|
-
gasPriceWei1 = gasPriceWei1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1601
|
-
}
|
|
1602
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
1603
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
1604
|
-
if (configured > gasPriceWei1) gasPriceWei1 = configured;
|
|
1605
|
-
}
|
|
1606
|
-
const ser1 = viem.serializeTransaction({
|
|
1607
|
-
type: "legacy",
|
|
1608
|
-
to: toRouter,
|
|
1609
|
-
data: dataHex,
|
|
1610
|
-
value: valueWei,
|
|
1611
|
-
gas: gasLimit1,
|
|
1612
|
-
gasPrice: gasPriceWei1,
|
|
1613
|
-
nonce: currentNonce1,
|
|
1614
|
-
chainId: args.chainId
|
|
1615
|
-
});
|
|
1616
|
-
const h1 = viem.keccak256(ser1);
|
|
1617
|
-
messageHashes.push(h1.startsWith("0x") ? h1.slice(2) : h1);
|
|
1618
|
-
messageRawBatch.push(ser1);
|
|
1619
|
-
proposalTxParamsBatch.push({
|
|
1620
|
-
nonce: currentNonce1,
|
|
1621
|
-
gasLimit: gasLimit1.toString(),
|
|
1622
|
-
txType: "legacy",
|
|
1623
|
-
gasPrice: gasPriceWei1.toString()
|
|
1624
|
-
});
|
|
1625
|
-
} else {
|
|
1626
|
-
const fetchedBase1 = feeParams.baseFeeGwei ?? 0;
|
|
1627
|
-
const fetchedPriority1 = feeParams.priorityFeeGwei ?? 0;
|
|
1628
|
-
const configuredBase1 = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
1629
|
-
const configuredPriority1 = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
1630
|
-
const effectiveBaseFeeGwei1 = Math.max(fetchedBase1, configuredBase1);
|
|
1631
|
-
const effectivePriorityFeeGwei1 = Math.max(fetchedPriority1, configuredPriority1);
|
|
1632
|
-
const baseFeeMultiplierPct1 = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
1633
|
-
const baseComponentGwei1 = effectiveBaseFeeGwei1 * baseFeeMultiplierPct1 / 100;
|
|
1634
|
-
const maxFeePerGasGwei1 = baseComponentGwei1 + effectivePriorityFeeGwei1;
|
|
1635
|
-
let maxPriorityFeePerGas1 = effectivePriorityFeeGwei1 > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei1)) : viem.parseGwei("1");
|
|
1636
|
-
let maxFeePerGas1 = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei1));
|
|
1637
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
1638
|
-
maxPriorityFeePerGas1 = maxPriorityFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1639
|
-
maxFeePerGas1 = maxFeePerGas1 * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
1640
|
-
}
|
|
1641
|
-
({ maxFeePerGas: maxFeePerGas1, maxPriorityFeePerGas: maxPriorityFeePerGas1 } = alignEip1559FeesWithLatestBase(maxFeePerGas1, maxPriorityFeePerGas1, latestBaseFeeWeiSkipBatch));
|
|
1642
|
-
const ser1 = viem.serializeTransaction({
|
|
1643
|
-
type: "eip1559",
|
|
1644
|
-
to: toRouter,
|
|
1645
|
-
data: dataHex,
|
|
1646
|
-
value: valueWei,
|
|
1647
|
-
gas: gasLimit1,
|
|
1648
|
-
maxFeePerGas: maxFeePerGas1,
|
|
1649
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas1,
|
|
1650
|
-
nonce: currentNonce1,
|
|
1651
|
-
chainId: args.chainId
|
|
1652
|
-
});
|
|
1653
|
-
const h1 = viem.keccak256(ser1);
|
|
1654
|
-
messageHashes.push(h1.startsWith("0x") ? h1.slice(2) : h1);
|
|
1655
|
-
messageRawBatch.push(ser1);
|
|
1656
|
-
proposalTxParamsBatch.push({
|
|
1657
|
-
nonce: currentNonce1,
|
|
1658
|
-
gasLimit: gasLimit1.toString(),
|
|
1659
|
-
txType: "eip1559",
|
|
1660
|
-
maxFeePerGas: maxFeePerGas1.toString(),
|
|
1661
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas1.toString()
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
const swapMsgIndex = usePermit2Triple ? 2 : 1;
|
|
1665
|
-
const audit = {
|
|
1026
|
+
steps.push({
|
|
1027
|
+
to: toRouter,
|
|
1028
|
+
data: dataHex,
|
|
1029
|
+
value: valueWei,
|
|
1030
|
+
routerSwap: true,
|
|
1031
|
+
fallbackGas: DEFAULT_UNIVERSAL_ROUTER_GAS_FALLBACK
|
|
1032
|
+
});
|
|
1033
|
+
const swapStepIndex = steps.length - 1;
|
|
1034
|
+
const approveMsgRawNo0x = approveData.startsWith("0x") ? approveData.slice(2) : approveData;
|
|
1035
|
+
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).";
|
|
1036
|
+
const buildSwapAudit = () => ({
|
|
1666
1037
|
skipPermit2Batch: true,
|
|
1667
1038
|
approvalPath: usePermit2Triple ? "permit2_triple" : "dispatcher",
|
|
1668
1039
|
approveAmount: {
|
|
@@ -1676,9 +1047,9 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
|
1676
1047
|
requestId: args.createSwapResponse.requestId,
|
|
1677
1048
|
gasFee: args.createSwapResponse.gasFee,
|
|
1678
1049
|
gasBuildSwap: {
|
|
1679
|
-
useCustomGas,
|
|
1050
|
+
useCustomGas: args.useCustomGas,
|
|
1680
1051
|
source: gasBuildSource,
|
|
1681
|
-
baseGasUnits:
|
|
1052
|
+
baseGasUnits: swapBaseGasUnits.toString(),
|
|
1682
1053
|
...estimateGasError != null && estimateGasError !== "" ? { estimateGasError } : {}
|
|
1683
1054
|
},
|
|
1684
1055
|
swap: {
|
|
@@ -1720,92 +1091,98 @@ async function buildEvmMultisignBodyUniswapV4SkipPermit2Batch(args) {
|
|
|
1720
1091
|
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)."
|
|
1721
1092
|
}
|
|
1722
1093
|
}
|
|
1723
|
-
};
|
|
1724
|
-
|
|
1725
|
-
{
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1094
|
+
});
|
|
1095
|
+
return buildEvmMultisignBatch({
|
|
1096
|
+
context: {
|
|
1097
|
+
chainCategory: "evm",
|
|
1098
|
+
keyGen: args.keyGen,
|
|
1099
|
+
purposeText: args.purposeText,
|
|
1100
|
+
chainId: args.chainId,
|
|
1101
|
+
rpcUrl: args.rpcUrl,
|
|
1102
|
+
executorAddress: args.executorAddress,
|
|
1103
|
+
chainDetail: args.chainDetail,
|
|
1104
|
+
useCustomGas: args.useCustomGas,
|
|
1105
|
+
customGasChainDetails: args.customGasChainDetails
|
|
1106
|
+
},
|
|
1107
|
+
steps,
|
|
1108
|
+
purposeSuffix,
|
|
1109
|
+
firstMsgRawNo0x: approveMsgRawNo0x,
|
|
1110
|
+
destinationAddress: tokenIn,
|
|
1111
|
+
payableValueWei: valueWei > 0n ? valueWei : void 0,
|
|
1112
|
+
estimateGasForStep: async ({ step, index, publicClient, executor }) => {
|
|
1113
|
+
if (index !== swapStepIndex) {
|
|
1114
|
+
return publicClient.estimateGas({
|
|
1115
|
+
to: step.to,
|
|
1116
|
+
data: step.data,
|
|
1117
|
+
value: step.value,
|
|
1118
|
+
account: executor
|
|
1119
|
+
});
|
|
1740
1120
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1121
|
+
const r = await estimateUniswapRouterSwapGas({
|
|
1122
|
+
publicClient,
|
|
1123
|
+
executor,
|
|
1124
|
+
to: toRouter,
|
|
1125
|
+
data: dataHex,
|
|
1126
|
+
value: valueWei,
|
|
1127
|
+
swapRecord,
|
|
1128
|
+
useCustomGas: args.useCustomGas,
|
|
1129
|
+
chainDetail: args.chainDetail
|
|
1130
|
+
});
|
|
1131
|
+
gasBuildSource = r.source;
|
|
1132
|
+
estimateGasError = r.estimateGasError;
|
|
1133
|
+
swapBaseGasUnits = r.baseGasUnits;
|
|
1134
|
+
return r.baseGasUnits;
|
|
1135
|
+
},
|
|
1136
|
+
buildBatchMeta: ({ index }) => {
|
|
1137
|
+
if (index === 0) {
|
|
1138
|
+
return {
|
|
1139
|
+
signatureText: JSON.stringify({
|
|
1140
|
+
kind: "UniswapV4",
|
|
1141
|
+
name: "ERC20.approve",
|
|
1142
|
+
to: usePermit2Triple ? "allowance hub" : "dispatcher(swap.to)",
|
|
1143
|
+
function: "approve(address spender, uint256 amount)",
|
|
1144
|
+
spender: erc20ApproveSpender,
|
|
1145
|
+
amountWei: approveAmountWei.toString()
|
|
1146
|
+
}),
|
|
1147
|
+
evm: {
|
|
1148
|
+
type: usePermit2Triple ? "uniswap_v4_skip_permit2_approve" : "uniswap_v4_skip_permit2_dispatcher_approve",
|
|
1149
|
+
version: 1,
|
|
1150
|
+
chainId: String(args.chainId),
|
|
1151
|
+
...usePermit2Triple ? { permit2: PERMIT2_ADDRESS } : { dispatcher: toRouter }
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1761
1154
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1155
|
+
if (usePermit2Triple && index === 1) {
|
|
1156
|
+
return {
|
|
1157
|
+
signatureText: JSON.stringify({
|
|
1158
|
+
kind: "UniswapV4",
|
|
1159
|
+
name: "AllowanceHub.approve",
|
|
1160
|
+
function: "approve(address token, address spender, uint160 amount, uint48 expiration)",
|
|
1161
|
+
token: tokenIn,
|
|
1162
|
+
spender: permit2Spender,
|
|
1163
|
+
amountWei: approveAmountWei.toString(),
|
|
1164
|
+
expiration: expiration48.toString()
|
|
1165
|
+
}),
|
|
1166
|
+
evm: {
|
|
1167
|
+
type: "uniswap_v4_skip_permit2_permit2_approve",
|
|
1168
|
+
version: 1,
|
|
1169
|
+
chainId: String(args.chainId),
|
|
1170
|
+
permit2: PERMIT2_ADDRESS,
|
|
1171
|
+
permit2Spender
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
signatureText: JSON.stringify({
|
|
1177
|
+
kind: "UniswapV4",
|
|
1178
|
+
name: "UniversalRouter.execute",
|
|
1179
|
+
note: `Calldata from Trade API POST /swap; signed tx hash in messageHashes[${swapMsgIndex}].`
|
|
1180
|
+
}),
|
|
1181
|
+
evm: { type: "uniswap_v4_swap_tx", version: 1, chainId: String(args.chainId) },
|
|
1182
|
+
uniswapV4: buildSwapAudit()
|
|
1183
|
+
};
|
|
1779
1184
|
}
|
|
1780
|
-
}
|
|
1781
|
-
const extraJSON = JSON.stringify(extraPayload);
|
|
1782
|
-
const firstSigText = batchMeta[0].signatureText;
|
|
1783
|
-
const bodyForSign = {
|
|
1784
|
-
keyList,
|
|
1785
|
-
pubKey: ph,
|
|
1786
|
-
msgHash: messageHashes[0],
|
|
1787
|
-
msgRaw: approveMsgRawNo0x,
|
|
1788
|
-
messageHashes,
|
|
1789
|
-
messageRawBatch,
|
|
1790
|
-
destinationChainID: String(args.chainId),
|
|
1791
|
-
destinationAddress: tokenIn,
|
|
1792
|
-
extraJSON,
|
|
1793
|
-
signatureText: firstSigText,
|
|
1794
|
-
purpose: (() => {
|
|
1795
|
-
const t = args.purposeText.trim();
|
|
1796
|
-
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).";
|
|
1797
|
-
return (t ? `${t}
|
|
1798
|
-
|
|
1799
|
-
` : "") + batchDesc;
|
|
1800
|
-
})(),
|
|
1801
|
-
...firstTxFeePayload,
|
|
1802
|
-
proposalTxParams: proposalTxParamsBatch
|
|
1803
|
-
};
|
|
1804
|
-
if (valueWei > 0n) {
|
|
1805
|
-
bodyForSign.value = valueWei.toString();
|
|
1806
|
-
}
|
|
1807
|
-
if (clientId) bodyForSign.clientId = clientId;
|
|
1808
|
-
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
1185
|
+
});
|
|
1809
1186
|
}
|
|
1810
1187
|
|
|
1811
1188
|
// src/protocols/evm/uniswap-v4/swap.ts
|
|
@@ -2234,357 +1611,34 @@ var curveDao = {
|
|
|
2234
1611
|
loadSession: loadFullCurveSessionForRpc
|
|
2235
1612
|
};
|
|
2236
1613
|
|
|
2237
|
-
// src/agent/commonParamDocs.ts
|
|
2238
|
-
var EVM_COMMON_PARAM_DOCS = {
|
|
2239
|
-
keyGen: {
|
|
2240
|
-
type: "object",
|
|
2241
|
-
required: true,
|
|
2242
|
-
description: "MPC key slice: { pubkeyhex: string (required), keylist: string[], ClientKeys?: Record<string,string> }. Used for pubKey/keyList on POST /multiSignRequest."
|
|
2243
|
-
},
|
|
2244
|
-
purposeText: {
|
|
2245
|
-
type: "string",
|
|
2246
|
-
required: true,
|
|
2247
|
-
description: "Human-readable purpose for the sign request. Stored in bodyForSign.purpose (may be appended with an automatic batch suffix)."
|
|
2248
|
-
},
|
|
2249
|
-
useCustomGas: {
|
|
2250
|
-
type: "boolean",
|
|
2251
|
-
required: true,
|
|
2252
|
-
description: "When true, apply chain gas settings from chainDetail / customGasChainDetails instead of raw RPC estimates only."
|
|
2253
|
-
},
|
|
2254
|
-
chainId: {
|
|
2255
|
-
type: "number",
|
|
2256
|
-
required: true,
|
|
2257
|
-
description: "EVM chain id (decimal). Becomes destinationChainID on the sign request."
|
|
2258
|
-
},
|
|
2259
|
-
rpcUrl: {
|
|
2260
|
-
type: "string",
|
|
2261
|
-
required: true,
|
|
2262
|
-
description: "HTTPS JSON-RPC URL for gas estimation, nonce, and allowance reads."
|
|
2263
|
-
},
|
|
2264
|
-
executorAddress: {
|
|
2265
|
-
type: "address",
|
|
2266
|
-
required: true,
|
|
2267
|
-
description: "MPC wallet address (from keyGen ethereumaddress) \u2014 tx sender for estimates and approvals."
|
|
2268
|
-
},
|
|
2269
|
-
chainDetail: {
|
|
2270
|
-
type: "object",
|
|
2271
|
-
required: true,
|
|
2272
|
-
description: "Optional gas config: { legacy?, gasLimit?, gasMultiplier?, gasPrice?, baseFee?, priorityFee?, baseFeeMultiplier? }."
|
|
2273
|
-
},
|
|
2274
|
-
customGasChainDetails: {
|
|
2275
|
-
type: "object",
|
|
2276
|
-
required: false,
|
|
2277
|
-
description: "Snapshot written to extraJSON.customGasChainDetails when useCustomGas is true."
|
|
2278
|
-
}
|
|
2279
|
-
};
|
|
2280
|
-
var MULTISIGN_OUTPUT_DOC = {
|
|
2281
|
-
description: "Unsigned mpc-auth multiSignRequest payload. The caller must sign messageToSign (MetaMask personal_sign or Ed25519) and POST { ...bodyForSign, clientSig, signedMessage: messageToSign } to /multiSignRequest.",
|
|
2282
|
-
fields: {
|
|
2283
|
-
bodyForSign: {
|
|
2284
|
-
type: "object",
|
|
2285
|
-
description: "POST body fields without clientSig: keyList, pubKey, msgHash, msgRaw, destinationChainID, purpose, extraJSON, proposalTxParams (batch), messageHashes/messageRawBatch when N>1 txs."
|
|
2286
|
-
},
|
|
2287
|
-
messageToSign: {
|
|
2288
|
-
type: "string",
|
|
2289
|
-
description: "JSON.stringify(bodyForSign) \u2014 exact string to sign before adding clientSig."
|
|
2290
|
-
}
|
|
2291
|
-
}
|
|
2292
|
-
};
|
|
2293
|
-
var MANAGEMENT_SIG_DOC = {
|
|
2294
|
-
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.",
|
|
2295
|
-
fields: {
|
|
2296
|
-
nonce: {
|
|
2297
|
-
type: "number",
|
|
2298
|
-
description: "From GET /getPublicMgtKeyNonce (Ed25519) or GET /getNodeMgtKeyNonce (Ethereum NodeMgtKey)."
|
|
2299
|
-
},
|
|
2300
|
-
clientSig: {
|
|
2301
|
-
type: "string",
|
|
2302
|
-
description: "Management signature; empty string in the message to sign."
|
|
2303
|
-
},
|
|
2304
|
-
nodeKey: {
|
|
2305
|
-
type: "string",
|
|
2306
|
-
description: "Required. 128-hex MPC node id from GET /getNodeKey (no 0x prefix)."
|
|
2307
|
-
}
|
|
2308
|
-
},
|
|
2309
|
-
helpers: {
|
|
2310
|
-
managementSigFields: "Base envelope with clientSig cleared.",
|
|
2311
|
-
buildManagementPostBody: "Spread managementSigFields then endpoint fields.",
|
|
2312
|
-
messageToSignManagementBody: "Canonical JSON string to sign.",
|
|
2313
|
-
withManagementClientSig: "Attach signature to POST body.",
|
|
2314
|
-
fetchNodeKey: "GET /getNodeKey via nodeFetchWithReadAuth.",
|
|
2315
|
-
fetchManagementNonce: "GET nonce for Ed25519 or Ethereum management key."
|
|
2316
|
-
}
|
|
2317
|
-
};
|
|
2318
|
-
|
|
2319
|
-
// src/agent/mcpTools.ts
|
|
2320
|
-
function paramProperties(params, includeCommon = []) {
|
|
2321
|
-
const out = {};
|
|
2322
|
-
for (const k of includeCommon) {
|
|
2323
|
-
const d = EVM_COMMON_PARAM_DOCS[k];
|
|
2324
|
-
if (d) out[k] = { type: d.type, description: d.description };
|
|
2325
|
-
}
|
|
2326
|
-
for (const [k, d] of Object.entries(params)) {
|
|
2327
|
-
out[k] = { type: d.type, description: d.description };
|
|
2328
|
-
}
|
|
2329
|
-
return out;
|
|
2330
|
-
}
|
|
2331
|
-
function requiredKeys(params, includeCommon = []) {
|
|
2332
|
-
const req = [];
|
|
2333
|
-
for (const k of includeCommon) {
|
|
2334
|
-
if (EVM_COMMON_PARAM_DOCS[k]?.required) req.push(k);
|
|
2335
|
-
}
|
|
2336
|
-
for (const [k, d] of Object.entries(params)) {
|
|
2337
|
-
if (d.required) req.push(k);
|
|
2338
|
-
}
|
|
2339
|
-
return req;
|
|
2340
|
-
}
|
|
2341
|
-
var multisignOutputSchema = {
|
|
2342
|
-
type: "object",
|
|
2343
|
-
description: MULTISIGN_OUTPUT_DOC.description,
|
|
2344
|
-
properties: {
|
|
2345
|
-
bodyForSign: {
|
|
2346
|
-
type: "object",
|
|
2347
|
-
description: MULTISIGN_OUTPUT_DOC.fields.bodyForSign.description
|
|
2348
|
-
},
|
|
2349
|
-
messageToSign: {
|
|
2350
|
-
type: "string",
|
|
2351
|
-
description: MULTISIGN_OUTPUT_DOC.fields.messageToSign.description
|
|
2352
|
-
}
|
|
2353
|
-
},
|
|
2354
|
-
required: ["bodyForSign", "messageToSign"]
|
|
2355
|
-
};
|
|
2356
|
-
var MCP_TOOL_DEFINITIONS = [
|
|
2357
|
-
{
|
|
2358
|
-
name: "ctm_uniswap_v4_quote",
|
|
2359
|
-
actionId: "uniswap-v4.quote",
|
|
2360
|
-
protocolId: "uniswap-v4",
|
|
2361
|
-
chainCategory: "evm",
|
|
2362
|
-
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.",
|
|
2363
|
-
prerequisites: ["Chain must be supported by Uniswap V4 (Universal Router map)."],
|
|
2364
|
-
followUp: ["ctm_uniswap_v4_create_swap", "ctm_uniswap_v4_build_swap_multisign"],
|
|
2365
|
-
handler: { importPath: "protocols/evm/uniswap-v4", exportName: "uniswapTradeQuote" },
|
|
2366
|
-
inputSchema: {
|
|
2367
|
-
type: "object",
|
|
2368
|
-
properties: paramProperties({
|
|
2369
|
-
type: { type: "string", required: true, description: "EXACT_INPUT or EXACT_OUTPUT" },
|
|
2370
|
-
amount: { type: "string", required: true, description: "Amount in token-in base units (wei string for ERC-20)" },
|
|
2371
|
-
tokenIn: { type: "address", required: true, description: "Input token; 0x0 for native ETH" },
|
|
2372
|
-
tokenOut: { type: "address", required: true, description: "Output token address" },
|
|
2373
|
-
chainId: { type: "number", required: true, description: "tokenInChainId / same-chain default" },
|
|
2374
|
-
uniswapApiKey: { type: "string", required: true, description: "Uniswap Trade API x-api-key" },
|
|
2375
|
-
swapper: { type: "address", required: false, description: "MPC executor; omit if keyGen + managementNodeUrl provided" },
|
|
2376
|
-
slippage: { type: "number", required: false, description: "Slippage percent; omit for API auto slippage" }
|
|
2377
|
-
}),
|
|
2378
|
-
required: requiredKeys({
|
|
2379
|
-
type: { type: "string", required: true, description: "" },
|
|
2380
|
-
amount: { type: "string", required: true, description: "" },
|
|
2381
|
-
tokenIn: { type: "address", required: true, description: "" },
|
|
2382
|
-
tokenOut: { type: "address", required: true, description: "" },
|
|
2383
|
-
chainId: { type: "number", required: true, description: "" },
|
|
2384
|
-
uniswapApiKey: { type: "string", required: true, description: "" }
|
|
2385
|
-
})
|
|
2386
|
-
},
|
|
2387
|
-
outputSchema: {
|
|
2388
|
-
type: "object",
|
|
2389
|
-
description: "Full Uniswap POST /quote JSON (includes nested quote object with input/output amounts)."
|
|
2390
|
-
}
|
|
2391
|
-
},
|
|
2392
|
-
{
|
|
2393
|
-
name: "ctm_uniswap_v4_create_swap",
|
|
2394
|
-
actionId: "uniswap-v4.create-swap",
|
|
2395
|
-
protocolId: "uniswap-v4",
|
|
2396
|
-
chainCategory: "evm",
|
|
2397
|
-
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.",
|
|
2398
|
-
prerequisites: ["ctm_uniswap_v4_quote output (fullQuoteFromPermit)"],
|
|
2399
|
-
followUp: ["ctm_uniswap_v4_build_swap_multisign"],
|
|
2400
|
-
handler: { importPath: "protocols/evm/uniswap-v4", exportName: "uniswapCreateSwap" },
|
|
2401
|
-
inputSchema: {
|
|
2402
|
-
type: "object",
|
|
2403
|
-
properties: paramProperties({
|
|
2404
|
-
uniswapApiKey: { type: "string", required: true, description: "Uniswap Trade API key" },
|
|
2405
|
-
fullQuoteFromPermit: { type: "object", required: true, description: "Full quote JSON from ctm_uniswap_v4_quote" },
|
|
2406
|
-
swapTransactionDeadlineUnix: {
|
|
2407
|
-
type: "number",
|
|
2408
|
-
required: false,
|
|
2409
|
-
description: "On-chain deadline unix seconds; default ~30 min from now"
|
|
2410
|
-
},
|
|
2411
|
-
useServerProxy: {
|
|
2412
|
-
type: "boolean",
|
|
2413
|
-
required: false,
|
|
2414
|
-
description: "Set false in Node/agents; true only in browser via Next API route"
|
|
2415
|
-
}
|
|
2416
|
-
}),
|
|
2417
|
-
required: requiredKeys({
|
|
2418
|
-
uniswapApiKey: { type: "string", required: true, description: "" },
|
|
2419
|
-
fullQuoteFromPermit: { type: "object", required: true, description: "" }
|
|
2420
|
-
})
|
|
2421
|
-
},
|
|
2422
|
-
outputSchema: {
|
|
2423
|
-
type: "object",
|
|
2424
|
-
description: "{ swap: TransactionRequest, requestId?, gasFee? }"
|
|
2425
|
-
}
|
|
2426
|
-
},
|
|
2427
|
-
{
|
|
2428
|
-
name: "ctm_uniswap_v4_build_swap_multisign",
|
|
2429
|
-
actionId: "uniswap-v4.swap-exact-input",
|
|
2430
|
-
protocolId: "uniswap-v4",
|
|
2431
|
-
chainCategory: "evm",
|
|
2432
|
-
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.",
|
|
2433
|
-
prerequisites: [
|
|
2434
|
-
"ctm_uniswap_v4_create_swap output",
|
|
2435
|
-
"keyGen with pubkeyhex",
|
|
2436
|
-
"executorAddress matching MPC wallet",
|
|
2437
|
-
"RPC URL and chainDetail from node chain config"
|
|
2438
|
-
],
|
|
2439
|
-
followUp: ["Sign messageToSign", "POST /multiSignRequest with clientSig and signedMessage"],
|
|
2440
|
-
handler: { importPath: "protocols/evm/uniswap-v4", exportName: "buildEvmMultisignBodyUniswapV4SkipPermit2Batch" },
|
|
2441
|
-
inputSchema: {
|
|
2442
|
-
type: "object",
|
|
2443
|
-
properties: paramProperties(
|
|
2444
|
-
{
|
|
2445
|
-
tokenIn: { type: "address", required: true, description: "Token in; 0x0 for native ETH" },
|
|
2446
|
-
swap: { type: "object", required: true, description: "swap field from create_swap response" },
|
|
2447
|
-
createSwapResponse: { type: "object", required: true, description: "Full create_swap response" },
|
|
2448
|
-
fullQuoteSnapshot: { type: "object", required: true, description: "Quote JSON used for the swap" },
|
|
2449
|
-
swapDeadlineUnix: { type: "number", required: true, description: "Same deadline passed to create_swap" },
|
|
2450
|
-
slippagePercent: { type: "number", required: false, description: "Extra approve headroom for EXACT_OUTPUT" }
|
|
2451
|
-
},
|
|
2452
|
-
["keyGen", "purposeText", "useCustomGas", "chainId", "rpcUrl", "executorAddress", "chainDetail", "customGasChainDetails"]
|
|
2453
|
-
),
|
|
2454
|
-
required: requiredKeys(
|
|
2455
|
-
{
|
|
2456
|
-
tokenIn: { type: "address", required: true, description: "" },
|
|
2457
|
-
swap: { type: "object", required: true, description: "" },
|
|
2458
|
-
createSwapResponse: { type: "object", required: true, description: "" },
|
|
2459
|
-
fullQuoteSnapshot: { type: "object", required: true, description: "" },
|
|
2460
|
-
swapDeadlineUnix: { type: "number", required: true, description: "" }
|
|
2461
|
-
},
|
|
2462
|
-
["keyGen", "purposeText", "useCustomGas", "chainId", "rpcUrl", "executorAddress", "chainDetail"]
|
|
2463
|
-
)
|
|
2464
|
-
},
|
|
2465
|
-
outputSchema: multisignOutputSchema
|
|
2466
|
-
},
|
|
2467
|
-
{
|
|
2468
|
-
name: "ctm_curve_dao_build_swap_multisign",
|
|
2469
|
-
actionId: "curve-dao.swap",
|
|
2470
|
-
protocolId: "curve-dao",
|
|
2471
|
-
chainCategory: "evm",
|
|
2472
|
-
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.",
|
|
2473
|
-
prerequisites: ["keyGen", "executorAddress", "tokenIn/tokenOut/amountHuman/slippage", "RPC URL"],
|
|
2474
|
-
followUp: ["Sign messageToSign", "POST /multiSignRequest with clientSig and signedMessage"],
|
|
2475
|
-
handler: { importPath: "protocols/evm/curve-dao", exportName: "buildEvmMultisignBodyCurveDaoBatch" },
|
|
2476
|
-
inputSchema: {
|
|
2477
|
-
type: "object",
|
|
2478
|
-
properties: paramProperties(
|
|
2479
|
-
{
|
|
2480
|
-
tokenIn: { type: "address", required: true, description: "ERC-20 sold (native in uses WETH path in UI)" },
|
|
2481
|
-
tokenOut: { type: "string", required: true, description: "Output token or 0xeeee\u2026 native placeholder" },
|
|
2482
|
-
amountHuman: { type: "string", required: true, description: "Human-readable amount of tokenIn" },
|
|
2483
|
-
slippagePercent: { type: "number", required: true, description: "Slippage 0\u2013100 exclusive" }
|
|
2484
|
-
},
|
|
2485
|
-
["keyGen", "purposeText", "useCustomGas", "chainId", "rpcUrl", "executorAddress", "chainDetail", "customGasChainDetails"]
|
|
2486
|
-
),
|
|
2487
|
-
required: requiredKeys(
|
|
2488
|
-
{
|
|
2489
|
-
tokenIn: { type: "address", required: true, description: "" },
|
|
2490
|
-
tokenOut: { type: "string", required: true, description: "" },
|
|
2491
|
-
amountHuman: { type: "string", required: true, description: "" },
|
|
2492
|
-
slippagePercent: { type: "number", required: true, description: "" }
|
|
2493
|
-
},
|
|
2494
|
-
["keyGen", "purposeText", "useCustomGas", "chainId", "rpcUrl", "executorAddress", "chainDetail"]
|
|
2495
|
-
)
|
|
2496
|
-
},
|
|
2497
|
-
outputSchema: multisignOutputSchema
|
|
2498
|
-
}
|
|
2499
|
-
];
|
|
2500
|
-
function getAgentCatalogForMcp() {
|
|
2501
|
-
return {
|
|
2502
|
-
tools: MCP_TOOL_DEFINITIONS,
|
|
2503
|
-
protocols: getProtocolModules(),
|
|
2504
|
-
commonParams: EVM_COMMON_PARAM_DOCS,
|
|
2505
|
-
multisignOutput: MULTISIGN_OUTPUT_DOC,
|
|
2506
|
-
managementSig: MANAGEMENT_SIG_DOC,
|
|
2507
|
-
workflow: {
|
|
2508
|
-
evmSwapTypical: [
|
|
2509
|
-
"1. Quote (protocol-specific API if needed)",
|
|
2510
|
-
"2. Build protocol calldata (e.g. create_swap)",
|
|
2511
|
-
"3. build_*_multisign \u2192 { bodyForSign, messageToSign }",
|
|
2512
|
-
"4. Sign messageToSign (MetaMask or Ed25519)",
|
|
2513
|
-
"5. POST /multiSignRequest with clientSig and signedMessage"
|
|
2514
|
-
],
|
|
2515
|
-
managementPostTypical: [
|
|
2516
|
-
"1. GET /getNodeKey \u2192 nodeKey (128 hex)",
|
|
2517
|
-
"2. GET /getPublicMgtKeyNonce or /getNodeMgtKeyNonce \u2192 nonce",
|
|
2518
|
-
"3. buildManagementPostBody(nonce, nodeKey, { \u2026endpoint fields })",
|
|
2519
|
-
"4. messageToSignManagementBody(body) \u2192 sign \u2192 withManagementClientSig(body, sig)",
|
|
2520
|
-
"5. POST management route with signed body"
|
|
2521
|
-
]
|
|
2522
|
-
}
|
|
2523
|
-
};
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
|
-
// src/agent/catalog.ts
|
|
2527
|
-
registerProtocolModule(uniswapV4ProtocolModule);
|
|
2528
|
-
registerProtocolModule(curveDaoProtocolModule);
|
|
2529
|
-
function getAgentCatalog() {
|
|
2530
|
-
return {
|
|
2531
|
-
protocols: getProtocolModules(),
|
|
2532
|
-
byCategory: {
|
|
2533
|
-
evm: getActionsByChainCategory("evm"),
|
|
2534
|
-
solana: getActionsByChainCategory("solana"),
|
|
2535
|
-
near: getActionsByChainCategory("near")
|
|
2536
|
-
},
|
|
2537
|
-
uniswapV4: uniswapV4ProtocolModule,
|
|
2538
|
-
curveDao: curveDaoProtocolModule,
|
|
2539
|
-
/** Prefer getAgentCatalogForMcp() or getMcpToolDefinitions() for MCP servers. */
|
|
2540
|
-
mcp: getAgentCatalogForMcp()
|
|
2541
|
-
};
|
|
2542
|
-
}
|
|
2543
|
-
|
|
2544
1614
|
// src/index.ts
|
|
2545
1615
|
registerProtocolModule(uniswapV4ProtocolModule);
|
|
2546
1616
|
registerProtocolModule(curveDaoProtocolModule);
|
|
2547
1617
|
|
|
1618
|
+
Object.defineProperty(exports, "firstClientIdFromKeyGen", {
|
|
1619
|
+
enumerable: true,
|
|
1620
|
+
get: function () { return continuumNodeSdk.getClientIdFromKeyGenResult; }
|
|
1621
|
+
});
|
|
2548
1622
|
exports.NEAR_CHAIN_CATEGORY = NEAR_CHAIN_CATEGORY;
|
|
2549
1623
|
exports.SOLANA_CHAIN_CATEGORY = SOLANA_CHAIN_CATEGORY;
|
|
2550
|
-
exports.alignEip1559FeesWithLatestBase = alignEip1559FeesWithLatestBase;
|
|
2551
1624
|
exports.buildEvmMultisignBatch = buildEvmMultisignBatch;
|
|
2552
|
-
exports.buildManagementPostBody = buildManagementPostBody;
|
|
2553
|
-
exports.chainSnapshotForCustomGasExtraJSON = chainSnapshotForCustomGasExtraJSON;
|
|
2554
|
-
exports.composeFeePayloadToTxParams = composeFeePayloadToTxParams;
|
|
2555
1625
|
exports.coreChainCategoryModule = coreChainCategoryModule;
|
|
2556
1626
|
exports.curveDao = curveDao;
|
|
2557
1627
|
exports.curveDaoProtocolModule = curveDaoProtocolModule;
|
|
2558
1628
|
exports.evmChainCategoryModule = evmChainCategoryModule;
|
|
2559
|
-
exports.fetchChainFeeParams = fetchChainFeeParams;
|
|
2560
|
-
exports.fetchManagementNonce = fetchManagementNonce;
|
|
2561
|
-
exports.fetchNodeKey = fetchNodeKey;
|
|
2562
1629
|
exports.finalizeMultisign = finalizeMultisign;
|
|
2563
|
-
exports.firstClientIdFromKeyGen = firstClientIdFromKeyGen;
|
|
2564
|
-
exports.gasLimitFromEstimateAndChainConfig = gasLimitFromEstimateAndChainConfig;
|
|
2565
1630
|
exports.getActionsByChainCategory = getActionsByChainCategory;
|
|
2566
|
-
exports.getAgentCatalog = getAgentCatalog;
|
|
2567
1631
|
exports.getProtocolModule = getProtocolModule;
|
|
2568
1632
|
exports.getProtocolModules = getProtocolModules;
|
|
2569
|
-
exports.gweiToDecimalString = gweiToDecimalString;
|
|
2570
1633
|
exports.isEvmNativeToken = isEvmNativeToken;
|
|
2571
|
-
exports.keyListFromKeyGen = keyListFromKeyGen;
|
|
2572
|
-
exports.managementSigFields = managementSigFields;
|
|
2573
1634
|
exports.matchEvmTokenKind = matchEvmTokenKind;
|
|
2574
1635
|
exports.mergePurposeText = mergePurposeText;
|
|
2575
|
-
exports.messageToSignManagementBody = messageToSignManagementBody;
|
|
2576
1636
|
exports.nearChainCategoryModule = nearChainCategoryModule;
|
|
2577
|
-
exports.nodeFetchWithReadAuth = nodeFetchWithReadAuth;
|
|
2578
|
-
exports.normalizeManagementNodeKey = normalizeManagementNodeKey;
|
|
2579
1637
|
exports.parseEvmChainIdToNumber = parseEvmChainIdToNumber;
|
|
2580
|
-
exports.proposalTxParamsToFeeSnapshot = proposalTxParamsToFeeSnapshot;
|
|
2581
1638
|
exports.registerProtocolModule = registerProtocolModule;
|
|
2582
|
-
exports.requirePubKeyHex = requirePubKeyHex;
|
|
2583
1639
|
exports.routerSwapGasLimitFromEstimate = routerSwapGasLimitFromEstimate;
|
|
2584
1640
|
exports.solanaChainCategoryModule = solanaChainCategoryModule;
|
|
2585
|
-
exports.triggerTxParamsFromComposeBody = triggerTxParamsFromComposeBody;
|
|
2586
1641
|
exports.uniswapV4 = uniswapV4;
|
|
2587
1642
|
exports.uniswapV4ProtocolModule = uniswapV4ProtocolModule;
|
|
2588
|
-
exports.withManagementClientSig = withManagementClientSig;
|
|
2589
1643
|
//# sourceMappingURL=index.cjs.map
|
|
2590
1644
|
//# sourceMappingURL=index.cjs.map
|