@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.
- package/config/tokens/hyperevm.toml +1 -1
- package/dist/index.js +284 -37
- package/dist/index.js.map +1 -1
- package/dist/main.js +318 -63
- package/dist/main.js.map +1 -1
- package/dist/mcp-server.js +123 -21
- package/dist/mcp-server.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/main.ts
|
|
4
|
+
import { config } from "dotenv";
|
|
5
|
+
import { resolve as resolve4 } from "path";
|
|
6
|
+
|
|
3
7
|
// src/cli.ts
|
|
4
8
|
import { Command } from "commander";
|
|
5
9
|
import { createRequire } from "module";
|
|
6
10
|
|
|
7
11
|
// src/executor.ts
|
|
8
|
-
import { createPublicClient as createPublicClient2, createWalletClient, http as http2 } from "viem";
|
|
12
|
+
import { createPublicClient as createPublicClient2, createWalletClient, http as http2, parseAbi as parseAbi3, encodeFunctionData as encodeFunctionData3 } from "viem";
|
|
9
13
|
import { privateKeyToAccount } from "viem/accounts";
|
|
10
14
|
|
|
11
15
|
// ../defi-core/dist/index.js
|
|
@@ -1012,8 +1016,13 @@ var Registry = class _Registry {
|
|
|
1012
1016
|
};
|
|
1013
1017
|
|
|
1014
1018
|
// src/executor.ts
|
|
1019
|
+
var ERC20_ABI = parseAbi3([
|
|
1020
|
+
"function allowance(address owner, address spender) external view returns (uint256)",
|
|
1021
|
+
"function approve(address spender, uint256 amount) external returns (bool)"
|
|
1022
|
+
]);
|
|
1015
1023
|
var GAS_BUFFER_BPS = 12000n;
|
|
1016
|
-
var DEFAULT_PRIORITY_FEE_WEI =
|
|
1024
|
+
var DEFAULT_PRIORITY_FEE_WEI = 20000000000n;
|
|
1025
|
+
var MAX_GAS_LIMIT = 5000000000n;
|
|
1017
1026
|
var Executor = class _Executor {
|
|
1018
1027
|
dryRun;
|
|
1019
1028
|
rpcUrl;
|
|
@@ -1027,6 +1036,62 @@ var Executor = class _Executor {
|
|
|
1027
1036
|
static applyGasBuffer(gas) {
|
|
1028
1037
|
return gas * GAS_BUFFER_BPS / 10000n;
|
|
1029
1038
|
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Check allowance for a single token/spender pair and send an approve tx if needed.
|
|
1041
|
+
* Only called in broadcast mode (not dry-run).
|
|
1042
|
+
*/
|
|
1043
|
+
async checkAndApprove(token, spender, amount, owner, publicClient, walletClient) {
|
|
1044
|
+
const allowance = await publicClient.readContract({
|
|
1045
|
+
address: token,
|
|
1046
|
+
abi: ERC20_ABI,
|
|
1047
|
+
functionName: "allowance",
|
|
1048
|
+
args: [owner, spender]
|
|
1049
|
+
});
|
|
1050
|
+
if (allowance >= amount) return;
|
|
1051
|
+
process.stderr.write(
|
|
1052
|
+
` Approving ${amount} of ${token} for ${spender}...
|
|
1053
|
+
`
|
|
1054
|
+
);
|
|
1055
|
+
const approveData = encodeFunctionData3({
|
|
1056
|
+
abi: ERC20_ABI,
|
|
1057
|
+
functionName: "approve",
|
|
1058
|
+
args: [spender, amount]
|
|
1059
|
+
});
|
|
1060
|
+
const rpcUrl = this.rpcUrl;
|
|
1061
|
+
const gasLimit = await (async () => {
|
|
1062
|
+
try {
|
|
1063
|
+
const estimated = await publicClient.estimateGas({
|
|
1064
|
+
to: token,
|
|
1065
|
+
data: approveData,
|
|
1066
|
+
account: owner
|
|
1067
|
+
});
|
|
1068
|
+
const buffered = _Executor.applyGasBuffer(estimated);
|
|
1069
|
+
return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
|
|
1070
|
+
} catch {
|
|
1071
|
+
return 80000n;
|
|
1072
|
+
}
|
|
1073
|
+
})();
|
|
1074
|
+
const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
|
|
1075
|
+
const approveTxHash = await walletClient.sendTransaction({
|
|
1076
|
+
chain: null,
|
|
1077
|
+
account: walletClient.account,
|
|
1078
|
+
to: token,
|
|
1079
|
+
data: approveData,
|
|
1080
|
+
gas: gasLimit > 0n ? gasLimit : void 0,
|
|
1081
|
+
maxFeePerGas: maxFeePerGas > 0n ? maxFeePerGas : void 0,
|
|
1082
|
+
maxPriorityFeePerGas: maxPriorityFeePerGas > 0n ? maxPriorityFeePerGas : void 0
|
|
1083
|
+
});
|
|
1084
|
+
const approveTxUrl = this.explorerUrl ? `${this.explorerUrl}/tx/${approveTxHash}` : void 0;
|
|
1085
|
+
process.stderr.write(` Approve tx: ${approveTxHash}
|
|
1086
|
+
`);
|
|
1087
|
+
if (approveTxUrl) process.stderr.write(` Explorer: ${approveTxUrl}
|
|
1088
|
+
`);
|
|
1089
|
+
await publicClient.waitForTransactionReceipt({ hash: approveTxHash });
|
|
1090
|
+
process.stderr.write(
|
|
1091
|
+
` Approved ${amount} of ${token} for ${spender}
|
|
1092
|
+
`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1030
1095
|
/** Fetch EIP-1559 fee params from the network. Returns [maxFeePerGas, maxPriorityFeePerGas]. */
|
|
1031
1096
|
async fetchEip1559Fees(rpcUrl) {
|
|
1032
1097
|
try {
|
|
@@ -1053,7 +1118,10 @@ var Executor = class _Executor {
|
|
|
1053
1118
|
value: tx.value,
|
|
1054
1119
|
account: from
|
|
1055
1120
|
});
|
|
1056
|
-
if (estimated > 0n)
|
|
1121
|
+
if (estimated > 0n) {
|
|
1122
|
+
const buffered = _Executor.applyGasBuffer(estimated);
|
|
1123
|
+
return buffered > MAX_GAS_LIMIT ? MAX_GAS_LIMIT : buffered;
|
|
1124
|
+
}
|
|
1057
1125
|
} catch {
|
|
1058
1126
|
}
|
|
1059
1127
|
return tx.gas_estimate ? BigInt(tx.gas_estimate) : 0n;
|
|
@@ -1139,6 +1207,18 @@ var Executor = class _Executor {
|
|
|
1139
1207
|
}
|
|
1140
1208
|
const publicClient = createPublicClient2({ transport: http2(rpcUrl) });
|
|
1141
1209
|
const walletClient = createWalletClient({ account, transport: http2(rpcUrl) });
|
|
1210
|
+
if (tx.approvals && tx.approvals.length > 0) {
|
|
1211
|
+
for (const approval of tx.approvals) {
|
|
1212
|
+
await this.checkAndApprove(
|
|
1213
|
+
approval.token,
|
|
1214
|
+
approval.spender,
|
|
1215
|
+
approval.amount,
|
|
1216
|
+
account.address,
|
|
1217
|
+
publicClient,
|
|
1218
|
+
walletClient
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1142
1222
|
const gasLimit = await this.estimateGasWithBuffer(rpcUrl, tx, account.address);
|
|
1143
1223
|
const [maxFeePerGas, maxPriorityFeePerGas] = await this.fetchEip1559Fees(rpcUrl);
|
|
1144
1224
|
process.stderr.write(`Broadcasting transaction to ${rpcUrl}...
|
|
@@ -1715,10 +1795,10 @@ function registerSchema(parent, getOpts) {
|
|
|
1715
1795
|
}
|
|
1716
1796
|
|
|
1717
1797
|
// ../defi-protocols/dist/index.js
|
|
1718
|
-
import { encodeFunctionData as
|
|
1798
|
+
import { encodeFunctionData as encodeFunctionData4, parseAbi as parseAbi4, createPublicClient as createPublicClient4, http as http4, decodeAbiParameters } from "viem";
|
|
1719
1799
|
import { encodeFunctionData as encodeFunctionData22, parseAbi as parseAbi22, createPublicClient as createPublicClient22, http as http22, decodeFunctionResult as decodeFunctionResult2, decodeAbiParameters as decodeAbiParameters2 } from "viem";
|
|
1720
1800
|
import { encodeFunctionData as encodeFunctionData32, parseAbi as parseAbi32, createPublicClient as createPublicClient32, http as http32, decodeAbiParameters as decodeAbiParameters3, concatHex, zeroAddress } from "viem";
|
|
1721
|
-
import { encodeFunctionData as
|
|
1801
|
+
import { encodeFunctionData as encodeFunctionData42, parseAbi as parseAbi42, zeroAddress as zeroAddress2 } from "viem";
|
|
1722
1802
|
import { encodeFunctionData as encodeFunctionData5, parseAbi as parseAbi5 } from "viem";
|
|
1723
1803
|
import { encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi6, createPublicClient as createPublicClient42, http as http42, decodeAbiParameters as decodeAbiParameters4 } from "viem";
|
|
1724
1804
|
import { encodeFunctionData as encodeFunctionData7, parseAbi as parseAbi7, zeroAddress as zeroAddress3 } from "viem";
|
|
@@ -1741,19 +1821,19 @@ import { parseAbi as parseAbi23, encodeFunctionData as encodeFunctionData21 } fr
|
|
|
1741
1821
|
import { parseAbi as parseAbi24, encodeFunctionData as encodeFunctionData222 } from "viem";
|
|
1742
1822
|
import { createPublicClient as createPublicClient19, http as http19, parseAbi as parseAbi25 } from "viem";
|
|
1743
1823
|
var DEFAULT_FEE = 3e3;
|
|
1744
|
-
var swapRouterAbi =
|
|
1824
|
+
var swapRouterAbi = parseAbi4([
|
|
1745
1825
|
"struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; }",
|
|
1746
1826
|
"function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut)"
|
|
1747
1827
|
]);
|
|
1748
|
-
var quoterAbi =
|
|
1828
|
+
var quoterAbi = parseAbi4([
|
|
1749
1829
|
"struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; }",
|
|
1750
1830
|
"function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
|
|
1751
1831
|
]);
|
|
1752
|
-
var ramsesQuoterAbi =
|
|
1832
|
+
var ramsesQuoterAbi = parseAbi4([
|
|
1753
1833
|
"struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; int24 tickSpacing; uint160 sqrtPriceLimitX96; }",
|
|
1754
1834
|
"function quoteExactInputSingle(QuoteExactInputSingleParams memory params) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate)"
|
|
1755
1835
|
]);
|
|
1756
|
-
var positionManagerAbi =
|
|
1836
|
+
var positionManagerAbi = parseAbi4([
|
|
1757
1837
|
"struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; }",
|
|
1758
1838
|
"function mint(MintParams calldata params) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1)"
|
|
1759
1839
|
]);
|
|
@@ -1786,7 +1866,7 @@ var UniswapV3Adapter = class {
|
|
|
1786
1866
|
async buildSwap(params) {
|
|
1787
1867
|
const deadline = BigInt(params.deadline ?? 18446744073709551615n);
|
|
1788
1868
|
const amountOutMinimum = 0n;
|
|
1789
|
-
const data =
|
|
1869
|
+
const data = encodeFunctionData4({
|
|
1790
1870
|
abi: swapRouterAbi,
|
|
1791
1871
|
functionName: "exactInputSingle",
|
|
1792
1872
|
args: [
|
|
@@ -1807,7 +1887,8 @@ var UniswapV3Adapter = class {
|
|
|
1807
1887
|
to: this.router,
|
|
1808
1888
|
data,
|
|
1809
1889
|
value: 0n,
|
|
1810
|
-
gas_estimate: 2e5
|
|
1890
|
+
gas_estimate: 2e5,
|
|
1891
|
+
approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
|
|
1811
1892
|
};
|
|
1812
1893
|
}
|
|
1813
1894
|
async quote(params) {
|
|
@@ -1822,7 +1903,7 @@ var UniswapV3Adapter = class {
|
|
|
1822
1903
|
tickSpacings.map(async (ts) => {
|
|
1823
1904
|
const result = await client2.call({
|
|
1824
1905
|
to: this.quoter,
|
|
1825
|
-
data:
|
|
1906
|
+
data: encodeFunctionData4({
|
|
1826
1907
|
abi: ramsesQuoterAbi,
|
|
1827
1908
|
functionName: "quoteExactInputSingle",
|
|
1828
1909
|
args: [
|
|
@@ -1868,7 +1949,7 @@ var UniswapV3Adapter = class {
|
|
|
1868
1949
|
feeTiers.map(async (fee) => {
|
|
1869
1950
|
const result = await client2.call({
|
|
1870
1951
|
to: this.quoter,
|
|
1871
|
-
data:
|
|
1952
|
+
data: encodeFunctionData4({
|
|
1872
1953
|
abi: quoterAbi,
|
|
1873
1954
|
functionName: "quoteExactInputSingle",
|
|
1874
1955
|
args: [
|
|
@@ -1907,7 +1988,7 @@ var UniswapV3Adapter = class {
|
|
|
1907
1988
|
}
|
|
1908
1989
|
}
|
|
1909
1990
|
const client = createPublicClient4({ transport: http4(this.rpcUrl) });
|
|
1910
|
-
const callData =
|
|
1991
|
+
const callData = encodeFunctionData4({
|
|
1911
1992
|
abi: swapRouterAbi,
|
|
1912
1993
|
functionName: "exactInputSingle",
|
|
1913
1994
|
args: [
|
|
@@ -1953,7 +2034,7 @@ var UniswapV3Adapter = class {
|
|
|
1953
2034
|
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];
|
|
1954
2035
|
const amount0 = rawAmount0 === 0n && rawAmount1 > 0n ? 1n : rawAmount0;
|
|
1955
2036
|
const amount1 = rawAmount1 === 0n && rawAmount0 > 0n ? 1n : rawAmount1;
|
|
1956
|
-
const data =
|
|
2037
|
+
const data = encodeFunctionData4({
|
|
1957
2038
|
abi: positionManagerAbi,
|
|
1958
2039
|
functionName: "mint",
|
|
1959
2040
|
args: [
|
|
@@ -1977,7 +2058,11 @@ var UniswapV3Adapter = class {
|
|
|
1977
2058
|
to: pm,
|
|
1978
2059
|
data,
|
|
1979
2060
|
value: 0n,
|
|
1980
|
-
gas_estimate: 5e5
|
|
2061
|
+
gas_estimate: 5e5,
|
|
2062
|
+
approvals: [
|
|
2063
|
+
{ token: token0, spender: pm, amount: amount0 },
|
|
2064
|
+
{ token: token1, spender: pm, amount: amount1 }
|
|
2065
|
+
]
|
|
1981
2066
|
};
|
|
1982
2067
|
}
|
|
1983
2068
|
async buildRemoveLiquidity(_params) {
|
|
@@ -2036,7 +2121,8 @@ var UniswapV2Adapter = class {
|
|
|
2036
2121
|
to: this.router,
|
|
2037
2122
|
data,
|
|
2038
2123
|
value: 0n,
|
|
2039
|
-
gas_estimate: 15e4
|
|
2124
|
+
gas_estimate: 15e4,
|
|
2125
|
+
approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
|
|
2040
2126
|
};
|
|
2041
2127
|
}
|
|
2042
2128
|
async quote(params) {
|
|
@@ -2155,7 +2241,11 @@ var UniswapV2Adapter = class {
|
|
|
2155
2241
|
to: this.router,
|
|
2156
2242
|
data,
|
|
2157
2243
|
value: 0n,
|
|
2158
|
-
gas_estimate: 3e5
|
|
2244
|
+
gas_estimate: 3e5,
|
|
2245
|
+
approvals: [
|
|
2246
|
+
{ token: params.token_a, spender: this.router, amount: params.amount_a },
|
|
2247
|
+
{ token: params.token_b, spender: this.router, amount: params.amount_b }
|
|
2248
|
+
]
|
|
2159
2249
|
};
|
|
2160
2250
|
}
|
|
2161
2251
|
async buildRemoveLiquidity(params) {
|
|
@@ -2242,7 +2332,8 @@ var AlgebraV3Adapter = class {
|
|
|
2242
2332
|
to: this.router,
|
|
2243
2333
|
data,
|
|
2244
2334
|
value: 0n,
|
|
2245
|
-
gas_estimate: 25e4
|
|
2335
|
+
gas_estimate: 25e4,
|
|
2336
|
+
approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
|
|
2246
2337
|
};
|
|
2247
2338
|
}
|
|
2248
2339
|
async quote(params) {
|
|
@@ -2360,7 +2451,11 @@ var AlgebraV3Adapter = class {
|
|
|
2360
2451
|
to: pm,
|
|
2361
2452
|
data,
|
|
2362
2453
|
value: 0n,
|
|
2363
|
-
gas_estimate: 5e5
|
|
2454
|
+
gas_estimate: 5e5,
|
|
2455
|
+
approvals: [
|
|
2456
|
+
{ token: token0, spender: pm, amount: amount0 },
|
|
2457
|
+
{ token: token1, spender: pm, amount: amount1 }
|
|
2458
|
+
]
|
|
2364
2459
|
};
|
|
2365
2460
|
}
|
|
2366
2461
|
async buildRemoveLiquidity(_params) {
|
|
@@ -2369,7 +2464,7 @@ var AlgebraV3Adapter = class {
|
|
|
2369
2464
|
);
|
|
2370
2465
|
}
|
|
2371
2466
|
};
|
|
2372
|
-
var abi3 =
|
|
2467
|
+
var abi3 = parseAbi42([
|
|
2373
2468
|
"function swapSingleTokenExactIn(address pool, address tokenIn, address tokenOut, uint256 exactAmountIn, uint256 minAmountOut, uint256 deadline, bool wethIsEth, bytes calldata userData) external returns (uint256 amountOut)"
|
|
2374
2469
|
]);
|
|
2375
2470
|
var BalancerV3Adapter = class {
|
|
@@ -2389,7 +2484,7 @@ var BalancerV3Adapter = class {
|
|
|
2389
2484
|
async buildSwap(params) {
|
|
2390
2485
|
const minAmountOut = 0n;
|
|
2391
2486
|
const deadline = BigInt(params.deadline ?? 18446744073709551615n);
|
|
2392
|
-
const data =
|
|
2487
|
+
const data = encodeFunctionData42({
|
|
2393
2488
|
abi: abi3,
|
|
2394
2489
|
functionName: "swapSingleTokenExactIn",
|
|
2395
2490
|
args: [
|
|
@@ -2537,7 +2632,8 @@ var SolidlyAdapter = class {
|
|
|
2537
2632
|
to: this.router,
|
|
2538
2633
|
data,
|
|
2539
2634
|
value: 0n,
|
|
2540
|
-
gas_estimate: 2e5
|
|
2635
|
+
gas_estimate: 2e5,
|
|
2636
|
+
approvals: [{ token: params.token_in, spender: this.router, amount: params.amount_in }]
|
|
2541
2637
|
};
|
|
2542
2638
|
}
|
|
2543
2639
|
async callGetAmountsOut(client, callData) {
|
|
@@ -2620,7 +2716,11 @@ var SolidlyAdapter = class {
|
|
|
2620
2716
|
to: this.router,
|
|
2621
2717
|
data,
|
|
2622
2718
|
value: 0n,
|
|
2623
|
-
gas_estimate: 35e4
|
|
2719
|
+
gas_estimate: 35e4,
|
|
2720
|
+
approvals: [
|
|
2721
|
+
{ token: params.token_a, spender: this.router, amount: params.amount_a },
|
|
2722
|
+
{ token: params.token_b, spender: this.router, amount: params.amount_b }
|
|
2723
|
+
]
|
|
2624
2724
|
};
|
|
2625
2725
|
}
|
|
2626
2726
|
async buildRemoveLiquidity(params) {
|
|
@@ -2746,7 +2846,7 @@ var SolidlyGaugeAdapter = class {
|
|
|
2746
2846
|
return this.protocolName;
|
|
2747
2847
|
}
|
|
2748
2848
|
// IGauge
|
|
2749
|
-
async buildDeposit(gauge, amount, tokenId) {
|
|
2849
|
+
async buildDeposit(gauge, amount, tokenId, lpToken) {
|
|
2750
2850
|
if (tokenId !== void 0) {
|
|
2751
2851
|
const data2 = encodeFunctionData8({
|
|
2752
2852
|
abi: gaugeAbi,
|
|
@@ -2758,7 +2858,8 @@ var SolidlyGaugeAdapter = class {
|
|
|
2758
2858
|
to: gauge,
|
|
2759
2859
|
data: data2,
|
|
2760
2860
|
value: 0n,
|
|
2761
|
-
gas_estimate: 2e5
|
|
2861
|
+
gas_estimate: 2e5,
|
|
2862
|
+
approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
|
|
2762
2863
|
};
|
|
2763
2864
|
}
|
|
2764
2865
|
const data = encodeFunctionData8({
|
|
@@ -2771,7 +2872,8 @@ var SolidlyGaugeAdapter = class {
|
|
|
2771
2872
|
to: gauge,
|
|
2772
2873
|
data,
|
|
2773
2874
|
value: 0n,
|
|
2774
|
-
gas_estimate: 2e5
|
|
2875
|
+
gas_estimate: 2e5,
|
|
2876
|
+
approvals: lpToken ? [{ token: lpToken, spender: gauge, amount }] : void 0
|
|
2775
2877
|
};
|
|
2776
2878
|
}
|
|
2777
2879
|
async buildWithdraw(gauge, amount) {
|
|
@@ -3071,7 +3173,7 @@ var POOL_ABI = parseAbi10([
|
|
|
3071
3173
|
"function getUserAccountData(address user) external view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
|
|
3072
3174
|
"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)"
|
|
3073
3175
|
]);
|
|
3074
|
-
var
|
|
3176
|
+
var ERC20_ABI2 = parseAbi10([
|
|
3075
3177
|
"function totalSupply() external view returns (uint256)"
|
|
3076
3178
|
]);
|
|
3077
3179
|
var INCENTIVES_ABI = parseAbi10([
|
|
@@ -3124,7 +3226,8 @@ var AaveV3Adapter = class {
|
|
|
3124
3226
|
to: this.pool,
|
|
3125
3227
|
data,
|
|
3126
3228
|
value: 0n,
|
|
3127
|
-
gas_estimate: 3e5
|
|
3229
|
+
gas_estimate: 3e5,
|
|
3230
|
+
approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
|
|
3128
3231
|
};
|
|
3129
3232
|
}
|
|
3130
3233
|
async buildBorrow(params) {
|
|
@@ -3154,7 +3257,8 @@ var AaveV3Adapter = class {
|
|
|
3154
3257
|
to: this.pool,
|
|
3155
3258
|
data,
|
|
3156
3259
|
value: 0n,
|
|
3157
|
-
gas_estimate: 3e5
|
|
3260
|
+
gas_estimate: 3e5,
|
|
3261
|
+
approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
|
|
3158
3262
|
};
|
|
3159
3263
|
}
|
|
3160
3264
|
async buildWithdraw(params) {
|
|
@@ -3196,12 +3300,12 @@ var AaveV3Adapter = class {
|
|
|
3196
3300
|
const [totalSupply, totalBorrow] = await Promise.all([
|
|
3197
3301
|
client.readContract({
|
|
3198
3302
|
address: aTokenAddress,
|
|
3199
|
-
abi:
|
|
3303
|
+
abi: ERC20_ABI2,
|
|
3200
3304
|
functionName: "totalSupply"
|
|
3201
3305
|
}).catch(() => 0n),
|
|
3202
3306
|
client.readContract({
|
|
3203
3307
|
address: variableDebtTokenAddress,
|
|
3204
|
-
abi:
|
|
3308
|
+
abi: ERC20_ABI2,
|
|
3205
3309
|
functionName: "totalSupply"
|
|
3206
3310
|
}).catch(() => 0n)
|
|
3207
3311
|
]);
|
|
@@ -3425,7 +3529,7 @@ var POOL_ABI2 = parseAbi11([
|
|
|
3425
3529
|
// [9]=variableDebtTokenAddress, [10]=interestRateStrategyAddress, [11]=id
|
|
3426
3530
|
"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)"
|
|
3427
3531
|
]);
|
|
3428
|
-
var
|
|
3532
|
+
var ERC20_ABI22 = parseAbi11([
|
|
3429
3533
|
"function totalSupply() external view returns (uint256)"
|
|
3430
3534
|
]);
|
|
3431
3535
|
function u256ToF642(v) {
|
|
@@ -3458,7 +3562,8 @@ var AaveV2Adapter = class {
|
|
|
3458
3562
|
to: this.pool,
|
|
3459
3563
|
data,
|
|
3460
3564
|
value: 0n,
|
|
3461
|
-
gas_estimate: 3e5
|
|
3565
|
+
gas_estimate: 3e5,
|
|
3566
|
+
approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
|
|
3462
3567
|
};
|
|
3463
3568
|
}
|
|
3464
3569
|
async buildBorrow(params) {
|
|
@@ -3488,7 +3593,8 @@ var AaveV2Adapter = class {
|
|
|
3488
3593
|
to: this.pool,
|
|
3489
3594
|
data,
|
|
3490
3595
|
value: 0n,
|
|
3491
|
-
gas_estimate: 3e5
|
|
3596
|
+
gas_estimate: 3e5,
|
|
3597
|
+
approvals: [{ token: params.asset, spender: this.pool, amount: params.amount }]
|
|
3492
3598
|
};
|
|
3493
3599
|
}
|
|
3494
3600
|
async buildWithdraw(params) {
|
|
@@ -3530,12 +3636,12 @@ var AaveV2Adapter = class {
|
|
|
3530
3636
|
const [totalSupply, totalBorrow] = await Promise.all([
|
|
3531
3637
|
client.readContract({
|
|
3532
3638
|
address: aTokenAddress,
|
|
3533
|
-
abi:
|
|
3639
|
+
abi: ERC20_ABI22,
|
|
3534
3640
|
functionName: "totalSupply"
|
|
3535
3641
|
}).catch(() => 0n),
|
|
3536
3642
|
client.readContract({
|
|
3537
3643
|
address: variableDebtTokenAddress,
|
|
3538
|
-
abi:
|
|
3644
|
+
abi: ERC20_ABI22,
|
|
3539
3645
|
functionName: "totalSupply"
|
|
3540
3646
|
}).catch(() => 0n)
|
|
3541
3647
|
]);
|
|
@@ -8223,6 +8329,150 @@ function registerFarm(parent, getOpts, makeExecutor2) {
|
|
|
8223
8329
|
});
|
|
8224
8330
|
}
|
|
8225
8331
|
|
|
8332
|
+
// src/commands/setup.ts
|
|
8333
|
+
import pc2 from "picocolors";
|
|
8334
|
+
import { createInterface } from "readline";
|
|
8335
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
8336
|
+
import { resolve as resolve3 } from "path";
|
|
8337
|
+
var DEFI_DIR = resolve3(process.env.HOME || "~", ".defi");
|
|
8338
|
+
var ENV_FILE = resolve3(DEFI_DIR, ".env");
|
|
8339
|
+
function ensureDefiDir() {
|
|
8340
|
+
if (!existsSync3(DEFI_DIR)) mkdirSync2(DEFI_DIR, { recursive: true, mode: 448 });
|
|
8341
|
+
}
|
|
8342
|
+
function loadEnvFile() {
|
|
8343
|
+
if (!existsSync3(ENV_FILE)) return {};
|
|
8344
|
+
const lines = readFileSync3(ENV_FILE, "utf-8").split("\n");
|
|
8345
|
+
const env = {};
|
|
8346
|
+
for (const line of lines) {
|
|
8347
|
+
const trimmed = line.trim();
|
|
8348
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
8349
|
+
const eqIdx = trimmed.indexOf("=");
|
|
8350
|
+
if (eqIdx > 0) {
|
|
8351
|
+
env[trimmed.slice(0, eqIdx)] = trimmed.slice(eqIdx + 1);
|
|
8352
|
+
}
|
|
8353
|
+
}
|
|
8354
|
+
return env;
|
|
8355
|
+
}
|
|
8356
|
+
function writeEnvFile(env) {
|
|
8357
|
+
ensureDefiDir();
|
|
8358
|
+
const lines = [
|
|
8359
|
+
"# defi-cli configuration",
|
|
8360
|
+
"# Generated by 'defi setup' \u2014 edit freely",
|
|
8361
|
+
""
|
|
8362
|
+
];
|
|
8363
|
+
for (const [key, value] of Object.entries(env)) {
|
|
8364
|
+
lines.push(`${key}=${value}`);
|
|
8365
|
+
}
|
|
8366
|
+
lines.push("");
|
|
8367
|
+
writeFileSync2(ENV_FILE, lines.join("\n"), { mode: 384 });
|
|
8368
|
+
}
|
|
8369
|
+
function ask(rl, question) {
|
|
8370
|
+
return new Promise((res) => rl.question(question, (answer) => res(answer.trim())));
|
|
8371
|
+
}
|
|
8372
|
+
function isValidAddress(s) {
|
|
8373
|
+
return /^0x[0-9a-fA-F]{40}$/.test(s);
|
|
8374
|
+
}
|
|
8375
|
+
function isValidPrivateKey(s) {
|
|
8376
|
+
return /^0x[0-9a-fA-F]{64}$/.test(s);
|
|
8377
|
+
}
|
|
8378
|
+
async function deriveAddress(privateKey) {
|
|
8379
|
+
try {
|
|
8380
|
+
const { privateKeyToAccount: privateKeyToAccount3 } = await import("viem/accounts");
|
|
8381
|
+
const account = privateKeyToAccount3(privateKey);
|
|
8382
|
+
return account.address;
|
|
8383
|
+
} catch {
|
|
8384
|
+
return null;
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
8387
|
+
function registerSetup(program2) {
|
|
8388
|
+
program2.command("setup").alias("init").description("Interactive setup wizard \u2014 configure wallet & RPC URLs").action(async () => {
|
|
8389
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
8390
|
+
try {
|
|
8391
|
+
console.log(pc2.cyan(pc2.bold("\n defi-cli Setup Wizard\n")));
|
|
8392
|
+
const existing = loadEnvFile();
|
|
8393
|
+
if (Object.keys(existing).length > 0) {
|
|
8394
|
+
console.log(pc2.white(" Current configuration:"));
|
|
8395
|
+
for (const [key, value] of Object.entries(existing)) {
|
|
8396
|
+
const masked = key.toLowerCase().includes("key") ? value.slice(0, 6) + "..." + value.slice(-4) : value;
|
|
8397
|
+
console.log(` ${pc2.cyan(key.padEnd(24))} ${pc2.gray(masked)}`);
|
|
8398
|
+
}
|
|
8399
|
+
console.log();
|
|
8400
|
+
const overwrite = await ask(rl, " Overwrite existing config? (y/N): ");
|
|
8401
|
+
if (overwrite.toLowerCase() !== "y" && overwrite.toLowerCase() !== "yes") {
|
|
8402
|
+
console.log(pc2.gray("\n Keeping existing configuration.\n"));
|
|
8403
|
+
rl.close();
|
|
8404
|
+
return;
|
|
8405
|
+
}
|
|
8406
|
+
console.log();
|
|
8407
|
+
}
|
|
8408
|
+
const newEnv = {};
|
|
8409
|
+
console.log(pc2.cyan(pc2.bold(" Wallet")));
|
|
8410
|
+
const privateKey = await ask(rl, " Private key (optional, for --broadcast, 0x...): ");
|
|
8411
|
+
if (privateKey) {
|
|
8412
|
+
const normalized = privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
|
|
8413
|
+
if (!isValidPrivateKey(normalized)) {
|
|
8414
|
+
console.log(pc2.red(" Invalid private key (must be 0x + 64 hex chars). Skipped."));
|
|
8415
|
+
} else {
|
|
8416
|
+
newEnv.DEFI_PRIVATE_KEY = normalized;
|
|
8417
|
+
const derived = await deriveAddress(normalized);
|
|
8418
|
+
if (derived) {
|
|
8419
|
+
newEnv.DEFI_WALLET_ADDRESS = derived;
|
|
8420
|
+
console.log(` ${pc2.green("OK")} derived address: ${pc2.gray(derived)}`);
|
|
8421
|
+
}
|
|
8422
|
+
}
|
|
8423
|
+
}
|
|
8424
|
+
if (!newEnv.DEFI_WALLET_ADDRESS) {
|
|
8425
|
+
const address = await ask(rl, " Wallet address (0x...): ");
|
|
8426
|
+
if (address) {
|
|
8427
|
+
if (!isValidAddress(address)) {
|
|
8428
|
+
console.log(pc2.yellow(" Invalid address format. Skipping."));
|
|
8429
|
+
} else {
|
|
8430
|
+
newEnv.DEFI_WALLET_ADDRESS = address;
|
|
8431
|
+
console.log(` ${pc2.green("OK")} ${pc2.gray(address)}`);
|
|
8432
|
+
}
|
|
8433
|
+
}
|
|
8434
|
+
}
|
|
8435
|
+
console.log(pc2.cyan(pc2.bold("\n RPC URLs")) + pc2.gray(" (press Enter to use public defaults)"));
|
|
8436
|
+
const hyperevmRpc = await ask(rl, " HyperEVM RPC URL: ");
|
|
8437
|
+
if (hyperevmRpc) {
|
|
8438
|
+
newEnv.HYPEREVM_RPC_URL = hyperevmRpc;
|
|
8439
|
+
console.log(` ${pc2.green("OK")} HyperEVM RPC set`);
|
|
8440
|
+
}
|
|
8441
|
+
const mantleRpc = await ask(rl, " Mantle RPC URL: ");
|
|
8442
|
+
if (mantleRpc) {
|
|
8443
|
+
newEnv.MANTLE_RPC_URL = mantleRpc;
|
|
8444
|
+
console.log(` ${pc2.green("OK")} Mantle RPC set`);
|
|
8445
|
+
}
|
|
8446
|
+
const finalEnv = { ...existing, ...newEnv };
|
|
8447
|
+
writeEnvFile(finalEnv);
|
|
8448
|
+
console.log(pc2.cyan(pc2.bold("\n Setup Complete!\n")));
|
|
8449
|
+
console.log(` Config: ${pc2.gray(ENV_FILE)}`);
|
|
8450
|
+
if (finalEnv.DEFI_WALLET_ADDRESS) {
|
|
8451
|
+
console.log(` Wallet: ${pc2.gray(finalEnv.DEFI_WALLET_ADDRESS)}`);
|
|
8452
|
+
}
|
|
8453
|
+
if (finalEnv.DEFI_PRIVATE_KEY) {
|
|
8454
|
+
console.log(` Key: ${pc2.green("configured")}`);
|
|
8455
|
+
}
|
|
8456
|
+
if (finalEnv.HYPEREVM_RPC_URL) {
|
|
8457
|
+
console.log(` HyperEVM RPC: ${pc2.gray(finalEnv.HYPEREVM_RPC_URL)}`);
|
|
8458
|
+
}
|
|
8459
|
+
if (finalEnv.MANTLE_RPC_URL) {
|
|
8460
|
+
console.log(` Mantle RPC: ${pc2.gray(finalEnv.MANTLE_RPC_URL)}`);
|
|
8461
|
+
}
|
|
8462
|
+
console.log(pc2.bold(pc2.white("\n Next steps:")));
|
|
8463
|
+
console.log(` ${pc2.green("defi portfolio")} view balances & positions`);
|
|
8464
|
+
console.log(` ${pc2.green("defi scan")} scan for exploits`);
|
|
8465
|
+
console.log(` ${pc2.green("defi dex quote")} get a swap quote`);
|
|
8466
|
+
console.log(` ${pc2.green("defi --help")} browse all commands
|
|
8467
|
+
`);
|
|
8468
|
+
rl.close();
|
|
8469
|
+
} catch (err) {
|
|
8470
|
+
rl.close();
|
|
8471
|
+
throw err;
|
|
8472
|
+
}
|
|
8473
|
+
});
|
|
8474
|
+
}
|
|
8475
|
+
|
|
8226
8476
|
// src/cli.ts
|
|
8227
8477
|
var _require = createRequire(import.meta.url);
|
|
8228
8478
|
var _pkg = _require("../package.json");
|
|
@@ -8274,6 +8524,7 @@ registerSwap(program, getOutputMode, makeExecutor);
|
|
|
8274
8524
|
registerBridge(program, getOutputMode);
|
|
8275
8525
|
registerNft(program, getOutputMode);
|
|
8276
8526
|
registerFarm(program, getOutputMode, makeExecutor);
|
|
8527
|
+
registerSetup(program);
|
|
8277
8528
|
program.command("agent").description("Agent mode: read JSON commands from stdin (for AI agents)").action(async () => {
|
|
8278
8529
|
const executor = makeExecutor();
|
|
8279
8530
|
process.stderr.write("Agent mode: reading JSON commands from stdin...\n");
|
|
@@ -8282,7 +8533,7 @@ program.command("agent").description("Agent mode: read JSON commands from stdin
|
|
|
8282
8533
|
});
|
|
8283
8534
|
|
|
8284
8535
|
// src/landing.ts
|
|
8285
|
-
import
|
|
8536
|
+
import pc3 from "picocolors";
|
|
8286
8537
|
import { encodeFunctionData as encodeFunctionData28, parseAbi as parseAbi31, formatUnits } from "viem";
|
|
8287
8538
|
var HYPEREVM_DISPLAY = ["HYPE", "WHYPE", "USDC", "USDT0", "USDe", "kHYPE", "wstHYPE"];
|
|
8288
8539
|
var MANTLE_DISPLAY = ["MNT", "WMNT", "USDC", "USDT", "WETH", "mETH"];
|
|
@@ -8376,20 +8627,20 @@ async function showLandingPage(isJson) {
|
|
|
8376
8627
|
const version = pkg.version;
|
|
8377
8628
|
if (!wallet) {
|
|
8378
8629
|
console.log("");
|
|
8379
|
-
console.log(
|
|
8630
|
+
console.log(pc3.bold(pc3.cyan(" DeFi CLI v" + version)));
|
|
8380
8631
|
console.log("");
|
|
8381
|
-
console.log(
|
|
8632
|
+
console.log(pc3.yellow(" Wallet not configured."));
|
|
8382
8633
|
console.log(" Set DEFI_WALLET_ADDRESS to see your balances:");
|
|
8383
8634
|
console.log("");
|
|
8384
|
-
console.log(
|
|
8635
|
+
console.log(pc3.dim(" export DEFI_WALLET_ADDRESS=0x..."));
|
|
8385
8636
|
console.log("");
|
|
8386
8637
|
console.log(" Commands:");
|
|
8387
|
-
console.log(
|
|
8388
|
-
console.log(
|
|
8389
|
-
console.log(
|
|
8390
|
-
console.log(
|
|
8391
|
-
console.log(
|
|
8392
|
-
console.log(
|
|
8638
|
+
console.log(pc3.dim(" defi status Protocol overview"));
|
|
8639
|
+
console.log(pc3.dim(" defi lending rates Compare lending APYs"));
|
|
8640
|
+
console.log(pc3.dim(" defi dex quote Get swap quotes"));
|
|
8641
|
+
console.log(pc3.dim(" defi portfolio View all positions"));
|
|
8642
|
+
console.log(pc3.dim(" defi scan Exploit detection"));
|
|
8643
|
+
console.log(pc3.dim(" defi --help Full command list"));
|
|
8393
8644
|
console.log("");
|
|
8394
8645
|
return;
|
|
8395
8646
|
}
|
|
@@ -8411,20 +8662,20 @@ async function showLandingPage(isJson) {
|
|
|
8411
8662
|
const divider = "\u2500".repeat(colWidth - 2);
|
|
8412
8663
|
console.log("");
|
|
8413
8664
|
console.log(
|
|
8414
|
-
|
|
8665
|
+
pc3.bold(pc3.cyan(" DeFi CLI v" + version)) + pc3.dim(" \u2014 ") + pc3.bold(heChain.name) + pc3.dim(" \xB7 ") + pc3.bold(mantleChain.name)
|
|
8415
8666
|
);
|
|
8416
8667
|
console.log("");
|
|
8417
|
-
console.log(" Wallet: " +
|
|
8668
|
+
console.log(" Wallet: " + pc3.yellow(shortenAddress(wallet)));
|
|
8418
8669
|
console.log("");
|
|
8419
8670
|
const heHeader = padRight(
|
|
8420
|
-
" " +
|
|
8671
|
+
" " + pc3.bold(heChain.name),
|
|
8421
8672
|
colWidth + 10
|
|
8422
8673
|
/* account for ANSI */
|
|
8423
8674
|
);
|
|
8424
|
-
const mantleHeader =
|
|
8675
|
+
const mantleHeader = pc3.bold(mantleChain.name);
|
|
8425
8676
|
console.log(heHeader + " " + mantleHeader);
|
|
8426
|
-
const heDivider = padRight(" " +
|
|
8427
|
-
const mantleDivider =
|
|
8677
|
+
const heDivider = padRight(" " + pc3.dim(divider), colWidth + 10);
|
|
8678
|
+
const mantleDivider = pc3.dim(divider);
|
|
8428
8679
|
console.log(heDivider + " " + mantleDivider);
|
|
8429
8680
|
const maxRows = Math.max(heBalances.length, mantleBalances.length);
|
|
8430
8681
|
for (let i = 0; i < maxRows; i++) {
|
|
@@ -8432,25 +8683,27 @@ async function showLandingPage(isJson) {
|
|
|
8432
8683
|
const mantleEntry = mantleBalances[i];
|
|
8433
8684
|
const heText = heEntry ? formatBalanceLine(heEntry.symbol, heEntry.balance) : "";
|
|
8434
8685
|
const mantleText = mantleEntry ? formatBalanceLine(mantleEntry.symbol, mantleEntry.balance) : "";
|
|
8435
|
-
const heColored = heEntry ? heEntry.balance === "0.00" || heEntry.balance === "?" ?
|
|
8436
|
-
const mantleColored = mantleEntry ? mantleEntry.balance === "0.00" || mantleEntry.balance === "?" ?
|
|
8686
|
+
const heColored = heEntry ? heEntry.balance === "0.00" || heEntry.balance === "?" ? pc3.dim(heText) : heText : "";
|
|
8687
|
+
const mantleColored = mantleEntry ? mantleEntry.balance === "0.00" || mantleEntry.balance === "?" ? pc3.dim(mantleText) : mantleText : "";
|
|
8437
8688
|
const visibleLen = heText.length;
|
|
8438
8689
|
const padNeeded = colWidth - visibleLen;
|
|
8439
8690
|
const paddedHe = heColored + (padNeeded > 0 ? " ".repeat(padNeeded) : "");
|
|
8440
8691
|
console.log(paddedHe + " " + mantleColored);
|
|
8441
8692
|
}
|
|
8442
8693
|
console.log("");
|
|
8443
|
-
console.log(" " +
|
|
8444
|
-
console.log(" " +
|
|
8445
|
-
console.log(" " +
|
|
8446
|
-
console.log(" " +
|
|
8447
|
-
console.log(" " +
|
|
8448
|
-
console.log(" " +
|
|
8449
|
-
console.log(" " +
|
|
8694
|
+
console.log(" " + pc3.bold("Commands:"));
|
|
8695
|
+
console.log(" " + pc3.cyan("defi status") + " Protocol overview");
|
|
8696
|
+
console.log(" " + pc3.cyan("defi lending rates") + " Compare lending APYs");
|
|
8697
|
+
console.log(" " + pc3.cyan("defi dex quote") + " Get swap quotes");
|
|
8698
|
+
console.log(" " + pc3.cyan("defi portfolio") + " View all positions");
|
|
8699
|
+
console.log(" " + pc3.cyan("defi scan") + " Exploit detection");
|
|
8700
|
+
console.log(" " + pc3.cyan("defi --help") + " Full command list");
|
|
8450
8701
|
console.log("");
|
|
8451
8702
|
}
|
|
8452
8703
|
|
|
8453
8704
|
// src/main.ts
|
|
8705
|
+
config({ path: resolve4(process.env.HOME || "~", ".defi", ".env"), quiet: true });
|
|
8706
|
+
config({ quiet: true });
|
|
8454
8707
|
async function main() {
|
|
8455
8708
|
try {
|
|
8456
8709
|
const rawArgs = process.argv.slice(2);
|
|
@@ -8479,7 +8732,9 @@ async function main() {
|
|
|
8479
8732
|
"bridge",
|
|
8480
8733
|
"nft",
|
|
8481
8734
|
"farm",
|
|
8482
|
-
"agent"
|
|
8735
|
+
"agent",
|
|
8736
|
+
"setup",
|
|
8737
|
+
"init"
|
|
8483
8738
|
]);
|
|
8484
8739
|
const hasSubcommand = rawArgs.some((a) => !a.startsWith("-") && knownSubcommands.has(a));
|
|
8485
8740
|
const isJson = rawArgs.includes("--json") || rawArgs.includes("--ndjson");
|