@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.
Files changed (100) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +563 -5
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +166 -20
  5. package/dist/agent/catalog.js +551 -7
  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 +13 -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 +79 -224
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +26 -26
  18. package/dist/chains/evm/index.js +69 -209
  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 +68 -106
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.ts +21 -36
  25. package/dist/core/index.js +57 -96
  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 +356 -1855
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -11
  31. package/dist/index.js +332 -1826
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +1152 -669
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/aave-v4/index.d.ts +418 -3
  36. package/dist/protocols/evm/aave-v4/index.js +1126 -670
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  38. package/dist/protocols/evm/curve-dao/index.cjs +257 -131
  39. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  40. package/dist/protocols/evm/curve-dao/index.d.ts +69 -5
  41. package/dist/protocols/evm/curve-dao/index.js +242 -124
  42. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  43. package/dist/protocols/evm/ethena/index.cjs +394 -402
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  45. package/dist/protocols/evm/ethena/index.d.ts +47 -3
  46. package/dist/protocols/evm/ethena/index.js +390 -404
  47. package/dist/protocols/evm/ethena/index.js.map +1 -1
  48. package/dist/protocols/evm/euler-v2/index.cjs +2810 -1191
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  50. package/dist/protocols/evm/euler-v2/index.d.ts +465 -3
  51. package/dist/protocols/evm/euler-v2/index.js +2761 -1192
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  53. package/dist/protocols/evm/lido/index.cjs +351 -236
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  55. package/dist/protocols/evm/lido/index.d.ts +34 -4
  56. package/dist/protocols/evm/lido/index.js +348 -238
  57. package/dist/protocols/evm/lido/index.js.map +1 -1
  58. package/dist/protocols/evm/maple/index.cjs +390 -395
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  60. package/dist/protocols/evm/maple/index.d.ts +23 -3
  61. package/dist/protocols/evm/maple/index.js +390 -397
  62. package/dist/protocols/evm/maple/index.js.map +1 -1
  63. package/dist/protocols/evm/sky/index.cjs +454 -232
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  65. package/dist/protocols/evm/sky/index.d.ts +57 -3
  66. package/dist/protocols/evm/sky/index.js +444 -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;
79
+ }
80
+ const valueWei = first.valueWei;
81
+ if (valueWei != null && valueWei > 0n) {
82
+ bodyForSign.value = valueWei.toString();
40
83
  }
41
- const cfg = BigInt(Math.floor(chainGasLimit));
42
- return cfg > estimatedGas ? cfg : estimatedGas;
84
+ if (clientId) bodyForSign.clientId = clientId;
85
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
86
+ }
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;
43
92
  }
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",
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;
329
- }
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;
469
+ return s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : MAPLE_SYRUP_DEPOSIT_FALLBACK;
356
470
  }
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,90 @@ 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;
578
+ maple: { step: "request_redeem", pool, gasBuildRedeem: { baseGasUnits: gasLimit.toString() } }
579
+ })
580
+ });
581
+ }
582
+ async function postJsonViaOptionalProxy(args) {
583
+ const r = await fetch(args.directUrl, {
584
+ method: "POST",
585
+ headers: { "content-type": "application/json" },
586
+ body: JSON.stringify(args.body)
587
+ });
588
+ if (!r.ok) {
589
+ const t = await r.text().catch(() => "");
590
+ throw new Error(t ? `HTTP ${r.status}: ${t.slice(0, 200)}` : `HTTP ${r.status}`);
644
591
  }
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}
592
+ return await r.json();
593
+ }
661
594
 
662
- ` : "") + purposeSuffix;
663
- })(),
664
- ...firstTxFeePayload,
665
- proposalTxParams: proposalTxParamsBatch
595
+ // src/protocols/evm/maple/graphql.ts
596
+ var POOLS_GQL = `
597
+ query MapleSyrupPools {
598
+ poolV2S(where: { syrupRouter_not: null }) {
599
+ id
600
+ name
601
+ asset {
602
+ id
603
+ symbol
604
+ decimals
605
+ }
606
+ syrupRouter {
607
+ id
608
+ }
609
+ }
610
+ }
611
+ `;
612
+ function normalizePool(p) {
613
+ return {
614
+ id: getAddress(p.id),
615
+ name: (p.name ?? "").trim(),
616
+ asset: {
617
+ id: getAddress(p.asset.id),
618
+ symbol: (p.asset.symbol ?? "").trim(),
619
+ decimals: Number(p.asset.decimals)
620
+ },
621
+ syrupRouter: { id: getAddress(p.syrupRouter.id) }
666
622
  };
667
- if (clientId) bodyForSign.clientId = clientId;
668
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
623
+ }
624
+ async function mapleGraphqlPost(args) {
625
+ const endpoint = mapleGraphqlEndpointForChain(args.chainId);
626
+ if (!endpoint) throw new Error(`Maple GraphQL is not configured for chain ${args.chainId}`);
627
+ const body = { query: args.query, variables: args.variables ?? {} };
628
+ return postJsonViaOptionalProxy({
629
+ directUrl: endpoint,
630
+ body,
631
+ proxyEnvelope: { chainId: args.chainId, query: args.query, variables: args.variables ?? {} }
632
+ });
633
+ }
634
+ async function fetchMapleSyrupPools(chainId) {
635
+ const raw = await mapleGraphqlPost({ chainId, query: POOLS_GQL });
636
+ if (raw.errors?.length) {
637
+ throw new Error(raw.errors.map((e) => e.message ?? "GraphQL error").join("; "));
638
+ }
639
+ const rows = raw.data?.poolV2S ?? [];
640
+ return rows.map(normalizePool);
641
+ }
642
+ var ACCOUNT_GQL = `
643
+ query MapleAccount($accountId: ID!) {
644
+ account(id: $accountId) {
645
+ isSyrupLender
646
+ }
647
+ }
648
+ `;
649
+ async function fetchMapleAccountIsSyrupLender(args) {
650
+ try {
651
+ const raw = await mapleGraphqlPost({
652
+ chainId: args.chainId,
653
+ query: ACCOUNT_GQL,
654
+ variables: { accountId: args.account.toLowerCase() }
655
+ });
656
+ const acct = raw.data?.account;
657
+ if (!acct) return null;
658
+ return Boolean(acct.isSyrupLender);
659
+ } catch {
660
+ return null;
661
+ }
669
662
  }
670
663
 
671
664
  // src/protocols/evm/maple/index.ts
@@ -688,6 +681,6 @@ var mapleProtocolModule = {
688
681
  };
689
682
  registerProtocolModule(mapleProtocolModule);
690
683
 
691
- export { MAPLE_INTEGRATION_DOCS_URL, MAPLE_PROTOCOL_ID, MAPLE_SYRUP_DEPOSIT_DATA_ASCII, MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK, buildEvmMultisignBodyMaplePoolRequestRedeem, buildEvmMultisignBodyMapleSyrupDeposit, isMapleSyrupSupportedChain, mapleGraphqlEndpointForChain, mapleProtocolModule, parseMapleStakeAuthInputs, readMaplePoolShareDecimals, readMapleStakePreviewShares, readMapleUnstakeExitSharesForAssets };
684
+ export { MAPLE_INTEGRATION_DOCS_URL, MAPLE_PROTOCOL_ID, MAPLE_SYRUP_DEPOSIT_DATA_ASCII, MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK, buildEvmMultisignBodyMaplePoolRequestRedeem, buildEvmMultisignBodyMapleSyrupDeposit, fetchMapleAccountIsSyrupLender, fetchMapleSyrupPools, isMapleSyrupSupportedChain, mapleGraphqlEndpointForChain, mapleProtocolModule, parseMapleStakeAuthInputs, readMaplePoolShareDecimals, readMapleStakePreviewShares, readMapleUnstakeExitSharesForAssets };
692
685
  //# sourceMappingURL=index.js.map
693
686
  //# sourceMappingURL=index.js.map