@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,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var viem = require('viem');
|
|
4
|
+
var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
|
|
4
5
|
|
|
5
6
|
// src/core/registry.ts
|
|
6
7
|
var modules = [];
|
|
@@ -25,87 +26,234 @@ function isMapleSyrupSupportedChain(chainId) {
|
|
|
25
26
|
return chainId === 1 || chainId === 11155111;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
// src/core/
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
// src/core/purpose.ts
|
|
30
|
+
function mergePurposeText(purposeText, purposeSuffix) {
|
|
31
|
+
const t = purposeText.trim();
|
|
32
|
+
const suffix = (purposeSuffix ?? "").trim();
|
|
33
|
+
if (!suffix) return t;
|
|
34
|
+
return t ? `${t}
|
|
35
|
+
|
|
36
|
+
${suffix}` : suffix;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
// src/
|
|
39
|
-
function
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
// src/core/envelope.ts
|
|
40
|
+
function finalizeMultisign(input) {
|
|
41
|
+
const { keyGen, destinationChainID, legs } = input;
|
|
42
|
+
if (legs.length === 0) {
|
|
43
|
+
throw new Error("finalizeMultisign requires at least one leg");
|
|
44
|
+
}
|
|
45
|
+
const ph = (keyGen.pubkeyhex ?? "").trim();
|
|
46
|
+
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
47
|
+
const keyList = keyGen.keylist ?? [];
|
|
48
|
+
const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
|
|
49
|
+
const first = legs[0];
|
|
50
|
+
const messageHashes = legs.map((l) => l.msgHash);
|
|
51
|
+
const messageRawBatch = legs.map((l) => l.msgRaw);
|
|
52
|
+
const batchMeta = legs.map((l) => ({
|
|
53
|
+
destinationAddress: l.destinationAddress,
|
|
54
|
+
signatureText: l.signatureText,
|
|
55
|
+
...l.audit
|
|
56
|
+
}));
|
|
57
|
+
const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
|
|
58
|
+
const extraPayload = {
|
|
59
|
+
batchMeta,
|
|
60
|
+
...input.extraJSON ?? {}
|
|
61
|
+
};
|
|
62
|
+
const extraJSON = JSON.stringify(extraPayload);
|
|
63
|
+
const bodyForSign = {
|
|
64
|
+
keyList,
|
|
65
|
+
pubKey: ph,
|
|
66
|
+
msgHash: messageHashes[0],
|
|
67
|
+
msgRaw: first.msgRaw,
|
|
68
|
+
destinationChainID,
|
|
69
|
+
destinationAddress: input.destinationAddress ?? first.destinationAddress,
|
|
70
|
+
extraJSON,
|
|
71
|
+
signatureText: first.signatureText,
|
|
72
|
+
purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
|
|
73
|
+
...first.feeSnapshot
|
|
74
|
+
};
|
|
75
|
+
if (legs.length > 1) {
|
|
76
|
+
bodyForSign.messageHashes = messageHashes;
|
|
77
|
+
bodyForSign.messageRawBatch = messageRawBatch;
|
|
78
|
+
}
|
|
79
|
+
if (proposalTxParams.length > 0) {
|
|
80
|
+
bodyForSign.proposalTxParams = proposalTxParams;
|
|
42
81
|
}
|
|
43
|
-
const
|
|
44
|
-
|
|
82
|
+
const valueWei = first.valueWei;
|
|
83
|
+
if (valueWei != null && valueWei > 0n) {
|
|
84
|
+
bodyForSign.value = valueWei.toString();
|
|
85
|
+
}
|
|
86
|
+
if (clientId) bodyForSign.clientId = clientId;
|
|
87
|
+
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
45
88
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
89
|
+
function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
|
|
90
|
+
if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
|
|
91
|
+
return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
|
|
92
|
+
}
|
|
93
|
+
return (estimatedGas * 12n + 9n) / 10n;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/chains/evm/buildBatch.ts
|
|
97
|
+
async function buildEvmMultisignBatch(args) {
|
|
98
|
+
const { context, steps } = args;
|
|
99
|
+
const {
|
|
100
|
+
chainId,
|
|
101
|
+
rpcUrl,
|
|
102
|
+
executorAddress,
|
|
103
|
+
chainDetail,
|
|
104
|
+
useCustomGas,
|
|
105
|
+
customGasChainDetails,
|
|
106
|
+
keyGen,
|
|
107
|
+
purposeText
|
|
108
|
+
} = context;
|
|
109
|
+
if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
|
|
110
|
+
const ch = viem.defineChain({
|
|
111
|
+
id: chainId,
|
|
112
|
+
name: "Destination",
|
|
54
113
|
nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
|
|
55
|
-
rpcUrls: { default: { http: [
|
|
56
|
-
});
|
|
57
|
-
const publicClient = viem.createPublicClient({
|
|
58
|
-
chain,
|
|
59
|
-
transport: viem.http(url)
|
|
114
|
+
rpcUrls: { default: { http: [rpcUrl] } }
|
|
60
115
|
});
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
116
|
+
const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
|
|
117
|
+
const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
|
|
118
|
+
const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
|
|
119
|
+
const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
120
|
+
const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
|
|
121
|
+
const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
|
|
122
|
+
const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
|
|
123
|
+
const executor = viem.getAddress(executorAddress);
|
|
124
|
+
const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
|
|
125
|
+
const legs = [];
|
|
126
|
+
for (let i = 0; i < steps.length; i++) {
|
|
127
|
+
const step = steps[i];
|
|
128
|
+
const currentNonce = baseNonce + i;
|
|
129
|
+
let estimatedGas;
|
|
130
|
+
if (args.estimateGasForStep) {
|
|
131
|
+
estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
|
|
132
|
+
} else {
|
|
133
|
+
try {
|
|
134
|
+
estimatedGas = await publicClient.estimateGas({
|
|
135
|
+
to: step.to,
|
|
136
|
+
data: step.data,
|
|
137
|
+
value: step.value,
|
|
138
|
+
account: executor
|
|
139
|
+
});
|
|
140
|
+
} catch {
|
|
141
|
+
estimatedGas = step.fallbackGas ?? 100000n;
|
|
142
|
+
}
|
|
71
143
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
144
|
+
let gasLimitI;
|
|
145
|
+
if (args.resolveGasLimit) {
|
|
146
|
+
gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient });
|
|
147
|
+
} else if (step.routerSwap) {
|
|
148
|
+
gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
|
|
149
|
+
} else {
|
|
150
|
+
gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
78
151
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
152
|
+
let proposalTxParams;
|
|
153
|
+
let feeSnapshot;
|
|
154
|
+
let serialized;
|
|
155
|
+
if (legacy) {
|
|
156
|
+
let gasPriceWei = await publicClient.getGasPrice();
|
|
157
|
+
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
158
|
+
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
159
|
+
}
|
|
160
|
+
if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
|
|
161
|
+
const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
|
|
162
|
+
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
163
|
+
}
|
|
164
|
+
serialized = viem.serializeTransaction({
|
|
165
|
+
type: "legacy",
|
|
166
|
+
to: step.to,
|
|
167
|
+
data: step.data,
|
|
168
|
+
value: step.value,
|
|
169
|
+
gas: gasLimitI,
|
|
170
|
+
gasPrice: gasPriceWei,
|
|
171
|
+
nonce: currentNonce,
|
|
172
|
+
chainId
|
|
173
|
+
});
|
|
174
|
+
proposalTxParams = {
|
|
175
|
+
nonce: currentNonce,
|
|
176
|
+
gasLimit: gasLimitI.toString(),
|
|
177
|
+
txType: "legacy",
|
|
178
|
+
gasPrice: gasPriceWei.toString()
|
|
179
|
+
};
|
|
180
|
+
feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
|
|
181
|
+
} else {
|
|
182
|
+
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
183
|
+
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
184
|
+
const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
|
|
185
|
+
const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
|
|
186
|
+
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
187
|
+
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
188
|
+
const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
|
|
189
|
+
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
190
|
+
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
191
|
+
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
192
|
+
let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
|
|
193
|
+
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
194
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
195
|
+
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
196
|
+
}
|
|
197
|
+
({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
|
|
198
|
+
maxFeePerGas,
|
|
199
|
+
maxPriorityFeePerGas,
|
|
200
|
+
latestBaseFeeWei
|
|
201
|
+
));
|
|
202
|
+
serialized = viem.serializeTransaction({
|
|
203
|
+
type: "eip1559",
|
|
204
|
+
to: step.to,
|
|
205
|
+
data: step.data,
|
|
206
|
+
value: step.value,
|
|
207
|
+
gas: gasLimitI,
|
|
208
|
+
maxFeePerGas,
|
|
209
|
+
maxPriorityFeePerGas,
|
|
210
|
+
nonce: currentNonce,
|
|
211
|
+
chainId
|
|
212
|
+
});
|
|
213
|
+
proposalTxParams = {
|
|
214
|
+
nonce: currentNonce,
|
|
215
|
+
gasLimit: gasLimitI.toString(),
|
|
216
|
+
txType: "eip1559",
|
|
217
|
+
maxFeePerGas: maxFeePerGas.toString(),
|
|
218
|
+
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
219
|
+
};
|
|
220
|
+
feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
|
|
221
|
+
}
|
|
222
|
+
const h = viem.keccak256(serialized);
|
|
223
|
+
const msgHash = h.startsWith("0x") ? h.slice(2) : h;
|
|
224
|
+
const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
|
|
225
|
+
legs.push({
|
|
226
|
+
msgHash,
|
|
227
|
+
msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
|
|
228
|
+
destinationAddress: step.to,
|
|
229
|
+
signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
|
|
230
|
+
audit: batchMetaExtra,
|
|
231
|
+
feeSnapshot: i === 0 ? feeSnapshot : {},
|
|
232
|
+
proposalTxParams,
|
|
233
|
+
valueWei: i === 0 ? step.value : void 0
|
|
234
|
+
});
|
|
235
|
+
if (i === 0 && args.firstMsgRawNo0x != null) {
|
|
236
|
+
legs[0].msgRaw = args.firstMsgRawNo0x;
|
|
93
237
|
}
|
|
94
238
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
let maxF = maxFeePerGas;
|
|
99
|
-
if (baseWei > 0n && maxF < baseWei + maxP) {
|
|
100
|
-
maxF = baseWei + maxP + viem.parseGwei("0.001");
|
|
239
|
+
const extraJSON = {};
|
|
240
|
+
if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
|
|
241
|
+
extraJSON.customGasChainDetails = customGasChainDetails;
|
|
101
242
|
}
|
|
102
|
-
|
|
103
|
-
|
|
243
|
+
const result = finalizeMultisign({
|
|
244
|
+
keyGen,
|
|
245
|
+
purposeText,
|
|
246
|
+
purposeSuffix: args.purposeSuffix,
|
|
247
|
+
destinationChainID: String(chainId),
|
|
248
|
+
destinationAddress: args.destinationAddress ?? steps[0].to,
|
|
249
|
+
legs,
|
|
250
|
+
extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
|
|
251
|
+
});
|
|
252
|
+
const pv = args.payableValueWei;
|
|
253
|
+
if (pv != null && pv > 0n) {
|
|
254
|
+
result.bodyForSign.value = pv.toString();
|
|
104
255
|
}
|
|
105
|
-
return
|
|
106
|
-
}
|
|
107
|
-
function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
|
|
108
|
-
return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
|
|
256
|
+
return result;
|
|
109
257
|
}
|
|
110
258
|
|
|
111
259
|
// src/protocols/evm/maple/multisign.ts
|
|
@@ -128,13 +276,6 @@ var poolV2ExitAbi = viem.parseAbi([
|
|
|
128
276
|
"function requestRedeem(uint256 shares, address receiver) returns (uint256)",
|
|
129
277
|
"function decimals() view returns (uint8)"
|
|
130
278
|
]);
|
|
131
|
-
function gweiToDecimalString(n) {
|
|
132
|
-
if (!Number.isFinite(n)) return "0";
|
|
133
|
-
if (n === 0) return "0";
|
|
134
|
-
const s = String(n);
|
|
135
|
-
if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
|
|
136
|
-
return s;
|
|
137
|
-
}
|
|
138
279
|
function formatBytes32DataLabel(s) {
|
|
139
280
|
const b = viem.stringToBytes(s);
|
|
140
281
|
if (b.length > 32) throw new Error("Maple depositData label is too long for bytes32.");
|
|
@@ -224,10 +365,6 @@ async function buildEvmMultisignBodyMapleSyrupDeposit(args) {
|
|
|
224
365
|
if (args.chainId !== 1 && args.chainId !== 11155111) {
|
|
225
366
|
throw new Error("Maple Syrup deposit is only supported on Ethereum mainnet or Sepolia.");
|
|
226
367
|
}
|
|
227
|
-
const ph = (args.keyGen.pubkeyhex ?? "").trim();
|
|
228
|
-
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
229
|
-
const keyList = args.keyGen.keylist ?? [];
|
|
230
|
-
const clientId = firstClientIdFromKeyGen(args.keyGen);
|
|
231
368
|
const asset = viem.getAddress(args.asset);
|
|
232
369
|
const router = viem.getAddress(args.syrupRouter);
|
|
233
370
|
const pool = viem.getAddress(args.pool);
|
|
@@ -283,33 +420,44 @@ async function buildEvmMultisignBodyMapleSyrupDeposit(args) {
|
|
|
283
420
|
});
|
|
284
421
|
steps.push({ kind: "deposit", to: router, data: depositCalldata, value: 0n });
|
|
285
422
|
}
|
|
286
|
-
const
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
423
|
+
const chainIdStr = String(args.chainId);
|
|
424
|
+
const evmSteps = steps.map((s) => ({
|
|
425
|
+
to: s.to,
|
|
426
|
+
data: s.data,
|
|
427
|
+
value: s.value,
|
|
428
|
+
fallbackGas: s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : MAPLE_SYRUP_DEPOSIT_FALLBACK
|
|
429
|
+
}));
|
|
430
|
+
const n = steps.length;
|
|
431
|
+
const finalVerb = stakeMethod === "authorizeAndDeposit" ? "authorizeAndDeposit (permission + deposit)" : "deposit";
|
|
432
|
+
const purposeSuffix = n === 1 ? `Maple Syrup: 1-tx \u2014 ${finalVerb} via SyrupRouter (allowance already set).` : `Maple Syrup: ${n}-tx batch \u2014 approve asset for SyrupRouter, then ${finalVerb}.`;
|
|
433
|
+
const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
|
|
434
|
+
return buildEvmMultisignBatch({
|
|
435
|
+
context: {
|
|
436
|
+
chainCategory: "evm",
|
|
437
|
+
keyGen: args.keyGen,
|
|
438
|
+
purposeText: args.purposeText,
|
|
439
|
+
chainId: args.chainId,
|
|
440
|
+
rpcUrl: args.rpcUrl,
|
|
441
|
+
executorAddress: executor,
|
|
442
|
+
chainDetail: args.chainDetail,
|
|
443
|
+
useCustomGas: args.useCustomGas,
|
|
444
|
+
customGasChainDetails: args.customGasChainDetails
|
|
445
|
+
},
|
|
446
|
+
steps: evmSteps,
|
|
447
|
+
purposeSuffix,
|
|
448
|
+
firstMsgRawNo0x: firstDataNo0x,
|
|
449
|
+
destinationAddress: steps[0].to,
|
|
450
|
+
estimateGasForStep: async ({ step, index, publicClient: publicClient2, executor: exec }) => {
|
|
451
|
+
const s = steps[index];
|
|
452
|
+
if ((s.kind === "deposit" || s.kind === "authorizeAndDeposit") && index > 0) {
|
|
453
|
+
return MAPLE_SYRUP_DEPOSIT_FALLBACK;
|
|
454
|
+
}
|
|
307
455
|
try {
|
|
308
|
-
|
|
309
|
-
to:
|
|
310
|
-
data:
|
|
311
|
-
value:
|
|
312
|
-
account:
|
|
456
|
+
return await publicClient2.estimateGas({
|
|
457
|
+
to: step.to,
|
|
458
|
+
data: step.data,
|
|
459
|
+
value: step.value,
|
|
460
|
+
account: exec
|
|
313
461
|
});
|
|
314
462
|
} catch (e) {
|
|
315
463
|
if (s.kind === "deposit" || s.kind === "authorizeAndDeposit") {
|
|
@@ -320,129 +468,43 @@ async function buildEvmMultisignBodyMapleSyrupDeposit(args) {
|
|
|
320
468
|
);
|
|
321
469
|
}
|
|
322
470
|
}
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
327
|
-
if (legacy) {
|
|
328
|
-
let gasPriceWei = await publicClient.getGasPrice();
|
|
329
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
330
|
-
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
331
|
-
}
|
|
332
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
333
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
334
|
-
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
335
|
-
}
|
|
336
|
-
const ser = viem.serializeTransaction({
|
|
337
|
-
type: "legacy",
|
|
338
|
-
to: s.to,
|
|
339
|
-
data: s.data,
|
|
340
|
-
value: s.value,
|
|
341
|
-
gas: gasLimitI,
|
|
342
|
-
gasPrice: gasPriceWei,
|
|
343
|
-
nonce: currentNonce,
|
|
344
|
-
chainId: args.chainId
|
|
345
|
-
});
|
|
346
|
-
const h = viem.keccak256(ser);
|
|
347
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
348
|
-
messageRawBatch.push(ser);
|
|
349
|
-
proposalTxParamsBatch.push({
|
|
350
|
-
nonce: currentNonce,
|
|
351
|
-
gasLimit: gasLimitI.toString(),
|
|
352
|
-
txType: "legacy",
|
|
353
|
-
gasPrice: gasPriceWei.toString()
|
|
354
|
-
});
|
|
355
|
-
if (i === 0) {
|
|
356
|
-
firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
|
|
357
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
471
|
+
return s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : MAPLE_SYRUP_DEPOSIT_FALLBACK;
|
|
358
472
|
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
473
|
+
},
|
|
474
|
+
buildBatchMeta: ({ index, gasLimit }) => {
|
|
475
|
+
const s = steps[index];
|
|
476
|
+
if (s.kind === "approve") {
|
|
477
|
+
return {
|
|
478
|
+
signatureText: JSON.stringify({
|
|
479
|
+
kind: "MapleSyrup",
|
|
480
|
+
name: "ERC20.approve",
|
|
481
|
+
note: "Allow SyrupRouter to pull this deposit amount.",
|
|
482
|
+
spender: router,
|
|
483
|
+
asset,
|
|
484
|
+
pool,
|
|
485
|
+
amountHuman: args.amountHuman
|
|
486
|
+
}),
|
|
487
|
+
evm: { type: "maple_syrup_erc20_approve", version: 1, chainId: chainIdStr },
|
|
488
|
+
maple: { step: "approve_asset", router, pool, asset }
|
|
489
|
+
};
|
|
374
490
|
}
|
|
375
|
-
(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
nonce: currentNonce,
|
|
389
|
-
chainId: args.chainId
|
|
390
|
-
});
|
|
391
|
-
const h = viem.keccak256(ser);
|
|
392
|
-
messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
|
|
393
|
-
messageRawBatch.push(ser);
|
|
394
|
-
proposalTxParamsBatch.push({
|
|
395
|
-
nonce: currentNonce,
|
|
396
|
-
gasLimit: gasLimitI.toString(),
|
|
397
|
-
txType: "eip1559",
|
|
398
|
-
maxFeePerGas: maxFeePerGas.toString(),
|
|
399
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
400
|
-
});
|
|
401
|
-
if (i === 0) {
|
|
402
|
-
firstTxFeePayload = {
|
|
403
|
-
txNonce: currentNonce,
|
|
404
|
-
txGasLimit: gasLimitI.toString(),
|
|
405
|
-
txMaxFeePerGas: maxFeePerGas.toString(),
|
|
406
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
491
|
+
if (s.kind === "deposit") {
|
|
492
|
+
return {
|
|
493
|
+
signatureText: JSON.stringify({
|
|
494
|
+
kind: "MapleSyrup",
|
|
495
|
+
name: "SyrupRouter.deposit",
|
|
496
|
+
function: "deposit(uint256 assets, bytes32 depositData)",
|
|
497
|
+
assets: amountWei.toString(),
|
|
498
|
+
pool,
|
|
499
|
+
router,
|
|
500
|
+
amountHuman: args.amountHuman
|
|
501
|
+
}),
|
|
502
|
+
evm: { type: "maple_syrup_router_deposit", version: 1, chainId: chainIdStr },
|
|
503
|
+
maple: { step: "deposit", router, pool, gasBuildDeposit: { baseGasUnits: gasLimit.toString() } }
|
|
407
504
|
};
|
|
408
|
-
firstDataNo0x = s.data.startsWith("0x") ? s.data.slice(2) : s.data;
|
|
409
505
|
}
|
|
410
|
-
}
|
|
411
|
-
const chainIdStr = String(args.chainId);
|
|
412
|
-
if (s.kind === "approve") {
|
|
413
|
-
batchMeta.push({
|
|
414
|
-
destinationAddress: asset,
|
|
415
|
-
signatureText: JSON.stringify({
|
|
416
|
-
kind: "MapleSyrup",
|
|
417
|
-
name: "ERC20.approve",
|
|
418
|
-
note: "Allow SyrupRouter to pull this deposit amount.",
|
|
419
|
-
spender: router,
|
|
420
|
-
asset,
|
|
421
|
-
pool,
|
|
422
|
-
amountHuman: args.amountHuman
|
|
423
|
-
}),
|
|
424
|
-
evm: { type: "maple_syrup_erc20_approve", version: 1, chainId: chainIdStr },
|
|
425
|
-
maple: { step: "approve_asset", router, pool, asset }
|
|
426
|
-
});
|
|
427
|
-
} else if (s.kind === "deposit") {
|
|
428
|
-
batchMeta.push({
|
|
429
|
-
destinationAddress: router,
|
|
430
|
-
signatureText: JSON.stringify({
|
|
431
|
-
kind: "MapleSyrup",
|
|
432
|
-
name: "SyrupRouter.deposit",
|
|
433
|
-
function: "deposit(uint256 assets, bytes32 depositData)",
|
|
434
|
-
assets: amountWei.toString(),
|
|
435
|
-
pool,
|
|
436
|
-
router,
|
|
437
|
-
amountHuman: args.amountHuman
|
|
438
|
-
}),
|
|
439
|
-
evm: { type: "maple_syrup_router_deposit", version: 1, chainId: chainIdStr },
|
|
440
|
-
maple: { step: "deposit", router, pool, gasBuildDeposit: { baseGasUnits: gasLimitI.toString() } }
|
|
441
|
-
});
|
|
442
|
-
} else {
|
|
443
506
|
const a = args.authorizeSig;
|
|
444
|
-
|
|
445
|
-
destinationAddress: router,
|
|
507
|
+
return {
|
|
446
508
|
signatureText: JSON.stringify({
|
|
447
509
|
kind: "MapleSyrup",
|
|
448
510
|
name: "SyrupRouter.authorizeAndDeposit",
|
|
@@ -456,50 +518,15 @@ async function buildEvmMultisignBodyMapleSyrupDeposit(args) {
|
|
|
456
518
|
amountHuman: args.amountHuman
|
|
457
519
|
}),
|
|
458
520
|
evm: { type: "maple_syrup_router_authorize_and_deposit", version: 1, chainId: chainIdStr },
|
|
459
|
-
maple: { step: "authorize_and_deposit", router, pool, gasBuildDeposit: { baseGasUnits:
|
|
460
|
-
}
|
|
521
|
+
maple: { step: "authorize_and_deposit", router, pool, gasBuildDeposit: { baseGasUnits: gasLimit.toString() } }
|
|
522
|
+
};
|
|
461
523
|
}
|
|
462
|
-
}
|
|
463
|
-
const extraPayload = { batchMeta };
|
|
464
|
-
if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
|
|
465
|
-
extraPayload.customGasChainDetails = args.customGasChainDetails;
|
|
466
|
-
}
|
|
467
|
-
const extraJSON = JSON.stringify(extraPayload);
|
|
468
|
-
const firstSigText = batchMeta[0].signatureText;
|
|
469
|
-
const n = steps.length;
|
|
470
|
-
const finalVerb = stakeMethod === "authorizeAndDeposit" ? "authorizeAndDeposit (permission + deposit)" : "deposit";
|
|
471
|
-
const purposeSuffix = n === 1 ? `Maple Syrup: 1-tx \u2014 ${finalVerb} via SyrupRouter (allowance already set).` : `Maple Syrup: ${n}-tx batch \u2014 approve asset for SyrupRouter, then ${finalVerb}.`;
|
|
472
|
-
const bodyForSign = {
|
|
473
|
-
keyList,
|
|
474
|
-
pubKey: ph,
|
|
475
|
-
msgHash: messageHashes[0],
|
|
476
|
-
msgRaw: firstDataNo0x,
|
|
477
|
-
messageHashes,
|
|
478
|
-
messageRawBatch,
|
|
479
|
-
destinationChainID: String(args.chainId),
|
|
480
|
-
destinationAddress: steps[0].to,
|
|
481
|
-
extraJSON,
|
|
482
|
-
signatureText: firstSigText,
|
|
483
|
-
purpose: (() => {
|
|
484
|
-
const t = args.purposeText.trim();
|
|
485
|
-
return (t ? `${t}
|
|
486
|
-
|
|
487
|
-
` : "") + purposeSuffix;
|
|
488
|
-
})(),
|
|
489
|
-
...firstTxFeePayload,
|
|
490
|
-
proposalTxParams: proposalTxParamsBatch
|
|
491
|
-
};
|
|
492
|
-
if (clientId) bodyForSign.clientId = clientId;
|
|
493
|
-
return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
|
|
524
|
+
});
|
|
494
525
|
}
|
|
495
526
|
async function buildEvmMultisignBodyMaplePoolRequestRedeem(args) {
|
|
496
527
|
if (args.chainId !== 1 && args.chainId !== 11155111) {
|
|
497
528
|
throw new Error("Maple Syrup redeem request is only supported on Ethereum mainnet or Sepolia.");
|
|
498
529
|
}
|
|
499
|
-
const ph = (args.keyGen.pubkeyhex ?? "").trim();
|
|
500
|
-
if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
|
|
501
|
-
const keyList = args.keyGen.keylist ?? [];
|
|
502
|
-
const clientId = firstClientIdFromKeyGen(args.keyGen);
|
|
503
530
|
const pool = viem.getAddress(args.pool);
|
|
504
531
|
const executor = viem.getAddress(args.executorAddress);
|
|
505
532
|
const receiver = executor;
|
|
@@ -520,113 +547,26 @@ async function buildEvmMultisignBodyMaplePoolRequestRedeem(args) {
|
|
|
520
547
|
functionName: "requestRedeem",
|
|
521
548
|
args: [exitShares, receiver]
|
|
522
549
|
});
|
|
523
|
-
const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
|
|
524
|
-
const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
|
|
525
|
-
const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
|
|
526
|
-
const useCustomGas = args.useCustomGas;
|
|
527
|
-
const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
|
|
528
|
-
const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
|
|
529
|
-
const currentNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
|
|
530
|
-
let estimatedGas;
|
|
531
|
-
try {
|
|
532
|
-
estimatedGas = await publicClient.estimateGas({
|
|
533
|
-
to: pool,
|
|
534
|
-
data,
|
|
535
|
-
value: 0n,
|
|
536
|
-
account: executor
|
|
537
|
-
});
|
|
538
|
-
} catch {
|
|
539
|
-
estimatedGas = MAPLE_REQUEST_REDEEM_FALLBACK;
|
|
540
|
-
}
|
|
541
|
-
const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
|
|
542
550
|
const chainIdStr = String(args.chainId);
|
|
543
|
-
let firstTxFeePayload = {};
|
|
544
|
-
let ser;
|
|
545
|
-
let proposalTxParams0;
|
|
546
|
-
if (legacy) {
|
|
547
|
-
let gasPriceWei = await publicClient.getGasPrice();
|
|
548
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
549
|
-
gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
550
|
-
}
|
|
551
|
-
if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
|
|
552
|
-
const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
|
|
553
|
-
if (configured > gasPriceWei) gasPriceWei = configured;
|
|
554
|
-
}
|
|
555
|
-
ser = viem.serializeTransaction({
|
|
556
|
-
type: "legacy",
|
|
557
|
-
to: pool,
|
|
558
|
-
data,
|
|
559
|
-
value: 0n,
|
|
560
|
-
gas: gasLimitI,
|
|
561
|
-
gasPrice: gasPriceWei,
|
|
562
|
-
nonce: currentNonce,
|
|
563
|
-
chainId: args.chainId
|
|
564
|
-
});
|
|
565
|
-
firstTxFeePayload = {
|
|
566
|
-
txNonce: currentNonce,
|
|
567
|
-
txGasLimit: gasLimitI.toString(),
|
|
568
|
-
txGasPrice: gasPriceWei.toString()
|
|
569
|
-
};
|
|
570
|
-
proposalTxParams0 = {
|
|
571
|
-
nonce: currentNonce,
|
|
572
|
-
gasLimit: gasLimitI.toString(),
|
|
573
|
-
txType: "legacy",
|
|
574
|
-
gasPrice: gasPriceWei.toString()
|
|
575
|
-
};
|
|
576
|
-
} else {
|
|
577
|
-
const fetchedBase = feeParams.baseFeeGwei ?? 0;
|
|
578
|
-
const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
|
|
579
|
-
const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
|
|
580
|
-
const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
|
|
581
|
-
const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
|
|
582
|
-
const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
|
|
583
|
-
const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
|
|
584
|
-
const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
|
|
585
|
-
const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
|
|
586
|
-
let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
|
|
587
|
-
let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
|
|
588
|
-
if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
|
|
589
|
-
maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
590
|
-
maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
|
|
591
|
-
}
|
|
592
|
-
({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
|
|
593
|
-
maxFeePerGas,
|
|
594
|
-
maxPriorityFeePerGas,
|
|
595
|
-
latestBaseFeeWei
|
|
596
|
-
));
|
|
597
|
-
ser = viem.serializeTransaction({
|
|
598
|
-
type: "eip1559",
|
|
599
|
-
to: pool,
|
|
600
|
-
data,
|
|
601
|
-
value: 0n,
|
|
602
|
-
gas: gasLimitI,
|
|
603
|
-
maxFeePerGas,
|
|
604
|
-
maxPriorityFeePerGas,
|
|
605
|
-
nonce: currentNonce,
|
|
606
|
-
chainId: args.chainId
|
|
607
|
-
});
|
|
608
|
-
firstTxFeePayload = {
|
|
609
|
-
txNonce: currentNonce,
|
|
610
|
-
txGasLimit: gasLimitI.toString(),
|
|
611
|
-
txMaxFeePerGas: maxFeePerGas.toString(),
|
|
612
|
-
txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
613
|
-
};
|
|
614
|
-
proposalTxParams0 = {
|
|
615
|
-
nonce: currentNonce,
|
|
616
|
-
gasLimit: gasLimitI.toString(),
|
|
617
|
-
txType: "eip1559",
|
|
618
|
-
maxFeePerGas: maxFeePerGas.toString(),
|
|
619
|
-
maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
|
-
const h = viem.keccak256(ser);
|
|
623
|
-
const messageHashes = [h.startsWith("0x") ? h.slice(2) : h];
|
|
624
|
-
const messageRawBatch = [ser];
|
|
625
|
-
const proposalTxParamsBatch = [proposalTxParams0];
|
|
626
551
|
const firstDataNo0x = data.startsWith("0x") ? data.slice(2) : data;
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
552
|
+
const purposeSuffix = "Maple Syrup: 1-tx \u2014 request redeem (queue withdrawal of underlying from pool shares).";
|
|
553
|
+
return buildEvmMultisignBatch({
|
|
554
|
+
context: {
|
|
555
|
+
chainCategory: "evm",
|
|
556
|
+
keyGen: args.keyGen,
|
|
557
|
+
purposeText: args.purposeText,
|
|
558
|
+
chainId: args.chainId,
|
|
559
|
+
rpcUrl: args.rpcUrl,
|
|
560
|
+
executorAddress: executor,
|
|
561
|
+
chainDetail: args.chainDetail,
|
|
562
|
+
useCustomGas: args.useCustomGas,
|
|
563
|
+
customGasChainDetails: args.customGasChainDetails
|
|
564
|
+
},
|
|
565
|
+
steps: [{ to: pool, data, value: 0n, fallbackGas: MAPLE_REQUEST_REDEEM_FALLBACK }],
|
|
566
|
+
purposeSuffix,
|
|
567
|
+
firstMsgRawNo0x: firstDataNo0x,
|
|
568
|
+
destinationAddress: pool,
|
|
569
|
+
buildBatchMeta: ({ gasLimit }) => ({
|
|
630
570
|
signatureText: JSON.stringify({
|
|
631
571
|
kind: "MapleSyrup",
|
|
632
572
|
name: "PoolV2.requestRedeem",
|
|
@@ -637,37 +577,90 @@ async function buildEvmMultisignBodyMaplePoolRequestRedeem(args) {
|
|
|
637
577
|
pool
|
|
638
578
|
}),
|
|
639
579
|
evm: { type: "maple_pool_v2_request_redeem", version: 1, chainId: chainIdStr },
|
|
640
|
-
maple: { step: "request_redeem", pool, gasBuildRedeem: { baseGasUnits:
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
580
|
+
maple: { step: "request_redeem", pool, gasBuildRedeem: { baseGasUnits: gasLimit.toString() } }
|
|
581
|
+
})
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
async function postJsonViaOptionalProxy(args) {
|
|
585
|
+
const r = await fetch(args.directUrl, {
|
|
586
|
+
method: "POST",
|
|
587
|
+
headers: { "content-type": "application/json" },
|
|
588
|
+
body: JSON.stringify(args.body)
|
|
589
|
+
});
|
|
590
|
+
if (!r.ok) {
|
|
591
|
+
const t = await r.text().catch(() => "");
|
|
592
|
+
throw new Error(t ? `HTTP ${r.status}: ${t.slice(0, 200)}` : `HTTP ${r.status}`);
|
|
646
593
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
const bodyForSign = {
|
|
650
|
-
keyList,
|
|
651
|
-
pubKey: ph,
|
|
652
|
-
msgHash: messageHashes[0],
|
|
653
|
-
msgRaw: firstDataNo0x,
|
|
654
|
-
messageHashes,
|
|
655
|
-
messageRawBatch,
|
|
656
|
-
destinationChainID: String(args.chainId),
|
|
657
|
-
destinationAddress: pool,
|
|
658
|
-
extraJSON,
|
|
659
|
-
signatureText: batchMeta[0].signatureText,
|
|
660
|
-
purpose: (() => {
|
|
661
|
-
const t = args.purposeText.trim();
|
|
662
|
-
return (t ? `${t}
|
|
594
|
+
return await r.json();
|
|
595
|
+
}
|
|
663
596
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
597
|
+
// src/protocols/evm/maple/graphql.ts
|
|
598
|
+
var POOLS_GQL = `
|
|
599
|
+
query MapleSyrupPools {
|
|
600
|
+
poolV2S(where: { syrupRouter_not: null }) {
|
|
601
|
+
id
|
|
602
|
+
name
|
|
603
|
+
asset {
|
|
604
|
+
id
|
|
605
|
+
symbol
|
|
606
|
+
decimals
|
|
607
|
+
}
|
|
608
|
+
syrupRouter {
|
|
609
|
+
id
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
`;
|
|
614
|
+
function normalizePool(p) {
|
|
615
|
+
return {
|
|
616
|
+
id: viem.getAddress(p.id),
|
|
617
|
+
name: (p.name ?? "").trim(),
|
|
618
|
+
asset: {
|
|
619
|
+
id: viem.getAddress(p.asset.id),
|
|
620
|
+
symbol: (p.asset.symbol ?? "").trim(),
|
|
621
|
+
decimals: Number(p.asset.decimals)
|
|
622
|
+
},
|
|
623
|
+
syrupRouter: { id: viem.getAddress(p.syrupRouter.id) }
|
|
668
624
|
};
|
|
669
|
-
|
|
670
|
-
|
|
625
|
+
}
|
|
626
|
+
async function mapleGraphqlPost(args) {
|
|
627
|
+
const endpoint = mapleGraphqlEndpointForChain(args.chainId);
|
|
628
|
+
if (!endpoint) throw new Error(`Maple GraphQL is not configured for chain ${args.chainId}`);
|
|
629
|
+
const body = { query: args.query, variables: args.variables ?? {} };
|
|
630
|
+
return postJsonViaOptionalProxy({
|
|
631
|
+
directUrl: endpoint,
|
|
632
|
+
body,
|
|
633
|
+
proxyEnvelope: { chainId: args.chainId, query: args.query, variables: args.variables ?? {} }
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
async function fetchMapleSyrupPools(chainId) {
|
|
637
|
+
const raw = await mapleGraphqlPost({ chainId, query: POOLS_GQL });
|
|
638
|
+
if (raw.errors?.length) {
|
|
639
|
+
throw new Error(raw.errors.map((e) => e.message ?? "GraphQL error").join("; "));
|
|
640
|
+
}
|
|
641
|
+
const rows = raw.data?.poolV2S ?? [];
|
|
642
|
+
return rows.map(normalizePool);
|
|
643
|
+
}
|
|
644
|
+
var ACCOUNT_GQL = `
|
|
645
|
+
query MapleAccount($accountId: ID!) {
|
|
646
|
+
account(id: $accountId) {
|
|
647
|
+
isSyrupLender
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
`;
|
|
651
|
+
async function fetchMapleAccountIsSyrupLender(args) {
|
|
652
|
+
try {
|
|
653
|
+
const raw = await mapleGraphqlPost({
|
|
654
|
+
chainId: args.chainId,
|
|
655
|
+
query: ACCOUNT_GQL,
|
|
656
|
+
variables: { accountId: args.account.toLowerCase() }
|
|
657
|
+
});
|
|
658
|
+
const acct = raw.data?.account;
|
|
659
|
+
if (!acct) return null;
|
|
660
|
+
return Boolean(acct.isSyrupLender);
|
|
661
|
+
} catch {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
671
664
|
}
|
|
672
665
|
|
|
673
666
|
// src/protocols/evm/maple/index.ts
|
|
@@ -696,6 +689,8 @@ exports.MAPLE_SYRUP_DEPOSIT_DATA_ASCII = MAPLE_SYRUP_DEPOSIT_DATA_ASCII;
|
|
|
696
689
|
exports.MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK = MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK;
|
|
697
690
|
exports.buildEvmMultisignBodyMaplePoolRequestRedeem = buildEvmMultisignBodyMaplePoolRequestRedeem;
|
|
698
691
|
exports.buildEvmMultisignBodyMapleSyrupDeposit = buildEvmMultisignBodyMapleSyrupDeposit;
|
|
692
|
+
exports.fetchMapleAccountIsSyrupLender = fetchMapleAccountIsSyrupLender;
|
|
693
|
+
exports.fetchMapleSyrupPools = fetchMapleSyrupPools;
|
|
699
694
|
exports.isMapleSyrupSupportedChain = isMapleSyrupSupportedChain;
|
|
700
695
|
exports.mapleGraphqlEndpointForChain = mapleGraphqlEndpointForChain;
|
|
701
696
|
exports.mapleProtocolModule = mapleProtocolModule;
|