@continuumdao/ctm-mpc-defi 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +563 -5
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +166 -20
  5. package/dist/agent/catalog.js +551 -7
  6. package/dist/agent/catalog.js.map +1 -1
  7. package/dist/agent/skills/aave-v4/SKILL.md +43 -0
  8. package/dist/agent/skills/curve-dao/SKILL.md +13 -0
  9. package/dist/agent/skills/ethena/SKILL.md +10 -0
  10. package/dist/agent/skills/euler-v2/SKILL.md +10 -0
  11. package/dist/agent/skills/lido/SKILL.md +22 -0
  12. package/dist/agent/skills/maple-syrup/SKILL.md +10 -0
  13. package/dist/agent/skills/sky/SKILL.md +10 -0
  14. package/dist/agent/skills/uniswap-v4/SKILL.md +22 -0
  15. package/dist/chains/evm/index.cjs +79 -224
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +26 -26
  18. package/dist/chains/evm/index.js +69 -209
  19. package/dist/chains/evm/index.js.map +1 -1
  20. package/dist/chains/near/index.d.ts +1 -1
  21. package/dist/chains/solana/index.d.ts +1 -1
  22. package/dist/core/index.cjs +68 -106
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.ts +21 -36
  25. package/dist/core/index.js +57 -96
  26. package/dist/core/index.js.map +1 -1
  27. package/dist/{envelope-CcE5Cz_q.d.ts → envelope-CpBUh9eP.d.ts} +1 -1
  28. package/dist/index.cjs +356 -1855
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -11
  31. package/dist/index.js +332 -1826
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +1152 -669
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/aave-v4/index.d.ts +418 -3
  36. package/dist/protocols/evm/aave-v4/index.js +1126 -670
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  38. package/dist/protocols/evm/curve-dao/index.cjs +257 -131
  39. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  40. package/dist/protocols/evm/curve-dao/index.d.ts +69 -5
  41. package/dist/protocols/evm/curve-dao/index.js +242 -124
  42. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  43. package/dist/protocols/evm/ethena/index.cjs +394 -402
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  45. package/dist/protocols/evm/ethena/index.d.ts +47 -3
  46. package/dist/protocols/evm/ethena/index.js +390 -404
  47. package/dist/protocols/evm/ethena/index.js.map +1 -1
  48. package/dist/protocols/evm/euler-v2/index.cjs +2810 -1191
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  50. package/dist/protocols/evm/euler-v2/index.d.ts +465 -3
  51. package/dist/protocols/evm/euler-v2/index.js +2761 -1192
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  53. package/dist/protocols/evm/lido/index.cjs +351 -236
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  55. package/dist/protocols/evm/lido/index.d.ts +34 -4
  56. package/dist/protocols/evm/lido/index.js +348 -238
  57. package/dist/protocols/evm/lido/index.js.map +1 -1
  58. package/dist/protocols/evm/maple/index.cjs +390 -395
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  60. package/dist/protocols/evm/maple/index.d.ts +23 -3
  61. package/dist/protocols/evm/maple/index.js +390 -397
  62. package/dist/protocols/evm/maple/index.js.map +1 -1
  63. package/dist/protocols/evm/sky/index.cjs +454 -232
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  65. package/dist/protocols/evm/sky/index.d.ts +57 -3
  66. package/dist/protocols/evm/sky/index.js +444 -231
  67. package/dist/protocols/evm/sky/index.js.map +1 -1
  68. package/dist/protocols/evm/uniswap-v4/index.cjs +423 -658
  69. package/dist/protocols/evm/uniswap-v4/index.cjs.map +1 -1
  70. package/dist/protocols/evm/uniswap-v4/index.d.ts +3 -4
  71. package/dist/protocols/evm/uniswap-v4/index.js +422 -657
  72. package/dist/protocols/evm/uniswap-v4/index.js.map +1 -1
  73. package/dist/{registry-oMKlO_5z.d.ts → registry-Bv5o37_w.d.ts} +1 -1
  74. package/dist/{types-Ce2qNHai.d.cts → types-BfjWdw1j.d.ts} +3 -1
  75. package/dist/{types-5u863Fd9.d.ts → types-DUeNJLr9.d.ts} +1 -1
  76. package/package.json +7 -6
  77. package/dist/agent/catalog.d.cts +0 -939
  78. package/dist/chains/evm/index.d.cts +0 -64
  79. package/dist/chains/near/index.d.cts +0 -37
  80. package/dist/chains/solana/index.d.cts +0 -40
  81. package/dist/core/index.d.cts +0 -43
  82. package/dist/envelope-DYDPnrHZ.d.cts +0 -35
  83. package/dist/index.d.cts +0 -16
  84. package/dist/keygen-CfNp8yKJ.d.cts +0 -9
  85. package/dist/keygen-DsINazx8.d.ts +0 -9
  86. package/dist/nodeRead-BnmSaMGO.d.cts +0 -8
  87. package/dist/nodeRead-BnmSaMGO.d.ts +0 -8
  88. package/dist/protocols/evm/aave-v4/index.d.cts +0 -500
  89. package/dist/protocols/evm/curve-dao/index.d.cts +0 -147
  90. package/dist/protocols/evm/ethena/index.d.cts +0 -161
  91. package/dist/protocols/evm/euler-v2/index.d.cts +0 -317
  92. package/dist/protocols/evm/lido/index.d.cts +0 -120
  93. package/dist/protocols/evm/maple/index.d.cts +0 -109
  94. package/dist/protocols/evm/sky/index.d.cts +0 -218
  95. package/dist/protocols/evm/uniswap-v4/index.d.cts +0 -324
  96. package/dist/registry-BwZoE668.d.cts +0 -8
  97. package/dist/txParams-BC7ogvdR.d.cts +0 -19
  98. package/dist/txParams-BC7ogvdR.d.ts +0 -19
  99. package/dist/types-B8idm_gu.d.cts +0 -34
  100. package/dist/types-Ce2qNHai.d.ts +0 -57
@@ -1,4 +1,5 @@
1
- import { parseAbi, isAddress, getAddress, defineChain, createPublicClient, http, parseUnits, encodeFunctionData, parseGwei, serializeTransaction, keccak256, formatUnits } from 'viem';
1
+ import { parseAbi, isAddress, getAddress, defineChain, createPublicClient, http, parseUnits, encodeFunctionData, formatUnits, zeroAddress, parseGwei, serializeTransaction, keccak256 } from 'viem';
2
+ import { isValidRpcUrl, fetchChainFeeParams, gasLimitFromEstimateAndChainConfig, gweiToDecimalString, proposalTxParamsToFeeSnapshot, alignEip1559FeesWithLatestBase, getClientIdFromKeyGenResult } from '@continuumdao/continuum-node-sdk';
2
3
 
3
4
  // src/core/registry.ts
4
5
  var modules = [];
@@ -10,18 +11,26 @@ function registerProtocolModule(mod) {
10
11
  modules.push(mod);
11
12
  }
12
13
  }
13
- var AAVE_V4_GRAPHQL_URL = "https://api.v4.aave.com/graphql";
14
- async function aaveV4Gql(query, variables) {
15
- const r = await fetch(AAVE_V4_GRAPHQL_URL, {
14
+ async function postJsonViaOptionalProxy(args) {
15
+ const r = await fetch(args.directUrl, {
16
16
  method: "POST",
17
17
  headers: { "content-type": "application/json" },
18
- body: JSON.stringify({ query, variables: variables ?? {} })
18
+ body: JSON.stringify(args.body)
19
19
  });
20
20
  if (!r.ok) {
21
21
  const t = await r.text().catch(() => "");
22
- throw new Error(t ? `Aave V4 API HTTP ${r.status}: ${t.slice(0, 200)}` : `Aave V4 API HTTP ${r.status}`);
22
+ throw new Error(t ? `HTTP ${r.status}: ${t.slice(0, 200)}` : `HTTP ${r.status}`);
23
23
  }
24
- const j = await r.json();
24
+ return await r.json();
25
+ }
26
+
27
+ // src/protocols/evm/aave-v4/api.ts
28
+ var AAVE_V4_GRAPHQL_URL = "https://api.v4.aave.com/graphql";
29
+ async function aaveV4Gql(query, variables) {
30
+ const body = { query, variables: variables ?? {} };
31
+ const j = await postJsonViaOptionalProxy({
32
+ directUrl: AAVE_V4_GRAPHQL_URL,
33
+ body});
25
34
  if (j.errors?.length) {
26
35
  const msg = j.errors.map((e) => e.message ?? "Unknown").join("; ");
27
36
  throw new Error(msg);
@@ -560,20 +569,6 @@ function buildAaveV4BorrowTableRowsFromHub(borrowable, hubReserves, debtByUnderl
560
569
  };
561
570
  });
562
571
  }
563
-
564
- // src/chains/evm/rpcUrl.ts
565
- function isValidRpcUrl(url) {
566
- const t = url.trim();
567
- if (!t) return false;
568
- try {
569
- const u = new URL(t);
570
- return u.protocol === "http:" || u.protocol === "https:";
571
- } catch {
572
- return false;
573
- }
574
- }
575
-
576
- // src/protocols/evm/aave-v4/spokeOnChain.ts
577
572
  var spokeStaticAbi = [
578
573
  {
579
574
  name: "getReserveCount",
@@ -682,87 +677,234 @@ async function fetchAaveV4SpokeReserveStatusForUnderlying(args) {
682
677
  };
683
678
  }
684
679
 
685
- // src/core/keygen.ts
686
- function firstClientIdFromKeyGen(data) {
687
- const map = data?.ClientKeys;
688
- if (!map || typeof map !== "object") return null;
689
- for (const v of Object.values(map)) {
690
- if (typeof v === "string" && v.trim()) return v.trim();
680
+ // src/core/purpose.ts
681
+ function mergePurposeText(purposeText, purposeSuffix) {
682
+ const t = purposeText.trim();
683
+ const suffix = (purposeSuffix ?? "").trim();
684
+ if (!suffix) return t;
685
+ return t ? `${t}
686
+
687
+ ${suffix}` : suffix;
688
+ }
689
+
690
+ // src/core/envelope.ts
691
+ function finalizeMultisign(input) {
692
+ const { keyGen, destinationChainID, legs } = input;
693
+ if (legs.length === 0) {
694
+ throw new Error("finalizeMultisign requires at least one leg");
691
695
  }
692
- return null;
696
+ const ph = (keyGen.pubkeyhex ?? "").trim();
697
+ if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
698
+ const keyList = keyGen.keylist ?? [];
699
+ const clientId = getClientIdFromKeyGenResult(keyGen);
700
+ const first = legs[0];
701
+ const messageHashes = legs.map((l) => l.msgHash);
702
+ const messageRawBatch = legs.map((l) => l.msgRaw);
703
+ const batchMeta = legs.map((l) => ({
704
+ destinationAddress: l.destinationAddress,
705
+ signatureText: l.signatureText,
706
+ ...l.audit
707
+ }));
708
+ const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
709
+ const extraPayload = {
710
+ batchMeta,
711
+ ...input.extraJSON ?? {}
712
+ };
713
+ const extraJSON = JSON.stringify(extraPayload);
714
+ const bodyForSign = {
715
+ keyList,
716
+ pubKey: ph,
717
+ msgHash: messageHashes[0],
718
+ msgRaw: first.msgRaw,
719
+ destinationChainID,
720
+ destinationAddress: input.destinationAddress ?? first.destinationAddress,
721
+ extraJSON,
722
+ signatureText: first.signatureText,
723
+ purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
724
+ ...first.feeSnapshot
725
+ };
726
+ if (legs.length > 1) {
727
+ bodyForSign.messageHashes = messageHashes;
728
+ bodyForSign.messageRawBatch = messageRawBatch;
729
+ }
730
+ if (proposalTxParams.length > 0) {
731
+ bodyForSign.proposalTxParams = proposalTxParams;
732
+ }
733
+ const valueWei = first.valueWei;
734
+ if (valueWei != null && valueWei > 0n) {
735
+ bodyForSign.value = valueWei.toString();
736
+ }
737
+ if (clientId) bodyForSign.clientId = clientId;
738
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
739
+ }
740
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
741
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
742
+ return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
743
+ }
744
+ return (estimatedGas * 12n + 9n) / 10n;
693
745
  }
694
746
 
695
- // src/chains/evm/txParams.ts
696
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
697
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
698
- return estimatedGas;
699
- }
700
- const cfg = BigInt(Math.floor(chainGasLimit));
701
- return cfg > estimatedGas ? cfg : estimatedGas;
702
- }
703
- async function fetchChainFeeParams(rpcUrl, chainId) {
704
- const url = rpcUrl.trim();
705
- if (!url) return { isEip1559: false };
706
- const chainIdNum = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
707
- if (Number.isNaN(chainIdNum)) return { isEip1559: false };
708
- const chain = defineChain({
709
- id: chainIdNum,
710
- name: "Discovery",
747
+ // src/chains/evm/buildBatch.ts
748
+ async function buildEvmMultisignBatch(args) {
749
+ const { context, steps } = args;
750
+ const {
751
+ chainId,
752
+ rpcUrl,
753
+ executorAddress,
754
+ chainDetail,
755
+ useCustomGas,
756
+ customGasChainDetails,
757
+ keyGen,
758
+ purposeText
759
+ } = context;
760
+ if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
761
+ const ch = defineChain({
762
+ id: chainId,
763
+ name: "Destination",
711
764
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
712
- rpcUrls: { default: { http: [url] } }
713
- });
714
- const publicClient = createPublicClient({
715
- chain,
716
- transport: http(url)
765
+ rpcUrls: { default: { http: [rpcUrl] } }
717
766
  });
718
- const getGasPriceGwei = async () => {
719
- const gasPriceWei = await publicClient.getGasPrice();
720
- return parseFloat(formatUnits(gasPriceWei, 9));
721
- };
722
- try {
723
- const block = await publicClient.getBlock({ blockTag: "latest" });
724
- const baseFeePerGas = block?.baseFeePerGas;
725
- if (baseFeePerGas == null || baseFeePerGas === void 0) {
726
- const gasPriceGwei2 = await getGasPriceGwei();
727
- return { isEip1559: false, gasPriceGwei: gasPriceGwei2 };
767
+ const publicClient = createPublicClient({ chain: ch, transport: http(rpcUrl) });
768
+ const feeParams = await fetchChainFeeParams(rpcUrl, chainId);
769
+ const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
770
+ const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
771
+ const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
772
+ const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
773
+ const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
774
+ const executor = getAddress(executorAddress);
775
+ const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
776
+ const legs = [];
777
+ for (let i = 0; i < steps.length; i++) {
778
+ const step = steps[i];
779
+ const currentNonce = baseNonce + i;
780
+ let estimatedGas;
781
+ if (args.estimateGasForStep) {
782
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
783
+ } else {
784
+ try {
785
+ estimatedGas = await publicClient.estimateGas({
786
+ to: step.to,
787
+ data: step.data,
788
+ value: step.value,
789
+ account: executor
790
+ });
791
+ } catch {
792
+ estimatedGas = step.fallbackGas ?? 100000n;
793
+ }
728
794
  }
729
- const baseFeeGwei = parseFloat(formatUnits(baseFeePerGas, 9));
730
- let priorityFeeGwei;
731
- try {
732
- const priorityWei = await publicClient.estimateMaxPriorityFeePerGas();
733
- priorityFeeGwei = parseFloat(formatUnits(priorityWei, 9));
734
- } catch {
795
+ let gasLimitI;
796
+ if (args.resolveGasLimit) {
797
+ gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient });
798
+ } else if (step.routerSwap) {
799
+ gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
800
+ } else {
801
+ gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
735
802
  }
736
- const gasPriceGwei = await getGasPriceGwei();
737
- return {
738
- isEip1559: true,
739
- baseFeeGwei,
740
- priorityFeeGwei,
741
- gasPriceGwei
742
- };
743
- } catch {
744
- try {
745
- const gasPriceWei = await publicClient.getGasPrice();
746
- const gasPriceGwei = parseFloat(formatUnits(gasPriceWei, 9));
747
- return { isEip1559: false, gasPriceGwei };
748
- } catch {
749
- return { isEip1559: false };
803
+ let proposalTxParams;
804
+ let feeSnapshot;
805
+ let serialized;
806
+ if (legacy) {
807
+ let gasPriceWei = await publicClient.getGasPrice();
808
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
809
+ gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
810
+ }
811
+ if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
812
+ const configured = parseGwei(gweiToDecimalString(Number(chainDetail.gasPrice)));
813
+ if (configured > gasPriceWei) gasPriceWei = configured;
814
+ }
815
+ serialized = serializeTransaction({
816
+ type: "legacy",
817
+ to: step.to,
818
+ data: step.data,
819
+ value: step.value,
820
+ gas: gasLimitI,
821
+ gasPrice: gasPriceWei,
822
+ nonce: currentNonce,
823
+ chainId
824
+ });
825
+ proposalTxParams = {
826
+ nonce: currentNonce,
827
+ gasLimit: gasLimitI.toString(),
828
+ txType: "legacy",
829
+ gasPrice: gasPriceWei.toString()
830
+ };
831
+ feeSnapshot = proposalTxParamsToFeeSnapshot(proposalTxParams);
832
+ } else {
833
+ const fetchedBase = feeParams.baseFeeGwei ?? 0;
834
+ const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
835
+ const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
836
+ const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
837
+ const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
838
+ const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
839
+ const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
840
+ const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
841
+ const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
842
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
843
+ let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
844
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
845
+ maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
846
+ maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
847
+ }
848
+ ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
849
+ maxFeePerGas,
850
+ maxPriorityFeePerGas,
851
+ latestBaseFeeWei
852
+ ));
853
+ serialized = serializeTransaction({
854
+ type: "eip1559",
855
+ to: step.to,
856
+ data: step.data,
857
+ value: step.value,
858
+ gas: gasLimitI,
859
+ maxFeePerGas,
860
+ maxPriorityFeePerGas,
861
+ nonce: currentNonce,
862
+ chainId
863
+ });
864
+ proposalTxParams = {
865
+ nonce: currentNonce,
866
+ gasLimit: gasLimitI.toString(),
867
+ txType: "eip1559",
868
+ maxFeePerGas: maxFeePerGas.toString(),
869
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
870
+ };
871
+ feeSnapshot = i === 0 ? proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
872
+ }
873
+ const h = keccak256(serialized);
874
+ const msgHash = h.startsWith("0x") ? h.slice(2) : h;
875
+ const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
876
+ legs.push({
877
+ msgHash,
878
+ msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
879
+ destinationAddress: step.to,
880
+ signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
881
+ audit: batchMetaExtra,
882
+ feeSnapshot: i === 0 ? feeSnapshot : {},
883
+ proposalTxParams,
884
+ valueWei: i === 0 ? step.value : void 0
885
+ });
886
+ if (i === 0 && args.firstMsgRawNo0x != null) {
887
+ legs[0].msgRaw = args.firstMsgRawNo0x;
750
888
  }
751
889
  }
752
- }
753
- function finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, floor, baseWei) {
754
- let maxP = maxPriorityFeePerGas;
755
- let maxF = maxFeePerGas;
756
- if (baseWei > 0n && maxF < baseWei + maxP) {
757
- maxF = baseWei + maxP + parseGwei("0.001");
890
+ const extraJSON = {};
891
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
892
+ extraJSON.customGasChainDetails = customGasChainDetails;
758
893
  }
759
- if (maxF < maxP) {
760
- maxF = baseWei > 0n ? baseWei + maxP + parseGwei("0.001") : maxP * 2n;
894
+ const result = finalizeMultisign({
895
+ keyGen,
896
+ purposeText,
897
+ purposeSuffix: args.purposeSuffix,
898
+ destinationChainID: String(chainId),
899
+ destinationAddress: args.destinationAddress ?? steps[0].to,
900
+ legs,
901
+ extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
902
+ });
903
+ const pv = args.payableValueWei;
904
+ if (pv != null && pv > 0n) {
905
+ result.bodyForSign.value = pv.toString();
761
906
  }
762
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
763
- }
764
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
765
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
907
+ return result;
766
908
  }
767
909
 
768
910
  // src/protocols/evm/aave-v4/multisign.ts
@@ -779,16 +921,6 @@ var AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS = 1000000n;
779
921
  var AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK = AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS;
780
922
  var AAVE_MERKL_CLAIM_ESTIMATE_FALLBACK = 500000n;
781
923
  var EULER_REUL_UNLOCK_ESTIMATE_FALLBACK = 500000n;
782
- function gweiToDecimalString(n) {
783
- if (!Number.isFinite(n)) return "0";
784
- if (n === 0) return "0";
785
- const s = String(n);
786
- if (s.indexOf("e") !== -1 || s.indexOf("E") !== -1) return n.toFixed(9).replace(/\.?0+$/, "") || "0";
787
- return s;
788
- }
789
- function txToViemStep(tx) {
790
- return { to: getAddress(tx.to), data: tx.data, value: tx.value };
791
- }
792
924
  var wethDepositAbi = parseAbi(["function deposit() payable"]);
793
925
  var erc20AllowanceAbi = parseAbi([
794
926
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -803,10 +935,6 @@ var spokeSetUsingAsCollateralAbi = parseAbi([
803
935
  "function setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)"
804
936
  ]);
805
937
  async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
806
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
807
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
808
- const keyList = args.keyGen.keylist ?? [];
809
- const clientId = firstClientIdFromKeyGen(args.keyGen);
810
938
  const asset = getAddress(args.asset);
811
939
  const spoke = getAddress(args.spoke);
812
940
  const weth = getAddress(args.nativeWrapped);
@@ -904,172 +1032,102 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
904
1032
  });
905
1033
  steps.push({ kind: "set_collateral", to: spoke, data: setCollateralData, value: 0n });
906
1034
  }
907
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
908
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
909
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
910
- const useCustomGas = args.useCustomGas;
911
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
912
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
913
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
914
- const messageHashes = [];
915
- const messageRawBatch = [];
916
- const proposalTxParamsBatch = [];
917
- const batchMeta = [];
918
- let firstTxFeePayload = {};
919
- let firstDataNo0x = "";
920
1035
  const marketLabel = String(args.market);
921
- for (let i = 0; i < steps.length; i++) {
922
- const s = steps[i];
923
- const v = txToViemStep(s);
924
- const currentNonce = baseNonce + i;
925
- let estimatedGas;
926
- try {
927
- estimatedGas = await publicClient.estimateGas({
928
- to: v.to,
929
- data: v.data,
930
- value: v.value,
931
- account: executor
932
- });
933
- } catch {
934
- if (s.kind === "weth_deposit") estimatedGas = AAVE_WETH_DEPOSIT_FALLBACK;
935
- else if (s.kind === "approve") estimatedGas = AAVE_ERC20_APPROVE_FALLBACK;
936
- else if (s.kind === "set_collateral") estimatedGas = AAVE_SPOKE_SET_USING_AS_COLLATERAL_FALLBACK;
937
- else estimatedGas = AAVE_SPOKE_SUPPLY_ESTIMATE_FALLBACK;
1036
+ const evmSteps = steps.map((s) => ({
1037
+ to: s.to,
1038
+ data: s.data,
1039
+ value: s.value,
1040
+ fallbackGas: s.kind === "weth_deposit" ? AAVE_WETH_DEPOSIT_FALLBACK : s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : s.kind === "set_collateral" ? AAVE_SPOKE_SET_USING_AS_COLLATERAL_FALLBACK : AAVE_SPOKE_SUPPLY_ESTIMATE_FALLBACK
1041
+ }));
1042
+ const n = steps.length;
1043
+ const hasWrap = args.isNativeIn;
1044
+ const withCollateral = args.enableAsCollateralAfterSupply === true;
1045
+ const purposeSuffix = (() => {
1046
+ if (hasWrap) {
1047
+ return withCollateral ? `Aave v4: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve spoke for the exact amount, supply, then setUsingAsCollateral.` : `Aave v4: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve spoke for the exact amount, then supply.`;
938
1048
  }
939
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
940
- if (legacy) {
941
- let gasPriceWei = await publicClient.getGasPrice();
942
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
943
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
944
- }
945
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
946
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
947
- if (configured > gasPriceWei) gasPriceWei = configured;
948
- }
949
- const ser = serializeTransaction({
950
- type: "legacy",
951
- to: v.to,
952
- data: v.data,
953
- value: v.value,
954
- gas: gasLimitI,
955
- gasPrice: gasPriceWei,
956
- nonce: currentNonce,
957
- chainId: args.chainId
958
- });
959
- const h = keccak256(ser);
960
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
961
- messageRawBatch.push(ser);
962
- proposalTxParamsBatch.push({
963
- nonce: currentNonce,
964
- gasLimit: gasLimitI.toString(),
965
- txType: "legacy",
966
- gasPrice: gasPriceWei.toString()
967
- });
968
- if (i === 0) {
969
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
970
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1049
+ if (n === 1) {
1050
+ return "Aave v4: 1-tx \u2014 supply (allowance already sufficient).";
1051
+ }
1052
+ if (withCollateral && n === 2) {
1053
+ return "Aave v4: 2-tx batch \u2014 supply (allowance already sufficient), then setUsingAsCollateral.";
1054
+ }
1055
+ if (withCollateral) {
1056
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, supply, then setUsingAsCollateral.`;
1057
+ }
1058
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, then supply.`;
1059
+ })();
1060
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1061
+ return buildEvmMultisignBatch({
1062
+ context: {
1063
+ chainCategory: "evm",
1064
+ keyGen: args.keyGen,
1065
+ purposeText: args.purposeText,
1066
+ chainId: args.chainId,
1067
+ rpcUrl: args.rpcUrl,
1068
+ executorAddress: executor,
1069
+ chainDetail: args.chainDetail,
1070
+ useCustomGas: args.useCustomGas,
1071
+ customGasChainDetails: args.customGasChainDetails
1072
+ },
1073
+ steps: evmSteps,
1074
+ purposeSuffix,
1075
+ firstMsgRawNo0x: firstDataNo0x,
1076
+ destinationAddress: steps[0].to,
1077
+ buildBatchMeta: ({ index, gasLimit }) => {
1078
+ const s = steps[index];
1079
+ if (s.kind === "weth_deposit") {
1080
+ return {
1081
+ signatureText: JSON.stringify({
1082
+ kind: "AaveV4",
1083
+ name: "WETH.deposit",
1084
+ function: "deposit()",
1085
+ valueWei: amountWei.toString(),
1086
+ market: marketLabel,
1087
+ note: "Wrap native to WETH, then supply to Aave v4 (same batch)."
1088
+ }),
1089
+ evm: { type: "aave_v4_weth_deposit", version: 1, chainId: String(args.chainId) },
1090
+ aaveV4: { step: "weth_deposit", market: marketLabel, amountHuman: args.amountHuman, hubAsset: asset }
1091
+ };
971
1092
  }
972
- } else {
973
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
974
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
975
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
976
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
977
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
978
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
979
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
980
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
981
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
982
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
983
- let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
984
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
985
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
986
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1093
+ if (s.kind === "approve") {
1094
+ return {
1095
+ signatureText: JSON.stringify({
1096
+ kind: "AaveV4",
1097
+ name: "ERC20.approve",
1098
+ to: "Aave v4 spoke",
1099
+ function: "approve(address spender, uint256 amount)",
1100
+ spoke,
1101
+ amountHuman: args.amountHuman,
1102
+ note: "Allowance for this supply amount only (not unlimited)."
1103
+ }),
1104
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1105
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke }
1106
+ };
987
1107
  }
988
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
989
- maxFeePerGas,
990
- maxPriorityFeePerGas,
991
- latestBaseFeeWei
992
- ));
993
- const ser = serializeTransaction({
994
- type: "eip1559",
995
- to: v.to,
996
- data: v.data,
997
- value: v.value,
998
- gas: gasLimitI,
999
- maxFeePerGas,
1000
- maxPriorityFeePerGas,
1001
- nonce: currentNonce,
1002
- chainId: args.chainId
1003
- });
1004
- const h = keccak256(ser);
1005
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1006
- messageRawBatch.push(ser);
1007
- proposalTxParamsBatch.push({
1008
- nonce: currentNonce,
1009
- gasLimit: gasLimitI.toString(),
1010
- txType: "eip1559",
1011
- maxFeePerGas: maxFeePerGas.toString(),
1012
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1013
- });
1014
- if (i === 0) {
1015
- firstTxFeePayload = {
1016
- txNonce: currentNonce,
1017
- txGasLimit: gasLimitI.toString(),
1018
- txMaxFeePerGas: maxFeePerGas.toString(),
1019
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1108
+ if (s.kind === "set_collateral") {
1109
+ return {
1110
+ signatureText: JSON.stringify({
1111
+ kind: "AaveV4",
1112
+ name: "Spoke.setUsingAsCollateral",
1113
+ function: "setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)",
1114
+ reserveId: reserveId.toString(),
1115
+ usingAsCollateral: true,
1116
+ onBehalfOf: onBehalf,
1117
+ market: marketLabel,
1118
+ note: "Enables this supplied reserve as collateral for borrowing (after supply in the same batch)."
1119
+ }),
1120
+ evm: { type: "aave_v4_spoke_set_using_as_collateral", version: 1, chainId: String(args.chainId) },
1121
+ aaveV4: {
1122
+ market: marketLabel,
1123
+ asset,
1124
+ spoke,
1125
+ reserveId: reserveId.toString(),
1126
+ gasBuildSetCollateral: { baseGasUnits: gasLimit.toString() }
1127
+ }
1020
1128
  };
1021
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1022
1129
  }
1023
- }
1024
- if (s.kind === "weth_deposit") {
1025
- batchMeta.push({
1026
- destinationAddress: weth,
1027
- signatureText: JSON.stringify({
1028
- kind: "AaveV4",
1029
- name: "WETH.deposit",
1030
- function: "deposit()",
1031
- valueWei: amountWei.toString(),
1032
- market: marketLabel,
1033
- note: "Wrap native to WETH, then supply to Aave v4 (same batch)."
1034
- }),
1035
- evm: { type: "aave_v4_weth_deposit", version: 1, chainId: String(args.chainId) },
1036
- aaveV4: { step: "weth_deposit", market: marketLabel, amountHuman: args.amountHuman, hubAsset: asset }
1037
- });
1038
- } else if (s.kind === "approve") {
1039
- const tokenForApprove = s.to;
1040
- batchMeta.push({
1041
- destinationAddress: tokenForApprove,
1042
- signatureText: JSON.stringify({
1043
- kind: "AaveV4",
1044
- name: "ERC20.approve",
1045
- to: "Aave v4 spoke",
1046
- function: "approve(address spender, uint256 amount)",
1047
- spoke,
1048
- amountHuman: args.amountHuman,
1049
- note: "Allowance for this supply amount only (not unlimited)."
1050
- }),
1051
- evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1052
- aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke }
1053
- });
1054
- } else if (s.kind === "set_collateral") {
1055
- batchMeta.push({
1056
- destinationAddress: spoke,
1057
- signatureText: JSON.stringify({
1058
- kind: "AaveV4",
1059
- name: "Spoke.setUsingAsCollateral",
1060
- function: "setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)",
1061
- reserveId: reserveId.toString(),
1062
- usingAsCollateral: true,
1063
- onBehalfOf: onBehalf,
1064
- market: marketLabel,
1065
- note: "Enables this supplied reserve as collateral for borrowing (after supply in the same batch)."
1066
- }),
1067
- evm: { type: "aave_v4_spoke_set_using_as_collateral", version: 1, chainId: String(args.chainId) },
1068
- aaveV4: { market: marketLabel, asset, spoke, reserveId: reserveId.toString(), gasBuildSetCollateral: { baseGasUnits: gasLimitI.toString() } }
1069
- });
1070
- } else {
1071
- batchMeta.push({
1072
- destinationAddress: spoke,
1130
+ return {
1073
1131
  signatureText: JSON.stringify({
1074
1132
  kind: "AaveV4",
1075
1133
  name: "Spoke.supply",
@@ -1087,67 +1145,13 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
1087
1145
  asset,
1088
1146
  spoke,
1089
1147
  reserveId: reserveId.toString(),
1090
- gasBuildSupply: { baseGasUnits: gasLimitI.toString() }
1148
+ gasBuildSupply: { baseGasUnits: gasLimit.toString() }
1091
1149
  }
1092
- });
1093
- }
1094
- }
1095
- const extraPayload = { batchMeta };
1096
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1097
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1098
- }
1099
- const extraJSON = JSON.stringify(extraPayload);
1100
- const firstSigText = batchMeta[0].signatureText;
1101
- const n = steps.length;
1102
- const hasWrap = args.isNativeIn;
1103
- const withCollateral = args.enableAsCollateralAfterSupply === true;
1104
- const purposeSuffix = (() => {
1105
- if (hasWrap) {
1106
- return withCollateral ? `Aave v4: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve spoke for the exact amount, supply, then setUsingAsCollateral.` : `Aave v4: ${n}-tx batch \u2014 wrap native to WETH (if needed), approve spoke for the exact amount, then supply.`;
1107
- }
1108
- if (n === 1) {
1109
- return "Aave v4: 1-tx \u2014 supply (allowance already sufficient).";
1110
- }
1111
- if (withCollateral && n === 2) {
1112
- return "Aave v4: 2-tx batch \u2014 supply (allowance already sufficient), then setUsingAsCollateral.";
1113
- }
1114
- if (withCollateral) {
1115
- return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, supply, then setUsingAsCollateral.`;
1150
+ };
1116
1151
  }
1117
- return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, then supply.`;
1118
- })();
1119
- const firstValue = steps[0].value;
1120
- const bodyForSign = {
1121
- keyList,
1122
- pubKey: ph,
1123
- msgHash: messageHashes[0],
1124
- msgRaw: firstDataNo0x,
1125
- messageHashes,
1126
- messageRawBatch,
1127
- destinationChainID: String(args.chainId),
1128
- destinationAddress: steps[0].to,
1129
- extraJSON,
1130
- signatureText: firstSigText,
1131
- purpose: (() => {
1132
- const t = args.purposeText.trim();
1133
- return (t ? `${t}
1134
-
1135
- ` : "") + purposeSuffix;
1136
- })(),
1137
- ...firstTxFeePayload,
1138
- proposalTxParams: proposalTxParamsBatch
1139
- };
1140
- if (firstValue > 0n) {
1141
- bodyForSign.value = firstValue.toString();
1142
- }
1143
- if (clientId) bodyForSign.clientId = clientId;
1144
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1152
+ });
1145
1153
  }
1146
1154
  async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1147
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1148
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1149
- const keyList = args.keyGen.keylist ?? [];
1150
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1151
1155
  const asset = getAddress(args.underlying);
1152
1156
  const spoke = getAddress(args.spoke);
1153
1157
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1188,9 +1192,7 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1188
1192
  });
1189
1193
  const tx = { to: spoke, data, value: 0n };
1190
1194
  return buildEvmMultisignBodyAaveV4OneStep({
1191
- ph,
1192
- keyList,
1193
- clientId: clientId ?? void 0,
1195
+ keyGen: args.keyGen,
1194
1196
  chainId: args.chainId,
1195
1197
  rpcUrl: args.rpcUrl,
1196
1198
  chainDetail: args.chainDetail,
@@ -1226,10 +1228,6 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1226
1228
  });
1227
1229
  }
1228
1230
  async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1229
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1230
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1231
- const keyList = args.keyGen.keylist ?? [];
1232
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1233
1231
  const asset = getAddress(args.underlying);
1234
1232
  const spoke = getAddress(args.spoke);
1235
1233
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1270,9 +1268,7 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1270
1268
  });
1271
1269
  const tx = { to: spoke, data, value: 0n };
1272
1270
  return buildEvmMultisignBodyAaveV4OneStep({
1273
- ph,
1274
- keyList,
1275
- clientId: clientId ?? void 0,
1271
+ keyGen: args.keyGen,
1276
1272
  chainId: args.chainId,
1277
1273
  rpcUrl: args.rpcUrl,
1278
1274
  chainDetail: args.chainDetail,
@@ -1308,10 +1304,6 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1308
1304
  });
1309
1305
  }
1310
1306
  async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1311
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1312
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1313
- const keyList = args.keyGen.keylist ?? [];
1314
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1315
1307
  const asset = getAddress(args.underlying);
1316
1308
  const spoke = getAddress(args.spoke);
1317
1309
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1374,140 +1366,50 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1374
1366
  args: [reserveId, amountWei, onBehalf]
1375
1367
  });
1376
1368
  steps.push({ kind: "repay", to: spoke, data: repayData, value: 0n });
1377
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1378
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1379
- const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1380
- const useCustom = args.useCustomGas;
1381
- const gasLimitConfig = useCustom && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1382
- const gasFeeMultiplier = useCustom && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1383
- const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
1384
- const messageHashes = [];
1385
- const messageRawBatch = [];
1386
- const proposalTxParamsBatch = [];
1387
- const batchMeta = [];
1388
- let firstTxFeePayload = {};
1389
- let firstDataNo0x = "";
1390
1369
  const marketLabel = String(args.market);
1391
- for (let i = 0; i < steps.length; i++) {
1392
- const s = steps[i];
1393
- const v = txToViemStep(s);
1394
- const currentNonce = baseNonce + i;
1395
- let estimatedGas;
1396
- try {
1397
- estimatedGas = await publicClient.estimateGas({
1398
- to: v.to,
1399
- data: v.data,
1400
- value: v.value,
1401
- account: executor
1402
- });
1403
- } catch {
1404
- if (s.kind === "approve") estimatedGas = AAVE_ERC20_APPROVE_FALLBACK;
1405
- else estimatedGas = AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK;
1406
- }
1407
- const gasLimitI = useCustom ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1408
- if (legacy) {
1409
- let gasPriceWei = await publicClient.getGasPrice();
1410
- if (useCustom && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1411
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1412
- }
1413
- if (useCustom && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1414
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1415
- if (configured > gasPriceWei) gasPriceWei = configured;
1416
- }
1417
- const ser = serializeTransaction({
1418
- type: "legacy",
1419
- to: v.to,
1420
- data: v.data,
1421
- value: v.value,
1422
- gas: gasLimitI,
1423
- gasPrice: gasPriceWei,
1424
- nonce: currentNonce,
1425
- chainId: args.chainId
1426
- });
1427
- const h = keccak256(ser);
1428
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1429
- messageRawBatch.push(ser);
1430
- proposalTxParamsBatch.push({
1431
- nonce: currentNonce,
1432
- gasLimit: gasLimitI.toString(),
1433
- txType: "legacy",
1434
- gasPrice: gasPriceWei.toString()
1435
- });
1436
- if (i === 0) {
1437
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
1438
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1439
- }
1440
- } else {
1441
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1442
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1443
- const configuredBase = useCustom && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1444
- const configuredPriority = useCustom && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1445
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1446
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1447
- const baseFeeMultiplierPct = useCustom && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1448
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1449
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1450
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
1451
- let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
1452
- if (useCustom && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1453
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1454
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1455
- }
1456
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1457
- maxFeePerGas,
1458
- maxPriorityFeePerGas,
1459
- latestBaseFeeWei
1460
- ));
1461
- const ser = serializeTransaction({
1462
- type: "eip1559",
1463
- to: v.to,
1464
- data: v.data,
1465
- value: v.value,
1466
- gas: gasLimitI,
1467
- maxFeePerGas,
1468
- maxPriorityFeePerGas,
1469
- nonce: currentNonce,
1470
- chainId: args.chainId
1471
- });
1472
- const h = keccak256(ser);
1473
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1474
- messageRawBatch.push(ser);
1475
- proposalTxParamsBatch.push({
1476
- nonce: currentNonce,
1477
- gasLimit: gasLimitI.toString(),
1478
- txType: "eip1559",
1479
- maxFeePerGas: maxFeePerGas.toString(),
1480
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1481
- });
1482
- if (i === 0) {
1483
- firstTxFeePayload = {
1484
- txNonce: currentNonce,
1485
- txGasLimit: gasLimitI.toString(),
1486
- txMaxFeePerGas: maxFeePerGas.toString(),
1487
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1370
+ const evmSteps = steps.map((s) => ({
1371
+ to: s.to,
1372
+ data: s.data,
1373
+ value: s.value,
1374
+ fallbackGas: s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK
1375
+ }));
1376
+ const n = steps.length;
1377
+ const purposeSuffix = `Aave v4: ${n}-tx batch \u2014 approve spoke if needed, then repay ${(args.amountHuman || "").trim() || "\u2026"} of debt.`;
1378
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1379
+ return buildEvmMultisignBatch({
1380
+ context: {
1381
+ chainCategory: "evm",
1382
+ keyGen: args.keyGen,
1383
+ purposeText: args.purposeText,
1384
+ chainId: args.chainId,
1385
+ rpcUrl: args.rpcUrl,
1386
+ executorAddress: executor,
1387
+ chainDetail: args.chainDetail,
1388
+ useCustomGas: args.useCustomGas,
1389
+ customGasChainDetails: args.customGasChainDetails
1390
+ },
1391
+ steps: evmSteps,
1392
+ purposeSuffix,
1393
+ firstMsgRawNo0x: firstDataNo0x,
1394
+ destinationAddress: steps[0].to,
1395
+ buildBatchMeta: ({ index, gasLimit }) => {
1396
+ const s = steps[index];
1397
+ if (s.kind === "approve") {
1398
+ return {
1399
+ signatureText: JSON.stringify({
1400
+ kind: "AaveV4",
1401
+ name: "ERC20.approve (repay)",
1402
+ to: "Aave v4 spoke",
1403
+ function: "approve(address spender, uint256 amount)",
1404
+ spoke,
1405
+ amountHuman: args.amountHuman,
1406
+ note: "Allowance to repay this amount (or reset+approve to exact amount)."
1407
+ }),
1408
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1409
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke, step: "repay_prepare" }
1488
1410
  };
1489
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1490
1411
  }
1491
- }
1492
- if (s.kind === "approve") {
1493
- const tokenForApprove = s.to;
1494
- batchMeta.push({
1495
- destinationAddress: tokenForApprove,
1496
- signatureText: JSON.stringify({
1497
- kind: "AaveV4",
1498
- name: "ERC20.approve (repay)",
1499
- to: "Aave v4 spoke",
1500
- function: "approve(address spender, uint256 amount)",
1501
- spoke,
1502
- amountHuman: args.amountHuman,
1503
- note: "Allowance to repay this amount (or reset+approve to exact amount)."
1504
- }),
1505
- evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1506
- aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke, step: "repay_prepare" }
1507
- });
1508
- } else {
1509
- batchMeta.push({
1510
- destinationAddress: spoke,
1412
+ return {
1511
1413
  signatureText: JSON.stringify({
1512
1414
  kind: "AaveV4",
1513
1415
  name: "Spoke.repay",
@@ -1525,57 +1427,17 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1525
1427
  asset,
1526
1428
  spoke,
1527
1429
  reserveId: reserveId.toString(),
1528
- gasBuildRepay: { baseGasUnits: gasLimitI.toString() }
1430
+ gasBuildRepay: { baseGasUnits: gasLimit.toString() }
1529
1431
  }
1530
- });
1432
+ };
1531
1433
  }
1532
- }
1533
- const extraPayload = { batchMeta };
1534
- if (useCustom && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1535
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1536
- }
1537
- const extraJSON = JSON.stringify(extraPayload);
1538
- const firstSigText = batchMeta[0].signatureText;
1539
- const n = steps.length;
1540
- const purposeSuffix = `Aave v4: ${n}-tx batch \u2014 approve spoke if needed, then repay ${(args.amountHuman || "").trim() || "\u2026"} of debt.`;
1541
- const firstValue = steps[0].value;
1542
- const bodyForSign = {
1543
- keyList,
1544
- pubKey: ph,
1545
- msgHash: messageHashes[0],
1546
- msgRaw: firstDataNo0x,
1547
- messageHashes,
1548
- messageRawBatch,
1549
- destinationChainID: String(args.chainId),
1550
- destinationAddress: steps[0].to,
1551
- extraJSON,
1552
- signatureText: firstSigText,
1553
- purpose: (() => {
1554
- const t = args.purposeText.trim();
1555
- return (t ? `${t}
1556
-
1557
- ` : "") + purposeSuffix;
1558
- })(),
1559
- ...firstTxFeePayload,
1560
- proposalTxParams: proposalTxParamsBatch
1561
- };
1562
- if (firstValue > 0n) {
1563
- bodyForSign.value = firstValue.toString();
1564
- }
1565
- if (clientId) bodyForSign.clientId = clientId;
1566
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1434
+ });
1567
1435
  }
1568
1436
  async function buildEvmMultisignBodyAaveV4MerklClaimRewards(args) {
1569
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1570
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1571
- const keyList = args.keyGen.keylist ?? [];
1572
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1573
1437
  const to = getAddress(args.to);
1574
1438
  const executor = getAddress(args.executorAddress);
1575
1439
  return buildEvmMultisignBodyAaveV4OneStep({
1576
- ph,
1577
- keyList,
1578
- clientId: clientId ?? void 0,
1440
+ keyGen: args.keyGen,
1579
1441
  chainId: args.chainId,
1580
1442
  rpcUrl: args.rpcUrl,
1581
1443
  chainDetail: args.chainDetail,
@@ -1602,16 +1464,10 @@ async function buildEvmMultisignBodyAaveV4MerklClaimRewards(args) {
1602
1464
  });
1603
1465
  }
1604
1466
  async function buildEvmMultisignBodyEulerV2MerklDistributorClaim(args) {
1605
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1606
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1607
- const keyList = args.keyGen.keylist ?? [];
1608
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1609
1467
  const to = getAddress(args.to);
1610
1468
  const executor = getAddress(args.executorAddress);
1611
1469
  return buildEvmMultisignBodyAaveV4OneStep({
1612
- ph,
1613
- keyList,
1614
- clientId: clientId ?? void 0,
1470
+ keyGen: args.keyGen,
1615
1471
  chainId: args.chainId,
1616
1472
  rpcUrl: args.rpcUrl,
1617
1473
  chainDetail: args.chainDetail,
@@ -1638,17 +1494,11 @@ async function buildEvmMultisignBodyEulerV2MerklDistributorClaim(args) {
1638
1494
  });
1639
1495
  }
1640
1496
  async function buildEvmMultisignBodyEulerV2ReulUnlock(args) {
1641
- const ph = (args.keyGen.pubkeyhex ?? "").trim();
1642
- if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
1643
- const keyList = args.keyGen.keylist ?? [];
1644
- const clientId = firstClientIdFromKeyGen(args.keyGen);
1645
1497
  const to = getAddress(args.to);
1646
1498
  const executor = getAddress(args.executorAddress);
1647
1499
  const lossLabel = args.allowRemainderLoss ? "early unlock (remainder to receiver)" : "vested only";
1648
1500
  return buildEvmMultisignBodyAaveV4OneStep({
1649
- ph,
1650
- keyList,
1651
- clientId: clientId ?? void 0,
1501
+ keyGen: args.keyGen,
1652
1502
  chainId: args.chainId,
1653
1503
  rpcUrl: args.rpcUrl,
1654
1504
  chainDetail: args.chainDetail,
@@ -1681,151 +1531,32 @@ async function buildEvmMultisignBodyEulerV2ReulUnlock(args) {
1681
1531
  });
1682
1532
  }
1683
1533
  async function buildEvmMultisignBodyAaveV4OneStep(args) {
1684
- const ch = defineChain({
1685
- id: args.chainId,
1686
- name: "Destination",
1687
- nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
1688
- rpcUrls: { default: { http: [args.rpcUrl] } }
1534
+ const firstDataNo0x = args.v.data.startsWith("0x") ? args.v.data.slice(2) : args.v.data;
1535
+ return buildEvmMultisignBatch({
1536
+ context: {
1537
+ chainCategory: "evm",
1538
+ keyGen: args.keyGen,
1539
+ purposeText: args.purposeText,
1540
+ chainId: args.chainId,
1541
+ rpcUrl: args.rpcUrl,
1542
+ executorAddress: args.executorAddress,
1543
+ chainDetail: args.chainDetail,
1544
+ useCustomGas: args.useCustomGas,
1545
+ customGasChainDetails: args.customGasChainDetails
1546
+ },
1547
+ steps: [
1548
+ {
1549
+ to: args.v.to,
1550
+ data: args.v.data,
1551
+ value: args.v.value,
1552
+ fallbackGas: args.estimateGasFallback
1553
+ }
1554
+ ],
1555
+ purposeSuffix: args.purposeSuffix,
1556
+ firstMsgRawNo0x: firstDataNo0x,
1557
+ destinationAddress: args.v.to,
1558
+ buildBatchMeta: ({ gasLimit }) => args.buildBatchMeta({ gasLimit })
1689
1559
  });
1690
- const publicClient = createPublicClient({ chain: ch, transport: http(args.rpcUrl) });
1691
- const v = args.v;
1692
- const feeParams = await fetchChainFeeParams(args.rpcUrl, args.chainId);
1693
- const legacy = Boolean(args.chainDetail?.legacy) || !feeParams.isEip1559;
1694
- const latestBaseFeeWeiOneStep = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
1695
- const useCustomGas = args.useCustomGas;
1696
- const gasLimitConfig = useCustomGas && args.chainDetail?.gasLimit != null ? Number(args.chainDetail.gasLimit) : void 0;
1697
- const gasFeeMultiplier = useCustomGas && args.chainDetail?.gasMultiplier != null ? Number(args.chainDetail.gasMultiplier) : void 0;
1698
- const baseNonce = await publicClient.getTransactionCount({ address: args.executorAddress, blockTag: "pending" });
1699
- const currentNonce = baseNonce;
1700
- let estimatedGas;
1701
- try {
1702
- estimatedGas = await publicClient.estimateGas({
1703
- to: v.to,
1704
- data: v.data,
1705
- value: v.value,
1706
- account: args.executorAddress
1707
- });
1708
- } catch {
1709
- estimatedGas = args.estimateGasFallback;
1710
- }
1711
- const gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
1712
- const batchMeta0 = args.buildBatchMeta({ gasLimit: gasLimitI });
1713
- let firstTxFeePayload = {};
1714
- let firstDataNo0x = "";
1715
- const messageHashes = [];
1716
- const messageRawBatch = [];
1717
- const proposalTxParamsBatch = [];
1718
- if (legacy) {
1719
- let gasPriceWei = await publicClient.getGasPrice();
1720
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1721
- gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
1722
- }
1723
- if (useCustomGas && args.chainDetail?.gasPrice != null && args.chainDetail.gasPrice > 0) {
1724
- const configured = parseGwei(gweiToDecimalString(Number(args.chainDetail.gasPrice)));
1725
- if (configured > gasPriceWei) gasPriceWei = configured;
1726
- }
1727
- const ser = serializeTransaction({
1728
- type: "legacy",
1729
- to: v.to,
1730
- data: v.data,
1731
- value: v.value,
1732
- gas: gasLimitI,
1733
- gasPrice: gasPriceWei,
1734
- nonce: currentNonce,
1735
- chainId: args.chainId
1736
- });
1737
- const h = keccak256(ser);
1738
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1739
- messageRawBatch.push(ser);
1740
- proposalTxParamsBatch.push({
1741
- nonce: currentNonce,
1742
- gasLimit: gasLimitI.toString(),
1743
- txType: "legacy",
1744
- gasPrice: gasPriceWei.toString()
1745
- });
1746
- firstTxFeePayload = { txNonce: currentNonce, txGasLimit: gasLimitI.toString(), txGasPrice: gasPriceWei.toString() };
1747
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1748
- } else {
1749
- const fetchedBase = feeParams.baseFeeGwei ?? 0;
1750
- const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
1751
- const configuredBase = useCustomGas && args.chainDetail?.baseFee != null ? Number(args.chainDetail.baseFee) : 0;
1752
- const configuredPriority = useCustomGas && args.chainDetail?.priorityFee != null ? Number(args.chainDetail.priorityFee) : 0;
1753
- const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
1754
- const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
1755
- const baseFeeMultiplierPct = useCustomGas && args.chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(args.chainDetail.baseFeeMultiplier)) : 100;
1756
- const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
1757
- const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
1758
- let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
1759
- let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
1760
- if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
1761
- maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1762
- maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
1763
- }
1764
- ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
1765
- maxFeePerGas,
1766
- maxPriorityFeePerGas,
1767
- latestBaseFeeWeiOneStep
1768
- ));
1769
- const ser = serializeTransaction({
1770
- type: "eip1559",
1771
- to: v.to,
1772
- data: v.data,
1773
- value: v.value,
1774
- gas: gasLimitI,
1775
- maxFeePerGas,
1776
- maxPriorityFeePerGas,
1777
- nonce: currentNonce,
1778
- chainId: args.chainId
1779
- });
1780
- const h = keccak256(ser);
1781
- messageHashes.push(h.startsWith("0x") ? h.slice(2) : h);
1782
- messageRawBatch.push(ser);
1783
- proposalTxParamsBatch.push({
1784
- nonce: currentNonce,
1785
- gasLimit: gasLimitI.toString(),
1786
- txType: "eip1559",
1787
- maxFeePerGas: maxFeePerGas.toString(),
1788
- maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1789
- });
1790
- firstTxFeePayload = {
1791
- txNonce: currentNonce,
1792
- txGasLimit: gasLimitI.toString(),
1793
- txMaxFeePerGas: maxFeePerGas.toString(),
1794
- txMaxPriorityFeePerGas: maxPriorityFeePerGas.toString()
1795
- };
1796
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1797
- }
1798
- const extraPayload = { batchMeta: [batchMeta0] };
1799
- if (useCustomGas && args.customGasChainDetails && Object.keys(args.customGasChainDetails).length > 0) {
1800
- extraPayload.customGasChainDetails = args.customGasChainDetails;
1801
- }
1802
- const extraJSON = JSON.stringify(extraPayload);
1803
- const firstSigText = batchMeta0.signatureText;
1804
- const bodyForSign = {
1805
- keyList: args.keyList,
1806
- pubKey: args.ph,
1807
- msgHash: messageHashes[0],
1808
- msgRaw: firstDataNo0x,
1809
- messageHashes,
1810
- messageRawBatch,
1811
- destinationChainID: String(args.chainId),
1812
- destinationAddress: v.to,
1813
- extraJSON,
1814
- signatureText: firstSigText,
1815
- purpose: (() => {
1816
- const t = args.purposeText.trim();
1817
- return (t ? `${t}
1818
-
1819
- ` : "") + args.purposeSuffix;
1820
- })(),
1821
- ...firstTxFeePayload,
1822
- proposalTxParams: proposalTxParamsBatch
1823
- };
1824
- if (v.value > 0n) {
1825
- bodyForSign.value = v.value.toString();
1826
- }
1827
- if (args.clientId) bodyForSign.clientId = args.clientId;
1828
- return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
1829
1560
  }
1830
1561
  var MIN_AAVE_V4_DEPOSIT_GAS_EXEC = 400000n;
1831
1562
  var AAVE_V4_EVM_TYPES = /* @__PURE__ */ new Set([
@@ -1917,6 +1648,731 @@ function resolveAaveV4DepositGasUnitsFromSignRequest(detail, batchIndex) {
1917
1648
  }
1918
1649
  return null;
1919
1650
  }
1651
+ var POSITIONS_LIST = `
1652
+ query AaveUserPositions($r: UserPositionsRequest!, $currency: Currency! = USD, $w: TimeWindow! = LAST_DAY) {
1653
+ userPositions(request: $r) {
1654
+ id
1655
+ user
1656
+ createdAt
1657
+ spoke {
1658
+ id
1659
+ name
1660
+ address
1661
+ chain {
1662
+ chainId
1663
+ name
1664
+ }
1665
+ liquidationConfig {
1666
+ targetHealthFactor
1667
+ healthFactorForMaxBonus
1668
+ }
1669
+ }
1670
+ totalSupplied(currency: $currency) {
1671
+ current { value name symbol }
1672
+ }
1673
+ totalDebt(currency: $currency) {
1674
+ current { value name symbol }
1675
+ }
1676
+ netBalance(currency: $currency) {
1677
+ current { value name symbol }
1678
+ }
1679
+ healthFactor {
1680
+ current
1681
+ change(window: $w) {
1682
+ normalized
1683
+ value
1684
+ }
1685
+ }
1686
+ netApy {
1687
+ normalized
1688
+ value
1689
+ }
1690
+ }
1691
+ }
1692
+ `;
1693
+ var POSITION_DETAIL = `
1694
+ query AaveUserPosition(
1695
+ $r: UserPositionRequest!
1696
+ $currency: Currency! = USD
1697
+ $w: TimeWindow! = LAST_DAY
1698
+ ) {
1699
+ userPosition(request: $r) {
1700
+ id
1701
+ user
1702
+ createdAt
1703
+ spoke {
1704
+ id
1705
+ name
1706
+ address
1707
+ chain {
1708
+ chainId
1709
+ name
1710
+ }
1711
+ liquidationConfig {
1712
+ targetHealthFactor
1713
+ healthFactorForMaxBonus
1714
+ }
1715
+ }
1716
+ totalSupplied(currency: $currency) {
1717
+ current { value name symbol }
1718
+ change { normalized value }
1719
+ }
1720
+ totalCollateral(currency: $currency) {
1721
+ current { value name symbol }
1722
+ change { normalized value }
1723
+ }
1724
+ totalDebt(currency: $currency) {
1725
+ current { value name symbol }
1726
+ change { normalized value }
1727
+ }
1728
+ netBalance(currency: $currency) {
1729
+ current { value name symbol }
1730
+ change { normalized value }
1731
+ }
1732
+ netCollateral(currency: $currency) {
1733
+ current { value name symbol }
1734
+ change { normalized value }
1735
+ }
1736
+ netApy {
1737
+ normalized
1738
+ value
1739
+ }
1740
+ netSupplyApy {
1741
+ current {
1742
+ normalized
1743
+ }
1744
+ }
1745
+ netBorrowApy {
1746
+ current {
1747
+ normalized
1748
+ }
1749
+ }
1750
+ netAccruedInterest(currency: $currency) {
1751
+ value
1752
+ name
1753
+ symbol
1754
+ }
1755
+ healthFactor {
1756
+ current
1757
+ change(window: $w) {
1758
+ normalized
1759
+ value
1760
+ }
1761
+ }
1762
+ maxBorrowingPower(currency: $currency) {
1763
+ value
1764
+ name
1765
+ symbol
1766
+ }
1767
+ remainingBorrowingPower(currency: $currency) {
1768
+ value
1769
+ name
1770
+ symbol
1771
+ }
1772
+ averageCollateralFactor {
1773
+ normalized
1774
+ }
1775
+ liquidationPrice(currency: $currency) {
1776
+ value
1777
+ name
1778
+ symbol
1779
+ }
1780
+ canUpdateDynamicConfig
1781
+ netBalancePercentChange(window: $w) {
1782
+ normalized
1783
+ }
1784
+ }
1785
+ }
1786
+ `;
1787
+ var USER_SUPPLIES = `
1788
+ query AaveUserSupplies($r: UserSuppliesRequest!) {
1789
+ userSupplies(request: $r) {
1790
+ id
1791
+ isCollateral
1792
+ principal {
1793
+ amount {
1794
+ value
1795
+ }
1796
+ token {
1797
+ address
1798
+ info {
1799
+ symbol
1800
+ name
1801
+ icon
1802
+ }
1803
+ }
1804
+ }
1805
+ balance {
1806
+ amount {
1807
+ value
1808
+ }
1809
+ token {
1810
+ address
1811
+ info {
1812
+ symbol
1813
+ name
1814
+ }
1815
+ }
1816
+ }
1817
+ withdrawable {
1818
+ amount {
1819
+ value
1820
+ }
1821
+ token {
1822
+ address
1823
+ info {
1824
+ symbol
1825
+ }
1826
+ }
1827
+ }
1828
+ interest {
1829
+ amount {
1830
+ value
1831
+ }
1832
+ token {
1833
+ address
1834
+ info {
1835
+ symbol
1836
+ }
1837
+ }
1838
+ }
1839
+ reserve {
1840
+ id
1841
+ onChainId
1842
+ summary {
1843
+ supplyApy {
1844
+ normalized
1845
+ value
1846
+ }
1847
+ }
1848
+ asset {
1849
+ underlying {
1850
+ address
1851
+ info {
1852
+ symbol
1853
+ name
1854
+ icon
1855
+ }
1856
+ }
1857
+ }
1858
+ }
1859
+ }
1860
+ }
1861
+ `;
1862
+ var DEFAULT_CURRENCY = "USD";
1863
+ var DEFAULT_TIME_WINDOW = "LAST_DAY";
1864
+ function formatAaveV4ExchangeLabel(ex) {
1865
+ if (ex == null) return "\u2014";
1866
+ const sym = (ex.symbol ?? "").trim();
1867
+ const name = (ex.name ?? "").trim();
1868
+ if (sym === "$" && name) return name;
1869
+ if (name && sym && name.toUpperCase() !== sym) return name;
1870
+ return sym || name || "\u2014";
1871
+ }
1872
+ function formatAaveV4PositionPercent(normalized, value) {
1873
+ const n = (normalized ?? "").trim();
1874
+ const v = (value ?? "").trim();
1875
+ if (n === "0" && (v === "0" || v === "")) return "0%";
1876
+ const out = formatAaveV4PercentDisplay(normalized, value);
1877
+ return out;
1878
+ }
1879
+ function formatAaveV4PositionHealthFactor(raw) {
1880
+ if (raw == null || String(raw).trim() === "") return "\u221E";
1881
+ return formatAaveV4HealthFactorInner(raw);
1882
+ }
1883
+ function formatAaveV4HealthFactorInner(raw) {
1884
+ const n = Number(raw);
1885
+ if (!Number.isFinite(n)) return String(raw);
1886
+ if (n >= 1e12) return "\u221E";
1887
+ return n >= 10 ? n.toFixed(1) : n.toFixed(2);
1888
+ }
1889
+ function buildUserPositionsRequest(user, filter) {
1890
+ return {
1891
+ user,
1892
+ filter,
1893
+ orderBy: { balance: "DESC" }
1894
+ };
1895
+ }
1896
+ async function fetchAaveV4UserPositionsForChain(args) {
1897
+ const u = (args.user ?? "").trim();
1898
+ if (!u || !isAddress(u)) return [];
1899
+ const user = getAddress(u);
1900
+ const d = await aaveV4Gql(POSITIONS_LIST, {
1901
+ r: buildUserPositionsRequest(user, { chainIds: [args.chainId] }),
1902
+ currency: DEFAULT_CURRENCY,
1903
+ w: DEFAULT_TIME_WINDOW
1904
+ });
1905
+ return d.userPositions ?? [];
1906
+ }
1907
+ async function fetchAaveV4UserPositionsByAssetOnChain(args) {
1908
+ const u = (args.user ?? "").trim();
1909
+ if (!u || !isAddress(u)) {
1910
+ return { forAsset: [], other: [], filterUnderlying: null };
1911
+ }
1912
+ const user = getAddress(u);
1913
+ const c = args.chainId;
1914
+ const f = args.filterUnderlying;
1915
+ if (f == null) {
1916
+ const all2 = await fetchAaveV4UserPositionsForChain({ user: u, chainId: c });
1917
+ return { forAsset: all2, other: [], filterUnderlying: null };
1918
+ }
1919
+ const token = getAddress(f);
1920
+ const [allRes, withTokenRes] = await Promise.all([
1921
+ aaveV4Gql(POSITIONS_LIST, {
1922
+ r: buildUserPositionsRequest(user, { chainIds: [c] }),
1923
+ currency: DEFAULT_CURRENCY,
1924
+ w: DEFAULT_TIME_WINDOW
1925
+ }),
1926
+ aaveV4Gql(POSITIONS_LIST, {
1927
+ r: buildUserPositionsRequest(user, { tokens: [{ address: token, chainId: c }] }),
1928
+ currency: DEFAULT_CURRENCY,
1929
+ w: DEFAULT_TIME_WINDOW
1930
+ })
1931
+ ]);
1932
+ const all = allRes.userPositions ?? [];
1933
+ const forAsset = withTokenRes.userPositions ?? [];
1934
+ const want = new Set(forAsset.map((p) => p.id));
1935
+ const other = all.filter((p) => !want.has(p.id));
1936
+ return { forAsset, other, filterUnderlying: token };
1937
+ }
1938
+ async function fetchAaveV4UserPositionById(positionId) {
1939
+ const id = (positionId ?? "").trim();
1940
+ if (!id) return null;
1941
+ const d = await aaveV4Gql(POSITION_DETAIL, {
1942
+ r: { id },
1943
+ currency: DEFAULT_CURRENCY,
1944
+ w: DEFAULT_TIME_WINDOW
1945
+ });
1946
+ return d.userPosition ?? null;
1947
+ }
1948
+ async function fetchAaveV4UserSuppliesForPosition(userPositionId) {
1949
+ const pid = (userPositionId ?? "").trim();
1950
+ if (!pid) return [];
1951
+ const d = await aaveV4Gql(USER_SUPPLIES, {
1952
+ r: {
1953
+ query: { userPositionId: pid },
1954
+ orderBy: { amount: "DESC" },
1955
+ includeZeroBalances: false
1956
+ }
1957
+ });
1958
+ return d.userSupplies ?? [];
1959
+ }
1960
+ async function aaveV4UserHasAvailableBorrowCollateralForContextOnSpoke(args) {
1961
+ let wantSpoke;
1962
+ try {
1963
+ wantSpoke = getAddress(args.spokeAddress).toLowerCase();
1964
+ } catch {
1965
+ return false;
1966
+ }
1967
+ const u0 = getAddress(args.contextUnderlying).toLowerCase();
1968
+ const positions = await fetchAaveV4UserPositionsForChain({ user: args.user, chainId: args.chainId });
1969
+ const pos = positions.find((p) => {
1970
+ const a = (p.spoke?.address ?? "").trim();
1971
+ if (!a) return false;
1972
+ try {
1973
+ return getAddress(a).toLowerCase() === wantSpoke;
1974
+ } catch {
1975
+ return false;
1976
+ }
1977
+ });
1978
+ if (!pos) return false;
1979
+ const supplies = await fetchAaveV4UserSuppliesForPosition(pos.id);
1980
+ const row = supplies.find((s) => {
1981
+ const a = (s.reserve?.asset?.underlying?.address ?? "").trim();
1982
+ if (!a) return false;
1983
+ try {
1984
+ return getAddress(a).toLowerCase() === u0;
1985
+ } catch {
1986
+ return false;
1987
+ }
1988
+ });
1989
+ if (!row) return false;
1990
+ const bal = parseFloat((row.balance?.amount?.value ?? "").trim());
1991
+ if (!Number.isFinite(bal) || bal <= 0) return false;
1992
+ return row.isCollateral === true;
1993
+ }
1994
+ function formatAaveV4DecimalString(raw, maxFractionDigits = 6) {
1995
+ const s = (raw ?? "").trim();
1996
+ if (!s) return "\u2014";
1997
+ const n = Number(s);
1998
+ if (!Number.isFinite(n)) return s;
1999
+ if (Math.abs(n) >= 1e9) return n.toExponential(2);
2000
+ return n.toLocaleString(void 0, { maximumFractionDigits: maxFractionDigits });
2001
+ }
2002
+ function formatAaveV4RiskNotionalString(raw) {
2003
+ const s = (raw ?? "").trim();
2004
+ if (!s) return "\u2014";
2005
+ const n = Number(s);
2006
+ if (!Number.isFinite(n)) return s;
2007
+ if (n === 0) return "0";
2008
+ if (Math.abs(n) >= 1e9) return n.toExponential(2);
2009
+ if (n > 0 && n < 0.5) {
2010
+ return n.toLocaleString(void 0, { maximumSignificantDigits: 4, maximumFractionDigits: 8 });
2011
+ }
2012
+ return n.toLocaleString(void 0, { maximumFractionDigits: 6 });
2013
+ }
2014
+ function formatAaveV4HealthFactor(raw) {
2015
+ if (raw == null || String(raw).trim() === "") return "\u2014";
2016
+ return formatAaveV4HealthFactorInner(String(raw).trim());
2017
+ }
2018
+ var HF_EPS = 1e-9;
2019
+ function aaveV4WithdrawHealthGate(args) {
2020
+ const { hasBorrowDebt, liquidationConfig: liq } = args;
2021
+ const r0 = args.resultingHealthFactor;
2022
+ if (!hasBorrowDebt) {
2023
+ return { outcome: "allow" };
2024
+ }
2025
+ if (r0 == null || !Number.isFinite(r0)) {
2026
+ return { outcome: "block", reason: "Could not determine health factor after withdrawal." };
2027
+ }
2028
+ const r = r0;
2029
+ const t = liq == null ? NaN : Number(liq.targetHealthFactor);
2030
+ const m = liq == null ? NaN : Number(liq.healthFactorForMaxBonus);
2031
+ if (r <= 1 + HF_EPS) {
2032
+ return {
2033
+ outcome: "block",
2034
+ reason: "This withdrawal would leave health factor at or below 1.0 (liquidation range)."
2035
+ };
2036
+ }
2037
+ if (Number.isFinite(m) && m > 1 + HF_EPS && r <= m + HF_EPS) {
2038
+ return {
2039
+ outcome: "block",
2040
+ reason: `This withdrawal would put health factor at or below the spoke\u2019s max-liquidation-bonus threshold (${m}).`
2041
+ };
2042
+ }
2043
+ if (Number.isFinite(t) && r < t - HF_EPS) {
2044
+ return {
2045
+ outcome: "confirm",
2046
+ reason: `The resulting health factor would be below this market\u2019s target (${t.toFixed(4)}).`,
2047
+ targetHealthFactor: t,
2048
+ healthFactorForMaxBonus: Number.isFinite(m) ? m : 0
2049
+ };
2050
+ }
2051
+ return { outcome: "allow" };
2052
+ }
2053
+ function aaveV4BorrowHealthGate(args) {
2054
+ return aaveV4WithdrawHealthGate({
2055
+ resultingHealthFactor: args.resultingHealthFactor,
2056
+ hasBorrowDebt: true,
2057
+ liquidationConfig: args.liquidationConfig
2058
+ });
2059
+ }
2060
+ function aaveV4RepayHealthGate(args) {
2061
+ if (!args.strict) {
2062
+ return { outcome: "allow" };
2063
+ }
2064
+ return aaveV4WithdrawHealthGate({
2065
+ resultingHealthFactor: args.resultingHealthFactor,
2066
+ hasBorrowDebt: true,
2067
+ liquidationConfig: args.liquidationConfig
2068
+ });
2069
+ }
2070
+
2071
+ // src/protocols/evm/aave-v4/positionActionsApi.ts
2072
+ var PREVIEW_WITHDRAW = `
2073
+ query AaveV4PreviewWithdraw($req: PreviewRequest!) {
2074
+ preview(request: $req) {
2075
+ __typename
2076
+ ... on PreviewUserPosition {
2077
+ id
2078
+ healthFactor {
2079
+ __typename
2080
+ ... on HealthFactorVariation {
2081
+ current
2082
+ after
2083
+ }
2084
+ ... on HealthFactorError {
2085
+ reason
2086
+ current
2087
+ after
2088
+ }
2089
+ }
2090
+ }
2091
+ }
2092
+ }
2093
+ `;
2094
+ var USER_CLAIMABLE = `
2095
+ query AaveV4UserClaimableRewards($req: UserClaimableRewardsRequest!) {
2096
+ userClaimableRewards(request: $req) {
2097
+ __typename
2098
+ ... on UserMerklClaimableReward {
2099
+ id
2100
+ claimable {
2101
+ amount { value }
2102
+ exchange { value name symbol }
2103
+ token {
2104
+ address
2105
+ info { symbol name }
2106
+ }
2107
+ }
2108
+ }
2109
+ }
2110
+ }
2111
+ `;
2112
+ var CLAIM_REWARDS = `
2113
+ query AaveV4ClaimRewards($req: ClaimRewardsRequest!) {
2114
+ claimRewards(request: $req) {
2115
+ to
2116
+ from
2117
+ data
2118
+ value
2119
+ chainId
2120
+ }
2121
+ }
2122
+ `;
2123
+ function parseBigDecimalHf(s) {
2124
+ if (s == null || !String(s).trim()) return null;
2125
+ const n = Number(String(s).trim());
2126
+ return Number.isFinite(n) ? n : null;
2127
+ }
2128
+ async function previewAaveV4WithdrawResultingHf(args) {
2129
+ const req = {
2130
+ action: {
2131
+ withdraw: {
2132
+ sender: args.user,
2133
+ reserve: args.reserveId,
2134
+ amount: { erc20: { exact: args.amountExactHuman } }
2135
+ }
2136
+ }
2137
+ };
2138
+ const d = await aaveV4Gql(PREVIEW_WITHDRAW, { req });
2139
+ const p = d.preview;
2140
+ if (p?.__typename !== "PreviewUserPosition") {
2141
+ return { resultingHf: null, error: "Withdraw preview is not available for this request." };
2142
+ }
2143
+ const hf = p.healthFactor;
2144
+ if (hf?.__typename === "HealthFactorError") {
2145
+ return { resultingHf: null, error: hf.reason ?? "Invalid withdrawal for this position." };
2146
+ }
2147
+ if (hf?.__typename === "HealthFactorVariation") {
2148
+ return { resultingHf: parseBigDecimalHf(hf.after), error: null };
2149
+ }
2150
+ return { resultingHf: null, error: "Could not read health factor from preview." };
2151
+ }
2152
+ async function previewAaveV4BorrowResultingHf(args) {
2153
+ const req = {
2154
+ action: {
2155
+ borrow: {
2156
+ sender: args.user,
2157
+ reserve: args.reserveGraphqlId,
2158
+ amount: { erc20: { value: args.amountExactHuman } }
2159
+ }
2160
+ }
2161
+ };
2162
+ const d = await aaveV4Gql(PREVIEW_WITHDRAW, { req });
2163
+ const p = d.preview;
2164
+ if (p?.__typename !== "PreviewUserPosition") {
2165
+ return { resultingHf: null, error: "Borrow preview is not available for this request." };
2166
+ }
2167
+ const hf = p.healthFactor;
2168
+ if (hf?.__typename === "HealthFactorError") {
2169
+ return { resultingHf: null, error: hf.reason ?? "Invalid borrow for this position." };
2170
+ }
2171
+ if (hf?.__typename === "HealthFactorVariation") {
2172
+ return { resultingHf: parseBigDecimalHf(hf.after), error: null };
2173
+ }
2174
+ return { resultingHf: null, error: "Could not read health factor from borrow preview." };
2175
+ }
2176
+ var PREVIEW_REPAY = `
2177
+ query AaveV4PreviewRepay($req: PreviewRequest!) {
2178
+ preview(request: $req) {
2179
+ __typename
2180
+ ... on PreviewUserPosition {
2181
+ id
2182
+ healthFactor {
2183
+ __typename
2184
+ ... on HealthFactorVariation {
2185
+ current
2186
+ after
2187
+ }
2188
+ ... on HealthFactorError {
2189
+ reason
2190
+ current
2191
+ after
2192
+ }
2193
+ }
2194
+ }
2195
+ }
2196
+ }
2197
+ `;
2198
+ async function previewAaveV4RepayResultingHf(args) {
2199
+ const req = {
2200
+ action: {
2201
+ repay: {
2202
+ sender: args.user,
2203
+ reserve: args.reserveGraphqlId,
2204
+ amount: { erc20: { value: { exact: args.amountExactHuman } } }
2205
+ }
2206
+ }
2207
+ };
2208
+ const d = await aaveV4Gql(PREVIEW_REPAY, { req });
2209
+ const p = d.preview;
2210
+ if (p?.__typename !== "PreviewUserPosition") {
2211
+ return { resultingHf: null, error: "Repay preview is not available for this request." };
2212
+ }
2213
+ const hf = p.healthFactor;
2214
+ if (hf?.__typename === "HealthFactorError") {
2215
+ return { resultingHf: null, error: hf.reason ?? "Invalid repay for this position." };
2216
+ }
2217
+ if (hf?.__typename === "HealthFactorVariation") {
2218
+ return { resultingHf: parseBigDecimalHf(hf.after), error: null };
2219
+ }
2220
+ return { resultingHf: null, error: "Could not read health factor from repay preview." };
2221
+ }
2222
+ async function fetchAaveV4MerklClaimableRewardsForChain(args) {
2223
+ const d = await aaveV4Gql(USER_CLAIMABLE, { req: { user: args.user, chainId: args.chainId } });
2224
+ const out = [];
2225
+ for (const r of d.userClaimableRewards ?? []) {
2226
+ if (r.__typename !== "UserMerklClaimableReward" || !("claimable" in r)) continue;
2227
+ const id = (r.id ?? "").trim();
2228
+ if (!id) continue;
2229
+ const c = r.claimable;
2230
+ const sym = (c?.token?.info?.symbol ?? "").trim() || "\u2014";
2231
+ const name = (c?.token?.info?.name ?? "").trim() || sym;
2232
+ const addr = (c?.token?.address ?? "").trim();
2233
+ const amt = (c?.amount?.value ?? "").trim();
2234
+ const exV = (c?.exchange?.value ?? "").trim();
2235
+ const exName = (c?.exchange?.name ?? "").trim();
2236
+ const exSym = (c?.exchange?.symbol ?? "").trim();
2237
+ const exchangeLabel = exName && exSym && exName.toUpperCase() !== exSym.toUpperCase() ? exName : exSym || exName || "\u2014";
2238
+ let exchangeValue = null;
2239
+ if (exV) {
2240
+ const n = parseFloat(exV);
2241
+ exchangeValue = Number.isFinite(n) ? exV : null;
2242
+ }
2243
+ out.push({
2244
+ id,
2245
+ tokenSymbol: sym,
2246
+ tokenName: name,
2247
+ tokenAddress: addr,
2248
+ amountValue: amt,
2249
+ exchangeValue,
2250
+ exchangeLabel
2251
+ });
2252
+ }
2253
+ return out;
2254
+ }
2255
+ async function fetchAaveV4MerklClaimRewardIdsForChain(args) {
2256
+ const rows = await fetchAaveV4MerklClaimableRewardsForChain(args);
2257
+ return rows.map((r) => r.id);
2258
+ }
2259
+ async function fetchAaveV4ClaimRewardsCalldata(args) {
2260
+ if (args.rewardIds.length === 0) return null;
2261
+ const d = await aaveV4Gql(CLAIM_REWARDS, { req: { user: args.user, chainId: args.chainId, ids: args.rewardIds } });
2262
+ const c = d.claimRewards;
2263
+ if (!c) return null;
2264
+ return {
2265
+ to: c.to,
2266
+ from: c.from,
2267
+ data: c.data,
2268
+ value: c.value,
2269
+ chainId: c.chainId
2270
+ };
2271
+ }
2272
+
2273
+ // src/protocols/evm/aave-v4/loadSupportedChainIds.ts
2274
+ var cached = null;
2275
+ var inflight = null;
2276
+ function loadAaveV4SupportedChainIds() {
2277
+ if (cached) return Promise.resolve(cached);
2278
+ if (inflight) return inflight;
2279
+ inflight = (async () => {
2280
+ try {
2281
+ const s = await loadAaveV4SupportedChainIdsFromV4Api();
2282
+ cached = s;
2283
+ return s;
2284
+ } finally {
2285
+ inflight = null;
2286
+ }
2287
+ })();
2288
+ return inflight;
2289
+ }
2290
+
2291
+ // src/chains/evm/chainIdParse.ts
2292
+ function parseEvmChainIdToNumber(chainId) {
2293
+ if (chainId == null) return Number.NaN;
2294
+ if (typeof chainId === "bigint") {
2295
+ const n = Number(chainId);
2296
+ return Number.isSafeInteger(n) && n >= 0 ? n : Number.NaN;
2297
+ }
2298
+ if (typeof chainId === "number") {
2299
+ return Number.isInteger(chainId) && chainId >= 0 ? chainId : Number.NaN;
2300
+ }
2301
+ const t = String(chainId).trim();
2302
+ if (!t) return Number.NaN;
2303
+ const low = t.toLowerCase();
2304
+ if (low.startsWith("eip155:")) {
2305
+ const rest = t.slice("eip155:".length).trim();
2306
+ const n = Number.parseInt(rest, 10);
2307
+ return Number.isNaN(n) || n < 0 ? Number.NaN : n;
2308
+ }
2309
+ if (low.startsWith("0x")) {
2310
+ return Number.parseInt(t, 16);
2311
+ }
2312
+ return Number.parseInt(t, 10);
2313
+ }
2314
+
2315
+ // src/protocols/evm/aave-v4/reserveDisplay.ts
2316
+ function formatAavePercentDisplay(p) {
2317
+ if (!p) return "\u2014";
2318
+ const t = (p.formatted ?? "").trim();
2319
+ if (t) return t.includes("%") ? t : `${t}%`;
2320
+ const v = (p.value ?? "").trim();
2321
+ if (!v) return "\u2014";
2322
+ const n = Number(v) * 100;
2323
+ if (!Number.isFinite(n)) return "\u2014";
2324
+ if (n >= 0.01) return `${n.toFixed(2)}%`;
2325
+ if (n > 0) return `${n.toFixed(4)}%`;
2326
+ return "0%";
2327
+ }
2328
+ function aaveAvailableLiquidityDisplay(supplyInfo, borrowInfo) {
2329
+ const sTotal = supplyInfo?.total;
2330
+ const bAmt = borrowInfo?.total?.amount;
2331
+ if (!sTotal?.raw || sTotal.decimals == null) return "\u2014";
2332
+ if (!bAmt?.raw || bAmt.decimals == null) return "\u2014";
2333
+ try {
2334
+ if (sTotal.decimals !== bAmt.decimals) return "\u2014";
2335
+ const a = BigInt(sTotal.raw) - BigInt(bAmt.raw);
2336
+ if (a < 0n) return "0";
2337
+ return formatUnits(a, sTotal.decimals);
2338
+ } catch {
2339
+ return "\u2014";
2340
+ }
2341
+ }
2342
+ function aaveUnderlyingAddressForContext(args) {
2343
+ const raw = (args.contextContract ?? "").trim();
2344
+ try {
2345
+ const a = getAddress(raw);
2346
+ if (a.toLowerCase() === zeroAddress.toLowerCase() && args.chainNativeWrapped) {
2347
+ return getAddress(args.chainNativeWrapped.trim());
2348
+ }
2349
+ return a;
2350
+ } catch {
2351
+ return getAddress(zeroAddress);
2352
+ }
2353
+ }
2354
+ function isValidAaveChainId(assetsChainId) {
2355
+ if (assetsChainId == null) return false;
2356
+ const n = parseEvmChainIdToNumber(assetsChainId);
2357
+ return !Number.isNaN(n) && n >= 0;
2358
+ }
2359
+ function aaveReadSupplyMetrics(reserve, symbolForDisplay) {
2360
+ if (!reserve || typeof reserve !== "object") {
2361
+ return { depositedAmount: "\u2014", apy: "\u2014", totalDeposits: "\u2014", availableLiquidity: "\u2014" };
2362
+ }
2363
+ const r = reserve;
2364
+ const apy = formatAavePercentDisplay(r.supplyInfo?.apy);
2365
+ const tot = r.supplyInfo?.total?.value ?? "\u2014";
2366
+ const liq = aaveAvailableLiquidityDisplay(r.supplyInfo, r.borrowInfo);
2367
+ const dep = r.userState?.balance?.amount?.value ?? "\u2014";
2368
+ const sym = (symbolForDisplay ?? "").trim();
2369
+ return {
2370
+ depositedAmount: dep === "\u2014" ? "\u2014" : sym ? `${dep} ${sym}` : dep,
2371
+ apy,
2372
+ totalDeposits: tot === "\u2014" ? "\u2014" : sym ? `${tot} ${sym}` : tot,
2373
+ availableLiquidity: liq === "\u2014" ? "\u2014" : sym ? `${liq} ${sym}` : liq
2374
+ };
2375
+ }
1920
2376
 
1921
2377
  // src/protocols/evm/aave-v4/index.ts
1922
2378
  var AAVE_V4_PROTOCOL_ID = "aave-v4";
@@ -1938,6 +2394,6 @@ var aaveV4ProtocolModule = {
1938
2394
  };
1939
2395
  registerProtocolModule(aaveV4ProtocolModule);
1940
2396
 
1941
- export { AAVE_V4_GRAPHQL_URL, AAVE_V4_PROTOCOL_ID, AAVE_V4_SPOKE_BORROW_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_SUPPLY_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_WITHDRAW_DEFAULT_GAS_UNITS, MIN_AAVE_V4_DEPOSIT_GAS_EXEC, aaveV4Gql, aaveV4KeyForNodeAssetRow, aaveV4ProtocolModule, aaveV4UiMarketIdForHubName, aggregateV4SupplyDisplay, borrowableAssetsFromHubReserves, buildAaveV4BorrowTableRowsFromHub, buildEvmMultisignBodyAaveV4DepositBatch, buildEvmMultisignBodyAaveV4MerklClaimRewards, buildEvmMultisignBodyAaveV4SpokeBorrow, buildEvmMultisignBodyAaveV4SpokeRepay, buildEvmMultisignBodyAaveV4SpokeWithdraw, buildEvmMultisignBodyEulerV2MerklDistributorClaim, buildEvmMultisignBodyEulerV2ReulUnlock, ensureAaveV4ChainTokenCache, fetchAaveV4Chains, fetchAaveV4HubReserves, fetchAaveV4HubsForChain, fetchAaveV4NativeWrappedToken, fetchAaveV4ReservesForUnderlying, fetchAaveV4SpokeReserveIdForUnderlying, fetchAaveV4SpokeReserveStatusForUnderlying, fetchAaveV4SupportedUnderlyingAddressSet, fetchAaveV4UserBorrowsDebtByUnderlyingForHub, findAaveV4HubReserveForChainUnderlying, findHubReserveForUnderlying, formatAaveV4AmountHumanFromApiString, formatAaveV4PercentDisplay, formatAaveV4ReserveLiquidityFromSummary, formatAaveV4RiskDisplay, formatAaveV4TokenAmount, isAaveV4DepositEvmSignRequest, loadAaveV4SupportedChainIdsFromV4Api, pickAaveV4ReserveRowForSpoke, resolveAaveV4DepositGasUnitsFromSignRequest, resolveAaveV4HubForUiMarket };
2397
+ export { AAVE_V4_GRAPHQL_URL, AAVE_V4_PROTOCOL_ID, AAVE_V4_SPOKE_BORROW_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_SUPPLY_DEFAULT_GAS_UNITS, AAVE_V4_SPOKE_WITHDRAW_DEFAULT_GAS_UNITS, MIN_AAVE_V4_DEPOSIT_GAS_EXEC, aaveAvailableLiquidityDisplay, aaveReadSupplyMetrics, aaveUnderlyingAddressForContext, aaveV4BorrowHealthGate, aaveV4Gql, aaveV4KeyForNodeAssetRow, aaveV4ProtocolModule, aaveV4RepayHealthGate, aaveV4UiMarketIdForHubName, aaveV4UserHasAvailableBorrowCollateralForContextOnSpoke, aaveV4WithdrawHealthGate, aggregateV4SupplyDisplay, borrowableAssetsFromHubReserves, buildAaveV4BorrowTableRowsFromHub, buildEvmMultisignBodyAaveV4DepositBatch, buildEvmMultisignBodyAaveV4MerklClaimRewards, buildEvmMultisignBodyAaveV4SpokeBorrow, buildEvmMultisignBodyAaveV4SpokeRepay, buildEvmMultisignBodyAaveV4SpokeWithdraw, buildEvmMultisignBodyEulerV2MerklDistributorClaim, buildEvmMultisignBodyEulerV2ReulUnlock, ensureAaveV4ChainTokenCache, fetchAaveV4Chains, fetchAaveV4ClaimRewardsCalldata, fetchAaveV4HubReserves, fetchAaveV4HubsForChain, fetchAaveV4MerklClaimRewardIdsForChain, fetchAaveV4MerklClaimableRewardsForChain, fetchAaveV4NativeWrappedToken, fetchAaveV4ReservesForUnderlying, fetchAaveV4SpokeReserveIdForUnderlying, fetchAaveV4SpokeReserveStatusForUnderlying, fetchAaveV4SupportedUnderlyingAddressSet, fetchAaveV4UserBorrowsDebtByUnderlyingForHub, fetchAaveV4UserPositionById, fetchAaveV4UserPositionsByAssetOnChain, fetchAaveV4UserPositionsForChain, fetchAaveV4UserSuppliesForPosition, findAaveV4HubReserveForChainUnderlying, findHubReserveForUnderlying, formatAavePercentDisplay, formatAaveV4AmountHumanFromApiString, formatAaveV4DecimalString, formatAaveV4ExchangeLabel, formatAaveV4HealthFactor, formatAaveV4PercentDisplay, formatAaveV4PositionHealthFactor, formatAaveV4PositionPercent, formatAaveV4ReserveLiquidityFromSummary, formatAaveV4RiskDisplay, formatAaveV4RiskNotionalString, formatAaveV4TokenAmount, isAaveV4DepositEvmSignRequest, isValidAaveChainId, loadAaveV4SupportedChainIds, loadAaveV4SupportedChainIdsFromV4Api, parseBigDecimalHf, pickAaveV4ReserveRowForSpoke, previewAaveV4BorrowResultingHf, previewAaveV4RepayResultingHf, previewAaveV4WithdrawResultingHf, resolveAaveV4DepositGasUnitsFromSignRequest, resolveAaveV4HubForUiMarket };
1942
2398
  //# sourceMappingURL=index.js.map
1943
2399
  //# sourceMappingURL=index.js.map