@continuumdao/ctm-mpc-defi 0.2.0 → 0.2.1

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