@hypurrquant/defi-cli 0.2.3 → 0.2.5

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.
@@ -23,7 +23,7 @@ tags = ["stablecoin"]
23
23
  [[token]]
24
24
  symbol = "USDT0"
25
25
  name = "Tether USD (USDT0)"
26
- address = "0xB8CE59FC3717adA4c02EADF9682a9E934F625EBb"
26
+ address = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"
27
27
  decimals = 6
28
28
  tags = ["stablecoin"]
29
29
 
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
@@ -1008,8 +1008,13 @@ var Registry = class _Registry {
1008
1008
  };
1009
1009
 
1010
1010
  // src/executor.ts
1011
+ var ERC20_ABI = parseAbi3([
1012
+ "function allowance(address owner, address spender) external view returns (uint256)",
1013
+ "function approve(address spender, uint256 amount) external returns (bool)"
1014
+ ]);
1011
1015
  var GAS_BUFFER_BPS = 12000n;
1012
- var DEFAULT_PRIORITY_FEE_WEI = 100000000n;
1016
+ var DEFAULT_PRIORITY_FEE_WEI = 20000000000n;
1017
+ var MAX_GAS_LIMIT = 5000000000n;
1013
1018
  var Executor = class _Executor {
1014
1019
  dryRun;
1015
1020
  rpcUrl;
@@ -1023,6 +1028,62 @@ var Executor = class _Executor {
1023
1028
  static applyGasBuffer(gas) {
1024
1029
  return gas * GAS_BUFFER_BPS / 10000n;
1025
1030
  }
1031
+ /**
1032
+ * Check allowance for a single token/spender pair and send an approve tx if needed.
1033
+ * Only called in broadcast mode (not dry-run).
1034
+ */
1035
+ async checkAndApprove(token, spender, amount, owner, publicClient, walletClient) {
1036
+ const allowance = await publicClient.readContract({
1037
+ address: token,
1038
+ abi: ERC20_ABI,
1039
+ functionName: "allowance",
1040
+ args: [owner, spender]
1041
+ });
1042
+ if (allowance >= amount) return;
1043
+ process.stderr.write(
1044
+ ` Approving ${amount} of ${token} for ${spender}...
1045
+ `
1046
+ );
1047
+ const approveData = encodeFunctionData3({
1048
+ abi: ERC20_ABI,
1049
+ functionName: "approve",
1050
+ args: [spender, amount]
1051
+ });
1052
+ const rpcUrl = this.rpcUrl;
1053
+ const gasLimit = await (async () => {
1054
+ try {
1055
+ const estimated = await publicClient.estimateGas({
1056
+ to: token,
1057
+ data: approveData,
1058
+ account: owner
1059
+ });
1060
+ const buffered = _Executor.applyGasBuffer(estimated);
1061
+ return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
1062
+ } catch {
1063
+ return 80000n;
1064
+ }
1065
+ })();
1066
+ const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
1067
+ const approveTxHash = await walletClient.sendTransaction({
1068
+ chain: null,
1069
+ account: walletClient.account,
1070
+ to: token,
1071
+ data: approveData,
1072
+ gas: gasLimit > 0n ? gasLimit : void 0,
1073
+ maxFeePerGas: maxFeePerGas > 0n ? maxFeePerGas : void 0,
1074
+ maxPriorityFeePerGas: maxPriorityFeePerGas > 0n ? maxPriorityFeePerGas : void 0
1075
+ });
1076
+ const approveTxUrl = this.explorerUrl ? `${this.explorerUrl}/tx/${approveTxHash}` : void 0;
1077
+ process.stderr.write(` Approve tx: ${approveTxHash}
1078
+ `);
1079
+ if (approveTxUrl) process.stderr.write(` Explorer: ${approveTxUrl}
1080
+ `);
1081
+ await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
1082
+ process.stderr.write(
1083
+ ` Approved ${amount} of ${token} for ${spender}
1084
+ `
1085
+ );
1086
+ }
1026
1087
  /** Fetch EIP-1559 fee params from the network. Returns [maxFeePerGas, maxPriorityFeePerGas]. */
1027
1088
  async fetchEip1559Fees(rpcUrl) {
1028
1089
  try {
@@ -1049,7 +1110,10 @@ var Executor = class _Executor {
1049
1110
  value: tx.value,
1050
1111
  account: from
1051
1112
  });
1052
- if (estimated > 0n) return _Executor.applyGasBuffer(estimated);
1113
+ if (estimated > 0n) {
1114
+ const buffered = _Executor.applyGasBuffer(estimated);
1115
+ return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
1116
+ }
1053
1117
  } catch {
1054
1118
  }
1055
1119
  return tx.gas_estimate ? BigInt(tx.gas_estimate) : 0n;
@@ -1135,6 +1199,18 @@ var Executor = class _Executor {
1135
1199
  }
1136
1200
  const publicClient = createPublicClient2({ transport: http2(rpcUrl) });
1137
1201
  const walletClient = createWalletClient({ account, transport: http2(rpcUrl) });
1202
+ if (tx.approvals && tx.approvals.length > 0) {
1203
+ for (const approval of tx.approvals) {
1204
+ await this.checkAndApprove(
1205
+ approval.token,
1206
+ approval.spender,
1207
+ approval.amount,
1208
+ account.address,
1209
+ publicClient,
1210
+ walletClient
1211
+ );
1212
+ }
1213
+ }
1138
1214
  const gasLimit = await this.estimateGasWithBuffer(rpcUrl, tx, account.address);
1139
1215
  const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
1140
1216
  process.stderr.write(`Broadcasting transaction to ${rpcUrl}...
@@ -1711,10 +1787,10 @@ function registerSchema(parent, getOpts) {
1711
1787
  }
1712
1788
 
1713
1789
  // ../defi-protocols/dist/index.js
1714
- import { encodeFunctionData as encodeFunctionData3, parseAbi as parseAbi3, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters } from "viem";
1790
+ import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters } from "viem";
1715
1791
  import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, createPublicClient as createPublicClient22, http as http22, decodeFunctionResult as decodeFunctionResult2, decodeAbiParameters as decodeAbiParameters2 } from "viem";
1716
1792
  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";
1793
+ import { encodeFunctionData as encodeFunctionData42, parseAbi as parseAbi42, zeroAddress as zeroAddress2 } from "viem";
1718
1794
  import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
1719
1795
  import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, createPublicClient as createPublicClient42, http as http42, decodeAbiParameters as decodeAbiParameters4 } from "viem";
1720
1796
  import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, zeroAddress as zeroAddress3 } from "viem";
@@ -1737,19 +1813,19 @@ import { parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } fr
1737
1813
  import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
1738
1814
  import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25 } from "viem";
1739
1815
  var DEFAULT_FEE = 3e3;
1740
- var swapRouterAbi = parseAbi3([
1816
+ var swapRouterAbi = parseAbi4([
1741
1817
  "struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
1742
1818
  "function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut)"
1743
1819
  ]);
1744
- var quoterAbi = parseAbi3([
1820
+ var quoterAbi = parseAbi4([
1745
1821
  "struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; }",
1746
1822
  "function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
1747
1823
  ]);
1748
- var ramsesQuoterAbi = parseAbi3([
1824
+ var ramsesQuoterAbi = parseAbi4([
1749
1825
  "struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; int24 tickSpacing; uint160 sqrtPriceLimitX96; }",
1750
1826
  "function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
1751
1827
  ]);
1752
- var positionManagerAbi = parseAbi3([
1828
+ var positionManagerAbi = parseAbi4([
1753
1829
  "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
1830
  "function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
1755
1831
  ]);
@@ -1782,7 +1858,7 @@ var UniswapV3Adapter = class {
1782
1858
  async buildSwap(params) {
1783
1859
  const deadline = BigInt(params.deadline ?? 18446744073709551615n);
1784
1860
  const amountOutMinimum = 0n;
1785
- const data = encodeFunctionData3({
1861
+ const data = encodeFunctionData4({
1786
1862
  abi: swapRouterAbi,
1787
1863
  functionName: "exactInputSingle",
1788
1864
  args: [
@@ -1803,7 +1879,8 @@ var UniswapV3Adapter = class {
1803
1879
  to: this.router,
1804
1880
  data,
1805
1881
  value: 0n,
1806
- gas_estimate: 2e5
1882
+ gas_estimate: 2e5,
1883
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
1807
1884
  };
1808
1885
  }
1809
1886
  async quote(params) {
@@ -1818,7 +1895,7 @@ var UniswapV3Adapter = class {
1818
1895
  tickSpacings.map(async (ts) => {
1819
1896
  const result = await client2.call({
1820
1897
  to: this.quoter,
1821
- data: encodeFunctionData3({
1898
+ data: encodeFunctionData4({
1822
1899
  abi: ramsesQuoterAbi,
1823
1900
  functionName: "quoteExactInputSingle",
1824
1901
  args: [
@@ -1864,7 +1941,7 @@ var UniswapV3Adapter = class {
1864
1941
  feeTiers.map(async (fee) => {
1865
1942
  const result = await client2.call({
1866
1943
  to: this.quoter,
1867
- data: encodeFunctionData3({
1944
+ data: encodeFunctionData4({
1868
1945
  abi: quoterAbi,
1869
1946
  functionName: "quoteExactInputSingle",
1870
1947
  args: [
@@ -1903,7 +1980,7 @@ var UniswapV3Adapter = class {
1903
1980
  }
1904
1981
  }
1905
1982
  const client = createPublicClient4({ transport: http4(this.rpcUrl) });
1906
- const callData = encodeFunctionData3({
1983
+ const callData = encodeFunctionData4({
1907
1984
  abi: swapRouterAbi,
1908
1985
  functionName: "exactInputSingle",
1909
1986
  args: [
@@ -1949,7 +2026,7 @@ var UniswapV3Adapter = class {
1949
2026
  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
2027
  const amount0 = rawAmount0 === 0n && rawAmount1 > 0n ? 1n : rawAmount0;
1951
2028
  const amount1 = rawAmount1 === 0n && rawAmount0 > 0n ? 1n : rawAmount1;
1952
- const data = encodeFunctionData3({
2029
+ const data = encodeFunctionData4({
1953
2030
  abi: positionManagerAbi,
1954
2031
  functionName: "mint",
1955
2032
  args: [
@@ -1973,7 +2050,11 @@ var UniswapV3Adapter = class {
1973
2050
  to: pm,
1974
2051
  data,
1975
2052
  value: 0n,
1976
- gas_estimate: 5e5
2053
+ gas_estimate: 5e5,
2054
+ approvals: [
2055
+ { token: token0, spender: pm, amount: amount0 },
2056
+ { token: token1, spender: pm, amount: amount1 }
2057
+ ]
1977
2058
  };
1978
2059
  }
1979
2060
  async buildRemoveLiquidity(_params) {
@@ -2032,7 +2113,8 @@ var UniswapV2Adapter = class {
2032
2113
  to: this.router,
2033
2114
  data,
2034
2115
  value: 0n,
2035
- gas_estimate: 15e4
2116
+ gas_estimate: 15e4,
2117
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2036
2118
  };
2037
2119
  }
2038
2120
  async quote(params) {
@@ -2151,7 +2233,11 @@ var UniswapV2Adapter = class {
2151
2233
  to: this.router,
2152
2234
  data,
2153
2235
  value: 0n,
2154
- gas_estimate: 3e5
2236
+ gas_estimate: 3e5,
2237
+ approvals: [
2238
+ { token: params.token_a, spender: this.router, amount: params.amount_a },
2239
+ { token: params.token_b, spender: this.router, amount: params.amount_b }
2240
+ ]
2155
2241
  };
2156
2242
  }
2157
2243
  async buildRemoveLiquidity(params) {
@@ -2238,7 +2324,8 @@ var AlgebraV3Adapter = class {
2238
2324
  to: this.router,
2239
2325
  data,
2240
2326
  value: 0n,
2241
- gas_estimate: 25e4
2327
+ gas_estimate: 25e4,
2328
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2242
2329
  };
2243
2330
  }
2244
2331
  async quote(params) {
@@ -2356,7 +2443,11 @@ var AlgebraV3Adapter = class {
2356
2443
  to: pm,
2357
2444
  data,
2358
2445
  value: 0n,
2359
- gas_estimate: 5e5
2446
+ gas_estimate: 5e5,
2447
+ approvals: [
2448
+ { token: token0, spender: pm, amount: amount0 },
2449
+ { token: token1, spender: pm, amount: amount1 }
2450
+ ]
2360
2451
  };
2361
2452
  }
2362
2453
  async buildRemoveLiquidity(_params) {
@@ -2365,7 +2456,7 @@ var AlgebraV3Adapter = class {
2365
2456
  );
2366
2457
  }
2367
2458
  };
2368
- var abi3 = parseAbi4([
2459
+ var abi3 = parseAbi42([
2369
2460
  "function swapSingleTokenExactIn(address pool, address tokenIn, address tokenOut, uint256 exactAmountIn, uint256 minAmountOut, uint256 deadline, bool wethIsEth, bytes calldata userData) external returns (uint256 amountOut)"
2370
2461
  ]);
2371
2462
  var BalancerV3Adapter = class {
@@ -2385,7 +2476,7 @@ var BalancerV3Adapter = class {
2385
2476
  async buildSwap(params) {
2386
2477
  const minAmountOut = 0n;
2387
2478
  const deadline = BigInt(params.deadline ?? 18446744073709551615n);
2388
- const data = encodeFunctionData4({
2479
+ const data = encodeFunctionData42({
2389
2480
  abi: abi3,
2390
2481
  functionName: "swapSingleTokenExactIn",
2391
2482
  args: [
@@ -2533,7 +2624,8 @@ var SolidlyAdapter = class {
2533
2624
  to: this.router,
2534
2625
  data,
2535
2626
  value: 0n,
2536
- gas_estimate: 2e5
2627
+ gas_estimate: 2e5,
2628
+ approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
2537
2629
  };
2538
2630
  }
2539
2631
  async callGetAmountsOut(client, callData) {
@@ -2616,7 +2708,11 @@ var SolidlyAdapter = class {
2616
2708
  to: this.router,
2617
2709
  data,
2618
2710
  value: 0n,
2619
- gas_estimate: 35e4
2711
+ gas_estimate: 35e4,
2712
+ approvals: [
2713
+ { token: params.token_a, spender: this.router, amount: params.amount_a },
2714
+ { token: params.token_b, spender: this.router, amount: params.amount_b }
2715
+ ]
2620
2716
  };
2621
2717
  }
2622
2718
  async buildRemoveLiquidity(params) {
@@ -2742,7 +2838,7 @@ var SolidlyGaugeAdapter = class {
2742
2838
  return this.protocolName;
2743
2839
  }
2744
2840
  // IGauge
2745
- async buildDeposit(gauge, amount, tokenId) {
2841
+ async buildDeposit(gauge, amount, tokenId, lpToken) {
2746
2842
  if (tokenId !== void 0) {
2747
2843
  const data2 = encodeFunctionData8({
2748
2844
  abi: gaugeAbi,
@@ -2754,7 +2850,8 @@ var SolidlyGaugeAdapter = class {
2754
2850
  to: gauge,
2755
2851
  data: data2,
2756
2852
  value: 0n,
2757
- gas_estimate: 2e5
2853
+ gas_estimate: 2e5,
2854
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2758
2855
  };
2759
2856
  }
2760
2857
  const data = encodeFunctionData8({
@@ -2767,7 +2864,8 @@ var SolidlyGaugeAdapter = class {
2767
2864
  to: gauge,
2768
2865
  data,
2769
2866
  value: 0n,
2770
- gas_estimate: 2e5
2867
+ gas_estimate: 2e5,
2868
+ approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
2771
2869
  };
2772
2870
  }
2773
2871
  async buildWithdraw(gauge, amount) {
@@ -3067,7 +3165,7 @@ var POOL_ABI = parseAbi10([
3067
3165
  "function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
3068
3166
  "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
3167
  ]);
3070
- var ERC20_ABI = parseAbi10([
3168
+ var ERC20_ABI2 = parseAbi10([
3071
3169
  "function totalSupply() external view returns (uint256)"
3072
3170
  ]);
3073
3171
  var INCENTIVES_ABI = parseAbi10([
@@ -3120,7 +3218,8 @@ var AaveV3Adapter = class {
3120
3218
  to: this.pool,
3121
3219
  data,
3122
3220
  value: 0n,
3123
- gas_estimate: 3e5
3221
+ gas_estimate: 3e5,
3222
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3124
3223
  };
3125
3224
  }
3126
3225
  async buildBorrow(params) {
@@ -3150,7 +3249,8 @@ var AaveV3Adapter = class {
3150
3249
  to: this.pool,
3151
3250
  data,
3152
3251
  value: 0n,
3153
- gas_estimate: 3e5
3252
+ gas_estimate: 3e5,
3253
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3154
3254
  };
3155
3255
  }
3156
3256
  async buildWithdraw(params) {
@@ -3192,12 +3292,12 @@ var AaveV3Adapter = class {
3192
3292
  const [totalSupply, totalBorrow] = await Promise.all([
3193
3293
  client.readContract({
3194
3294
  address: aTokenAddress,
3195
- abi: ERC20_ABI,
3295
+ abi: ERC20_ABI2,
3196
3296
  functionName: "totalSupply"
3197
3297
  }).catch(() => 0n),
3198
3298
  client.readContract({
3199
3299
  address: variableDebtTokenAddress,
3200
- abi: ERC20_ABI,
3300
+ abi: ERC20_ABI2,
3201
3301
  functionName: "totalSupply"
3202
3302
  }).catch(() => 0n)
3203
3303
  ]);
@@ -3421,7 +3521,7 @@ var POOL_ABI2 = parseAbi11([
3421
3521
  // [9]=variableDebtTokenAddress, [10]=interestRateStrategyAddress, [11]=id
3422
3522
  "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
3523
  ]);
3424
- var ERC20_ABI2 = parseAbi11([
3524
+ var ERC20_ABI22 = parseAbi11([
3425
3525
  "function totalSupply() external view returns (uint256)"
3426
3526
  ]);
3427
3527
  function u256ToF642(v) {
@@ -3454,7 +3554,8 @@ var AaveV2Adapter = class {
3454
3554
  to: this.pool,
3455
3555
  data,
3456
3556
  value: 0n,
3457
- gas_estimate: 3e5
3557
+ gas_estimate: 3e5,
3558
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3458
3559
  };
3459
3560
  }
3460
3561
  async buildBorrow(params) {
@@ -3484,7 +3585,8 @@ var AaveV2Adapter = class {
3484
3585
  to: this.pool,
3485
3586
  data,
3486
3587
  value: 0n,
3487
- gas_estimate: 3e5
3588
+ gas_estimate: 3e5,
3589
+ approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
3488
3590
  };
3489
3591
  }
3490
3592
  async buildWithdraw(params) {
@@ -3526,12 +3628,12 @@ var AaveV2Adapter = class {
3526
3628
  const [totalSupply, totalBorrow] = await Promise.all([
3527
3629
  client.readContract({
3528
3630
  address: aTokenAddress,
3529
- abi: ERC20_ABI2,
3631
+ abi: ERC20_ABI22,
3530
3632
  functionName: "totalSupply"
3531
3633
  }).catch(() => 0n),
3532
3634
  client.readContract({
3533
3635
  address: variableDebtTokenAddress,
3534
- abi: ERC20_ABI2,
3636
+ abi: ERC20_ABI22,
3535
3637
  functionName: "totalSupply"
3536
3638
  }).catch(() => 0n)
3537
3639
  ]);
@@ -8219,6 +8321,150 @@ function registerFarm(parent, getOpts, makeExecutor2) {
8219
8321
  });
8220
8322
  }
8221
8323
 
8324
+ // src/commands/setup.ts
8325
+ import pc2 from "picocolors";
8326
+ import { createInterface } from "readline";
8327
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
8328
+ import { resolve as resolve3 } from "path";
8329
+ var DEFI_DIR = resolve3(process.env.HOME || "~", ".defi");
8330
+ var ENV_FILE = resolve3(DEFI_DIR, ".env");
8331
+ function ensureDefiDir() {
8332
+ if (!existsSync3(DEFI_DIR)) mkdirSync2(DEFI_DIR, { recursive: true, mode: 448 });
8333
+ }
8334
+ function loadEnvFile() {
8335
+ if (!existsSync3(ENV_FILE)) return {};
8336
+ const lines = readFileSync3(ENV_FILE, "utf-8").split("\n");
8337
+ const env = {};
8338
+ for (const line of lines) {
8339
+ const trimmed = line.trim();
8340
+ if (!trimmed || trimmed.startsWith("#")) continue;
8341
+ const eqIdx = trimmed.indexOf("=");
8342
+ if (eqIdx > 0) {
8343
+ env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
8344
+ }
8345
+ }
8346
+ return env;
8347
+ }
8348
+ function writeEnvFile(env) {
8349
+ ensureDefiDir();
8350
+ const lines = [
8351
+ "# defi-cli configuration",
8352
+ "# Generated by 'defi setup' \u2014 edit freely",
8353
+ ""
8354
+ ];
8355
+ for (const [key, value] of Object.entries(env)) {
8356
+ lines.push(`${key}=${value}`);
8357
+ }
8358
+ lines.push("");
8359
+ writeFileSync2(ENV_FILE, lines.join("\n"), { mode: 384 });
8360
+ }
8361
+ function ask(rl, question) {
8362
+ return new Promise((res) => rl.question(question, (answer) => res(answer.trim())));
8363
+ }
8364
+ function isValidAddress(s) {
8365
+ return /^0x[0-9a-fA-F]{40}$/.test(s);
8366
+ }
8367
+ function isValidPrivateKey(s) {
8368
+ return /^0x[0-9a-fA-F]{64}$/.test(s);
8369
+ }
8370
+ async function deriveAddress(privateKey) {
8371
+ try {
8372
+ const { privateKeyToAccount: privateKeyToAccount3 } = await import("viem/accounts");
8373
+ const account = privateKeyToAccount3(privateKey);
8374
+ return account.address;
8375
+ } catch {
8376
+ return null;
8377
+ }
8378
+ }
8379
+ function registerSetup(program2) {
8380
+ program2.command("setup").alias("init").description("Interactive setup wizard \u2014 configure wallet & RPC URLs").action(async () => {
8381
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
8382
+ try {
8383
+ console.log(pc2.cyan(pc2.bold("\n defi-cli Setup Wizard\n")));
8384
+ const existing = loadEnvFile();
8385
+ if (Object.keys(existing).length > 0) {
8386
+ console.log(pc2.white(" Current configuration:"));
8387
+ for (const [key, value] of Object.entries(existing)) {
8388
+ const masked = key.toLowerCase().includes("key") ? value.slice(0, 6) + "..." + value.slice(-4) : value;
8389
+ console.log(` ${pc2.cyan(key.padEnd(24))} ${pc2.gray(masked)}`);
8390
+ }
8391
+ console.log();
8392
+ const overwrite = await ask(rl, " Overwrite existing config? (y/N): ");
8393
+ if (overwrite.toLowerCase() !== "y" && overwrite.toLowerCase() !== "yes") {
8394
+ console.log(pc2.gray("\n Keeping existing configuration.\n"));
8395
+ rl.close();
8396
+ return;
8397
+ }
8398
+ console.log();
8399
+ }
8400
+ const newEnv = {};
8401
+ console.log(pc2.cyan(pc2.bold(" Wallet")));
8402
+ const privateKey = await ask(rl, " Private key (optional, for --broadcast, 0x...): ");
8403
+ if (privateKey) {
8404
+ const normalized = privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
8405
+ if (!isValidPrivateKey(normalized)) {
8406
+ console.log(pc2.red(" Invalid private key (must be 0x + 64 hex chars). Skipped."));
8407
+ } else {
8408
+ newEnv.DEFI_PRIVATE_KEY = normalized;
8409
+ const derived = await deriveAddress(normalized);
8410
+ if (derived) {
8411
+ newEnv.DEFI_WALLET_ADDRESS = derived;
8412
+ console.log(` ${pc2.green("OK")} derived address: ${pc2.gray(derived)}`);
8413
+ }
8414
+ }
8415
+ }
8416
+ if (!newEnv.DEFI_WALLET_ADDRESS) {
8417
+ const address = await ask(rl, " Wallet address (0x...): ");
8418
+ if (address) {
8419
+ if (!isValidAddress(address)) {
8420
+ console.log(pc2.yellow(" Invalid address format. Skipping."));
8421
+ } else {
8422
+ newEnv.DEFI_WALLET_ADDRESS = address;
8423
+ console.log(` ${pc2.green("OK")} ${pc2.gray(address)}`);
8424
+ }
8425
+ }
8426
+ }
8427
+ console.log(pc2.cyan(pc2.bold("\n RPC URLs")) + pc2.gray(" (press Enter to use public defaults)"));
8428
+ const hyperevmRpc = await ask(rl, " HyperEVM RPC URL: ");
8429
+ if (hyperevmRpc) {
8430
+ newEnv.HYPEREVM_RPC_URL = hyperevmRpc;
8431
+ console.log(` ${pc2.green("OK")} HyperEVM RPC set`);
8432
+ }
8433
+ const mantleRpc = await ask(rl, " Mantle RPC URL: ");
8434
+ if (mantleRpc) {
8435
+ newEnv.MANTLE_RPC_URL = mantleRpc;
8436
+ console.log(` ${pc2.green("OK")} Mantle RPC set`);
8437
+ }
8438
+ const finalEnv = { ...existing, ...newEnv };
8439
+ writeEnvFile(finalEnv);
8440
+ console.log(pc2.cyan(pc2.bold("\n Setup Complete!\n")));
8441
+ console.log(` Config: ${pc2.gray(ENV_FILE)}`);
8442
+ if (finalEnv.DEFI_WALLET_ADDRESS) {
8443
+ console.log(` Wallet: ${pc2.gray(finalEnv.DEFI_WALLET_ADDRESS)}`);
8444
+ }
8445
+ if (finalEnv.DEFI_PRIVATE_KEY) {
8446
+ console.log(` Key: ${pc2.green("configured")}`);
8447
+ }
8448
+ if (finalEnv.HYPEREVM_RPC_URL) {
8449
+ console.log(` HyperEVM RPC: ${pc2.gray(finalEnv.HYPEREVM_RPC_URL)}`);
8450
+ }
8451
+ if (finalEnv.MANTLE_RPC_URL) {
8452
+ console.log(` Mantle RPC: ${pc2.gray(finalEnv.MANTLE_RPC_URL)}`);
8453
+ }
8454
+ console.log(pc2.bold(pc2.white("\n Next steps:")));
8455
+ console.log(` ${pc2.green("defi portfolio")} view balances & positions`);
8456
+ console.log(` ${pc2.green("defi scan")} scan for exploits`);
8457
+ console.log(` ${pc2.green("defi dex quote")} get a swap quote`);
8458
+ console.log(` ${pc2.green("defi --help")} browse all commands
8459
+ `);
8460
+ rl.close();
8461
+ } catch (err) {
8462
+ rl.close();
8463
+ throw err;
8464
+ }
8465
+ });
8466
+ }
8467
+
8222
8468
  // src/cli.ts
8223
8469
  var _require = createRequire(import.meta.url);
8224
8470
  var _pkg = _require("../package.json");
@@ -8270,6 +8516,7 @@ registerSwap(program, getOutputMode, makeExecutor);
8270
8516
  registerBridge(program, getOutputMode);
8271
8517
  registerNft(program, getOutputMode);
8272
8518
  registerFarm(program, getOutputMode, makeExecutor);
8519
+ registerSetup(program);
8273
8520
  program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
8274
8521
  const executor = makeExecutor();
8275
8522
  process.stderr.write("Agent mode: reading JSON commands from stdin...\n");