@continuumdao/ctm-mpc-defi 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +20 -78
  2. package/dist/agent/catalog.cjs +511 -4
  3. package/dist/agent/catalog.cjs.map +1 -1
  4. package/dist/agent/catalog.d.ts +140 -20
  5. package/dist/agent/catalog.js +501 -6
  6. package/dist/agent/catalog.js.map +1 -1
  7. package/dist/agent/skills/aave-v4/SKILL.md +43 -0
  8. package/dist/agent/skills/curve-dao/SKILL.md +12 -0
  9. package/dist/agent/skills/ethena/SKILL.md +10 -0
  10. package/dist/agent/skills/euler-v2/SKILL.md +10 -0
  11. package/dist/agent/skills/lido/SKILL.md +22 -0
  12. package/dist/agent/skills/maple-syrup/SKILL.md +10 -0
  13. package/dist/agent/skills/sky/SKILL.md +10 -0
  14. package/dist/agent/skills/uniswap-v4/SKILL.md +22 -0
  15. package/dist/chains/evm/index.cjs +27 -226
  16. package/dist/chains/evm/index.cjs.map +1 -1
  17. package/dist/chains/evm/index.d.ts +14 -26
  18. package/dist/chains/evm/index.js +21 -211
  19. package/dist/chains/evm/index.js.map +1 -1
  20. package/dist/chains/near/index.d.ts +1 -1
  21. package/dist/chains/solana/index.d.ts +1 -1
  22. package/dist/core/index.cjs +8 -110
  23. package/dist/core/index.cjs.map +1 -1
  24. package/dist/core/index.d.ts +5 -39
  25. package/dist/core/index.js +6 -100
  26. package/dist/core/index.js.map +1 -1
  27. package/dist/{envelope-CcE5Cz_q.d.ts → envelope-CpBUh9eP.d.ts} +1 -1
  28. package/dist/index.cjs +238 -1868
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.ts +7 -11
  31. package/dist/index.js +227 -1839
  32. package/dist/index.js.map +1 -1
  33. package/dist/protocols/evm/aave-v4/index.cjs +385 -662
  34. package/dist/protocols/evm/aave-v4/index.cjs.map +1 -1
  35. package/dist/protocols/evm/aave-v4/index.d.ts +1 -2
  36. package/dist/protocols/evm/aave-v4/index.js +385 -662
  37. package/dist/protocols/evm/aave-v4/index.js.map +1 -1
  38. package/dist/protocols/evm/curve-dao/index.cjs +24 -124
  39. package/dist/protocols/evm/curve-dao/index.cjs.map +1 -1
  40. package/dist/protocols/evm/curve-dao/index.d.ts +3 -4
  41. package/dist/protocols/evm/curve-dao/index.js +15 -115
  42. package/dist/protocols/evm/curve-dao/index.js.map +1 -1
  43. package/dist/protocols/evm/ethena/index.cjs +290 -402
  44. package/dist/protocols/evm/ethena/index.cjs.map +1 -1
  45. package/dist/protocols/evm/ethena/index.d.ts +1 -2
  46. package/dist/protocols/evm/ethena/index.js +291 -403
  47. package/dist/protocols/evm/ethena/index.js.map +1 -1
  48. package/dist/protocols/evm/euler-v2/index.cjs +485 -1163
  49. package/dist/protocols/evm/euler-v2/index.cjs.map +1 -1
  50. package/dist/protocols/evm/euler-v2/index.d.ts +1 -2
  51. package/dist/protocols/evm/euler-v2/index.js +486 -1164
  52. package/dist/protocols/evm/euler-v2/index.js.map +1 -1
  53. package/dist/protocols/evm/lido/index.cjs +241 -236
  54. package/dist/protocols/evm/lido/index.cjs.map +1 -1
  55. package/dist/protocols/evm/lido/index.d.ts +1 -2
  56. package/dist/protocols/evm/lido/index.js +242 -237
  57. package/dist/protocols/evm/lido/index.js.map +1 -1
  58. package/dist/protocols/evm/maple/index.cjs +310 -398
  59. package/dist/protocols/evm/maple/index.cjs.map +1 -1
  60. package/dist/protocols/evm/maple/index.d.ts +1 -2
  61. package/dist/protocols/evm/maple/index.js +311 -399
  62. package/dist/protocols/evm/maple/index.js.map +1 -1
  63. package/dist/protocols/evm/sky/index.cjs +238 -233
  64. package/dist/protocols/evm/sky/index.cjs.map +1 -1
  65. package/dist/protocols/evm/sky/index.d.ts +1 -2
  66. package/dist/protocols/evm/sky/index.js +236 -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, 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 = [];
@@ -560,20 +561,6 @@ function buildAaveV4BorrowTableRowsFromHub(borrowable, hubReserves, debtByUnderl
560
561
  };
561
562
  });
562
563
  }
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
564
  var spokeStaticAbi = [
578
565
  {
579
566
  name: "getReserveCount",
@@ -682,87 +669,234 @@ async function fetchAaveV4SpokeReserveStatusForUnderlying(args) {
682
669
  };
683
670
  }
684
671
 
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();
691
- }
692
- return null;
672
+ // src/core/purpose.ts
673
+ function mergePurposeText(purposeText, purposeSuffix) {
674
+ const t = purposeText.trim();
675
+ const suffix = (purposeSuffix ?? "").trim();
676
+ if (!suffix) return t;
677
+ return t ? `${t}
678
+
679
+ ${suffix}` : suffix;
693
680
  }
694
681
 
695
- // src/chains/evm/txParams.ts
696
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
697
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
698
- return estimatedGas;
682
+ // src/core/envelope.ts
683
+ function finalizeMultisign(input) {
684
+ const { keyGen, destinationChainID, legs } = input;
685
+ if (legs.length === 0) {
686
+ throw new Error("finalizeMultisign requires at least one leg");
687
+ }
688
+ const ph = (keyGen.pubkeyhex ?? "").trim();
689
+ if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
690
+ const keyList = keyGen.keylist ?? [];
691
+ const clientId = getClientIdFromKeyGenResult(keyGen);
692
+ const first = legs[0];
693
+ const messageHashes = legs.map((l) => l.msgHash);
694
+ const messageRawBatch = legs.map((l) => l.msgRaw);
695
+ const batchMeta = legs.map((l) => ({
696
+ destinationAddress: l.destinationAddress,
697
+ signatureText: l.signatureText,
698
+ ...l.audit
699
+ }));
700
+ const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
701
+ const extraPayload = {
702
+ batchMeta,
703
+ ...input.extraJSON ?? {}
704
+ };
705
+ const extraJSON = JSON.stringify(extraPayload);
706
+ const bodyForSign = {
707
+ keyList,
708
+ pubKey: ph,
709
+ msgHash: messageHashes[0],
710
+ msgRaw: first.msgRaw,
711
+ destinationChainID,
712
+ destinationAddress: input.destinationAddress ?? first.destinationAddress,
713
+ extraJSON,
714
+ signatureText: first.signatureText,
715
+ purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
716
+ ...first.feeSnapshot
717
+ };
718
+ if (legs.length > 1) {
719
+ bodyForSign.messageHashes = messageHashes;
720
+ bodyForSign.messageRawBatch = messageRawBatch;
721
+ }
722
+ if (proposalTxParams.length > 0) {
723
+ bodyForSign.proposalTxParams = proposalTxParams;
724
+ }
725
+ const valueWei = first.valueWei;
726
+ if (valueWei != null && valueWei > 0n) {
727
+ bodyForSign.value = valueWei.toString();
728
+ }
729
+ if (clientId) bodyForSign.clientId = clientId;
730
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
731
+ }
732
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
733
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
734
+ return gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
699
735
  }
700
- const cfg = BigInt(Math.floor(chainGasLimit));
701
- return cfg > estimatedGas ? cfg : estimatedGas;
736
+ return (estimatedGas * 12n + 9n) / 10n;
702
737
  }
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",
738
+
739
+ // src/chains/evm/buildBatch.ts
740
+ async function buildEvmMultisignBatch(args) {
741
+ const { context, steps } = args;
742
+ const {
743
+ chainId,
744
+ rpcUrl,
745
+ executorAddress,
746
+ chainDetail,
747
+ useCustomGas,
748
+ customGasChainDetails,
749
+ keyGen,
750
+ purposeText
751
+ } = context;
752
+ if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
753
+ const ch = defineChain({
754
+ id: chainId,
755
+ name: "Destination",
711
756
  nativeCurrency: { decimals: 18, name: "Ether", symbol: "ETH" },
712
- rpcUrls: { default: { http: [url] } }
713
- });
714
- const publicClient = createPublicClient({
715
- chain,
716
- transport: http(url)
757
+ rpcUrls: { default: { http: [rpcUrl] } }
717
758
  });
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 };
759
+ const publicClient = createPublicClient({ chain: ch, transport: http(rpcUrl) });
760
+ const feeParams = await fetchChainFeeParams(rpcUrl, chainId);
761
+ const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
762
+ const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
763
+ const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
764
+ const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
765
+ const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
766
+ const executor = getAddress(executorAddress);
767
+ const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
768
+ const legs = [];
769
+ for (let i = 0; i < steps.length; i++) {
770
+ const step = steps[i];
771
+ const currentNonce = baseNonce + i;
772
+ let estimatedGas;
773
+ if (args.estimateGasForStep) {
774
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
775
+ } else {
776
+ try {
777
+ estimatedGas = await publicClient.estimateGas({
778
+ to: step.to,
779
+ data: step.data,
780
+ value: step.value,
781
+ account: executor
782
+ });
783
+ } catch {
784
+ estimatedGas = step.fallbackGas ?? 100000n;
785
+ }
728
786
  }
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 {
787
+ let gasLimitI;
788
+ if (args.resolveGasLimit) {
789
+ gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient });
790
+ } else if (step.routerSwap) {
791
+ gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
792
+ } else {
793
+ gasLimitI = useCustomGas ? gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
735
794
  }
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 };
795
+ let proposalTxParams;
796
+ let feeSnapshot;
797
+ let serialized;
798
+ if (legacy) {
799
+ let gasPriceWei = await publicClient.getGasPrice();
800
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
801
+ gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
802
+ }
803
+ if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
804
+ const configured = parseGwei(gweiToDecimalString(Number(chainDetail.gasPrice)));
805
+ if (configured > gasPriceWei) gasPriceWei = configured;
806
+ }
807
+ serialized = serializeTransaction({
808
+ type: "legacy",
809
+ to: step.to,
810
+ data: step.data,
811
+ value: step.value,
812
+ gas: gasLimitI,
813
+ gasPrice: gasPriceWei,
814
+ nonce: currentNonce,
815
+ chainId
816
+ });
817
+ proposalTxParams = {
818
+ nonce: currentNonce,
819
+ gasLimit: gasLimitI.toString(),
820
+ txType: "legacy",
821
+ gasPrice: gasPriceWei.toString()
822
+ };
823
+ feeSnapshot = proposalTxParamsToFeeSnapshot(proposalTxParams);
824
+ } else {
825
+ const fetchedBase = feeParams.baseFeeGwei ?? 0;
826
+ const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
827
+ const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
828
+ const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
829
+ const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
830
+ const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
831
+ const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
832
+ const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
833
+ const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
834
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? parseGwei(gweiToDecimalString(effectivePriorityFeeGwei)) : parseGwei("1");
835
+ let maxFeePerGas = parseGwei(gweiToDecimalString(maxFeePerGasGwei));
836
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
837
+ maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
838
+ maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
839
+ }
840
+ ({ maxFeePerGas, maxPriorityFeePerGas } = alignEip1559FeesWithLatestBase(
841
+ maxFeePerGas,
842
+ maxPriorityFeePerGas,
843
+ latestBaseFeeWei
844
+ ));
845
+ serialized = serializeTransaction({
846
+ type: "eip1559",
847
+ to: step.to,
848
+ data: step.data,
849
+ value: step.value,
850
+ gas: gasLimitI,
851
+ maxFeePerGas,
852
+ maxPriorityFeePerGas,
853
+ nonce: currentNonce,
854
+ chainId
855
+ });
856
+ proposalTxParams = {
857
+ nonce: currentNonce,
858
+ gasLimit: gasLimitI.toString(),
859
+ txType: "eip1559",
860
+ maxFeePerGas: maxFeePerGas.toString(),
861
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
862
+ };
863
+ feeSnapshot = i === 0 ? proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
864
+ }
865
+ const h = keccak256(serialized);
866
+ const msgHash = h.startsWith("0x") ? h.slice(2) : h;
867
+ const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
868
+ legs.push({
869
+ msgHash,
870
+ msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
871
+ destinationAddress: step.to,
872
+ signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
873
+ audit: batchMetaExtra,
874
+ feeSnapshot: i === 0 ? feeSnapshot : {},
875
+ proposalTxParams,
876
+ valueWei: i === 0 ? step.value : void 0
877
+ });
878
+ if (i === 0 && args.firstMsgRawNo0x != null) {
879
+ legs[0].msgRaw = args.firstMsgRawNo0x;
750
880
  }
751
881
  }
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");
882
+ const extraJSON = {};
883
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
884
+ extraJSON.customGasChainDetails = customGasChainDetails;
758
885
  }
759
- if (maxF < maxP) {
760
- maxF = baseWei > 0n ? baseWei + maxP + parseGwei("0.001") : maxP * 2n;
886
+ const result = finalizeMultisign({
887
+ keyGen,
888
+ purposeText,
889
+ purposeSuffix: args.purposeSuffix,
890
+ destinationChainID: String(chainId),
891
+ destinationAddress: args.destinationAddress ?? steps[0].to,
892
+ legs,
893
+ extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
894
+ });
895
+ const pv = args.payableValueWei;
896
+ if (pv != null && pv > 0n) {
897
+ result.bodyForSign.value = pv.toString();
761
898
  }
762
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
763
- }
764
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
765
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
899
+ return result;
766
900
  }
767
901
 
768
902
  // src/protocols/evm/aave-v4/multisign.ts
@@ -779,16 +913,6 @@ var AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS = 1000000n;
779
913
  var AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK = AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS;
780
914
  var AAVE_MERKL_CLAIM_ESTIMATE_FALLBACK = 500000n;
781
915
  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
916
  var wethDepositAbi = parseAbi(["function deposit() payable"]);
793
917
  var erc20AllowanceAbi = parseAbi([
794
918
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -803,10 +927,6 @@ var spokeSetUsingAsCollateralAbi = parseAbi([
803
927
  "function setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)"
804
928
  ]);
805
929
  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
930
  const asset = getAddress(args.asset);
811
931
  const spoke = getAddress(args.spoke);
812
932
  const weth = getAddress(args.nativeWrapped);
@@ -904,172 +1024,102 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
904
1024
  });
905
1025
  steps.push({ kind: "set_collateral", to: spoke, data: setCollateralData, value: 0n });
906
1026
  }
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
1027
  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;
1028
+ const evmSteps = steps.map((s) => ({
1029
+ to: s.to,
1030
+ data: s.data,
1031
+ value: s.value,
1032
+ 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
1033
+ }));
1034
+ const n = steps.length;
1035
+ const hasWrap = args.isNativeIn;
1036
+ const withCollateral = args.enableAsCollateralAfterSupply === true;
1037
+ const purposeSuffix = (() => {
1038
+ if (hasWrap) {
1039
+ 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
1040
  }
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;
1041
+ if (n === 1) {
1042
+ return "Aave v4: 1-tx \u2014 supply (allowance already sufficient).";
1043
+ }
1044
+ if (withCollateral && n === 2) {
1045
+ return "Aave v4: 2-tx batch \u2014 supply (allowance already sufficient), then setUsingAsCollateral.";
1046
+ }
1047
+ if (withCollateral) {
1048
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, supply, then setUsingAsCollateral.`;
1049
+ }
1050
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, then supply.`;
1051
+ })();
1052
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1053
+ return buildEvmMultisignBatch({
1054
+ context: {
1055
+ chainCategory: "evm",
1056
+ keyGen: args.keyGen,
1057
+ purposeText: args.purposeText,
1058
+ chainId: args.chainId,
1059
+ rpcUrl: args.rpcUrl,
1060
+ executorAddress: executor,
1061
+ chainDetail: args.chainDetail,
1062
+ useCustomGas: args.useCustomGas,
1063
+ customGasChainDetails: args.customGasChainDetails
1064
+ },
1065
+ steps: evmSteps,
1066
+ purposeSuffix,
1067
+ firstMsgRawNo0x: firstDataNo0x,
1068
+ destinationAddress: steps[0].to,
1069
+ buildBatchMeta: ({ index, gasLimit }) => {
1070
+ const s = steps[index];
1071
+ if (s.kind === "weth_deposit") {
1072
+ return {
1073
+ signatureText: JSON.stringify({
1074
+ kind: "AaveV4",
1075
+ name: "WETH.deposit",
1076
+ function: "deposit()",
1077
+ valueWei: amountWei.toString(),
1078
+ market: marketLabel,
1079
+ note: "Wrap native to WETH, then supply to Aave v4 (same batch)."
1080
+ }),
1081
+ evm: { type: "aave_v4_weth_deposit", version: 1, chainId: String(args.chainId) },
1082
+ aaveV4: { step: "weth_deposit", market: marketLabel, amountHuman: args.amountHuman, hubAsset: asset }
1083
+ };
971
1084
  }
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;
1085
+ if (s.kind === "approve") {
1086
+ return {
1087
+ signatureText: JSON.stringify({
1088
+ kind: "AaveV4",
1089
+ name: "ERC20.approve",
1090
+ to: "Aave v4 spoke",
1091
+ function: "approve(address spender, uint256 amount)",
1092
+ spoke,
1093
+ amountHuman: args.amountHuman,
1094
+ note: "Allowance for this supply amount only (not unlimited)."
1095
+ }),
1096
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1097
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke }
1098
+ };
987
1099
  }
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()
1100
+ if (s.kind === "set_collateral") {
1101
+ return {
1102
+ signatureText: JSON.stringify({
1103
+ kind: "AaveV4",
1104
+ name: "Spoke.setUsingAsCollateral",
1105
+ function: "setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)",
1106
+ reserveId: reserveId.toString(),
1107
+ usingAsCollateral: true,
1108
+ onBehalfOf: onBehalf,
1109
+ market: marketLabel,
1110
+ note: "Enables this supplied reserve as collateral for borrowing (after supply in the same batch)."
1111
+ }),
1112
+ evm: { type: "aave_v4_spoke_set_using_as_collateral", version: 1, chainId: String(args.chainId) },
1113
+ aaveV4: {
1114
+ market: marketLabel,
1115
+ asset,
1116
+ spoke,
1117
+ reserveId: reserveId.toString(),
1118
+ gasBuildSetCollateral: { baseGasUnits: gasLimit.toString() }
1119
+ }
1020
1120
  };
1021
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1022
1121
  }
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,
1122
+ return {
1073
1123
  signatureText: JSON.stringify({
1074
1124
  kind: "AaveV4",
1075
1125
  name: "Spoke.supply",
@@ -1087,67 +1137,13 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
1087
1137
  asset,
1088
1138
  spoke,
1089
1139
  reserveId: reserveId.toString(),
1090
- gasBuildSupply: { baseGasUnits: gasLimitI.toString() }
1140
+ gasBuildSupply: { baseGasUnits: gasLimit.toString() }
1091
1141
  }
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.";
1142
+ };
1113
1143
  }
1114
- if (withCollateral) {
1115
- return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, supply, then setUsingAsCollateral.`;
1116
- }
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) };
1144
+ });
1145
1145
  }
1146
1146
  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
1147
  const asset = getAddress(args.underlying);
1152
1148
  const spoke = getAddress(args.spoke);
1153
1149
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1188,9 +1184,7 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1188
1184
  });
1189
1185
  const tx = { to: spoke, data, value: 0n };
1190
1186
  return buildEvmMultisignBodyAaveV4OneStep({
1191
- ph,
1192
- keyList,
1193
- clientId: clientId ?? void 0,
1187
+ keyGen: args.keyGen,
1194
1188
  chainId: args.chainId,
1195
1189
  rpcUrl: args.rpcUrl,
1196
1190
  chainDetail: args.chainDetail,
@@ -1226,10 +1220,6 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1226
1220
  });
1227
1221
  }
1228
1222
  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
1223
  const asset = getAddress(args.underlying);
1234
1224
  const spoke = getAddress(args.spoke);
1235
1225
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1270,9 +1260,7 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1270
1260
  });
1271
1261
  const tx = { to: spoke, data, value: 0n };
1272
1262
  return buildEvmMultisignBodyAaveV4OneStep({
1273
- ph,
1274
- keyList,
1275
- clientId: clientId ?? void 0,
1263
+ keyGen: args.keyGen,
1276
1264
  chainId: args.chainId,
1277
1265
  rpcUrl: args.rpcUrl,
1278
1266
  chainDetail: args.chainDetail,
@@ -1308,10 +1296,6 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1308
1296
  });
1309
1297
  }
1310
1298
  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
1299
  const asset = getAddress(args.underlying);
1316
1300
  const spoke = getAddress(args.spoke);
1317
1301
  const onBehalf = getAddress(args.onBehalfOf);
@@ -1374,140 +1358,50 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1374
1358
  args: [reserveId, amountWei, onBehalf]
1375
1359
  });
1376
1360
  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
1361
  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()
1362
+ const evmSteps = steps.map((s) => ({
1363
+ to: s.to,
1364
+ data: s.data,
1365
+ value: s.value,
1366
+ fallbackGas: s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK
1367
+ }));
1368
+ const n = steps.length;
1369
+ const purposeSuffix = `Aave v4: ${n}-tx batch \u2014 approve spoke if needed, then repay ${(args.amountHuman || "").trim() || "\u2026"} of debt.`;
1370
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1371
+ return buildEvmMultisignBatch({
1372
+ context: {
1373
+ chainCategory: "evm",
1374
+ keyGen: args.keyGen,
1375
+ purposeText: args.purposeText,
1376
+ chainId: args.chainId,
1377
+ rpcUrl: args.rpcUrl,
1378
+ executorAddress: executor,
1379
+ chainDetail: args.chainDetail,
1380
+ useCustomGas: args.useCustomGas,
1381
+ customGasChainDetails: args.customGasChainDetails
1382
+ },
1383
+ steps: evmSteps,
1384
+ purposeSuffix,
1385
+ firstMsgRawNo0x: firstDataNo0x,
1386
+ destinationAddress: steps[0].to,
1387
+ buildBatchMeta: ({ index, gasLimit }) => {
1388
+ const s = steps[index];
1389
+ if (s.kind === "approve") {
1390
+ return {
1391
+ signatureText: JSON.stringify({
1392
+ kind: "AaveV4",
1393
+ name: "ERC20.approve (repay)",
1394
+ to: "Aave v4 spoke",
1395
+ function: "approve(address spender, uint256 amount)",
1396
+ spoke,
1397
+ amountHuman: args.amountHuman,
1398
+ note: "Allowance to repay this amount (or reset+approve to exact amount)."
1399
+ }),
1400
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1401
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke, step: "repay_prepare" }
1488
1402
  };
1489
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1490
1403
  }
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,
1404
+ return {
1511
1405
  signatureText: JSON.stringify({
1512
1406
  kind: "AaveV4",
1513
1407
  name: "Spoke.repay",
@@ -1525,57 +1419,17 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1525
1419
  asset,
1526
1420
  spoke,
1527
1421
  reserveId: reserveId.toString(),
1528
- gasBuildRepay: { baseGasUnits: gasLimitI.toString() }
1422
+ gasBuildRepay: { baseGasUnits: gasLimit.toString() }
1529
1423
  }
1530
- });
1424
+ };
1531
1425
  }
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) };
1426
+ });
1567
1427
  }
1568
1428
  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
1429
  const to = getAddress(args.to);
1574
1430
  const executor = getAddress(args.executorAddress);
1575
1431
  return buildEvmMultisignBodyAaveV4OneStep({
1576
- ph,
1577
- keyList,
1578
- clientId: clientId ?? void 0,
1432
+ keyGen: args.keyGen,
1579
1433
  chainId: args.chainId,
1580
1434
  rpcUrl: args.rpcUrl,
1581
1435
  chainDetail: args.chainDetail,
@@ -1602,16 +1456,10 @@ async function buildEvmMultisignBodyAaveV4MerklClaimRewards(args) {
1602
1456
  });
1603
1457
  }
1604
1458
  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
1459
  const to = getAddress(args.to);
1610
1460
  const executor = getAddress(args.executorAddress);
1611
1461
  return buildEvmMultisignBodyAaveV4OneStep({
1612
- ph,
1613
- keyList,
1614
- clientId: clientId ?? void 0,
1462
+ keyGen: args.keyGen,
1615
1463
  chainId: args.chainId,
1616
1464
  rpcUrl: args.rpcUrl,
1617
1465
  chainDetail: args.chainDetail,
@@ -1638,17 +1486,11 @@ async function buildEvmMultisignBodyEulerV2MerklDistributorClaim(args) {
1638
1486
  });
1639
1487
  }
1640
1488
  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
1489
  const to = getAddress(args.to);
1646
1490
  const executor = getAddress(args.executorAddress);
1647
1491
  const lossLabel = args.allowRemainderLoss ? "early unlock (remainder to receiver)" : "vested only";
1648
1492
  return buildEvmMultisignBodyAaveV4OneStep({
1649
- ph,
1650
- keyList,
1651
- clientId: clientId ?? void 0,
1493
+ keyGen: args.keyGen,
1652
1494
  chainId: args.chainId,
1653
1495
  rpcUrl: args.rpcUrl,
1654
1496
  chainDetail: args.chainDetail,
@@ -1681,151 +1523,32 @@ async function buildEvmMultisignBodyEulerV2ReulUnlock(args) {
1681
1523
  });
1682
1524
  }
1683
1525
  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] } }
1526
+ const firstDataNo0x = args.v.data.startsWith("0x") ? args.v.data.slice(2) : args.v.data;
1527
+ return buildEvmMultisignBatch({
1528
+ context: {
1529
+ chainCategory: "evm",
1530
+ keyGen: args.keyGen,
1531
+ purposeText: args.purposeText,
1532
+ chainId: args.chainId,
1533
+ rpcUrl: args.rpcUrl,
1534
+ executorAddress: args.executorAddress,
1535
+ chainDetail: args.chainDetail,
1536
+ useCustomGas: args.useCustomGas,
1537
+ customGasChainDetails: args.customGasChainDetails
1538
+ },
1539
+ steps: [
1540
+ {
1541
+ to: args.v.to,
1542
+ data: args.v.data,
1543
+ value: args.v.value,
1544
+ fallbackGas: args.estimateGasFallback
1545
+ }
1546
+ ],
1547
+ purposeSuffix: args.purposeSuffix,
1548
+ firstMsgRawNo0x: firstDataNo0x,
1549
+ destinationAddress: args.v.to,
1550
+ buildBatchMeta: ({ gasLimit }) => args.buildBatchMeta({ gasLimit })
1689
1551
  });
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
1552
  }
1830
1553
  var MIN_AAVE_V4_DEPOSIT_GAS_EXEC = 400000n;
1831
1554
  var AAVE_V4_EVM_TYPES = /* @__PURE__ */ new Set([