@continuumdao/ctm-mpc-defi 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -78
- package/dist/agent/catalog.cjs +563 -5
- package/dist/agent/catalog.cjs.map +1 -1
- package/dist/agent/catalog.d.ts +166 -20
- package/dist/agent/catalog.js +551 -7
- 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 +13 -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 +79 -224
- package/dist/chains/evm/index.cjs.map +1 -1
- package/dist/chains/evm/index.d.ts +26 -26
- package/dist/chains/evm/index.js +69 -209
- 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 +68 -106
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.ts +21 -36
- package/dist/core/index.js +57 -96
- 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 +356 -1855
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -11
- package/dist/index.js +332 -1826
- package/dist/index.js.map +1 -1
- package/dist/protocols/evm/aave-v4/index.cjs +1152 -669
- package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
- package/dist/protocols/evm/aave-v4/index.d.ts +418 -3
- package/dist/protocols/evm/aave-v4/index.js +1126 -670
- package/dist/protocols/evm/aave-v4/index.js.map +1 -1
- package/dist/protocols/evm/curve-dao/index.cjs +257 -131
- package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
- package/dist/protocols/evm/curve-dao/index.d.ts +69 -5
- package/dist/protocols/evm/curve-dao/index.js +242 -124
- package/dist/protocols/evm/curve-dao/index.js.map +1 -1
- package/dist/protocols/evm/ethena/index.cjs +394 -402
- package/dist/protocols/evm/ethena/index.cjs.map +1 -1
- package/dist/protocols/evm/ethena/index.d.ts +47 -3
- package/dist/protocols/evm/ethena/index.js +390 -404
- package/dist/protocols/evm/ethena/index.js.map +1 -1
- package/dist/protocols/evm/euler-v2/index.cjs +2810 -1191
- package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
- package/dist/protocols/evm/euler-v2/index.d.ts +465 -3
- package/dist/protocols/evm/euler-v2/index.js +2761 -1192
- package/dist/protocols/evm/euler-v2/index.js.map +1 -1
- package/dist/protocols/evm/lido/index.cjs +351 -236
- package/dist/protocols/evm/lido/index.cjs.map +1 -1
- package/dist/protocols/evm/lido/index.d.ts +34 -4
- package/dist/protocols/evm/lido/index.js +348 -238
- package/dist/protocols/evm/lido/index.js.map +1 -1
- package/dist/protocols/evm/maple/index.cjs +390 -395
- package/dist/protocols/evm/maple/index.cjs.map +1 -1
- package/dist/protocols/evm/maple/index.d.ts +23 -3
- package/dist/protocols/evm/maple/index.js +390 -397
- package/dist/protocols/evm/maple/index.js.map +1 -1
- package/dist/protocols/evm/sky/index.cjs +454 -232
- package/dist/protocols/evm/sky/index.cjs.map +1 -1
- package/dist/protocols/evm/sky/index.d.ts +57 -3
- package/dist/protocols/evm/sky/index.js +444 -231
- package/dist/protocols/evm/sky/index.js.map +1 -1
- 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 +7 -6
- package/dist/agent/catalog.d.cts +0 -939
- package/dist/chains/evm/index.d.cts +0 -64
- 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 -16
- 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/aave-v4/index.d.cts +0 -500
- package/dist/protocols/evm/curve-dao/index.d.cts +0 -147
- package/dist/protocols/evm/ethena/index.d.cts +0 -161
- package/dist/protocols/evm/euler-v2/index.d.cts +0 -317
- package/dist/protocols/evm/lido/index.d.cts +0 -120
- package/dist/protocols/evm/maple/index.d.cts +0 -109
- package/dist/protocols/evm/sky/index.d.cts +0 -218
- 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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var viem = require('viem');
|
|
4
|
+
var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
|
|
5
|
+
var chains = require('viem/chains');
|
|
4
6
|
|
|
5
7
|
// src/core/registry.ts
|
|
6
8
|
var modules = [];
|
|
@@ -144,101 +146,239 @@ function isEvmChainInEthenaUsdeList(chainId) {
|
|
|
144
146
|
return usdeTokenAddressOnEvmChain(chainId) != null;
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
// src/core/
|
|
148
|
-
function
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
// src/core/purpose.ts
|
|
150
|
+
function mergePurposeText(purposeText, purposeSuffix) {
|
|
151
|
+
const t = purposeText.trim();
|
|
152
|
+
const suffix = (purposeSuffix ?? "").trim();
|
|
153
|
+
if (!suffix) return t;
|
|
154
|
+
return t ? `${t}
|
|
155
|
+
|
|
156
|
+
${suffix}` : suffix;
|
|
155
157
|
}
|
|
156
158
|
|
|
157
|
-
// src/
|
|
158
|
-
function
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
// src/core/envelope.ts
|
|
160
|
+
function finalizeMultisign(input) {
|
|
161
|
+
const { keyGen, destinationChainID, legs } = input;
|
|
162
|
+
if (legs.length === 0) {
|
|
163
|
+
throw new Error("finalizeMultisign requires at least one leg");
|
|
164
|
+
}
|
|
165
|
+
const ph = (keyGen.pubkeyhex ?? "").trim();
|
|
166
|
+
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
167
|
+
const keyList = keyGen.keylist ?? [];
|
|
168
|
+
const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
|
|
169
|
+
const first = legs[0];
|
|
170
|
+
const messageHashes = legs.map((l) => l.msgHash);
|
|
171
|
+
const messageRawBatch = legs.map((l) => l.msgRaw);
|
|
172
|
+
const batchMeta = legs.map((l) => ({
|
|
173
|
+
destinationAddress: l.destinationAddress,
|
|
174
|
+
signatureText: l.signatureText,
|
|
175
|
+
...l.audit
|
|
176
|
+
}));
|
|
177
|
+
const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
|
|
178
|
+
const extraPayload = {
|
|
179
|
+
batchMeta,
|
|
180
|
+
...input.extraJSON ?? {}
|
|
181
|
+
};
|
|
182
|
+
const extraJSON = JSON.stringify(extraPayload);
|
|
183
|
+
const bodyForSign = {
|
|
184
|
+
keyList,
|
|
185
|
+
pubKey: ph,
|
|
186
|
+
msgHash: messageHashes[0],
|
|
187
|
+
msgRaw: first.msgRaw,
|
|
188
|
+
destinationChainID,
|
|
189
|
+
destinationAddress: input.destinationAddress ?? first.destinationAddress,
|
|
190
|
+
extraJSON,
|
|
191
|
+
signatureText: first.signatureText,
|
|
192
|
+
purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
|
|
193
|
+
...first.feeSnapshot
|
|
194
|
+
};
|
|
195
|
+
if (legs.length > 1) {
|
|
196
|
+
bodyForSign.messageHashes = messageHashes;
|
|
197
|
+
bodyForSign.messageRawBatch = messageRawBatch;
|
|
198
|
+
}
|
|
199
|
+
if (proposalTxParams.length > 0) {
|
|
200
|
+
bodyForSign.proposalTxParams = proposalTxParams;
|
|
161
201
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
202
|
+
const valueWei = first.valueWei;
|
|
203
|
+
if (valueWei != null && valueWei > 0n) {
|
|
204
|
+
bodyForSign.value = valueWei.toString();
|
|
205
|
+
}
|
|
206
|
+
if (clientId) bodyForSign.clientId = clientId;
|
|
207
|
+
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
164
208
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
209
|
+
function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
|
|
210
|
+
if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
|
|
211
|
+
return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
|
|
212
|
+
}
|
|
213
|
+
return (estimatedGas * 12n + 9n) / 10n;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/chains/evm/buildBatch.ts
|
|
217
|
+
async function buildEvmMultisignBatch(args) {
|
|
218
|
+
const { context, steps } = args;
|
|
219
|
+
const {
|
|
220
|
+
chainId,
|
|
221
|
+
rpcUrl,
|
|
222
|
+
executorAddress,
|
|
223
|
+
chainDetail,
|
|
224
|
+
useCustomGas,
|
|
225
|
+
customGasChainDetails,
|
|
226
|
+
keyGen,
|
|
227
|
+
purposeText
|
|
228
|
+
} = context;
|
|
229
|
+
if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
|
|
230
|
+
const ch = viem.defineChain({
|
|
231
|
+
id: chainId,
|
|
232
|
+
name: "Destination",
|
|
173
233
|
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
174
|
-
rpcUrls: { default: { http: [
|
|
234
|
+
rpcUrls: { default: { http: [rpcUrl] } }
|
|
175
235
|
});
|
|
176
|
-
const publicClient = viem.createPublicClient({
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
});
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
236
|
+
const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
|
|
237
|
+
const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
|
|
238
|
+
const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
|
|
239
|
+
const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
240
|
+
const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
|
|
241
|
+
const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
|
|
242
|
+
const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
|
|
243
|
+
const executor = viem.getAddress(executorAddress);
|
|
244
|
+
const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
|
|
245
|
+
const legs = [];
|
|
246
|
+
for (let i = 0; i < steps.length; i++) {
|
|
247
|
+
const step = steps[i];
|
|
248
|
+
const currentNonce = baseNonce + i;
|
|
249
|
+
let estimatedGas;
|
|
250
|
+
if (args.estimateGasForStep) {
|
|
251
|
+
estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
|
|
252
|
+
} else {
|
|
253
|
+
try {
|
|
254
|
+
estimatedGas = await publicClient.estimateGas({
|
|
255
|
+
to: step.to,
|
|
256
|
+
data: step.data,
|
|
257
|
+
value: step.value,
|
|
258
|
+
account: executor
|
|
259
|
+
});
|
|
260
|
+
} catch {
|
|
261
|
+
estimatedGas = step.fallbackGas ?? 100000n;
|
|
262
|
+
}
|
|
190
263
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
264
|
+
let gasLimitI;
|
|
265
|
+
if (args.resolveGasLimit) {
|
|
266
|
+
gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient });
|
|
267
|
+
} else if (step.routerSwap) {
|
|
268
|
+
gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
|
|
269
|
+
} else {
|
|
270
|
+
gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
197
271
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
272
|
+
let proposalTxParams;
|
|
273
|
+
let feeSnapshot;
|
|
274
|
+
let serialized;
|
|
275
|
+
if (legacy) {
|
|
276
|
+
let gasPriceWei = await publicClient.getGasPrice();
|
|
277
|
+
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
278
|
+
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
279
|
+
}
|
|
280
|
+
if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
|
|
281
|
+
const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
|
|
282
|
+
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
283
|
+
}
|
|
284
|
+
serialized = viem.serializeTransaction({
|
|
285
|
+
type: "legacy",
|
|
286
|
+
to: step.to,
|
|
287
|
+
data: step.data,
|
|
288
|
+
value: step.value,
|
|
289
|
+
gas: gasLimitI,
|
|
290
|
+
gasPrice: gasPriceWei,
|
|
291
|
+
nonce: currentNonce,
|
|
292
|
+
chainId
|
|
293
|
+
});
|
|
294
|
+
proposalTxParams = {
|
|
295
|
+
nonce: currentNonce,
|
|
296
|
+
gasLimit: gasLimitI.toString(),
|
|
297
|
+
txType: "legacy",
|
|
298
|
+
gasPrice: gasPriceWei.toString()
|
|
299
|
+
};
|
|
300
|
+
feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
|
|
301
|
+
} else {
|
|
302
|
+
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
303
|
+
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
304
|
+
const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
|
|
305
|
+
const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
|
|
306
|
+
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
307
|
+
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
308
|
+
const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
|
|
309
|
+
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
310
|
+
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
311
|
+
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
312
|
+
let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
|
|
313
|
+
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
314
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
315
|
+
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
316
|
+
}
|
|
317
|
+
({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
|
|
318
|
+
maxFeePerGas,
|
|
319
|
+
maxPriorityFeePerGas,
|
|
320
|
+
latestBaseFeeWei
|
|
321
|
+
));
|
|
322
|
+
serialized = viem.serializeTransaction({
|
|
323
|
+
type: "eip1559",
|
|
324
|
+
to: step.to,
|
|
325
|
+
data: step.data,
|
|
326
|
+
value: step.value,
|
|
327
|
+
gas: gasLimitI,
|
|
328
|
+
maxFeePerGas,
|
|
329
|
+
maxPriorityFeePerGas,
|
|
330
|
+
nonce: currentNonce,
|
|
331
|
+
chainId
|
|
332
|
+
});
|
|
333
|
+
proposalTxParams = {
|
|
334
|
+
nonce: currentNonce,
|
|
335
|
+
gasLimit: gasLimitI.toString(),
|
|
336
|
+
txType: "eip1559",
|
|
337
|
+
maxFeePerGas: maxFeePerGas.toString(),
|
|
338
|
+
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
339
|
+
};
|
|
340
|
+
feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
|
|
341
|
+
}
|
|
342
|
+
const h = viem.keccak256(serialized);
|
|
343
|
+
const msgHash = h.startsWith("0x") ? h.slice(2) : h;
|
|
344
|
+
const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
|
|
345
|
+
legs.push({
|
|
346
|
+
msgHash,
|
|
347
|
+
msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
|
|
348
|
+
destinationAddress: step.to,
|
|
349
|
+
signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
|
|
350
|
+
audit: batchMetaExtra,
|
|
351
|
+
feeSnapshot: i === 0 ? feeSnapshot : {},
|
|
352
|
+
proposalTxParams,
|
|
353
|
+
valueWei: i === 0 ? step.value : void 0
|
|
354
|
+
});
|
|
355
|
+
if (i === 0 && args.firstMsgRawNo0x != null) {
|
|
356
|
+
legs[0].msgRaw = args.firstMsgRawNo0x;
|
|
212
357
|
}
|
|
213
358
|
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
359
|
+
const extraJSON = {};
|
|
360
|
+
if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
|
|
361
|
+
extraJSON.customGasChainDetails = customGasChainDetails;
|
|
362
|
+
}
|
|
363
|
+
const result = finalizeMultisign({
|
|
364
|
+
keyGen,
|
|
365
|
+
purposeText,
|
|
366
|
+
purposeSuffix: args.purposeSuffix,
|
|
367
|
+
destinationChainID: String(chainId),
|
|
368
|
+
destinationAddress: args.destinationAddress ?? steps[0].to,
|
|
369
|
+
legs,
|
|
370
|
+
extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
|
|
371
|
+
});
|
|
372
|
+
const pv = args.payableValueWei;
|
|
373
|
+
if (pv != null && pv > 0n) {
|
|
374
|
+
result.bodyForSign.value = pv.toString();
|
|
223
375
|
}
|
|
224
|
-
return
|
|
376
|
+
return result;
|
|
225
377
|
}
|
|
226
|
-
function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
|
|
227
|
-
return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// src/protocols/evm/ethena/multisign.ts
|
|
231
378
|
var AAVE_ERC20_APPROVE_FALLBACK = 100000n;
|
|
232
379
|
var ETHENA_SUSDE_DEPOSIT_GET_SIG_GAS_FALLBACK = 1200000n;
|
|
233
380
|
var ETHENA_SUSDE_DEPOSIT_FALLBACK = ETHENA_SUSDE_DEPOSIT_GET_SIG_GAS_FALLBACK;
|
|
234
381
|
var ETHENA_SUSDE_REDEEM_FALLBACK = 1200000n;
|
|
235
|
-
function gweiToDecimalString(n) {
|
|
236
|
-
if (!Number.isFinite(n)) return "0";
|
|
237
|
-
if (n === 0) return "0";
|
|
238
|
-
const s = String(n);
|
|
239
|
-
if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
|
|
240
|
-
return s;
|
|
241
|
-
}
|
|
242
382
|
var erc20AllowanceAbi = viem.parseAbi([
|
|
243
383
|
"function allowance(address owner, address spender) view returns (uint256)",
|
|
244
384
|
"function decimals() view returns (uint8)"
|
|
@@ -295,10 +435,6 @@ async function buildEvmMultisignBodyEthenaUsdeStakeToSusde(args) {
|
|
|
295
435
|
if (args.chainId !== 1) {
|
|
296
436
|
throw new Error("Ethena USDe \u2192 sUSDe stake is only supported on Ethereum mainnet (chain id 1).");
|
|
297
437
|
}
|
|
298
|
-
const ph = (args.keyGen.pubkeyhex ?? "").trim();
|
|
299
|
-
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
300
|
-
const keyList = args.keyGen.keylist ?? [];
|
|
301
|
-
const clientId = firstClientIdFromKeyGen(args.keyGen);
|
|
302
438
|
const usde = viem.getAddress(args.usde);
|
|
303
439
|
const mainnetUsde = viem.getAddress(USDE_ETHEREUM_MAINNET);
|
|
304
440
|
if (usde.toLowerCase() !== mainnetUsde.toLowerCase()) {
|
|
@@ -353,141 +489,58 @@ async function buildEvmMultisignBodyEthenaUsdeStakeToSusde(args) {
|
|
|
353
489
|
args: [amountWei, receiver]
|
|
354
490
|
});
|
|
355
491
|
steps.push({ kind: "deposit", to: susde, data: depositData, value: 0n });
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
}
|
|
388
|
-
const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
389
|
-
if (legacy) {
|
|
390
|
-
let gasPriceWei = await publicClient.getGasPrice();
|
|
391
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
392
|
-
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
393
|
-
}
|
|
394
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
395
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
396
|
-
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
397
|
-
}
|
|
398
|
-
const ser = viem.serializeTransaction({
|
|
399
|
-
type: "legacy",
|
|
400
|
-
to: s.to,
|
|
401
|
-
data: s.data,
|
|
402
|
-
value: s.value,
|
|
403
|
-
gas: gasLimitI,
|
|
404
|
-
gasPrice: gasPriceWei,
|
|
405
|
-
nonce: currentNonce,
|
|
406
|
-
chainId: 1
|
|
407
|
-
});
|
|
408
|
-
const h = viem.keccak256(ser);
|
|
409
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
410
|
-
messageRawBatch.push(ser);
|
|
411
|
-
proposalTxParamsBatch.push({
|
|
412
|
-
nonce: currentNonce,
|
|
413
|
-
gasLimit: gasLimitI.toString(),
|
|
414
|
-
txType: "legacy",
|
|
415
|
-
gasPrice: gasPriceWei.toString()
|
|
416
|
-
});
|
|
417
|
-
if (i === 0) {
|
|
418
|
-
firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
|
|
419
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
420
|
-
}
|
|
421
|
-
} else {
|
|
422
|
-
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
423
|
-
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
424
|
-
const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
425
|
-
const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
426
|
-
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
427
|
-
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
428
|
-
const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
429
|
-
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
430
|
-
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
431
|
-
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
432
|
-
let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
|
|
433
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
434
|
-
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
435
|
-
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
492
|
+
const evmSteps = steps.map((s) => ({
|
|
493
|
+
to: s.to,
|
|
494
|
+
data: s.data,
|
|
495
|
+
value: s.value,
|
|
496
|
+
fallbackGas: s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : ETHENA_SUSDE_DEPOSIT_FALLBACK
|
|
497
|
+
}));
|
|
498
|
+
const n = steps.length;
|
|
499
|
+
const purposeSuffix = n === 1 ? "Ethena: 1-tx \u2014 deposit USDe to sUSDe (allowance already set)." : `Ethena: ${n}-tx batch \u2014 approve USDe to sUSDe vault, then deposit.`;
|
|
500
|
+
const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
|
|
501
|
+
const gasLimitConfig = args.useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
|
|
502
|
+
return buildEvmMultisignBatch({
|
|
503
|
+
context: {
|
|
504
|
+
chainCategory: "evm",
|
|
505
|
+
keyGen: args.keyGen,
|
|
506
|
+
purposeText: args.purposeText,
|
|
507
|
+
chainId: 1,
|
|
508
|
+
rpcUrl: args.rpcUrl.trim(),
|
|
509
|
+
executorAddress: executor,
|
|
510
|
+
chainDetail: args.chainDetail,
|
|
511
|
+
useCustomGas: args.useCustomGas,
|
|
512
|
+
customGasChainDetails: args.customGasChainDetails
|
|
513
|
+
},
|
|
514
|
+
steps: evmSteps,
|
|
515
|
+
purposeSuffix,
|
|
516
|
+
firstMsgRawNo0x: firstDataNo0x,
|
|
517
|
+
destinationAddress: steps[0].to,
|
|
518
|
+
resolveGasLimit: ({ index, estimatedGas }) => {
|
|
519
|
+
const s = steps[index];
|
|
520
|
+
if (s.kind === "deposit" && index > 0) {
|
|
521
|
+
const gas = ETHENA_SUSDE_DEPOSIT_FALLBACK;
|
|
522
|
+
return args.useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(gas, gasLimitConfig) : gas;
|
|
436
523
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
)
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
455
|
-
messageRawBatch.push(ser);
|
|
456
|
-
proposalTxParamsBatch.push({
|
|
457
|
-
nonce: currentNonce,
|
|
458
|
-
gasLimit: gasLimitI.toString(),
|
|
459
|
-
txType: "eip1559",
|
|
460
|
-
maxFeePerGas: maxFeePerGas.toString(),
|
|
461
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
462
|
-
});
|
|
463
|
-
if (i === 0) {
|
|
464
|
-
firstTxFeePayload = {
|
|
465
|
-
txNonce: currentNonce,
|
|
466
|
-
txGasLimit: gasLimitI.toString(),
|
|
467
|
-
txMaxFeePerGas: maxFeePerGas.toString(),
|
|
468
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
524
|
+
return estimatedGas;
|
|
525
|
+
},
|
|
526
|
+
buildBatchMeta: ({ index, gasLimit }) => {
|
|
527
|
+
const s = steps[index];
|
|
528
|
+
if (s.kind === "approve") {
|
|
529
|
+
return {
|
|
530
|
+
signatureText: JSON.stringify({
|
|
531
|
+
kind: "Ethena",
|
|
532
|
+
name: "ERC20.approve",
|
|
533
|
+
to: "sUSDe vault",
|
|
534
|
+
function: "approve(address spender, uint256 amount)",
|
|
535
|
+
spender: susde,
|
|
536
|
+
amountHuman: args.amountHuman,
|
|
537
|
+
note: "Allowance to stake this USDe amount (not unlimited)."
|
|
538
|
+
}),
|
|
539
|
+
evm: { type: "ethena_erc20_approve", version: 1, chainId: "1" },
|
|
540
|
+
ethena: { step: "approve_usde", susde }
|
|
469
541
|
};
|
|
470
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
471
542
|
}
|
|
472
|
-
|
|
473
|
-
if (s.kind === "approve") {
|
|
474
|
-
batchMeta.push({
|
|
475
|
-
destinationAddress: usde,
|
|
476
|
-
signatureText: JSON.stringify({
|
|
477
|
-
kind: "Ethena",
|
|
478
|
-
name: "ERC20.approve",
|
|
479
|
-
to: "sUSDe vault",
|
|
480
|
-
function: "approve(address spender, uint256 amount)",
|
|
481
|
-
spender: susde,
|
|
482
|
-
amountHuman: args.amountHuman,
|
|
483
|
-
note: "Allowance to stake this USDe amount (not unlimited)."
|
|
484
|
-
}),
|
|
485
|
-
evm: { type: "ethena_erc20_approve", version: 1, chainId: "1" },
|
|
486
|
-
ethena: { step: "approve_usde", susde }
|
|
487
|
-
});
|
|
488
|
-
} else {
|
|
489
|
-
batchMeta.push({
|
|
490
|
-
destinationAddress: susde,
|
|
543
|
+
return {
|
|
491
544
|
signatureText: JSON.stringify({
|
|
492
545
|
kind: "Ethena",
|
|
493
546
|
name: "StakedUSDe (ERC-4626).deposit",
|
|
@@ -497,40 +550,10 @@ async function buildEvmMultisignBodyEthenaUsdeStakeToSusde(args) {
|
|
|
497
550
|
amountHuman: args.amountHuman
|
|
498
551
|
}),
|
|
499
552
|
evm: { type: "ethena_susde_deposit", version: 1, chainId: "1" },
|
|
500
|
-
ethena: { step: "deposit", vault: susde, gasBuildDeposit: { baseGasUnits:
|
|
501
|
-
}
|
|
553
|
+
ethena: { step: "deposit", vault: susde, gasBuildDeposit: { baseGasUnits: gasLimit.toString() } }
|
|
554
|
+
};
|
|
502
555
|
}
|
|
503
|
-
}
|
|
504
|
-
const extraPayload = { batchMeta };
|
|
505
|
-
if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
|
|
506
|
-
extraPayload.customGasChainDetails = args.customGasChainDetails;
|
|
507
|
-
}
|
|
508
|
-
const extraJSON = JSON.stringify(extraPayload);
|
|
509
|
-
const firstSigText = batchMeta[0].signatureText;
|
|
510
|
-
const n = steps.length;
|
|
511
|
-
const purposeSuffix = n === 1 ? "Ethena: 1-tx \u2014 deposit USDe to sUSDe (allowance already set)." : `Ethena: ${n}-tx batch \u2014 approve USDe to sUSDe vault, then deposit.`;
|
|
512
|
-
const bodyForSign = {
|
|
513
|
-
keyList,
|
|
514
|
-
pubKey: ph,
|
|
515
|
-
msgHash: messageHashes[0],
|
|
516
|
-
msgRaw: firstDataNo0x,
|
|
517
|
-
messageHashes,
|
|
518
|
-
messageRawBatch,
|
|
519
|
-
destinationChainID: "1",
|
|
520
|
-
destinationAddress: steps[0].to,
|
|
521
|
-
extraJSON,
|
|
522
|
-
signatureText: firstSigText,
|
|
523
|
-
purpose: (() => {
|
|
524
|
-
const t = args.purposeText.trim();
|
|
525
|
-
return (t ? `${t}
|
|
526
|
-
|
|
527
|
-
` : "") + purposeSuffix;
|
|
528
|
-
})(),
|
|
529
|
-
...firstTxFeePayload,
|
|
530
|
-
proposalTxParams: proposalTxParamsBatch
|
|
531
|
-
};
|
|
532
|
-
if (clientId) bodyForSign.clientId = clientId;
|
|
533
|
-
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
556
|
+
});
|
|
534
557
|
}
|
|
535
558
|
var ETHENA_SUSDE_COOLDOWN_SHARES_FALLBACK = 1200000n;
|
|
536
559
|
var ETHENA_SUSDE_UNSTAKE_CLAIM_FALLBACK = 500000n;
|
|
@@ -538,161 +561,27 @@ async function buildEthenaStakedUsdeOneTxMultisignBody(args) {
|
|
|
538
561
|
if (args.chainId !== 1) {
|
|
539
562
|
throw new Error("Ethena sUSDe exit is only supported on Ethereum mainnet (chain id 1).");
|
|
540
563
|
}
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
564
|
+
const step = args.step;
|
|
565
|
+
const evmSteps = [{ to: step.to, data: step.data, value: step.value, fallbackGas: args.gasFallback }];
|
|
566
|
+
const firstDataNo0x = step.data.startsWith("0x") ? step.data.slice(2) : step.data;
|
|
567
|
+
return buildEvmMultisignBatch({
|
|
568
|
+
context: {
|
|
569
|
+
chainCategory: "evm",
|
|
570
|
+
keyGen: args.keyGen,
|
|
571
|
+
purposeText: args.purposeText,
|
|
572
|
+
chainId: 1,
|
|
573
|
+
rpcUrl: args.rpcUrl.trim(),
|
|
574
|
+
executorAddress: args.executor,
|
|
575
|
+
chainDetail: args.chainDetail,
|
|
576
|
+
useCustomGas: args.useCustomGas,
|
|
577
|
+
customGasChainDetails: args.customGasChainDetails
|
|
578
|
+
},
|
|
579
|
+
steps: evmSteps,
|
|
580
|
+
purposeSuffix: args.purposeSuffix,
|
|
581
|
+
firstMsgRawNo0x: firstDataNo0x,
|
|
582
|
+
destinationAddress: step.to,
|
|
583
|
+
buildBatchMeta: ({ gasLimit }) => args.makeBatchMeta({ gasLimitI: gasLimit })
|
|
557
584
|
});
|
|
558
|
-
const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl.trim()) });
|
|
559
|
-
const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
560
|
-
const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
|
|
561
|
-
const messageHashes = [];
|
|
562
|
-
const messageRawBatch = [];
|
|
563
|
-
const proposalTxParamsBatch = [];
|
|
564
|
-
const batchMeta = [];
|
|
565
|
-
let firstTxFeePayload = {};
|
|
566
|
-
let firstDataNo0x = "";
|
|
567
|
-
for (let i = 0; i < steps.length; i++) {
|
|
568
|
-
const s = steps[i];
|
|
569
|
-
const currentNonce = baseNonce + i;
|
|
570
|
-
let estimatedGas;
|
|
571
|
-
try {
|
|
572
|
-
estimatedGas = await publicClient.estimateGas({
|
|
573
|
-
to: s.to,
|
|
574
|
-
data: s.data,
|
|
575
|
-
value: s.value,
|
|
576
|
-
account: executor
|
|
577
|
-
});
|
|
578
|
-
} catch {
|
|
579
|
-
estimatedGas = args.gasFallback;
|
|
580
|
-
}
|
|
581
|
-
const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
582
|
-
if (legacy) {
|
|
583
|
-
let gasPriceWei = await publicClient.getGasPrice();
|
|
584
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
585
|
-
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
586
|
-
}
|
|
587
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
588
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
589
|
-
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
590
|
-
}
|
|
591
|
-
const ser = viem.serializeTransaction({
|
|
592
|
-
type: "legacy",
|
|
593
|
-
to: s.to,
|
|
594
|
-
data: s.data,
|
|
595
|
-
value: s.value,
|
|
596
|
-
gas: gasLimitI,
|
|
597
|
-
gasPrice: gasPriceWei,
|
|
598
|
-
nonce: currentNonce,
|
|
599
|
-
chainId: 1
|
|
600
|
-
});
|
|
601
|
-
const h = viem.keccak256(ser);
|
|
602
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
603
|
-
messageRawBatch.push(ser);
|
|
604
|
-
proposalTxParamsBatch.push({
|
|
605
|
-
nonce: currentNonce,
|
|
606
|
-
gasLimit: gasLimitI.toString(),
|
|
607
|
-
txType: "legacy",
|
|
608
|
-
gasPrice: gasPriceWei.toString()
|
|
609
|
-
});
|
|
610
|
-
if (i === 0) {
|
|
611
|
-
firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
|
|
612
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
613
|
-
}
|
|
614
|
-
} else {
|
|
615
|
-
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
616
|
-
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
617
|
-
const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
618
|
-
const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
619
|
-
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
620
|
-
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
621
|
-
const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
622
|
-
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
623
|
-
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
624
|
-
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
625
|
-
let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
|
|
626
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
627
|
-
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
628
|
-
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
629
|
-
}
|
|
630
|
-
({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
|
|
631
|
-
maxFeePerGas,
|
|
632
|
-
maxPriorityFeePerGas,
|
|
633
|
-
latestBaseFeeWei
|
|
634
|
-
));
|
|
635
|
-
const ser = viem.serializeTransaction({
|
|
636
|
-
type: "eip1559",
|
|
637
|
-
to: s.to,
|
|
638
|
-
data: s.data,
|
|
639
|
-
value: s.value,
|
|
640
|
-
gas: gasLimitI,
|
|
641
|
-
maxFeePerGas,
|
|
642
|
-
maxPriorityFeePerGas,
|
|
643
|
-
nonce: currentNonce,
|
|
644
|
-
chainId: 1
|
|
645
|
-
});
|
|
646
|
-
const h = viem.keccak256(ser);
|
|
647
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
648
|
-
messageRawBatch.push(ser);
|
|
649
|
-
proposalTxParamsBatch.push({
|
|
650
|
-
nonce: currentNonce,
|
|
651
|
-
gasLimit: gasLimitI.toString(),
|
|
652
|
-
txType: "eip1559",
|
|
653
|
-
maxFeePerGas: maxFeePerGas.toString(),
|
|
654
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
655
|
-
});
|
|
656
|
-
if (i === 0) {
|
|
657
|
-
firstTxFeePayload = {
|
|
658
|
-
txNonce: currentNonce,
|
|
659
|
-
txGasLimit: gasLimitI.toString(),
|
|
660
|
-
txMaxFeePerGas: maxFeePerGas.toString(),
|
|
661
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
662
|
-
};
|
|
663
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
batchMeta.push(args.makeBatchMeta({ gasLimitI }));
|
|
667
|
-
}
|
|
668
|
-
const extraPayload = { batchMeta };
|
|
669
|
-
if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
|
|
670
|
-
extraPayload.customGasChainDetails = args.customGasChainDetails;
|
|
671
|
-
}
|
|
672
|
-
const extraJSON = JSON.stringify(extraPayload);
|
|
673
|
-
const firstSigText = batchMeta[0].signatureText;
|
|
674
|
-
const bodyForSign = {
|
|
675
|
-
keyList,
|
|
676
|
-
pubKey: ph,
|
|
677
|
-
msgHash: messageHashes[0],
|
|
678
|
-
msgRaw: firstDataNo0x,
|
|
679
|
-
messageHashes,
|
|
680
|
-
messageRawBatch,
|
|
681
|
-
destinationChainID: "1",
|
|
682
|
-
destinationAddress: steps[0].to,
|
|
683
|
-
extraJSON,
|
|
684
|
-
signatureText: firstSigText,
|
|
685
|
-
purpose: (() => {
|
|
686
|
-
const t = args.purposeText.trim();
|
|
687
|
-
return (t ? `${t}
|
|
688
|
-
|
|
689
|
-
` : "") + args.purposeSuffix;
|
|
690
|
-
})(),
|
|
691
|
-
...firstTxFeePayload,
|
|
692
|
-
proposalTxParams: proposalTxParamsBatch
|
|
693
|
-
};
|
|
694
|
-
if (clientId) bodyForSign.clientId = clientId;
|
|
695
|
-
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
696
585
|
}
|
|
697
586
|
async function buildEvmMultisignBodyEthenaSusdeRedeemToUsde(args) {
|
|
698
587
|
if (args.chainId !== 1) {
|
|
@@ -917,6 +806,103 @@ function resolveEthenaBatchStepGasFromSignRequest(detail, batchIndex) {
|
|
|
917
806
|
}
|
|
918
807
|
return null;
|
|
919
808
|
}
|
|
809
|
+
var ETHENA_MINTING_V2_MAINNET = "0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3";
|
|
810
|
+
var ETHENA_MINTING_READ_ABI = viem.parseAbi([
|
|
811
|
+
"function isSupportedAsset(address asset) view returns (bool)"
|
|
812
|
+
]);
|
|
813
|
+
var cachedClient = null;
|
|
814
|
+
function publicClientForMainnetRpc(rpcUrl) {
|
|
815
|
+
if (cachedClient && cachedClient.rpc === rpcUrl) return cachedClient.client;
|
|
816
|
+
const c = viem.createPublicClient({ chain: chains.mainnet, transport: viem.http(rpcUrl.trim(), { batch: { batchSize: 64 } }) });
|
|
817
|
+
cachedClient = { rpc: rpcUrl, client: c };
|
|
818
|
+
return c;
|
|
819
|
+
}
|
|
820
|
+
async function fetchEthenaMintingIsSupportedMap(rpcUrl, contractAddresses) {
|
|
821
|
+
const out = /* @__PURE__ */ new Map();
|
|
822
|
+
if (!rpcUrl.trim()) return out;
|
|
823
|
+
const unique = [];
|
|
824
|
+
const seen = /* @__PURE__ */ new Set();
|
|
825
|
+
for (const raw of contractAddresses) {
|
|
826
|
+
try {
|
|
827
|
+
const a = viem.getAddress(raw);
|
|
828
|
+
const k = a.toLowerCase();
|
|
829
|
+
if (seen.has(k)) continue;
|
|
830
|
+
seen.add(k);
|
|
831
|
+
unique.push(a);
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (unique.length === 0) return out;
|
|
836
|
+
const client = publicClientForMainnetRpc(rpcUrl);
|
|
837
|
+
const res = await client.multicall({
|
|
838
|
+
contracts: unique.map((asset) => ({
|
|
839
|
+
address: ETHENA_MINTING_V2_MAINNET,
|
|
840
|
+
abi: ETHENA_MINTING_READ_ABI,
|
|
841
|
+
functionName: "isSupportedAsset",
|
|
842
|
+
args: [asset]
|
|
843
|
+
})),
|
|
844
|
+
allowFailure: true
|
|
845
|
+
});
|
|
846
|
+
for (let i = 0; i < unique.length; i++) {
|
|
847
|
+
const row = res[i];
|
|
848
|
+
if (row.status !== "success") continue;
|
|
849
|
+
if (row.result === true) out.set(unique[i], true);
|
|
850
|
+
}
|
|
851
|
+
return out;
|
|
852
|
+
}
|
|
853
|
+
var STAKED_USDE_V2_VIEWS_ABI = viem.parseAbi([
|
|
854
|
+
"function cooldownDuration() view returns (uint24)",
|
|
855
|
+
"function cooldowns(address account) view returns (uint104 cooldownEnd, uint152 underlyingAmount)"
|
|
856
|
+
]);
|
|
857
|
+
function publicClientForMainnet(rpcUrl) {
|
|
858
|
+
return viem.createPublicClient({
|
|
859
|
+
chain: { id: 1, name: "Ethereum", nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 }, rpcUrls: { default: { http: [rpcUrl.trim()] } } },
|
|
860
|
+
transport: viem.http(rpcUrl.trim())
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
async function readEthenaStakedUsdeCooldownDuration(args) {
|
|
864
|
+
const v = viem.getAddress(args.vault ?? SUSDE_ETHEREUM_MAINNET);
|
|
865
|
+
const c = publicClientForMainnet(args.rpcUrl);
|
|
866
|
+
const d = await c.readContract({
|
|
867
|
+
address: v,
|
|
868
|
+
abi: STAKED_USDE_V2_VIEWS_ABI,
|
|
869
|
+
functionName: "cooldownDuration"
|
|
870
|
+
});
|
|
871
|
+
return BigInt(d);
|
|
872
|
+
}
|
|
873
|
+
async function readEthenaStakedUsdeUserCooldown(args) {
|
|
874
|
+
const v = viem.getAddress(args.vault ?? SUSDE_ETHEREUM_MAINNET);
|
|
875
|
+
const c = publicClientForMainnet(args.rpcUrl);
|
|
876
|
+
const r = await c.readContract({
|
|
877
|
+
address: v,
|
|
878
|
+
abi: STAKED_USDE_V2_VIEWS_ABI,
|
|
879
|
+
functionName: "cooldowns",
|
|
880
|
+
args: [viem.getAddress(args.account)]
|
|
881
|
+
});
|
|
882
|
+
const tuple = r;
|
|
883
|
+
return {
|
|
884
|
+
cooldownEnd: BigInt(tuple[0]),
|
|
885
|
+
underlyingAmount: BigInt(tuple[1])
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
async function readEthenaMainnetBlockTimestamp(rpcUrl) {
|
|
889
|
+
const c = publicClientForMainnet(rpcUrl);
|
|
890
|
+
const b = await c.getBlock({ blockTag: "latest" });
|
|
891
|
+
return b.timestamp;
|
|
892
|
+
}
|
|
893
|
+
function formatEthenaCooldownDurationLabel(totalSec) {
|
|
894
|
+
if (totalSec <= 0n) return "0 seconds";
|
|
895
|
+
const d = totalSec / 86400n;
|
|
896
|
+
const h = totalSec % 86400n / 3600n;
|
|
897
|
+
const m = totalSec % 3600n / 60n;
|
|
898
|
+
const s = totalSec % 60n;
|
|
899
|
+
const parts = [];
|
|
900
|
+
if (d > 0n) parts.push(`${d} day${d === 1n ? "" : "s"}`);
|
|
901
|
+
if (h > 0n) parts.push(`${h} hour${h === 1n ? "" : "s"}`);
|
|
902
|
+
if (m > 0n) parts.push(`${m} min`);
|
|
903
|
+
if (s > 0n) parts.push(`${s} sec`);
|
|
904
|
+
return parts.join(", ");
|
|
905
|
+
}
|
|
920
906
|
|
|
921
907
|
// src/protocols/evm/ethena/index.ts
|
|
922
908
|
var ETHENA_PROTOCOL_ID = "ethena";
|
|
@@ -942,6 +928,7 @@ registerProtocolModule(ethenaProtocolModule);
|
|
|
942
928
|
|
|
943
929
|
exports.ETHENA_KEY_ADDRESSES_DOC = ETHENA_KEY_ADDRESSES_DOC;
|
|
944
930
|
exports.ETHENA_LABS_GITHUB = ETHENA_LABS_GITHUB;
|
|
931
|
+
exports.ETHENA_MINTING_V2_MAINNET = ETHENA_MINTING_V2_MAINNET;
|
|
945
932
|
exports.ETHENA_PROTOCOL_ID = ETHENA_PROTOCOL_ID;
|
|
946
933
|
exports.ETHENA_SUSDE_DEPOSIT_GET_SIG_GAS_FALLBACK = ETHENA_SUSDE_DEPOSIT_GET_SIG_GAS_FALLBACK;
|
|
947
934
|
exports.SUSDE_ETHEREUM_MAINNET = SUSDE_ETHEREUM_MAINNET;
|
|
@@ -953,11 +940,16 @@ exports.buildEvmMultisignBodyEthenaSusdeRedeemToUsde = buildEvmMultisignBodyEthe
|
|
|
953
940
|
exports.buildEvmMultisignBodyEthenaUnstakeClaim = buildEvmMultisignBodyEthenaUnstakeClaim;
|
|
954
941
|
exports.buildEvmMultisignBodyEthenaUsdeStakeToSusde = buildEvmMultisignBodyEthenaUsdeStakeToSusde;
|
|
955
942
|
exports.ethenaProtocolModule = ethenaProtocolModule;
|
|
943
|
+
exports.fetchEthenaMintingIsSupportedMap = fetchEthenaMintingIsSupportedMap;
|
|
944
|
+
exports.formatEthenaCooldownDurationLabel = formatEthenaCooldownDurationLabel;
|
|
956
945
|
exports.isEthenaSusdeDepositBatchStep = isEthenaSusdeDepositBatchStep;
|
|
957
946
|
exports.isEthenaUsdeOnAssetsChain = isEthenaUsdeOnAssetsChain;
|
|
958
947
|
exports.isEvmChainInEthenaUsdeList = isEvmChainInEthenaUsdeList;
|
|
959
948
|
exports.listEthenaUsdeEvmNetworkRows = listEthenaUsdeEvmNetworkRows;
|
|
949
|
+
exports.readEthenaMainnetBlockTimestamp = readEthenaMainnetBlockTimestamp;
|
|
960
950
|
exports.readEthenaStakePreviewShares = readEthenaStakePreviewShares;
|
|
951
|
+
exports.readEthenaStakedUsdeCooldownDuration = readEthenaStakedUsdeCooldownDuration;
|
|
952
|
+
exports.readEthenaStakedUsdeUserCooldown = readEthenaStakedUsdeUserCooldown;
|
|
961
953
|
exports.readEthenaUnstakePreviewUsde = readEthenaUnstakePreviewUsde;
|
|
962
954
|
exports.resolveEthenaBatchStepGasFromSignRequest = resolveEthenaBatchStepGasFromSignRequest;
|
|
963
955
|
exports.usdeTokenAddressOnEvmChain = usdeTokenAddressOnEvmChain;
|