@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,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/keygen.ts
29
- function firstClientIdFromKeyGen(data) {
30
- const map = data?.ClientKeys;
31
- if (!map || typeof map !== "object") return null;
32
- for (const v of Object.values(map)) {
33
- if (typeof v === "string" && v.trim()) return v.trim();
34
- }
35
- return null;
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/chains/evm/txParams.ts
39
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
40
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
41
- return estimatedGas;
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 cfg = BigInt(Math.floor(chainGasLimit));
44
- return cfg > estimatedGas ? cfg : estimatedGas;
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
- async function fetchChainFeeParams(rpcUrl, chainId) {
47
- const url = rpcUrl.trim();
48
- if (!url) return { isEip1559: false };
49
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
50
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
51
- const chain = viem.defineChain({
52
- id: chainIdNum,
53
- name: "Discovery",
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: [url] } }
56
- });
57
- const publicClient = viem.createPublicClient({
58
- chain,
59
- transport: viem.http(url)
114
+ rpcUrls: { default: { http: [rpcUrl] } }
60
115
  });
61
- const getGasPriceGwei = async () => {
62
- const gasPriceWei = await publicClient.getGasPrice();
63
- return parseFloat(viem.formatUnits(gasPriceWei, 9));
64
- };
65
- try {
66
- const block = await publicClient.getBlock({ blockTag: "latest" });
67
- const baseFeePerGas = block?.baseFeePerGas;
68
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
69
- const gasPriceGwei2 = await getGasPriceGwei();
70
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
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
- const baseFeeGwei = parseFloat(viem.formatUnits(baseFeePerGas, 9));
73
- let priorityFeeGwei;
74
- try {
75
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
76
- priorityFeeGwei = parseFloat(viem.formatUnits(priorityWei, 9));
77
- } catch {
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
- const gasPriceGwei = await getGasPriceGwei();
80
- return {
81
- isEip1559: true,
82
- baseFeeGwei,
83
- priorityFeeGwei,
84
- gasPriceGwei
85
- };
86
- } catch {
87
- try {
88
- const gasPriceWei = await publicClient.getGasPrice();
89
- const gasPriceGwei = parseFloat(viem.formatUnits(gasPriceWei, 9));
90
- return { isEip1559: false, gasPriceGwei };
91
- } catch {
92
- return { isEip1559: false };
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
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
97
- let maxP = maxPriorityFeePerGas;
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
- if (maxF < maxP) {
103
- maxF = baseWei > 0n ? baseWei + maxP + viem.parseGwei("0.001") : maxP * 2n;
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 { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
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 feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
287
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
288
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
289
- const useCustomGas = args.useCustomGas;
290
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
291
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
292
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
293
- const messageHashes = [];
294
- const messageRawBatch = [];
295
- const proposalTxParamsBatch = [];
296
- const batchMeta = [];
297
- let firstTxFeePayload = {};
298
- let firstDataNo0x = "";
299
- for (let i = 0; i < steps.length; i++) {
300
- const s = steps[i];
301
- const currentNonce = baseNonce + i;
302
- let estimatedGas;
303
- const skipFinalStakeEstimateBecausePriorApproves = (s.kind === "deposit" || s.kind === "authorizeAndDeposit") && i > 0;
304
- if (skipFinalStakeEstimateBecausePriorApproves) {
305
- estimatedGas = MAPLE_SYRUP_DEPOSIT_FALLBACK;
306
- } else {
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
- estimatedGas = await publicClient.estimateGas({
309
- to: s.to,
310
- data: s.data,
311
- value: s.value,
312
- account: executor
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
- estimatedGas = s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : MAPLE_SYRUP_DEPOSIT_FALLBACK;
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
- } else {
360
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
361
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
362
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
363
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
364
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
365
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
366
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
367
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
368
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
369
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
370
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
371
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
372
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
373
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
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
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
376
- maxFeePerGas,
377
- maxPriorityFeePerGas,
378
- latestBaseFeeWei
379
- ));
380
- const ser = viem.serializeTransaction({
381
- type: "eip1559",
382
- to: s.to,
383
- data: s.data,
384
- value: s.value,
385
- gas: gasLimitI,
386
- maxFeePerGas,
387
- maxPriorityFeePerGas,
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
- batchMeta.push({
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: gasLimitI.toString() } }
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 batchMeta = [
628
- {
629
- destinationAddress: pool,
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: gasLimitI.toString() } }
641
- }
642
- ];
643
- const extraPayload = { batchMeta };
644
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
645
- extraPayload.customGasChainDetails = args.customGasChainDetails;
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
- const extraJSON = JSON.stringify(extraPayload);
648
- const purposeSuffix = "Maple Syrup: 1-tx \u2014 request redeem (queue withdrawal of underlying from pool shares).";
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
- ` : "") + purposeSuffix;
665
- })(),
666
- ...firstTxFeePayload,
667
- proposalTxParams: proposalTxParamsBatch
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
- if (clientId) bodyForSign.clientId = clientId;
670
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
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;