@hypurrquant/defi-cli 0.2.4 → 0.3.0

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.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { Command } from "commander";
5
5
  import { createRequire } from "module";
6
6
 
7
7
  // src/executor.ts
8
- import { createPublicClient as createPublicClient2, createWalletClient, http as http2 } from "viem";
8
+ import { createPublicClient as createPublicClient2, createWalletClient, http as http2, parseAbi as parseAbi3, encodeFunctionData as encodeFunctionData3 } from "viem";
9
9
  import { privateKeyToAccount } from "viem/accounts";
10
10
 
11
11
  // ../defi-core/dist/index.js
@@ -703,6 +703,16 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
703
703
 
704
704
  // ../defi-core/dist/index.js
705
705
  import { existsSync } from "fs";
706
+ var TxStatus = /* @__PURE__ */ ((TxStatus2) => {
707
+ TxStatus2["DryRun"] = "dry_run";
708
+ TxStatus2["Simulated"] = "simulated";
709
+ TxStatus2["SimulationFailed"] = "simulation_failed";
710
+ TxStatus2["NeedsApproval"] = "needs_approval";
711
+ TxStatus2["Pending"] = "pending";
712
+ TxStatus2["Confirmed"] = "confirmed";
713
+ TxStatus2["Failed"] = "failed";
714
+ return TxStatus2;
715
+ })(TxStatus || {});
706
716
  var InterestRateMode = /* @__PURE__ */ ((InterestRateMode2) => {
707
717
  InterestRateMode2["Variable"] = "variable";
708
718
  InterestRateMode2["Stable"] = "stable";
@@ -864,6 +874,10 @@ async function multicallRead(rpcUrl, calls) {
864
874
  });
865
875
  return decoded.map((r) => r.success ? r.returnData : null);
866
876
  }
877
+ function decodeU256(data) {
878
+ if (!data || data.length < 66) return 0n;
879
+ return BigInt(data.slice(0, 66));
880
+ }
867
881
  var ChainConfig = class {
868
882
  name;
869
883
  chain_id;
@@ -1008,8 +1022,13 @@ var Registry = class _Registry {
1008
1022
  };
1009
1023
 
1010
1024
  // src/executor.ts
1025
+ var ERC20_ABI = parseAbi3([
1026
+ "function allowance(address owner, address spender) external view returns (uint256)",
1027
+ "function approve(address spender, uint256 amount) external returns (bool)"
1028
+ ]);
1011
1029
  var GAS_BUFFER_BPS = 12000n;
1012
- var DEFAULT_PRIORITY_FEE_WEI = 100000000n;
1030
+ var DEFAULT_PRIORITY_FEE_WEI = 20000000000n;
1031
+ var MAX_GAS_LIMIT = 5000000000n;
1013
1032
  var Executor = class _Executor {
1014
1033
  dryRun;
1015
1034
  rpcUrl;
@@ -1023,6 +1042,62 @@ var Executor = class _Executor {
1023
1042
  static applyGasBuffer(gas) {
1024
1043
  return gas * GAS_BUFFER_BPS / 10000n;
1025
1044
  }
1045
+ /**
1046
+ * Check allowance for a single token/spender pair and send an approve tx if needed.
1047
+ * Only called in broadcast mode (not dry-run).
1048
+ */
1049
+ async checkAndApprove(token, spender, amount, owner, publicClient, walletClient) {
1050
+ const allowance = await publicClient.readContract({
1051
+ address: token,
1052
+ abi: ERC20_ABI,
1053
+ functionName: "allowance",
1054
+ args: [owner, spender]
1055
+ });
1056
+ if (allowance >= amount) return;
1057
+ process.stderr.write(
1058
+ ` Approving ${amount} of ${token} for ${spender}...
1059
+ `
1060
+ );
1061
+ const approveData = encodeFunctionData3({
1062
+ abi: ERC20_ABI,
1063
+ functionName: "approve",
1064
+ args: [spender, amount]
1065
+ });
1066
+ const rpcUrl = this.rpcUrl;
1067
+ const gasLimit = await (async () => {
1068
+ try {
1069
+ const estimated = await publicClient.estimateGas({
1070
+ to: token,
1071
+ data: approveData,
1072
+ account: owner
1073
+ });
1074
+ const buffered = _Executor.applyGasBuffer(estimated);
1075
+ return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
1076
+ } catch {
1077
+ return 80000n;
1078
+ }
1079
+ })();
1080
+ const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
1081
+ const approveTxHash = await walletClient.sendTransaction({
1082
+ chain: null,
1083
+ account: walletClient.account,
1084
+ to: token,
1085
+ data: approveData,
1086
+ gas: gasLimit > 0n ? gasLimit : void 0,
1087
+ maxFeePerGas: maxFeePerGas > 0n ? maxFeePerGas : void 0,
1088
+ maxPriorityFeePerGas: maxPriorityFeePerGas > 0n ? maxPriorityFeePerGas : void 0
1089
+ });
1090
+ const approveTxUrl = this.explorerUrl ? `${this.explorerUrl}/tx/${approveTxHash}` : void 0;
1091
+ process.stderr.write(` Approve tx: ${approveTxHash}
1092
+ `);
1093
+ if (approveTxUrl) process.stderr.write(` Explorer: ${approveTxUrl}
1094
+ `);
1095
+ await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
1096
+ process.stderr.write(
1097
+ ` Approved ${amount} of ${token} for ${spender}
1098
+ `
1099
+ );
1100
+ }
1026
1101
  /** Fetch EIP-1559 fee params from the network. Returns [maxFeePerGas, maxPriorityFeePerGas]. */
1027
1102
  async fetchEip1559Fees(rpcUrl) {
1028
1103
  try {
@@ -1049,7 +1124,10 @@ var Executor = class _Executor {
1049
1124
  value: tx.value,
1050
1125
  account: from
1051
1126
  });
1052
- if (estimated > 0n) return _Executor.applyGasBuffer(estimated);
1127
+ if (estimated > 0n) {
1128
+ const buffered = _Executor.applyGasBuffer(estimated);
1129
+ return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
1130
+ }
1053
1131
  } catch {
1054
1132
  }
1055
1133
  return tx.gas_estimate ? BigInt(tx.gas_estimate) : 0n;
@@ -1063,6 +1141,46 @@ var Executor = class _Executor {
1063
1141
  const client = createPublicClient2({ transport: http2(rpcUrl) });
1064
1142
  const privateKey = process.env["DEFI_PRIVATE_KEY"];
1065
1143
  const from = privateKey ? privateKeyToAccount(privateKey).address : "0x0000000000000000000000000000000000000001";
1144
+ if (tx.approvals && tx.approvals.length > 0) {
1145
+ const pendingApprovals = [];
1146
+ for (const approval of tx.approvals) {
1147
+ try {
1148
+ const allowance = await client.readContract({
1149
+ address: approval.token,
1150
+ abi: ERC20_ABI,
1151
+ functionName: "allowance",
1152
+ args: [from, approval.spender]
1153
+ });
1154
+ if (allowance < approval.amount) {
1155
+ pendingApprovals.push({
1156
+ token: approval.token,
1157
+ spender: approval.spender,
1158
+ needed: approval.amount.toString(),
1159
+ current: allowance.toString()
1160
+ });
1161
+ }
1162
+ } catch {
1163
+ }
1164
+ }
1165
+ if (pendingApprovals.length > 0) {
1166
+ return {
1167
+ tx_hash: void 0,
1168
+ status: TxStatus.NeedsApproval,
1169
+ gas_used: tx.gas_estimate,
1170
+ description: tx.description,
1171
+ details: {
1172
+ to: tx.to,
1173
+ from,
1174
+ data: tx.data,
1175
+ value: tx.value.toString(),
1176
+ mode: "simulated",
1177
+ result: "needs_approval",
1178
+ pending_approvals: pendingApprovals,
1179
+ hint: "Use --broadcast to auto-approve and execute"
1180
+ }
1181
+ };
1182
+ }
1183
+ }
1066
1184
  try {
1067
1185
  await client.call({ to: tx.to, data: tx.data, value: tx.value, account: from });
1068
1186
  const gasEstimate = await this.estimateGasWithBuffer(rpcUrl, tx, from);
@@ -1135,6 +1253,18 @@ var Executor = class _Executor {
1135
1253
  }
1136
1254
  const publicClient = createPublicClient2({ transport: http2(rpcUrl) });
1137
1255
  const walletClient = createWalletClient({ account, transport: http2(rpcUrl) });
1256
+ if (tx.approvals && tx.approvals.length > 0) {
1257
+ for (const approval of tx.approvals) {
1258
+ await this.checkAndApprove(
1259
+ approval.token,
1260
+ approval.spender,
1261
+ approval.amount,
1262
+ account.address,
1263
+ publicClient,
1264
+ walletClient
1265
+ );
1266
+ }
1267
+ }
1138
1268
  const gasLimit = await this.estimateGasWithBuffer(rpcUrl, tx, account.address);
1139
1269
  const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
1140
1270
  process.stderr.write(`Broadcasting transaction to ${rpcUrl}...
@@ -1711,45 +1841,52 @@ function registerSchema(parent, getOpts) {
1711
1841
  }
1712
1842
 
1713
1843
  // ../defi-protocols/dist/index.js
1714
- import { encodeFunctionData as encodeFunctionData3, parseAbi as parseAbi3, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters } from "viem";
1844
+ import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters } from "viem";
1715
1845
  import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, createPublicClient as createPublicClient22, http as http22, decodeFunctionResult as decodeFunctionResult2, decodeAbiParameters as decodeAbiParameters2 } from "viem";
1716
1846
  import { encodeFunctionData as encodeFunctionData32, parseAbi as parseAbi32, createPublicClient as createPublicClient32, http as http32, decodeAbiParameters as decodeAbiParameters3, concatHex, zeroAddress } from "viem";
1717
- import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4, zeroAddress as zeroAddress2 } from "viem";
1847
+ import { encodeFunctionData as encodeFunctionData42, parseAbi as parseAbi42, zeroAddress as zeroAddress2 } from "viem";
1718
1848
  import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
1719
- import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, createPublicClient as createPublicClient42, http as http42, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1849
+ import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1720
1850
  import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, zeroAddress as zeroAddress3 } from "viem";
1721
- import { createPublicClient as createPublicClient5, encodeFunctionData as encodeFunctionData8, http as http5, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1722
- import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, createPublicClient as createPublicClient6, http as http6 } from "viem";
1723
- import { createPublicClient as createPublicClient7, http as http7, parseAbi as parseAbi10, encodeFunctionData as encodeFunctionData10, zeroAddress as zeroAddress5 } from "viem";
1724
- import { createPublicClient as createPublicClient8, http as http8, parseAbi as parseAbi11, encodeFunctionData as encodeFunctionData11, zeroAddress as zeroAddress6 } from "viem";
1725
- import { createPublicClient as createPublicClient9, http as http9, parseAbi as parseAbi12 } from "viem";
1726
- import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi13, encodeFunctionData as encodeFunctionData12 } from "viem";
1727
- import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData13 } from "viem";
1728
- import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData14 } from "viem";
1729
- import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi16, encodeFunctionData as encodeFunctionData15, zeroAddress as zeroAddress7 } from "viem";
1730
- import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16, zeroAddress as zeroAddress8 } from "viem";
1731
- import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi18 } from "viem";
1732
- import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi19, encodeFunctionData as encodeFunctionData17 } from "viem";
1733
- import { parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData18 } from "viem";
1734
- import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData19, zeroAddress as zeroAddress9 } from "viem";
1735
- import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi222, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress10 } from "viem";
1736
- import { parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } from "viem";
1851
+ import { createPublicClient as createPublicClient42, encodeFunctionData as encodeFunctionData8, http as http42, parseAbi as parseAbi8, zeroAddress as zeroAddress4 } from "viem";
1852
+ import { encodeFunctionData as encodeFunctionData9, parseAbi as parseAbi9, createPublicClient as createPublicClient5, http as http5 } from "viem";
1853
+ import {
1854
+ encodeFunctionData as encodeFunctionData10,
1855
+ decodeFunctionResult as decodeFunctionResult22,
1856
+ parseAbi as parseAbi10,
1857
+ createPublicClient as createPublicClient6,
1858
+ http as http6
1859
+ } from "viem";
1860
+ import { createPublicClient as createPublicClient7, http as http7, parseAbi as parseAbi11, encodeFunctionData as encodeFunctionData11, decodeFunctionResult as decodeFunctionResult3, zeroAddress as zeroAddress5 } from "viem";
1861
+ import { createPublicClient as createPublicClient8, http as http8, parseAbi as parseAbi12, encodeFunctionData as encodeFunctionData12, zeroAddress as zeroAddress6 } from "viem";
1862
+ import { createPublicClient as createPublicClient9, http as http9, parseAbi as parseAbi13 } from "viem";
1863
+ import { createPublicClient as createPublicClient10, http as http10, parseAbi as parseAbi14, encodeFunctionData as encodeFunctionData13 } from "viem";
1864
+ import { createPublicClient as createPublicClient11, http as http11, parseAbi as parseAbi15, encodeFunctionData as encodeFunctionData14 } from "viem";
1865
+ import { createPublicClient as createPublicClient12, http as http12, parseAbi as parseAbi16, encodeFunctionData as encodeFunctionData15 } from "viem";
1866
+ import { parseAbi as parseAbi17, encodeFunctionData as encodeFunctionData16, decodeFunctionResult as decodeFunctionResult4, zeroAddress as zeroAddress7 } from "viem";
1867
+ import { createPublicClient as createPublicClient13, http as http13, parseAbi as parseAbi18, encodeFunctionData as encodeFunctionData17, zeroAddress as zeroAddress8 } from "viem";
1868
+ import { createPublicClient as createPublicClient14, http as http14, parseAbi as parseAbi19 } from "viem";
1869
+ import { createPublicClient as createPublicClient15, http as http15, parseAbi as parseAbi20, encodeFunctionData as encodeFunctionData18 } from "viem";
1870
+ import { parseAbi as parseAbi21, encodeFunctionData as encodeFunctionData19 } from "viem";
1871
+ import { createPublicClient as createPublicClient16, http as http16, parseAbi as parseAbi222, encodeFunctionData as encodeFunctionData20, zeroAddress as zeroAddress9 } from "viem";
1872
+ import { createPublicClient as createPublicClient17, http as http17, parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21, zeroAddress as zeroAddress10 } from "viem";
1737
1873
  import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
1738
- import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25 } from "viem";
1874
+ import { parseAbi as parseAbi25, encodeFunctionData as encodeFunctionData23 } from "viem";
1875
+ import { createPublicClient as createPublicClient18, http as http18, parseAbi as parseAbi26 } from "viem";
1739
1876
  var DEFAULT_FEE = 3e3;
1740
- var swapRouterAbi = parseAbi3([
1877
+ var swapRouterAbi = parseAbi4([
1741
1878
  "struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
1742
1879
  "function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut)"
1743
1880
  ]);
1744
- var quoterAbi = parseAbi3([
1881
+ var quoterAbi = parseAbi4([
1745
1882
  "struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; }",
1746
1883
  "function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
1747
1884
  ]);
1748
- var ramsesQuoterAbi = parseAbi3([
1885
+ var ramsesQuoterAbi = parseAbi4([
1749
1886
  "struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; int24 tickSpacing; uint160 sqrtPriceLimitX96; }",
1750
1887
  "function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
1751
1888
  ]);
1752
- var positionManagerAbi = parseAbi3([
1889
+ var positionManagerAbi = parseAbi4([
1753
1890
  "struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; }",
1754
1891
  "function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
1755
1892
  ]);
@@ -1782,7 +1919,7 @@ var UniswapV3Adapter = class {
1782
1919
  async buildSwap(params) {
1783
1920
  const deadline = BigInt(params.deadline ?? 18446744073709551615n);
1784
1921
  const amountOutMinimum = 0n;
1785
- const data = encodeFunctionData3({
1922
+ const data = encodeFunctionData4({
1786
1923
  abi: swapRouterAbi,
1787
1924
  functionName: "exactInputSingle",
1788
1925
  args: [
@@ -1803,7 +1940,8 @@ var UniswapV3Adapter = class {
1803
1940
  to: this.router,
1804
1941
  data,
1805
1942
  value: 0n,
1806
- gas_estimate: 2e5
1943
+ gas_estimate: 2e5,
1944
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
1807
1945
  };
1808
1946
  }
1809
1947
  async quote(params) {
@@ -1818,7 +1956,7 @@ var UniswapV3Adapter = class {
1818
1956
  tickSpacings.map(async (ts) => {
1819
1957
  const result = await client2.call({
1820
1958
  to: this.quoter,
1821
- data: encodeFunctionData3({
1959
+ data: encodeFunctionData4({
1822
1960
  abi: ramsesQuoterAbi,
1823
1961
  functionName: "quoteExactInputSingle",
1824
1962
  args: [
@@ -1864,7 +2002,7 @@ var UniswapV3Adapter = class {
1864
2002
  feeTiers.map(async (fee) => {
1865
2003
  const result = await client2.call({
1866
2004
  to: this.quoter,
1867
- data: encodeFunctionData3({
2005
+ data: encodeFunctionData4({
1868
2006
  abi: quoterAbi,
1869
2007
  functionName: "quoteExactInputSingle",
1870
2008
  args: [
@@ -1903,7 +2041,7 @@ var UniswapV3Adapter = class {
1903
2041
  }
1904
2042
  }
1905
2043
  const client = createPublicClient4({ transport: http4(this.rpcUrl) });
1906
- const callData = encodeFunctionData3({
2044
+ const callData = encodeFunctionData4({
1907
2045
  abi: swapRouterAbi,
1908
2046
  functionName: "exactInputSingle",
1909
2047
  args: [
@@ -1949,7 +2087,7 @@ var UniswapV3Adapter = class {
1949
2087
  const [token0, token1, rawAmount0, rawAmount1] = params.token_a.toLowerCase() < params.token_b.toLowerCase() ? [params.token_a, params.token_b, params.amount_a, params.amount_b] : [params.token_b, params.token_a, params.amount_b, params.amount_a];
1950
2088
  const amount0 = rawAmount0 === 0n && rawAmount1 > 0n ? 1n : rawAmount0;
1951
2089
  const amount1 = rawAmount1 === 0n && rawAmount0 > 0n ? 1n : rawAmount1;
1952
- const data = encodeFunctionData3({
2090
+ const data = encodeFunctionData4({
1953
2091
  abi: positionManagerAbi,
1954
2092
  functionName: "mint",
1955
2093
  args: [
@@ -1973,7 +2111,11 @@ var UniswapV3Adapter = class {
1973
2111
  to: pm,
1974
2112
  data,
1975
2113
  value: 0n,
1976
- gas_estimate: 5e5
2114
+ gas_estimate: 5e5,
2115
+ approvals: [
2116
+ { token: token0, spender: pm, amount: amount0 },
2117
+ { token: token1, spender: pm, amount: amount1 }
2118
+ ]
1977
2119
  };
1978
2120
  }
1979
2121
  async buildRemoveLiquidity(_params) {
@@ -2032,7 +2174,8 @@ var UniswapV2Adapter = class {
2032
2174
  to: this.router,
2033
2175
  data,
2034
2176
  value: 0n,
2035
- gas_estimate: 15e4
2177
+ gas_estimate: 15e4,
2178
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2036
2179
  };
2037
2180
  }
2038
2181
  async quote(params) {
@@ -2151,7 +2294,11 @@ var UniswapV2Adapter = class {
2151
2294
  to: this.router,
2152
2295
  data,
2153
2296
  value: 0n,
2154
- gas_estimate: 3e5
2297
+ gas_estimate: 3e5,
2298
+ approvals: [
2299
+ { token: params.token_a, spender: this.router, amount: params.amount_a },
2300
+ { token: params.token_b, spender: this.router, amount: params.amount_b }
2301
+ ]
2155
2302
  };
2156
2303
  }
2157
2304
  async buildRemoveLiquidity(params) {
@@ -2238,7 +2385,8 @@ var AlgebraV3Adapter = class {
2238
2385
  to: this.router,
2239
2386
  data,
2240
2387
  value: 0n,
2241
- gas_estimate: 25e4
2388
+ gas_estimate: 25e4,
2389
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2242
2390
  };
2243
2391
  }
2244
2392
  async quote(params) {
@@ -2356,7 +2504,11 @@ var AlgebraV3Adapter = class {
2356
2504
  to: pm,
2357
2505
  data,
2358
2506
  value: 0n,
2359
- gas_estimate: 5e5
2507
+ gas_estimate: 5e5,
2508
+ approvals: [
2509
+ { token: token0, spender: pm, amount: amount0 },
2510
+ { token: token1, spender: pm, amount: amount1 }
2511
+ ]
2360
2512
  };
2361
2513
  }
2362
2514
  async buildRemoveLiquidity(_params) {
@@ -2365,7 +2517,7 @@ var AlgebraV3Adapter = class {
2365
2517
  );
2366
2518
  }
2367
2519
  };
2368
- var abi3 = parseAbi4([
2520
+ var abi3 = parseAbi42([
2369
2521
  "function swapSingleTokenExactIn(address pool, address tokenIn, address tokenOut, uint256 exactAmountIn, uint256 minAmountOut, uint256 deadline, bool wethIsEth, bytes calldata userData) external returns (uint256 amountOut)"
2370
2522
  ]);
2371
2523
  var BalancerV3Adapter = class {
@@ -2385,7 +2537,7 @@ var BalancerV3Adapter = class {
2385
2537
  async buildSwap(params) {
2386
2538
  const minAmountOut = 0n;
2387
2539
  const deadline = BigInt(params.deadline ?? 18446744073709551615n);
2388
- const data = encodeFunctionData4({
2540
+ const data = encodeFunctionData42({
2389
2541
  abi: abi3,
2390
2542
  functionName: "swapSingleTokenExactIn",
2391
2543
  args: [
@@ -2533,18 +2685,10 @@ var SolidlyAdapter = class {
2533
2685
  to: this.router,
2534
2686
  data,
2535
2687
  value: 0n,
2536
- gas_estimate: 2e5
2688
+ gas_estimate: 2e5,
2689
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2537
2690
  };
2538
2691
  }
2539
- async callGetAmountsOut(client, callData) {
2540
- const result = await client.call({ to: this.router, data: callData });
2541
- if (!result.data) return 0n;
2542
- const [amounts] = decodeAbiParameters4(
2543
- [{ name: "amounts", type: "uint256[]" }],
2544
- result.data
2545
- );
2546
- return amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2547
- }
2548
2692
  encodeV1(params, stable) {
2549
2693
  return encodeFunctionData6({
2550
2694
  abi: abi4,
@@ -2561,7 +2705,6 @@ var SolidlyAdapter = class {
2561
2705
  }
2562
2706
  async quote(params) {
2563
2707
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
2564
- const client = createPublicClient42({ transport: http42(this.rpcUrl) });
2565
2708
  const candidates = [
2566
2709
  { callData: this.encodeV1(params, false), stable: false },
2567
2710
  { callData: this.encodeV1(params, true), stable: true }
@@ -2572,16 +2715,26 @@ var SolidlyAdapter = class {
2572
2715
  { callData: this.encodeV2(params, true), stable: true }
2573
2716
  );
2574
2717
  }
2575
- const results = await Promise.allSettled(
2576
- candidates.map((c) => this.callGetAmountsOut(client, c.callData))
2718
+ const rawResults = await multicallRead(
2719
+ this.rpcUrl,
2720
+ candidates.map((c) => [this.router, c.callData])
2577
2721
  );
2578
2722
  let bestOut = 0n;
2579
2723
  let bestStable = false;
2580
- for (let i = 0; i < results.length; i++) {
2581
- const r = results[i];
2582
- if (r.status === "fulfilled" && r.value > bestOut) {
2583
- bestOut = r.value;
2584
- bestStable = candidates[i].stable;
2724
+ for (let i = 0; i < rawResults.length; i++) {
2725
+ const raw = rawResults[i];
2726
+ if (!raw) continue;
2727
+ try {
2728
+ const [amounts] = decodeAbiParameters4(
2729
+ [{ name: "amounts", type: "uint256[]" }],
2730
+ raw
2731
+ );
2732
+ const out = amounts.length >= 2 ? amounts[amounts.length - 1] : 0n;
2733
+ if (out > bestOut) {
2734
+ bestOut = out;
2735
+ bestStable = candidates[i].stable;
2736
+ }
2737
+ } catch {
2585
2738
  }
2586
2739
  }
2587
2740
  if (bestOut === 0n) {
@@ -2616,7 +2769,11 @@ var SolidlyAdapter = class {
2616
2769
  to: this.router,
2617
2770
  data,
2618
2771
  value: 0n,
2619
- gas_estimate: 35e4
2772
+ gas_estimate: 35e4,
2773
+ approvals: [
2774
+ { token: params.token_a, spender: this.router, amount: params.amount_a },
2775
+ { token: params.token_b, spender: this.router, amount: params.amount_b }
2776
+ ]
2620
2777
  };
2621
2778
  }
2622
2779
  async buildRemoveLiquidity(params) {
@@ -2742,7 +2899,7 @@ var SolidlyGaugeAdapter = class {
2742
2899
  return this.protocolName;
2743
2900
  }
2744
2901
  // IGauge
2745
- async buildDeposit(gauge, amount, tokenId) {
2902
+ async buildDeposit(gauge, amount, tokenId, lpToken) {
2746
2903
  if (tokenId !== void 0) {
2747
2904
  const data2 = encodeFunctionData8({
2748
2905
  abi: gaugeAbi,
@@ -2754,7 +2911,8 @@ var SolidlyGaugeAdapter = class {
2754
2911
  to: gauge,
2755
2912
  data: data2,
2756
2913
  value: 0n,
2757
- gas_estimate: 2e5
2914
+ gas_estimate: 2e5,
2915
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2758
2916
  };
2759
2917
  }
2760
2918
  const data = encodeFunctionData8({
@@ -2767,7 +2925,8 @@ var SolidlyGaugeAdapter = class {
2767
2925
  to: gauge,
2768
2926
  data,
2769
2927
  value: 0n,
2770
- gas_estimate: 2e5
2928
+ gas_estimate: 2e5,
2929
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2771
2930
  };
2772
2931
  }
2773
2932
  async buildWithdraw(gauge, amount) {
@@ -2787,7 +2946,7 @@ var SolidlyGaugeAdapter = class {
2787
2946
  async buildClaimRewards(gauge, account) {
2788
2947
  if (account && this.rpcUrl) {
2789
2948
  try {
2790
- const client = createPublicClient5({ transport: http5(this.rpcUrl) });
2949
+ const client = createPublicClient42({ transport: http42(this.rpcUrl) });
2791
2950
  const listLen = await client.readContract({
2792
2951
  address: gauge,
2793
2952
  abi: gaugeAbi,
@@ -3045,7 +3204,7 @@ var MasterChefAdapter = class {
3045
3204
  if (!this.rpcUrl) {
3046
3205
  throw DefiError.unsupported(`[${this.protocolName}] getPendingRewards requires RPC`);
3047
3206
  }
3048
- const client = createPublicClient6({ transport: http6(this.rpcUrl) });
3207
+ const client = createPublicClient5({ transport: http5(this.rpcUrl) });
3049
3208
  const rewards = await client.readContract({
3050
3209
  address: this.masterchef,
3051
3210
  abi: masterchefAbi,
@@ -3059,7 +3218,682 @@ var MasterChefAdapter = class {
3059
3218
  }));
3060
3219
  }
3061
3220
  };
3062
- var POOL_ABI = parseAbi10([
3221
+ var lbRouterAbi = parseAbi10([
3222
+ "struct LiquidityParameters { address tokenX; address tokenY; uint256 binStep; uint256 amountX; uint256 amountY; uint256 amountXMin; uint256 amountYMin; uint256 activeIdDesired; uint256 idSlippage; int256[] deltaIds; uint256[] distributionX; uint256[] distributionY; address to; address refundTo; uint256 deadline; }",
3223
+ "function addLiquidity(LiquidityParameters calldata liquidityParameters) external returns (uint256 amountXAdded, uint256 amountYAdded, uint256 amountXLeft, uint256 amountYLeft, uint256[] memory depositIds, uint256[] memory liquidityMinted)",
3224
+ "function removeLiquidity(address tokenX, address tokenY, uint16 binStep, uint256 amountXMin, uint256 amountYMin, uint256[] memory ids, uint256[] memory amounts, address to, uint256 deadline) external returns (uint256 amountX, uint256 amountY)"
3225
+ ]);
3226
+ var lbFactoryAbi = parseAbi10([
3227
+ "function getNumberOfLBPairs() external view returns (uint256)",
3228
+ "function getLBPairAtIndex(uint256 index) external view returns (address)"
3229
+ ]);
3230
+ var lbPairAbi = parseAbi10([
3231
+ "function getLBHooksParameters() external view returns (bytes32)",
3232
+ "function getActiveId() external view returns (uint24)",
3233
+ "function getBinStep() external view returns (uint16)",
3234
+ "function getTokenX() external view returns (address)",
3235
+ "function getTokenY() external view returns (address)",
3236
+ "function balanceOf(address account, uint256 id) external view returns (uint256)",
3237
+ "function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory)"
3238
+ ]);
3239
+ var lbRewarderAbi = parseAbi10([
3240
+ "function getRewardToken() external view returns (address)",
3241
+ "function getRewardedRange() external view returns (uint256 minBinId, uint256 maxBinId)",
3242
+ "function getPendingRewards(address user, uint256[] calldata ids) external view returns (uint256 pendingRewards)",
3243
+ "function claim(address user, uint256[] calldata ids) external",
3244
+ "function getPid() external view returns (uint256)",
3245
+ "function isStopped() external view returns (bool)",
3246
+ "function getLBPair() external view returns (address)",
3247
+ "function getMasterChef() external view returns (address)"
3248
+ ]);
3249
+ var masterChefAbi = parseAbi10([
3250
+ "function getMoePerSecond() external view returns (uint256)",
3251
+ "function getTreasuryShare() external view returns (uint256)",
3252
+ "function getStaticShare() external view returns (uint256)",
3253
+ "function getVeMoe() external view returns (address)"
3254
+ ]);
3255
+ var veMoeAbi = parseAbi10([
3256
+ "function getWeight(uint256 pid) external view returns (uint256)",
3257
+ "function getTotalWeight() external view returns (uint256)",
3258
+ "function getTopPoolIds() external view returns (uint256[] memory)"
3259
+ ]);
3260
+ var lbPairBinAbi = parseAbi10([
3261
+ "function getBin(uint24 id) external view returns (uint128 reserveX, uint128 reserveY)",
3262
+ "function getActiveId() external view returns (uint24)"
3263
+ ]);
3264
+ var lbQuoterAbi2 = parseAbi10([
3265
+ "function findBestPathFromAmountIn(address[] calldata route, uint128 amountIn) external view returns ((address[] route, address[] pairs, uint256[] binSteps, uint256[] versions, uint128[] amounts, uint128[] virtualAmountsWithoutSlippage, uint128[] fees))"
3266
+ ]);
3267
+ var erc20Abi2 = parseAbi10([
3268
+ "function symbol() external view returns (string)"
3269
+ ]);
3270
+ var _addressAbi = parseAbi10(["function f() external view returns (address)"]);
3271
+ function decodeAddressResult(data) {
3272
+ if (!data) return null;
3273
+ try {
3274
+ return decodeFunctionResult22({ abi: _addressAbi, functionName: "f", data });
3275
+ } catch {
3276
+ return null;
3277
+ }
3278
+ }
3279
+ var _uint256Abi = parseAbi10(["function f() external view returns (uint256)"]);
3280
+ function decodeUint256Result(data) {
3281
+ if (!data) return null;
3282
+ try {
3283
+ return decodeFunctionResult22({ abi: _uint256Abi, functionName: "f", data });
3284
+ } catch {
3285
+ return null;
3286
+ }
3287
+ }
3288
+ var _boolAbi = parseAbi10(["function f() external view returns (bool)"]);
3289
+ function decodeBoolResult(data) {
3290
+ if (!data) return null;
3291
+ try {
3292
+ return decodeFunctionResult22({ abi: _boolAbi, functionName: "f", data });
3293
+ } catch {
3294
+ return null;
3295
+ }
3296
+ }
3297
+ function decodeStringResult(data) {
3298
+ if (!data) return "?";
3299
+ try {
3300
+ return decodeFunctionResult22({ abi: erc20Abi2, functionName: "symbol", data });
3301
+ } catch {
3302
+ return "?";
3303
+ }
3304
+ }
3305
+ var _rangeAbi = parseAbi10(["function f() external view returns (uint256 minBinId, uint256 maxBinId)"]);
3306
+ function decodeRangeResult(data) {
3307
+ if (!data) return null;
3308
+ try {
3309
+ return decodeFunctionResult22({ abi: _rangeAbi, functionName: "f", data });
3310
+ } catch {
3311
+ return null;
3312
+ }
3313
+ }
3314
+ var _binAbi = parseAbi10(["function f() external view returns (uint128 reserveX, uint128 reserveY)"]);
3315
+ function decodeBinResult(data) {
3316
+ if (!data) return null;
3317
+ try {
3318
+ return decodeFunctionResult22({ abi: _binAbi, functionName: "f", data });
3319
+ } catch {
3320
+ return null;
3321
+ }
3322
+ }
3323
+ var _uint256ArrayAbi = parseAbi10(["function f() external view returns (uint256[] memory)"]);
3324
+ function decodeUint256ArrayResult(data) {
3325
+ if (!data) return null;
3326
+ try {
3327
+ return decodeFunctionResult22({ abi: _uint256ArrayAbi, functionName: "f", data });
3328
+ } catch {
3329
+ return null;
3330
+ }
3331
+ }
3332
+ function extractRewarderAddress(hooksParams) {
3333
+ if (!hooksParams || hooksParams === "0x0000000000000000000000000000000000000000000000000000000000000000") {
3334
+ return null;
3335
+ }
3336
+ const hex = hooksParams.slice(2);
3337
+ if (hex.length < 64) return null;
3338
+ const addrHex = hex.slice(24, 64);
3339
+ if (addrHex === "0000000000000000000000000000000000000000") return null;
3340
+ return `0x${addrHex}`;
3341
+ }
3342
+ function buildUniformDistribution(deltaIds) {
3343
+ const PRECISION = 10n ** 18n;
3344
+ const n = deltaIds.length;
3345
+ const xBins = deltaIds.filter((d) => d >= 0).length;
3346
+ const yBins = deltaIds.filter((d) => d <= 0).length;
3347
+ const distributionX = [];
3348
+ const distributionY = [];
3349
+ for (const delta of deltaIds) {
3350
+ const xShare = delta >= 0 && xBins > 0 ? PRECISION / BigInt(xBins) : 0n;
3351
+ const yShare = delta <= 0 && yBins > 0 ? PRECISION / BigInt(yBins) : 0n;
3352
+ distributionX.push(xShare);
3353
+ distributionY.push(yShare);
3354
+ }
3355
+ const xSum = distributionX.reduce((a, b) => a + b, 0n);
3356
+ const ySum = distributionY.reduce((a, b) => a + b, 0n);
3357
+ if (xSum > 0n && xSum !== PRECISION) {
3358
+ const firstX = distributionX.findIndex((v) => v > 0n);
3359
+ if (firstX !== -1) distributionX[firstX] += PRECISION - xSum;
3360
+ }
3361
+ if (ySum > 0n && ySum !== PRECISION) {
3362
+ const firstY = distributionY.findIndex((v) => v > 0n);
3363
+ if (firstY !== -1) distributionY[firstY] += PRECISION - ySum;
3364
+ }
3365
+ return { distributionX, distributionY };
3366
+ }
3367
+ var MerchantMoeLBAdapter = class {
3368
+ protocolName;
3369
+ lbRouter;
3370
+ lbFactory;
3371
+ lbQuoter;
3372
+ rpcUrl;
3373
+ /** WMNT address (lb_mid_wmnt in config) used for MOE price routing */
3374
+ wmnt;
3375
+ /** USDT address (lb_mid_usdt in config) used for MNT/USD price routing */
3376
+ usdt;
3377
+ constructor(entry, rpcUrl) {
3378
+ this.protocolName = entry.name;
3379
+ const lbRouter = entry.contracts?.["lb_router"];
3380
+ if (!lbRouter) {
3381
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_router' contract address");
3382
+ }
3383
+ const lbFactory = entry.contracts?.["lb_factory"];
3384
+ if (!lbFactory) {
3385
+ throw new DefiError("CONTRACT_ERROR", "Missing 'lb_factory' contract address");
3386
+ }
3387
+ this.lbRouter = lbRouter;
3388
+ this.lbFactory = lbFactory;
3389
+ this.lbQuoter = entry.contracts?.["lb_quoter"];
3390
+ this.wmnt = entry.contracts?.["lb_mid_wmnt"];
3391
+ this.usdt = entry.contracts?.["lb_mid_usdt"];
3392
+ this.rpcUrl = rpcUrl;
3393
+ }
3394
+ name() {
3395
+ return this.protocolName;
3396
+ }
3397
+ requireRpc() {
3398
+ if (!this.rpcUrl) {
3399
+ throw DefiError.rpcError(`[${this.protocolName}] RPC URL required`);
3400
+ }
3401
+ return this.rpcUrl;
3402
+ }
3403
+ /**
3404
+ * Build an addLiquidity transaction for a Liquidity Book pair.
3405
+ * Distributes tokenX/tokenY uniformly across active bin ± numBins.
3406
+ */
3407
+ async buildAddLiquidity(params) {
3408
+ const numBins = params.numBins ?? 5;
3409
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
3410
+ let activeIdDesired = params.activeIdDesired;
3411
+ if (activeIdDesired === void 0) {
3412
+ const rpcUrl = this.requireRpc();
3413
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3414
+ const activeId = await client.readContract({
3415
+ address: params.pool,
3416
+ abi: lbPairAbi,
3417
+ functionName: "getActiveId"
3418
+ });
3419
+ activeIdDesired = activeId;
3420
+ }
3421
+ const deltaIds = [];
3422
+ for (let d = -numBins; d <= numBins; d++) {
3423
+ deltaIds.push(d);
3424
+ }
3425
+ const { distributionX, distributionY } = buildUniformDistribution(deltaIds);
3426
+ const data = encodeFunctionData10({
3427
+ abi: lbRouterAbi,
3428
+ functionName: "addLiquidity",
3429
+ args: [
3430
+ {
3431
+ tokenX: params.tokenX,
3432
+ tokenY: params.tokenY,
3433
+ binStep: BigInt(params.binStep),
3434
+ amountX: params.amountX,
3435
+ amountY: params.amountY,
3436
+ amountXMin: 0n,
3437
+ amountYMin: 0n,
3438
+ activeIdDesired: BigInt(activeIdDesired),
3439
+ idSlippage: BigInt(numBins + 2),
3440
+ deltaIds: deltaIds.map(BigInt),
3441
+ distributionX,
3442
+ distributionY,
3443
+ to: params.recipient,
3444
+ refundTo: params.recipient,
3445
+ deadline
3446
+ }
3447
+ ]
3448
+ });
3449
+ return {
3450
+ description: `[${this.protocolName}] LB addLiquidity ${params.amountX} tokenX + ${params.amountY} tokenY across ${deltaIds.length} bins`,
3451
+ to: this.lbRouter,
3452
+ data,
3453
+ value: 0n,
3454
+ gas_estimate: 8e5,
3455
+ approvals: [
3456
+ { token: params.tokenX, spender: this.lbRouter, amount: params.amountX },
3457
+ { token: params.tokenY, spender: this.lbRouter, amount: params.amountY }
3458
+ ]
3459
+ };
3460
+ }
3461
+ /**
3462
+ * Build a removeLiquidity transaction for specific LB bins.
3463
+ */
3464
+ async buildRemoveLiquidity(params) {
3465
+ const deadline = params.deadline ?? BigInt("18446744073709551615");
3466
+ const data = encodeFunctionData10({
3467
+ abi: lbRouterAbi,
3468
+ functionName: "removeLiquidity",
3469
+ args: [
3470
+ params.tokenX,
3471
+ params.tokenY,
3472
+ params.binStep,
3473
+ params.amountXMin ?? 0n,
3474
+ params.amountYMin ?? 0n,
3475
+ params.binIds.map(BigInt),
3476
+ params.amounts,
3477
+ params.recipient,
3478
+ deadline
3479
+ ]
3480
+ });
3481
+ return {
3482
+ description: `[${this.protocolName}] LB removeLiquidity from ${params.binIds.length} bins`,
3483
+ to: this.lbRouter,
3484
+ data,
3485
+ value: 0n,
3486
+ gas_estimate: 6e5
3487
+ };
3488
+ }
3489
+ /**
3490
+ * Auto-detect bin IDs for a pool from the rewarder's rewarded range.
3491
+ * Falls back to active bin ± 50 scan if no rewarder exists.
3492
+ */
3493
+ async autoDetectBins(pool) {
3494
+ const rpcUrl = this.requireRpc();
3495
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3496
+ const hooksParams = await client.readContract({
3497
+ address: pool,
3498
+ abi: lbPairAbi,
3499
+ functionName: "getLBHooksParameters"
3500
+ });
3501
+ const rewarder = extractRewarderAddress(hooksParams);
3502
+ if (rewarder) {
3503
+ const range = await client.readContract({
3504
+ address: rewarder,
3505
+ abi: lbRewarderAbi,
3506
+ functionName: "getRewardedRange"
3507
+ });
3508
+ const min = Number(range[0]);
3509
+ const max = Number(range[1]);
3510
+ const ids2 = [];
3511
+ for (let b = min; b <= max; b++) ids2.push(b);
3512
+ return ids2;
3513
+ }
3514
+ const activeId = await client.readContract({
3515
+ address: pool,
3516
+ abi: lbPairAbi,
3517
+ functionName: "getActiveId"
3518
+ });
3519
+ const ids = [];
3520
+ for (let b = activeId - 50; b <= activeId + 50; b++) ids.push(b);
3521
+ return ids;
3522
+ }
3523
+ /**
3524
+ * Get pending MOE rewards for a user across specified bin IDs.
3525
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
3526
+ * Reads the rewarder address from the pool's hooks parameters.
3527
+ */
3528
+ async getPendingRewards(user, pool, binIds) {
3529
+ const rpcUrl = this.requireRpc();
3530
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3531
+ const hooksParams = await client.readContract({
3532
+ address: pool,
3533
+ abi: lbPairAbi,
3534
+ functionName: "getLBHooksParameters"
3535
+ });
3536
+ const rewarder = extractRewarderAddress(hooksParams);
3537
+ if (!rewarder) {
3538
+ return [];
3539
+ }
3540
+ let resolvedBinIds = binIds;
3541
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
3542
+ const range = await client.readContract({
3543
+ address: rewarder,
3544
+ abi: lbRewarderAbi,
3545
+ functionName: "getRewardedRange"
3546
+ });
3547
+ const min = Number(range[0]);
3548
+ const max = Number(range[1]);
3549
+ resolvedBinIds = [];
3550
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
3551
+ }
3552
+ const [pending, rewardToken] = await Promise.all([
3553
+ client.readContract({
3554
+ address: rewarder,
3555
+ abi: lbRewarderAbi,
3556
+ functionName: "getPendingRewards",
3557
+ args: [user, resolvedBinIds.map(BigInt)]
3558
+ }),
3559
+ client.readContract({
3560
+ address: rewarder,
3561
+ abi: lbRewarderAbi,
3562
+ functionName: "getRewardToken"
3563
+ })
3564
+ ]);
3565
+ return [
3566
+ {
3567
+ token: rewardToken,
3568
+ symbol: "MOE",
3569
+ amount: pending
3570
+ }
3571
+ ];
3572
+ }
3573
+ /**
3574
+ * Build a claim rewards transaction for specific LB bins.
3575
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range.
3576
+ */
3577
+ async buildClaimRewards(user, pool, binIds) {
3578
+ const rpcUrl = this.requireRpc();
3579
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3580
+ const hooksParams = await client.readContract({
3581
+ address: pool,
3582
+ abi: lbPairAbi,
3583
+ functionName: "getLBHooksParameters"
3584
+ });
3585
+ const rewarder = extractRewarderAddress(hooksParams);
3586
+ if (!rewarder) {
3587
+ throw new DefiError("CONTRACT_ERROR", `[${this.protocolName}] Pool ${pool} has no active rewarder`);
3588
+ }
3589
+ let resolvedBinIds = binIds;
3590
+ if (!resolvedBinIds || resolvedBinIds.length === 0) {
3591
+ const range = await client.readContract({
3592
+ address: rewarder,
3593
+ abi: lbRewarderAbi,
3594
+ functionName: "getRewardedRange"
3595
+ });
3596
+ const min = Number(range[0]);
3597
+ const max = Number(range[1]);
3598
+ resolvedBinIds = [];
3599
+ for (let b = min; b <= max; b++) resolvedBinIds.push(b);
3600
+ }
3601
+ const data = encodeFunctionData10({
3602
+ abi: lbRewarderAbi,
3603
+ functionName: "claim",
3604
+ args: [user, resolvedBinIds.map(BigInt)]
3605
+ });
3606
+ return {
3607
+ description: `[${this.protocolName}] LB claim rewards for ${resolvedBinIds.length} bins`,
3608
+ to: rewarder,
3609
+ data,
3610
+ value: 0n,
3611
+ gas_estimate: 3e5
3612
+ };
3613
+ }
3614
+ /**
3615
+ * Discover all active rewarded LB pools by iterating the factory.
3616
+ * Uses 7 multicall batches to minimise RPC round-trips and avoid 429s.
3617
+ *
3618
+ * Batch 1: getNumberOfLBPairs(), then getLBPairAtIndex(i) for all i
3619
+ * Batch 2: getLBHooksParameters() for all pairs → extract rewarder addresses
3620
+ * Batch 3: isStopped/getRewardedRange/getRewardToken/getPid/getMasterChef for each rewarder
3621
+ * Batch 4: getTokenX/getTokenY for each rewarded pair, then symbol() for unique tokens
3622
+ * Batch 5: Bootstrap MasterChef→VeMoe, then getMoePerSecond/getTreasuryShare/getStaticShare/getTotalWeight/getTopPoolIds
3623
+ * Batch 6: VeMoe.getWeight(pid) for each rewarded pool
3624
+ * Batch 7: Pool.getBin(binId) for all bins in rewarded range of each pool
3625
+ * Price: LB Quoter findBestPathFromAmountIn for MOE/WMNT and WMNT/USDT prices
3626
+ */
3627
+ async discoverRewardedPools() {
3628
+ const rpcUrl = this.requireRpc();
3629
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3630
+ const pairCount = await client.readContract({
3631
+ address: this.lbFactory,
3632
+ abi: lbFactoryAbi,
3633
+ functionName: "getNumberOfLBPairs"
3634
+ });
3635
+ const count = Number(pairCount);
3636
+ if (count === 0) return [];
3637
+ const batch1Calls = Array.from({ length: count }, (_, i) => [
3638
+ this.lbFactory,
3639
+ encodeFunctionData10({ abi: lbFactoryAbi, functionName: "getLBPairAtIndex", args: [BigInt(i)] })
3640
+ ]);
3641
+ const batch1Results = await multicallRead(rpcUrl, batch1Calls);
3642
+ const pairAddresses = batch1Results.map((r) => decodeAddressResult(r)).filter((a) => a !== null);
3643
+ if (pairAddresses.length === 0) return [];
3644
+ const batch2Calls = pairAddresses.map((pair) => [
3645
+ pair,
3646
+ encodeFunctionData10({ abi: lbPairAbi, functionName: "getLBHooksParameters" })
3647
+ ]);
3648
+ const batch2Results = await multicallRead(rpcUrl, batch2Calls);
3649
+ const rewardedPairs = [];
3650
+ for (let i = 0; i < pairAddresses.length; i++) {
3651
+ const raw = batch2Results[i];
3652
+ if (!raw) continue;
3653
+ let hooksBytes;
3654
+ try {
3655
+ const _bytes32Abi = parseAbi10(["function f() external view returns (bytes32)"]);
3656
+ hooksBytes = decodeFunctionResult22({ abi: _bytes32Abi, functionName: "f", data: raw });
3657
+ } catch {
3658
+ continue;
3659
+ }
3660
+ const rewarder = extractRewarderAddress(hooksBytes);
3661
+ if (rewarder) {
3662
+ rewardedPairs.push({ pool: pairAddresses[i], rewarder });
3663
+ }
3664
+ }
3665
+ if (rewardedPairs.length === 0) return [];
3666
+ const batch3Calls = [];
3667
+ for (const { rewarder } of rewardedPairs) {
3668
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "isStopped" })]);
3669
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getRewardedRange" })]);
3670
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getRewardToken" })]);
3671
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getPid" })]);
3672
+ batch3Calls.push([rewarder, encodeFunctionData10({ abi: lbRewarderAbi, functionName: "getMasterChef" })]);
3673
+ }
3674
+ const batch3Results = await multicallRead(rpcUrl, batch3Calls);
3675
+ const batch4aCalls = [];
3676
+ for (const { pool } of rewardedPairs) {
3677
+ batch4aCalls.push([pool, encodeFunctionData10({ abi: lbPairAbi, functionName: "getTokenX" })]);
3678
+ batch4aCalls.push([pool, encodeFunctionData10({ abi: lbPairAbi, functionName: "getTokenY" })]);
3679
+ }
3680
+ const batch4aResults = await multicallRead(rpcUrl, batch4aCalls);
3681
+ const tokenXAddresses = [];
3682
+ const tokenYAddresses = [];
3683
+ for (let i = 0; i < rewardedPairs.length; i++) {
3684
+ tokenXAddresses.push(decodeAddressResult(batch4aResults[i * 2] ?? null));
3685
+ tokenYAddresses.push(decodeAddressResult(batch4aResults[i * 2 + 1] ?? null));
3686
+ }
3687
+ const uniqueTokens = Array.from(
3688
+ new Set([...tokenXAddresses, ...tokenYAddresses].filter((a) => a !== null))
3689
+ );
3690
+ const batch4bCalls = uniqueTokens.map((token) => [
3691
+ token,
3692
+ encodeFunctionData10({ abi: erc20Abi2, functionName: "symbol" })
3693
+ ]);
3694
+ const batch4bResults = await multicallRead(rpcUrl, batch4bCalls);
3695
+ const symbolMap = /* @__PURE__ */ new Map();
3696
+ for (let i = 0; i < uniqueTokens.length; i++) {
3697
+ symbolMap.set(uniqueTokens[i], decodeStringResult(batch4bResults[i] ?? null));
3698
+ }
3699
+ const STRIDE3 = 5;
3700
+ const poolData = [];
3701
+ for (let i = 0; i < rewardedPairs.length; i++) {
3702
+ const base = i * STRIDE3;
3703
+ poolData.push({
3704
+ stopped: decodeBoolResult(batch3Results[base] ?? null) ?? false,
3705
+ range: decodeRangeResult(batch3Results[base + 1] ?? null),
3706
+ rewardToken: decodeAddressResult(batch3Results[base + 2] ?? null),
3707
+ pid: Number(decodeUint256Result(batch3Results[base + 3] ?? null) ?? 0n),
3708
+ masterChef: decodeAddressResult(batch3Results[base + 4] ?? null)
3709
+ });
3710
+ }
3711
+ const masterChefAddr = poolData.map((d) => d.masterChef).find((a) => a !== null) ?? null;
3712
+ let moePerDay = 0;
3713
+ let topPoolIds = /* @__PURE__ */ new Set();
3714
+ let totalWeightRaw = 0n;
3715
+ let veMoeAddr = null;
3716
+ if (masterChefAddr) {
3717
+ veMoeAddr = await client.readContract({
3718
+ address: masterChefAddr,
3719
+ abi: masterChefAbi,
3720
+ functionName: "getVeMoe"
3721
+ });
3722
+ const batch5Calls = [
3723
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getMoePerSecond" })],
3724
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getTreasuryShare" })],
3725
+ [masterChefAddr, encodeFunctionData10({ abi: masterChefAbi, functionName: "getStaticShare" })],
3726
+ [veMoeAddr, encodeFunctionData10({ abi: veMoeAbi, functionName: "getTotalWeight" })],
3727
+ [veMoeAddr, encodeFunctionData10({ abi: veMoeAbi, functionName: "getTopPoolIds" })]
3728
+ ];
3729
+ const batch5Results = await multicallRead(rpcUrl, batch5Calls);
3730
+ const moePerSecRaw = decodeUint256Result(batch5Results[0] ?? null) ?? 0n;
3731
+ const treasuryShareRaw = decodeUint256Result(batch5Results[1] ?? null) ?? 0n;
3732
+ const staticShareRaw = decodeUint256Result(batch5Results[2] ?? null) ?? 0n;
3733
+ totalWeightRaw = decodeUint256Result(batch5Results[3] ?? null) ?? 0n;
3734
+ const topPoolIdsRaw = decodeUint256ArrayResult(batch5Results[4] ?? null) ?? [];
3735
+ topPoolIds = new Set(topPoolIdsRaw.map(Number));
3736
+ const PRECISION = 10n ** 18n;
3737
+ const netPerSec = moePerSecRaw * (PRECISION - treasuryShareRaw) / PRECISION * (PRECISION - staticShareRaw) / PRECISION;
3738
+ moePerDay = Number(netPerSec * 86400n) / 1e18;
3739
+ }
3740
+ const weightByPid = /* @__PURE__ */ new Map();
3741
+ if (veMoeAddr && rewardedPairs.length > 0) {
3742
+ const batch6Calls = poolData.map((d) => [
3743
+ veMoeAddr,
3744
+ encodeFunctionData10({ abi: veMoeAbi, functionName: "getWeight", args: [BigInt(d.pid)] })
3745
+ ]);
3746
+ const batch6Results = await multicallRead(rpcUrl, batch6Calls);
3747
+ for (let i = 0; i < poolData.length; i++) {
3748
+ weightByPid.set(poolData[i].pid, decodeUint256Result(batch6Results[i] ?? null) ?? 0n);
3749
+ }
3750
+ }
3751
+ let moePriceUsd = 0;
3752
+ let wmntPriceUsd = 0;
3753
+ const MOE_ADDR = "0x4515A45337F461A11Ff0FE8aBF3c606AE5dC00c9";
3754
+ if (this.lbQuoter && this.wmnt && this.usdt) {
3755
+ try {
3756
+ const [moeWmntQuote, wmntUsdtQuote] = await Promise.all([
3757
+ client.readContract({
3758
+ address: this.lbQuoter,
3759
+ abi: lbQuoterAbi2,
3760
+ functionName: "findBestPathFromAmountIn",
3761
+ args: [[MOE_ADDR, this.wmnt], 10n ** 18n]
3762
+ }),
3763
+ client.readContract({
3764
+ address: this.lbQuoter,
3765
+ abi: lbQuoterAbi2,
3766
+ functionName: "findBestPathFromAmountIn",
3767
+ args: [[this.wmnt, this.usdt], 10n ** 18n]
3768
+ })
3769
+ ]);
3770
+ const moeInWmnt = Number(moeWmntQuote.amounts.at(-1) ?? 0n) / 1e18;
3771
+ wmntPriceUsd = Number(wmntUsdtQuote.amounts.at(-1) ?? 0n) / 1e6;
3772
+ moePriceUsd = moeInWmnt * wmntPriceUsd;
3773
+ } catch {
3774
+ }
3775
+ }
3776
+ const binRequests = [];
3777
+ for (let i = 0; i < rewardedPairs.length; i++) {
3778
+ const range = poolData[i].range;
3779
+ if (!range) continue;
3780
+ const minBin = Number(range[0]);
3781
+ const maxBin = Number(range[1]);
3782
+ for (let b = minBin; b <= maxBin; b++) {
3783
+ binRequests.push({ poolIdx: i, binId: b });
3784
+ }
3785
+ }
3786
+ const binReservesX = /* @__PURE__ */ new Map();
3787
+ const binReservesY = /* @__PURE__ */ new Map();
3788
+ if (binRequests.length > 0) {
3789
+ const batch7Calls = binRequests.map(({ poolIdx, binId }) => [
3790
+ rewardedPairs[poolIdx].pool,
3791
+ encodeFunctionData10({ abi: lbPairBinAbi, functionName: "getBin", args: [binId] })
3792
+ ]);
3793
+ const batch7Results = await multicallRead(rpcUrl, batch7Calls);
3794
+ for (let j = 0; j < binRequests.length; j++) {
3795
+ const { poolIdx, binId } = binRequests[j];
3796
+ const decoded = decodeBinResult(batch7Results[j] ?? null);
3797
+ if (!decoded) continue;
3798
+ if (!binReservesX.has(poolIdx)) {
3799
+ binReservesX.set(poolIdx, /* @__PURE__ */ new Map());
3800
+ binReservesY.set(poolIdx, /* @__PURE__ */ new Map());
3801
+ }
3802
+ binReservesX.get(poolIdx).set(binId, decoded[0]);
3803
+ binReservesY.get(poolIdx).set(binId, decoded[1]);
3804
+ }
3805
+ }
3806
+ const stableSymbols = /* @__PURE__ */ new Set(["USDT", "USDC", "MUSD", "AUSD", "USDY", "FDUSD"]);
3807
+ const mntSymbols = /* @__PURE__ */ new Set(["WMNT", "MNT"]);
3808
+ const moeSymbols = /* @__PURE__ */ new Set(["MOE"]);
3809
+ const sixDecimalStables = /* @__PURE__ */ new Set(["USDT", "USDC", "FDUSD"]);
3810
+ const getTokenPriceUsd = (sym) => {
3811
+ if (stableSymbols.has(sym)) return 1;
3812
+ if (mntSymbols.has(sym)) return wmntPriceUsd;
3813
+ if (moeSymbols.has(sym)) return moePriceUsd;
3814
+ return 0;
3815
+ };
3816
+ const getTokenDecimals = (sym) => {
3817
+ return sixDecimalStables.has(sym) ? 6 : 18;
3818
+ };
3819
+ const results = [];
3820
+ for (let i = 0; i < rewardedPairs.length; i++) {
3821
+ const { pool, rewarder } = rewardedPairs[i];
3822
+ const data = poolData[i];
3823
+ const tokenX = tokenXAddresses[i] ?? "0x0000000000000000000000000000000000000000";
3824
+ const tokenY = tokenYAddresses[i] ?? "0x0000000000000000000000000000000000000000";
3825
+ const symX = symbolMap.get(tokenX) ?? "?";
3826
+ const symY = symbolMap.get(tokenY) ?? "?";
3827
+ const isTopPool = topPoolIds.has(data.pid);
3828
+ const weight = weightByPid.get(data.pid) ?? 0n;
3829
+ let poolMoePerDay = 0;
3830
+ if (isTopPool && totalWeightRaw > 0n && weight > 0n) {
3831
+ poolMoePerDay = moePerDay * (Number(weight) / Number(totalWeightRaw));
3832
+ }
3833
+ const rxMap = binReservesX.get(i);
3834
+ const ryMap = binReservesY.get(i);
3835
+ const range = data.range;
3836
+ let rangeTvlUsd = 0;
3837
+ let rewardedBins = 0;
3838
+ if (range) {
3839
+ const minBin = Number(range[0]);
3840
+ const maxBin = Number(range[1]);
3841
+ rewardedBins = maxBin - minBin + 1;
3842
+ if (rxMap && ryMap) {
3843
+ const priceX = getTokenPriceUsd(symX);
3844
+ const priceY = getTokenPriceUsd(symY);
3845
+ const decX = getTokenDecimals(symX);
3846
+ const decY = getTokenDecimals(symY);
3847
+ for (let b = minBin; b <= maxBin; b++) {
3848
+ const rx = rxMap.get(b) ?? 0n;
3849
+ const ry = ryMap.get(b) ?? 0n;
3850
+ rangeTvlUsd += Number(rx) / 10 ** decX * priceX;
3851
+ rangeTvlUsd += Number(ry) / 10 ** decY * priceY;
3852
+ }
3853
+ }
3854
+ }
3855
+ const aprPercent = rangeTvlUsd > 0 && moePriceUsd > 0 ? poolMoePerDay * moePriceUsd * 365 / rangeTvlUsd * 100 : 0;
3856
+ results.push({
3857
+ pool,
3858
+ rewarder,
3859
+ rewardToken: data.rewardToken ?? "0x0000000000000000000000000000000000000000",
3860
+ minBinId: range ? Number(range[0]) : 0,
3861
+ maxBinId: range ? Number(range[1]) : 0,
3862
+ pid: data.pid,
3863
+ stopped: data.stopped,
3864
+ tokenX,
3865
+ tokenY,
3866
+ symbolX: symX,
3867
+ symbolY: symY,
3868
+ isTopPool,
3869
+ moePerDay: poolMoePerDay,
3870
+ rangeTvlUsd,
3871
+ aprPercent,
3872
+ rewardedBins
3873
+ });
3874
+ }
3875
+ return results;
3876
+ }
3877
+ /**
3878
+ * Get a user's LB positions (bin balances) across a range of bin IDs.
3879
+ * If binIds is omitted, auto-detects from the rewarder's rewarded range (or active ± 50).
3880
+ */
3881
+ async getUserPositions(user, pool, binIds) {
3882
+ const rpcUrl = this.requireRpc();
3883
+ const client = createPublicClient6({ transport: http6(rpcUrl) });
3884
+ const resolvedBinIds = binIds && binIds.length > 0 ? binIds : await this.autoDetectBins(pool);
3885
+ const accounts = resolvedBinIds.map(() => user);
3886
+ const ids = resolvedBinIds.map(BigInt);
3887
+ const balances = await client.readContract({
3888
+ address: pool,
3889
+ abi: lbPairAbi,
3890
+ functionName: "balanceOfBatch",
3891
+ args: [accounts, ids]
3892
+ });
3893
+ return resolvedBinIds.map((binId, i) => ({ binId, balance: balances[i] ?? 0n })).filter((p) => p.balance > 0n);
3894
+ }
3895
+ };
3896
+ var POOL_ABI = parseAbi11([
3063
3897
  "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
3064
3898
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
3065
3899
  "function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external returns (uint256)",
@@ -3067,27 +3901,27 @@ var POOL_ABI = parseAbi10([
3067
3901
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
3068
3902
  "function getReserveData(address asset) external view returns (uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt)"
3069
3903
  ]);
3070
- var ERC20_ABI = parseAbi10([
3904
+ var ERC20_ABI2 = parseAbi11([
3071
3905
  "function totalSupply() external view returns (uint256)"
3072
3906
  ]);
3073
- var INCENTIVES_ABI = parseAbi10([
3907
+ var INCENTIVES_ABI = parseAbi11([
3074
3908
  "function getIncentivesController() external view returns (address)"
3075
3909
  ]);
3076
- var REWARDS_CONTROLLER_ABI = parseAbi10([
3910
+ var REWARDS_CONTROLLER_ABI = parseAbi11([
3077
3911
  "function getRewardsByAsset(address asset) external view returns (address[])",
3078
3912
  "function getRewardsData(address asset, address reward) external view returns (uint256 index, uint256 emissionsPerSecond, uint256 lastUpdateTimestamp, uint256 distributionEnd)"
3079
3913
  ]);
3080
- var POOL_PROVIDER_ABI = parseAbi10([
3914
+ var POOL_PROVIDER_ABI = parseAbi11([
3081
3915
  "function ADDRESSES_PROVIDER() external view returns (address)"
3082
3916
  ]);
3083
- var ADDRESSES_PROVIDER_ABI = parseAbi10([
3917
+ var ADDRESSES_PROVIDER_ABI = parseAbi11([
3084
3918
  "function getPriceOracle() external view returns (address)"
3085
3919
  ]);
3086
- var ORACLE_ABI = parseAbi10([
3920
+ var ORACLE_ABI = parseAbi11([
3087
3921
  "function getAssetPrice(address asset) external view returns (uint256)",
3088
3922
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
3089
3923
  ]);
3090
- var ERC20_DECIMALS_ABI = parseAbi10([
3924
+ var ERC20_DECIMALS_ABI = parseAbi11([
3091
3925
  "function decimals() external view returns (uint8)"
3092
3926
  ]);
3093
3927
  function u256ToF64(v) {
@@ -3095,6 +3929,46 @@ function u256ToF64(v) {
3095
3929
  if (v > MAX_U128) return Infinity;
3096
3930
  return Number(v);
3097
3931
  }
3932
+ function decodeAddress(data) {
3933
+ if (!data || data.length < 66) return null;
3934
+ return `0x${data.slice(26, 66)}`;
3935
+ }
3936
+ function decodeAddressArray(data) {
3937
+ if (!data) return [];
3938
+ try {
3939
+ return decodeFunctionResult3({
3940
+ abi: REWARDS_CONTROLLER_ABI,
3941
+ functionName: "getRewardsByAsset",
3942
+ data
3943
+ });
3944
+ } catch {
3945
+ return [];
3946
+ }
3947
+ }
3948
+ function decodeReserveData(data) {
3949
+ if (!data) return null;
3950
+ try {
3951
+ return decodeFunctionResult3({
3952
+ abi: POOL_ABI,
3953
+ functionName: "getReserveData",
3954
+ data
3955
+ });
3956
+ } catch {
3957
+ return null;
3958
+ }
3959
+ }
3960
+ function decodeRewardsData(data) {
3961
+ if (!data) return null;
3962
+ try {
3963
+ return decodeFunctionResult3({
3964
+ abi: REWARDS_CONTROLLER_ABI,
3965
+ functionName: "getRewardsData",
3966
+ data
3967
+ });
3968
+ } catch {
3969
+ return null;
3970
+ }
3971
+ }
3098
3972
  var AaveV3Adapter = class {
3099
3973
  protocolName;
3100
3974
  pool;
@@ -3110,7 +3984,7 @@ var AaveV3Adapter = class {
3110
3984
  return this.protocolName;
3111
3985
  }
3112
3986
  async buildSupply(params) {
3113
- const data = encodeFunctionData10({
3987
+ const data = encodeFunctionData11({
3114
3988
  abi: POOL_ABI,
3115
3989
  functionName: "supply",
3116
3990
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -3120,12 +3994,13 @@ var AaveV3Adapter = class {
3120
3994
  to: this.pool,
3121
3995
  data,
3122
3996
  value: 0n,
3123
- gas_estimate: 3e5
3997
+ gas_estimate: 3e5,
3998
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3124
3999
  };
3125
4000
  }
3126
4001
  async buildBorrow(params) {
3127
4002
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3128
- const data = encodeFunctionData10({
4003
+ const data = encodeFunctionData11({
3129
4004
  abi: POOL_ABI,
3130
4005
  functionName: "borrow",
3131
4006
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -3140,7 +4015,7 @@ var AaveV3Adapter = class {
3140
4015
  }
3141
4016
  async buildRepay(params) {
3142
4017
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3143
- const data = encodeFunctionData10({
4018
+ const data = encodeFunctionData11({
3144
4019
  abi: POOL_ABI,
3145
4020
  functionName: "repay",
3146
4021
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -3150,11 +4025,12 @@ var AaveV3Adapter = class {
3150
4025
  to: this.pool,
3151
4026
  data,
3152
4027
  value: 0n,
3153
- gas_estimate: 3e5
4028
+ gas_estimate: 3e5,
4029
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3154
4030
  };
3155
4031
  }
3156
4032
  async buildWithdraw(params) {
3157
- const data = encodeFunctionData10({
4033
+ const data = encodeFunctionData11({
3158
4034
  abi: POOL_ABI,
3159
4035
  functionName: "withdraw",
3160
4036
  args: [params.asset, params.amount, params.to]
@@ -3169,15 +4045,21 @@ var AaveV3Adapter = class {
3169
4045
  }
3170
4046
  async getRates(asset) {
3171
4047
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
3172
- const client = createPublicClient7({ transport: http7(this.rpcUrl) });
3173
- const result = await client.readContract({
3174
- address: this.pool,
4048
+ const reserveCallData = encodeFunctionData11({
3175
4049
  abi: POOL_ABI,
3176
4050
  functionName: "getReserveData",
3177
4051
  args: [asset]
3178
- }).catch((e) => {
4052
+ });
4053
+ const [reserveRaw] = await multicallRead(this.rpcUrl, [
4054
+ [this.pool, reserveCallData]
4055
+ ]).catch((e) => {
3179
4056
  throw DefiError.rpcError(`[${this.protocolName}] getReserveData failed: ${e}`);
3180
4057
  });
4058
+ const reserveDecoded = decodeReserveData(reserveRaw ?? null);
4059
+ if (!reserveDecoded) {
4060
+ throw DefiError.rpcError(`[${this.protocolName}] getReserveData returned no data`);
4061
+ }
4062
+ const result = reserveDecoded;
3181
4063
  const RAY = 1e27;
3182
4064
  const SECONDS_PER_YEAR4 = 31536e3;
3183
4065
  const toApy = (rayRate) => {
@@ -3189,74 +4071,56 @@ var AaveV3Adapter = class {
3189
4071
  const stableRate = toApy(result[5]);
3190
4072
  const aTokenAddress = result[8];
3191
4073
  const variableDebtTokenAddress = result[10];
3192
- const [totalSupply, totalBorrow] = await Promise.all([
3193
- client.readContract({
3194
- address: aTokenAddress,
3195
- abi: ERC20_ABI,
3196
- functionName: "totalSupply"
3197
- }).catch(() => 0n),
3198
- client.readContract({
3199
- address: variableDebtTokenAddress,
3200
- abi: ERC20_ABI,
3201
- functionName: "totalSupply"
3202
- }).catch(() => 0n)
4074
+ const [supplyRaw, borrowRaw] = await multicallRead(this.rpcUrl, [
4075
+ [aTokenAddress, encodeFunctionData11({ abi: ERC20_ABI2, functionName: "totalSupply" })],
4076
+ [variableDebtTokenAddress, encodeFunctionData11({ abi: ERC20_ABI2, functionName: "totalSupply" })]
3203
4077
  ]);
4078
+ const totalSupply = decodeU256(supplyRaw ?? null);
4079
+ const totalBorrow = decodeU256(borrowRaw ?? null);
3204
4080
  const utilization = totalSupply > 0n ? Number(totalBorrow * 10000n / totalSupply) / 100 : 0;
3205
4081
  const supplyRewardTokens = [];
3206
4082
  const borrowRewardTokens = [];
3207
4083
  const supplyEmissions = [];
3208
4084
  const borrowEmissions = [];
3209
4085
  try {
3210
- const controllerAddr = await client.readContract({
3211
- address: aTokenAddress,
3212
- abi: INCENTIVES_ABI,
3213
- functionName: "getIncentivesController"
3214
- });
4086
+ const [controllerRaw] = await multicallRead(this.rpcUrl, [
4087
+ [aTokenAddress, encodeFunctionData11({ abi: INCENTIVES_ABI, functionName: "getIncentivesController" })]
4088
+ ]);
4089
+ const controllerAddr = decodeAddress(controllerRaw ?? null);
3215
4090
  if (controllerAddr && controllerAddr !== zeroAddress5) {
3216
- const [supplyRewards, borrowRewards] = await Promise.all([
3217
- client.readContract({
3218
- address: controllerAddr,
3219
- abi: REWARDS_CONTROLLER_ABI,
3220
- functionName: "getRewardsByAsset",
3221
- args: [aTokenAddress]
3222
- }).catch(() => []),
3223
- client.readContract({
3224
- address: controllerAddr,
3225
- abi: REWARDS_CONTROLLER_ABI,
3226
- functionName: "getRewardsByAsset",
3227
- args: [variableDebtTokenAddress]
3228
- }).catch(() => [])
4091
+ const [supplyRewardsRaw, borrowRewardsRaw] = await multicallRead(this.rpcUrl, [
4092
+ [controllerAddr, encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [aTokenAddress] })],
4093
+ [controllerAddr, encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsByAsset", args: [variableDebtTokenAddress] })]
3229
4094
  ]);
3230
- const supplyDataPromises = supplyRewards.map(
3231
- (reward) => client.readContract({
3232
- address: controllerAddr,
3233
- abi: REWARDS_CONTROLLER_ABI,
3234
- functionName: "getRewardsData",
3235
- args: [aTokenAddress, reward]
3236
- }).catch(() => null)
3237
- );
3238
- const supplyData = await Promise.all(supplyDataPromises);
3239
- for (let i = 0; i < supplyRewards.length; i++) {
3240
- const data = supplyData[i];
3241
- if (data && data[1] > 0n) {
3242
- supplyRewardTokens.push(supplyRewards[i]);
3243
- supplyEmissions.push(data[1].toString());
4095
+ const supplyRewards = decodeAddressArray(supplyRewardsRaw ?? null);
4096
+ const borrowRewards = decodeAddressArray(borrowRewardsRaw ?? null);
4097
+ const rewardsDataCalls = [
4098
+ ...supplyRewards.map((reward) => [
4099
+ controllerAddr,
4100
+ encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [aTokenAddress, reward] })
4101
+ ]),
4102
+ ...borrowRewards.map((reward) => [
4103
+ controllerAddr,
4104
+ encodeFunctionData11({ abi: REWARDS_CONTROLLER_ABI, functionName: "getRewardsData", args: [variableDebtTokenAddress, reward] })
4105
+ ])
4106
+ ];
4107
+ if (rewardsDataCalls.length > 0) {
4108
+ const rewardsDataResults = await multicallRead(this.rpcUrl, rewardsDataCalls);
4109
+ const supplyDataResults = rewardsDataResults.slice(0, supplyRewards.length);
4110
+ const borrowDataResults = rewardsDataResults.slice(supplyRewards.length);
4111
+ for (let i = 0; i < supplyRewards.length; i++) {
4112
+ const data = decodeRewardsData(supplyDataResults[i] ?? null);
4113
+ if (data && data[1] > 0n) {
4114
+ supplyRewardTokens.push(supplyRewards[i]);
4115
+ supplyEmissions.push(data[1].toString());
4116
+ }
3244
4117
  }
3245
- }
3246
- const borrowDataPromises = borrowRewards.map(
3247
- (reward) => client.readContract({
3248
- address: controllerAddr,
3249
- abi: REWARDS_CONTROLLER_ABI,
3250
- functionName: "getRewardsData",
3251
- args: [variableDebtTokenAddress, reward]
3252
- }).catch(() => null)
3253
- );
3254
- const borrowData = await Promise.all(borrowDataPromises);
3255
- for (let i = 0; i < borrowRewards.length; i++) {
3256
- const data = borrowData[i];
3257
- if (data && data[1] > 0n) {
3258
- borrowRewardTokens.push(borrowRewards[i]);
3259
- borrowEmissions.push(data[1].toString());
4118
+ for (let i = 0; i < borrowRewards.length; i++) {
4119
+ const data = decodeRewardsData(borrowDataResults[i] ?? null);
4120
+ if (data && data[1] > 0n) {
4121
+ borrowRewardTokens.push(borrowRewards[i]);
4122
+ borrowEmissions.push(data[1].toString());
4123
+ }
3260
4124
  }
3261
4125
  }
3262
4126
  }
@@ -3268,55 +4132,49 @@ var AaveV3Adapter = class {
3268
4132
  const hasBorrowRewards = borrowRewardTokens.length > 0;
3269
4133
  if ((hasSupplyRewards || hasBorrowRewards) && totalSupply > 0n) {
3270
4134
  try {
3271
- const providerAddr = await client.readContract({
3272
- address: this.pool,
3273
- abi: POOL_PROVIDER_ABI,
3274
- functionName: "ADDRESSES_PROVIDER"
3275
- });
3276
- const oracleAddr = await client.readContract({
3277
- address: providerAddr,
3278
- abi: ADDRESSES_PROVIDER_ABI,
3279
- functionName: "getPriceOracle"
3280
- });
3281
- const [assetPrice, baseCurrencyUnit, assetDecimals] = await Promise.all([
3282
- client.readContract({
3283
- address: oracleAddr,
3284
- abi: ORACLE_ABI,
3285
- functionName: "getAssetPrice",
3286
- args: [asset]
3287
- }),
3288
- client.readContract({
3289
- address: oracleAddr,
3290
- abi: ORACLE_ABI,
3291
- functionName: "BASE_CURRENCY_UNIT"
3292
- }),
3293
- client.readContract({
3294
- address: asset,
3295
- abi: ERC20_DECIMALS_ABI,
3296
- functionName: "decimals"
3297
- }).catch(() => 18)
4135
+ const [providerRaw] = await multicallRead(this.rpcUrl, [
4136
+ [this.pool, encodeFunctionData11({ abi: POOL_PROVIDER_ABI, functionName: "ADDRESSES_PROVIDER" })]
3298
4137
  ]);
3299
- const priceUnit = Number(baseCurrencyUnit);
4138
+ const providerAddr = decodeAddress(providerRaw ?? null);
4139
+ if (!providerAddr) throw new Error("No provider address");
4140
+ const [oracleRaw] = await multicallRead(this.rpcUrl, [
4141
+ [providerAddr, encodeFunctionData11({ abi: ADDRESSES_PROVIDER_ABI, functionName: "getPriceOracle" })]
4142
+ ]);
4143
+ const oracleAddr = decodeAddress(oracleRaw ?? null);
4144
+ if (!oracleAddr) throw new Error("No oracle address");
4145
+ const [assetPriceRaw, baseCurrencyUnitRaw, assetDecimalsRaw] = await multicallRead(this.rpcUrl, [
4146
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [asset] })],
4147
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "BASE_CURRENCY_UNIT" })],
4148
+ [asset, encodeFunctionData11({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
4149
+ ]);
4150
+ const assetPrice = decodeU256(assetPriceRaw ?? null);
4151
+ const baseCurrencyUnit = decodeU256(baseCurrencyUnitRaw ?? null);
4152
+ const assetDecimals = assetDecimalsRaw ? Number(decodeU256(assetDecimalsRaw)) : 18;
4153
+ const priceUnit = Number(baseCurrencyUnit) || 1e8;
3300
4154
  const assetPriceF = Number(assetPrice) / priceUnit;
3301
4155
  const assetDecimalsDivisor = 10 ** assetDecimals;
4156
+ const allRewardTokens = Array.from(/* @__PURE__ */ new Set([...supplyRewardTokens, ...borrowRewardTokens]));
4157
+ const rewardPriceCalls = allRewardTokens.flatMap((token) => [
4158
+ [oracleAddr, encodeFunctionData11({ abi: ORACLE_ABI, functionName: "getAssetPrice", args: [token] })],
4159
+ [token, encodeFunctionData11({ abi: ERC20_DECIMALS_ABI, functionName: "decimals" })]
4160
+ ]);
4161
+ const rewardPriceResults = rewardPriceCalls.length > 0 ? await multicallRead(this.rpcUrl, rewardPriceCalls) : [];
4162
+ const rewardPriceMap = /* @__PURE__ */ new Map();
4163
+ for (let i = 0; i < allRewardTokens.length; i++) {
4164
+ const priceRaw = rewardPriceResults[i * 2] ?? null;
4165
+ const decimalsRaw = rewardPriceResults[i * 2 + 1] ?? null;
4166
+ const price = decodeU256(priceRaw);
4167
+ const decimals = decimalsRaw ? Number(decodeU256(decimalsRaw)) : 18;
4168
+ rewardPriceMap.set(allRewardTokens[i].toLowerCase(), { price, decimals });
4169
+ }
3302
4170
  if (hasSupplyRewards) {
3303
4171
  let totalSupplyIncentiveUsdPerYear = 0;
3304
4172
  const totalSupplyUsd = Number(totalSupply) / assetDecimalsDivisor * assetPriceF;
3305
4173
  for (let i = 0; i < supplyRewardTokens.length; i++) {
3306
4174
  const emissionPerSec = BigInt(supplyEmissions[i]);
3307
- const [rewardPrice, rewardDecimals] = await Promise.all([
3308
- client.readContract({
3309
- address: oracleAddr,
3310
- abi: ORACLE_ABI,
3311
- functionName: "getAssetPrice",
3312
- args: [supplyRewardTokens[i]]
3313
- }).catch(() => 0n),
3314
- client.readContract({
3315
- address: supplyRewardTokens[i],
3316
- abi: ERC20_DECIMALS_ABI,
3317
- functionName: "decimals"
3318
- }).catch(() => 18)
3319
- ]);
4175
+ const entry = rewardPriceMap.get(supplyRewardTokens[i].toLowerCase());
4176
+ const rewardPrice = entry?.price ?? 0n;
4177
+ const rewardDecimals = entry?.decimals ?? 18;
3320
4178
  if (rewardPrice > 0n) {
3321
4179
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3322
4180
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3332,19 +4190,9 @@ var AaveV3Adapter = class {
3332
4190
  const totalBorrowUsd = Number(totalBorrow) / assetDecimalsDivisor * assetPriceF;
3333
4191
  for (let i = 0; i < borrowRewardTokens.length; i++) {
3334
4192
  const emissionPerSec = BigInt(borrowEmissions[i]);
3335
- const [rewardPrice, rewardDecimals] = await Promise.all([
3336
- client.readContract({
3337
- address: oracleAddr,
3338
- abi: ORACLE_ABI,
3339
- functionName: "getAssetPrice",
3340
- args: [borrowRewardTokens[i]]
3341
- }).catch(() => 0n),
3342
- client.readContract({
3343
- address: borrowRewardTokens[i],
3344
- abi: ERC20_DECIMALS_ABI,
3345
- functionName: "decimals"
3346
- }).catch(() => 18)
3347
- ]);
4193
+ const entry = rewardPriceMap.get(borrowRewardTokens[i].toLowerCase());
4194
+ const rewardPrice = entry?.price ?? 0n;
4195
+ const rewardDecimals = entry?.decimals ?? 18;
3348
4196
  if (rewardPrice > 0n) {
3349
4197
  const rewardPriceF = Number(rewardPrice) / priceUnit;
3350
4198
  const emissionPerYear = Number(emissionPerSec) / 10 ** rewardDecimals * SECONDS_PER_YEAR4;
@@ -3408,7 +4256,7 @@ var AaveV3Adapter = class {
3408
4256
  };
3409
4257
  }
3410
4258
  };
3411
- var POOL_ABI2 = parseAbi11([
4259
+ var POOL_ABI2 = parseAbi12([
3412
4260
  "function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
3413
4261
  "function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
3414
4262
  "function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256)",
@@ -3421,7 +4269,7 @@ var POOL_ABI2 = parseAbi11([
3421
4269
  // [9]=variableDebtTokenAddress, [10]=interestRateStrategyAddress, [11]=id
3422
4270
  "function getReserveData(address asset) external view returns (uint256 configuration, uint128 liquidityIndex, uint128 variableBorrowIndex, uint128 currentLiquidityRate, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint8 id)"
3423
4271
  ]);
3424
- var ERC20_ABI2 = parseAbi11([
4272
+ var ERC20_ABI22 = parseAbi12([
3425
4273
  "function totalSupply() external view returns (uint256)"
3426
4274
  ]);
3427
4275
  function u256ToF642(v) {
@@ -3444,7 +4292,7 @@ var AaveV2Adapter = class {
3444
4292
  return this.protocolName;
3445
4293
  }
3446
4294
  async buildSupply(params) {
3447
- const data = encodeFunctionData11({
4295
+ const data = encodeFunctionData12({
3448
4296
  abi: POOL_ABI2,
3449
4297
  functionName: "deposit",
3450
4298
  args: [params.asset, params.amount, params.on_behalf_of, 0]
@@ -3454,12 +4302,13 @@ var AaveV2Adapter = class {
3454
4302
  to: this.pool,
3455
4303
  data,
3456
4304
  value: 0n,
3457
- gas_estimate: 3e5
4305
+ gas_estimate: 3e5,
4306
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3458
4307
  };
3459
4308
  }
3460
4309
  async buildBorrow(params) {
3461
4310
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3462
- const data = encodeFunctionData11({
4311
+ const data = encodeFunctionData12({
3463
4312
  abi: POOL_ABI2,
3464
4313
  functionName: "borrow",
3465
4314
  args: [params.asset, params.amount, rateMode, 0, params.on_behalf_of]
@@ -3474,7 +4323,7 @@ var AaveV2Adapter = class {
3474
4323
  }
3475
4324
  async buildRepay(params) {
3476
4325
  const rateMode = params.interest_rate_mode === InterestRateMode.Stable ? 1n : 2n;
3477
- const data = encodeFunctionData11({
4326
+ const data = encodeFunctionData12({
3478
4327
  abi: POOL_ABI2,
3479
4328
  functionName: "repay",
3480
4329
  args: [params.asset, params.amount, rateMode, params.on_behalf_of]
@@ -3484,11 +4333,12 @@ var AaveV2Adapter = class {
3484
4333
  to: this.pool,
3485
4334
  data,
3486
4335
  value: 0n,
3487
- gas_estimate: 3e5
4336
+ gas_estimate: 3e5,
4337
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3488
4338
  };
3489
4339
  }
3490
4340
  async buildWithdraw(params) {
3491
- const data = encodeFunctionData11({
4341
+ const data = encodeFunctionData12({
3492
4342
  abi: POOL_ABI2,
3493
4343
  functionName: "withdraw",
3494
4344
  args: [params.asset, params.amount, params.to]
@@ -3526,12 +4376,12 @@ var AaveV2Adapter = class {
3526
4376
  const [totalSupply, totalBorrow] = await Promise.all([
3527
4377
  client.readContract({
3528
4378
  address: aTokenAddress,
3529
- abi: ERC20_ABI2,
4379
+ abi: ERC20_ABI22,
3530
4380
  functionName: "totalSupply"
3531
4381
  }).catch(() => 0n),
3532
4382
  client.readContract({
3533
4383
  address: variableDebtTokenAddress,
3534
- abi: ERC20_ABI2,
4384
+ abi: ERC20_ABI22,
3535
4385
  functionName: "totalSupply"
3536
4386
  }).catch(() => 0n)
3537
4387
  ]);
@@ -3576,7 +4426,7 @@ var AaveV2Adapter = class {
3576
4426
  };
3577
4427
  }
3578
4428
  };
3579
- var ORACLE_ABI2 = parseAbi12([
4429
+ var ORACLE_ABI2 = parseAbi13([
3580
4430
  "function getAssetPrice(address asset) external view returns (uint256)",
3581
4431
  "function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory)",
3582
4432
  "function BASE_CURRENCY_UNIT() external view returns (uint256)"
@@ -3653,7 +4503,7 @@ var AaveOracleAdapter = class {
3653
4503
  });
3654
4504
  }
3655
4505
  };
3656
- var CTOKEN_ABI = parseAbi13([
4506
+ var CTOKEN_ABI = parseAbi14([
3657
4507
  "function supplyRatePerBlock() external view returns (uint256)",
3658
4508
  "function borrowRatePerBlock() external view returns (uint256)",
3659
4509
  "function totalSupply() external view returns (uint256)",
@@ -3680,7 +4530,7 @@ var CompoundV2Adapter = class {
3680
4530
  return this.protocolName;
3681
4531
  }
3682
4532
  async buildSupply(params) {
3683
- const data = encodeFunctionData12({
4533
+ const data = encodeFunctionData13({
3684
4534
  abi: CTOKEN_ABI,
3685
4535
  functionName: "mint",
3686
4536
  args: [params.amount]
@@ -3694,7 +4544,7 @@ var CompoundV2Adapter = class {
3694
4544
  };
3695
4545
  }
3696
4546
  async buildBorrow(params) {
3697
- const data = encodeFunctionData12({
4547
+ const data = encodeFunctionData13({
3698
4548
  abi: CTOKEN_ABI,
3699
4549
  functionName: "borrow",
3700
4550
  args: [params.amount]
@@ -3708,7 +4558,7 @@ var CompoundV2Adapter = class {
3708
4558
  };
3709
4559
  }
3710
4560
  async buildRepay(params) {
3711
- const data = encodeFunctionData12({
4561
+ const data = encodeFunctionData13({
3712
4562
  abi: CTOKEN_ABI,
3713
4563
  functionName: "repayBorrow",
3714
4564
  args: [params.amount]
@@ -3722,7 +4572,7 @@ var CompoundV2Adapter = class {
3722
4572
  };
3723
4573
  }
3724
4574
  async buildWithdraw(params) {
3725
- const data = encodeFunctionData12({
4575
+ const data = encodeFunctionData13({
3726
4576
  abi: CTOKEN_ABI,
3727
4577
  functionName: "redeem",
3728
4578
  args: [params.amount]
@@ -3771,7 +4621,7 @@ var CompoundV2Adapter = class {
3771
4621
  );
3772
4622
  }
3773
4623
  };
3774
- var COMET_ABI = parseAbi14([
4624
+ var COMET_ABI = parseAbi15([
3775
4625
  "function getUtilization() external view returns (uint256)",
3776
4626
  "function getSupplyRate(uint256 utilization) external view returns (uint64)",
3777
4627
  "function getBorrowRate(uint256 utilization) external view returns (uint64)",
@@ -3797,7 +4647,7 @@ var CompoundV3Adapter = class {
3797
4647
  return this.protocolName;
3798
4648
  }
3799
4649
  async buildSupply(params) {
3800
- const data = encodeFunctionData13({
4650
+ const data = encodeFunctionData14({
3801
4651
  abi: COMET_ABI,
3802
4652
  functionName: "supply",
3803
4653
  args: [params.asset, params.amount]
@@ -3811,7 +4661,7 @@ var CompoundV3Adapter = class {
3811
4661
  };
3812
4662
  }
3813
4663
  async buildBorrow(params) {
3814
- const data = encodeFunctionData13({
4664
+ const data = encodeFunctionData14({
3815
4665
  abi: COMET_ABI,
3816
4666
  functionName: "withdraw",
3817
4667
  args: [params.asset, params.amount]
@@ -3825,7 +4675,7 @@ var CompoundV3Adapter = class {
3825
4675
  };
3826
4676
  }
3827
4677
  async buildRepay(params) {
3828
- const data = encodeFunctionData13({
4678
+ const data = encodeFunctionData14({
3829
4679
  abi: COMET_ABI,
3830
4680
  functionName: "supply",
3831
4681
  args: [params.asset, params.amount]
@@ -3839,7 +4689,7 @@ var CompoundV3Adapter = class {
3839
4689
  };
3840
4690
  }
3841
4691
  async buildWithdraw(params) {
3842
- const data = encodeFunctionData13({
4692
+ const data = encodeFunctionData14({
3843
4693
  abi: COMET_ABI,
3844
4694
  functionName: "withdraw",
3845
4695
  args: [params.asset, params.amount]
@@ -3893,7 +4743,7 @@ var CompoundV3Adapter = class {
3893
4743
  );
3894
4744
  }
3895
4745
  };
3896
- var EULER_VAULT_ABI = parseAbi15([
4746
+ var EULER_VAULT_ABI = parseAbi16([
3897
4747
  "function deposit(uint256 amount, address receiver) external returns (uint256)",
3898
4748
  "function withdraw(uint256 amount, address receiver, address owner) external returns (uint256)",
3899
4749
  "function borrow(uint256 amount, address receiver) external returns (uint256)",
@@ -3919,7 +4769,7 @@ var EulerV2Adapter = class {
3919
4769
  return this.protocolName;
3920
4770
  }
3921
4771
  async buildSupply(params) {
3922
- const data = encodeFunctionData14({
4772
+ const data = encodeFunctionData15({
3923
4773
  abi: EULER_VAULT_ABI,
3924
4774
  functionName: "deposit",
3925
4775
  args: [params.amount, params.on_behalf_of]
@@ -3933,7 +4783,7 @@ var EulerV2Adapter = class {
3933
4783
  };
3934
4784
  }
3935
4785
  async buildBorrow(params) {
3936
- const data = encodeFunctionData14({
4786
+ const data = encodeFunctionData15({
3937
4787
  abi: EULER_VAULT_ABI,
3938
4788
  functionName: "borrow",
3939
4789
  args: [params.amount, params.on_behalf_of]
@@ -3947,7 +4797,7 @@ var EulerV2Adapter = class {
3947
4797
  };
3948
4798
  }
3949
4799
  async buildRepay(params) {
3950
- const data = encodeFunctionData14({
4800
+ const data = encodeFunctionData15({
3951
4801
  abi: EULER_VAULT_ABI,
3952
4802
  functionName: "repay",
3953
4803
  args: [params.amount, params.on_behalf_of]
@@ -3961,7 +4811,7 @@ var EulerV2Adapter = class {
3961
4811
  };
3962
4812
  }
3963
4813
  async buildWithdraw(params) {
3964
- const data = encodeFunctionData14({
4814
+ const data = encodeFunctionData15({
3965
4815
  abi: EULER_VAULT_ABI,
3966
4816
  functionName: "withdraw",
3967
4817
  args: [params.amount, params.to, params.to]
@@ -4010,7 +4860,7 @@ var EulerV2Adapter = class {
4010
4860
  );
4011
4861
  }
4012
4862
  };
4013
- var MORPHO_ABI = parseAbi16([
4863
+ var MORPHO_ABI = parseAbi17([
4014
4864
  "function market(bytes32 id) external view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
4015
4865
  "function idToMarketParams(bytes32 id) external view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)",
4016
4866
  "function supply((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsSupplied, uint256 sharesSupplied)",
@@ -4018,13 +4868,13 @@ var MORPHO_ABI = parseAbi16([
4018
4868
  "function repay((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, bytes data) external returns (uint256 assetsRepaid, uint256 sharesRepaid)",
4019
4869
  "function withdraw((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn)"
4020
4870
  ]);
4021
- var META_MORPHO_ABI = parseAbi16([
4871
+ var META_MORPHO_ABI = parseAbi17([
4022
4872
  "function supplyQueueLength() external view returns (uint256)",
4023
4873
  "function supplyQueue(uint256 index) external view returns (bytes32)",
4024
4874
  "function totalAssets() external view returns (uint256)",
4025
4875
  "function totalSupply() external view returns (uint256)"
4026
4876
  ]);
4027
- var IRM_ABI = parseAbi16([
4877
+ var IRM_ABI = parseAbi17([
4028
4878
  "function borrowRateView((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) marketParams, (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee) market) external view returns (uint256)"
4029
4879
  ]);
4030
4880
  var SECONDS_PER_YEAR3 = 365.25 * 24 * 3600;
@@ -4037,6 +4887,30 @@ function defaultMarketParams(loanToken = zeroAddress7) {
4037
4887
  lltv: 0n
4038
4888
  };
4039
4889
  }
4890
+ function decodeMarket(data) {
4891
+ if (!data) return null;
4892
+ try {
4893
+ return decodeFunctionResult4({
4894
+ abi: MORPHO_ABI,
4895
+ functionName: "market",
4896
+ data
4897
+ });
4898
+ } catch {
4899
+ return null;
4900
+ }
4901
+ }
4902
+ function decodeMarketParams(data) {
4903
+ if (!data) return null;
4904
+ try {
4905
+ return decodeFunctionResult4({
4906
+ abi: MORPHO_ABI,
4907
+ functionName: "idToMarketParams",
4908
+ data
4909
+ });
4910
+ } catch {
4911
+ return null;
4912
+ }
4913
+ }
4040
4914
  var MorphoBlueAdapter = class {
4041
4915
  protocolName;
4042
4916
  morpho;
@@ -4056,7 +4930,7 @@ var MorphoBlueAdapter = class {
4056
4930
  }
4057
4931
  async buildSupply(params) {
4058
4932
  const market = defaultMarketParams(params.asset);
4059
- const data = encodeFunctionData15({
4933
+ const data = encodeFunctionData16({
4060
4934
  abi: MORPHO_ABI,
4061
4935
  functionName: "supply",
4062
4936
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -4071,7 +4945,7 @@ var MorphoBlueAdapter = class {
4071
4945
  }
4072
4946
  async buildBorrow(params) {
4073
4947
  const market = defaultMarketParams(params.asset);
4074
- const data = encodeFunctionData15({
4948
+ const data = encodeFunctionData16({
4075
4949
  abi: MORPHO_ABI,
4076
4950
  functionName: "borrow",
4077
4951
  args: [market, params.amount, 0n, params.on_behalf_of, params.on_behalf_of]
@@ -4086,7 +4960,7 @@ var MorphoBlueAdapter = class {
4086
4960
  }
4087
4961
  async buildRepay(params) {
4088
4962
  const market = defaultMarketParams(params.asset);
4089
- const data = encodeFunctionData15({
4963
+ const data = encodeFunctionData16({
4090
4964
  abi: MORPHO_ABI,
4091
4965
  functionName: "repay",
4092
4966
  args: [market, params.amount, 0n, params.on_behalf_of, "0x"]
@@ -4101,7 +4975,7 @@ var MorphoBlueAdapter = class {
4101
4975
  }
4102
4976
  async buildWithdraw(params) {
4103
4977
  const market = defaultMarketParams(params.asset);
4104
- const data = encodeFunctionData15({
4978
+ const data = encodeFunctionData16({
4105
4979
  abi: MORPHO_ABI,
4106
4980
  functionName: "withdraw",
4107
4981
  args: [market, params.amount, 0n, params.to, params.to]
@@ -4119,14 +4993,12 @@ var MorphoBlueAdapter = class {
4119
4993
  if (!this.defaultVault) {
4120
4994
  throw DefiError.contractError(`[${this.protocolName}] No MetaMorpho vault configured for rate query`);
4121
4995
  }
4122
- const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4123
- const queueLen = await client.readContract({
4124
- address: this.defaultVault,
4125
- abi: META_MORPHO_ABI,
4126
- functionName: "supplyQueueLength"
4127
- }).catch((e) => {
4996
+ const [queueLenRaw] = await multicallRead(this.rpcUrl, [
4997
+ [this.defaultVault, encodeFunctionData16({ abi: META_MORPHO_ABI, functionName: "supplyQueueLength" })]
4998
+ ]).catch((e) => {
4128
4999
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueueLength failed: ${e}`);
4129
5000
  });
5001
+ const queueLen = decodeU256(queueLenRaw ?? null);
4130
5002
  if (queueLen === 0n) {
4131
5003
  return {
4132
5004
  protocol: this.protocolName,
@@ -4138,45 +5010,40 @@ var MorphoBlueAdapter = class {
4138
5010
  total_borrow: 0n
4139
5011
  };
4140
5012
  }
4141
- const marketId = await client.readContract({
4142
- address: this.defaultVault,
4143
- abi: META_MORPHO_ABI,
4144
- functionName: "supplyQueue",
4145
- args: [0n]
4146
- }).catch((e) => {
5013
+ const [marketIdRaw] = await multicallRead(this.rpcUrl, [
5014
+ [this.defaultVault, encodeFunctionData16({ abi: META_MORPHO_ABI, functionName: "supplyQueue", args: [0n] })]
5015
+ ]).catch((e) => {
4147
5016
  throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) failed: ${e}`);
4148
5017
  });
4149
- const mkt = await client.readContract({
4150
- address: this.morpho,
4151
- abi: MORPHO_ABI,
4152
- functionName: "market",
4153
- args: [marketId]
4154
- }).catch((e) => {
4155
- throw DefiError.rpcError(`[${this.protocolName}] market() failed: ${e}`);
5018
+ if (!marketIdRaw || marketIdRaw.length < 66) {
5019
+ throw DefiError.rpcError(`[${this.protocolName}] supplyQueue(0) returned no data`);
5020
+ }
5021
+ const marketId = marketIdRaw.slice(0, 66);
5022
+ const [marketRaw, paramsRaw] = await multicallRead(this.rpcUrl, [
5023
+ [this.morpho, encodeFunctionData16({ abi: MORPHO_ABI, functionName: "market", args: [marketId] })],
5024
+ [this.morpho, encodeFunctionData16({ abi: MORPHO_ABI, functionName: "idToMarketParams", args: [marketId] })]
5025
+ ]).catch((e) => {
5026
+ throw DefiError.rpcError(`[${this.protocolName}] market/idToMarketParams failed: ${e}`);
4156
5027
  });
4157
- const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mkt;
5028
+ const mktDecoded = decodeMarket(marketRaw ?? null);
5029
+ if (!mktDecoded) throw DefiError.rpcError(`[${this.protocolName}] market() returned no data`);
5030
+ const [totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee] = mktDecoded;
5031
+ const paramsDecoded = decodeMarketParams(paramsRaw ?? null);
5032
+ if (!paramsDecoded) throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams returned no data`);
5033
+ const [loanToken, collateralToken, oracle, irm, lltv] = paramsDecoded;
4158
5034
  const supplyF = Number(totalSupplyAssets);
4159
5035
  const borrowF = Number(totalBorrowAssets);
4160
5036
  const util = supplyF > 0 ? borrowF / supplyF : 0;
4161
- const params2 = await client.readContract({
4162
- address: this.morpho,
4163
- abi: MORPHO_ABI,
4164
- functionName: "idToMarketParams",
4165
- args: [marketId]
4166
- }).catch((e) => {
4167
- throw DefiError.rpcError(`[${this.protocolName}] idToMarketParams failed: ${e}`);
4168
- });
4169
- const [loanToken, collateralToken, oracle, irm, lltv] = params2;
4170
5037
  const irmMarketParams = { loanToken, collateralToken, oracle, irm, lltv };
4171
5038
  const irmMarket = { totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares, lastUpdate, fee };
4172
- const borrowRatePerSec = await client.readContract({
4173
- address: irm,
4174
- abi: IRM_ABI,
4175
- functionName: "borrowRateView",
4176
- args: [irmMarketParams, irmMarket]
4177
- }).catch((e) => {
4178
- throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
4179
- });
5039
+ const borrowRatePerSec = await (async () => {
5040
+ const [borrowRateRaw] = await multicallRead(this.rpcUrl, [
5041
+ [irm, encodeFunctionData16({ abi: IRM_ABI, functionName: "borrowRateView", args: [irmMarketParams, irmMarket] })]
5042
+ ]).catch((e) => {
5043
+ throw DefiError.rpcError(`[${this.protocolName}] borrowRateView failed: ${e}`);
5044
+ });
5045
+ return decodeU256(borrowRateRaw ?? null);
5046
+ })();
4180
5047
  const ratePerSec = Number(borrowRatePerSec) / 1e18;
4181
5048
  const borrowApy = ratePerSec * SECONDS_PER_YEAR3 * 100;
4182
5049
  const feePct = Number(fee) / 1e18;
@@ -4197,18 +5064,18 @@ var MorphoBlueAdapter = class {
4197
5064
  );
4198
5065
  }
4199
5066
  };
4200
- var BORROWER_OPS_ABI = parseAbi17([
5067
+ var BORROWER_OPS_ABI = parseAbi18([
4201
5068
  "function openTrove(address _owner, uint256 _ownerIndex, uint256 _collAmount, uint256 _boldAmount, uint256 _upperHint, uint256 _lowerHint, uint256 _annualInterestRate, uint256 _maxUpfrontFee, address _addManager, address _removeManager, address _receiver) external returns (uint256)",
4202
5069
  "function adjustTrove(uint256 _troveId, uint256 _collChange, bool _isCollIncrease, uint256 _debtChange, bool _isDebtIncrease, uint256 _upperHint, uint256 _lowerHint, uint256 _maxUpfrontFee) external",
4203
5070
  "function closeTrove(uint256 _troveId) external"
4204
5071
  ]);
4205
- var TROVE_MANAGER_ABI = parseAbi17([
5072
+ var TROVE_MANAGER_ABI = parseAbi18([
4206
5073
  "function getLatestTroveData(uint256 _troveId) external view returns (uint256 entireDebt, uint256 entireColl, uint256 redistDebtGain, uint256 redistCollGain, uint256 accruedInterest, uint256 recordedDebt, uint256 annualInterestRate, uint256 accruedBatchManagementFee, uint256 weightedRecordedDebt, uint256 lastInterestRateAdjTime)"
4207
5074
  ]);
4208
- var HINT_HELPERS_ABI = parseAbi17([
5075
+ var HINT_HELPERS_ABI = parseAbi18([
4209
5076
  "function getApproxHint(uint256 _collIndex, uint256 _interestRate, uint256 _numTrials, uint256 _inputRandomSeed) external view returns (uint256 hintId, uint256 diff, uint256 latestRandomSeed)"
4210
5077
  ]);
4211
- var SORTED_TROVES_ABI = parseAbi17([
5078
+ var SORTED_TROVES_ABI = parseAbi18([
4212
5079
  "function findInsertPosition(uint256 _annualInterestRate, uint256 _prevId, uint256 _nextId) external view returns (uint256 prevId, uint256 nextId)"
4213
5080
  ]);
4214
5081
  var FelixCdpAdapter = class {
@@ -4236,7 +5103,7 @@ var FelixCdpAdapter = class {
4236
5103
  if (!this.hintHelpers || !this.sortedTroves || !this.rpcUrl) {
4237
5104
  return [0n, 0n];
4238
5105
  }
4239
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
5106
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4240
5107
  const approxResult = await client.readContract({
4241
5108
  address: this.hintHelpers,
4242
5109
  abi: HINT_HELPERS_ABI,
@@ -4259,7 +5126,7 @@ var FelixCdpAdapter = class {
4259
5126
  const interestRate = 50000000000000000n;
4260
5127
  const [upperHint, lowerHint] = await this.getHints(interestRate);
4261
5128
  const hasHints = upperHint !== 0n || lowerHint !== 0n;
4262
- const data = encodeFunctionData16({
5129
+ const data = encodeFunctionData17({
4263
5130
  abi: BORROWER_OPS_ABI,
4264
5131
  functionName: "openTrove",
4265
5132
  args: [
@@ -4288,7 +5155,7 @@ var FelixCdpAdapter = class {
4288
5155
  async buildAdjust(params) {
4289
5156
  const collChange = params.collateral_delta ?? 0n;
4290
5157
  const debtChange = params.debt_delta ?? 0n;
4291
- const data = encodeFunctionData16({
5158
+ const data = encodeFunctionData17({
4292
5159
  abi: BORROWER_OPS_ABI,
4293
5160
  functionName: "adjustTrove",
4294
5161
  args: [
@@ -4311,7 +5178,7 @@ var FelixCdpAdapter = class {
4311
5178
  };
4312
5179
  }
4313
5180
  async buildClose(params) {
4314
- const data = encodeFunctionData16({
5181
+ const data = encodeFunctionData17({
4315
5182
  abi: BORROWER_OPS_ABI,
4316
5183
  functionName: "closeTrove",
4317
5184
  args: [params.cdp_id]
@@ -4327,7 +5194,7 @@ var FelixCdpAdapter = class {
4327
5194
  async getCdpInfo(cdpId) {
4328
5195
  if (!this.rpcUrl) throw DefiError.rpcError(`[${this.protocolName}] getCdpInfo requires RPC \u2014 set HYPEREVM_RPC_URL`);
4329
5196
  if (!this.troveManager) throw DefiError.contractError(`[${this.protocolName}] trove_manager contract not configured`);
4330
- const client = createPublicClient14({ transport: http14(this.rpcUrl) });
5197
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
4331
5198
  const data = await client.readContract({
4332
5199
  address: this.troveManager,
4333
5200
  abi: TROVE_MANAGER_ABI,
@@ -4360,7 +5227,7 @@ var FelixCdpAdapter = class {
4360
5227
  };
4361
5228
  }
4362
5229
  };
4363
- var PRICE_FEED_ABI = parseAbi18([
5230
+ var PRICE_FEED_ABI = parseAbi19([
4364
5231
  "function fetchPrice() external view returns (uint256 price, bool isNewOracleFailureDetected)",
4365
5232
  "function lastGoodPrice() external view returns (uint256)"
4366
5233
  ]);
@@ -4386,7 +5253,7 @@ var FelixOracleAdapter = class {
4386
5253
  if (asset !== this.asset && this.asset !== "0x0000000000000000000000000000000000000000") {
4387
5254
  throw DefiError.unsupported(`[${this.protocolName}] Felix PriceFeed only supports asset ${this.asset}`);
4388
5255
  }
4389
- const client = createPublicClient15({ transport: http15(this.rpcUrl) });
5256
+ const client = createPublicClient14({ transport: http14(this.rpcUrl) });
4390
5257
  let priceVal;
4391
5258
  try {
4392
5259
  const result = await client.readContract({
@@ -4425,7 +5292,7 @@ var FelixOracleAdapter = class {
4425
5292
  return results;
4426
5293
  }
4427
5294
  };
4428
- var ERC4626_ABI = parseAbi19([
5295
+ var ERC4626_ABI = parseAbi20([
4429
5296
  "function asset() external view returns (address)",
4430
5297
  "function totalAssets() external view returns (uint256)",
4431
5298
  "function totalSupply() external view returns (uint256)",
@@ -4449,7 +5316,7 @@ var ERC4626VaultAdapter = class {
4449
5316
  return this.protocolName;
4450
5317
  }
4451
5318
  async buildDeposit(assets, receiver) {
4452
- const data = encodeFunctionData17({
5319
+ const data = encodeFunctionData18({
4453
5320
  abi: ERC4626_ABI,
4454
5321
  functionName: "deposit",
4455
5322
  args: [assets, receiver]
@@ -4463,7 +5330,7 @@ var ERC4626VaultAdapter = class {
4463
5330
  };
4464
5331
  }
4465
5332
  async buildWithdraw(assets, receiver, owner) {
4466
- const data = encodeFunctionData17({
5333
+ const data = encodeFunctionData18({
4467
5334
  abi: ERC4626_ABI,
4468
5335
  functionName: "withdraw",
4469
5336
  args: [assets, receiver, owner]
@@ -4478,7 +5345,7 @@ var ERC4626VaultAdapter = class {
4478
5345
  }
4479
5346
  async totalAssets() {
4480
5347
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4481
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5348
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4482
5349
  return client.readContract({
4483
5350
  address: this.vaultAddress,
4484
5351
  abi: ERC4626_ABI,
@@ -4489,7 +5356,7 @@ var ERC4626VaultAdapter = class {
4489
5356
  }
4490
5357
  async convertToShares(assets) {
4491
5358
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4492
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5359
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4493
5360
  return client.readContract({
4494
5361
  address: this.vaultAddress,
4495
5362
  abi: ERC4626_ABI,
@@ -4501,7 +5368,7 @@ var ERC4626VaultAdapter = class {
4501
5368
  }
4502
5369
  async convertToAssets(shares) {
4503
5370
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4504
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5371
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4505
5372
  return client.readContract({
4506
5373
  address: this.vaultAddress,
4507
5374
  abi: ERC4626_ABI,
@@ -4513,7 +5380,7 @@ var ERC4626VaultAdapter = class {
4513
5380
  }
4514
5381
  async getVaultInfo() {
4515
5382
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4516
- const client = createPublicClient16({ transport: http16(this.rpcUrl) });
5383
+ const client = createPublicClient15({ transport: http15(this.rpcUrl) });
4517
5384
  const [totalAssets, totalSupply, asset] = await Promise.all([
4518
5385
  client.readContract({ address: this.vaultAddress, abi: ERC4626_ABI, functionName: "totalAssets" }).catch((e) => {
4519
5386
  throw DefiError.rpcError(`[${this.protocolName}] totalAssets failed: ${e}`);
@@ -4534,7 +5401,7 @@ var ERC4626VaultAdapter = class {
4534
5401
  };
4535
5402
  }
4536
5403
  };
4537
- var GENERIC_LST_ABI = parseAbi20([
5404
+ var GENERIC_LST_ABI = parseAbi21([
4538
5405
  "function stake() external payable returns (uint256)",
4539
5406
  "function unstake(uint256 amount) external returns (uint256)"
4540
5407
  ]);
@@ -4551,7 +5418,7 @@ var GenericLstAdapter = class {
4551
5418
  return this.protocolName;
4552
5419
  }
4553
5420
  async buildStake(params) {
4554
- const data = encodeFunctionData18({ abi: GENERIC_LST_ABI, functionName: "stake" });
5421
+ const data = encodeFunctionData19({ abi: GENERIC_LST_ABI, functionName: "stake" });
4555
5422
  return {
4556
5423
  description: `[${this.protocolName}] Stake ${params.amount} HYPE`,
4557
5424
  to: this.staking,
@@ -4561,7 +5428,7 @@ var GenericLstAdapter = class {
4561
5428
  };
4562
5429
  }
4563
5430
  async buildUnstake(params) {
4564
- const data = encodeFunctionData18({
5431
+ const data = encodeFunctionData19({
4565
5432
  abi: GENERIC_LST_ABI,
4566
5433
  functionName: "unstake",
4567
5434
  args: [params.amount]
@@ -4578,11 +5445,11 @@ var GenericLstAdapter = class {
4578
5445
  throw DefiError.unsupported(`[${this.protocolName}] getInfo requires RPC`);
4579
5446
  }
4580
5447
  };
4581
- var STHYPE_ABI = parseAbi21([
5448
+ var STHYPE_ABI = parseAbi222([
4582
5449
  "function submit(address referral) external payable returns (uint256)",
4583
5450
  "function requestWithdrawals(uint256[] amounts, address owner) external returns (uint256[] requestIds)"
4584
5451
  ]);
4585
- var ERC20_ABI3 = parseAbi21([
5452
+ var ERC20_ABI3 = parseAbi222([
4586
5453
  "function totalSupply() external view returns (uint256)"
4587
5454
  ]);
4588
5455
  var StHypeAdapter = class {
@@ -4602,7 +5469,7 @@ var StHypeAdapter = class {
4602
5469
  return this.protocolName;
4603
5470
  }
4604
5471
  async buildStake(params) {
4605
- const data = encodeFunctionData19({
5472
+ const data = encodeFunctionData20({
4606
5473
  abi: STHYPE_ABI,
4607
5474
  functionName: "submit",
4608
5475
  args: [zeroAddress9]
@@ -4616,7 +5483,7 @@ var StHypeAdapter = class {
4616
5483
  };
4617
5484
  }
4618
5485
  async buildUnstake(params) {
4619
- const data = encodeFunctionData19({
5486
+ const data = encodeFunctionData20({
4620
5487
  abi: STHYPE_ABI,
4621
5488
  functionName: "requestWithdrawals",
4622
5489
  args: [[params.amount], params.recipient]
@@ -4631,7 +5498,7 @@ var StHypeAdapter = class {
4631
5498
  }
4632
5499
  async getInfo() {
4633
5500
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4634
- const client = createPublicClient17({ transport: http17(this.rpcUrl) });
5501
+ const client = createPublicClient16({ transport: http16(this.rpcUrl) });
4635
5502
  const tokenAddr = this.sthypeToken ?? this.staking;
4636
5503
  const totalSupply = await client.readContract({
4637
5504
  address: tokenAddr,
@@ -4649,12 +5516,12 @@ var StHypeAdapter = class {
4649
5516
  };
4650
5517
  }
4651
5518
  };
4652
- var KINETIQ_ABI = parseAbi222([
5519
+ var KINETIQ_ABI = parseAbi23([
4653
5520
  "function stake() external payable returns (uint256)",
4654
5521
  "function requestUnstake(uint256 amount) external returns (uint256)",
4655
5522
  "function totalStaked() external view returns (uint256)"
4656
5523
  ]);
4657
- var ORACLE_ABI3 = parseAbi222([
5524
+ var ORACLE_ABI3 = parseAbi23([
4658
5525
  "function getAssetPrice(address asset) external view returns (uint256)"
4659
5526
  ]);
4660
5527
  var WHYPE = "0x5555555555555555555555555555555555555555";
@@ -4676,7 +5543,7 @@ var KinetiqAdapter = class {
4676
5543
  return this.protocolName;
4677
5544
  }
4678
5545
  async buildStake(params) {
4679
- const data = encodeFunctionData20({ abi: KINETIQ_ABI, functionName: "stake" });
5546
+ const data = encodeFunctionData21({ abi: KINETIQ_ABI, functionName: "stake" });
4680
5547
  return {
4681
5548
  description: `[${this.protocolName}] Stake ${params.amount} HYPE for kHYPE`,
4682
5549
  to: this.staking,
@@ -4686,7 +5553,7 @@ var KinetiqAdapter = class {
4686
5553
  };
4687
5554
  }
4688
5555
  async buildUnstake(params) {
4689
- const data = encodeFunctionData20({
5556
+ const data = encodeFunctionData21({
4690
5557
  abi: KINETIQ_ABI,
4691
5558
  functionName: "requestUnstake",
4692
5559
  args: [params.amount]
@@ -4701,7 +5568,7 @@ var KinetiqAdapter = class {
4701
5568
  }
4702
5569
  async getInfo() {
4703
5570
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4704
- const client = createPublicClient18({ transport: http18(this.rpcUrl) });
5571
+ const client = createPublicClient17({ transport: http17(this.rpcUrl) });
4705
5572
  const totalStaked = await client.readContract({
4706
5573
  address: this.staking,
4707
5574
  abi: KINETIQ_ABI,
@@ -4723,15 +5590,15 @@ var KinetiqAdapter = class {
4723
5590
  };
4724
5591
  }
4725
5592
  };
4726
- var HLP_ABI = parseAbi23([
5593
+ var HLP_ABI = parseAbi24([
4727
5594
  "function deposit(uint256 amount) external returns (uint256)",
4728
5595
  "function withdraw(uint256 shares) external returns (uint256)"
4729
5596
  ]);
4730
- var RYSK_ABI = parseAbi24([
5597
+ var RYSK_ABI = parseAbi25([
4731
5598
  "function openOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 premium)",
4732
5599
  "function closeOption(address underlying, uint256 strikePrice, uint256 expiry, bool isCall, uint256 amount) external returns (uint256 payout)"
4733
5600
  ]);
4734
- var ERC721_ABI = parseAbi25([
5601
+ var ERC721_ABI = parseAbi26([
4735
5602
  "function name() returns (string)",
4736
5603
  "function symbol() returns (string)",
4737
5604
  "function totalSupply() returns (uint256)",
@@ -4751,7 +5618,7 @@ var ERC721Adapter = class {
4751
5618
  }
4752
5619
  async getCollectionInfo(collection) {
4753
5620
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4754
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5621
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4755
5622
  const [collectionName, symbol, totalSupply] = await Promise.all([
4756
5623
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "name" }).catch((e) => {
4757
5624
  throw DefiError.rpcError(`[${this.protocolName}] name failed: ${e}`);
@@ -4770,7 +5637,7 @@ var ERC721Adapter = class {
4770
5637
  }
4771
5638
  async getTokenInfo(collection, tokenId) {
4772
5639
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4773
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5640
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4774
5641
  const [owner, tokenUri] = await Promise.all([
4775
5642
  client.readContract({ address: collection, abi: ERC721_ABI, functionName: "ownerOf", args: [tokenId] }).catch((e) => {
4776
5643
  throw DefiError.rpcError(`[${this.protocolName}] ownerOf failed: ${e}`);
@@ -4786,7 +5653,7 @@ var ERC721Adapter = class {
4786
5653
  }
4787
5654
  async getBalance(owner, collection) {
4788
5655
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
4789
- const client = createPublicClient19({ transport: http19(this.rpcUrl) });
5656
+ const client = createPublicClient18({ transport: http18(this.rpcUrl) });
4790
5657
  return client.readContract({ address: collection, abi: ERC721_ABI, functionName: "balanceOf", args: [owner] }).catch((e) => {
4791
5658
  throw DefiError.rpcError(`[${this.protocolName}] balanceOf failed: ${e}`);
4792
5659
  });
@@ -4907,6 +5774,9 @@ function createOracleFromCdp(entry, _asset, rpcUrl) {
4907
5774
  throw DefiError.unsupported(`Oracle not available for CDP interface '${entry.interface}'`);
4908
5775
  }
4909
5776
  }
5777
+ function createMerchantMoeLB(entry, rpcUrl) {
5778
+ return new MerchantMoeLBAdapter(entry, rpcUrl);
5779
+ }
4910
5780
  var DexSpotPrice = class {
4911
5781
  /**
4912
5782
  * Get the spot price for `token` denominated in `quoteToken` (e.g. USDC).
@@ -5914,20 +6784,20 @@ function registerYield(parent, getOpts, makeExecutor2) {
5914
6784
  }
5915
6785
 
5916
6786
  // src/commands/portfolio.ts
5917
- import { encodeFunctionData as encodeFunctionData24, parseAbi as parseAbi27 } from "viem";
6787
+ import { encodeFunctionData as encodeFunctionData25, parseAbi as parseAbi28 } from "viem";
5918
6788
 
5919
6789
  // src/portfolio-tracker.ts
5920
6790
  import { mkdirSync, writeFileSync, readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
5921
6791
  import { homedir } from "os";
5922
6792
  import { resolve as resolve2 } from "path";
5923
- import { encodeFunctionData as encodeFunctionData23, parseAbi as parseAbi26 } from "viem";
5924
- var ERC20_ABI4 = parseAbi26([
6793
+ import { encodeFunctionData as encodeFunctionData24, parseAbi as parseAbi27 } from "viem";
6794
+ var ERC20_ABI4 = parseAbi27([
5925
6795
  "function balanceOf(address owner) external view returns (uint256)"
5926
6796
  ]);
5927
- var ORACLE_ABI4 = parseAbi26([
6797
+ var ORACLE_ABI4 = parseAbi27([
5928
6798
  "function getAssetPrice(address asset) external view returns (uint256)"
5929
6799
  ]);
5930
- var POOL_ABI3 = parseAbi26([
6800
+ var POOL_ABI3 = parseAbi27([
5931
6801
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
5932
6802
  ]);
5933
6803
  function decodeU256Word(data, wordOffset = 0) {
@@ -5956,7 +6826,7 @@ async function takeSnapshot(chainName, wallet, registry) {
5956
6826
  tokenEntries.push({ symbol: t.symbol, address: entry.address, decimals: entry.decimals });
5957
6827
  calls.push([
5958
6828
  entry.address,
5959
- encodeFunctionData23({ abi: ERC20_ABI4, functionName: "balanceOf", args: [user] })
6829
+ encodeFunctionData24({ abi: ERC20_ABI4, functionName: "balanceOf", args: [user] })
5960
6830
  ]);
5961
6831
  callLabels.push(`balance:${t.symbol}`);
5962
6832
  }
@@ -5964,7 +6834,7 @@ async function takeSnapshot(chainName, wallet, registry) {
5964
6834
  for (const p of lendingProtocols) {
5965
6835
  calls.push([
5966
6836
  p.contracts["pool"],
5967
- encodeFunctionData23({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] })
6837
+ encodeFunctionData24({ abi: POOL_ABI3, functionName: "getUserAccountData", args: [user] })
5968
6838
  ]);
5969
6839
  callLabels.push(`lending:${p.name}`);
5970
6840
  }
@@ -5974,7 +6844,7 @@ async function takeSnapshot(chainName, wallet, registry) {
5974
6844
  if (oracleAddr) {
5975
6845
  calls.push([
5976
6846
  oracleAddr,
5977
- encodeFunctionData23({ abi: ORACLE_ABI4, functionName: "getAssetPrice", args: [wrappedNative] })
6847
+ encodeFunctionData24({ abi: ORACLE_ABI4, functionName: "getAssetPrice", args: [wrappedNative] })
5978
6848
  ]);
5979
6849
  callLabels.push("price:native");
5980
6850
  }
@@ -6112,16 +6982,16 @@ function calculatePnL(current, previous) {
6112
6982
  }
6113
6983
 
6114
6984
  // src/commands/portfolio.ts
6115
- var ERC20_ABI5 = parseAbi27([
6985
+ var ERC20_ABI5 = parseAbi28([
6116
6986
  "function balanceOf(address owner) external view returns (uint256)"
6117
6987
  ]);
6118
- var POOL_ABI4 = parseAbi27([
6988
+ var POOL_ABI4 = parseAbi28([
6119
6989
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
6120
6990
  ]);
6121
- var ORACLE_ABI5 = parseAbi27([
6991
+ var ORACLE_ABI5 = parseAbi28([
6122
6992
  "function getAssetPrice(address asset) external view returns (uint256)"
6123
6993
  ]);
6124
- function decodeU256(data, wordOffset = 0) {
6994
+ function decodeU2562(data, wordOffset = 0) {
6125
6995
  if (!data || data.length < 2 + (wordOffset + 1) * 64) return 0n;
6126
6996
  const hex = data.slice(2 + wordOffset * 64, 2 + wordOffset * 64 + 64);
6127
6997
  return BigInt("0x" + hex);
@@ -6158,7 +7028,7 @@ function registerPortfolio(parent, getOpts) {
6158
7028
  if (entry.address === "0x0000000000000000000000000000000000000000") continue;
6159
7029
  calls.push([
6160
7030
  entry.address,
6161
- encodeFunctionData24({ abi: ERC20_ABI5, functionName: "balanceOf", args: [user] })
7031
+ encodeFunctionData25({ abi: ERC20_ABI5, functionName: "balanceOf", args: [user] })
6162
7032
  ]);
6163
7033
  callLabels.push(`balance:${symbol}`);
6164
7034
  }
@@ -6166,7 +7036,7 @@ function registerPortfolio(parent, getOpts) {
6166
7036
  for (const p of lendingProtocols) {
6167
7037
  calls.push([
6168
7038
  p.contracts["pool"],
6169
- encodeFunctionData24({ abi: POOL_ABI4, functionName: "getUserAccountData", args: [user] })
7039
+ encodeFunctionData25({ abi: POOL_ABI4, functionName: "getUserAccountData", args: [user] })
6170
7040
  ]);
6171
7041
  callLabels.push(`lending:${p.name}`);
6172
7042
  }
@@ -6176,7 +7046,7 @@ function registerPortfolio(parent, getOpts) {
6176
7046
  if (oracleAddr) {
6177
7047
  calls.push([
6178
7048
  oracleAddr,
6179
- encodeFunctionData24({ abi: ORACLE_ABI5, functionName: "getAssetPrice", args: [wrappedNative] })
7049
+ encodeFunctionData25({ abi: ORACLE_ABI5, functionName: "getAssetPrice", args: [wrappedNative] })
6180
7050
  ]);
6181
7051
  callLabels.push("price:native");
6182
7052
  }
@@ -6201,7 +7071,7 @@ function registerPortfolio(parent, getOpts) {
6201
7071
  let nativePriceUsd = 0;
6202
7072
  if (oracleAddr) {
6203
7073
  const priceData = results[results.length - 1] ?? null;
6204
- nativePriceUsd = Number(decodeU256(priceData)) / 1e8;
7074
+ nativePriceUsd = Number(decodeU2562(priceData)) / 1e8;
6205
7075
  }
6206
7076
  let totalValueUsd = 0;
6207
7077
  let idx = 0;
@@ -6215,7 +7085,7 @@ function registerPortfolio(parent, getOpts) {
6215
7085
  }
6216
7086
  if (entry.address === "0x0000000000000000000000000000000000000000") continue;
6217
7087
  if (idx >= results.length) break;
6218
- const balance = decodeU256(results[idx] ?? null);
7088
+ const balance = decodeU2562(results[idx] ?? null);
6219
7089
  if (balance > 0n) {
6220
7090
  const decimals = entry.decimals;
6221
7091
  const balF64 = Number(balance) / 10 ** decimals;
@@ -6235,9 +7105,9 @@ function registerPortfolio(parent, getOpts) {
6235
7105
  if (idx >= results.length) break;
6236
7106
  const data = results[idx] ?? null;
6237
7107
  if (data && data.length >= 2 + 192 * 2) {
6238
- const collateral = Number(decodeU256(data, 0)) / 1e8;
6239
- const debt = Number(decodeU256(data, 1)) / 1e8;
6240
- const hfRaw = decodeU256(data, 5);
7108
+ const collateral = Number(decodeU2562(data, 0)) / 1e8;
7109
+ const debt = Number(decodeU2562(data, 1)) / 1e8;
7110
+ const hfRaw = decodeU2562(data, 5);
6241
7111
  let hf = null;
6242
7112
  if (hfRaw <= BigInt("0xffffffffffffffffffffffffffffffff")) {
6243
7113
  const v = Number(hfRaw) / 1e18;
@@ -6538,14 +7408,14 @@ function registerAlert(parent, getOpts) {
6538
7408
  }
6539
7409
 
6540
7410
  // src/commands/scan.ts
6541
- import { encodeFunctionData as encodeFunctionData25, parseAbi as parseAbi28 } from "viem";
6542
- var AAVE_ORACLE_ABI = parseAbi28([
7411
+ import { encodeFunctionData as encodeFunctionData26, parseAbi as parseAbi29 } from "viem";
7412
+ var AAVE_ORACLE_ABI = parseAbi29([
6543
7413
  "function getAssetPrice(address asset) external view returns (uint256)"
6544
7414
  ]);
6545
- var UNIV2_ROUTER_ABI = parseAbi28([
7415
+ var UNIV2_ROUTER_ABI = parseAbi29([
6546
7416
  "function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory)"
6547
7417
  ]);
6548
- var VTOKEN_ABI = parseAbi28([
7418
+ var VTOKEN_ABI = parseAbi29([
6549
7419
  "function exchangeRateStored() external view returns (uint256)"
6550
7420
  ]);
6551
7421
  var STABLECOINS = /* @__PURE__ */ new Set(["USDC", "USDT", "DAI", "USDT0"]);
@@ -6655,7 +7525,7 @@ function registerScan(parent, getOpts) {
6655
7525
  callTypes.push({ kind: "oracle", oracle: oracle.name, token: token.symbol, oracleDecimals: oracle.decimals });
6656
7526
  calls.push([
6657
7527
  oracle.addr,
6658
- encodeFunctionData25({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })
7528
+ encodeFunctionData26({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })
6659
7529
  ]);
6660
7530
  }
6661
7531
  }
@@ -6666,7 +7536,7 @@ function registerScan(parent, getOpts) {
6666
7536
  callTypes.push({ kind: "dex", token: token.symbol, outDecimals: quoteStable.decimals });
6667
7537
  calls.push([
6668
7538
  dexRouter,
6669
- encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [amountIn, path] })
7539
+ encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [amountIn, path] })
6670
7540
  ]);
6671
7541
  }
6672
7542
  }
@@ -6675,7 +7545,7 @@ function registerScan(parent, getOpts) {
6675
7545
  callTypes.push({ kind: "stable", from: "USDC", to: "USDT", outDecimals: usdt.decimals });
6676
7546
  calls.push([
6677
7547
  dexRouter,
6678
- encodeFunctionData25({
7548
+ encodeFunctionData26({
6679
7549
  abi: UNIV2_ROUTER_ABI,
6680
7550
  functionName: "getAmountsOut",
6681
7551
  args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]]
@@ -6684,7 +7554,7 @@ function registerScan(parent, getOpts) {
6684
7554
  callTypes.push({ kind: "stable", from: "USDT", to: "USDC", outDecimals: usdc.decimals });
6685
7555
  calls.push([
6686
7556
  dexRouter,
6687
- encodeFunctionData25({
7557
+ encodeFunctionData26({
6688
7558
  abi: UNIV2_ROUTER_ABI,
6689
7559
  functionName: "getAmountsOut",
6690
7560
  args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]]
@@ -6695,7 +7565,7 @@ function registerScan(parent, getOpts) {
6695
7565
  for (const fork of compoundForks) {
6696
7566
  for (const { key, addr } of fork.vtokens) {
6697
7567
  callTypes.push({ kind: "exchangeRate", protocol: fork.name, vtoken: key });
6698
- calls.push([addr, encodeFunctionData25({ abi: VTOKEN_ABI, functionName: "exchangeRateStored", args: [] })]);
7568
+ calls.push([addr, encodeFunctionData26({ abi: VTOKEN_ABI, functionName: "exchangeRateStored", args: [] })]);
6699
7569
  }
6700
7570
  }
6701
7571
  }
@@ -6913,22 +7783,22 @@ async function runAllChains(registry, patterns, oracleThreshold, stableThreshold
6913
7783
  for (const oracle of oracles) {
6914
7784
  for (const token of scanTokens) {
6915
7785
  cts.push({ kind: "oracle", oracle: oracle.name, token: token.symbol, dec: oracle.decimals });
6916
- calls.push([oracle.addr, encodeFunctionData25({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })]);
7786
+ calls.push([oracle.addr, encodeFunctionData26({ abi: AAVE_ORACLE_ABI, functionName: "getAssetPrice", args: [token.address] })]);
6917
7787
  }
6918
7788
  }
6919
7789
  if (dexRouter) {
6920
7790
  for (const token of scanTokens) {
6921
7791
  const path = wrappedNative && token.address.toLowerCase() === wrappedNative.toLowerCase() ? [token.address, quoteStable.address] : wrappedNative ? [token.address, wrappedNative, quoteStable.address] : [token.address, quoteStable.address];
6922
7792
  cts.push({ kind: "dex", token: token.symbol, dec: quoteStable.decimals });
6923
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(token.decimals), path] })]);
7793
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(token.decimals), path] })]);
6924
7794
  }
6925
7795
  }
6926
7796
  }
6927
7797
  if (doStable && usdc && usdt && dexRouter) {
6928
7798
  cts.push({ kind: "stable", from: "USDC", to: "USDT", dec: usdt.decimals });
6929
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]] })]);
7799
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdc.decimals), [usdc.address, usdt.address]] })]);
6930
7800
  cts.push({ kind: "stable", from: "USDT", to: "USDC", dec: usdc.decimals });
6931
- calls.push([dexRouter, encodeFunctionData25({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]] })]);
7801
+ calls.push([dexRouter, encodeFunctionData26({ abi: UNIV2_ROUTER_ABI, functionName: "getAmountsOut", args: [BigInt(10) ** BigInt(usdt.decimals), [usdt.address, usdc.address]] })]);
6932
7802
  }
6933
7803
  if (calls.length === 0) return null;
6934
7804
  const ct0 = Date.now();
@@ -7056,14 +7926,14 @@ function registerArb(parent, getOpts, makeExecutor2) {
7056
7926
  }
7057
7927
 
7058
7928
  // src/commands/positions.ts
7059
- import { encodeFunctionData as encodeFunctionData26, parseAbi as parseAbi29 } from "viem";
7060
- var ERC20_ABI6 = parseAbi29([
7929
+ import { encodeFunctionData as encodeFunctionData27, parseAbi as parseAbi30 } from "viem";
7930
+ var ERC20_ABI6 = parseAbi30([
7061
7931
  "function balanceOf(address owner) external view returns (uint256)"
7062
7932
  ]);
7063
- var POOL_ABI5 = parseAbi29([
7933
+ var POOL_ABI5 = parseAbi30([
7064
7934
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
7065
7935
  ]);
7066
- var ORACLE_ABI6 = parseAbi29([
7936
+ var ORACLE_ABI6 = parseAbi30([
7067
7937
  "function getAssetPrice(address asset) external view returns (uint256)"
7068
7938
  ]);
7069
7939
  function round22(x) {
@@ -7079,7 +7949,7 @@ function estimateTokenValue(symbol, balance, nativePrice) {
7079
7949
  if (["WETH", "ETH", "METH", "CBETH", "WSTETH"].includes(s)) return balance * 2350;
7080
7950
  return balance * nativePrice;
7081
7951
  }
7082
- function decodeU2562(data, offset = 0) {
7952
+ function decodeU2563(data, offset = 0) {
7083
7953
  if (!data || data.length < 2 + (offset + 32) * 2) return 0n;
7084
7954
  const hex = data.slice(2 + offset * 64, 2 + offset * 64 + 64);
7085
7955
  return BigInt("0x" + hex);
@@ -7092,7 +7962,7 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7092
7962
  callTypes.push({ kind: "token", symbol: token.symbol, decimals: token.decimals });
7093
7963
  calls.push([
7094
7964
  token.address,
7095
- encodeFunctionData26({ abi: ERC20_ABI6, functionName: "balanceOf", args: [user] })
7965
+ encodeFunctionData27({ abi: ERC20_ABI6, functionName: "balanceOf", args: [user] })
7096
7966
  ]);
7097
7967
  }
7098
7968
  }
@@ -7100,14 +7970,14 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7100
7970
  callTypes.push({ kind: "lending", protocol: name, iface });
7101
7971
  calls.push([
7102
7972
  pool,
7103
- encodeFunctionData26({ abi: POOL_ABI5, functionName: "getUserAccountData", args: [user] })
7973
+ encodeFunctionData27({ abi: POOL_ABI5, functionName: "getUserAccountData", args: [user] })
7104
7974
  ]);
7105
7975
  }
7106
7976
  if (oracleAddr) {
7107
7977
  callTypes.push({ kind: "native_price" });
7108
7978
  calls.push([
7109
7979
  oracleAddr,
7110
- encodeFunctionData26({ abi: ORACLE_ABI6, functionName: "getAssetPrice", args: [wrappedNative] })
7980
+ encodeFunctionData27({ abi: ORACLE_ABI6, functionName: "getAssetPrice", args: [wrappedNative] })
7111
7981
  ]);
7112
7982
  }
7113
7983
  if (calls.length === 0) return null;
@@ -7117,7 +7987,7 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7117
7987
  } catch {
7118
7988
  return null;
7119
7989
  }
7120
- const nativePrice = oracleAddr ? Number(decodeU2562(results[results.length - 1])) / 1e8 : 0;
7990
+ const nativePrice = oracleAddr ? Number(decodeU2563(results[results.length - 1])) / 1e8 : 0;
7121
7991
  const tokenBalances = [];
7122
7992
  const lendingPositions = [];
7123
7993
  let chainValue = 0;
@@ -7127,7 +7997,7 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7127
7997
  const ct = callTypes[i];
7128
7998
  const data = results[i] ?? null;
7129
7999
  if (ct.kind === "token") {
7130
- const balance = decodeU2562(data);
8000
+ const balance = decodeU2563(data);
7131
8001
  if (balance > 0n) {
7132
8002
  const balF64 = Number(balance) / 10 ** ct.decimals;
7133
8003
  const valueUsd = estimateTokenValue(ct.symbol, balF64, nativePrice);
@@ -7144,9 +8014,9 @@ async function scanSingleChain(chainName, rpc, user, tokens, lendingPools, oracl
7144
8014
  if (data && data.length >= 2 + 192 * 2) {
7145
8015
  const priceDecimals = ct.iface === "aave_v2" ? 18 : 8;
7146
8016
  const divisor = 10 ** priceDecimals;
7147
- const collateral = Number(decodeU2562(data, 0)) / divisor;
7148
- const debt = Number(decodeU2562(data, 1)) / divisor;
7149
- const hfRaw = decodeU2562(data, 5);
8017
+ const collateral = Number(decodeU2563(data, 0)) / divisor;
8018
+ const debt = Number(decodeU2563(data, 1)) / divisor;
8019
+ const hfRaw = decodeU2563(data, 5);
7150
8020
  let hf = null;
7151
8021
  if (hfRaw <= BigInt("0xffffffffffffffffffffffffffffffff")) {
7152
8022
  const v = Number(hfRaw) / 1e18;
@@ -7400,14 +8270,14 @@ function registerPrice(parent, getOpts) {
7400
8270
  }
7401
8271
 
7402
8272
  // src/commands/wallet.ts
7403
- import { createPublicClient as createPublicClient20, http as http20, formatEther } from "viem";
8273
+ import { createPublicClient as createPublicClient19, http as http19, formatEther } from "viem";
7404
8274
  function registerWallet(parent, getOpts) {
7405
8275
  const wallet = parent.command("wallet").description("Wallet management");
7406
8276
  wallet.command("balance").description("Show native token balance").requiredOption("--address <address>", "Wallet address to query").action(async (opts) => {
7407
8277
  const chainName = parent.opts().chain ?? "hyperevm";
7408
8278
  const registry = Registry.loadEmbedded();
7409
8279
  const chain = registry.getChain(chainName);
7410
- const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
8280
+ const client = createPublicClient19({ transport: http19(chain.effectiveRpcUrl()) });
7411
8281
  const balance = await client.getBalance({ address: opts.address });
7412
8282
  printOutput({
7413
8283
  chain: chain.name,
@@ -7424,14 +8294,14 @@ function registerWallet(parent, getOpts) {
7424
8294
  }
7425
8295
 
7426
8296
  // src/commands/token.ts
7427
- import { createPublicClient as createPublicClient21, http as http21, maxUint256 } from "viem";
8297
+ import { createPublicClient as createPublicClient20, http as http20, maxUint256 } from "viem";
7428
8298
  function registerToken(parent, getOpts, makeExecutor2) {
7429
8299
  const token = parent.command("token").description("Token operations: approve, allowance, transfer, balance");
7430
8300
  token.command("balance").description("Query token balance for an address").requiredOption("--token <token>", "Token symbol or address").requiredOption("--owner <address>", "Wallet address to query").action(async (opts) => {
7431
8301
  const chainName = parent.opts().chain ?? "hyperevm";
7432
8302
  const registry = Registry.loadEmbedded();
7433
8303
  const chain = registry.getChain(chainName);
7434
- const client = createPublicClient21({ transport: http21(chain.effectiveRpcUrl()) });
8304
+ const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
7435
8305
  const tokenAddr = opts.token.startsWith("0x") ? opts.token : registry.resolveToken(chainName, opts.token).address;
7436
8306
  const [balance, symbol, decimals] = await Promise.all([
7437
8307
  client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "balanceOf", args: [opts.owner] }),
@@ -7460,7 +8330,7 @@ function registerToken(parent, getOpts, makeExecutor2) {
7460
8330
  const chainName = parent.opts().chain ?? "hyperevm";
7461
8331
  const registry = Registry.loadEmbedded();
7462
8332
  const chain = registry.getChain(chainName);
7463
- const client = createPublicClient21({ transport: http21(chain.effectiveRpcUrl()) });
8333
+ const client = createPublicClient20({ transport: http20(chain.effectiveRpcUrl()) });
7464
8334
  const tokenAddr = opts.token.startsWith("0x") ? opts.token : registry.resolveToken(chainName, opts.token).address;
7465
8335
  const allowance = await client.readContract({
7466
8336
  address: tokenAddr,
@@ -7482,8 +8352,8 @@ function registerToken(parent, getOpts, makeExecutor2) {
7482
8352
  }
7483
8353
 
7484
8354
  // src/commands/whales.ts
7485
- import { encodeFunctionData as encodeFunctionData27, parseAbi as parseAbi30 } from "viem";
7486
- var POOL_ABI6 = parseAbi30([
8355
+ import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31 } from "viem";
8356
+ var POOL_ABI6 = parseAbi31([
7487
8357
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)"
7488
8358
  ]);
7489
8359
  function round24(x) {
@@ -7492,7 +8362,7 @@ function round24(x) {
7492
8362
  function round43(x) {
7493
8363
  return Math.round(x * 1e4) / 1e4;
7494
8364
  }
7495
- function decodeU2563(data, wordOffset = 0) {
8365
+ function decodeU2564(data, wordOffset = 0) {
7496
8366
  if (!data || data.length < 2 + (wordOffset + 1) * 64) return 0n;
7497
8367
  const hex = data.slice(2 + wordOffset * 64, 2 + wordOffset * 64 + 64);
7498
8368
  return BigInt("0x" + hex);
@@ -7594,7 +8464,7 @@ function registerWhales(parent, getOpts) {
7594
8464
  for (const { pool } of lendingPools) {
7595
8465
  calls.push([
7596
8466
  pool,
7597
- encodeFunctionData27({ abi: POOL_ABI6, functionName: "getUserAccountData", args: [whale.address] })
8467
+ encodeFunctionData28({ abi: POOL_ABI6, functionName: "getUserAccountData", args: [whale.address] })
7598
8468
  ]);
7599
8469
  }
7600
8470
  }
@@ -7617,9 +8487,9 @@ function registerWhales(parent, getOpts) {
7617
8487
  if (data && data.length >= 2 + 192 * 2) {
7618
8488
  const dec = iface === "aave_v2" ? 18 : 8;
7619
8489
  const divisor = 10 ** dec;
7620
- const collateral = Number(decodeU2563(data, 0)) / divisor;
7621
- const debt = Number(decodeU2563(data, 1)) / divisor;
7622
- const hfRaw = decodeU2563(data, 5);
8490
+ const collateral = Number(decodeU2564(data, 0)) / divisor;
8491
+ const debt = Number(decodeU2564(data, 1)) / divisor;
8492
+ const hfRaw = decodeU2564(data, 5);
7623
8493
  let hf = null;
7624
8494
  if (hfRaw <= BigInt("0xffffffffffffffffffffffffffffffff")) {
7625
8495
  const v = Number(hfRaw) / 1e18;
@@ -8022,11 +8892,11 @@ function registerBridge(parent, getOpts) {
8022
8892
  const amountUsdc = Number(BigInt(opts.amount)) / 1e6;
8023
8893
  const { fee, maxFeeSubunits } = await getCctpFeeEstimate(srcDomain, dstDomain, amountUsdc);
8024
8894
  const recipientPadded = `0x${"0".repeat(24)}${recipient.replace("0x", "").toLowerCase()}`;
8025
- const { encodeFunctionData: encodeFunctionData28, parseAbi: parseAbi31 } = await import("viem");
8026
- const tokenMessengerAbi = parseAbi31([
8895
+ const { encodeFunctionData: encodeFunctionData29, parseAbi: parseAbi33 } = await import("viem");
8896
+ const tokenMessengerAbi = parseAbi33([
8027
8897
  "function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 minFinalityThreshold) external returns (uint64 nonce)"
8028
8898
  ]);
8029
- const data = encodeFunctionData28({
8899
+ const data = encodeFunctionData29({
8030
8900
  abi: tokenMessengerAbi,
8031
8901
  functionName: "depositForBurn",
8032
8902
  args: [
@@ -8363,6 +9233,107 @@ function registerSetup(program2) {
8363
9233
  });
8364
9234
  }
8365
9235
 
9236
+ // src/commands/lb.ts
9237
+ function registerLB(parent, getOpts, makeExecutor2) {
9238
+ const lb = parent.command("lb").description("Merchant Moe Liquidity Book: add/remove liquidity, rewards, positions");
9239
+ lb.command("add").description("Add liquidity to a Liquidity Book pair").requiredOption("--protocol <protocol>", "Protocol slug (e.g. merchantmoe-mantle)").requiredOption("--pool <address>", "LB pair address").requiredOption("--token-x <address>", "Token X address").requiredOption("--token-y <address>", "Token Y address").requiredOption("--bin-step <step>", "Bin step of the pair").option("--amount-x <wei>", "Amount of token X in wei", "0").option("--amount-y <wei>", "Amount of token Y in wei", "0").option("--bins <N>", "Number of bins on each side of active bin", "5").option("--active-id <id>", "Active bin id (defaults to on-chain query)").option("--recipient <address>", "Recipient address").action(async (opts) => {
9240
+ const executor = makeExecutor2();
9241
+ const registry = Registry.loadEmbedded();
9242
+ const protocol = registry.getProtocol(opts.protocol);
9243
+ const chainName = parent.opts().chain;
9244
+ const chain = registry.getChain(chainName ?? "mantle");
9245
+ const rpcUrl = chain.effectiveRpcUrl();
9246
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9247
+ const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
9248
+ const tx = await adapter.buildAddLiquidity({
9249
+ pool: opts.pool,
9250
+ tokenX: opts.tokenX,
9251
+ tokenY: opts.tokenY,
9252
+ binStep: parseInt(opts.binStep),
9253
+ amountX: BigInt(opts.amountX),
9254
+ amountY: BigInt(opts.amountY),
9255
+ numBins: parseInt(opts.bins),
9256
+ activeIdDesired: opts.activeId ? parseInt(opts.activeId) : void 0,
9257
+ recipient
9258
+ });
9259
+ const result = await executor.execute(tx);
9260
+ printOutput(result, getOpts());
9261
+ });
9262
+ lb.command("remove").description("Remove liquidity from Liquidity Book bins").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--token-x <address>", "Token X address").requiredOption("--token-y <address>", "Token Y address").requiredOption("--bin-step <step>", "Bin step of the pair").requiredOption("--bins <binIds>", "Comma-separated bin IDs to remove from").requiredOption("--amounts <amounts>", "Comma-separated LB token amounts to remove per bin (wei)").option("--recipient <address>", "Recipient address").action(async (opts) => {
9263
+ const executor = makeExecutor2();
9264
+ const registry = Registry.loadEmbedded();
9265
+ const protocol = registry.getProtocol(opts.protocol);
9266
+ const adapter = createMerchantMoeLB(protocol);
9267
+ const recipient = opts.recipient ?? process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
9268
+ const binIds = opts.bins.split(",").map((s) => parseInt(s.trim()));
9269
+ const amounts = opts.amounts.split(",").map((s) => BigInt(s.trim()));
9270
+ const tx = await adapter.buildRemoveLiquidity({
9271
+ tokenX: opts.tokenX,
9272
+ tokenY: opts.tokenY,
9273
+ binStep: parseInt(opts.binStep),
9274
+ binIds,
9275
+ amounts,
9276
+ recipient
9277
+ });
9278
+ const result = await executor.execute(tx);
9279
+ printOutput(result, getOpts());
9280
+ });
9281
+ lb.command("rewards").description("Show pending MOE rewards for a pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to check (auto-detected from rewarder range if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9282
+ const registry = Registry.loadEmbedded();
9283
+ const protocol = registry.getProtocol(opts.protocol);
9284
+ const chainName = parent.opts().chain;
9285
+ const chain = registry.getChain(chainName ?? "mantle");
9286
+ const rpcUrl = chain.effectiveRpcUrl();
9287
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9288
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9289
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9290
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9291
+ const rewards = await adapter.getPendingRewards(user, opts.pool, binIds);
9292
+ printOutput(rewards, getOpts());
9293
+ });
9294
+ lb.command("claim").description("Claim pending MOE rewards from a pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to claim from (auto-detected from rewarder range if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9295
+ const executor = makeExecutor2();
9296
+ const registry = Registry.loadEmbedded();
9297
+ const protocol = registry.getProtocol(opts.protocol);
9298
+ const chainName = parent.opts().chain;
9299
+ const chain = registry.getChain(chainName ?? "mantle");
9300
+ const rpcUrl = chain.effectiveRpcUrl();
9301
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9302
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9303
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9304
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9305
+ const tx = await adapter.buildClaimRewards(user, opts.pool, binIds);
9306
+ const result = await executor.execute(tx);
9307
+ printOutput(result, getOpts());
9308
+ });
9309
+ lb.command("discover").description("Find all rewarded LB pools on chain").requiredOption("--protocol <protocol>", "Protocol slug").option("--active-only", "Only show non-stopped pools").action(async (opts) => {
9310
+ const registry = Registry.loadEmbedded();
9311
+ const protocol = registry.getProtocol(opts.protocol);
9312
+ const chainName = parent.opts().chain;
9313
+ const chain = registry.getChain(chainName ?? "mantle");
9314
+ const rpcUrl = chain.effectiveRpcUrl();
9315
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9316
+ let pools = await adapter.discoverRewardedPools();
9317
+ if (opts.activeOnly) {
9318
+ pools = pools.filter((p) => !p.stopped);
9319
+ }
9320
+ printOutput(pools, getOpts());
9321
+ });
9322
+ lb.command("positions").description("Show user positions per bin in a LB pool").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--pool <address>", "LB pair address").option("--bins <binIds>", "Comma-separated bin IDs to query (auto-detected from rewarder range or active \xB1 50 if omitted)").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
9323
+ const registry = Registry.loadEmbedded();
9324
+ const protocol = registry.getProtocol(opts.protocol);
9325
+ const chainName = parent.opts().chain;
9326
+ const chain = registry.getChain(chainName ?? "mantle");
9327
+ const rpcUrl = chain.effectiveRpcUrl();
9328
+ const adapter = createMerchantMoeLB(protocol, rpcUrl);
9329
+ const user = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
9330
+ if (!user) throw new Error("--address or DEFI_WALLET_ADDRESS required");
9331
+ const binIds = opts.bins ? opts.bins.split(",").map((s) => parseInt(s.trim())) : void 0;
9332
+ const positions = await adapter.getUserPositions(user, opts.pool, binIds);
9333
+ printOutput(positions, getOpts());
9334
+ });
9335
+ }
9336
+
8366
9337
  // src/cli.ts
8367
9338
  var _require = createRequire(import.meta.url);
8368
9339
  var _pkg = _require("../package.json");
@@ -8374,7 +9345,7 @@ var BANNER = `
8374
9345
  \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
8375
9346
  \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D
8376
9347
 
8377
- 2 chains \xB7 32 protocols \xB7 by HypurrQuant
9348
+ 2 chains \xB7 30 protocols \xB7 by HypurrQuant
8378
9349
 
8379
9350
  Scan exploits, swap tokens, bridge assets, track whales,
8380
9351
  compare yields \u2014 all from your terminal.
@@ -8414,6 +9385,7 @@ registerSwap(program, getOutputMode, makeExecutor);
8414
9385
  registerBridge(program, getOutputMode);
8415
9386
  registerNft(program, getOutputMode);
8416
9387
  registerFarm(program, getOutputMode, makeExecutor);
9388
+ registerLB(program, getOutputMode, makeExecutor);
8417
9389
  registerSetup(program);
8418
9390
  program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
8419
9391
  const executor = makeExecutor();