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