@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 = [];
@@ -87,98 +88,238 @@ function eulerSameAssetApproveAmountWithBuffer(args) {
87
88
  return args.totalPullWei + extra + 1n;
88
89
  }
89
90
 
90
- // src/core/keygen.ts
91
- function firstClientIdFromKeyGen(data) {
92
- const map = data?.ClientKeys;
93
- if (!map || typeof map !== "object") return null;
94
- for (const v of Object.values(map)) {
95
- if (typeof v === "string" && v.trim()) return v.trim();
91
+ // src/core/purpose.ts
92
+ function mergePurposeText(purposeText, purposeSuffix) {
93
+ const t = purposeText.trim();
94
+ const suffix = (purposeSuffix ?? "").trim();
95
+ if (!suffix) return t;
96
+ return t ? `${t}
97
+
98
+ ${suffix}` : suffix;
99
+ }
100
+
101
+ // src/core/envelope.ts
102
+ function finalizeMultisign(input) {
103
+ const { keyGen, destinationChainID, legs } = input;
104
+ if (legs.length === 0) {
105
+ throw new Error("finalizeMultisign requires at least one leg");
96
106
  }
97
- return null;
107
+ const ph = (keyGen.pubkeyhex ?? "").trim();
108
+ if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
109
+ const keyList = keyGen.keylist ?? [];
110
+ const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
111
+ const first = legs[0];
112
+ const messageHashes = legs.map((l) => l.msgHash);
113
+ const messageRawBatch = legs.map((l) => l.msgRaw);
114
+ const batchMeta = legs.map((l) => ({
115
+ destinationAddress: l.destinationAddress,
116
+ signatureText: l.signatureText,
117
+ ...l.audit
118
+ }));
119
+ const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
120
+ const extraPayload = {
121
+ batchMeta,
122
+ ...input.extraJSON ?? {}
123
+ };
124
+ const extraJSON = JSON.stringify(extraPayload);
125
+ const bodyForSign = {
126
+ keyList,
127
+ pubKey: ph,
128
+ msgHash: messageHashes[0],
129
+ msgRaw: first.msgRaw,
130
+ destinationChainID,
131
+ destinationAddress: input.destinationAddress ?? first.destinationAddress,
132
+ extraJSON,
133
+ signatureText: first.signatureText,
134
+ purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
135
+ ...first.feeSnapshot
136
+ };
137
+ if (legs.length > 1) {
138
+ bodyForSign.messageHashes = messageHashes;
139
+ bodyForSign.messageRawBatch = messageRawBatch;
140
+ }
141
+ if (proposalTxParams.length > 0) {
142
+ bodyForSign.proposalTxParams = proposalTxParams;
143
+ }
144
+ const valueWei = first.valueWei;
145
+ if (valueWei != null && valueWei > 0n) {
146
+ bodyForSign.value = valueWei.toString();
147
+ }
148
+ if (clientId) bodyForSign.clientId = clientId;
149
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
150
+ }
151
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
152
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
153
+ return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
154
+ }
155
+ return (estimatedGas * 12n + 9n) / 10n;
98
156
  }
99
157
 
100
- // src/chains/evm/txParams.ts
101
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
102
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
103
- return estimatedGas;
104
- }
105
- const cfg = BigInt(Math.floor(chainGasLimit));
106
- return cfg > estimatedGas ? cfg : estimatedGas;
107
- }
108
- async function fetchChainFeeParams(rpcUrl, chainId) {
109
- const url = rpcUrl.trim();
110
- if (!url) return { isEip1559: false };
111
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
112
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
113
- const chain = viem.defineChain({
114
- id: chainIdNum,
115
- name: "Discovery",
158
+ // src/chains/evm/buildBatch.ts
159
+ async function buildEvmMultisignBatch(args) {
160
+ const { context, steps } = args;
161
+ const {
162
+ chainId,
163
+ rpcUrl,
164
+ executorAddress,
165
+ chainDetail,
166
+ useCustomGas,
167
+ customGasChainDetails,
168
+ keyGen,
169
+ purposeText
170
+ } = context;
171
+ if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
172
+ const ch = viem.defineChain({
173
+ id: chainId,
174
+ name: "Destination",
116
175
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
117
- rpcUrls: { default: { http: [url] } }
176
+ rpcUrls: { default: { http: [rpcUrl] } }
118
177
  });
119
- const publicClient = viem.createPublicClient({
120
- chain,
121
- transport: viem.http(url)
122
- });
123
- const getGasPriceGwei = async () => {
124
- const gasPriceWei = await publicClient.getGasPrice();
125
- return parseFloat(viem.formatUnits(gasPriceWei, 9));
126
- };
127
- try {
128
- const block = await publicClient.getBlock({ blockTag: "latest" });
129
- const baseFeePerGas = block?.baseFeePerGas;
130
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
131
- const gasPriceGwei2 = await getGasPriceGwei();
132
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
133
- }
134
- const baseFeeGwei = parseFloat(viem.formatUnits(baseFeePerGas, 9));
135
- let priorityFeeGwei;
136
- try {
137
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
138
- priorityFeeGwei = parseFloat(viem.formatUnits(priorityWei, 9));
139
- } catch {
178
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
179
+ const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
180
+ const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
181
+ const latestBaseFeeWei = !legacy ? (await publicClient2.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
182
+ const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
183
+ const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
184
+ const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
185
+ const executor = viem.getAddress(executorAddress);
186
+ const baseNonce = await publicClient2.getTransactionCount({ address: executor, blockTag: "pending" });
187
+ const legs = [];
188
+ for (let i = 0; i < steps.length; i++) {
189
+ const step = steps[i];
190
+ const currentNonce = baseNonce + i;
191
+ let estimatedGas;
192
+ if (args.estimateGasForStep) {
193
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient: publicClient2, executor });
194
+ } else {
195
+ try {
196
+ estimatedGas = await publicClient2.estimateGas({
197
+ to: step.to,
198
+ data: step.data,
199
+ value: step.value,
200
+ account: executor
201
+ });
202
+ } catch {
203
+ estimatedGas = step.fallbackGas ?? 100000n;
204
+ }
140
205
  }
141
- const gasPriceGwei = await getGasPriceGwei();
142
- return {
143
- isEip1559: true,
144
- baseFeeGwei,
145
- priorityFeeGwei,
146
- gasPriceGwei
147
- };
148
- } catch {
149
- try {
150
- const gasPriceWei = await publicClient.getGasPrice();
151
- const gasPriceGwei = parseFloat(viem.formatUnits(gasPriceWei, 9));
152
- return { isEip1559: false, gasPriceGwei };
153
- } catch {
154
- return { isEip1559: false };
206
+ let gasLimitI;
207
+ if (args.resolveGasLimit) {
208
+ gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient: publicClient2 });
209
+ } else if (step.routerSwap) {
210
+ gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
211
+ } else {
212
+ gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
213
+ }
214
+ let proposalTxParams;
215
+ let feeSnapshot;
216
+ let serialized;
217
+ if (legacy) {
218
+ let gasPriceWei = await publicClient2.getGasPrice();
219
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
220
+ gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
221
+ }
222
+ if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
223
+ const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
224
+ if (configured > gasPriceWei) gasPriceWei = configured;
225
+ }
226
+ serialized = viem.serializeTransaction({
227
+ type: "legacy",
228
+ to: step.to,
229
+ data: step.data,
230
+ value: step.value,
231
+ gas: gasLimitI,
232
+ gasPrice: gasPriceWei,
233
+ nonce: currentNonce,
234
+ chainId
235
+ });
236
+ proposalTxParams = {
237
+ nonce: currentNonce,
238
+ gasLimit: gasLimitI.toString(),
239
+ txType: "legacy",
240
+ gasPrice: gasPriceWei.toString()
241
+ };
242
+ feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
243
+ } else {
244
+ const fetchedBase = feeParams.baseFeeGwei ?? 0;
245
+ const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
246
+ const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
247
+ const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
248
+ const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
249
+ const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
250
+ const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
251
+ const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
252
+ const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
253
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
254
+ let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
255
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
256
+ maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
257
+ maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
258
+ }
259
+ ({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
260
+ maxFeePerGas,
261
+ maxPriorityFeePerGas,
262
+ latestBaseFeeWei
263
+ ));
264
+ serialized = viem.serializeTransaction({
265
+ type: "eip1559",
266
+ to: step.to,
267
+ data: step.data,
268
+ value: step.value,
269
+ gas: gasLimitI,
270
+ maxFeePerGas,
271
+ maxPriorityFeePerGas,
272
+ nonce: currentNonce,
273
+ chainId
274
+ });
275
+ proposalTxParams = {
276
+ nonce: currentNonce,
277
+ gasLimit: gasLimitI.toString(),
278
+ txType: "eip1559",
279
+ maxFeePerGas: maxFeePerGas.toString(),
280
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
281
+ };
282
+ feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
283
+ }
284
+ const h = viem.keccak256(serialized);
285
+ const msgHash = h.startsWith("0x") ? h.slice(2) : h;
286
+ const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
287
+ legs.push({
288
+ msgHash,
289
+ msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
290
+ destinationAddress: step.to,
291
+ signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
292
+ audit: batchMetaExtra,
293
+ feeSnapshot: i === 0 ? feeSnapshot : {},
294
+ proposalTxParams,
295
+ valueWei: i === 0 ? step.value : void 0
296
+ });
297
+ if (i === 0 && args.firstMsgRawNo0x != null) {
298
+ legs[0].msgRaw = args.firstMsgRawNo0x;
155
299
  }
156
300
  }
157
- }
158
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
159
- let maxP = maxPriorityFeePerGas;
160
- let maxF = maxFeePerGas;
161
- if (baseWei > 0n && maxF < baseWei + maxP) {
162
- maxF = baseWei + maxP + viem.parseGwei("0.001");
301
+ const extraJSON = {};
302
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
303
+ extraJSON.customGasChainDetails = customGasChainDetails;
163
304
  }
164
- if (maxF < maxP) {
165
- maxF = baseWei > 0n ? baseWei + maxP + viem.parseGwei("0.001") : maxP * 2n;
305
+ const result = finalizeMultisign({
306
+ keyGen,
307
+ purposeText,
308
+ purposeSuffix: args.purposeSuffix,
309
+ destinationChainID: String(chainId),
310
+ destinationAddress: args.destinationAddress ?? steps[0].to,
311
+ legs,
312
+ extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
313
+ });
314
+ const pv = args.payableValueWei;
315
+ if (pv != null && pv > 0n) {
316
+ result.bodyForSign.value = pv.toString();
166
317
  }
167
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
168
- }
169
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
170
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
318
+ return result;
171
319
  }
172
320
 
173
321
  // src/protocols/evm/euler-v2/vaultWithdrawMultisign.ts
174
322
  var EULER_V2_VAULT_WITHDRAW_FALLBACK_GAS = 900000n;
175
- function gweiToDecimalString(n) {
176
- if (!Number.isFinite(n)) return "0";
177
- if (n === 0) return "0";
178
- const s = String(n);
179
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
180
- return s;
181
- }
182
323
  var erc20DecimalsAbi = viem.parseAbi(["function decimals() view returns (uint8)"]);
183
324
  var erc4626AssetAbi = viem.parseAbi(["function asset() view returns (address)"]);
184
325
  var erc4626MaxWithdrawAbi = viem.parseAbi(["function maxWithdraw(address owner) view returns (uint256)"]);
@@ -192,14 +333,14 @@ async function fetchEulerVaultUnderlyingMeta(args) {
192
333
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
193
334
  rpcUrls: { default: { http: [args.rpcUrl] } }
194
335
  });
195
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
196
- const assetAddrRaw = await publicClient.readContract({
336
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
337
+ const assetAddrRaw = await publicClient2.readContract({
197
338
  address: args.evault,
198
339
  abi: erc4626AssetAbi,
199
340
  functionName: "asset"
200
341
  });
201
342
  const assetAddr = viem.getAddress(assetAddrRaw);
202
- const d = await publicClient.readContract({
343
+ const d = await publicClient2.readContract({
203
344
  address: assetAddr,
204
345
  abi: erc20DecimalsAbi,
205
346
  functionName: "decimals"
@@ -231,8 +372,8 @@ async function fetchEulerVaultMaxWithdrawWei(args) {
231
372
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
232
373
  rpcUrls: { default: { http: [args.rpcUrl] } }
233
374
  });
234
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
235
- return publicClient.readContract({
375
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
376
+ return publicClient2.readContract({
236
377
  address: args.evault,
237
378
  abi: erc4626MaxWithdrawAbi,
238
379
  functionName: "maxWithdraw",
@@ -269,19 +410,19 @@ async function eulerLendEarnEffectiveMaxWeiBySimulation(args) {
269
410
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
270
411
  rpcUrls: { default: { http: [args.rpcUrl] } }
271
412
  });
272
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
413
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
273
414
  let shareBal;
274
415
  let vaultCash;
275
416
  try {
276
417
  ;
277
418
  [shareBal, vaultCash] = await Promise.all([
278
- publicClient.readContract({
419
+ publicClient2.readContract({
279
420
  address: args.evault,
280
421
  abi: eulerVaultSharesCashAbi,
281
422
  functionName: "balanceOf",
282
423
  args: [args.vaultShareOwner]
283
424
  }),
284
- publicClient.readContract({
425
+ publicClient2.readContract({
285
426
  address: args.evault,
286
427
  abi: eulerVaultSharesCashAbi,
287
428
  functionName: "cash"
@@ -293,7 +434,7 @@ async function eulerLendEarnEffectiveMaxWeiBySimulation(args) {
293
434
  if (shareBal === 0n) return 0n;
294
435
  let assetsOwned;
295
436
  try {
296
- assetsOwned = await publicClient.readContract({
437
+ assetsOwned = await publicClient2.readContract({
297
438
  address: args.evault,
298
439
  abi: eulerVaultSharesCashAbi,
299
440
  functionName: "convertToAssets",
@@ -310,7 +451,7 @@ async function eulerLendEarnEffectiveMaxWeiBySimulation(args) {
310
451
  while (lo <= hiProbe) {
311
452
  const mid = lo + (hiProbe - lo) / 2n;
312
453
  const ok = await eulerDirectWithdrawSimulatesOk({
313
- publicClient,
454
+ publicClient: publicClient2,
314
455
  evault: args.evault,
315
456
  vaultShareOwner: args.vaultShareOwner,
316
457
  receiver: args.receiver,
@@ -349,157 +490,7 @@ async function fetchEulerLendEarnVaultEffectiveMaxWithdrawWei(args) {
349
490
  txSender
350
491
  });
351
492
  }
352
- async function eulerMultisignBodyOneStep(args) {
353
- const ch = viem.defineChain({
354
- id: args.chainId,
355
- name: "Destination",
356
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
357
- rpcUrls: { default: { http: [args.rpcUrl] } }
358
- });
359
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
360
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
361
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
362
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
363
- const useCustomGas = args.useCustomGas;
364
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
365
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
366
- const baseNonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
367
- let estimatedGas;
368
- try {
369
- estimatedGas = await publicClient.estimateGas({
370
- to: args.to,
371
- data: args.data,
372
- value: args.value,
373
- account: args.executorAddress
374
- });
375
- } catch {
376
- estimatedGas = args.estimateGasFallback;
377
- }
378
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
379
- const batchMeta0 = args.buildBatchMeta({ gasLimit: gasLimitI });
380
- let firstTxFeePayload = {};
381
- let firstDataNo0x = "";
382
- const messageHashes = [];
383
- const messageRawBatch = [];
384
- const proposalTxParamsBatch = [];
385
- const vTo = args.to;
386
- const vData = args.data;
387
- const vValue = args.value;
388
- if (legacy) {
389
- let gasPriceWei = await publicClient.getGasPrice();
390
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
391
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
392
- }
393
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
394
- const configured = viem.parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
395
- if (configured > gasPriceWei) gasPriceWei = configured;
396
- }
397
- const ser = viem.serializeTransaction({
398
- type: "legacy",
399
- to: vTo,
400
- data: vData,
401
- value: vValue,
402
- gas: gasLimitI,
403
- gasPrice: gasPriceWei,
404
- nonce: baseNonce,
405
- chainId: args.chainId
406
- });
407
- const h = viem.keccak256(ser);
408
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
409
- messageRawBatch.push(ser);
410
- proposalTxParamsBatch.push({
411
- nonce: baseNonce,
412
- gasLimit: gasLimitI.toString(),
413
- txType: "legacy",
414
- gasPrice: gasPriceWei.toString()
415
- });
416
- firstTxFeePayload = { txNonce: baseNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
417
- firstDataNo0x = vData.startsWith("0x") ? vData.slice(2) : vData;
418
- } else {
419
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
420
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
421
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
422
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
423
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
424
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
425
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
426
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
427
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
428
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
429
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString(maxFeePerGasGwei));
430
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
431
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
432
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
433
- }
434
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
435
- maxFeePerGas,
436
- maxPriorityFeePerGas,
437
- latestBaseFeeWei
438
- ));
439
- const ser = viem.serializeTransaction({
440
- type: "eip1559",
441
- to: vTo,
442
- data: vData,
443
- value: vValue,
444
- gas: gasLimitI,
445
- maxFeePerGas,
446
- maxPriorityFeePerGas,
447
- nonce: baseNonce,
448
- chainId: args.chainId
449
- });
450
- const h = viem.keccak256(ser);
451
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
452
- messageRawBatch.push(ser);
453
- proposalTxParamsBatch.push({
454
- nonce: baseNonce,
455
- gasLimit: gasLimitI.toString(),
456
- txType: "eip1559",
457
- maxFeePerGas: maxFeePerGas.toString(),
458
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
459
- });
460
- firstTxFeePayload = {
461
- txNonce: baseNonce,
462
- txGasLimit: gasLimitI.toString(),
463
- txMaxFeePerGas: maxFeePerGas.toString(),
464
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
465
- };
466
- firstDataNo0x = vData.startsWith("0x") ? vData.slice(2) : vData;
467
- }
468
- const extraPayload = { batchMeta: [batchMeta0] };
469
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
470
- extraPayload.customGasChainDetails = args.customGasChainDetails;
471
- }
472
- const extraJSON = JSON.stringify(extraPayload);
473
- const firstSigText = batchMeta0.signatureText;
474
- const bodyForSign = {
475
- keyList: args.keyList,
476
- pubKey: args.ph,
477
- msgHash: messageHashes[0],
478
- msgRaw: firstDataNo0x,
479
- messageHashes,
480
- messageRawBatch,
481
- destinationChainID: String(args.chainId),
482
- destinationAddress: vTo,
483
- extraJSON,
484
- signatureText: firstSigText,
485
- purpose: (() => {
486
- const t = args.purposeText.trim();
487
- return (t ? `${t}
488
-
489
- ` : "") + args.purposeSuffix;
490
- })(),
491
- ...firstTxFeePayload,
492
- proposalTxParams: proposalTxParamsBatch
493
- };
494
- if (vValue > 0n) bodyForSign.value = vValue.toString();
495
- if (args.clientId) bodyForSign.clientId = args.clientId;
496
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
497
- }
498
493
  async function buildEvmMultisignBodyEulerV2VaultWithdraw(args) {
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
494
  const evault = viem.getAddress(args.evault);
504
495
  const receiver = viem.getAddress(args.owner);
505
496
  const shareOwner = viem.getAddress(args.vaultShareOwner ?? args.owner);
@@ -524,24 +515,32 @@ async function buildEvmMultisignBodyEulerV2VaultWithdraw(args) {
524
515
  });
525
516
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
526
517
  const purposeSuffix = `Euler v2: 1-tx \u2014 eVault.withdraw (${args.amountHuman} underlying) from isolated vault "${vaultLabel}" (ERC-4626).`;
527
- return eulerMultisignBodyOneStep({
528
- ph,
529
- keyList,
530
- clientId: clientId ?? void 0,
531
- chainId: args.chainId,
532
- rpcUrl: args.rpcUrl,
533
- chainDetail: args.chainDetail,
534
- useCustomGas: args.useCustomGas,
535
- customGasChainDetails: args.customGasChainDetails,
536
- purposeText: args.purposeText,
518
+ const evmSteps = [
519
+ {
520
+ to: evault,
521
+ data: withdrawData,
522
+ value: 0n,
523
+ fallbackGas: EULER_V2_VAULT_WITHDRAW_FALLBACK_GAS
524
+ }
525
+ ];
526
+ const firstDataNo0x = withdrawData.startsWith("0x") ? withdrawData.slice(2) : withdrawData;
527
+ return buildEvmMultisignBatch({
528
+ context: {
529
+ chainCategory: "evm",
530
+ keyGen: args.keyGen,
531
+ purposeText: args.purposeText,
532
+ chainId: args.chainId,
533
+ rpcUrl: args.rpcUrl,
534
+ executorAddress: executor,
535
+ chainDetail: args.chainDetail,
536
+ useCustomGas: args.useCustomGas,
537
+ customGasChainDetails: args.customGasChainDetails
538
+ },
539
+ steps: evmSteps,
537
540
  purposeSuffix,
538
- executorAddress: executor,
539
- to: evault,
540
- data: withdrawData,
541
- value: 0n,
542
- estimateGasFallback: EULER_V2_VAULT_WITHDRAW_FALLBACK_GAS,
543
- buildBatchMeta: (ctx) => ({
544
- destinationAddress: evault,
541
+ firstMsgRawNo0x: firstDataNo0x,
542
+ destinationAddress: evault,
543
+ buildBatchMeta: ({ gasLimit }) => ({
545
544
  signatureText: JSON.stringify({
546
545
  kind: "EulerV2",
547
546
  name: "EVault.withdraw",
@@ -558,7 +557,7 @@ async function buildEvmMultisignBodyEulerV2VaultWithdraw(args) {
558
557
  amountHuman: args.amountHuman,
559
558
  evault,
560
559
  owner: shareOwner,
561
- gasBuildWithdraw: { baseGasUnits: ctx.gasLimit.toString() }
560
+ gasBuildWithdraw: { baseGasUnits: gasLimit.toString() }
562
561
  }
563
562
  })
564
563
  });
@@ -615,20 +614,20 @@ async function collateralMaxWithdrawBySimulation(args) {
615
614
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
616
615
  rpcUrls: { default: { http: [args.rpcUrl] } }
617
616
  });
618
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
617
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
619
618
  let shareBal;
620
619
  let assetsOwned;
621
620
  let vaultCash;
622
621
  try {
623
622
  ;
624
623
  [shareBal, vaultCash] = await Promise.all([
625
- publicClient.readContract({
624
+ publicClient2.readContract({
626
625
  address: args.collateralVault,
627
626
  abi: eulerCollateralVaultReadAbi,
628
627
  functionName: "balanceOf",
629
628
  args: [args.subAccount]
630
629
  }),
631
- publicClient.readContract({
630
+ publicClient2.readContract({
632
631
  address: args.collateralVault,
633
632
  abi: eulerCollateralVaultReadAbi,
634
633
  functionName: "cash"
@@ -639,7 +638,7 @@ async function collateralMaxWithdrawBySimulation(args) {
639
638
  }
640
639
  if (shareBal === 0n) return 0n;
641
640
  try {
642
- assetsOwned = await publicClient.readContract({
641
+ assetsOwned = await publicClient2.readContract({
643
642
  address: args.collateralVault,
644
643
  abi: eulerCollateralVaultReadAbi,
645
644
  functionName: "convertToAssets",
@@ -656,7 +655,7 @@ async function collateralMaxWithdrawBySimulation(args) {
656
655
  while (lo <= hiProbe) {
657
656
  const mid = lo + (hiProbe - lo) / 2n;
658
657
  const ok = await evcWithdrawSimulatesOk({
659
- publicClient,
658
+ publicClient: publicClient2,
660
659
  evc: args.evc,
661
660
  collateralVault: args.collateralVault,
662
661
  subAccount: args.subAccount,
@@ -699,16 +698,6 @@ var EULER_V2_ISOLATED_VAULT_DEPOSIT_FALLBACK_GAS = 950000n;
699
698
  var EULER_VAULT_DEPOSIT_ESTIMATE_FALLBACK = EULER_V2_ISOLATED_VAULT_DEPOSIT_FALLBACK_GAS;
700
699
  var EULER_ERC20_APPROVE_FALLBACK = 100000n;
701
700
  var EULER_WETH_DEPOSIT_FALLBACK = 120000n;
702
- function gweiToDecimalString2(n) {
703
- if (!Number.isFinite(n)) return "0";
704
- if (n === 0) return "0";
705
- const s = String(n);
706
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
707
- return s;
708
- }
709
- function txToViemStep(tx) {
710
- return { to: viem.getAddress(tx.to), data: tx.data, value: tx.value };
711
- }
712
701
  var wethDepositAbi = viem.parseAbi(["function deposit() payable"]);
713
702
  var erc20AllowanceAbi = viem.parseAbi([
714
703
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -719,10 +708,6 @@ var erc4626DepositAbi = viem.parseAbi([
719
708
  "function deposit(uint256 assets, address receiver) returns (uint256 shares)"
720
709
  ]);
721
710
  async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
722
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
723
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
724
- const keyList = args.keyGen.keylist ?? [];
725
- const clientId = firstClientIdFromKeyGen(args.keyGen);
726
711
  const asset = viem.getAddress(args.underlying);
727
712
  const evault = viem.getAddress(args.evault);
728
713
  const weth = viem.getAddress(args.nativeWrapped);
@@ -737,8 +722,8 @@ async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
737
722
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
738
723
  rpcUrls: { default: { http: [args.rpcUrl] } }
739
724
  });
740
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
741
- const dec = await publicClient.readContract({
725
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
726
+ const dec = await publicClient2.readContract({
742
727
  address: asset,
743
728
  abi: erc20AllowanceAbi,
744
729
  functionName: "decimals"
@@ -749,7 +734,7 @@ async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
749
734
  if (args.isNativeIn) {
750
735
  const dataDeposit = viem.encodeFunctionData({ abi: wethDepositAbi, functionName: "deposit", args: [] });
751
736
  steps.push({ kind: "weth_deposit", to: weth, data: dataDeposit, value: amountWei });
752
- const wethAllowance = await publicClient.readContract({
737
+ const wethAllowance = await publicClient2.readContract({
753
738
  address: weth,
754
739
  abi: erc20AllowanceAbi,
755
740
  functionName: "allowance",
@@ -772,7 +757,7 @@ async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
772
757
  steps.push({ kind: "approve", to: weth, data: dataApprove, value: 0n });
773
758
  }
774
759
  } else {
775
- const currentAllowance = await publicClient.readContract({
760
+ const currentAllowance = await publicClient2.readContract({
776
761
  address: asset,
777
762
  abi: erc20AllowanceAbi,
778
763
  functionName: "allowance",
@@ -801,154 +786,79 @@ async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
801
786
  args: [amountWei, receiver]
802
787
  });
803
788
  steps.push({ kind: "vault_deposit", to: evault, data: depositData, value: 0n });
804
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
805
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
806
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
807
- const useCustomGas = args.useCustomGas;
808
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
809
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
810
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
811
- const messageHashes = [];
812
- const messageRawBatch = [];
813
- const proposalTxParamsBatch = [];
814
- const batchMeta = [];
815
- let firstTxFeePayload = {};
816
- let firstDataNo0x = "";
817
789
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
818
- for (let i = 0; i < steps.length; i++) {
819
- const s = steps[i];
820
- const v = txToViemStep(s);
821
- const currentNonce = baseNonce + i;
822
- let estimatedGas;
823
- try {
824
- estimatedGas = await publicClient.estimateGas({
825
- to: v.to,
826
- data: v.data,
827
- value: v.value,
828
- account: executor
829
- });
830
- } catch {
831
- if (s.kind === "weth_deposit") estimatedGas = EULER_WETH_DEPOSIT_FALLBACK;
832
- else if (s.kind === "approve") estimatedGas = EULER_ERC20_APPROVE_FALLBACK;
833
- else estimatedGas = EULER_VAULT_DEPOSIT_ESTIMATE_FALLBACK;
790
+ const evmSteps = steps.map((s) => ({
791
+ to: s.to,
792
+ data: s.data,
793
+ value: s.value,
794
+ fallbackGas: s.kind === "weth_deposit" ? EULER_WETH_DEPOSIT_FALLBACK : s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK : EULER_VAULT_DEPOSIT_ESTIMATE_FALLBACK
795
+ }));
796
+ const n = steps.length;
797
+ const hasWrap = args.isNativeIn;
798
+ const purposeSuffix = (() => {
799
+ if (hasWrap) {
800
+ return `Euler v2: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve eVault for the exact amount, then ERC-4626 deposit into isolated vault "${vaultLabel}".`;
834
801
  }
835
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
836
- if (legacy) {
837
- let gasPriceWei = await publicClient.getGasPrice();
838
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
839
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
840
- }
841
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
842
- const configured = viem.parseGwei(gweiToDecimalString2(Number(args.chainDetail.gasPrice)));
843
- if (configured > gasPriceWei) gasPriceWei = configured;
844
- }
845
- const ser = viem.serializeTransaction({
846
- type: "legacy",
847
- to: v.to,
848
- data: v.data,
849
- value: v.value,
850
- gas: gasLimitI,
851
- gasPrice: gasPriceWei,
852
- nonce: currentNonce,
853
- chainId: args.chainId
854
- });
855
- const h = viem.keccak256(ser);
856
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
857
- messageRawBatch.push(ser);
858
- proposalTxParamsBatch.push({
859
- nonce: currentNonce,
860
- gasLimit: gasLimitI.toString(),
861
- txType: "legacy",
862
- gasPrice: gasPriceWei.toString()
863
- });
864
- if (i === 0) {
865
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
866
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
867
- }
868
- } else {
869
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
870
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
871
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
872
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
873
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
874
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
875
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
876
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
877
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
878
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString2(effectivePriorityFeeGwei)) : viem.parseGwei("1");
879
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString2(maxFeePerGasGwei));
880
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
881
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
882
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
802
+ if (n === 1) {
803
+ return `Euler v2: 1-tx \u2014 eVault.deposit (allowance already sufficient) into "${vaultLabel}".`;
804
+ }
805
+ return `Euler v2: ${n}-tx batch \u2014 approve eVault for the exact amount, then ERC-4626 deposit into "${vaultLabel}".`;
806
+ })();
807
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
808
+ return buildEvmMultisignBatch({
809
+ context: {
810
+ chainCategory: "evm",
811
+ keyGen: args.keyGen,
812
+ purposeText: args.purposeText,
813
+ chainId: args.chainId,
814
+ rpcUrl: args.rpcUrl,
815
+ executorAddress: executor,
816
+ chainDetail: args.chainDetail,
817
+ useCustomGas: args.useCustomGas,
818
+ customGasChainDetails: args.customGasChainDetails
819
+ },
820
+ steps: evmSteps,
821
+ purposeSuffix,
822
+ firstMsgRawNo0x: firstDataNo0x,
823
+ destinationAddress: steps[0].to,
824
+ buildBatchMeta: ({ index, gasLimit }) => {
825
+ const s = steps[index];
826
+ if (s.kind === "weth_deposit") {
827
+ return {
828
+ signatureText: JSON.stringify({
829
+ kind: "EulerV2",
830
+ name: "WETH.deposit",
831
+ function: "deposit()",
832
+ valueWei: amountWei.toString(),
833
+ vaultMarket: vaultLabel,
834
+ note: "Wrap native for Euler v2 isolated vault deposit (same batch)."
835
+ }),
836
+ evm: { type: "euler_v2_weth_deposit", version: 1, chainId: String(args.chainId) },
837
+ eulerV2: {
838
+ step: "weth_deposit",
839
+ vaultMarket: vaultLabel,
840
+ amountHuman: args.amountHuman,
841
+ evault,
842
+ underlying: asset
843
+ }
844
+ };
883
845
  }
884
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
885
- maxFeePerGas,
886
- maxPriorityFeePerGas,
887
- latestBaseFeeWei
888
- ));
889
- const ser = viem.serializeTransaction({
890
- type: "eip1559",
891
- to: v.to,
892
- data: v.data,
893
- value: v.value,
894
- gas: gasLimitI,
895
- maxFeePerGas,
896
- maxPriorityFeePerGas,
897
- nonce: currentNonce,
898
- chainId: args.chainId
899
- });
900
- const h = viem.keccak256(ser);
901
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
902
- messageRawBatch.push(ser);
903
- proposalTxParamsBatch.push({
904
- nonce: currentNonce,
905
- gasLimit: gasLimitI.toString(),
906
- txType: "eip1559",
907
- maxFeePerGas: maxFeePerGas.toString(),
908
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
909
- });
910
- if (i === 0) {
911
- firstTxFeePayload = {
912
- txNonce: currentNonce,
913
- txGasLimit: gasLimitI.toString(),
914
- txMaxFeePerGas: maxFeePerGas.toString(),
915
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
846
+ if (s.kind === "approve") {
847
+ return {
848
+ signatureText: JSON.stringify({
849
+ kind: "EulerV2",
850
+ name: "ERC20.approve",
851
+ to: "Euler eVault",
852
+ function: "approve(address spender, uint256 amount)",
853
+ evault,
854
+ amountHuman: args.amountHuman,
855
+ note: "Allowance for this deposit amount only (not unlimited)."
856
+ }),
857
+ evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
858
+ eulerV2: { vaultMarket: vaultLabel, amountHuman: args.amountHuman, evault, underlying: asset }
916
859
  };
917
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
918
860
  }
919
- }
920
- if (s.kind === "weth_deposit") {
921
- batchMeta.push({
922
- destinationAddress: weth,
923
- signatureText: JSON.stringify({
924
- kind: "EulerV2",
925
- name: "WETH.deposit",
926
- function: "deposit()",
927
- valueWei: amountWei.toString(),
928
- vaultMarket: vaultLabel,
929
- note: "Wrap native for Euler v2 isolated vault deposit (same batch)."
930
- }),
931
- evm: { type: "euler_v2_weth_deposit", version: 1, chainId: String(args.chainId) },
932
- eulerV2: { step: "weth_deposit", vaultMarket: vaultLabel, amountHuman: args.amountHuman, evault, underlying: asset }
933
- });
934
- } else if (s.kind === "approve") {
935
- batchMeta.push({
936
- destinationAddress: s.to,
937
- signatureText: JSON.stringify({
938
- kind: "EulerV2",
939
- name: "ERC20.approve",
940
- to: "Euler eVault",
941
- function: "approve(address spender, uint256 amount)",
942
- evault,
943
- amountHuman: args.amountHuman,
944
- note: "Allowance for this deposit amount only (not unlimited)."
945
- }),
946
- evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
947
- eulerV2: { vaultMarket: vaultLabel, amountHuman: args.amountHuman, evault, underlying: asset }
948
- });
949
- } else {
950
- batchMeta.push({
951
- destinationAddress: evault,
861
+ return {
952
862
  signatureText: JSON.stringify({
953
863
  kind: "EulerV2",
954
864
  name: "EVault.deposit",
@@ -966,54 +876,11 @@ async function buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch(args) {
966
876
  evault,
967
877
  underlying: asset,
968
878
  receiver,
969
- gasBuildDeposit: { baseGasUnits: gasLimitI.toString() }
879
+ gasBuildDeposit: { baseGasUnits: gasLimit.toString() }
970
880
  }
971
- });
972
- }
973
- }
974
- const extraPayload = { batchMeta };
975
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
976
- extraPayload.customGasChainDetails = args.customGasChainDetails;
977
- }
978
- const extraJSON = JSON.stringify(extraPayload);
979
- const firstSigText = batchMeta[0].signatureText;
980
- const n = steps.length;
981
- const hasWrap = args.isNativeIn;
982
- const purposeSuffix = (() => {
983
- if (hasWrap) {
984
- return `Euler v2: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve eVault for the exact amount, then ERC-4626 deposit into isolated vault "${vaultLabel}".`;
985
- }
986
- if (n === 1) {
987
- return `Euler v2: 1-tx \u2014 eVault.deposit (allowance already sufficient) into "${vaultLabel}".`;
881
+ };
988
882
  }
989
- return `Euler v2: ${n}-tx batch \u2014 approve eVault for the exact amount, then ERC-4626 deposit into "${vaultLabel}".`;
990
- })();
991
- const firstValue = steps[0].value;
992
- const bodyForSign = {
993
- keyList,
994
- pubKey: ph,
995
- msgHash: messageHashes[0],
996
- msgRaw: firstDataNo0x,
997
- messageHashes,
998
- messageRawBatch,
999
- destinationChainID: String(args.chainId),
1000
- destinationAddress: steps[0].to,
1001
- extraJSON,
1002
- signatureText: firstSigText,
1003
- purpose: (() => {
1004
- const t = args.purposeText.trim();
1005
- return (t ? `${t}
1006
-
1007
- ` : "") + purposeSuffix;
1008
- })(),
1009
- ...firstTxFeePayload,
1010
- proposalTxParams: proposalTxParamsBatch
1011
- };
1012
- if (firstValue > 0n) {
1013
- bodyForSign.value = firstValue.toString();
1014
- }
1015
- if (clientId) bodyForSign.clientId = clientId;
1016
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
883
+ });
1017
884
  }
1018
885
  var EULER_BORROW_BATCH_FALLBACK_GAS = 2500000n;
1019
886
  var EULER_BORROW_BATCH_FALLBACK_GAS_PER_ROUND = 350000n;
@@ -1032,21 +899,7 @@ var evaultBorrowAbi = viem.parseAbi(["function borrow(uint256 amount, address re
1032
899
  var evcAbi = viem.parseAbi([
1033
900
  "function batch((address targetContract, address onBehalfOfAccount, uint256 value, bytes data)[])"
1034
901
  ]);
1035
- function gweiToDecimalString3(n) {
1036
- if (!Number.isFinite(n)) return "0";
1037
- if (n === 0) return "0";
1038
- const s = String(n);
1039
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
1040
- return s;
1041
- }
1042
- function txToViemStep2(tx) {
1043
- return { to: viem.getAddress(tx.to), data: tx.data, value: tx.value };
1044
- }
1045
902
  async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1046
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1047
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1048
- const keyList = args.keyGen.keylist ?? [];
1049
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1050
903
  const evc = viem.getAddress(args.evc);
1051
904
  const borrowVault = viem.getAddress(args.borrowVault);
1052
905
  const collateralVault = viem.getAddress(args.collateralVault);
@@ -1064,8 +917,8 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1064
917
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1065
918
  rpcUrls: { default: { http: [args.rpcUrl] } }
1066
919
  });
1067
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1068
- const cDecRaw = await publicClient.readContract({
920
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
921
+ const cDecRaw = await publicClient2.readContract({
1069
922
  address: collateralAsset,
1070
923
  abi: erc20AllowanceAbi2,
1071
924
  functionName: "decimals"
@@ -1073,7 +926,7 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1073
926
  const collateralDecimals = Number(cDecRaw);
1074
927
  const collateralWei = viem.parseUnits(args.collateralAmountHuman, collateralDecimals);
1075
928
  if (collateralWei === 0n) throw new Error("Collateral amount is zero after converting with token decimals.");
1076
- await publicClient.readContract({
929
+ await publicClient2.readContract({
1077
930
  address: borrowAsset,
1078
931
  abi: erc20AllowanceAbi2,
1079
932
  functionName: "decimals"
@@ -1096,7 +949,7 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1096
949
  if (args.isNativeCollateralIn) {
1097
950
  const dataDeposit = viem.encodeFunctionData({ abi: wethDepositAbi2, functionName: "deposit", args: [] });
1098
951
  steps.push({ kind: "weth_deposit", to: weth, data: dataDeposit, value: collateralWei });
1099
- const wethAllowance = await publicClient.readContract({
952
+ const wethAllowance = await publicClient2.readContract({
1100
953
  address: weth,
1101
954
  abi: erc20AllowanceAbi2,
1102
955
  functionName: "allowance",
@@ -1119,7 +972,7 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1119
972
  steps.push({ kind: "approve", to: weth, data: dataApprove, value: 0n });
1120
973
  }
1121
974
  } else {
1122
- const currentAllowance = await publicClient.readContract({
975
+ const currentAllowance = await publicClient2.readContract({
1123
976
  address: collateralAsset,
1124
977
  abi: erc20AllowanceAbi2,
1125
978
  functionName: "allowance",
@@ -1195,156 +1048,73 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1195
1048
  });
1196
1049
  steps.push({ kind: "evc_batch", to: evc, data: batchData, value: 0n });
1197
1050
  const borrowRoundsExtraGas = EULER_BORROW_BATCH_FALLBACK_GAS_PER_ROUND * BigInt(Math.max(0, loops.length - 1 + (args.redepositBorrowedToCollateral ? loops.length : 0)));
1198
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1199
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1200
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1201
- const useCustomGas = args.useCustomGas;
1202
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1203
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1204
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
1205
- const messageHashes = [];
1206
- const messageRawBatch = [];
1207
- const proposalTxParamsBatch = [];
1208
- const batchMeta = [];
1209
- let firstTxFeePayload = {};
1210
- let firstDataNo0x = "";
1211
1051
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
1212
- for (let i = 0; i < steps.length; i++) {
1213
- const s = steps[i];
1214
- const v = txToViemStep2(s);
1215
- const currentNonce = baseNonce + i;
1216
- let estimatedGas;
1217
- try {
1218
- estimatedGas = await publicClient.estimateGas({
1219
- to: v.to,
1220
- data: v.data,
1221
- value: v.value,
1222
- account: executor
1223
- });
1224
- } catch {
1225
- if (s.kind === "weth_deposit") estimatedGas = EULER_WETH_DEPOSIT_FALLBACK2;
1226
- else if (s.kind === "approve") estimatedGas = EULER_ERC20_APPROVE_FALLBACK2;
1227
- else estimatedGas = EULER_BORROW_BATCH_FALLBACK_GAS + borrowRoundsExtraGas;
1052
+ const evmSteps = steps.map((s) => ({
1053
+ to: s.to,
1054
+ data: s.data,
1055
+ value: s.value,
1056
+ fallbackGas: s.kind === "weth_deposit" ? EULER_WETH_DEPOSIT_FALLBACK2 : s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK2 : EULER_BORROW_BATCH_FALLBACK_GAS + borrowRoundsExtraGas
1057
+ }));
1058
+ const n = steps.length;
1059
+ const hasWrap = args.isNativeCollateralIn;
1060
+ const purposeSuffix = (() => {
1061
+ const tail = args.redepositBorrowedToCollateral ? `deposit collateral, enableCollateral, enableController, then ${loops.length}\xD7 borrow+redeposit on "${vaultLabel}" (same-asset target LTV loop).` : `deposit collateral, enableCollateral, enableController, borrow from "${vaultLabel}".`;
1062
+ if (hasWrap) {
1063
+ return `Euler v2: ${n}-tx batch \u2014 wrap native collateral (if needed), approve collateral eVault (buffered for all deposits), then EVC batch: ${tail}`;
1228
1064
  }
1229
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1230
- if (legacy) {
1231
- let gasPriceWei = await publicClient.getGasPrice();
1232
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1233
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1065
+ return `Euler v2: ${n}-tx batch \u2014 approve collateral (if needed) with buffer for all deposits, then EVC batch: ${tail}`;
1066
+ })();
1067
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1068
+ return buildEvmMultisignBatch({
1069
+ context: {
1070
+ chainCategory: "evm",
1071
+ keyGen: args.keyGen,
1072
+ purposeText: args.purposeText,
1073
+ chainId: args.chainId,
1074
+ rpcUrl: args.rpcUrl,
1075
+ executorAddress: executor,
1076
+ chainDetail: args.chainDetail,
1077
+ useCustomGas: args.useCustomGas,
1078
+ customGasChainDetails: args.customGasChainDetails
1079
+ },
1080
+ steps: evmSteps,
1081
+ purposeSuffix,
1082
+ firstMsgRawNo0x: firstDataNo0x,
1083
+ destinationAddress: steps[0].to,
1084
+ buildBatchMeta: ({ index }) => {
1085
+ const s = steps[index];
1086
+ if (s.kind === "weth_deposit") {
1087
+ return {
1088
+ signatureText: JSON.stringify({
1089
+ kind: "EulerV2",
1090
+ name: "WETH.deposit",
1091
+ function: "deposit()",
1092
+ valueWei: collateralWei.toString(),
1093
+ vaultMarket: vaultLabel,
1094
+ note: "Wrap native for Euler v2 isolated borrow collateral (same batch as borrow flow)."
1095
+ }),
1096
+ evm: { type: "euler_v2_weth_deposit", version: 1, chainId: String(args.chainId) },
1097
+ eulerV2: { step: "weth_deposit", vaultMarket: vaultLabel, flow: "borrow" }
1098
+ };
1234
1099
  }
1235
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1236
- const configured = viem.parseGwei(gweiToDecimalString3(Number(args.chainDetail.gasPrice)));
1237
- if (configured > gasPriceWei) gasPriceWei = configured;
1100
+ if (s.kind === "approve") {
1101
+ return {
1102
+ signatureText: JSON.stringify({
1103
+ kind: "EulerV2",
1104
+ name: "ERC20.approve",
1105
+ to: "Euler collateral eVault",
1106
+ function: "approve(address spender, uint256 amount)",
1107
+ collateralVault,
1108
+ amountHuman: args.collateralAmountHuman,
1109
+ note: "Allowance for initial and follow-on collateral deposits (buffered).",
1110
+ approveTotalWei: approveTargetWei.toString()
1111
+ }),
1112
+ evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1113
+ eulerV2: { vaultMarket: vaultLabel, flow: "borrow_collateral_approve" }
1114
+ };
1238
1115
  }
1239
- const ser = viem.serializeTransaction({
1240
- type: "legacy",
1241
- to: v.to,
1242
- data: v.data,
1243
- value: v.value,
1244
- gas: gasLimitI,
1245
- gasPrice: gasPriceWei,
1246
- nonce: currentNonce,
1247
- chainId: args.chainId
1248
- });
1249
- const h = viem.keccak256(ser);
1250
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1251
- messageRawBatch.push(ser);
1252
- proposalTxParamsBatch.push({
1253
- nonce: currentNonce,
1254
- gasLimit: gasLimitI.toString(),
1255
- txType: "legacy",
1256
- gasPrice: gasPriceWei.toString()
1257
- });
1258
- if (i === 0) {
1259
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
1260
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1261
- }
1262
- } else {
1263
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1264
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1265
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1266
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1267
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1268
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1269
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1270
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1271
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1272
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString3(effectivePriorityFeeGwei)) : viem.parseGwei("1");
1273
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString3(maxFeePerGasGwei));
1274
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1275
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1276
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1277
- }
1278
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1279
- maxFeePerGas,
1280
- maxPriorityFeePerGas,
1281
- latestBaseFeeWei
1282
- ));
1283
- const ser = viem.serializeTransaction({
1284
- type: "eip1559",
1285
- to: v.to,
1286
- data: v.data,
1287
- value: v.value,
1288
- gas: gasLimitI,
1289
- maxFeePerGas,
1290
- maxPriorityFeePerGas,
1291
- nonce: currentNonce,
1292
- chainId: args.chainId
1293
- });
1294
- const h = viem.keccak256(ser);
1295
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1296
- messageRawBatch.push(ser);
1297
- proposalTxParamsBatch.push({
1298
- nonce: currentNonce,
1299
- gasLimit: gasLimitI.toString(),
1300
- txType: "eip1559",
1301
- maxFeePerGas: maxFeePerGas.toString(),
1302
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1303
- });
1304
- if (i === 0) {
1305
- firstTxFeePayload = {
1306
- txNonce: currentNonce,
1307
- txGasLimit: gasLimitI.toString(),
1308
- txMaxFeePerGas: maxFeePerGas.toString(),
1309
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1310
- };
1311
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1312
- }
1313
- }
1314
- if (s.kind === "weth_deposit") {
1315
- batchMeta.push({
1316
- destinationAddress: weth,
1317
- signatureText: JSON.stringify({
1318
- kind: "EulerV2",
1319
- name: "WETH.deposit",
1320
- function: "deposit()",
1321
- valueWei: collateralWei.toString(),
1322
- vaultMarket: vaultLabel,
1323
- note: "Wrap native for Euler v2 isolated borrow collateral (same batch as borrow flow)."
1324
- }),
1325
- evm: { type: "euler_v2_weth_deposit", version: 1, chainId: String(args.chainId) },
1326
- eulerV2: { step: "weth_deposit", vaultMarket: vaultLabel, flow: "borrow" }
1327
- });
1328
- } else if (s.kind === "approve") {
1329
- batchMeta.push({
1330
- destinationAddress: s.to,
1331
- signatureText: JSON.stringify({
1332
- kind: "EulerV2",
1333
- name: "ERC20.approve",
1334
- to: "Euler collateral eVault",
1335
- function: "approve(address spender, uint256 amount)",
1336
- collateralVault,
1337
- amountHuman: args.collateralAmountHuman,
1338
- note: "Allowance for initial and follow-on collateral deposits (buffered).",
1339
- approveTotalWei: approveTargetWei.toString()
1340
- }),
1341
- evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1342
- eulerV2: { vaultMarket: vaultLabel, flow: "borrow_collateral_approve" }
1343
- });
1344
- } else {
1345
1116
  const borrowNote = args.redepositBorrowedToCollateral ? `Same-asset leverage: ${loops.length} borrow\u2192deposit round(s); total borrow wei ${borrowWeiTotal.toString()}.` : "Deposit collateral, enableCollateral, enableController, borrow in one EVC batch.";
1346
- batchMeta.push({
1347
- destinationAddress: evc,
1117
+ return {
1348
1118
  signatureText: JSON.stringify({
1349
1119
  kind: "EulerV2",
1350
1120
  name: "EVC.batch",
@@ -1372,50 +1142,9 @@ async function buildEvmMultisignBodyEulerV2IsolatedBorrowBatch(args) {
1372
1142
  redepositBorrowedToCollateral: args.redepositBorrowedToCollateral,
1373
1143
  borrowWeiTotal: borrowWeiTotal.toString()
1374
1144
  }
1375
- });
1376
- }
1377
- }
1378
- const extraPayload = { batchMeta };
1379
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1380
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1381
- }
1382
- const extraJSON = JSON.stringify(extraPayload);
1383
- const firstSigText = batchMeta[0].signatureText;
1384
- const n = steps.length;
1385
- const hasWrap = args.isNativeCollateralIn;
1386
- const purposeSuffix = (() => {
1387
- const tail = args.redepositBorrowedToCollateral ? `deposit collateral, enableCollateral, enableController, then ${loops.length}\xD7 borrow+redeposit on "${vaultLabel}" (same-asset target LTV loop).` : `deposit collateral, enableCollateral, enableController, borrow from "${vaultLabel}".`;
1388
- if (hasWrap) {
1389
- return `Euler v2: ${n}-tx batch \u2014 wrap native collateral (if needed), approve collateral eVault (buffered for all deposits), then EVC batch: ${tail}`;
1145
+ };
1390
1146
  }
1391
- return `Euler v2: ${n}-tx batch \u2014 approve collateral (if needed) with buffer for all deposits, then EVC batch: ${tail}`;
1392
- })();
1393
- const firstValue = steps[0].value;
1394
- const bodyForSign = {
1395
- keyList,
1396
- pubKey: ph,
1397
- msgHash: messageHashes[0],
1398
- msgRaw: firstDataNo0x,
1399
- messageHashes,
1400
- messageRawBatch,
1401
- destinationChainID: String(args.chainId),
1402
- destinationAddress: steps[0].to,
1403
- extraJSON,
1404
- signatureText: firstSigText,
1405
- purpose: (() => {
1406
- const t = args.purposeText.trim();
1407
- return (t ? `${t}
1408
-
1409
- ` : "") + purposeSuffix;
1410
- })(),
1411
- ...firstTxFeePayload,
1412
- proposalTxParams: proposalTxParamsBatch
1413
- };
1414
- if (firstValue > 0n) {
1415
- bodyForSign.value = firstValue.toString();
1416
- }
1417
- if (clientId) bodyForSign.clientId = clientId;
1418
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1147
+ });
1419
1148
  }
1420
1149
  var EULER_REPAY_BATCH_FALLBACK = 1200000n;
1421
1150
  var EULER_ERC20_APPROVE_FALLBACK3 = 100000n;
@@ -1428,21 +1157,7 @@ var evaultRepayAbi = viem.parseAbi(["function repay(uint256 amount, address rece
1428
1157
  var evcAbi2 = viem.parseAbi([
1429
1158
  "function batch((address targetContract, address onBehalfOfAccount, uint256 value, bytes data)[])"
1430
1159
  ]);
1431
- function gweiToDecimalString4(n) {
1432
- if (!Number.isFinite(n)) return "0";
1433
- if (n === 0) return "0";
1434
- const s = String(n);
1435
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
1436
- return s;
1437
- }
1438
- function txToViemStep3(tx) {
1439
- return { to: viem.getAddress(tx.to), data: tx.data, value: tx.value };
1440
- }
1441
1160
  async function buildEvmMultisignBodyEulerV2BorrowRepayBatch(args) {
1442
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1443
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1444
- const keyList = args.keyGen.keylist ?? [];
1445
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1446
1161
  const evc = viem.getAddress(args.evc);
1447
1162
  const borrowVault = viem.getAddress(args.borrowVault);
1448
1163
  const borrowAsset = viem.getAddress(args.borrowUnderlying);
@@ -1454,15 +1169,15 @@ async function buildEvmMultisignBodyEulerV2BorrowRepayBatch(args) {
1454
1169
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1455
1170
  rpcUrls: { default: { http: [args.rpcUrl] } }
1456
1171
  });
1457
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1458
- const bDecRaw = await publicClient.readContract({
1172
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1173
+ const bDecRaw = await publicClient2.readContract({
1459
1174
  address: borrowAsset,
1460
1175
  abi: erc20AllowanceAbi3,
1461
1176
  functionName: "decimals"
1462
1177
  });
1463
1178
  const borrowDecimals = Number(bDecRaw);
1464
1179
  const debtAbi = viem.parseAbi(["function debtOf(address account) view returns (uint256)"]);
1465
- const owed = await publicClient.readContract({
1180
+ const owed = await publicClient2.readContract({
1466
1181
  address: borrowVault,
1467
1182
  abi: debtAbi,
1468
1183
  functionName: "debtOf",
@@ -1480,7 +1195,7 @@ async function buildEvmMultisignBodyEulerV2BorrowRepayBatch(args) {
1480
1195
  }
1481
1196
  const steps = [];
1482
1197
  const allowanceTarget = repayWei === viem.maxUint256 ? owed : repayWei;
1483
- const currentAllowance = await publicClient.readContract({
1198
+ const currentAllowance = await publicClient2.readContract({
1484
1199
  address: borrowAsset,
1485
1200
  abi: erc20AllowanceAbi3,
1486
1201
  functionName: "allowance",
@@ -1517,137 +1232,49 @@ async function buildEvmMultisignBodyEulerV2BorrowRepayBatch(args) {
1517
1232
  args: [batchItems]
1518
1233
  });
1519
1234
  steps.push({ kind: "evc_batch", to: evc, data: batchData, value: 0n });
1520
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1521
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1522
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1523
- const useCustomGas = args.useCustomGas;
1524
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1525
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1526
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
1527
- const messageHashes = [];
1528
- const messageRawBatch = [];
1529
- const proposalTxParamsBatch = [];
1530
- const batchMeta = [];
1531
- let firstTxFeePayload = {};
1532
- let firstDataNo0x = "";
1533
1235
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
1534
- for (let i = 0; i < steps.length; i++) {
1535
- const s = steps[i];
1536
- const v = txToViemStep3(s);
1537
- const currentNonce = baseNonce + i;
1538
- let estimatedGas;
1539
- try {
1540
- estimatedGas = await publicClient.estimateGas({
1541
- to: v.to,
1542
- data: v.data,
1543
- value: v.value,
1544
- account: executor
1545
- });
1546
- } catch {
1547
- estimatedGas = s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK3 : EULER_REPAY_BATCH_FALLBACK;
1548
- }
1549
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1550
- if (legacy) {
1551
- let gasPriceWei = await publicClient.getGasPrice();
1552
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1553
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1554
- }
1555
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1556
- const configured = viem.parseGwei(gweiToDecimalString4(Number(args.chainDetail.gasPrice)));
1557
- if (configured > gasPriceWei) gasPriceWei = configured;
1558
- }
1559
- const ser = viem.serializeTransaction({
1560
- type: "legacy",
1561
- to: v.to,
1562
- data: v.data,
1563
- value: v.value,
1564
- gas: gasLimitI,
1565
- gasPrice: gasPriceWei,
1566
- nonce: currentNonce,
1567
- chainId: args.chainId
1568
- });
1569
- const h = viem.keccak256(ser);
1570
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1571
- messageRawBatch.push(ser);
1572
- proposalTxParamsBatch.push({
1573
- nonce: currentNonce,
1574
- gasLimit: gasLimitI.toString(),
1575
- txType: "legacy",
1576
- gasPrice: gasPriceWei.toString()
1577
- });
1578
- if (i === 0) {
1579
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
1580
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1581
- }
1582
- } else {
1583
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1584
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1585
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1586
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1587
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1588
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1589
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1590
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1591
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1592
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString4(effectivePriorityFeeGwei)) : viem.parseGwei("1");
1593
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString4(maxFeePerGasGwei));
1594
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1595
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1596
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1597
- }
1598
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1599
- maxFeePerGas,
1600
- maxPriorityFeePerGas,
1601
- latestBaseFeeWei
1602
- ));
1603
- const ser = viem.serializeTransaction({
1604
- type: "eip1559",
1605
- to: v.to,
1606
- data: v.data,
1607
- value: v.value,
1608
- gas: gasLimitI,
1609
- maxFeePerGas,
1610
- maxPriorityFeePerGas,
1611
- nonce: currentNonce,
1612
- chainId: args.chainId
1613
- });
1614
- const h = viem.keccak256(ser);
1615
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1616
- messageRawBatch.push(ser);
1617
- proposalTxParamsBatch.push({
1618
- nonce: currentNonce,
1619
- gasLimit: gasLimitI.toString(),
1620
- txType: "eip1559",
1621
- maxFeePerGas: maxFeePerGas.toString(),
1622
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1623
- });
1624
- if (i === 0) {
1625
- firstTxFeePayload = {
1626
- txNonce: currentNonce,
1627
- txGasLimit: gasLimitI.toString(),
1628
- txMaxFeePerGas: maxFeePerGas.toString(),
1629
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1236
+ const evmSteps = steps.map((s) => ({
1237
+ to: s.to,
1238
+ data: s.data,
1239
+ value: s.value,
1240
+ fallbackGas: s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK3 : EULER_REPAY_BATCH_FALLBACK
1241
+ }));
1242
+ const n = steps.length;
1243
+ const purposeSuffix = `Euler v2: ${n}-tx batch \u2014 repay borrow on "${vaultLabel}" (approve if needed, then EVC repay).`;
1244
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1245
+ return buildEvmMultisignBatch({
1246
+ context: {
1247
+ chainCategory: "evm",
1248
+ keyGen: args.keyGen,
1249
+ purposeText: args.purposeText,
1250
+ chainId: args.chainId,
1251
+ rpcUrl: args.rpcUrl,
1252
+ executorAddress: executor,
1253
+ chainDetail: args.chainDetail,
1254
+ useCustomGas: args.useCustomGas,
1255
+ customGasChainDetails: args.customGasChainDetails
1256
+ },
1257
+ steps: evmSteps,
1258
+ purposeSuffix,
1259
+ firstMsgRawNo0x: firstDataNo0x,
1260
+ destinationAddress: steps[0].to,
1261
+ buildBatchMeta: ({ index }) => {
1262
+ const s = steps[index];
1263
+ if (s.kind === "approve") {
1264
+ return {
1265
+ signatureText: JSON.stringify({
1266
+ kind: "EulerV2",
1267
+ name: "ERC20.approve",
1268
+ function: "approve(address spender, uint256 amount)",
1269
+ spender: borrowVault,
1270
+ borrowUnderlying: borrowAsset,
1271
+ note: "Allow Euler liability vault to pull assets for repay."
1272
+ }),
1273
+ evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1274
+ eulerV2: { vaultMarket: vaultLabel, flow: "borrow_repay_approve" }
1630
1275
  };
1631
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1632
1276
  }
1633
- }
1634
- if (s.kind === "approve") {
1635
- batchMeta.push({
1636
- destinationAddress: s.to,
1637
- signatureText: JSON.stringify({
1638
- kind: "EulerV2",
1639
- name: "ERC20.approve",
1640
- function: "approve(address spender, uint256 amount)",
1641
- spender: borrowVault,
1642
- borrowUnderlying: borrowAsset,
1643
- note: "Allow Euler liability vault to pull assets for repay."
1644
- }),
1645
- evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1646
- eulerV2: { vaultMarket: vaultLabel, flow: "borrow_repay_approve" }
1647
- });
1648
- } else {
1649
- batchMeta.push({
1650
- destinationAddress: evc,
1277
+ return {
1651
1278
  signatureText: JSON.stringify({
1652
1279
  kind: "EulerV2",
1653
1280
  name: "EVC.batch",
@@ -1668,39 +1295,9 @@ async function buildEvmMultisignBodyEulerV2BorrowRepayBatch(args) {
1668
1295
  repayAll: args.repayAll,
1669
1296
  amountHuman: args.amountHuman
1670
1297
  }
1671
- });
1298
+ };
1672
1299
  }
1673
- }
1674
- const extraPayload = { batchMeta };
1675
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1676
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1677
- }
1678
- const extraJSON = JSON.stringify(extraPayload);
1679
- const firstSigText = batchMeta[0].signatureText;
1680
- const n = steps.length;
1681
- const purposeSuffix = `Euler v2: ${n}-tx batch \u2014 repay borrow on "${vaultLabel}" (approve if needed, then EVC repay).`;
1682
- const bodyForSign = {
1683
- keyList,
1684
- pubKey: ph,
1685
- msgHash: messageHashes[0],
1686
- msgRaw: firstDataNo0x,
1687
- messageHashes,
1688
- messageRawBatch,
1689
- destinationChainID: String(args.chainId),
1690
- destinationAddress: steps[0].to,
1691
- extraJSON,
1692
- signatureText: firstSigText,
1693
- purpose: (() => {
1694
- const t = args.purposeText.trim();
1695
- return (t ? `${t}
1696
-
1697
- ` : "") + purposeSuffix;
1698
- })(),
1699
- ...firstTxFeePayload,
1700
- proposalTxParams: proposalTxParamsBatch
1701
- };
1702
- if (clientId) bodyForSign.clientId = clientId;
1703
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1300
+ });
1704
1301
  }
1705
1302
  var EULER_COLLATERAL_DEPOSIT_BATCH_FALLBACK = 1600000n;
1706
1303
  var EULER_ERC20_APPROVE_FALLBACK4 = 100000n;
@@ -1714,21 +1311,7 @@ var erc4626DepositAbi3 = viem.parseAbi([
1714
1311
  var evcAbi3 = viem.parseAbi([
1715
1312
  "function batch((address targetContract, address onBehalfOfAccount, uint256 value, bytes data)[])"
1716
1313
  ]);
1717
- function gweiToDecimalString5(n) {
1718
- if (!Number.isFinite(n)) return "0";
1719
- if (n === 0) return "0";
1720
- const s = String(n);
1721
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
1722
- return s;
1723
- }
1724
- function txToViemStep4(tx) {
1725
- return { to: viem.getAddress(tx.to), data: tx.data, value: tx.value };
1726
- }
1727
1314
  async function buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch(args) {
1728
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1729
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1730
- const keyList = args.keyGen.keylist ?? [];
1731
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1732
1315
  const evc = viem.getAddress(args.evc);
1733
1316
  const collateralVault = viem.getAddress(args.collateralVault);
1734
1317
  const collateralAsset = viem.getAddress(args.collateralUnderlying);
@@ -1740,7 +1323,7 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch(args) {
1740
1323
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1741
1324
  rpcUrls: { default: { http: [args.rpcUrl] } }
1742
1325
  });
1743
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1326
+ const publicClient2 = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1744
1327
  const dec = await fetchEulerVaultAssetDecimals({
1745
1328
  rpcUrl: args.rpcUrl,
1746
1329
  chainId: args.chainId,
@@ -1749,7 +1332,7 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch(args) {
1749
1332
  const amountWei = viem.parseUnits(args.amountHuman, dec);
1750
1333
  if (amountWei === 0n) throw new Error("Deposit amount is zero after converting with token decimals.");
1751
1334
  const steps = [];
1752
- const currentAllowance = await publicClient.readContract({
1335
+ const currentAllowance = await publicClient2.readContract({
1753
1336
  address: collateralAsset,
1754
1337
  abi: erc20AllowanceAbi4,
1755
1338
  functionName: "allowance",
@@ -1790,137 +1373,49 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch(args) {
1790
1373
  args: [batchItems]
1791
1374
  });
1792
1375
  steps.push({ kind: "evc_batch", to: evc, data: batchData, value: 0n });
1793
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1794
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1795
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1796
- const useCustomGas = args.useCustomGas;
1797
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1798
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1799
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
1800
- const messageHashes = [];
1801
- const messageRawBatch = [];
1802
- const proposalTxParamsBatch = [];
1803
- const batchMeta = [];
1804
- let firstTxFeePayload = {};
1805
- let firstDataNo0x = "";
1806
1376
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
1807
- for (let i = 0; i < steps.length; i++) {
1808
- const s = steps[i];
1809
- const v = txToViemStep4(s);
1810
- const currentNonce = baseNonce + i;
1811
- let estimatedGas;
1812
- try {
1813
- estimatedGas = await publicClient.estimateGas({
1814
- to: v.to,
1815
- data: v.data,
1816
- value: v.value,
1817
- account: executor
1818
- });
1819
- } catch {
1820
- estimatedGas = s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK4 : EULER_COLLATERAL_DEPOSIT_BATCH_FALLBACK;
1821
- }
1822
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1823
- if (legacy) {
1824
- let gasPriceWei = await publicClient.getGasPrice();
1825
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1826
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1827
- }
1828
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1829
- const configured = viem.parseGwei(gweiToDecimalString5(Number(args.chainDetail.gasPrice)));
1830
- if (configured > gasPriceWei) gasPriceWei = configured;
1831
- }
1832
- const ser = viem.serializeTransaction({
1833
- type: "legacy",
1834
- to: v.to,
1835
- data: v.data,
1836
- value: v.value,
1837
- gas: gasLimitI,
1838
- gasPrice: gasPriceWei,
1839
- nonce: currentNonce,
1840
- chainId: args.chainId
1841
- });
1842
- const h = viem.keccak256(ser);
1843
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1844
- messageRawBatch.push(ser);
1845
- proposalTxParamsBatch.push({
1846
- nonce: currentNonce,
1847
- gasLimit: gasLimitI.toString(),
1848
- txType: "legacy",
1849
- gasPrice: gasPriceWei.toString()
1850
- });
1851
- if (i === 0) {
1852
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
1853
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1854
- }
1855
- } else {
1856
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1857
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1858
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1859
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1860
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1861
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1862
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1863
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1864
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1865
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString5(effectivePriorityFeeGwei)) : viem.parseGwei("1");
1866
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString5(maxFeePerGasGwei));
1867
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1868
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1869
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1870
- }
1871
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1872
- maxFeePerGas,
1873
- maxPriorityFeePerGas,
1874
- latestBaseFeeWei
1875
- ));
1876
- const ser = viem.serializeTransaction({
1877
- type: "eip1559",
1878
- to: v.to,
1879
- data: v.data,
1880
- value: v.value,
1881
- gas: gasLimitI,
1882
- maxFeePerGas,
1883
- maxPriorityFeePerGas,
1884
- nonce: currentNonce,
1885
- chainId: args.chainId
1886
- });
1887
- const h = viem.keccak256(ser);
1888
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1889
- messageRawBatch.push(ser);
1890
- proposalTxParamsBatch.push({
1891
- nonce: currentNonce,
1892
- gasLimit: gasLimitI.toString(),
1893
- txType: "eip1559",
1894
- maxFeePerGas: maxFeePerGas.toString(),
1895
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1896
- });
1897
- if (i === 0) {
1898
- firstTxFeePayload = {
1899
- txNonce: currentNonce,
1900
- txGasLimit: gasLimitI.toString(),
1901
- txMaxFeePerGas: maxFeePerGas.toString(),
1902
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1377
+ const evmSteps = steps.map((s) => ({
1378
+ to: s.to,
1379
+ data: s.data,
1380
+ value: s.value,
1381
+ fallbackGas: s.kind === "approve" ? EULER_ERC20_APPROVE_FALLBACK4 : EULER_COLLATERAL_DEPOSIT_BATCH_FALLBACK
1382
+ }));
1383
+ const n = steps.length;
1384
+ const purposeSuffix = `Euler v2: ${n}-tx batch \u2014 deposit ${args.amountHuman} collateral into "${vaultLabel}" (approve if needed, then EVC deposit).`;
1385
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1386
+ return buildEvmMultisignBatch({
1387
+ context: {
1388
+ chainCategory: "evm",
1389
+ keyGen: args.keyGen,
1390
+ purposeText: args.purposeText,
1391
+ chainId: args.chainId,
1392
+ rpcUrl: args.rpcUrl,
1393
+ executorAddress: executor,
1394
+ chainDetail: args.chainDetail,
1395
+ useCustomGas: args.useCustomGas,
1396
+ customGasChainDetails: args.customGasChainDetails
1397
+ },
1398
+ steps: evmSteps,
1399
+ purposeSuffix,
1400
+ firstMsgRawNo0x: firstDataNo0x,
1401
+ destinationAddress: steps[0].to,
1402
+ buildBatchMeta: ({ index }) => {
1403
+ const s = steps[index];
1404
+ if (s.kind === "approve") {
1405
+ return {
1406
+ signatureText: JSON.stringify({
1407
+ kind: "EulerV2",
1408
+ name: "ERC20.approve",
1409
+ function: "approve(address spender, uint256 amount)",
1410
+ spender: collateralVault,
1411
+ collateralUnderlying: collateralAsset,
1412
+ note: "Allow Euler collateral eVault to pull assets for collateral deposit."
1413
+ }),
1414
+ evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1415
+ eulerV2: { vaultMarket: vaultLabel, flow: "borrow_collateral_deposit_approve" }
1903
1416
  };
1904
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1905
1417
  }
1906
- }
1907
- if (s.kind === "approve") {
1908
- batchMeta.push({
1909
- destinationAddress: s.to,
1910
- signatureText: JSON.stringify({
1911
- kind: "EulerV2",
1912
- name: "ERC20.approve",
1913
- function: "approve(address spender, uint256 amount)",
1914
- spender: collateralVault,
1915
- collateralUnderlying: collateralAsset,
1916
- note: "Allow Euler collateral eVault to pull assets for collateral deposit."
1917
- }),
1918
- evm: { type: "euler_v2_erc20_approve", version: 1, chainId: String(args.chainId) },
1919
- eulerV2: { vaultMarket: vaultLabel, flow: "borrow_collateral_deposit_approve" }
1920
- });
1921
- } else {
1922
- batchMeta.push({
1923
- destinationAddress: evc,
1418
+ return {
1924
1419
  signatureText: JSON.stringify({
1925
1420
  kind: "EulerV2",
1926
1421
  name: "EVC.batch",
@@ -1940,39 +1435,9 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch(args) {
1940
1435
  subAccount,
1941
1436
  amountHuman: args.amountHuman
1942
1437
  }
1943
- });
1438
+ };
1944
1439
  }
1945
- }
1946
- const extraPayload = { batchMeta };
1947
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1948
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1949
- }
1950
- const extraJSON = JSON.stringify(extraPayload);
1951
- const firstSigText = batchMeta[0].signatureText;
1952
- const n = steps.length;
1953
- const purposeSuffix = `Euler v2: ${n}-tx batch \u2014 deposit ${args.amountHuman} collateral into "${vaultLabel}" (approve if needed, then EVC deposit).`;
1954
- const bodyForSign = {
1955
- keyList,
1956
- pubKey: ph,
1957
- msgHash: messageHashes[0],
1958
- msgRaw: firstDataNo0x,
1959
- messageHashes,
1960
- messageRawBatch,
1961
- destinationChainID: String(args.chainId),
1962
- destinationAddress: steps[0].to,
1963
- extraJSON,
1964
- signatureText: firstSigText,
1965
- purpose: (() => {
1966
- const t = args.purposeText.trim();
1967
- return (t ? `${t}
1968
-
1969
- ` : "") + purposeSuffix;
1970
- })(),
1971
- ...firstTxFeePayload,
1972
- proposalTxParams: proposalTxParamsBatch
1973
- };
1974
- if (clientId) bodyForSign.clientId = clientId;
1975
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1440
+ });
1976
1441
  }
1977
1442
  var EULER_COLLATERAL_WITHDRAW_BATCH_FALLBACK = 1400000n;
1978
1443
  var erc4626WithdrawAbi3 = viem.parseAbi([
@@ -1981,33 +1446,12 @@ var erc4626WithdrawAbi3 = viem.parseAbi([
1981
1446
  var evcAbi4 = viem.parseAbi([
1982
1447
  "function batch((address targetContract, address onBehalfOfAccount, uint256 value, bytes data)[])"
1983
1448
  ]);
1984
- function gweiToDecimalString6(n) {
1985
- if (!Number.isFinite(n)) return "0";
1986
- if (n === 0) return "0";
1987
- const s = String(n);
1988
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
1989
- return s;
1990
- }
1991
- function txToViemStep5(tx) {
1992
- return { to: viem.getAddress(tx.to), data: tx.data, value: tx.value };
1993
- }
1994
1449
  async function buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch(args) {
1995
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1996
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1997
- const keyList = args.keyGen.keylist ?? [];
1998
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1999
1450
  const evc = viem.getAddress(args.evc);
2000
1451
  const collateralVault = viem.getAddress(args.collateralVault);
2001
1452
  const subAccount = viem.getAddress(args.subAccount);
2002
1453
  const receiver = viem.getAddress(args.receiver);
2003
1454
  const executor = viem.getAddress(args.executorAddress);
2004
- const ch = viem.defineChain({
2005
- id: args.chainId,
2006
- name: "EulerColWithdraw",
2007
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2008
- rpcUrls: { default: { http: [args.rpcUrl] } }
2009
- });
2010
- const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
2011
1455
  const dec = await fetchEulerVaultAssetDecimals({ rpcUrl: args.rpcUrl, chainId: args.chainId, evault: collateralVault });
2012
1456
  const amountWei = viem.parseUnits(args.amountHuman, dec);
2013
1457
  if (amountWei === 0n) throw new Error("Withdraw amount is zero after converting with token decimals.");
@@ -2043,122 +1487,29 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch(args) {
2043
1487
  args: [batchItems]
2044
1488
  });
2045
1489
  const steps = [{ kind: "evc_batch", to: evc, data: batchData, value: 0n }];
2046
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
2047
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
2048
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
2049
- const useCustomGas = args.useCustomGas;
2050
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
2051
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
2052
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
2053
- const messageHashes = [];
2054
- const messageRawBatch = [];
2055
- const proposalTxParamsBatch = [];
2056
- const batchMeta = [];
2057
- let firstTxFeePayload = {};
2058
- let firstDataNo0x = "";
2059
1490
  const vaultLabel = (args.vaultMarketLabel ?? "").trim() || "Euler vault";
2060
- for (let i = 0; i < steps.length; i++) {
2061
- const s = steps[i];
2062
- const v = txToViemStep5(s);
2063
- const currentNonce = baseNonce + i;
2064
- let estimatedGas;
2065
- try {
2066
- estimatedGas = await publicClient.estimateGas({
2067
- to: v.to,
2068
- data: v.data,
2069
- value: v.value,
2070
- account: executor
2071
- });
2072
- } catch {
2073
- estimatedGas = EULER_COLLATERAL_WITHDRAW_BATCH_FALLBACK;
2074
- }
2075
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
2076
- if (legacy) {
2077
- let gasPriceWei = await publicClient.getGasPrice();
2078
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
2079
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
2080
- }
2081
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
2082
- const configured = viem.parseGwei(gweiToDecimalString6(Number(args.chainDetail.gasPrice)));
2083
- if (configured > gasPriceWei) gasPriceWei = configured;
2084
- }
2085
- const ser = viem.serializeTransaction({
2086
- type: "legacy",
2087
- to: v.to,
2088
- data: v.data,
2089
- value: v.value,
2090
- gas: gasLimitI,
2091
- gasPrice: gasPriceWei,
2092
- nonce: currentNonce,
2093
- chainId: args.chainId
2094
- });
2095
- const h = viem.keccak256(ser);
2096
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
2097
- messageRawBatch.push(ser);
2098
- proposalTxParamsBatch.push({
2099
- nonce: currentNonce,
2100
- gasLimit: gasLimitI.toString(),
2101
- txType: "legacy",
2102
- gasPrice: gasPriceWei.toString()
2103
- });
2104
- if (i === 0) {
2105
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
2106
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
2107
- }
2108
- } else {
2109
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
2110
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
2111
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
2112
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
2113
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
2114
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
2115
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
2116
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
2117
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
2118
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(gweiToDecimalString6(effectivePriorityFeeGwei)) : viem.parseGwei("1");
2119
- let maxFeePerGas = viem.parseGwei(gweiToDecimalString6(maxFeePerGasGwei));
2120
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
2121
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
2122
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
2123
- }
2124
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
2125
- maxFeePerGas,
2126
- maxPriorityFeePerGas,
2127
- latestBaseFeeWei
2128
- ));
2129
- const ser = viem.serializeTransaction({
2130
- type: "eip1559",
2131
- to: v.to,
2132
- data: v.data,
2133
- value: v.value,
2134
- gas: gasLimitI,
2135
- maxFeePerGas,
2136
- maxPriorityFeePerGas,
2137
- nonce: currentNonce,
2138
- chainId: args.chainId
2139
- });
2140
- const h = viem.keccak256(ser);
2141
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
2142
- messageRawBatch.push(ser);
2143
- proposalTxParamsBatch.push({
2144
- nonce: currentNonce,
2145
- gasLimit: gasLimitI.toString(),
2146
- txType: "eip1559",
2147
- maxFeePerGas: maxFeePerGas.toString(),
2148
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
2149
- });
2150
- if (i === 0) {
2151
- firstTxFeePayload = {
2152
- txNonce: currentNonce,
2153
- txGasLimit: gasLimitI.toString(),
2154
- txMaxFeePerGas: maxFeePerGas.toString(),
2155
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
2156
- };
2157
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
2158
- }
2159
- }
2160
- batchMeta.push({
2161
- destinationAddress: evc,
1491
+ const purposeSuffix = `Euler v2: 1-tx \u2014 withdraw ${args.amountHuman} collateral from "${vaultLabel}" via EVC (sub-account).`;
1492
+ const firstDataNo0x = batchData.startsWith("0x") ? batchData.slice(2) : batchData;
1493
+ const evmSteps = [
1494
+ { to: evc, data: batchData, value: 0n, fallbackGas: EULER_COLLATERAL_WITHDRAW_BATCH_FALLBACK }
1495
+ ];
1496
+ return buildEvmMultisignBatch({
1497
+ context: {
1498
+ chainCategory: "evm",
1499
+ keyGen: args.keyGen,
1500
+ purposeText: args.purposeText,
1501
+ chainId: args.chainId,
1502
+ rpcUrl: args.rpcUrl,
1503
+ executorAddress: executor,
1504
+ chainDetail: args.chainDetail,
1505
+ useCustomGas: args.useCustomGas,
1506
+ customGasChainDetails: args.customGasChainDetails
1507
+ },
1508
+ steps: evmSteps,
1509
+ purposeSuffix,
1510
+ firstMsgRawNo0x: firstDataNo0x,
1511
+ destinationAddress: steps[0].to,
1512
+ buildBatchMeta: () => ({
2162
1513
  signatureText: JSON.stringify({
2163
1514
  kind: "EulerV2",
2164
1515
  name: "EVC.batch",
@@ -2180,37 +1531,2255 @@ async function buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch(args) {
2180
1531
  receiver,
2181
1532
  amountHuman: args.amountHuman
2182
1533
  }
1534
+ })
1535
+ });
1536
+ }
1537
+
1538
+ // src/core/defiProxy.ts
1539
+ var aaveGraphqlProxyUrl;
1540
+ var eulerGraphqlProxyUrl;
1541
+ var coingeckoProxyUrl;
1542
+ function getAaveGraphqlProxyUrl() {
1543
+ return aaveGraphqlProxyUrl;
1544
+ }
1545
+ function getEulerGraphqlProxyUrl() {
1546
+ return eulerGraphqlProxyUrl;
1547
+ }
1548
+ function getCoingeckoProxyUrl() {
1549
+ return coingeckoProxyUrl;
1550
+ }
1551
+ async function postJsonViaOptionalProxy(args) {
1552
+ const proxy = args.proxyUrl?.trim();
1553
+ if (proxy) {
1554
+ const r2 = await fetch(proxy, {
1555
+ method: "POST",
1556
+ headers: { "content-type": "application/json" },
1557
+ body: JSON.stringify(args.proxyEnvelope ?? args.body)
2183
1558
  });
1559
+ if (!r2.ok) {
1560
+ const t = await r2.text().catch(() => "");
1561
+ throw new Error(t ? `Proxy HTTP ${r2.status}: ${t.slice(0, 200)}` : `Proxy HTTP ${r2.status}`);
1562
+ }
1563
+ return await r2.json();
2184
1564
  }
2185
- const extraPayload = { batchMeta };
2186
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
2187
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1565
+ const r = await fetch(args.directUrl, {
1566
+ method: "POST",
1567
+ headers: { "content-type": "application/json" },
1568
+ body: JSON.stringify(args.body)
1569
+ });
1570
+ if (!r.ok) {
1571
+ const t = await r.text().catch(() => "");
1572
+ throw new Error(t ? `HTTP ${r.status}: ${t.slice(0, 200)}` : `HTTP ${r.status}`);
2188
1573
  }
2189
- const extraJSON = JSON.stringify(extraPayload);
2190
- const firstSigText = batchMeta[0].signatureText;
2191
- const purposeSuffix = `Euler v2: 1-tx \u2014 withdraw ${args.amountHuman} collateral from "${vaultLabel}" via EVC (sub-account).`;
2192
- const bodyForSign = {
2193
- keyList,
2194
- pubKey: ph,
2195
- msgHash: messageHashes[0],
2196
- msgRaw: firstDataNo0x,
2197
- messageHashes,
2198
- messageRawBatch,
2199
- destinationChainID: String(args.chainId),
2200
- destinationAddress: steps[0].to,
2201
- extraJSON,
2202
- signatureText: firstSigText,
2203
- purpose: (() => {
2204
- const t = args.purposeText.trim();
2205
- return (t ? `${t}
1574
+ return await r.json();
1575
+ }
2206
1576
 
2207
- ` : "") + purposeSuffix;
2208
- })(),
2209
- ...firstTxFeePayload,
2210
- proposalTxParams: proposalTxParamsBatch
1577
+ // src/protocols/evm/aave-v4/api.ts
1578
+ var AAVE_V4_GRAPHQL_URL = "https://api.v4.aave.com/graphql";
1579
+ async function aaveV4Gql(query, variables) {
1580
+ const body = { query, variables: variables ?? {} };
1581
+ const j = await postJsonViaOptionalProxy({
1582
+ directUrl: AAVE_V4_GRAPHQL_URL,
1583
+ body,
1584
+ proxyUrl: getAaveGraphqlProxyUrl(),
1585
+ proxyEnvelope: body
1586
+ });
1587
+ if (j.errors?.length) {
1588
+ const msg = j.errors.map((e) => e.message ?? "Unknown").join("; ");
1589
+ throw new Error(msg);
1590
+ }
1591
+ if (j.data == null) {
1592
+ throw new Error("Aave V4 API: empty response");
1593
+ }
1594
+ return j.data;
1595
+ }
1596
+ async function fetchAaveV4Chains() {
1597
+ const d = await aaveV4Gql(`
1598
+ query C($c: ChainsRequest!) { chains(request: $c) { chainId name nativeWrappedToken } }
1599
+ `, { c: { query: { filter: "ALL" } } });
1600
+ return d.chains ?? [];
1601
+ }
1602
+ async function fetchAaveV4NativeWrappedToken(chainId) {
1603
+ const all = await fetchAaveV4Chains();
1604
+ const c = all.find((x) => x.chainId === chainId);
1605
+ const t = (c?.nativeWrappedToken ?? "").trim();
1606
+ if (t && viem.isAddress(t)) return viem.getAddress(t);
1607
+ return null;
1608
+ }
1609
+ var EULER_EVAULT_CAP_UNLIMITED_WEI = (1n << 256n) - 1n;
1610
+ var UINT256_MAX = EULER_EVAULT_CAP_UNLIMITED_WEI;
1611
+ var EULER_EVAULT_SUPPLY_CAP_UNLIMITED_WEI = EULER_EVAULT_CAP_UNLIMITED_WEI;
1612
+ var EULER_V2_PREFER_ON_CHAIN_LEND_METRICS = false;
1613
+ var eulerVaultLendAbi = viem.parseAbi([
1614
+ "function caps() view returns (uint16 supplyCap, uint16 borrowCap)",
1615
+ "function cash() view returns (uint256)",
1616
+ "function totalBorrows() view returns (uint256)",
1617
+ "function totalAssets() view returns (uint256)"
1618
+ ]);
1619
+ function resolveEulerAmountCapToWei(rawCap16) {
1620
+ const amountCap = BigInt(rawCap16) & 0xffffn;
1621
+ if (amountCap === 0n) return UINT256_MAX;
1622
+ const exp = amountCap & 63n;
1623
+ const mantissa = amountCap >> 6n;
1624
+ return 10n ** exp * mantissa / 100n;
1625
+ }
1626
+ var resolveEulerAmountCapToSupplyWei = resolveEulerAmountCapToWei;
1627
+ function eulerSubgraphVaultCapToUnderlyingWei(raw) {
1628
+ try {
1629
+ const v = BigInt((raw ?? "").trim() || "0");
1630
+ if (v >= UINT256_MAX - 3n) return v;
1631
+ if (v <= 0xffffn) return resolveEulerAmountCapToWei(v);
1632
+ return v;
1633
+ } catch {
1634
+ return 0n;
1635
+ }
1636
+ }
1637
+ function eulerVaultLendMetricsFromIndexerVaultState(args) {
1638
+ let rawSupplyCap16 = 0;
1639
+ let rawBorrowCap16 = 0;
1640
+ try {
1641
+ rawSupplyCap16 = Number(BigInt((args.supplyCapRaw ?? "").trim() || "0") & 0xffffn);
1642
+ } catch {
1643
+ rawSupplyCap16 = 0;
1644
+ }
1645
+ try {
1646
+ rawBorrowCap16 = Number(BigInt((args.borrowCapRaw ?? "").trim() || "0") & 0xffffn);
1647
+ } catch {
1648
+ rawBorrowCap16 = 0;
1649
+ }
1650
+ return {
1651
+ rawSupplyCap16,
1652
+ rawBorrowCap16,
1653
+ supplyCapWei: eulerSubgraphVaultCapToUnderlyingWei(args.supplyCapRaw),
1654
+ borrowCapWei: eulerSubgraphVaultCapToUnderlyingWei(args.borrowCapRaw),
1655
+ cashWei: args.cashWei,
1656
+ totalBorrowsWei: args.totalBorrowsWei,
1657
+ totalAssetsWei: args.totalAssetsWei
2211
1658
  };
2212
- if (clientId) bodyForSign.clientId = clientId;
2213
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1659
+ }
1660
+ function formatEulerResolvedCapOrCashForUi(wei, decimals, symbolSuffix) {
1661
+ if (wei >= EULER_EVAULT_CAP_UNLIMITED_WEI - 3n) return "Unlimited";
1662
+ if (wei === 0n) return symbolSuffix ? `0 ${symbolSuffix}` : "0";
1663
+ try {
1664
+ const s = viem.formatUnits(wei, decimals);
1665
+ const n = Number(s);
1666
+ if (Number.isFinite(n) && Math.abs(n) >= 1e9) return `${n.toExponential(2)}${symbolSuffix ? ` ${symbolSuffix}` : ""}`;
1667
+ return symbolSuffix ? `${s} ${symbolSuffix}` : s;
1668
+ } catch {
1669
+ return wei.toString();
1670
+ }
1671
+ }
1672
+ function eulerVaultMaxNewSupplyWei(metrics) {
1673
+ const { supplyCapWei, totalAssetsWei } = metrics;
1674
+ if (supplyCapWei === 0n) return 0n;
1675
+ if (supplyCapWei >= EULER_EVAULT_CAP_UNLIMITED_WEI - 3n) return EULER_EVAULT_CAP_UNLIMITED_WEI;
1676
+ if (totalAssetsWei >= supplyCapWei) return 0n;
1677
+ return supplyCapWei - totalAssetsWei;
1678
+ }
1679
+ function eulerVaultMaxNewBorrowWei(metrics) {
1680
+ const { cashWei, borrowCapWei, totalBorrowsWei } = metrics;
1681
+ if (borrowCapWei === 0n) return 0n;
1682
+ if (borrowCapWei >= EULER_EVAULT_CAP_UNLIMITED_WEI - 3n) return cashWei;
1683
+ const capLeft = borrowCapWei > totalBorrowsWei ? borrowCapWei - totalBorrowsWei : 0n;
1684
+ return cashWei < capLeft ? cashWei : capLeft;
1685
+ }
1686
+ async function fetchEulerVaultOnChainLendMetrics(args) {
1687
+ const ch = viem.defineChain({
1688
+ id: args.chainId,
1689
+ name: "EulerVaultRead",
1690
+ nativeCurrency: { decimals: 18, name: "x", symbol: "x" },
1691
+ rpcUrls: { default: { http: [args.rpcUrl] } }
1692
+ });
1693
+ const client = viem.createPublicClient({ chain: ch, transport: viem.http(args.rpcUrl) });
1694
+ const addr = viem.getAddress(args.evault);
1695
+ const [[supplyRaw, borrowRaw], cashWei, totalBorrowsWei, totalAssetsWei] = await Promise.all([
1696
+ client.readContract({
1697
+ address: addr,
1698
+ abi: eulerVaultLendAbi,
1699
+ functionName: "caps"
1700
+ }),
1701
+ client.readContract({
1702
+ address: addr,
1703
+ abi: eulerVaultLendAbi,
1704
+ functionName: "cash"
1705
+ }),
1706
+ client.readContract({
1707
+ address: addr,
1708
+ abi: eulerVaultLendAbi,
1709
+ functionName: "totalBorrows"
1710
+ }),
1711
+ client.readContract({
1712
+ address: addr,
1713
+ abi: eulerVaultLendAbi,
1714
+ functionName: "totalAssets"
1715
+ })
1716
+ ]);
1717
+ const rs = Number(supplyRaw);
1718
+ const rb = Number(borrowRaw);
1719
+ return {
1720
+ rawSupplyCap16: rs,
1721
+ rawBorrowCap16: rb,
1722
+ supplyCapWei: resolveEulerAmountCapToWei(rs),
1723
+ borrowCapWei: resolveEulerAmountCapToWei(rb),
1724
+ cashWei,
1725
+ totalBorrowsWei,
1726
+ totalAssetsWei
1727
+ };
1728
+ }
1729
+ async function fetchEulerVaultOnChainLendMetricsForVaults(args) {
1730
+ const rpc = (args.rpcUrl ?? "").trim();
1731
+ const out = /* @__PURE__ */ new Map();
1732
+ if (!rpc || !args.vaults.length) return out;
1733
+ const concurrency = 8;
1734
+ let idx = 0;
1735
+ const list = [...args.vaults];
1736
+ async function worker() {
1737
+ while (idx < list.length) {
1738
+ const i = idx++;
1739
+ const row = list[i];
1740
+ try {
1741
+ const ev = viem.getAddress(row.evault.trim());
1742
+ const data = await fetchEulerVaultOnChainLendMetrics({
1743
+ rpcUrl: rpc,
1744
+ chainId: args.chainId,
1745
+ evault: ev
1746
+ });
1747
+ out.set(row.key, { ok: true, data });
1748
+ } catch (e) {
1749
+ out.set(row.key, {
1750
+ ok: false,
1751
+ message: e instanceof Error ? e.message : "On-chain read failed"
1752
+ });
1753
+ }
1754
+ }
1755
+ }
1756
+ await Promise.all(Array.from({ length: Math.min(concurrency, list.length) }, () => worker()));
1757
+ return out;
1758
+ }
1759
+
1760
+ // src/protocols/evm/euler-v2/eulerV2Subgraph.ts
1761
+ var EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID = {
1762
+ 1: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-mainnet/latest/gn",
1763
+ 8453: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-base/latest/gn",
1764
+ 1923: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-swell/latest/gn",
1765
+ 146: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-sonic/latest/gn",
1766
+ 60808: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-bob/latest/gn",
1767
+ 80094: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-berachain/latest/gn",
1768
+ 43114: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-avalanche/latest/gn",
1769
+ 42161: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-arbitrum/latest/gn",
1770
+ 130: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-unichain/latest/gn",
1771
+ 57073: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-ink/latest/gn",
1772
+ 56: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-bsc/latest/gn",
1773
+ 999: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-hyperevm/latest/gn",
1774
+ 10: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-optimism/latest/gn",
1775
+ 100: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-gnosis/latest/gn",
1776
+ 480: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-worldchain/latest/gn",
1777
+ 239: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-tac/latest/gn",
1778
+ 9745: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-plasma/latest/gn",
1779
+ 5e3: "https://api.goldsky.com/api/public/project_cm4iagnemt1wp01xn4gh1agft/subgraphs/euler-v2-mantle/latest/gn"
1780
+ };
1781
+ var WRAPPED_NATIVE_FALLBACK = {
1782
+ 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
1783
+ 10: "0x4200000000000000000000000000000000000006",
1784
+ 56: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
1785
+ 100: "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d",
1786
+ 130: "0x4200000000000000000000000000000000000006",
1787
+ 146: "0x03980325872071166574bcd94670450917897468",
1788
+ 239: "0xB63B9f0eb4A6E6f191529D71d4D88cc8900Df2C9",
1789
+ // TAC: WTAC (https://docs.tac.build/ecosystem/token-list)
1790
+ 480: "0x4200000000000000000000000000000000000006",
1791
+ 999: "0x5555555555555555555555555555555555555555",
1792
+ // HyperEVM: WHYPE (Hyperliquid docs)
1793
+ 1923: "0x4200000000000000000000000000000000000006",
1794
+ 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
1795
+ 43114: "0xB31f66AA3C1e785363F0875A1B74D27b85FE0459",
1796
+ 5e3: "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8",
1797
+ // Mantle: WMNT
1798
+ 57073: "0x4200000000000000000000000000000000000006",
1799
+ 60808: "0x4200000000000000000000000000000000000006",
1800
+ 80094: "0x6969696969696969696969696969696969696969",
1801
+ // Berachain: WBERA (https://docs.berachain.com)
1802
+ 8453: "0x4200000000000000000000000000000000000006",
1803
+ 9745: "0x6100E367285b01F48D07953803A2d8dCA5D19873"
1804
+ // Plasma: WXPL
1805
+ };
1806
+ for (const id of Object.keys(EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID).map(Number)) {
1807
+ if (WRAPPED_NATIVE_FALLBACK[id] == null) {
1808
+ throw new Error(`eulerV2Subgraph: add WRAPPED_NATIVE_FALLBACK for Euler Goldsky chain ${id}`);
1809
+ }
1810
+ }
1811
+ function eulerV2GoldskyUrlForChain(chainId) {
1812
+ return EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID[chainId];
1813
+ }
1814
+ async function resolveEulerWrappedNativeToken(chainId) {
1815
+ try {
1816
+ const fromAave = await fetchAaveV4NativeWrappedToken(chainId);
1817
+ if (fromAave) return fromAave;
1818
+ } catch {
1819
+ }
1820
+ const fb = WRAPPED_NATIVE_FALLBACK[chainId];
1821
+ if (fb && viem.isAddress(fb)) return viem.getAddress(fb);
1822
+ return null;
1823
+ }
1824
+ async function eulerWrappedGasTokenAliasesLower(chainId) {
1825
+ const s = /* @__PURE__ */ new Set();
1826
+ const fb = WRAPPED_NATIVE_FALLBACK[chainId];
1827
+ if (fb && viem.isAddress(fb)) {
1828
+ try {
1829
+ s.add(viem.getAddress(fb).toLowerCase());
1830
+ } catch {
1831
+ }
1832
+ }
1833
+ try {
1834
+ const aave = await fetchAaveV4NativeWrappedToken(chainId);
1835
+ if (aave && viem.isAddress(aave)) s.add(viem.getAddress(aave).toLowerCase());
1836
+ } catch {
1837
+ }
1838
+ return s;
1839
+ }
1840
+ function eulerV2KeyForNodeAssetRow(args) {
1841
+ const raw = (args.contractAddress ?? "").trim();
1842
+ try {
1843
+ const a = viem.getAddress(raw);
1844
+ if (a.toLowerCase() === "0x0000000000000000000000000000000000000000" && args.nativeWrapped) {
1845
+ return viem.getAddress(args.nativeWrapped.trim()).toLowerCase();
1846
+ }
1847
+ return a.toLowerCase();
1848
+ } catch {
1849
+ return null;
1850
+ }
1851
+ }
1852
+ async function eulerSubgraphGql(endpoint, query, variables, chainId) {
1853
+ const body = { query, variables: variables ?? {} };
1854
+ const proxy = getEulerGraphqlProxyUrl();
1855
+ const j = await postJsonViaOptionalProxy({
1856
+ directUrl: endpoint,
1857
+ body,
1858
+ proxyUrl: proxy,
1859
+ proxyEnvelope: chainId != null ? { chainId, query, variables: variables ?? {} } : body
1860
+ });
1861
+ if (j.errors?.length) {
1862
+ throw new Error(j.errors.map((e) => e.message ?? "Unknown").join("; "));
1863
+ }
1864
+ if (j.data == null) throw new Error("Euler subgraph: empty response");
1865
+ return j.data;
1866
+ }
1867
+ async function eulerV2QueryGraphQl(chainId, query, variables) {
1868
+ const endpoint = eulerV2GoldskyUrlForChain(chainId);
1869
+ if (!endpoint) {
1870
+ throw new Error(`Euler v2 subgraph is not configured for chain ${chainId}`);
1871
+ }
1872
+ return eulerSubgraphGql(endpoint, query, variables, chainId);
1873
+ }
1874
+ var EULER_TRACKING_DEPOSITS_GQL = `
1875
+ query EulerTrackingDeposits($id: Bytes!) {
1876
+ trackingActiveAccount(id: $id) {
1877
+ deposits
1878
+ }
1879
+ }`;
1880
+ async function fetchEulerV2TrackingDepositEntries(args) {
1881
+ if (!eulerV2GoldskyUrlForChain(args.chainId)) return [];
1882
+ const id = args.mainAddress.toLowerCase();
1883
+ const data = await eulerV2QueryGraphQl(
1884
+ args.chainId,
1885
+ EULER_TRACKING_DEPOSITS_GQL,
1886
+ { id }
1887
+ );
1888
+ const raw = data.trackingActiveAccount?.deposits ?? [];
1889
+ return raw.filter((x) => typeof x === "string" && x.trim().length > 0);
1890
+ }
1891
+ function normAssetAddr(raw) {
1892
+ const s = (raw ?? "").trim();
1893
+ if (!s || !viem.isAddress(s)) return null;
1894
+ return viem.getAddress(s).toLowerCase();
1895
+ }
1896
+ function vaultShowsBorrowTab(borrowCap, totalBorrows) {
1897
+ let borrows = 0n;
1898
+ try {
1899
+ borrows = BigInt((totalBorrows ?? "").trim() || "0");
1900
+ } catch {
1901
+ borrows = 0n;
1902
+ }
1903
+ if (borrows > 0n) return true;
1904
+ const w = eulerSubgraphVaultCapToUnderlyingWei(borrowCap);
1905
+ if (w >= EULER_EVAULT_CAP_UNLIMITED_WEI - 3n) return true;
1906
+ return w > 0n;
1907
+ }
1908
+ var VAULT_PAGE = `
1909
+ query V($first: Int!, $skip: Int!) {
1910
+ eulerVaults(first: $first, skip: $skip) {
1911
+ asset
1912
+ borrowCap
1913
+ state { totalBorrows }
1914
+ }
1915
+ }
1916
+ `;
1917
+ var EARN_PAGE = `
1918
+ query E($first: Int!, $skip: Int!) {
1919
+ eulerEarnVaults(first: $first, skip: $skip) {
1920
+ asset
1921
+ }
1922
+ }
1923
+ `;
1924
+ async function paginateEulerVaultRows(endpoint) {
1925
+ const out = [];
1926
+ let skip = 0;
1927
+ const first = 1e3;
1928
+ while (true) {
1929
+ const d = await eulerSubgraphGql(endpoint, VAULT_PAGE, { first, skip });
1930
+ const rows = d.eulerVaults ?? [];
1931
+ if (!rows.length) break;
1932
+ for (const r of rows) {
1933
+ const tb = (r.state?.totalBorrows ?? "0").toString();
1934
+ out.push({ asset: r.asset ?? null, borrowCap: r.borrowCap, totalBorrows: tb });
1935
+ }
1936
+ if (rows.length < first) break;
1937
+ skip += first;
1938
+ }
1939
+ return out;
1940
+ }
1941
+ async function paginateEulerEarnAssets(endpoint) {
1942
+ const assets = [];
1943
+ let skip = 0;
1944
+ const first = 1e3;
1945
+ while (true) {
1946
+ const d = await eulerSubgraphGql(endpoint, EARN_PAGE, {
1947
+ first,
1948
+ skip
1949
+ });
1950
+ const rows = d.eulerEarnVaults ?? [];
1951
+ if (!rows.length) break;
1952
+ for (const r of rows) {
1953
+ const a = normAssetAddr(r.asset ?? void 0);
1954
+ if (a) assets.push(a);
1955
+ }
1956
+ if (rows.length < first) break;
1957
+ skip += first;
1958
+ }
1959
+ return assets;
1960
+ }
1961
+ var eulerV2ChainAssetCache = /* @__PURE__ */ new Map();
1962
+ async function fetchEulerV2ChainAssetCache(chainId) {
1963
+ const endpoint = eulerV2GoldskyUrlForChain(chainId);
1964
+ if (!endpoint) {
1965
+ return { nativeWrapped: null, modesByUnderlying: /* @__PURE__ */ new Map() };
1966
+ }
1967
+ const [nativeWrapped, vaultRows, earnAssets] = await Promise.all([
1968
+ resolveEulerWrappedNativeToken(chainId),
1969
+ paginateEulerVaultRows(endpoint),
1970
+ paginateEulerEarnAssets(endpoint)
1971
+ ]);
1972
+ const modes = /* @__PURE__ */ new Map();
1973
+ const bump = (addr, patch) => {
1974
+ const cur = modes.get(addr) ?? { lend: false, borrow: false, earn: false };
1975
+ modes.set(addr, {
1976
+ lend: cur.lend || !!patch.lend,
1977
+ borrow: cur.borrow || !!patch.borrow,
1978
+ earn: cur.earn || !!patch.earn
1979
+ });
1980
+ };
1981
+ for (const e of earnAssets) bump(e, { earn: true });
1982
+ for (const row of vaultRows) {
1983
+ const a = normAssetAddr(row.asset);
1984
+ if (!a) continue;
1985
+ bump(a, {
1986
+ lend: true,
1987
+ borrow: vaultShowsBorrowTab(row.borrowCap, row.totalBorrows)
1988
+ });
1989
+ }
1990
+ return { nativeWrapped, modesByUnderlying: modes };
1991
+ }
1992
+ function ensureEulerV2ChainAssetCache(chainId) {
1993
+ const hit = eulerV2ChainAssetCache.get(chainId);
1994
+ if (hit) return hit;
1995
+ const p = fetchEulerV2ChainAssetCache(chainId);
1996
+ eulerV2ChainAssetCache.set(chainId, p);
1997
+ return p;
1998
+ }
1999
+ var LABELS_PRODUCTS_URL = (chainId) => `https://raw.githubusercontent.com/euler-xyz/euler-labels/master/${chainId}/products.json`;
2000
+ function normAddrKey(raw) {
2001
+ const s = (raw ?? "").trim();
2002
+ if (!s) return null;
2003
+ try {
2004
+ return viem.getAddress(s.startsWith("0x") ? s : `0x${s}`).toLowerCase();
2005
+ } catch {
2006
+ return null;
2007
+ }
2008
+ }
2009
+ function eulerLabelsAppendUnderlyingIfDistinct(base, underlyingSymbol) {
2010
+ const b = (base ?? "").trim();
2011
+ const sym = (underlyingSymbol ?? "").trim();
2012
+ if (!b) return "\u2014";
2013
+ if (!sym) return b;
2014
+ if (b.toLowerCase().includes(sym.toLowerCase())) return b;
2015
+ return `${b} ${sym}`;
2016
+ }
2017
+ var labelMapCache = /* @__PURE__ */ new Map();
2018
+ function fetchEulerLabelsVaultNameMap(chainId) {
2019
+ let hit = labelMapCache.get(chainId);
2020
+ if (!hit) {
2021
+ hit = (async () => {
2022
+ const m = /* @__PURE__ */ new Map();
2023
+ try {
2024
+ const res = await fetch(LABELS_PRODUCTS_URL(chainId), { cache: "force-cache" });
2025
+ if (!res.ok) return m;
2026
+ const j = await res.json();
2027
+ if (!j || typeof j !== "object") return m;
2028
+ for (const prod of Object.values(j)) {
2029
+ const productName = (prod?.name ?? "").trim();
2030
+ const vaults = prod?.vaults ?? [];
2031
+ const overrides = prod?.vaultOverrides ?? {};
2032
+ const overrideNameByVault = /* @__PURE__ */ new Map();
2033
+ for (const [addr, ov] of Object.entries(overrides)) {
2034
+ const k = normAddrKey(addr);
2035
+ const n = (ov?.name ?? "").trim();
2036
+ if (k && n) overrideNameByVault.set(k, n);
2037
+ }
2038
+ for (const vAddr of vaults) {
2039
+ const k = normAddrKey(vAddr);
2040
+ if (!k) continue;
2041
+ const overrideName = overrideNameByVault.get(k);
2042
+ const base = overrideName || productName;
2043
+ if (!base) continue;
2044
+ m.set(k, base);
2045
+ }
2046
+ }
2047
+ } catch {
2048
+ }
2049
+ return m;
2050
+ })();
2051
+ labelMapCache.set(chainId, hit);
2052
+ }
2053
+ return hit;
2054
+ }
2055
+ function eulerLabelsLookupLabelForVault(labelMap, evaultAddress) {
2056
+ const k = normAddrKey(evaultAddress);
2057
+ if (!k) return void 0;
2058
+ const v = labelMap.get(k);
2059
+ return typeof v === "string" && v.trim() ? v.trim() : void 0;
2060
+ }
2061
+
2062
+ // src/protocols/evm/euler-v2/eulerV2LendMarkets.ts
2063
+ var erc20StringMetaAbi = viem.parseAbi([
2064
+ "function name() view returns (string)",
2065
+ "function symbol() view returns (string)"
2066
+ ]);
2067
+ var LEND_VAULT_PAGE = `
2068
+ query EulerLendVaults($first: Int!, $skip: Int!, $asset: Bytes!) {
2069
+ eulerVaults(
2070
+ first: $first
2071
+ skip: $skip
2072
+ where: { asset: $asset }
2073
+ orderBy: state__supplyApy
2074
+ orderDirection: desc
2075
+ ) {
2076
+ id
2077
+ evc
2078
+ evault
2079
+ name
2080
+ symbol
2081
+ asset
2082
+ decimals
2083
+ supplyCap
2084
+ borrowCap
2085
+ interestFee
2086
+ perspectives
2087
+ collaterals
2088
+ oracle
2089
+ unitOfAccount
2090
+ governonAdmin
2091
+ state {
2092
+ cash
2093
+ totalBorrows
2094
+ totalShares
2095
+ supplyApy
2096
+ borrowApy
2097
+ timestamp
2098
+ }
2099
+ }
2100
+ }
2101
+ `;
2102
+ var COLLATERAL_META = `
2103
+ query EulerCollateralVaults($first: Int!, $ids: [Bytes!]!) {
2104
+ eulerVaults(first: $first, where: { id_in: $ids }) {
2105
+ id
2106
+ evault
2107
+ name
2108
+ symbol
2109
+ asset
2110
+ decimals
2111
+ state {
2112
+ supplyApy
2113
+ }
2114
+ }
2115
+ }
2116
+ `;
2117
+ function normId(raw) {
2118
+ const s = (raw ?? "").trim().toLowerCase();
2119
+ return s.length ? s : null;
2120
+ }
2121
+ function normAssetLower(raw) {
2122
+ const s = (raw ?? "").trim();
2123
+ if (!s || !viem.isAddress(s)) return null;
2124
+ return viem.getAddress(s).toLowerCase();
2125
+ }
2126
+ function checksumHex(raw) {
2127
+ const s = (raw ?? "").trim();
2128
+ if (!s || !viem.isAddress(s)) return null;
2129
+ try {
2130
+ return viem.getAddress(s);
2131
+ } catch {
2132
+ return null;
2133
+ }
2134
+ }
2135
+ function eulerMetaPublicClient(chainId, rpcUrl) {
2136
+ const chain = viem.defineChain({
2137
+ id: chainId,
2138
+ name: "EulerCollateralMeta",
2139
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2140
+ rpcUrls: { default: { http: [rpcUrl] } }
2141
+ });
2142
+ return viem.createPublicClient({ chain, transport: viem.http(rpcUrl) });
2143
+ }
2144
+ async function readErc20StringMeta(client, addrLower) {
2145
+ try {
2146
+ const addr = viem.getAddress(addrLower);
2147
+ const [nameResult, symbolResult] = await Promise.all([
2148
+ client.readContract({ address: addr, abi: erc20StringMetaAbi, functionName: "name" }),
2149
+ client.readContract({ address: addr, abi: erc20StringMetaAbi, functionName: "symbol" })
2150
+ ]);
2151
+ return {
2152
+ name: typeof nameResult === "string" ? nameResult.trim() : String(nameResult ?? "").trim(),
2153
+ symbol: typeof symbolResult === "string" ? symbolResult.trim() : String(symbolResult ?? "").trim()
2154
+ };
2155
+ } catch {
2156
+ return null;
2157
+ }
2158
+ }
2159
+ async function resolveUnderlyingTokenLabels(args) {
2160
+ const out = /* @__PURE__ */ new Map();
2161
+ const uniq = [...new Set(args.assetAddresses.map((a) => normAssetLower(a)).filter(Boolean))];
2162
+ const missingFromNode = [];
2163
+ const node = args.nodeErc20ByAddress;
2164
+ for (const low of uniq) {
2165
+ const hit = node?.get(low);
2166
+ if (hit && ((hit.symbol ?? "").trim() || (hit.name ?? "").trim())) {
2167
+ out.set(low, { name: (hit.name ?? "").trim(), symbol: (hit.symbol ?? "").trim() });
2168
+ } else {
2169
+ missingFromNode.push(low);
2170
+ }
2171
+ }
2172
+ const rpc = (args.rpcUrl ?? "").trim();
2173
+ if (!missingFromNode.length || !rpc) return out;
2174
+ const client = eulerMetaPublicClient(args.chainId, rpc);
2175
+ const batchSize = 10;
2176
+ for (let i = 0; i < missingFromNode.length; i += batchSize) {
2177
+ const chunk = missingFromNode.slice(i, i + batchSize);
2178
+ const settled = await Promise.all(chunk.map((low) => readErc20StringMeta(client, low)));
2179
+ chunk.forEach((low, j) => {
2180
+ const m = settled[j];
2181
+ if (m && (m.symbol || m.name)) out.set(low, m);
2182
+ });
2183
+ }
2184
+ return out;
2185
+ }
2186
+ function formatEulerRayApyPercent(apyRay) {
2187
+ if (apyRay === 0n) return "0.00%";
2188
+ const r = Number(viem.formatUnits(apyRay, 27));
2189
+ if (!Number.isFinite(r)) return "\u2014";
2190
+ const pct = r * 100;
2191
+ if (pct >= 100) return `${pct.toFixed(1)}%`;
2192
+ if (pct >= 10) return `${pct.toFixed(2)}%`;
2193
+ return `${pct.toFixed(2)}%`;
2194
+ }
2195
+ var formatEulerRaySupplyApyPercent = formatEulerRayApyPercent;
2196
+ function formatUnderlyingAmount(raw, decimals) {
2197
+ try {
2198
+ const v = BigInt((raw ?? "").trim() || "0");
2199
+ const s = viem.formatUnits(v, decimals);
2200
+ const n = Number(s);
2201
+ if (!Number.isFinite(n)) return s;
2202
+ if (n === 0) return "0";
2203
+ const abs = Math.abs(n);
2204
+ if (abs >= 1e9) return n.toExponential(2);
2205
+ if (abs >= 1e6) return n.toLocaleString(void 0, { maximumFractionDigits: 0 });
2206
+ if (abs >= 1) return n.toLocaleString(void 0, { maximumFractionDigits: 2 });
2207
+ return n.toLocaleString(void 0, { maximumFractionDigits: 6 });
2208
+ } catch {
2209
+ return "\u2014";
2210
+ }
2211
+ }
2212
+ function formatEulerVaultCapDisplay(raw, decimals) {
2213
+ try {
2214
+ const wei = eulerSubgraphVaultCapToUnderlyingWei(raw);
2215
+ if (wei >= EULER_EVAULT_CAP_UNLIMITED_WEI - 3n) return "Unlimited";
2216
+ if (wei === 0n) return "0";
2217
+ return formatUnderlyingAmount(wei.toString(), decimals);
2218
+ } catch {
2219
+ return "\u2014";
2220
+ }
2221
+ }
2222
+ function formatEulerInterestFee(raw) {
2223
+ try {
2224
+ const fee = BigInt((raw ?? "").trim() || "0");
2225
+ if (fee === 0n) return "0%";
2226
+ const pct = Number(fee) / 100;
2227
+ return `${pct.toFixed(2)}%`;
2228
+ } catch {
2229
+ return "\u2014";
2230
+ }
2231
+ }
2232
+ function formatEulerIndexedTimestamp(raw) {
2233
+ try {
2234
+ const sec = BigInt((raw ?? "").trim() || "0");
2235
+ const n = Number(sec);
2236
+ if (!Number.isFinite(n) || n <= 0) return "\u2014";
2237
+ return new Date(n * 1e3).toLocaleString(void 0, {
2238
+ dateStyle: "medium",
2239
+ timeStyle: "short"
2240
+ });
2241
+ } catch {
2242
+ return "\u2014";
2243
+ }
2244
+ }
2245
+ function utilizationPercentLabel(cash, borrows) {
2246
+ const denom = cash + borrows;
2247
+ if (denom === 0n) return "0.00%";
2248
+ const scaled = borrows * 1000000n / denom;
2249
+ const pct = Number(scaled) / 1e4;
2250
+ return `${pct.toFixed(2)}%`;
2251
+ }
2252
+ function collateralLabelFromVault(name, symbol, id) {
2253
+ const n = (name ?? "").trim();
2254
+ const sym = (symbol ?? "").trim();
2255
+ if (n && sym && n.toLowerCase() !== sym.toLowerCase()) return `${n} (${sym})`;
2256
+ if (n) return n;
2257
+ if (sym) return sym;
2258
+ return id.slice(0, 10);
2259
+ }
2260
+ function marketLabelFromSubgraphRow(r, evaultChecksum) {
2261
+ const n = (r.name ?? "").trim();
2262
+ if (n) return n;
2263
+ const sym = (r.symbol ?? "").trim();
2264
+ if (sym) return sym;
2265
+ const addr = (evaultChecksum ?? "").trim();
2266
+ if (addr.startsWith("0x") && addr.length >= 14) return `${addr.slice(0, 8)}\u2026${addr.slice(-6)}`;
2267
+ return addr || "\u2014";
2268
+ }
2269
+ function normalizePerspectives(raw) {
2270
+ const out = [];
2271
+ for (const p of raw ?? []) {
2272
+ const s = (p ?? "").trim();
2273
+ if (s) out.push(s);
2274
+ }
2275
+ return out;
2276
+ }
2277
+ function vaultSupplyBorrowApyRays(r) {
2278
+ let supplyApyRay = 0n;
2279
+ let borrowApyRay = 0n;
2280
+ try {
2281
+ supplyApyRay = BigInt((r.state?.supplyApy ?? "0").toString().trim() || "0");
2282
+ } catch {
2283
+ supplyApyRay = 0n;
2284
+ }
2285
+ try {
2286
+ borrowApyRay = BigInt((r.state?.borrowApy ?? "0").toString().trim() || "0");
2287
+ } catch {
2288
+ borrowApyRay = 0n;
2289
+ }
2290
+ return { supplyApyRay, borrowApyRay };
2291
+ }
2292
+ function vaultCashAndBorrows(r) {
2293
+ let cash = 0n;
2294
+ let borrows = 0n;
2295
+ try {
2296
+ cash = BigInt((r.state?.cash ?? "0").toString().trim() || "0");
2297
+ } catch {
2298
+ cash = 0n;
2299
+ }
2300
+ try {
2301
+ borrows = BigInt((r.state?.totalBorrows ?? "0").toString().trim() || "0");
2302
+ } catch {
2303
+ borrows = 0n;
2304
+ }
2305
+ return { cash, borrows };
2306
+ }
2307
+ async function paginateLendVaultRows(chainId, assetLower) {
2308
+ const out = [];
2309
+ let skip = 0;
2310
+ const first = 500;
2311
+ while (true) {
2312
+ const d = await eulerV2QueryGraphQl(chainId, LEND_VAULT_PAGE, {
2313
+ first,
2314
+ skip,
2315
+ asset: assetLower
2316
+ });
2317
+ const rows = d.eulerVaults ?? [];
2318
+ if (!rows.length) break;
2319
+ out.push(...rows);
2320
+ if (rows.length < first) break;
2321
+ skip += first;
2322
+ }
2323
+ return out;
2324
+ }
2325
+ async function fetchCollateralVaultMeta(chainId, collateralIds) {
2326
+ const map = /* @__PURE__ */ new Map();
2327
+ const uniq = [...new Set(collateralIds.map((x) => x.toLowerCase()))].filter(Boolean);
2328
+ const chunkSize = 400;
2329
+ for (let i = 0; i < uniq.length; i += chunkSize) {
2330
+ const chunk = uniq.slice(i, i + chunkSize);
2331
+ const d = await eulerV2QueryGraphQl(chainId, COLLATERAL_META, { first: chunk.length, ids: chunk });
2332
+ for (const r of d.eulerVaults ?? []) {
2333
+ const id = normId(r.id ?? void 0);
2334
+ if (!id) continue;
2335
+ let dec = 18;
2336
+ try {
2337
+ dec = Number.parseInt((r.decimals ?? "18").trim(), 10);
2338
+ if (!Number.isFinite(dec) || dec < 0 || dec > 36) dec = 18;
2339
+ } catch {
2340
+ dec = 18;
2341
+ }
2342
+ let supplyApyRay = 0n;
2343
+ try {
2344
+ supplyApyRay = BigInt((r.state?.supplyApy ?? "0").toString().trim() || "0");
2345
+ } catch {
2346
+ supplyApyRay = 0n;
2347
+ }
2348
+ map.set(id, {
2349
+ name: (r.name ?? "").trim(),
2350
+ symbol: (r.symbol ?? "").trim(),
2351
+ assetLower: normAssetLower(r.asset ?? void 0),
2352
+ evaultChecksum: checksumHex(r.evault ?? void 0) ?? checksumHex(r.id ?? void 0),
2353
+ decimals: dec,
2354
+ supplyApyRay
2355
+ });
2356
+ }
2357
+ }
2358
+ return map;
2359
+ }
2360
+ function flattenEulerV2BorrowCollateralRows(markets) {
2361
+ const out = [];
2362
+ for (const m of markets) {
2363
+ if (m.borrowApyRay === 0n) continue;
2364
+ const borrowNum = Number.parseFloat(m.borrowApyPercentLabel.replace(/%/g, "").trim()) || 0;
2365
+ for (const c of m.collateralTokens) {
2366
+ if (!c.collateralEvaultAddress) continue;
2367
+ const supplyNum = Number.parseFloat(c.collateralSupplyApyPercentLabel.replace(/%/g, "").trim()) || 0;
2368
+ const net = supplyNum - borrowNum;
2369
+ const netLabel = `${net.toFixed(2)}%`;
2370
+ out.push({
2371
+ pairKey: `${m.vaultId}:${c.vaultId}`,
2372
+ borrowVaultId: m.vaultId,
2373
+ borrowEvaultAddress: m.evaultAddress,
2374
+ borrowMarketName: m.marketName,
2375
+ borrowDecimals: m.decimals,
2376
+ borrowApyPercentLabel: m.borrowApyPercentLabel,
2377
+ borrowCash: m.cash,
2378
+ borrowTotalBorrows: m.totalBorrows,
2379
+ netApyPercentLabel: netLabel,
2380
+ utilizationPercentLabel: m.utilizationPercentLabel,
2381
+ availableLiquidityFormatted: m.availableLiquidityFormatted,
2382
+ evcAddress: m.evcAddress,
2383
+ oracleAddress: m.oracleAddress,
2384
+ unitOfAccountAddress: m.unitOfAccountAddress,
2385
+ borrowAssetAddressLower: m.borrowAssetAddressLower,
2386
+ governonAdminChecksum: m.governonAdminChecksum,
2387
+ collateralVaultId: c.vaultId,
2388
+ collateralEvaultAddress: c.collateralEvaultAddress,
2389
+ collateralSymbol: c.underlyingSymbol,
2390
+ collateralName: c.underlyingName,
2391
+ collateralVaultLabel: c.vaultMarketLabel,
2392
+ collateralDecimals: c.collateralDecimals,
2393
+ collateralAssetAddressLower: c.collateralAssetAddressLower,
2394
+ collateralSupplyApyPercentLabel: c.collateralSupplyApyPercentLabel,
2395
+ borrowIndexerLendMetrics: m.indexerLendMetrics
2396
+ });
2397
+ }
2398
+ }
2399
+ return out;
2400
+ }
2401
+ async function fetchEulerV2IsolatedLendMarketsForRowAsset(args) {
2402
+ const cache = await ensureEulerV2ChainAssetCache(args.chainId);
2403
+ const underlying = eulerV2KeyForNodeAssetRow({
2404
+ contractAddress: args.contractAddress,
2405
+ nativeWrapped: cache.nativeWrapped
2406
+ });
2407
+ if (!underlying) return [];
2408
+ const [gqlRows, labelMap] = await Promise.all([
2409
+ paginateLendVaultRows(args.chainId, underlying),
2410
+ fetchEulerLabelsVaultNameMap(args.chainId)
2411
+ ]);
2412
+ const eligibleRows = gqlRows.filter((r) => {
2413
+ const { supplyApyRay, borrowApyRay } = vaultSupplyBorrowApyRays(r);
2414
+ if (supplyApyRay === 0n && borrowApyRay === 0n) return false;
2415
+ const { cash, borrows } = vaultCashAndBorrows(r);
2416
+ return cash + borrows !== 0n;
2417
+ });
2418
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "development") {
2419
+ let matched = 0;
2420
+ for (const r of eligibleRows) {
2421
+ const evRaw = checksumHex(r.evault ?? void 0) ?? checksumHex(r.id ?? void 0);
2422
+ if (!evRaw) continue;
2423
+ if (eulerLabelsLookupLabelForVault(labelMap, evRaw)) matched += 1;
2424
+ }
2425
+ console.debug("[Euler labels]", {
2426
+ chainId: args.chainId,
2427
+ matchedEligibleVaults: matched,
2428
+ eligibleVaults: eligibleRows.length,
2429
+ labelMapEntries: labelMap.size
2430
+ });
2431
+ }
2432
+ const collateralIds = [];
2433
+ for (const r of eligibleRows) {
2434
+ for (const c of r.collaterals ?? []) {
2435
+ const id = normId(c ?? void 0);
2436
+ if (id) collateralIds.push(id);
2437
+ }
2438
+ }
2439
+ const collateralMeta = await fetchCollateralVaultMeta(args.chainId, collateralIds);
2440
+ const underlyingAssetAddrs = [];
2441
+ for (const m of collateralMeta.values()) {
2442
+ if (m.assetLower) underlyingAssetAddrs.push(m.assetLower);
2443
+ }
2444
+ const underlyingLabels = await resolveUnderlyingTokenLabels({
2445
+ chainId: args.chainId,
2446
+ rpcUrl: args.rpcUrl,
2447
+ nodeErc20ByAddress: args.nodeErc20ByAddress,
2448
+ assetAddresses: underlyingAssetAddrs
2449
+ });
2450
+ const rows = [];
2451
+ for (const r of eligibleRows) {
2452
+ const vaultId = normId(r.id ?? void 0);
2453
+ if (!vaultId) continue;
2454
+ const evaultAddress = checksumHex(r.evault ?? void 0) ?? checksumHex(r.id ?? void 0) ?? vaultId;
2455
+ const subgraphTitle = marketLabelFromSubgraphRow(r, evaultAddress);
2456
+ const labelBase = eulerLabelsLookupLabelForVault(labelMap, evaultAddress);
2457
+ const assetSym = (args.suppliedAssetSymbol ?? "").trim();
2458
+ const marketName = labelBase ? eulerLabelsAppendUnderlyingIfDistinct(labelBase, assetSym) : subgraphTitle;
2459
+ let dec = 18;
2460
+ try {
2461
+ dec = Number.parseInt((r.decimals ?? "18").trim(), 10);
2462
+ if (!Number.isFinite(dec) || dec < 0 || dec > 36) dec = 18;
2463
+ } catch {
2464
+ dec = 18;
2465
+ }
2466
+ const { cash, borrows } = vaultCashAndBorrows(r);
2467
+ const { supplyApyRay, borrowApyRay } = vaultSupplyBorrowApyRays(r);
2468
+ const total = cash + borrows;
2469
+ const cIds = [...new Set((r.collaterals ?? []).map((x) => normId(x ?? void 0)).filter(Boolean))];
2470
+ const collateralTokens = cIds.map((cid) => {
2471
+ const vm = collateralMeta.get(cid);
2472
+ const vaultMarketLabel = vm ? collateralLabelFromVault(vm.name, vm.symbol, cid) : cid.slice(0, 10);
2473
+ const assetLow = vm?.assetLower ?? null;
2474
+ const und = assetLow ? underlyingLabels.get(assetLow) : void 0;
2475
+ const sym = (und?.symbol ?? "").trim();
2476
+ const nam = (und?.name ?? "").trim();
2477
+ let underlyingSymbol;
2478
+ let underlyingName;
2479
+ if (sym || nam) {
2480
+ underlyingSymbol = sym || nam;
2481
+ underlyingName = sym && nam && nam.toLowerCase() !== sym.toLowerCase() ? nam : null;
2482
+ } else {
2483
+ underlyingSymbol = vaultMarketLabel;
2484
+ underlyingName = null;
2485
+ }
2486
+ const collSupplyRay = vm?.supplyApyRay ?? 0n;
2487
+ return {
2488
+ vaultId: cid,
2489
+ collateralEvaultAddress: vm?.evaultChecksum ?? null,
2490
+ collateralDecimals: vm?.decimals ?? 18,
2491
+ collateralAssetAddressLower: assetLow,
2492
+ collateralSupplyApyPercentLabel: formatEulerRayApyPercent(collSupplyRay),
2493
+ underlyingSymbol,
2494
+ underlyingName,
2495
+ vaultMarketLabel
2496
+ };
2497
+ });
2498
+ const indexerLendMetrics = eulerVaultLendMetricsFromIndexerVaultState({
2499
+ supplyCapRaw: r.supplyCap,
2500
+ borrowCapRaw: r.borrowCap,
2501
+ cashWei: cash,
2502
+ totalBorrowsWei: borrows,
2503
+ totalAssetsWei: total
2504
+ });
2505
+ rows.push({
2506
+ vaultId,
2507
+ evaultAddress,
2508
+ marketName,
2509
+ decimals: dec,
2510
+ cash,
2511
+ totalBorrows: borrows,
2512
+ supplyApyPercentLabel: formatEulerRayApyPercent(supplyApyRay),
2513
+ borrowApyPercentLabel: formatEulerRayApyPercent(borrowApyRay),
2514
+ totalSupplyFormatted: formatUnderlyingAmount(total.toString(), dec),
2515
+ availableLiquidityFormatted: formatUnderlyingAmount(cash.toString(), dec),
2516
+ utilizationPercentLabel: utilizationPercentLabel(cash, borrows),
2517
+ supplyCapFormatted: formatEulerVaultCapDisplay(r.supplyCap, dec),
2518
+ borrowCapFormatted: formatEulerVaultCapDisplay(r.borrowCap, dec),
2519
+ interestFeeLabel: formatEulerInterestFee(r.interestFee),
2520
+ stateIndexedDisplay: formatEulerIndexedTimestamp(r.state?.timestamp),
2521
+ perspectives: normalizePerspectives(r.perspectives),
2522
+ evcAddress: checksumHex(r.evc ?? void 0),
2523
+ oracleAddress: checksumHex(r.oracle ?? void 0),
2524
+ unitOfAccountAddress: checksumHex(r.unitOfAccount ?? void 0),
2525
+ borrowAssetAddressLower: normAssetLower(r.asset ?? void 0),
2526
+ governonAdminChecksum: checksumHex(r.governonAdmin ?? void 0),
2527
+ borrowApyRay,
2528
+ indexerLendMetrics,
2529
+ collateralTokens
2530
+ });
2531
+ }
2532
+ return rows;
2533
+ }
2534
+ var UINT256_MAX2 = (1n << 256n) - 1n;
2535
+ var EARN_STRATEGY_ALLOC_CAP_SUBGRAPH_UNBOUNDED = 87112285931760246646623899502532662132735n;
2536
+ var EARN_VAULTS_QUERY = `
2537
+ query EulerEarnForAsset($asset: Bytes!, $ids: [Bytes!]!) {
2538
+ eulerEarnVaults(first: 500, where: { asset: $asset, id_in: $ids }) {
2539
+ id
2540
+ name
2541
+ curator
2542
+ performanceFee
2543
+ totalAssets
2544
+ totalAllocated
2545
+ asset
2546
+ strategies(first: 200) {
2547
+ strategy
2548
+ allocatedAssets
2549
+ availableAssets
2550
+ currentAllocationCap
2551
+ }
2552
+ }
2553
+ }
2554
+ `;
2555
+ var STRATEGY_VAULT_APY = `
2556
+ query EulerStrategyVaults($ids: [Bytes!]!) {
2557
+ eulerVaults(first: 500, where: { id_in: $ids }) {
2558
+ id
2559
+ asset
2560
+ symbol
2561
+ state {
2562
+ supplyApy
2563
+ }
2564
+ }
2565
+ }
2566
+ `;
2567
+ function normLowerId(raw) {
2568
+ const s = (raw ?? "").trim().toLowerCase();
2569
+ if (!s.startsWith("0x") || s.length < 4) return null;
2570
+ return s;
2571
+ }
2572
+ function big(raw) {
2573
+ try {
2574
+ return BigInt((raw ?? "0").toString().trim() || "0");
2575
+ } catch {
2576
+ return 0n;
2577
+ }
2578
+ }
2579
+ async function fetchEulerLabelsEarnVaultAllowlist(chainId) {
2580
+ const url = `https://raw.githubusercontent.com/euler-xyz/euler-labels/master/${chainId}/earn-vaults.json`;
2581
+ const r = await fetch(url, { cache: "no-store" });
2582
+ if (!r.ok) return /* @__PURE__ */ new Set();
2583
+ let j;
2584
+ try {
2585
+ j = await r.json();
2586
+ } catch {
2587
+ return /* @__PURE__ */ new Set();
2588
+ }
2589
+ const out = /* @__PURE__ */ new Set();
2590
+ if (!Array.isArray(j)) return out;
2591
+ for (const entry of j) {
2592
+ if (typeof entry === "string") {
2593
+ const lo = normLowerId(entry);
2594
+ if (lo) out.add(lo);
2595
+ continue;
2596
+ }
2597
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
2598
+ const o = entry;
2599
+ if (o.deprecated === true) continue;
2600
+ const addr = typeof o.address === "string" ? o.address : typeof o.id === "string" ? o.id : null;
2601
+ const lo = normLowerId(addr);
2602
+ if (lo) out.add(lo);
2603
+ }
2604
+ }
2605
+ return out;
2606
+ }
2607
+ async function fetchEulerLabelsEntityNameByAddress(chainId) {
2608
+ const url = `https://raw.githubusercontent.com/euler-xyz/euler-labels/master/${chainId}/entities.json`;
2609
+ const r = await fetch(url, { cache: "no-store" });
2610
+ const m = /* @__PURE__ */ new Map();
2611
+ if (!r.ok) return m;
2612
+ let j;
2613
+ try {
2614
+ j = await r.json();
2615
+ } catch {
2616
+ return m;
2617
+ }
2618
+ if (!j || typeof j !== "object") return m;
2619
+ for (const ent of Object.values(j)) {
2620
+ if (!ent || typeof ent !== "object") continue;
2621
+ const name = ent.name;
2622
+ const groupName = typeof name === "string" && name.trim() ? name.trim() : null;
2623
+ if (!groupName) continue;
2624
+ const addrs = ent.addresses;
2625
+ if (!addrs || typeof addrs !== "object") continue;
2626
+ for (const k of Object.keys(addrs)) {
2627
+ const lo = normLowerId(k);
2628
+ if (lo) m.set(lo, groupName);
2629
+ }
2630
+ }
2631
+ return m;
2632
+ }
2633
+ function formatPerformanceFeePercent(feeWad) {
2634
+ if (feeWad === 0n) return "0%";
2635
+ const x = Number(viem.formatUnits(feeWad, 18));
2636
+ if (!Number.isFinite(x)) return "\u2014";
2637
+ const pct = x * 100;
2638
+ if (pct >= 10) return `${pct.toFixed(1)}%`;
2639
+ if (pct >= 1) return `${pct.toFixed(2)}%`;
2640
+ return `${pct.toFixed(2)}%`;
2641
+ }
2642
+ function isMaxUintCap(cap) {
2643
+ return cap >= UINT256_MAX2 - 3n;
2644
+ }
2645
+ function isUnboundedEarnStrategyAllocationCap(cap) {
2646
+ return isMaxUintCap(cap) || cap === EARN_STRATEGY_ALLOC_CAP_SUBGRAPH_UNBOUNDED;
2647
+ }
2648
+ async function fetchEulerV2EarnOfferingsForRowAsset(args) {
2649
+ const { chainId, underlyingDecimals } = args;
2650
+ const cache = await ensureEulerV2ChainAssetCache(chainId);
2651
+ const key = eulerV2KeyForNodeAssetRow({
2652
+ contractAddress: args.contractAddress,
2653
+ nativeWrapped: cache.nativeWrapped
2654
+ });
2655
+ if (!key) return [];
2656
+ const [allowlist, entityByAddr] = await Promise.all([
2657
+ fetchEulerLabelsEarnVaultAllowlist(chainId),
2658
+ fetchEulerLabelsEntityNameByAddress(chainId)
2659
+ ]);
2660
+ if (!allowlist.size) return [];
2661
+ const assetBytes = key;
2662
+ const ids = [...allowlist];
2663
+ const data = await eulerV2QueryGraphQl(chainId, EARN_VAULTS_QUERY, {
2664
+ asset: assetBytes,
2665
+ ids
2666
+ });
2667
+ const rawRows = data.eulerEarnVaults ?? [];
2668
+ const strategyIds = /* @__PURE__ */ new Set();
2669
+ for (const v of rawRows) {
2670
+ for (const s of v.strategies ?? []) {
2671
+ const sid = normLowerId(s.strategy ?? void 0);
2672
+ if (sid) strategyIds.add(sid);
2673
+ }
2674
+ }
2675
+ const apyByVault = /* @__PURE__ */ new Map();
2676
+ const sidList = [...strategyIds];
2677
+ const batch = 200;
2678
+ for (let i = 0; i < sidList.length; i += batch) {
2679
+ const chunk = sidList.slice(i, i + batch);
2680
+ const d2 = await eulerV2QueryGraphQl(chainId, STRATEGY_VAULT_APY, {
2681
+ ids: chunk
2682
+ });
2683
+ for (const row of d2.eulerVaults ?? []) {
2684
+ const id = normLowerId(row.id ?? void 0);
2685
+ if (!id) continue;
2686
+ const ray = big(row.state?.supplyApy ?? "0");
2687
+ const sym = (row.symbol ?? "").trim() || "\u2014";
2688
+ const al = normLowerId(row.asset ?? void 0);
2689
+ apyByVault.set(id, { apyRay: ray, symbol: sym, assetLower: al });
2690
+ }
2691
+ }
2692
+ const dec = Math.max(0, Math.min(36, Math.floor(underlyingDecimals)));
2693
+ const tic = (args.suppliedAssetSymbol ?? "").trim();
2694
+ const out = [];
2695
+ for (const v of rawRows) {
2696
+ const vid = normLowerId(v.id ?? void 0);
2697
+ if (!vid || !allowlist.has(vid)) continue;
2698
+ const curatorLo = normLowerId(v.curator ?? void 0);
2699
+ const curatorName = curatorLo && entityByAddr.has(curatorLo) ? entityByAddr.get(curatorLo) : curatorLo ? `${curatorLo.slice(0, 6)}\u2026${curatorLo.slice(-4)}` : "\u2014";
2700
+ const strategiesRaw = [...v.strategies ?? []];
2701
+ const sumStratAlloc = strategiesRaw.reduce((a, s) => a + big(s.allocatedAssets), 0n);
2702
+ const totalAssets = big(v.totalAssets);
2703
+ const totalAllocatedField = big(v.totalAllocated);
2704
+ let denomForApy = sumStratAlloc;
2705
+ if (denomForApy === 0n) denomForApy = totalAllocatedField;
2706
+ let weightedApyRay = 0n;
2707
+ if (denomForApy > 0n) {
2708
+ let acc = 0n;
2709
+ for (const s of strategiesRaw) {
2710
+ const alloc = big(s.allocatedAssets);
2711
+ const sid = normLowerId(s.strategy ?? void 0);
2712
+ const meta = sid ? apyByVault.get(sid) : void 0;
2713
+ const ray = meta?.apyRay ?? 0n;
2714
+ acc += ray * alloc;
2715
+ }
2716
+ weightedApyRay = acc / denomForApy;
2717
+ }
2718
+ const supplyApyPercentLabel = denomForApy > 0n ? formatEulerRayApyPercent(weightedApyRay) : "0.00%";
2719
+ const deployedForLiquidity = sumStratAlloc > 0n ? sumStratAlloc : totalAllocatedField > 0n ? totalAllocatedField : 0n;
2720
+ const availableWei = totalAssets > deployedForLiquidity ? totalAssets - deployedForLiquidity : 0n;
2721
+ const performanceFee = big(v.performanceFee);
2722
+ const performanceFeePercentLabel = formatPerformanceFeePercent(performanceFee);
2723
+ const vaultName = (v.name ?? "").trim() || "Euler Earn";
2724
+ const stratRows = strategiesRaw.map((s) => {
2725
+ const sid = normLowerId(s.strategy ?? void 0) ?? "";
2726
+ const meta = sid ? apyByVault.get(sid) : void 0;
2727
+ const alloc = big(s.allocatedAssets);
2728
+ const cap = big(s.currentAllocationCap);
2729
+ const pctOfTotal = totalAssets > 0n ? `${(Number(alloc * 10000n / totalAssets) / 100).toFixed(1)}%` : "0.0%";
2730
+ const capUnlimited = isUnboundedEarnStrategyAllocationCap(cap);
2731
+ let capLabel;
2732
+ if (capUnlimited) {
2733
+ capLabel = "\u221E";
2734
+ } else if (cap === 0n) {
2735
+ capLabel = `0${tic ? ` ${tic}` : ""}`;
2736
+ } else {
2737
+ try {
2738
+ capLabel = `${viem.formatUnits(cap, dec)}${tic ? ` ${tic}` : ""}`;
2739
+ } catch {
2740
+ capLabel = cap.toString();
2741
+ }
2742
+ }
2743
+ let allocHuman;
2744
+ try {
2745
+ allocHuman = `${viem.formatUnits(alloc, dec)}${tic ? ` ${tic}` : ""}`;
2746
+ } catch {
2747
+ allocHuman = alloc.toString();
2748
+ }
2749
+ return {
2750
+ strategyVaultIdLower: sid,
2751
+ strategySymbol: meta?.symbol ?? "\u2014",
2752
+ supplyApyPercentLabel: meta ? formatEulerRayApyPercent(meta.apyRay) : "\u2014",
2753
+ allocatedAssetsWei: alloc,
2754
+ allocatedHumanLabel: allocHuman,
2755
+ allocationPercentOfTvlLabel: pctOfTotal,
2756
+ allocationCapHumanLabel: capLabel,
2757
+ allocationCapUnlimited: capUnlimited
2758
+ };
2759
+ });
2760
+ const cs = checksumHex2(v.id);
2761
+ if (!cs) continue;
2762
+ let totalHuman;
2763
+ let availHuman;
2764
+ try {
2765
+ totalHuman = `${viem.formatUnits(totalAssets, dec)}${tic ? ` ${tic}` : ""}`;
2766
+ availHuman = `${viem.formatUnits(availableWei, dec)}${tic ? ` ${tic}` : ""}`;
2767
+ } catch {
2768
+ totalHuman = totalAssets.toString();
2769
+ availHuman = availableWei.toString();
2770
+ }
2771
+ out.push({
2772
+ vaultIdLower: vid,
2773
+ evaultAddress: cs,
2774
+ vaultName,
2775
+ curatorDisplayName: curatorName,
2776
+ strategyCount: strategiesRaw.length,
2777
+ supplyApyPercentLabel,
2778
+ totalAssetsWei: totalAssets,
2779
+ totalAssetsHumanLabel: totalHuman,
2780
+ availableLiquidityWei: availableWei,
2781
+ availableLiquidityHumanLabel: availHuman,
2782
+ performanceFeePercentLabel,
2783
+ underlyingDecimals: dec,
2784
+ strategies: stratRows
2785
+ });
2786
+ }
2787
+ out.sort((a, b) => {
2788
+ const ap = Number.parseFloat(a.supplyApyPercentLabel.replace("%", "")) || 0;
2789
+ const bp = Number.parseFloat(b.supplyApyPercentLabel.replace("%", "")) || 0;
2790
+ if (bp !== ap) return bp - ap;
2791
+ return a.vaultName.localeCompare(b.vaultName);
2792
+ });
2793
+ return out;
2794
+ }
2795
+ function checksumHex2(raw) {
2796
+ const s = (raw ?? "").trim();
2797
+ if (!s || !viem.isAddress(s)) return null;
2798
+ try {
2799
+ return viem.getAddress(s);
2800
+ } catch {
2801
+ return null;
2802
+ }
2803
+ }
2804
+ var eulerVaultRiskAbi = viem.parseAbi([
2805
+ "function LTVBorrow(address collateral) view returns (uint16)",
2806
+ "function LTVLiquidation(address collateral) view returns (uint16)"
2807
+ ]);
2808
+ var priceOracleAbi = viem.parseAbi([
2809
+ "function getQuote(uint256 inAmount, address base, address quote) view returns (uint256 outAmount)"
2810
+ ]);
2811
+ function metaClient(chainId, rpcUrl) {
2812
+ const chain = viem.defineChain({
2813
+ id: chainId,
2814
+ name: "EulerBorrowRisk",
2815
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2816
+ rpcUrls: { default: { http: [rpcUrl] } }
2817
+ });
2818
+ return viem.createPublicClient({ chain, transport: viem.http(rpcUrl) });
2819
+ }
2820
+ async function fetchEulerV2BorrowPairLtvs(args) {
2821
+ const rpc = (args.rpcUrl ?? "").trim();
2822
+ if (!rpc) return null;
2823
+ try {
2824
+ const client = metaClient(args.chainId, rpc);
2825
+ const coll = viem.getAddress(args.collateralEvault);
2826
+ const bor = viem.getAddress(args.borrowEvault);
2827
+ const [maxLt, liqLt] = await Promise.all([
2828
+ client.readContract({ address: bor, abi: eulerVaultRiskAbi, functionName: "LTVBorrow", args: [coll] }),
2829
+ client.readContract({ address: bor, abi: eulerVaultRiskAbi, functionName: "LTVLiquidation", args: [coll] })
2830
+ ]);
2831
+ return { maxLtvBps: Number(maxLt), liquidationLtvBps: Number(liqLt) };
2832
+ } catch {
2833
+ return null;
2834
+ }
2835
+ }
2836
+ async function fetchEulerV2BorrowOracleQuoteSnapshot(args) {
2837
+ const rpc = (args.rpcUrl ?? "").trim();
2838
+ if (!rpc) return null;
2839
+ if (!viem.isAddress(args.oracle) || !viem.isAddress(args.unitOfAccount)) return null;
2840
+ try {
2841
+ const client = metaClient(args.chainId, rpc);
2842
+ const oracle = viem.getAddress(args.oracle);
2843
+ const uoa = viem.getAddress(args.unitOfAccount);
2844
+ const bAss = viem.getAddress(args.borrowAsset);
2845
+ const cAss = viem.getAddress(args.collateralAsset);
2846
+ const oneBorrow = viem.parseUnits("1", args.borrowDecimals);
2847
+ const collWei = viem.parseUnits(args.collateralAmountHuman, args.collateralDecimals);
2848
+ const [oneBorrowUnitUoAWei, collateralUoAWei] = await Promise.all([
2849
+ client.readContract({
2850
+ address: oracle,
2851
+ abi: priceOracleAbi,
2852
+ functionName: "getQuote",
2853
+ args: [oneBorrow, bAss, uoa]
2854
+ }),
2855
+ collWei > 0n ? client.readContract({
2856
+ address: oracle,
2857
+ abi: priceOracleAbi,
2858
+ functionName: "getQuote",
2859
+ args: [collWei, cAss, uoa]
2860
+ }) : Promise.resolve(0n)
2861
+ ]);
2862
+ return { oneBorrowUnitUoAWei, collateralUoAWei };
2863
+ } catch {
2864
+ return null;
2865
+ }
2866
+ }
2867
+ function estimateBorrowHumanFromLtv(args) {
2868
+ if (args.collateralUoAWei <= 0n || args.oneBorrowUnitUoAWei <= 0n || !(args.ltvPercent > 0)) return "0";
2869
+ const bps = Math.min(1e4, Math.max(0, Math.round(args.ltvPercent * 100)));
2870
+ const debtUoA = args.collateralUoAWei * BigInt(bps) / 10000n;
2871
+ const borrowWei = debtUoA * viem.parseUnits("1", args.borrowDecimals) / args.oneBorrowUnitUoAWei;
2872
+ if (borrowWei <= 0n) return "0";
2873
+ return viem.formatUnits(borrowWei, args.borrowDecimals);
2874
+ }
2875
+ function maxCollateralWeiCappedByBorrowLiquidity(args) {
2876
+ const { walletBalWei, maxBorrowWei, collateralFullUoAWei, oneBorrowUnitUoAWei, ltvPercent, borrowDecimals } = args;
2877
+ if (walletBalWei <= 0n) return 0n;
2878
+ if (maxBorrowWei <= 0n) return 0n;
2879
+ if (!(ltvPercent > 0)) return walletBalWei;
2880
+ if (collateralFullUoAWei <= 0n || oneBorrowUnitUoAWei <= 0n) return walletBalWei;
2881
+ const bps = Math.min(1e4, Math.max(0, Math.round(ltvPercent * 100)));
2882
+ const debtUoA = collateralFullUoAWei * BigInt(bps) / 10000n;
2883
+ const borrowWeiFull = debtUoA * viem.parseUnits("1", borrowDecimals) / oneBorrowUnitUoAWei;
2884
+ if (borrowWeiFull <= 0n) return walletBalWei;
2885
+ if (borrowWeiFull <= maxBorrowWei) return walletBalWei;
2886
+ return walletBalWei * maxBorrowWei / borrowWeiFull;
2887
+ }
2888
+
2889
+ // src/protocols/evm/euler-v2/eulerV2BorrowPositionsLoad.ts
2890
+ var TRACKING_BORROWS = `
2891
+ query EulerTrackingBorrows($id: Bytes!) {
2892
+ trackingActiveAccount(id: $id) {
2893
+ borrows
2894
+ }
2895
+ }`;
2896
+ var VAULTS_FOR_EVAULTS = `
2897
+ query EulerVaultsForBorrows($ids: [ID!]!) {
2898
+ eulerVaults(where: { id_in: $ids }) {
2899
+ id
2900
+ evault
2901
+ evc
2902
+ name
2903
+ symbol
2904
+ asset
2905
+ decimals
2906
+ collaterals
2907
+ }
2908
+ }`;
2909
+ var erc20DecimalsAbi2 = viem.parseAbi(["function decimals() view returns (uint8)"]);
2910
+ var erc4626BalanceAbi = viem.parseAbi(["function balanceOf(address account) view returns (uint256)"]);
2911
+ var erc4626MaxWithdrawAbi2 = viem.parseAbi(["function maxWithdraw(address owner) view returns (uint256)"]);
2912
+ var eulerRiskLtAbi = viem.parseAbi(["function LTVBorrow(address collateral) view returns (uint16)"]);
2913
+ var eulerLiquidityAbi = viem.parseAbi([
2914
+ "function accountLiquidity(address account, bool liquidation) view returns (uint256 collateralValue, uint256 liabilityValue)"
2915
+ ]);
2916
+ function metaClient2(chainId, rpcUrl) {
2917
+ const chain = viem.defineChain({
2918
+ id: chainId,
2919
+ name: "EulerBorrowPos",
2920
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
2921
+ rpcUrls: { default: { http: [rpcUrl] } }
2922
+ });
2923
+ return viem.createPublicClient({ chain, transport: viem.http(rpcUrl) });
2924
+ }
2925
+ function parseEulerTrackingBorrowEntry(entry) {
2926
+ const s = (entry ?? "").trim().toLowerCase();
2927
+ if (!s.startsWith("0x")) return null;
2928
+ const hex = s.slice(2);
2929
+ if (hex.length < 80) return null;
2930
+ try {
2931
+ const subAccount = viem.getAddress(`0x${hex.slice(0, 40)}`);
2932
+ const borrowVault = viem.getAddress(`0x${hex.slice(40, 80)}`);
2933
+ return { subAccount, borrowVault };
2934
+ } catch {
2935
+ return null;
2936
+ }
2937
+ }
2938
+ async function fetchEulerV2TrackingBorrowEntries(args) {
2939
+ const id = args.mainAddress.toLowerCase();
2940
+ const data = await eulerV2QueryGraphQl(
2941
+ args.chainId,
2942
+ TRACKING_BORROWS,
2943
+ { id }
2944
+ );
2945
+ const raw = data.trackingActiveAccount?.borrows ?? [];
2946
+ return raw.filter((x) => typeof x === "string" && x.trim().length > 0);
2947
+ }
2948
+ async function pickCollateralEvault(args) {
2949
+ const cands = (args.collaterals ?? []).map((c) => (c ?? "").trim().toLowerCase()).filter((c) => c.startsWith("0x") && viem.isAddress(c));
2950
+ const uniq = [...new Set(cands)];
2951
+ for (const low of uniq) {
2952
+ try {
2953
+ const coll = viem.getAddress(low);
2954
+ const lt = await args.client.readContract({
2955
+ address: args.borrowVault,
2956
+ abi: eulerRiskLtAbi,
2957
+ functionName: "LTVBorrow",
2958
+ args: [coll]
2959
+ });
2960
+ if (Number(lt) === 0) continue;
2961
+ const bal = await args.client.readContract({
2962
+ address: coll,
2963
+ abi: erc4626BalanceAbi,
2964
+ functionName: "balanceOf",
2965
+ args: [args.subAccount]
2966
+ });
2967
+ if (bal > 0n) return coll;
2968
+ } catch {
2969
+ }
2970
+ }
2971
+ for (const low of uniq) {
2972
+ try {
2973
+ const coll = viem.getAddress(low);
2974
+ const lt = await args.client.readContract({
2975
+ address: args.borrowVault,
2976
+ abi: eulerRiskLtAbi,
2977
+ functionName: "LTVBorrow",
2978
+ args: [coll]
2979
+ });
2980
+ if (Number(lt) > 0) return coll;
2981
+ } catch {
2982
+ }
2983
+ }
2984
+ if (uniq.length) {
2985
+ try {
2986
+ return viem.getAddress(uniq[0]);
2987
+ } catch {
2988
+ return null;
2989
+ }
2990
+ }
2991
+ return null;
2992
+ }
2993
+ async function loadEulerV2BorrowPositionsForOwner(args) {
2994
+ const rpc = args.rpcUrl.trim();
2995
+ if (!rpc) return [];
2996
+ const [entries, depositEntries] = await Promise.all([
2997
+ fetchEulerV2TrackingBorrowEntries({ chainId: args.chainId, mainAddress: args.mainAddress }),
2998
+ fetchEulerV2TrackingDepositEntries({ chainId: args.chainId, mainAddress: args.mainAddress })
2999
+ ]);
3000
+ const pairKey = (sub, vault) => `${sub.toLowerCase()}-${vault.toLowerCase()}`;
3001
+ const seenPairs = /* @__PURE__ */ new Set();
3002
+ const pairs = [];
3003
+ const pushPair = (sub, vault) => {
3004
+ const k = pairKey(sub, vault);
3005
+ if (seenPairs.has(k)) return;
3006
+ seenPairs.add(k);
3007
+ pairs.push({ subAccount: sub, borrowVault: vault });
3008
+ };
3009
+ for (const e of entries) {
3010
+ const p = parseEulerTrackingBorrowEntry(e);
3011
+ if (p) pushPair(p.subAccount, p.borrowVault);
3012
+ }
3013
+ const client = metaClient2(args.chainId, rpc);
3014
+ const debtAbi = viem.parseAbi(["function debtOf(address account) view returns (uint256)"]);
3015
+ for (const e of depositEntries) {
3016
+ const p = parseEulerTrackingBorrowEntry(e);
3017
+ if (!p) continue;
3018
+ if (seenPairs.has(pairKey(p.subAccount, p.borrowVault))) continue;
3019
+ let debtWei = 0n;
3020
+ try {
3021
+ debtWei = await client.readContract({
3022
+ address: p.borrowVault,
3023
+ abi: debtAbi,
3024
+ functionName: "debtOf",
3025
+ args: [p.subAccount]
3026
+ });
3027
+ } catch {
3028
+ continue;
3029
+ }
3030
+ if (debtWei === 0n) continue;
3031
+ pushPair(p.subAccount, p.borrowVault);
3032
+ }
3033
+ if (!pairs.length) return [];
3034
+ const vaultIds = [...new Set(pairs.map((x) => x.borrowVault.toLowerCase()))];
3035
+ const vaultData = await eulerV2QueryGraphQl(args.chainId, VAULTS_FOR_EVAULTS, { ids: vaultIds });
3036
+ const byEvault = /* @__PURE__ */ new Map();
3037
+ for (const v of vaultData.eulerVaults ?? []) {
3038
+ const ev = (v.evault ?? "").trim().toLowerCase();
3039
+ if (ev) byEvault.set(ev, v);
3040
+ }
3041
+ const evcAbi5 = viem.parseAbi(["function EVC() view returns (address)"]);
3042
+ const out = [];
3043
+ const t = Date.now();
3044
+ for (const { subAccount, borrowVault } of pairs) {
3045
+ let debtWei = 0n;
3046
+ try {
3047
+ debtWei = await client.readContract({
3048
+ address: borrowVault,
3049
+ abi: debtAbi,
3050
+ functionName: "debtOf",
3051
+ args: [subAccount]
3052
+ });
3053
+ } catch {
3054
+ }
3055
+ const vrow = byEvault.get(borrowVault.toLowerCase());
3056
+ const decRaw = Number((vrow?.decimals ?? "18").toString().trim() || "18");
3057
+ const decimals = Number.isFinite(decRaw) && decRaw >= 0 && decRaw <= 36 ? decRaw : 18;
3058
+ let assetLow = (vrow?.asset ?? "").trim().toLowerCase();
3059
+ if (!assetLow || !viem.isAddress(assetLow)) {
3060
+ try {
3061
+ const a = await client.readContract({
3062
+ address: borrowVault,
3063
+ abi: viem.parseAbi(["function asset() view returns (address)"]),
3064
+ functionName: "asset"
3065
+ });
3066
+ assetLow = viem.getAddress(a).toLowerCase();
3067
+ } catch {
3068
+ assetLow = "";
3069
+ }
3070
+ }
3071
+ let decFinal = decimals;
3072
+ if (assetLow && viem.isAddress(assetLow)) {
3073
+ try {
3074
+ const d = await client.readContract({
3075
+ address: viem.getAddress(assetLow),
3076
+ abi: erc20DecimalsAbi2,
3077
+ functionName: "decimals"
3078
+ });
3079
+ const n = Number(d);
3080
+ if (Number.isFinite(n) && n >= 0 && n <= 36) decFinal = n;
3081
+ } catch {
3082
+ }
3083
+ }
3084
+ const debtHuman = viem.formatUnits(debtWei, decFinal);
3085
+ const collateralVault = await pickCollateralEvault({
3086
+ client,
3087
+ borrowVault,
3088
+ subAccount,
3089
+ collaterals: vrow?.collaterals ?? null
3090
+ });
3091
+ if (debtWei === 0n) {
3092
+ if (!collateralVault) continue;
3093
+ let maxWithdrawLeft = 0n;
3094
+ try {
3095
+ maxWithdrawLeft = await client.readContract({
3096
+ address: collateralVault,
3097
+ abi: erc4626MaxWithdrawAbi2,
3098
+ functionName: "maxWithdraw",
3099
+ args: [subAccount]
3100
+ });
3101
+ } catch {
3102
+ maxWithdrawLeft = 0n;
3103
+ }
3104
+ let collateralShares = 0n;
3105
+ if (maxWithdrawLeft === 0n) {
3106
+ try {
3107
+ collateralShares = await client.readContract({
3108
+ address: collateralVault,
3109
+ abi: erc4626BalanceAbi,
3110
+ functionName: "balanceOf",
3111
+ args: [subAccount]
3112
+ });
3113
+ } catch {
3114
+ collateralShares = 0n;
3115
+ }
3116
+ }
3117
+ if (maxWithdrawLeft === 0n && collateralShares === 0n) continue;
3118
+ }
3119
+ let collateralAssetAddressLower = null;
3120
+ let collateralAssetDecimals;
3121
+ let collateralUnderlyingSymbol = null;
3122
+ if (collateralVault) {
3123
+ try {
3124
+ const assetAddr = await client.readContract({
3125
+ address: collateralVault,
3126
+ abi: viem.parseAbi(["function asset() view returns (address)"]),
3127
+ functionName: "asset"
3128
+ });
3129
+ const cLow = viem.getAddress(assetAddr).toLowerCase();
3130
+ collateralAssetAddressLower = cLow;
3131
+ const cd = await client.readContract({
3132
+ address: viem.getAddress(cLow),
3133
+ abi: erc20DecimalsAbi2,
3134
+ functionName: "decimals"
3135
+ });
3136
+ const cn = Number(cd);
3137
+ if (Number.isFinite(cn) && cn >= 0 && cn <= 36) collateralAssetDecimals = cn;
3138
+ try {
3139
+ const sym = await client.readContract({
3140
+ address: viem.getAddress(cLow),
3141
+ abi: viem.parseAbi(["function symbol() view returns (string)"]),
3142
+ functionName: "symbol"
3143
+ });
3144
+ const s = typeof sym === "string" ? sym.trim() : "";
3145
+ if (s) collateralUnderlyingSymbol = s;
3146
+ } catch {
3147
+ }
3148
+ } catch {
3149
+ }
3150
+ }
3151
+ let maxLtvBps = null;
3152
+ let liquidationLtvBps = null;
3153
+ if (collateralVault) {
3154
+ const risk = await fetchEulerV2BorrowPairLtvs({
3155
+ chainId: args.chainId,
3156
+ rpcUrl: rpc,
3157
+ borrowEvault: borrowVault,
3158
+ collateralEvault: collateralVault
3159
+ });
3160
+ if (risk) {
3161
+ maxLtvBps = risk.maxLtvBps;
3162
+ liquidationLtvBps = risk.liquidationLtvBps;
3163
+ }
3164
+ }
3165
+ let currentLtvPercent = null;
3166
+ try {
3167
+ const [collV, liabV] = await client.readContract({
3168
+ address: borrowVault,
3169
+ abi: eulerLiquidityAbi,
3170
+ functionName: "accountLiquidity",
3171
+ args: [subAccount, false]
3172
+ });
3173
+ if (collV > 0n && liabV > 0n) {
3174
+ currentLtvPercent = Number(liabV * 10000n / collV) / 100;
3175
+ }
3176
+ } catch {
3177
+ }
3178
+ let evc = (vrow?.evc ?? "").trim() ? viem.getAddress(vrow.evc.trim()) : null;
3179
+ if (!evc) {
3180
+ try {
3181
+ const e = await client.readContract({
3182
+ address: borrowVault,
3183
+ abi: evcAbi5,
3184
+ functionName: "EVC"
3185
+ });
3186
+ evc = viem.getAddress(e);
3187
+ } catch {
3188
+ evc = null;
3189
+ }
3190
+ }
3191
+ const marketName = [(vrow?.symbol ?? "").trim(), (vrow?.name ?? "").trim()].filter(Boolean).join(" \xB7 ") || `Borrow ${borrowVault.slice(0, 10)}\u2026`;
3192
+ out.push({
3193
+ id: `borrow-${args.chainId}-${subAccount.toLowerCase()}-${borrowVault.toLowerCase()}`,
3194
+ chainId: args.chainId,
3195
+ vaultId: (vrow?.id ?? borrowVault).toString(),
3196
+ evaultAddress: borrowVault,
3197
+ marketName,
3198
+ underlyingSymbol: (vrow?.symbol ?? "\u2014").toString().trim() || "\u2014",
3199
+ amountHuman: debtHuman,
3200
+ createdAtMs: t,
3201
+ signRequestId: null,
3202
+ positionKind: "borrow",
3203
+ subAccountAddress: subAccount,
3204
+ collateralEvaultAddress: collateralVault,
3205
+ evcAddress: evc,
3206
+ borrowAssetAddressLower: assetLow || null,
3207
+ borrowAssetDecimals: decFinal,
3208
+ borrowDebtHuman: debtHuman,
3209
+ collateralAssetAddressLower,
3210
+ collateralAssetDecimals,
3211
+ collateralUnderlyingSymbol,
3212
+ currentLtvPercent,
3213
+ maxLtvBps,
3214
+ liquidationLtvBps
3215
+ });
3216
+ }
3217
+ return out.sort((a, b) => (a.marketName || "").localeCompare(b.marketName || ""));
3218
+ }
3219
+ async function fetchEulerV2BorrowDebtWei(args) {
3220
+ const rpc = args.rpcUrl.trim();
3221
+ if (!rpc) return 0n;
3222
+ const client = metaClient2(args.chainId, rpc);
3223
+ const debtAbi = viem.parseAbi(["function debtOf(address account) view returns (uint256)"]);
3224
+ try {
3225
+ return await client.readContract({
3226
+ address: args.borrowVault,
3227
+ abi: debtAbi,
3228
+ functionName: "debtOf",
3229
+ args: [args.subAccount]
3230
+ });
3231
+ } catch {
3232
+ return 0n;
3233
+ }
3234
+ }
3235
+ var VAULTS_FOR_EVAULTS2 = `
3236
+ query EulerVaultsForSupply($ids: [ID!]!) {
3237
+ eulerVaults(where: { id_in: $ids }) {
3238
+ id
3239
+ evault
3240
+ name
3241
+ symbol
3242
+ asset
3243
+ decimals
3244
+ }
3245
+ }`;
3246
+ var vaultSupplyAbi = viem.parseAbi([
3247
+ "function balanceOf(address account) view returns (uint256)",
3248
+ "function convertToAssets(uint256 shares) view returns (uint256)",
3249
+ "function asset() view returns (address)"
3250
+ ]);
3251
+ var debtOfAbi = viem.parseAbi(["function debtOf(address account) view returns (uint256)"]);
3252
+ function metaClient3(chainId, rpcUrl) {
3253
+ const chain = viem.defineChain({
3254
+ id: chainId,
3255
+ name: "EulerLendSupply",
3256
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
3257
+ rpcUrls: { default: { http: [rpcUrl] } }
3258
+ });
3259
+ return viem.createPublicClient({ chain, transport: viem.http(rpcUrl) });
3260
+ }
3261
+ async function readSupplyUnderlyingWei(client, vault, shareOwner) {
3262
+ try {
3263
+ const shares = await client.readContract({
3264
+ address: vault,
3265
+ abi: vaultSupplyAbi,
3266
+ functionName: "balanceOf",
3267
+ args: [shareOwner]
3268
+ });
3269
+ if (shares === 0n) return null;
3270
+ const assets = await client.readContract({
3271
+ address: vault,
3272
+ abi: vaultSupplyAbi,
3273
+ functionName: "convertToAssets",
3274
+ args: [shares]
3275
+ });
3276
+ if (assets === 0n) return null;
3277
+ const asset = await client.readContract({
3278
+ address: vault,
3279
+ abi: vaultSupplyAbi,
3280
+ functionName: "asset"
3281
+ });
3282
+ return { asset: viem.getAddress(asset), wei: assets };
3283
+ } catch {
3284
+ return null;
3285
+ }
3286
+ }
3287
+ async function loadEulerV2LendSupplyPositionsForOwner(args) {
3288
+ const rpc = args.rpcUrl.trim();
3289
+ if (!rpc) return [];
3290
+ if (!eulerV2GoldskyUrlForChain(args.chainId)) return [];
3291
+ const [entries, earnVaultAllowlist, gasAliases] = await Promise.all([
3292
+ fetchEulerV2TrackingDepositEntries({ chainId: args.chainId, mainAddress: args.mainAddress }),
3293
+ fetchEulerLabelsEarnVaultAllowlist(args.chainId),
3294
+ eulerWrappedGasTokenAliasesLower(args.chainId)
3295
+ ]);
3296
+ const pairs = [];
3297
+ for (const e of entries) {
3298
+ const p = parseEulerTrackingBorrowEntry(e);
3299
+ if (p) pairs.push({ subAccount: p.subAccount, evault: p.borrowVault });
3300
+ }
3301
+ if (!pairs.length) return [];
3302
+ const vaultIds = [...new Set(pairs.map((x) => x.evault.toLowerCase()))];
3303
+ const vaultData = await eulerV2QueryGraphQl(args.chainId, VAULTS_FOR_EVAULTS2, { ids: vaultIds });
3304
+ const byEvault = /* @__PURE__ */ new Map();
3305
+ for (const v of vaultData.eulerVaults ?? []) {
3306
+ const ev = (v.evault ?? "").trim().toLowerCase();
3307
+ if (ev) byEvault.set(ev, v);
3308
+ }
3309
+ const client = metaClient3(args.chainId, rpc);
3310
+ const t = Date.now();
3311
+ const out = [];
3312
+ const seenPair = /* @__PURE__ */ new Set();
3313
+ for (const { subAccount, evault } of pairs) {
3314
+ const pairKey = `${subAccount.toLowerCase()}-${evault.toLowerCase()}`;
3315
+ if (seenPair.has(pairKey)) continue;
3316
+ seenPair.add(pairKey);
3317
+ const supply = await readSupplyUnderlyingWei(client, evault, subAccount);
3318
+ if (!supply) continue;
3319
+ let liabilityDebtWei = 0n;
3320
+ try {
3321
+ liabilityDebtWei = await client.readContract({
3322
+ address: evault,
3323
+ abi: debtOfAbi,
3324
+ functionName: "debtOf",
3325
+ args: [subAccount]
3326
+ });
3327
+ } catch {
3328
+ liabilityDebtWei = 0n;
3329
+ }
3330
+ if (liabilityDebtWei > 0n) continue;
3331
+ const vrow = byEvault.get(evault.toLowerCase());
3332
+ const isEarn = earnVaultAllowlist.has(evault.toLowerCase());
3333
+ const positionKind = isEarn ? "earn" : "lend";
3334
+ const underlyingSymbol = (vrow?.symbol ?? "\u2014").toString().trim() || "\u2014";
3335
+ const marketName = [(vrow?.symbol ?? "").trim(), (vrow?.name ?? "").trim()].filter(Boolean).join(" \xB7 ") || `${isEarn ? "Earn" : "Lend"} ${evault.slice(0, 10)}\u2026`;
3336
+ let evChecksummed;
3337
+ try {
3338
+ evChecksummed = viem.getAddress(evault);
3339
+ } catch {
3340
+ continue;
3341
+ }
3342
+ let vaultMeta;
3343
+ try {
3344
+ vaultMeta = await fetchEulerVaultUnderlyingMeta({
3345
+ rpcUrl: rpc,
3346
+ chainId: args.chainId,
3347
+ evault: evChecksummed
3348
+ });
3349
+ } catch {
3350
+ continue;
3351
+ }
3352
+ const decimals = clampEulerUnderlyingDecimalsForEulerUi({
3353
+ fetchedDecimals: vaultMeta.decimals,
3354
+ underlyingAssetLower: vaultMeta.asset.toLowerCase(),
3355
+ marketName,
3356
+ underlyingSymbol,
3357
+ wrappedGasAliasesLower: gasAliases
3358
+ });
3359
+ const amountHuman = viem.formatUnits(supply.wei, decimals);
3360
+ out.push({
3361
+ id: `${positionKind}-supply-${args.chainId}-${subAccount.toLowerCase()}-${evault.toLowerCase()}`,
3362
+ chainId: args.chainId,
3363
+ vaultId: (vrow?.id ?? evault).toString(),
3364
+ evaultAddress: evault,
3365
+ marketName,
3366
+ underlyingSymbol,
3367
+ amountHuman,
3368
+ underlyingAssetsWei: supply.wei.toString(),
3369
+ underlyingAssetAddressLower: vaultMeta.asset.toLowerCase(),
3370
+ createdAtMs: t,
3371
+ signRequestId: null,
3372
+ positionKind,
3373
+ subAccountAddress: subAccount,
3374
+ underlyingAssetDecimals: decimals
3375
+ });
3376
+ }
3377
+ return out.sort((a, b) => (a.marketName || "").localeCompare(b.marketName || ""));
3378
+ }
3379
+ function mergeEulerV2PositionsTabRows(args) {
3380
+ const main = args.mainAddressLower.trim().toLowerCase();
3381
+ const keyOf = (p) => {
3382
+ const kind = p.positionKind ?? "lend";
3383
+ if (kind === "borrow") return p.id;
3384
+ const ev = p.evaultAddress.trim().toLowerCase();
3385
+ const sub = (p.subAccountAddress ?? main).trim().toLowerCase();
3386
+ return `supply|${ev}|${sub}`;
3387
+ };
3388
+ const chainKeys = new Set(args.chainSupply.map(keyOf));
3389
+ const sessionFiltered = args.session.filter((s) => !chainKeys.has(keyOf(s)));
3390
+ return [...args.borrow, ...args.chainSupply, ...sessionFiltered];
3391
+ }
3392
+ var REUL_LOCK_DAY_SEC = 86400n;
3393
+ var REUL_FULL_VEST_SEC = 180n * REUL_LOCK_DAY_SEC;
3394
+ var rewardTokenReadAbi = viem.parseAbi([
3395
+ "function getLockedAmounts(address account) view returns (uint256[] lockTimestamps, uint256[] amounts)",
3396
+ "function getWithdrawAmountsByLockTimestamp(address account, uint256 lockTimestamp) view returns (uint256 accountAmount, uint256 remainderAmount)"
3397
+ ]);
3398
+ var eulerReulUnlockAbi = viem.parseAbi([
3399
+ "function withdrawToByLockTimestamps(address account, uint256[] lockTimestamps, bool allowRemainderLoss) returns (bool)"
3400
+ ]);
3401
+ async function fetchEulerReulVestingTranches(args) {
3402
+ const rpc = args.rpcUrl.trim();
3403
+ if (!rpc) return [];
3404
+ const reul = viem.getAddress(args.reulToken);
3405
+ const user = viem.getAddress(args.user);
3406
+ const ch = viem.defineChain({
3407
+ id: args.chainId,
3408
+ name: "ReulVest",
3409
+ nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
3410
+ rpcUrls: { default: { http: [rpc] } }
3411
+ });
3412
+ const client = viem.createPublicClient({ chain: ch, transport: viem.http(rpc) });
3413
+ const [timestamps, amounts] = await client.readContract({
3414
+ address: reul,
3415
+ abi: rewardTokenReadAbi,
3416
+ functionName: "getLockedAmounts",
3417
+ args: [user]
3418
+ });
3419
+ const out = [];
3420
+ for (let i = 0; i < timestamps.length; i++) {
3421
+ const lockTs = timestamps[i];
3422
+ const lockedAmt = amounts[i];
3423
+ if (lockedAmt === 0n) continue;
3424
+ const [unlockToWalletWei, remainderWei] = await client.readContract({
3425
+ address: reul,
3426
+ abi: rewardTokenReadAbi,
3427
+ functionName: "getWithdrawAmountsByLockTimestamp",
3428
+ args: [user, lockTs]
3429
+ });
3430
+ out.push({
3431
+ reulToken: reul,
3432
+ lockTimestampSec: lockTs,
3433
+ lockedAmountWei: lockedAmt,
3434
+ unlockToWalletWei,
3435
+ remainderWei,
3436
+ fullVestTimestampSec: lockTs + REUL_FULL_VEST_SEC,
3437
+ isFullyVested: remainderWei === 0n
3438
+ });
3439
+ }
3440
+ return out;
3441
+ }
3442
+ function encodeEulerReulWithdrawToByLockTimestampsData(args) {
3443
+ const recipient = viem.getAddress(args.recipient);
3444
+ if (args.lockTimestampsSec.length === 0) throw new Error("No rEUL lock timestamps to unlock.");
3445
+ return viem.encodeFunctionData({
3446
+ abi: eulerReulUnlockAbi,
3447
+ functionName: "withdrawToByLockTimestamps",
3448
+ args: [recipient, [...args.lockTimestampsSec], args.allowRemainderLoss]
3449
+ });
3450
+ }
3451
+ var EULER_REUL_UNLOCK_GAS_FALLBACK = 500000n;
3452
+
3453
+ // src/chains/evm/coingecko.ts
3454
+ var COINGECKO_PLATFORM_BY_CHAIN_ID = {
3455
+ "1": "ethereum",
3456
+ "56": "binance-smart-chain",
3457
+ "137": "polygon-pos",
3458
+ "42161": "arbitrum-one",
3459
+ "10": "optimistic-ethereum",
3460
+ "43114": "avalanche",
3461
+ "8453": "base",
3462
+ "324": "zk-sync-era",
3463
+ "42220": "celo",
3464
+ "250": "fantom",
3465
+ "100": "gnosis",
3466
+ "204": "op-bnb",
3467
+ "534352": "scroll",
3468
+ "5000": "mantle",
3469
+ "169": "manta-pacific",
3470
+ "1116": "core",
3471
+ "30": "rootstock",
3472
+ "288": "boba",
3473
+ "1088": "metis-andromeda",
3474
+ "34443": "mode",
3475
+ "80084": "berachain",
3476
+ "146": "sonic",
3477
+ "60808": "bob-network",
3478
+ "80094": "berachain",
3479
+ "130": "unichain",
3480
+ "57073": "ink",
3481
+ "999": "hyperevm",
3482
+ "239": "tac",
3483
+ "9745": "plasma",
3484
+ "1923": "swellchain",
3485
+ "59144": "linea",
3486
+ "81457": "blast",
3487
+ "7777777": "zora"
3488
+ };
3489
+
3490
+ // src/protocols/evm/euler-v2/eulerV2PortfolioUsd.ts
3491
+ var TRACKING_ACCOUNT = `
3492
+ query EulerTrackingAccount($id: Bytes!) {
3493
+ trackingActiveAccount(id: $id) {
3494
+ deposits
3495
+ borrows
3496
+ }
3497
+ }`;
3498
+ var vaultSupplyAbi2 = viem.parseAbi([
3499
+ "function balanceOf(address account) view returns (uint256)",
3500
+ "function convertToAssets(uint256 shares) view returns (uint256)",
3501
+ "function asset() view returns (address)"
3502
+ ]);
3503
+ var erc20DecimalsAbi3 = viem.parseAbi(["function decimals() view returns (uint8)"]);
3504
+ var debtOfAbi2 = viem.parseAbi(["function debtOf(address account) view returns (uint256)"]);
3505
+ function publicClient(chainId, rpcUrl) {
3506
+ const ch = viem.defineChain({
3507
+ id: chainId,
3508
+ name: "EulerPortfolio",
3509
+ nativeCurrency: { decimals: 18, name: "x", symbol: "x" },
3510
+ rpcUrls: { default: { http: [rpcUrl] } }
3511
+ });
3512
+ return viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
3513
+ }
3514
+ async function gqlTrackingAccount(chainId, mainLower) {
3515
+ if (!eulerV2GoldskyUrlForChain(chainId)) {
3516
+ return { deposits: [], borrows: [] };
3517
+ }
3518
+ const data = await eulerV2QueryGraphQl(chainId, TRACKING_ACCOUNT, { id: mainLower });
3519
+ const a = data.trackingActiveAccount;
3520
+ const dep = (a?.deposits ?? []).filter((x) => typeof x === "string" && x.trim().length > 0);
3521
+ const bor = (a?.borrows ?? []).filter((x) => typeof x === "string" && x.trim().length > 0);
3522
+ return { deposits: dep, borrows: bor };
3523
+ }
3524
+ async function decimalsForAsset(client, asset) {
3525
+ try {
3526
+ const d = await client.readContract({
3527
+ address: asset,
3528
+ abi: erc20DecimalsAbi3,
3529
+ functionName: "decimals"
3530
+ });
3531
+ const n = Number(d);
3532
+ if (Number.isFinite(n) && n >= 0 && n <= 36) return n;
3533
+ } catch {
3534
+ }
3535
+ return 18;
3536
+ }
3537
+ async function readSupplyUnderlyingWei2(client, vault, subAccount) {
3538
+ try {
3539
+ const shares = await client.readContract({
3540
+ address: vault,
3541
+ abi: vaultSupplyAbi2,
3542
+ functionName: "balanceOf",
3543
+ args: [subAccount]
3544
+ });
3545
+ if (shares === 0n) return null;
3546
+ const assets = await client.readContract({
3547
+ address: vault,
3548
+ abi: vaultSupplyAbi2,
3549
+ functionName: "convertToAssets",
3550
+ args: [shares]
3551
+ });
3552
+ if (assets === 0n) return null;
3553
+ const asset = await client.readContract({
3554
+ address: vault,
3555
+ abi: vaultSupplyAbi2,
3556
+ functionName: "asset"
3557
+ });
3558
+ return { asset: viem.getAddress(asset), wei: assets };
3559
+ } catch {
3560
+ return null;
3561
+ }
3562
+ }
3563
+ async function readBorrowDebtWei(client, borrowVault, subAccount) {
3564
+ try {
3565
+ const debt = await client.readContract({
3566
+ address: borrowVault,
3567
+ abi: debtOfAbi2,
3568
+ functionName: "debtOf",
3569
+ args: [subAccount]
3570
+ });
3571
+ if (debt === 0n) return null;
3572
+ const asset = await client.readContract({
3573
+ address: borrowVault,
3574
+ abi: vaultSupplyAbi2,
3575
+ functionName: "asset"
3576
+ });
3577
+ return { asset: viem.getAddress(asset), wei: debt };
3578
+ } catch {
3579
+ return null;
3580
+ }
3581
+ }
3582
+ function mergeWei(into, asset, wei) {
3583
+ const k = asset.toLowerCase();
3584
+ into.set(k, (into.get(k) ?? 0n) + wei);
3585
+ }
3586
+ async function fetchCoingeckoContractUsdFromDetail(args) {
3587
+ const a = args.contractAddressLower.trim().toLowerCase();
3588
+ if (!a.startsWith("0x")) return null;
3589
+ const url = `https://api.coingecko.com/api/v3/coins/${encodeURIComponent(args.platform)}/contract/${a}`;
3590
+ try {
3591
+ const r = await fetch(url, { cache: "no-store" });
3592
+ if (!r.ok) return null;
3593
+ const j = await r.json();
3594
+ const u = j.market_data?.current_price?.usd;
3595
+ if (typeof u !== "number" || !Number.isFinite(u) || u < 0) return null;
3596
+ return u;
3597
+ } catch {
3598
+ return null;
3599
+ }
3600
+ }
3601
+ async function augmentMissingTokenPrices(args) {
3602
+ const missing = args.addressesLower.map((x) => x.trim().toLowerCase()).filter((x) => x.startsWith("0x") && !args.prices.has(x));
3603
+ for (const addr of missing.slice(0, 12)) {
3604
+ const u = await fetchCoingeckoContractUsdFromDetail({ platform: args.platform, contractAddressLower: addr });
3605
+ if (u != null) args.prices.set(addr, u);
3606
+ }
3607
+ }
3608
+ var COINGECKO_CHUNK = 45;
3609
+ async function fetchCoingeckoTokenUsdByContract(args) {
3610
+ const platform = COINGECKO_PLATFORM_BY_CHAIN_ID[String(args.chainId)];
3611
+ const out = /* @__PURE__ */ new Map();
3612
+ if (!platform || args.contractAddressesLower.length === 0) return out;
3613
+ const uniq = [...new Set(args.contractAddressesLower.map((a) => a.trim().toLowerCase()).filter((a) => a.startsWith("0x")))];
3614
+ for (let i = 0; i < uniq.length; i += COINGECKO_CHUNK) {
3615
+ const chunk = uniq.slice(i, i + COINGECKO_CHUNK);
3616
+ const url = `https://api.coingecko.com/api/v3/simple/token_price/${encodeURIComponent(platform)}?contract_addresses=${chunk.join(",")}&vs_currencies=usd`;
3617
+ try {
3618
+ const proxy = getCoingeckoProxyUrl();
3619
+ const r = proxy ? await fetch(proxy, {
3620
+ method: "POST",
3621
+ headers: { "content-type": "application/json" },
3622
+ body: JSON.stringify({ platform, contractAddresses: chunk })
3623
+ }) : await fetch(url, { cache: "no-store" });
3624
+ if (!r.ok) continue;
3625
+ const j = await r.json();
3626
+ for (const [addr, row] of Object.entries(j)) {
3627
+ const u = row?.usd;
3628
+ if (typeof u === "number" && Number.isFinite(u) && u >= 0) out.set(addr.toLowerCase(), u);
3629
+ }
3630
+ } catch {
3631
+ }
3632
+ }
3633
+ return out;
3634
+ }
3635
+ function sumSideUsd(args) {
3636
+ let partial = false;
3637
+ let total = 0;
3638
+ let anyPriced = false;
3639
+ let anyUnpricedNonZero = false;
3640
+ const entries = [...args.byAssetWei.entries()].filter(([, w]) => w > 0n);
3641
+ if (entries.length === 0) return { usd: 0, partial: false };
3642
+ for (const [assetLow, wei] of entries) {
3643
+ const dec = args.decimalsByAsset.get(assetLow) ?? 18;
3644
+ const p = args.prices.get(assetLow);
3645
+ if (p == null) {
3646
+ partial = true;
3647
+ anyUnpricedNonZero = true;
3648
+ continue;
3649
+ }
3650
+ let humanAmt;
3651
+ try {
3652
+ humanAmt = Number.parseFloat(viem.formatUnits(wei, dec));
3653
+ } catch {
3654
+ partial = true;
3655
+ anyUnpricedNonZero = true;
3656
+ continue;
3657
+ }
3658
+ const slice = humanAmt * p;
3659
+ if (!Number.isFinite(humanAmt) || !Number.isFinite(p) || !Number.isFinite(slice)) {
3660
+ partial = true;
3661
+ anyUnpricedNonZero = true;
3662
+ continue;
3663
+ }
3664
+ anyPriced = true;
3665
+ total += slice;
3666
+ }
3667
+ if (anyUnpricedNonZero && !anyPriced) return { usd: null, partial: true };
3668
+ if (anyUnpricedNonZero) partial = true;
3669
+ if (!Number.isFinite(total)) return { usd: null, partial: true };
3670
+ return { usd: total, partial };
3671
+ }
3672
+ async function loadEulerV2PortfolioUsdSnapshot(args) {
3673
+ const rpc = args.rpcUrl.trim();
3674
+ const empty = {
3675
+ totalSuppliedUsd: null,
3676
+ totalBorrowedUsd: null,
3677
+ netAssetValueUsd: null,
3678
+ partialPricing: false,
3679
+ pricingUnavailable: false,
3680
+ error: null
3681
+ };
3682
+ if (!rpc) {
3683
+ return { ...empty, error: "No RPC URL." };
3684
+ }
3685
+ const platform = COINGECKO_PLATFORM_BY_CHAIN_ID[String(args.chainId)];
3686
+ try {
3687
+ const mainLower = args.mainAddress.toLowerCase();
3688
+ const { deposits, borrows } = await gqlTrackingAccount(args.chainId, mainLower);
3689
+ const client = publicClient(args.chainId, rpc);
3690
+ const suppliedWeiByAsset = /* @__PURE__ */ new Map();
3691
+ const borrowedWeiByAsset = /* @__PURE__ */ new Map();
3692
+ const borrowPairSeen = /* @__PURE__ */ new Set();
3693
+ const borrowPairs = [];
3694
+ const pushBorrowPair = (sub, vault) => {
3695
+ const k = `${sub.toLowerCase()}-${vault.toLowerCase()}`;
3696
+ if (borrowPairSeen.has(k)) return;
3697
+ borrowPairSeen.add(k);
3698
+ borrowPairs.push({ subAccount: sub, vault });
3699
+ };
3700
+ const supplyReads = [];
3701
+ for (const entry of deposits) {
3702
+ const p = parseEulerTrackingBorrowEntry(entry);
3703
+ if (!p) continue;
3704
+ pushBorrowPair(p.subAccount, p.borrowVault);
3705
+ supplyReads.push(
3706
+ (async () => {
3707
+ const r = await readSupplyUnderlyingWei2(client, p.borrowVault, p.subAccount);
3708
+ if (!r) return;
3709
+ mergeWei(suppliedWeiByAsset, r.asset, r.wei);
3710
+ })()
3711
+ );
3712
+ }
3713
+ for (const entry of borrows) {
3714
+ const p = parseEulerTrackingBorrowEntry(entry);
3715
+ if (!p) continue;
3716
+ pushBorrowPair(p.subAccount, p.borrowVault);
3717
+ }
3718
+ const borrowReads = borrowPairs.map(
3719
+ ({ subAccount, vault }) => (async () => {
3720
+ const r = await readBorrowDebtWei(client, vault, subAccount);
3721
+ if (!r) return;
3722
+ mergeWei(borrowedWeiByAsset, r.asset, r.wei);
3723
+ })()
3724
+ );
3725
+ await Promise.all([...supplyReads, ...borrowReads]);
3726
+ const allAssets = /* @__PURE__ */ new Set();
3727
+ for (const [a, w] of suppliedWeiByAsset) if (w > 0n) allAssets.add(a.toLowerCase());
3728
+ for (const [a, w] of borrowedWeiByAsset) if (w > 0n) allAssets.add(a.toLowerCase());
3729
+ const decimalsByAsset = /* @__PURE__ */ new Map();
3730
+ for (const low of allAssets) {
3731
+ if (!viem.isAddress(low)) continue;
3732
+ const dec = await decimalsForAsset(client, viem.getAddress(low));
3733
+ decimalsByAsset.set(low.toLowerCase(), dec);
3734
+ }
3735
+ const prices = platform != null ? await fetchCoingeckoTokenUsdByContract({
3736
+ chainId: args.chainId,
3737
+ contractAddressesLower: [...allAssets]
3738
+ }) : /* @__PURE__ */ new Map();
3739
+ if (platform != null && allAssets.size > 0) {
3740
+ await augmentMissingTokenPrices({
3741
+ platform,
3742
+ addressesLower: [...allAssets],
3743
+ prices
3744
+ });
3745
+ }
3746
+ const s = sumSideUsd({ byAssetWei: suppliedWeiByAsset, decimalsByAsset, prices });
3747
+ const b = sumSideUsd({ byAssetWei: borrowedWeiByAsset, decimalsByAsset, prices });
3748
+ const sUsd = s.usd != null && Number.isFinite(s.usd) ? s.usd : null;
3749
+ const bUsd = b.usd != null && Number.isFinite(b.usd) ? b.usd : null;
3750
+ let nav = null;
3751
+ if (sUsd != null && bUsd != null) nav = sUsd - bUsd;
3752
+ else if (sUsd != null && (borrowedWeiByAsset.size === 0 || [...borrowedWeiByAsset.values()].every((w) => w === 0n))) {
3753
+ nav = sUsd;
3754
+ } else if (bUsd != null && (suppliedWeiByAsset.size === 0 || [...suppliedWeiByAsset.values()].every((w) => w === 0n))) {
3755
+ nav = -bUsd;
3756
+ }
3757
+ if (nav != null && !Number.isFinite(nav)) nav = null;
3758
+ const hasAnyPosition = [...suppliedWeiByAsset.values(), ...borrowedWeiByAsset.values()].some((w) => w > 0n);
3759
+ const partialPricing = s.partial || b.partial;
3760
+ const pricingUnavailable = platform == null && hasAnyPosition;
3761
+ return {
3762
+ totalSuppliedUsd: sUsd,
3763
+ totalBorrowedUsd: bUsd,
3764
+ netAssetValueUsd: nav,
3765
+ partialPricing: platform != null && partialPricing,
3766
+ pricingUnavailable,
3767
+ error: null
3768
+ };
3769
+ } catch (e) {
3770
+ return {
3771
+ ...empty,
3772
+ error: e instanceof Error ? e.message : "Could not load portfolio."
3773
+ };
3774
+ }
3775
+ }
3776
+
3777
+ // src/protocols/evm/euler-v2/loadEulerV2SupportedChainIds.ts
3778
+ var cached = null;
3779
+ function loadEulerV2SupportedChainIds() {
3780
+ if (cached) return Promise.resolve(cached);
3781
+ cached = new Set(Object.keys(EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID).map((k) => Number(k)));
3782
+ return Promise.resolve(cached);
2214
3783
  }
2215
3784
 
2216
3785
  // src/protocols/evm/euler-v2/index.ts
@@ -2235,13 +3804,20 @@ var eulerV2ProtocolModule = {
2235
3804
  };
2236
3805
  registerProtocolModule(eulerV2ProtocolModule);
2237
3806
 
3807
+ exports.EULER_EVAULT_CAP_UNLIMITED_WEI = EULER_EVAULT_CAP_UNLIMITED_WEI;
3808
+ exports.EULER_EVAULT_SUPPLY_CAP_UNLIMITED_WEI = EULER_EVAULT_SUPPLY_CAP_UNLIMITED_WEI;
3809
+ exports.EULER_REUL_UNLOCK_GAS_FALLBACK = EULER_REUL_UNLOCK_GAS_FALLBACK;
2238
3810
  exports.EULER_SAME_ASSET_BORROW_APPROVAL_BUFFER_BPS = EULER_SAME_ASSET_BORROW_APPROVAL_BUFFER_BPS;
2239
3811
  exports.EULER_SAME_ASSET_BORROW_MAX_ROUNDS = EULER_SAME_ASSET_BORROW_MAX_ROUNDS;
2240
3812
  exports.EULER_SAME_ASSET_BORROW_PROTOCOL_HEADROOM_BPS = EULER_SAME_ASSET_BORROW_PROTOCOL_HEADROOM_BPS;
2241
3813
  exports.EULER_SAME_ASSET_BORROW_RATIO_STOP_EPS_BPS = EULER_SAME_ASSET_BORROW_RATIO_STOP_EPS_BPS;
3814
+ exports.EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID = EULER_V2_GOLDSKY_SUBGRAPH_URL_BY_CHAIN_ID;
2242
3815
  exports.EULER_V2_ISOLATED_VAULT_DEPOSIT_FALLBACK_GAS = EULER_V2_ISOLATED_VAULT_DEPOSIT_FALLBACK_GAS;
3816
+ exports.EULER_V2_PREFER_ON_CHAIN_LEND_METRICS = EULER_V2_PREFER_ON_CHAIN_LEND_METRICS;
2243
3817
  exports.EULER_V2_PROTOCOL_ID = EULER_V2_PROTOCOL_ID;
2244
3818
  exports.EULER_V2_VAULT_WITHDRAW_FALLBACK_GAS = EULER_V2_VAULT_WITHDRAW_FALLBACK_GAS;
3819
+ exports.REUL_FULL_VEST_SEC = REUL_FULL_VEST_SEC;
3820
+ exports.REUL_LOCK_DAY_SEC = REUL_LOCK_DAY_SEC;
2245
3821
  exports.buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch = buildEvmMultisignBodyEulerV2BorrowCollateralDepositBatch;
2246
3822
  exports.buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch = buildEvmMultisignBodyEulerV2BorrowCollateralWithdrawBatch;
2247
3823
  exports.buildEvmMultisignBodyEulerV2BorrowRepayBatch = buildEvmMultisignBodyEulerV2BorrowRepayBatch;
@@ -2249,15 +3825,58 @@ exports.buildEvmMultisignBodyEulerV2IsolatedBorrowBatch = buildEvmMultisignBodyE
2249
3825
  exports.buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch = buildEvmMultisignBodyEulerV2IsolatedLendDepositBatch;
2250
3826
  exports.buildEvmMultisignBodyEulerV2VaultWithdraw = buildEvmMultisignBodyEulerV2VaultWithdraw;
2251
3827
  exports.clampEulerUnderlyingDecimalsForEulerUi = clampEulerUnderlyingDecimalsForEulerUi;
3828
+ exports.encodeEulerReulWithdrawToByLockTimestampsData = encodeEulerReulWithdrawToByLockTimestampsData;
3829
+ exports.ensureEulerV2ChainAssetCache = ensureEulerV2ChainAssetCache;
3830
+ exports.estimateBorrowHumanFromLtv = estimateBorrowHumanFromLtv;
2252
3831
  exports.eulerBorrowAndCollateralSameAsset = eulerBorrowAndCollateralSameAsset;
3832
+ exports.eulerLabelsAppendUnderlyingIfDistinct = eulerLabelsAppendUnderlyingIfDistinct;
3833
+ exports.eulerLabelsLookupLabelForVault = eulerLabelsLookupLabelForVault;
3834
+ exports.eulerReulUnlockAbi = eulerReulUnlockAbi;
2253
3835
  exports.eulerSameAssetApproveAmountWithBuffer = eulerSameAssetApproveAmountWithBuffer;
2254
3836
  exports.eulerSameAssetTotalCollateralPullWei = eulerSameAssetTotalCollateralPullWei;
3837
+ exports.eulerSubgraphVaultCapToUnderlyingWei = eulerSubgraphVaultCapToUnderlyingWei;
3838
+ exports.eulerV2GoldskyUrlForChain = eulerV2GoldskyUrlForChain;
3839
+ exports.eulerV2KeyForNodeAssetRow = eulerV2KeyForNodeAssetRow;
2255
3840
  exports.eulerV2ProtocolModule = eulerV2ProtocolModule;
3841
+ exports.eulerV2QueryGraphQl = eulerV2QueryGraphQl;
3842
+ exports.eulerVaultLendMetricsFromIndexerVaultState = eulerVaultLendMetricsFromIndexerVaultState;
3843
+ exports.eulerVaultMaxNewBorrowWei = eulerVaultMaxNewBorrowWei;
3844
+ exports.eulerVaultMaxNewSupplyWei = eulerVaultMaxNewSupplyWei;
3845
+ exports.eulerWrappedGasTokenAliasesLower = eulerWrappedGasTokenAliasesLower;
3846
+ exports.fetchCoingeckoTokenUsdByContract = fetchCoingeckoTokenUsdByContract;
2256
3847
  exports.fetchEulerBorrowCollateralMaxWithdrawAssetsWei = fetchEulerBorrowCollateralMaxWithdrawAssetsWei;
3848
+ exports.fetchEulerLabelsEarnVaultAllowlist = fetchEulerLabelsEarnVaultAllowlist;
3849
+ exports.fetchEulerLabelsEntityNameByAddress = fetchEulerLabelsEntityNameByAddress;
3850
+ exports.fetchEulerLabelsVaultNameMap = fetchEulerLabelsVaultNameMap;
2257
3851
  exports.fetchEulerLendEarnVaultEffectiveMaxWithdrawWei = fetchEulerLendEarnVaultEffectiveMaxWithdrawWei;
3852
+ exports.fetchEulerReulVestingTranches = fetchEulerReulVestingTranches;
3853
+ exports.fetchEulerV2BorrowDebtWei = fetchEulerV2BorrowDebtWei;
3854
+ exports.fetchEulerV2BorrowOracleQuoteSnapshot = fetchEulerV2BorrowOracleQuoteSnapshot;
3855
+ exports.fetchEulerV2BorrowPairLtvs = fetchEulerV2BorrowPairLtvs;
3856
+ exports.fetchEulerV2ChainAssetCache = fetchEulerV2ChainAssetCache;
3857
+ exports.fetchEulerV2EarnOfferingsForRowAsset = fetchEulerV2EarnOfferingsForRowAsset;
3858
+ exports.fetchEulerV2IsolatedLendMarketsForRowAsset = fetchEulerV2IsolatedLendMarketsForRowAsset;
3859
+ exports.fetchEulerV2TrackingBorrowEntries = fetchEulerV2TrackingBorrowEntries;
3860
+ exports.fetchEulerV2TrackingDepositEntries = fetchEulerV2TrackingDepositEntries;
2258
3861
  exports.fetchEulerVaultAssetDecimals = fetchEulerVaultAssetDecimals;
2259
3862
  exports.fetchEulerVaultMaxWithdrawWei = fetchEulerVaultMaxWithdrawWei;
3863
+ exports.fetchEulerVaultOnChainLendMetrics = fetchEulerVaultOnChainLendMetrics;
3864
+ exports.fetchEulerVaultOnChainLendMetricsForVaults = fetchEulerVaultOnChainLendMetricsForVaults;
2260
3865
  exports.fetchEulerVaultUnderlyingMeta = fetchEulerVaultUnderlyingMeta;
3866
+ exports.flattenEulerV2BorrowCollateralRows = flattenEulerV2BorrowCollateralRows;
3867
+ exports.formatEulerRayApyPercent = formatEulerRayApyPercent;
3868
+ exports.formatEulerRaySupplyApyPercent = formatEulerRaySupplyApyPercent;
3869
+ exports.formatEulerResolvedCapOrCashForUi = formatEulerResolvedCapOrCashForUi;
3870
+ exports.loadEulerV2BorrowPositionsForOwner = loadEulerV2BorrowPositionsForOwner;
3871
+ exports.loadEulerV2LendSupplyPositionsForOwner = loadEulerV2LendSupplyPositionsForOwner;
3872
+ exports.loadEulerV2PortfolioUsdSnapshot = loadEulerV2PortfolioUsdSnapshot;
3873
+ exports.loadEulerV2SupportedChainIds = loadEulerV2SupportedChainIds;
3874
+ exports.maxCollateralWeiCappedByBorrowLiquidity = maxCollateralWeiCappedByBorrowLiquidity;
3875
+ exports.mergeEulerV2PositionsTabRows = mergeEulerV2PositionsTabRows;
3876
+ exports.parseEulerTrackingBorrowEntry = parseEulerTrackingBorrowEntry;
2261
3877
  exports.planSameAssetLeveragedBorrows = planSameAssetLeveragedBorrows;
3878
+ exports.resolveEulerAmountCapToSupplyWei = resolveEulerAmountCapToSupplyWei;
3879
+ exports.resolveEulerAmountCapToWei = resolveEulerAmountCapToWei;
3880
+ exports.resolveEulerWrappedNativeToken = resolveEulerWrappedNativeToken;
2262
3881
  //# sourceMappingURL=index.cjs.map
2263
3882
  //# sourceMappingURL=index.cjs.map