@continuumdao/ctm-mpc-defi 0.1.4 → 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 (94) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +1388 -144
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +881 -17
  5. package/dist/agent/catalog.js +1327 -145
  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 -213
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +15 -25
  18. package/dist/chains/evm/index.js +21 -199
  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 -1184
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -10
  31. package/dist/index.js +227 -1156
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +1710 -0
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -0
  35. package/dist/protocols/evm/aave-v4/index.d.ts +499 -0
  36. package/dist/protocols/evm/aave-v4/index.js +1666 -0
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -0
  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 +853 -0
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -0
  45. package/dist/protocols/evm/ethena/index.d.ts +160 -0
  46. package/dist/protocols/evm/ethena/index.js +831 -0
  47. package/dist/protocols/evm/ethena/index.js.map +1 -0
  48. package/dist/protocols/evm/euler-v2/index.cjs +1585 -0
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -0
  50. package/dist/protocols/evm/euler-v2/index.d.ts +316 -0
  51. package/dist/protocols/evm/euler-v2/index.js +1560 -0
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -0
  53. package/dist/protocols/evm/lido/index.cjs +839 -0
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -0
  55. package/dist/protocols/evm/lido/index.d.ts +119 -0
  56. package/dist/protocols/evm/lido/index.js +814 -0
  57. package/dist/protocols/evm/lido/index.js.map +1 -0
  58. package/dist/protocols/evm/maple/index.cjs +619 -0
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -0
  60. package/dist/protocols/evm/maple/index.d.ts +108 -0
  61. package/dist/protocols/evm/maple/index.js +605 -0
  62. package/dist/protocols/evm/maple/index.js.map +1 -0
  63. package/dist/protocols/evm/sky/index.cjs +1259 -0
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -0
  65. package/dist/protocols/evm/sky/index.d.ts +217 -0
  66. package/dist/protocols/evm/sky/index.js +1234 -0
  67. package/dist/protocols/evm/sky/index.js.map +1 -0
  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 +43 -8
  77. package/dist/agent/catalog.d.cts +0 -195
  78. package/dist/chains/evm/index.d.cts +0 -62
  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 -15
  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/curve-dao/index.d.cts +0 -147
  89. package/dist/protocols/evm/uniswap-v4/index.d.cts +0 -324
  90. package/dist/registry-BwZoE668.d.cts +0 -8
  91. package/dist/txParams-BC7ogvdR.d.cts +0 -19
  92. package/dist/txParams-BC7ogvdR.d.ts +0 -19
  93. package/dist/types-B8idm_gu.d.cts +0 -34
  94. package/dist/types-Ce2qNHai.d.ts +0 -57
@@ -0,0 +1,619 @@
1
+ 'use strict';
2
+
3
+ var viem = require('viem');
4
+ var continuumNodeSdk = require('@continuumdao/continuum-node-sdk');
5
+
6
+ // src/core/registry.ts
7
+ var modules = [];
8
+ function registerProtocolModule(mod) {
9
+ const existing = modules.findIndex((m) => m.id === mod.id);
10
+ if (existing >= 0) {
11
+ modules[existing] = mod;
12
+ } else {
13
+ modules.push(mod);
14
+ }
15
+ }
16
+
17
+ // src/protocols/evm/maple/constants.ts
18
+ var MAPLE_SYRUP_DEPOSIT_DATA_ASCII = "0:continuumdao";
19
+ var MAPLE_INTEGRATION_DOCS_URL = "https://docs.maple.finance/integrate/ethereum-mainnet/frontend-integration";
20
+ function mapleGraphqlEndpointForChain(chainId) {
21
+ if (chainId === 1) return "https://api.maple.finance/v2/graphql";
22
+ if (chainId === 11155111) return "https://sepolia.api.maple.finance/v2/graphql";
23
+ return null;
24
+ }
25
+ function isMapleSyrupSupportedChain(chainId) {
26
+ return chainId === 1 || chainId === 11155111;
27
+ }
28
+
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;
37
+ }
38
+
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;
81
+ }
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) };
88
+ }
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",
113
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
114
+ rpcUrls: { default: { http: [rpcUrl] } }
115
+ });
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
+ }
143
+ }
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;
151
+ }
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;
237
+ }
238
+ }
239
+ const extraJSON = {};
240
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
241
+ extraJSON.customGasChainDetails = customGasChainDetails;
242
+ }
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();
255
+ }
256
+ return result;
257
+ }
258
+
259
+ // src/protocols/evm/maple/multisign.ts
260
+ var AAVE_ERC20_APPROVE_FALLBACK = 100000n;
261
+ var MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK = 1500000n;
262
+ var MAPLE_SYRUP_DEPOSIT_FALLBACK = MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK;
263
+ var MAPLE_REQUEST_REDEEM_FALLBACK = 1200000n;
264
+ var erc20AllowanceAbi = viem.parseAbi([
265
+ "function allowance(address owner, address spender) view returns (uint256)",
266
+ "function decimals() view returns (uint8)"
267
+ ]);
268
+ var erc20ApproveAbi = viem.parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]);
269
+ var syrupRouterAbi = viem.parseAbi([
270
+ "function deposit(uint256 assets, bytes32 depositData)",
271
+ "function authorizeAndDeposit(uint256 bitmap,uint256 deadline,uint8 auth_v,bytes32 auth_r,bytes32 auth_s,uint256 amount,bytes32 depositData)"
272
+ ]);
273
+ var poolV2ExitAbi = viem.parseAbi([
274
+ "function previewDeposit(uint256 assets) view returns (uint256 shares)",
275
+ "function convertToExitShares(uint256 assets_) view returns (uint256 shares_)",
276
+ "function requestRedeem(uint256 shares, address receiver) returns (uint256)",
277
+ "function decimals() view returns (uint8)"
278
+ ]);
279
+ function formatBytes32DataLabel(s) {
280
+ const b = viem.stringToBytes(s);
281
+ if (b.length > 32) throw new Error("Maple depositData label is too long for bytes32.");
282
+ const padded = new Uint8Array(32);
283
+ padded.set(b);
284
+ return viem.toHex(padded);
285
+ }
286
+ function publicClientForChain(chainId, rpcUrl) {
287
+ const rpc = rpcUrl.trim();
288
+ if (chainId === 1) {
289
+ const ch = viem.defineChain({
290
+ id: 1,
291
+ name: "Ethereum",
292
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
293
+ rpcUrls: { default: { http: [rpc] } }
294
+ });
295
+ return viem.createPublicClient({ chain: ch, transport: viem.http(rpc) });
296
+ }
297
+ if (chainId === 11155111) {
298
+ const ch = viem.defineChain({
299
+ id: 11155111,
300
+ name: "Sepolia",
301
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
302
+ rpcUrls: { default: { http: [rpc] } }
303
+ });
304
+ return viem.createPublicClient({ chain: ch, transport: viem.http(rpc) });
305
+ }
306
+ throw new Error(`Maple Syrup multisign: unsupported chain id ${chainId}.`);
307
+ }
308
+ async function readMaplePoolShareDecimals(args) {
309
+ const client = publicClientForChain(args.chainId, args.rpcUrl);
310
+ const d = await client.readContract({
311
+ address: viem.getAddress(args.pool),
312
+ abi: poolV2ExitAbi,
313
+ functionName: "decimals"
314
+ });
315
+ return Number(d);
316
+ }
317
+ async function readMapleStakePreviewShares(args) {
318
+ if (args.assetAmountWei <= 0n) return 0n;
319
+ const client = publicClientForChain(args.chainId, args.rpcUrl);
320
+ return client.readContract({
321
+ address: viem.getAddress(args.pool),
322
+ abi: poolV2ExitAbi,
323
+ functionName: "previewDeposit",
324
+ args: [args.assetAmountWei]
325
+ });
326
+ }
327
+ async function readMapleUnstakeExitSharesForAssets(args) {
328
+ if (args.assetAmountWei <= 0n) return 0n;
329
+ const client = publicClientForChain(args.chainId, args.rpcUrl);
330
+ return client.readContract({
331
+ address: viem.getAddress(args.pool),
332
+ abi: poolV2ExitAbi,
333
+ functionName: "convertToExitShares",
334
+ args: [args.assetAmountWei]
335
+ });
336
+ }
337
+ function parseMapleStakeAuthInputs(args) {
338
+ const bitmapT = args.bitmap.trim();
339
+ let bitmap;
340
+ if (!bitmapT) return { ok: false, message: "Enter authorization bitmap (uint256)." };
341
+ try {
342
+ bitmap = bitmapT.startsWith("0x") || bitmapT.startsWith("0X") ? BigInt(bitmapT) : BigInt(bitmapT);
343
+ } catch {
344
+ return { ok: false, message: "Bitmap must be a decimal or 0x-prefixed integer." };
345
+ }
346
+ const deadlineT = args.deadline.trim();
347
+ if (!deadlineT || !/^\d+$/.test(deadlineT)) {
348
+ return { ok: false, message: "Deadline must be a Unix timestamp (seconds), decimal digits only." };
349
+ }
350
+ const deadline = BigInt(deadlineT);
351
+ if (deadline <= 0n) return { ok: false, message: "Deadline must be positive." };
352
+ const vT = args.v.trim();
353
+ if (!/^\d+$/.test(vT)) return { ok: false, message: "v must be an integer 0\u2013255 (often 27 or 28)." };
354
+ const v = Number(vT);
355
+ if (!Number.isFinite(v) || v < 0 || v > 255) return { ok: false, message: "v must be between 0 and 255." };
356
+ let r = args.r.trim();
357
+ let s = args.s.trim();
358
+ if (!r.startsWith("0x")) r = "0x" + r;
359
+ if (!s.startsWith("0x")) s = "0x" + s;
360
+ if (!/^0x[0-9a-fA-F]{64}$/.test(r)) return { ok: false, message: "r must be 32 bytes (64 hex chars), optional 0x." };
361
+ if (!/^0x[0-9a-fA-F]{64}$/.test(s)) return { ok: false, message: "s must be 32 bytes (64 hex chars), optional 0x." };
362
+ return { ok: true, sig: { bitmap, deadline, v, r, s } };
363
+ }
364
+ async function buildEvmMultisignBodyMapleSyrupDeposit(args) {
365
+ if (args.chainId !== 1 && args.chainId !== 11155111) {
366
+ throw new Error("Maple Syrup deposit is only supported on Ethereum mainnet or Sepolia.");
367
+ }
368
+ const asset = viem.getAddress(args.asset);
369
+ const router = viem.getAddress(args.syrupRouter);
370
+ const pool = viem.getAddress(args.pool);
371
+ const executor = viem.getAddress(args.executorAddress);
372
+ const depositData = formatBytes32DataLabel(MAPLE_SYRUP_DEPOSIT_DATA_ASCII);
373
+ const publicClient = publicClientForChain(args.chainId, args.rpcUrl);
374
+ const dec = args.assetDecimals;
375
+ if (!Number.isFinite(dec) || dec < 0 || dec > 255) throw new Error("Invalid asset decimals.");
376
+ const amountWei = viem.parseUnits(args.amountHuman, dec);
377
+ if (amountWei === 0n) throw new Error("Amount is zero after converting with token decimals.");
378
+ const stakeMethod = args.stakeMethod ?? "deposit";
379
+ if (stakeMethod === "authorizeAndDeposit") {
380
+ const a = args.authorizeSig;
381
+ if (!a) throw new Error("authorizeSig is required for authorizeAndDeposit.");
382
+ if (a.v < 0 || a.v > 255) throw new Error("Invalid authorization v (must be 0\u2013255).");
383
+ }
384
+ const steps = [];
385
+ const currentAllowance = await publicClient.readContract({
386
+ address: asset,
387
+ abi: erc20AllowanceAbi,
388
+ functionName: "allowance",
389
+ args: [executor, router]
390
+ });
391
+ if (currentAllowance < amountWei) {
392
+ if (currentAllowance > 0n) {
393
+ const dataReset = viem.encodeFunctionData({
394
+ abi: erc20ApproveAbi,
395
+ functionName: "approve",
396
+ args: [router, 0n]
397
+ });
398
+ steps.push({ kind: "approve", to: asset, data: dataReset, value: 0n });
399
+ }
400
+ const dataApprove = viem.encodeFunctionData({
401
+ abi: erc20ApproveAbi,
402
+ functionName: "approve",
403
+ args: [router, amountWei]
404
+ });
405
+ steps.push({ kind: "approve", to: asset, data: dataApprove, value: 0n });
406
+ }
407
+ if (stakeMethod === "authorizeAndDeposit") {
408
+ const a = args.authorizeSig;
409
+ const authCalldata = viem.encodeFunctionData({
410
+ abi: syrupRouterAbi,
411
+ functionName: "authorizeAndDeposit",
412
+ args: [a.bitmap, a.deadline, a.v, a.r, a.s, amountWei, depositData]
413
+ });
414
+ steps.push({ kind: "authorizeAndDeposit", to: router, data: authCalldata, value: 0n });
415
+ } else {
416
+ const depositCalldata = viem.encodeFunctionData({
417
+ abi: syrupRouterAbi,
418
+ functionName: "deposit",
419
+ args: [amountWei, depositData]
420
+ });
421
+ steps.push({ kind: "deposit", to: router, data: depositCalldata, value: 0n });
422
+ }
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
+ }
455
+ try {
456
+ return await publicClient2.estimateGas({
457
+ to: step.to,
458
+ data: step.data,
459
+ value: step.value,
460
+ account: exec
461
+ });
462
+ } catch (e) {
463
+ if (s.kind === "deposit" || s.kind === "authorizeAndDeposit") {
464
+ const msg = e instanceof Error ? e.message : String(e);
465
+ if (/NOT_AUTHORIZED|SR:D:NOT_AUTHORIZED/i.test(msg)) {
466
+ throw new Error(
467
+ stakeMethod === "authorizeAndDeposit" ? "Maple SyrupRouter rejected authorizeAndDeposit (SR:D:NOT_AUTHORIZED). Check the authorization signature, deadline, and bitmap from Maple; they must match this chain, router, and owner." : "Maple SyrupRouter rejected deposit (SR:D:NOT_AUTHORIZED): this executor is not allowlisted as a Syrup lender on-chain. Use authorizeAndDeposit with a Maple-issued signature for the first deposit, or ask Maple to allowlist this address."
468
+ );
469
+ }
470
+ }
471
+ return s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : MAPLE_SYRUP_DEPOSIT_FALLBACK;
472
+ }
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
+ };
490
+ }
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() } }
504
+ };
505
+ }
506
+ const a = args.authorizeSig;
507
+ return {
508
+ signatureText: JSON.stringify({
509
+ kind: "MapleSyrup",
510
+ name: "SyrupRouter.authorizeAndDeposit",
511
+ function: "authorizeAndDeposit(uint256 bitmap,uint256 deadline,uint8 auth_v,bytes32 auth_r,bytes32 auth_s,uint256 amount,bytes32 depositData)",
512
+ bitmap: a.bitmap.toString(),
513
+ deadline: a.deadline.toString(),
514
+ auth_v: a.v,
515
+ assets: amountWei.toString(),
516
+ pool,
517
+ router,
518
+ amountHuman: args.amountHuman
519
+ }),
520
+ evm: { type: "maple_syrup_router_authorize_and_deposit", version: 1, chainId: chainIdStr },
521
+ maple: { step: "authorize_and_deposit", router, pool, gasBuildDeposit: { baseGasUnits: gasLimit.toString() } }
522
+ };
523
+ }
524
+ });
525
+ }
526
+ async function buildEvmMultisignBodyMaplePoolRequestRedeem(args) {
527
+ if (args.chainId !== 1 && args.chainId !== 11155111) {
528
+ throw new Error("Maple Syrup redeem request is only supported on Ethereum mainnet or Sepolia.");
529
+ }
530
+ const pool = viem.getAddress(args.pool);
531
+ const executor = viem.getAddress(args.executorAddress);
532
+ const receiver = executor;
533
+ const ud = args.underlyingDecimals;
534
+ if (!Number.isFinite(ud) || ud < 0 || ud > 255) throw new Error("Invalid underlying decimals.");
535
+ const assetWei = viem.parseUnits(args.underlyingAmountHuman, ud);
536
+ if (assetWei === 0n) throw new Error("Amount is zero after converting with token decimals.");
537
+ const publicClient = publicClientForChain(args.chainId, args.rpcUrl);
538
+ const exitShares = await publicClient.readContract({
539
+ address: pool,
540
+ abi: poolV2ExitAbi,
541
+ functionName: "convertToExitShares",
542
+ args: [assetWei]
543
+ });
544
+ if (exitShares === 0n) throw new Error("Exit shares are zero for this amount; check pool liquidity and amount.");
545
+ const data = viem.encodeFunctionData({
546
+ abi: poolV2ExitAbi,
547
+ functionName: "requestRedeem",
548
+ args: [exitShares, receiver]
549
+ });
550
+ const chainIdStr = String(args.chainId);
551
+ const firstDataNo0x = data.startsWith("0x") ? data.slice(2) : data;
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 }) => ({
570
+ signatureText: JSON.stringify({
571
+ kind: "MapleSyrup",
572
+ name: "PoolV2.requestRedeem",
573
+ function: "requestRedeem(uint256 shares, address receiver)",
574
+ shares: exitShares.toString(),
575
+ underlyingAmountHuman: args.underlyingAmountHuman,
576
+ receiver,
577
+ pool
578
+ }),
579
+ evm: { type: "maple_pool_v2_request_redeem", version: 1, chainId: chainIdStr },
580
+ maple: { step: "request_redeem", pool, gasBuildRedeem: { baseGasUnits: gasLimit.toString() } }
581
+ })
582
+ });
583
+ }
584
+
585
+ // src/protocols/evm/maple/index.ts
586
+ var MAPLE_PROTOCOL_ID = "maple-syrup";
587
+ var mapleProtocolModule = {
588
+ id: MAPLE_PROTOCOL_ID,
589
+ chainCategory: "evm",
590
+ isChainSupported(ctx) {
591
+ if (ctx.chainCategory !== "evm") return false;
592
+ const n = typeof ctx.chainId === "number" ? ctx.chainId : Number.parseInt(String(ctx.chainId), 10);
593
+ return isMapleSyrupSupportedChain(n);
594
+ },
595
+ isTokenSupported(token) {
596
+ return token.category === "evm" && token.kind === "erc20";
597
+ },
598
+ actions: [
599
+ { id: "maple-syrup.deposit", protocolId: MAPLE_PROTOCOL_ID, chainCategory: "evm", description: "Deposit into Maple Syrup pool", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} },
600
+ { id: "maple-syrup.request-redeem", protocolId: MAPLE_PROTOCOL_ID, chainCategory: "evm", description: "Request redeem from pool", commonParams: ["keyGen", "purposeText", "useCustomGas"], params: {} }
601
+ ]
602
+ };
603
+ registerProtocolModule(mapleProtocolModule);
604
+
605
+ exports.MAPLE_INTEGRATION_DOCS_URL = MAPLE_INTEGRATION_DOCS_URL;
606
+ exports.MAPLE_PROTOCOL_ID = MAPLE_PROTOCOL_ID;
607
+ exports.MAPLE_SYRUP_DEPOSIT_DATA_ASCII = MAPLE_SYRUP_DEPOSIT_DATA_ASCII;
608
+ exports.MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK = MAPLE_SYRUP_DEPOSIT_GAS_FALLBACK;
609
+ exports.buildEvmMultisignBodyMaplePoolRequestRedeem = buildEvmMultisignBodyMaplePoolRequestRedeem;
610
+ exports.buildEvmMultisignBodyMapleSyrupDeposit = buildEvmMultisignBodyMapleSyrupDeposit;
611
+ exports.isMapleSyrupSupportedChain = isMapleSyrupSupportedChain;
612
+ exports.mapleGraphqlEndpointForChain = mapleGraphqlEndpointForChain;
613
+ exports.mapleProtocolModule = mapleProtocolModule;
614
+ exports.parseMapleStakeAuthInputs = parseMapleStakeAuthInputs;
615
+ exports.readMaplePoolShareDecimals = readMaplePoolShareDecimals;
616
+ exports.readMapleStakePreviewShares = readMapleStakePreviewShares;
617
+ exports.readMapleUnstakeExitSharesForAssets = readMapleUnstakeExitSharesForAssets;
618
+ //# sourceMappingURL=index.cjs.map
619
+ //# sourceMappingURL=index.cjs.map