@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,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 = [];
@@ -562,20 +563,6 @@ function buildAaveV4BorrowTableRowsFromHub(borrowable, hubReserves, debtByUnderl
562
563
  };
563
564
  });
564
565
  }
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
566
  var spokeStaticAbi = [
580
567
  {
581
568
  name: "getReserveCount",
@@ -627,7 +614,7 @@ var spokeStaticAbi = [
627
614
  ];
628
615
  async function fetchAaveV4SpokeReserveIdForUnderlying(args) {
629
616
  const url = (args.rpcUrl ?? "").trim();
630
- if (!isValidRpcUrl(url)) return null;
617
+ if (!continuumNodeSdk.isValidRpcUrl(url)) return null;
631
618
  if (!Number.isFinite(args.chainId) || args.chainId < 0) return null;
632
619
  const spoke = viem.getAddress(args.spoke);
633
620
  const want = viem.getAddress(args.underlying).toLowerCase();
@@ -684,87 +671,234 @@ async function fetchAaveV4SpokeReserveStatusForUnderlying(args) {
684
671
  };
685
672
  }
686
673
 
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();
693
- }
694
- return null;
674
+ // src/core/purpose.ts
675
+ function mergePurposeText(purposeText, purposeSuffix) {
676
+ const t = purposeText.trim();
677
+ const suffix = (purposeSuffix ?? "").trim();
678
+ if (!suffix) return t;
679
+ return t ? `${t}
680
+
681
+ ${suffix}` : suffix;
695
682
  }
696
683
 
697
- // src/chains/evm/txParams.ts
698
- function gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit) {
699
- if (chainGasLimit == null || !Number.isFinite(chainGasLimit) || chainGasLimit <= 0) {
700
- return estimatedGas;
684
+ // src/core/envelope.ts
685
+ function finalizeMultisign(input) {
686
+ const { keyGen, destinationChainID, legs } = input;
687
+ if (legs.length === 0) {
688
+ throw new Error("finalizeMultisign requires at least one leg");
701
689
  }
702
- const cfg = BigInt(Math.floor(chainGasLimit));
703
- return cfg > estimatedGas ? cfg : estimatedGas;
690
+ const ph = (keyGen.pubkeyhex ?? "").trim();
691
+ if (!ph) throw new Error("keyGen pubKey (pubkeyhex) is required");
692
+ const keyList = keyGen.keylist ?? [];
693
+ const clientId = continuumNodeSdk.getClientIdFromKeyGenResult(keyGen);
694
+ const first = legs[0];
695
+ const messageHashes = legs.map((l) => l.msgHash);
696
+ const messageRawBatch = legs.map((l) => l.msgRaw);
697
+ const batchMeta = legs.map((l) => ({
698
+ destinationAddress: l.destinationAddress,
699
+ signatureText: l.signatureText,
700
+ ...l.audit
701
+ }));
702
+ const proposalTxParams = legs.map((l) => l.proposalTxParams).filter((p) => p != null && typeof p === "object");
703
+ const extraPayload = {
704
+ batchMeta,
705
+ ...input.extraJSON ?? {}
706
+ };
707
+ const extraJSON = JSON.stringify(extraPayload);
708
+ const bodyForSign = {
709
+ keyList,
710
+ pubKey: ph,
711
+ msgHash: messageHashes[0],
712
+ msgRaw: first.msgRaw,
713
+ destinationChainID,
714
+ destinationAddress: input.destinationAddress ?? first.destinationAddress,
715
+ extraJSON,
716
+ signatureText: first.signatureText,
717
+ purpose: mergePurposeText(input.purposeText, input.purposeSuffix),
718
+ ...first.feeSnapshot
719
+ };
720
+ if (legs.length > 1) {
721
+ bodyForSign.messageHashes = messageHashes;
722
+ bodyForSign.messageRawBatch = messageRawBatch;
723
+ }
724
+ if (proposalTxParams.length > 0) {
725
+ bodyForSign.proposalTxParams = proposalTxParams;
726
+ }
727
+ const valueWei = first.valueWei;
728
+ if (valueWei != null && valueWei > 0n) {
729
+ bodyForSign.value = valueWei.toString();
730
+ }
731
+ if (clientId) bodyForSign.clientId = clientId;
732
+ return { bodyForSign, messageToSign: JSON.stringify(bodyForSign) };
704
733
  }
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",
734
+ function routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimit) {
735
+ if (chainGasLimit != null && Number.isFinite(chainGasLimit) && chainGasLimit > 0) {
736
+ return continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, chainGasLimit);
737
+ }
738
+ return (estimatedGas * 12n + 9n) / 10n;
739
+ }
740
+
741
+ // src/chains/evm/buildBatch.ts
742
+ async function buildEvmMultisignBatch(args) {
743
+ const { context, steps } = args;
744
+ const {
745
+ chainId,
746
+ rpcUrl,
747
+ executorAddress,
748
+ chainDetail,
749
+ useCustomGas,
750
+ customGasChainDetails,
751
+ keyGen,
752
+ purposeText
753
+ } = context;
754
+ if (steps.length === 0) throw new Error("buildEvmMultisignBatch requires at least one step");
755
+ const ch = viem.defineChain({
756
+ id: chainId,
757
+ name: "Destination",
713
758
  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)
759
+ rpcUrls: { default: { http: [rpcUrl] } }
719
760
  });
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 };
761
+ const publicClient = viem.createPublicClient({ chain: ch, transport: viem.http(rpcUrl) });
762
+ const feeParams = await continuumNodeSdk.fetchChainFeeParams(rpcUrl, chainId);
763
+ const legacy = Boolean(chainDetail?.legacy) || !feeParams.isEip1559;
764
+ const latestBaseFeeWei = !legacy ? (await publicClient.getBlock({ blockTag: "latest" })).baseFeePerGas ?? 0n : 0n;
765
+ const gasLimitConfig = useCustomGas && chainDetail?.gasLimit != null ? Number(chainDetail.gasLimit) : void 0;
766
+ const chainGasLimitRouter = chainDetail?.gasLimit != null && Number.isFinite(Number(chainDetail.gasLimit)) && Number(chainDetail.gasLimit) > 0 ? Number(chainDetail.gasLimit) : void 0;
767
+ const gasFeeMultiplier = useCustomGas && chainDetail?.gasMultiplier != null ? Number(chainDetail.gasMultiplier) : void 0;
768
+ const executor = viem.getAddress(executorAddress);
769
+ const baseNonce = await publicClient.getTransactionCount({ address: executor, blockTag: "pending" });
770
+ const legs = [];
771
+ for (let i = 0; i < steps.length; i++) {
772
+ const step = steps[i];
773
+ const currentNonce = baseNonce + i;
774
+ let estimatedGas;
775
+ if (args.estimateGasForStep) {
776
+ estimatedGas = await args.estimateGasForStep({ step, index: i, publicClient, executor });
777
+ } else {
778
+ try {
779
+ estimatedGas = await publicClient.estimateGas({
780
+ to: step.to,
781
+ data: step.data,
782
+ value: step.value,
783
+ account: executor
784
+ });
785
+ } catch {
786
+ estimatedGas = step.fallbackGas ?? 100000n;
787
+ }
730
788
  }
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 {
789
+ let gasLimitI;
790
+ if (args.resolveGasLimit) {
791
+ gasLimitI = await args.resolveGasLimit({ step, index: i, estimatedGas, publicClient });
792
+ } else if (step.routerSwap) {
793
+ gasLimitI = routerSwapGasLimitFromEstimate(estimatedGas, chainGasLimitRouter);
794
+ } else {
795
+ gasLimitI = useCustomGas ? continuumNodeSdk.gasLimitFromEstimateAndChainConfig(estimatedGas, gasLimitConfig) : estimatedGas;
737
796
  }
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 };
797
+ let proposalTxParams;
798
+ let feeSnapshot;
799
+ let serialized;
800
+ if (legacy) {
801
+ let gasPriceWei = await publicClient.getGasPrice();
802
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
803
+ gasPriceWei = gasPriceWei * BigInt(100 + gasFeeMultiplier) / 100n;
804
+ }
805
+ if (useCustomGas && chainDetail?.gasPrice != null && chainDetail.gasPrice > 0) {
806
+ const configured = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(Number(chainDetail.gasPrice)));
807
+ if (configured > gasPriceWei) gasPriceWei = configured;
808
+ }
809
+ serialized = viem.serializeTransaction({
810
+ type: "legacy",
811
+ to: step.to,
812
+ data: step.data,
813
+ value: step.value,
814
+ gas: gasLimitI,
815
+ gasPrice: gasPriceWei,
816
+ nonce: currentNonce,
817
+ chainId
818
+ });
819
+ proposalTxParams = {
820
+ nonce: currentNonce,
821
+ gasLimit: gasLimitI.toString(),
822
+ txType: "legacy",
823
+ gasPrice: gasPriceWei.toString()
824
+ };
825
+ feeSnapshot = continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams);
826
+ } else {
827
+ const fetchedBase = feeParams.baseFeeGwei ?? 0;
828
+ const fetchedPriority = feeParams.priorityFeeGwei ?? 0;
829
+ const configuredBase = useCustomGas && chainDetail?.baseFee != null ? Number(chainDetail.baseFee) : 0;
830
+ const configuredPriority = useCustomGas && chainDetail?.priorityFee != null ? Number(chainDetail.priorityFee) : 0;
831
+ const effectiveBaseFeeGwei = Math.max(fetchedBase, configuredBase);
832
+ const effectivePriorityFeeGwei = Math.max(fetchedPriority, configuredPriority);
833
+ const baseFeeMultiplierPct = useCustomGas && chainDetail?.baseFeeMultiplier != null ? Math.max(100, Number(chainDetail.baseFeeMultiplier)) : 100;
834
+ const baseComponentGwei = effectiveBaseFeeGwei * baseFeeMultiplierPct / 100;
835
+ const maxFeePerGasGwei = baseComponentGwei + effectivePriorityFeeGwei;
836
+ let maxPriorityFeePerGas = effectivePriorityFeeGwei > 0 ? viem.parseGwei(continuumNodeSdk.gweiToDecimalString(effectivePriorityFeeGwei)) : viem.parseGwei("1");
837
+ let maxFeePerGas = viem.parseGwei(continuumNodeSdk.gweiToDecimalString(maxFeePerGasGwei));
838
+ if (useCustomGas && gasFeeMultiplier != null && gasFeeMultiplier > 0) {
839
+ maxPriorityFeePerGas = maxPriorityFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
840
+ maxFeePerGas = maxFeePerGas * BigInt(100 + gasFeeMultiplier) / 100n;
841
+ }
842
+ ({ maxFeePerGas, maxPriorityFeePerGas } = continuumNodeSdk.alignEip1559FeesWithLatestBase(
843
+ maxFeePerGas,
844
+ maxPriorityFeePerGas,
845
+ latestBaseFeeWei
846
+ ));
847
+ serialized = viem.serializeTransaction({
848
+ type: "eip1559",
849
+ to: step.to,
850
+ data: step.data,
851
+ value: step.value,
852
+ gas: gasLimitI,
853
+ maxFeePerGas,
854
+ maxPriorityFeePerGas,
855
+ nonce: currentNonce,
856
+ chainId
857
+ });
858
+ proposalTxParams = {
859
+ nonce: currentNonce,
860
+ gasLimit: gasLimitI.toString(),
861
+ txType: "eip1559",
862
+ maxFeePerGas: maxFeePerGas.toString(),
863
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
864
+ };
865
+ feeSnapshot = i === 0 ? continuumNodeSdk.proposalTxParamsToFeeSnapshot(proposalTxParams) : {};
866
+ }
867
+ const h = viem.keccak256(serialized);
868
+ const msgHash = h.startsWith("0x") ? h.slice(2) : h;
869
+ const batchMetaExtra = args.buildBatchMeta({ step, index: i, gasLimit: gasLimitI });
870
+ legs.push({
871
+ msgHash,
872
+ msgRaw: i === 0 && args.firstMsgRawNo0x != null ? args.firstMsgRawNo0x : serialized,
873
+ destinationAddress: step.to,
874
+ signatureText: typeof batchMetaExtra.signatureText === "string" ? batchMetaExtra.signatureText : JSON.stringify(batchMetaExtra.signatureText ?? {}),
875
+ audit: batchMetaExtra,
876
+ feeSnapshot: i === 0 ? feeSnapshot : {},
877
+ proposalTxParams,
878
+ valueWei: i === 0 ? step.value : void 0
879
+ });
880
+ if (i === 0 && args.firstMsgRawNo0x != null) {
881
+ legs[0].msgRaw = args.firstMsgRawNo0x;
752
882
  }
753
883
  }
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");
884
+ const extraJSON = {};
885
+ if (useCustomGas && customGasChainDetails && Object.keys(customGasChainDetails).length > 0) {
886
+ extraJSON.customGasChainDetails = customGasChainDetails;
760
887
  }
761
- if (maxF < maxP) {
762
- maxF = baseWei > 0n ? baseWei + maxP + viem.parseGwei("0.001") : maxP * 2n;
888
+ const result = finalizeMultisign({
889
+ keyGen,
890
+ purposeText,
891
+ purposeSuffix: args.purposeSuffix,
892
+ destinationChainID: String(chainId),
893
+ destinationAddress: args.destinationAddress ?? steps[0].to,
894
+ legs,
895
+ extraJSON: Object.keys(extraJSON).length > 0 ? extraJSON : void 0
896
+ });
897
+ const pv = args.payableValueWei;
898
+ if (pv != null && pv > 0n) {
899
+ result.bodyForSign.value = pv.toString();
763
900
  }
764
- return { maxFeePerGas: maxF, maxPriorityFeePerGas: maxP };
765
- }
766
- function alignEip1559FeesWithLatestBase(maxFeePerGas, maxPriorityFeePerGas, latestBlockBaseFeeWei) {
767
- return finalizeEip1559Fees(maxFeePerGas, maxPriorityFeePerGas, null, latestBlockBaseFeeWei);
901
+ return result;
768
902
  }
769
903
 
770
904
  // src/protocols/evm/aave-v4/multisign.ts
@@ -781,16 +915,6 @@ var AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS = 1000000n;
781
915
  var AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK = AAVE_V4_SPOKE_REPAY_DEFAULT_GAS_UNITS;
782
916
  var AAVE_MERKL_CLAIM_ESTIMATE_FALLBACK = 500000n;
783
917
  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
918
  var wethDepositAbi = viem.parseAbi(["function deposit() payable"]);
795
919
  var erc20AllowanceAbi = viem.parseAbi([
796
920
  "function allowance(address owner, address spender) view returns (uint256)",
@@ -805,10 +929,6 @@ var spokeSetUsingAsCollateralAbi = viem.parseAbi([
805
929
  "function setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)"
806
930
  ]);
807
931
  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
932
  const asset = viem.getAddress(args.asset);
813
933
  const spoke = viem.getAddress(args.spoke);
814
934
  const weth = viem.getAddress(args.nativeWrapped);
@@ -906,172 +1026,102 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
906
1026
  });
907
1027
  steps.push({ kind: "set_collateral", to: spoke, data: setCollateralData, value: 0n });
908
1028
  }
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
1029
  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;
1030
+ const evmSteps = steps.map((s) => ({
1031
+ to: s.to,
1032
+ data: s.data,
1033
+ value: s.value,
1034
+ 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
1035
+ }));
1036
+ const n = steps.length;
1037
+ const hasWrap = args.isNativeIn;
1038
+ const withCollateral = args.enableAsCollateralAfterSupply === true;
1039
+ const purposeSuffix = (() => {
1040
+ if (hasWrap) {
1041
+ 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
1042
  }
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;
1043
+ if (n === 1) {
1044
+ return "Aave v4: 1-tx \u2014 supply (allowance already sufficient).";
1045
+ }
1046
+ if (withCollateral && n === 2) {
1047
+ return "Aave v4: 2-tx batch \u2014 supply (allowance already sufficient), then setUsingAsCollateral.";
1048
+ }
1049
+ if (withCollateral) {
1050
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, supply, then setUsingAsCollateral.`;
1051
+ }
1052
+ return `Aave v4: ${n}-tx batch \u2014 approve spoke for the exact amount, then supply.`;
1053
+ })();
1054
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1055
+ return buildEvmMultisignBatch({
1056
+ context: {
1057
+ chainCategory: "evm",
1058
+ keyGen: args.keyGen,
1059
+ purposeText: args.purposeText,
1060
+ chainId: args.chainId,
1061
+ rpcUrl: args.rpcUrl,
1062
+ executorAddress: executor,
1063
+ chainDetail: args.chainDetail,
1064
+ useCustomGas: args.useCustomGas,
1065
+ customGasChainDetails: args.customGasChainDetails
1066
+ },
1067
+ steps: evmSteps,
1068
+ purposeSuffix,
1069
+ firstMsgRawNo0x: firstDataNo0x,
1070
+ destinationAddress: steps[0].to,
1071
+ buildBatchMeta: ({ index, gasLimit }) => {
1072
+ const s = steps[index];
1073
+ if (s.kind === "weth_deposit") {
1074
+ return {
1075
+ signatureText: JSON.stringify({
1076
+ kind: "AaveV4",
1077
+ name: "WETH.deposit",
1078
+ function: "deposit()",
1079
+ valueWei: amountWei.toString(),
1080
+ market: marketLabel,
1081
+ note: "Wrap native to WETH, then supply to Aave v4 (same batch)."
1082
+ }),
1083
+ evm: { type: "aave_v4_weth_deposit", version: 1, chainId: String(args.chainId) },
1084
+ aaveV4: { step: "weth_deposit", market: marketLabel, amountHuman: args.amountHuman, hubAsset: asset }
1085
+ };
973
1086
  }
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;
1087
+ if (s.kind === "approve") {
1088
+ return {
1089
+ signatureText: JSON.stringify({
1090
+ kind: "AaveV4",
1091
+ name: "ERC20.approve",
1092
+ to: "Aave v4 spoke",
1093
+ function: "approve(address spender, uint256 amount)",
1094
+ spoke,
1095
+ amountHuman: args.amountHuman,
1096
+ note: "Allowance for this supply amount only (not unlimited)."
1097
+ }),
1098
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1099
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke }
1100
+ };
989
1101
  }
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()
1102
+ if (s.kind === "set_collateral") {
1103
+ return {
1104
+ signatureText: JSON.stringify({
1105
+ kind: "AaveV4",
1106
+ name: "Spoke.setUsingAsCollateral",
1107
+ function: "setUsingAsCollateral(uint256 reserveId, bool usingAsCollateral, address onBehalfOf)",
1108
+ reserveId: reserveId.toString(),
1109
+ usingAsCollateral: true,
1110
+ onBehalfOf: onBehalf,
1111
+ market: marketLabel,
1112
+ note: "Enables this supplied reserve as collateral for borrowing (after supply in the same batch)."
1113
+ }),
1114
+ evm: { type: "aave_v4_spoke_set_using_as_collateral", version: 1, chainId: String(args.chainId) },
1115
+ aaveV4: {
1116
+ market: marketLabel,
1117
+ asset,
1118
+ spoke,
1119
+ reserveId: reserveId.toString(),
1120
+ gasBuildSetCollateral: { baseGasUnits: gasLimit.toString() }
1121
+ }
1022
1122
  };
1023
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1024
1123
  }
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,
1124
+ return {
1075
1125
  signatureText: JSON.stringify({
1076
1126
  kind: "AaveV4",
1077
1127
  name: "Spoke.supply",
@@ -1089,67 +1139,13 @@ async function buildEvmMultisignBodyAaveV4DepositBatch(args) {
1089
1139
  asset,
1090
1140
  spoke,
1091
1141
  reserveId: reserveId.toString(),
1092
- gasBuildSupply: { baseGasUnits: gasLimitI.toString() }
1142
+ gasBuildSupply: { baseGasUnits: gasLimit.toString() }
1093
1143
  }
1094
- });
1144
+ };
1095
1145
  }
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).";
1112
- }
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) };
1146
+ });
1147
1147
  }
1148
1148
  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
1149
  const asset = viem.getAddress(args.underlying);
1154
1150
  const spoke = viem.getAddress(args.spoke);
1155
1151
  const onBehalf = viem.getAddress(args.onBehalfOf);
@@ -1190,9 +1186,7 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1190
1186
  });
1191
1187
  const tx = { to: spoke, data, value: 0n };
1192
1188
  return buildEvmMultisignBodyAaveV4OneStep({
1193
- ph,
1194
- keyList,
1195
- clientId: clientId ?? void 0,
1189
+ keyGen: args.keyGen,
1196
1190
  chainId: args.chainId,
1197
1191
  rpcUrl: args.rpcUrl,
1198
1192
  chainDetail: args.chainDetail,
@@ -1228,10 +1222,6 @@ async function buildEvmMultisignBodyAaveV4SpokeWithdraw(args) {
1228
1222
  });
1229
1223
  }
1230
1224
  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
1225
  const asset = viem.getAddress(args.underlying);
1236
1226
  const spoke = viem.getAddress(args.spoke);
1237
1227
  const onBehalf = viem.getAddress(args.onBehalfOf);
@@ -1272,9 +1262,7 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1272
1262
  });
1273
1263
  const tx = { to: spoke, data, value: 0n };
1274
1264
  return buildEvmMultisignBodyAaveV4OneStep({
1275
- ph,
1276
- keyList,
1277
- clientId: clientId ?? void 0,
1265
+ keyGen: args.keyGen,
1278
1266
  chainId: args.chainId,
1279
1267
  rpcUrl: args.rpcUrl,
1280
1268
  chainDetail: args.chainDetail,
@@ -1310,10 +1298,6 @@ async function buildEvmMultisignBodyAaveV4SpokeBorrow(args) {
1310
1298
  });
1311
1299
  }
1312
1300
  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
1301
  const asset = viem.getAddress(args.underlying);
1318
1302
  const spoke = viem.getAddress(args.spoke);
1319
1303
  const onBehalf = viem.getAddress(args.onBehalfOf);
@@ -1376,140 +1360,50 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1376
1360
  args: [reserveId, amountWei, onBehalf]
1377
1361
  });
1378
1362
  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
1363
  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()
1364
+ const evmSteps = steps.map((s) => ({
1365
+ to: s.to,
1366
+ data: s.data,
1367
+ value: s.value,
1368
+ fallbackGas: s.kind === "approve" ? AAVE_ERC20_APPROVE_FALLBACK : AAVE_SPOKE_REPAY_ESTIMATE_FALLBACK
1369
+ }));
1370
+ const n = steps.length;
1371
+ const purposeSuffix = `Aave v4: ${n}-tx batch \u2014 approve spoke if needed, then repay ${(args.amountHuman || "").trim() || "\u2026"} of debt.`;
1372
+ const firstDataNo0x = evmSteps[0].data.startsWith("0x") ? evmSteps[0].data.slice(2) : evmSteps[0].data;
1373
+ return buildEvmMultisignBatch({
1374
+ context: {
1375
+ chainCategory: "evm",
1376
+ keyGen: args.keyGen,
1377
+ purposeText: args.purposeText,
1378
+ chainId: args.chainId,
1379
+ rpcUrl: args.rpcUrl,
1380
+ executorAddress: executor,
1381
+ chainDetail: args.chainDetail,
1382
+ useCustomGas: args.useCustomGas,
1383
+ customGasChainDetails: args.customGasChainDetails
1384
+ },
1385
+ steps: evmSteps,
1386
+ purposeSuffix,
1387
+ firstMsgRawNo0x: firstDataNo0x,
1388
+ destinationAddress: steps[0].to,
1389
+ buildBatchMeta: ({ index, gasLimit }) => {
1390
+ const s = steps[index];
1391
+ if (s.kind === "approve") {
1392
+ return {
1393
+ signatureText: JSON.stringify({
1394
+ kind: "AaveV4",
1395
+ name: "ERC20.approve (repay)",
1396
+ to: "Aave v4 spoke",
1397
+ function: "approve(address spender, uint256 amount)",
1398
+ spoke,
1399
+ amountHuman: args.amountHuman,
1400
+ note: "Allowance to repay this amount (or reset+approve to exact amount)."
1401
+ }),
1402
+ evm: { type: "aave_v4_erc20_approve", version: 1, chainId: String(args.chainId) },
1403
+ aaveV4: { market: marketLabel, amountHuman: args.amountHuman, spoke, step: "repay_prepare" }
1490
1404
  };
1491
- firstDataNo0x = v.data.startsWith("0x") ? v.data.slice(2) : v.data;
1492
1405
  }
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,
1406
+ return {
1513
1407
  signatureText: JSON.stringify({
1514
1408
  kind: "AaveV4",
1515
1409
  name: "Spoke.repay",
@@ -1527,57 +1421,17 @@ async function buildEvmMultisignBodyAaveV4SpokeRepay(args) {
1527
1421
  asset,
1528
1422
  spoke,
1529
1423
  reserveId: reserveId.toString(),
1530
- gasBuildRepay: { baseGasUnits: gasLimitI.toString() }
1424
+ gasBuildRepay: { baseGasUnits: gasLimit.toString() }
1531
1425
  }
1532
- });
1426
+ };
1533
1427
  }
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) };
1428
+ });
1569
1429
  }
1570
1430
  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
1431
  const to = viem.getAddress(args.to);
1576
1432
  const executor = viem.getAddress(args.executorAddress);
1577
1433
  return buildEvmMultisignBodyAaveV4OneStep({
1578
- ph,
1579
- keyList,
1580
- clientId: clientId ?? void 0,
1434
+ keyGen: args.keyGen,
1581
1435
  chainId: args.chainId,
1582
1436
  rpcUrl: args.rpcUrl,
1583
1437
  chainDetail: args.chainDetail,
@@ -1604,16 +1458,10 @@ async function buildEvmMultisignBodyAaveV4MerklClaimRewards(args) {
1604
1458
  });
1605
1459
  }
1606
1460
  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
1461
  const to = viem.getAddress(args.to);
1612
1462
  const executor = viem.getAddress(args.executorAddress);
1613
1463
  return buildEvmMultisignBodyAaveV4OneStep({
1614
- ph,
1615
- keyList,
1616
- clientId: clientId ?? void 0,
1464
+ keyGen: args.keyGen,
1617
1465
  chainId: args.chainId,
1618
1466
  rpcUrl: args.rpcUrl,
1619
1467
  chainDetail: args.chainDetail,
@@ -1640,17 +1488,11 @@ async function buildEvmMultisignBodyEulerV2MerklDistributorClaim(args) {
1640
1488
  });
1641
1489
  }
1642
1490
  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
1491
  const to = viem.getAddress(args.to);
1648
1492
  const executor = viem.getAddress(args.executorAddress);
1649
1493
  const lossLabel = args.allowRemainderLoss ? "early unlock (remainder to receiver)" : "vested only";
1650
1494
  return buildEvmMultisignBodyAaveV4OneStep({
1651
- ph,
1652
- keyList,
1653
- clientId: clientId ?? void 0,
1495
+ keyGen: args.keyGen,
1654
1496
  chainId: args.chainId,
1655
1497
  rpcUrl: args.rpcUrl,
1656
1498
  chainDetail: args.chainDetail,
@@ -1683,151 +1525,32 @@ async function buildEvmMultisignBodyEulerV2ReulUnlock(args) {
1683
1525
  });
1684
1526
  }
1685
1527
  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] } }
1528
+ const firstDataNo0x = args.v.data.startsWith("0x") ? args.v.data.slice(2) : args.v.data;
1529
+ return buildEvmMultisignBatch({
1530
+ context: {
1531
+ chainCategory: "evm",
1532
+ keyGen: args.keyGen,
1533
+ purposeText: args.purposeText,
1534
+ chainId: args.chainId,
1535
+ rpcUrl: args.rpcUrl,
1536
+ executorAddress: args.executorAddress,
1537
+ chainDetail: args.chainDetail,
1538
+ useCustomGas: args.useCustomGas,
1539
+ customGasChainDetails: args.customGasChainDetails
1540
+ },
1541
+ steps: [
1542
+ {
1543
+ to: args.v.to,
1544
+ data: args.v.data,
1545
+ value: args.v.value,
1546
+ fallbackGas: args.estimateGasFallback
1547
+ }
1548
+ ],
1549
+ purposeSuffix: args.purposeSuffix,
1550
+ firstMsgRawNo0x: firstDataNo0x,
1551
+ destinationAddress: args.v.to,
1552
+ buildBatchMeta: ({ gasLimit }) => args.buildBatchMeta({ gasLimit })
1691
1553
  });
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
1554
  }
1832
1555
  var MIN_AAVE_V4_DEPOSIT_GAS_EXEC = 400000n;
1833
1556
  var AAVE_V4_EVM_TYPES = /* @__PURE__ */ new Set([