@hypurrquant/defi-cli 1.0.1 → 1.0.3
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/chains.toml +54 -0
- package/config/protocols/dex/aerodrome_base.toml +15 -0
- package/config/protocols/dex/aerodrome_cl.toml +17 -0
- package/config/protocols/dex/apeswap_bnb.toml +14 -0
- package/config/protocols/dex/babydogeswap_bnb.toml +14 -0
- package/config/protocols/dex/bakeryswap_bnb.toml +14 -0
- package/config/protocols/dex/biswap_bnb.toml +14 -0
- package/config/protocols/dex/bscswap_bnb.toml +14 -0
- package/config/protocols/dex/curve_hyperevm.toml +21 -0
- package/config/protocols/dex/fstswap_bnb.toml +14 -0
- package/config/protocols/dex/hybra.toml +3 -1
- package/config/protocols/dex/hyperswap.toml +15 -0
- package/config/protocols/dex/kittenswap.toml +4 -1
- package/config/protocols/dex/merchantmoe_mantle.toml +1 -0
- package/config/protocols/dex/nest.toml +3 -1
- package/config/protocols/dex/pancakeswap_v2_bnb.toml +14 -0
- package/config/protocols/dex/pancakeswap_v3_bnb.toml +15 -0
- package/config/protocols/dex/project_x.toml +4 -2
- package/config/protocols/dex/ramses_cl.toml +14 -7
- package/config/protocols/dex/ramses_hl.toml +6 -14
- package/config/protocols/dex/thena_fusion_bnb.toml +14 -0
- package/config/protocols/dex/thena_v1_bnb.toml +13 -0
- package/config/protocols/dex/traderjoe_monad.toml +14 -0
- package/config/protocols/dex/uniswap_v2_monad.toml +12 -0
- package/config/protocols/dex/uniswap_v3_base.toml +14 -0
- package/config/protocols/dex/uniswap_v3_bnb.toml +13 -0
- package/config/protocols/dex/uniswap_v3_monad.toml +14 -0
- package/config/protocols/lending/.omc/state/last-tool-error.json +7 -0
- package/config/protocols/lending/aave_v3_base.toml +14 -0
- package/config/protocols/lending/aave_v3_bnb.toml +14 -0
- package/config/protocols/lending/compound_v3_base.toml +14 -0
- package/config/protocols/lending/felix_morpho.toml +2 -1
- package/config/protocols/lending/hyperlend.toml +2 -1
- package/config/protocols/lending/hypurrfi.toml +2 -1
- package/config/protocols/lending/kinza_bnb.toml +15 -0
- package/config/protocols/lending/morpho_blue_monad.toml +11 -0
- package/config/protocols/lending/venus_bnb.toml +18 -0
- package/config/protocols/lending/venus_flux_bnb.toml +22 -0
- package/config/protocols/vault/beefy_bnb.toml +12 -0
- package/config/tokens/arbitrum.toml +77 -0
- package/config/tokens/base.toml +50 -0
- package/config/tokens/bnb.toml +50 -0
- package/config/tokens/ethereum.toml +107 -0
- package/config/tokens/hyperevm.toml +1 -0
- package/config/tokens/monad.toml +48 -0
- package/dist/index.js +171 -68
- package/dist/index.js.map +1 -1
- package/dist/main.js +231 -136
- package/dist/main.js.map +1 -1
- package/dist/mcp-server.js +59 -4
- package/dist/mcp-server.js.map +1 -1
- package/package.json +3 -1
- package/skills/defi-cli/package.json +1 -1
- package/config/pools.example.toml +0 -31
- package/config/protocols/cdp/felix.toml +0 -21
- package/config/protocols/nft/seaport_hyperevm.toml +0 -10
- package/config/protocols/vault/felix_vaults.toml +0 -21
- package/config/protocols/vault/hyperbeat_hyperevm.toml +0 -29
- package/config/protocols/vault/hypersurface_hyperevm.toml +0 -13
- package/config/protocols/vault/looping_hyperevm.toml +0 -17
- package/config/protocols/vault/upshift.toml +0 -14
- package/config/protocols/yield_aggregator/lazy_summer.toml +0 -13
package/dist/index.js
CHANGED
|
@@ -5612,6 +5612,7 @@ var init_dist2 = __esm({
|
|
|
5612
5612
|
}
|
|
5613
5613
|
};
|
|
5614
5614
|
CTOKEN_ABI = parseAbi17([
|
|
5615
|
+
"function underlying() external view returns (address)",
|
|
5615
5616
|
"function supplyRatePerBlock() external view returns (uint256)",
|
|
5616
5617
|
"function borrowRatePerBlock() external view returns (uint256)",
|
|
5617
5618
|
"function totalSupply() external view returns (uint256)",
|
|
@@ -5625,7 +5626,10 @@ var init_dist2 = __esm({
|
|
|
5625
5626
|
CompoundV2Adapter = class {
|
|
5626
5627
|
protocolName;
|
|
5627
5628
|
defaultVtoken;
|
|
5629
|
+
vTokenCandidates;
|
|
5628
5630
|
rpcUrl;
|
|
5631
|
+
// Lazy cache: underlying asset address (lowercased) → vToken address
|
|
5632
|
+
vTokenByAsset = null;
|
|
5629
5633
|
constructor(entry, rpcUrl) {
|
|
5630
5634
|
this.protocolName = entry.name;
|
|
5631
5635
|
this.rpcUrl = rpcUrl;
|
|
@@ -5633,6 +5637,26 @@ var init_dist2 = __esm({
|
|
|
5633
5637
|
const vtoken = contracts["vusdt"] ?? contracts["vusdc"] ?? contracts["vbnb"] ?? contracts["comptroller"];
|
|
5634
5638
|
if (!vtoken) throw DefiError.contractError("Missing vToken or comptroller address");
|
|
5635
5639
|
this.defaultVtoken = vtoken;
|
|
5640
|
+
this.vTokenCandidates = Object.entries(contracts).filter(([k]) => /^v[a-z][a-z0-9]*$/i.test(k)).map(([, v]) => v);
|
|
5641
|
+
if (this.vTokenCandidates.length === 0) this.vTokenCandidates = [vtoken];
|
|
5642
|
+
}
|
|
5643
|
+
async resolveVtoken(asset) {
|
|
5644
|
+
if (!this.rpcUrl) return null;
|
|
5645
|
+
if (!this.vTokenByAsset) {
|
|
5646
|
+
const client = createPublicClient13({ transport: http13(this.rpcUrl) });
|
|
5647
|
+
const map = /* @__PURE__ */ new Map();
|
|
5648
|
+
const lookups = await Promise.allSettled(
|
|
5649
|
+
this.vTokenCandidates.map(async (v) => {
|
|
5650
|
+
const u = await client.readContract({ address: v, abi: CTOKEN_ABI, functionName: "underlying" });
|
|
5651
|
+
return [u.toLowerCase(), v];
|
|
5652
|
+
})
|
|
5653
|
+
);
|
|
5654
|
+
for (const r of lookups) {
|
|
5655
|
+
if (r.status === "fulfilled") map.set(r.value[0], r.value[1]);
|
|
5656
|
+
}
|
|
5657
|
+
this.vTokenByAsset = map;
|
|
5658
|
+
}
|
|
5659
|
+
return this.vTokenByAsset.get(asset.toLowerCase()) ?? null;
|
|
5636
5660
|
}
|
|
5637
5661
|
name() {
|
|
5638
5662
|
return this.protocolName;
|
|
@@ -5696,15 +5720,27 @@ var init_dist2 = __esm({
|
|
|
5696
5720
|
async getRates(asset) {
|
|
5697
5721
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
5698
5722
|
const client = createPublicClient13({ transport: http13(this.rpcUrl) });
|
|
5723
|
+
const vtoken = await this.resolveVtoken(asset);
|
|
5724
|
+
if (!vtoken) {
|
|
5725
|
+
return {
|
|
5726
|
+
protocol: this.protocolName,
|
|
5727
|
+
asset,
|
|
5728
|
+
supply_apy: 0,
|
|
5729
|
+
borrow_variable_apy: 0,
|
|
5730
|
+
utilization: 0,
|
|
5731
|
+
total_supply: 0n,
|
|
5732
|
+
total_borrow: 0n
|
|
5733
|
+
};
|
|
5734
|
+
}
|
|
5699
5735
|
const [supplyRate, borrowRate, totalSupply, totalBorrows] = await Promise.all([
|
|
5700
|
-
client.readContract({ address:
|
|
5736
|
+
client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "supplyRatePerBlock" }).catch((e) => {
|
|
5701
5737
|
throw DefiError.rpcError(`[${this.protocolName}] supplyRatePerBlock failed: ${e}`);
|
|
5702
5738
|
}),
|
|
5703
|
-
client.readContract({ address:
|
|
5739
|
+
client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "borrowRatePerBlock" }).catch((e) => {
|
|
5704
5740
|
throw DefiError.rpcError(`[${this.protocolName}] borrowRatePerBlock failed: ${e}`);
|
|
5705
5741
|
}),
|
|
5706
|
-
client.readContract({ address:
|
|
5707
|
-
client.readContract({ address:
|
|
5742
|
+
client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "totalSupply" }).catch(() => 0n),
|
|
5743
|
+
client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "totalBorrows" }).catch(() => 0n)
|
|
5708
5744
|
]);
|
|
5709
5745
|
const supplyPerBlock = Number(supplyRate) / 1e18;
|
|
5710
5746
|
const borrowPerBlock = Number(borrowRate) / 1e18;
|
|
@@ -5730,6 +5766,7 @@ var init_dist2 = __esm({
|
|
|
5730
5766
|
}
|
|
5731
5767
|
};
|
|
5732
5768
|
COMET_ABI = parseAbi18([
|
|
5769
|
+
"function baseToken() external view returns (address)",
|
|
5733
5770
|
"function getUtilization() external view returns (uint256)",
|
|
5734
5771
|
"function getSupplyRate(uint256 utilization) external view returns (uint64)",
|
|
5735
5772
|
"function getBorrowRate(uint256 utilization) external view returns (uint64)",
|
|
@@ -5815,6 +5852,24 @@ var init_dist2 = __esm({
|
|
|
5815
5852
|
async getRates(asset) {
|
|
5816
5853
|
if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
|
|
5817
5854
|
const client = createPublicClient14({ transport: http14(this.rpcUrl) });
|
|
5855
|
+
const baseToken = await client.readContract({
|
|
5856
|
+
address: this.comet,
|
|
5857
|
+
abi: COMET_ABI,
|
|
5858
|
+
functionName: "baseToken"
|
|
5859
|
+
}).catch((e) => {
|
|
5860
|
+
throw DefiError.rpcError(`[${this.protocolName}] baseToken failed: ${e}`);
|
|
5861
|
+
});
|
|
5862
|
+
if (baseToken.toLowerCase() !== asset.toLowerCase()) {
|
|
5863
|
+
return {
|
|
5864
|
+
protocol: this.protocolName,
|
|
5865
|
+
asset,
|
|
5866
|
+
supply_apy: 0,
|
|
5867
|
+
borrow_variable_apy: 0,
|
|
5868
|
+
utilization: 0,
|
|
5869
|
+
total_supply: 0n,
|
|
5870
|
+
total_borrow: 0n
|
|
5871
|
+
};
|
|
5872
|
+
}
|
|
5818
5873
|
const utilization = await client.readContract({
|
|
5819
5874
|
address: this.comet,
|
|
5820
5875
|
abi: COMET_ABI,
|
|
@@ -9414,11 +9469,16 @@ function registerLending(parent, getOpts, makeExecutor2) {
|
|
|
9414
9469
|
const rates = await adapter.getRates(asset);
|
|
9415
9470
|
printOutput(rates, getOpts());
|
|
9416
9471
|
});
|
|
9417
|
-
lending.command("position").description("Show current lending position").requiredOption("--protocol <protocol>", "Protocol slug").
|
|
9472
|
+
lending.command("position").description("Show current lending position").requiredOption("--protocol <protocol>", "Protocol slug").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
|
|
9418
9473
|
const ctx = resolveContext(parent, getOpts, opts.protocol);
|
|
9419
9474
|
if (!ctx) return;
|
|
9475
|
+
const address = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
9476
|
+
if (!address) {
|
|
9477
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, getOpts());
|
|
9478
|
+
return;
|
|
9479
|
+
}
|
|
9420
9480
|
const adapter = createLending(ctx.protocol, ctx.rpcUrl);
|
|
9421
|
-
const position = await adapter.getUserPosition(
|
|
9481
|
+
const position = await adapter.getUserPosition(address);
|
|
9422
9482
|
printOutput(position, getOpts());
|
|
9423
9483
|
});
|
|
9424
9484
|
lending.command("supply").description("Supply an asset to a lending protocol").requiredOption("--protocol <protocol>", "Protocol slug").requiredOption("--asset <token>", "Token symbol or address").requiredOption("--amount <amount>", "Amount to supply in wei").option("--on-behalf-of <address>", "On behalf of address").action(async (opts) => {
|
|
@@ -9692,39 +9752,6 @@ async function scanRatesForExecute(registry, asset) {
|
|
|
9692
9752
|
}
|
|
9693
9753
|
function registerYield(parent, getOpts, makeExecutor2) {
|
|
9694
9754
|
const yieldCmd = parent.command("yield").description("Yield operations: compare, scan, optimize, execute");
|
|
9695
|
-
yieldCmd.option("--asset <token>", "Token symbol or address", "USDC").action(async (opts) => {
|
|
9696
|
-
try {
|
|
9697
|
-
const registry = Registry.loadEmbedded();
|
|
9698
|
-
const asset = opts.asset;
|
|
9699
|
-
const specifiedChain = parent.opts().chain;
|
|
9700
|
-
const chainKeys = specifiedChain ? [specifiedChain.toLowerCase()] : Array.from(registry.chains.keys());
|
|
9701
|
-
const allRates = [];
|
|
9702
|
-
for (const chainKey of chainKeys) {
|
|
9703
|
-
try {
|
|
9704
|
-
const chain = registry.getChain(chainKey);
|
|
9705
|
-
const rpc = chain.effectiveRpcUrl();
|
|
9706
|
-
let assetAddr;
|
|
9707
|
-
try {
|
|
9708
|
-
assetAddr = resolveAsset(registry, chainKey, asset);
|
|
9709
|
-
} catch {
|
|
9710
|
-
continue;
|
|
9711
|
-
}
|
|
9712
|
-
const rates = await collectLendingRates(registry, chainKey, rpc, assetAddr);
|
|
9713
|
-
for (const r of rates) {
|
|
9714
|
-
if (r.supply_apy > 0) {
|
|
9715
|
-
allRates.push({ chain: chain.name, protocol: r.protocol, supply_apy: r.supply_apy, borrow_variable_apy: r.borrow_variable_apy });
|
|
9716
|
-
}
|
|
9717
|
-
}
|
|
9718
|
-
} catch {
|
|
9719
|
-
}
|
|
9720
|
-
}
|
|
9721
|
-
allRates.sort((a, b) => b.supply_apy - a.supply_apy);
|
|
9722
|
-
const best = allRates[0] ? `${allRates[0].protocol} on ${allRates[0].chain}` : null;
|
|
9723
|
-
printOutput({ asset, chains_scanned: registry.chains.size, rates: allRates, best_supply: best }, getOpts());
|
|
9724
|
-
} catch (err) {
|
|
9725
|
-
printOutput({ error: String(err) }, getOpts());
|
|
9726
|
-
}
|
|
9727
|
-
});
|
|
9728
9755
|
yieldCmd.command("compare").description("Compare lending rates across protocols for an asset").option("--asset <token>", "Token symbol or address", "USDC").action(async (opts) => {
|
|
9729
9756
|
try {
|
|
9730
9757
|
const registry = Registry.loadEmbedded();
|
|
@@ -10319,7 +10346,7 @@ function decodeU2562(data, wordOffset = 0) {
|
|
|
10319
10346
|
}
|
|
10320
10347
|
function registerPortfolio(parent, getOpts) {
|
|
10321
10348
|
const portfolio = parent.command("portfolio").description("Aggregate positions across all protocols");
|
|
10322
|
-
portfolio.command("show").description("Show current portfolio positions").
|
|
10349
|
+
portfolio.command("show").description("Show current portfolio positions").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
|
|
10323
10350
|
const mode = getOpts();
|
|
10324
10351
|
const registry = Registry.loadEmbedded();
|
|
10325
10352
|
const chainName = requireChain(parent, getOpts);
|
|
@@ -10331,9 +10358,14 @@ function registerPortfolio(parent, getOpts) {
|
|
|
10331
10358
|
printOutput({ error: `Chain not found: ${chainName}` }, mode);
|
|
10332
10359
|
return;
|
|
10333
10360
|
}
|
|
10334
|
-
const
|
|
10361
|
+
const addr = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10362
|
+
if (!addr) {
|
|
10363
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, mode);
|
|
10364
|
+
return;
|
|
10365
|
+
}
|
|
10366
|
+
const user = addr;
|
|
10335
10367
|
if (!/^0x[0-9a-fA-F]{40}$/.test(user)) {
|
|
10336
|
-
printOutput({ error: `Invalid address: ${
|
|
10368
|
+
printOutput({ error: `Invalid address: ${addr}` }, mode);
|
|
10337
10369
|
return;
|
|
10338
10370
|
}
|
|
10339
10371
|
const rpc = chain.effectiveRpcUrl();
|
|
@@ -10459,17 +10491,22 @@ function registerPortfolio(parent, getOpts) {
|
|
|
10459
10491
|
mode
|
|
10460
10492
|
);
|
|
10461
10493
|
});
|
|
10462
|
-
portfolio.command("snapshot").description("Take a new portfolio snapshot and save it locally").
|
|
10494
|
+
portfolio.command("snapshot").description("Take a new portfolio snapshot and save it locally").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
|
|
10463
10495
|
const mode = getOpts();
|
|
10464
10496
|
const chainName = requireChain(parent, getOpts);
|
|
10465
10497
|
if (!chainName) return;
|
|
10466
10498
|
const registry = Registry.loadEmbedded();
|
|
10467
|
-
|
|
10468
|
-
|
|
10499
|
+
const addr = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10500
|
+
if (!addr) {
|
|
10501
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, mode);
|
|
10502
|
+
return;
|
|
10503
|
+
}
|
|
10504
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(addr)) {
|
|
10505
|
+
printOutput({ error: `Invalid address: ${addr}` }, mode);
|
|
10469
10506
|
return;
|
|
10470
10507
|
}
|
|
10471
10508
|
try {
|
|
10472
|
-
const snapshot = await takeSnapshot(chainName,
|
|
10509
|
+
const snapshot = await takeSnapshot(chainName, addr, registry);
|
|
10473
10510
|
const filepath = saveSnapshot(snapshot);
|
|
10474
10511
|
printOutput(
|
|
10475
10512
|
{
|
|
@@ -10487,16 +10524,21 @@ function registerPortfolio(parent, getOpts) {
|
|
|
10487
10524
|
printOutput({ error: errMsg(e) }, mode);
|
|
10488
10525
|
}
|
|
10489
10526
|
});
|
|
10490
|
-
portfolio.command("pnl").description("Show PnL since the last snapshot").
|
|
10527
|
+
portfolio.command("pnl").description("Show PnL since the last snapshot").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").option("--since <hours>", "Compare against snapshot from N hours ago (default: last snapshot)").action(async (opts) => {
|
|
10491
10528
|
const mode = getOpts();
|
|
10492
10529
|
const chainName = requireChain(parent, getOpts);
|
|
10493
10530
|
if (!chainName) return;
|
|
10494
10531
|
const registry = Registry.loadEmbedded();
|
|
10495
|
-
|
|
10496
|
-
|
|
10532
|
+
const addr = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10533
|
+
if (!addr) {
|
|
10534
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, mode);
|
|
10535
|
+
return;
|
|
10536
|
+
}
|
|
10537
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(addr)) {
|
|
10538
|
+
printOutput({ error: `Invalid address: ${addr}` }, mode);
|
|
10497
10539
|
return;
|
|
10498
10540
|
}
|
|
10499
|
-
const snapshots = loadSnapshots(chainName,
|
|
10541
|
+
const snapshots = loadSnapshots(chainName, addr, 50);
|
|
10500
10542
|
if (snapshots.length === 0) {
|
|
10501
10543
|
printOutput({ error: "No snapshots found. Run `portfolio snapshot` first." }, mode);
|
|
10502
10544
|
return;
|
|
@@ -10513,12 +10555,12 @@ function registerPortfolio(parent, getOpts) {
|
|
|
10513
10555
|
previous = match;
|
|
10514
10556
|
}
|
|
10515
10557
|
try {
|
|
10516
|
-
const current = await takeSnapshot(chainName,
|
|
10558
|
+
const current = await takeSnapshot(chainName, addr, registry);
|
|
10517
10559
|
const pnl = calculatePnL(current, previous);
|
|
10518
10560
|
printOutput(
|
|
10519
10561
|
{
|
|
10520
10562
|
chain: chainName,
|
|
10521
|
-
wallet:
|
|
10563
|
+
wallet: addr,
|
|
10522
10564
|
previous_snapshot: new Date(previous.timestamp).toISOString(),
|
|
10523
10565
|
current_time: new Date(current.timestamp).toISOString(),
|
|
10524
10566
|
...pnl,
|
|
@@ -10533,16 +10575,21 @@ function registerPortfolio(parent, getOpts) {
|
|
|
10533
10575
|
printOutput({ error: errMsg(e) }, mode);
|
|
10534
10576
|
}
|
|
10535
10577
|
});
|
|
10536
|
-
portfolio.command("history").description("List saved portfolio snapshots with values").
|
|
10578
|
+
portfolio.command("history").description("List saved portfolio snapshots with values").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").option("--limit <n>", "Number of snapshots to show", "10").action(async (opts) => {
|
|
10537
10579
|
const mode = getOpts();
|
|
10538
10580
|
const chainName = requireChain(parent, getOpts);
|
|
10539
10581
|
if (!chainName) return;
|
|
10540
|
-
|
|
10541
|
-
|
|
10582
|
+
const addr = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10583
|
+
if (!addr) {
|
|
10584
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, mode);
|
|
10585
|
+
return;
|
|
10586
|
+
}
|
|
10587
|
+
if (!/^0x[0-9a-fA-F]{40}$/.test(addr)) {
|
|
10588
|
+
printOutput({ error: `Invalid address: ${addr}` }, mode);
|
|
10542
10589
|
return;
|
|
10543
10590
|
}
|
|
10544
10591
|
const limit = parseInt(opts.limit, 10);
|
|
10545
|
-
const snapshots = loadSnapshots(chainName,
|
|
10592
|
+
const snapshots = loadSnapshots(chainName, addr, limit);
|
|
10546
10593
|
if (snapshots.length === 0) {
|
|
10547
10594
|
printOutput({ message: "No snapshots found for this address on this chain." }, mode);
|
|
10548
10595
|
return;
|
|
@@ -10705,16 +10752,21 @@ init_dist();
|
|
|
10705
10752
|
import { createPublicClient as createPublicClient24, http as http24, formatEther } from "viem";
|
|
10706
10753
|
function registerWallet(parent, getOpts) {
|
|
10707
10754
|
const wallet = parent.command("wallet").description("Wallet management");
|
|
10708
|
-
wallet.command("balance").description("Show native token balance").
|
|
10755
|
+
wallet.command("balance").description("Show native token balance").option("--address <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
|
|
10709
10756
|
const chainName = requireChain(parent, getOpts);
|
|
10710
10757
|
if (!chainName) return;
|
|
10758
|
+
const addr = opts.address ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10759
|
+
if (!addr) {
|
|
10760
|
+
printOutput({ error: "--address required (or set DEFI_WALLET_ADDRESS)" }, getOpts());
|
|
10761
|
+
return;
|
|
10762
|
+
}
|
|
10711
10763
|
const registry = Registry.loadEmbedded();
|
|
10712
10764
|
const chain = registry.getChain(chainName);
|
|
10713
10765
|
const client = createPublicClient24({ transport: http24(chain.effectiveRpcUrl()) });
|
|
10714
|
-
const balance = await client.getBalance({ address:
|
|
10766
|
+
const balance = await client.getBalance({ address: addr });
|
|
10715
10767
|
printOutput({
|
|
10716
10768
|
chain: chain.name,
|
|
10717
|
-
address:
|
|
10769
|
+
address: addr,
|
|
10718
10770
|
native_token: chain.native_token,
|
|
10719
10771
|
balance_wei: balance,
|
|
10720
10772
|
balance_formatted: formatEther(balance)
|
|
@@ -10731,22 +10783,27 @@ init_dist();
|
|
|
10731
10783
|
import { createPublicClient as createPublicClient25, http as http25, maxUint256 } from "viem";
|
|
10732
10784
|
function registerToken(parent, getOpts, makeExecutor2) {
|
|
10733
10785
|
const token = parent.command("token").description("Token operations: approve, allowance, transfer, balance");
|
|
10734
|
-
token.command("balance").description("Query token balance for an address").requiredOption("--token <token>", "Token symbol or address").
|
|
10786
|
+
token.command("balance").description("Query token balance for an address").requiredOption("--token <token>", "Token symbol or address").option("--owner <address>", "Wallet address (defaults to DEFI_WALLET_ADDRESS)").action(async (opts) => {
|
|
10735
10787
|
const chainName = requireChain(parent, getOpts);
|
|
10736
10788
|
if (!chainName) return;
|
|
10789
|
+
const owner = opts.owner ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10790
|
+
if (!owner) {
|
|
10791
|
+
printOutput({ error: "--owner required (or set DEFI_WALLET_ADDRESS)" }, getOpts());
|
|
10792
|
+
return;
|
|
10793
|
+
}
|
|
10737
10794
|
const registry = Registry.loadEmbedded();
|
|
10738
10795
|
const chain = registry.getChain(chainName);
|
|
10739
10796
|
const client = createPublicClient25({ transport: http25(chain.effectiveRpcUrl()) });
|
|
10740
10797
|
const tokenAddr = resolveTokenAddress(registry, chainName, opts.token);
|
|
10741
10798
|
const [balance, symbol, decimals] = await Promise.all([
|
|
10742
|
-
client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "balanceOf", args: [
|
|
10799
|
+
client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "balanceOf", args: [owner] }),
|
|
10743
10800
|
client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "symbol" }),
|
|
10744
10801
|
client.readContract({ address: tokenAddr, abi: erc20Abi, functionName: "decimals" })
|
|
10745
10802
|
]);
|
|
10746
10803
|
printOutput({
|
|
10747
10804
|
token: tokenAddr,
|
|
10748
10805
|
symbol,
|
|
10749
|
-
owner
|
|
10806
|
+
owner,
|
|
10750
10807
|
balance,
|
|
10751
10808
|
decimals
|
|
10752
10809
|
}, getOpts());
|
|
@@ -10762,9 +10819,14 @@ function registerToken(parent, getOpts, makeExecutor2) {
|
|
|
10762
10819
|
const result = await executor.execute(tx);
|
|
10763
10820
|
printOutput(result, getOpts());
|
|
10764
10821
|
});
|
|
10765
|
-
token.command("allowance").description("Check token allowance").requiredOption("--token <token>", "Token symbol or address").
|
|
10822
|
+
token.command("allowance").description("Check token allowance").requiredOption("--token <token>", "Token symbol or address").option("--owner <address>", "Owner address (defaults to DEFI_WALLET_ADDRESS)").requiredOption("--spender <address>", "Spender address").action(async (opts) => {
|
|
10766
10823
|
const chainName = requireChain(parent, getOpts);
|
|
10767
10824
|
if (!chainName) return;
|
|
10825
|
+
const owner = opts.owner ?? process.env["DEFI_WALLET_ADDRESS"];
|
|
10826
|
+
if (!owner) {
|
|
10827
|
+
printOutput({ error: "--owner required (or set DEFI_WALLET_ADDRESS)" }, getOpts());
|
|
10828
|
+
return;
|
|
10829
|
+
}
|
|
10768
10830
|
const registry = Registry.loadEmbedded();
|
|
10769
10831
|
const chain = registry.getChain(chainName);
|
|
10770
10832
|
const client = createPublicClient25({ transport: http25(chain.effectiveRpcUrl()) });
|
|
@@ -10773,9 +10835,9 @@ function registerToken(parent, getOpts, makeExecutor2) {
|
|
|
10773
10835
|
address: tokenAddr,
|
|
10774
10836
|
abi: erc20Abi,
|
|
10775
10837
|
functionName: "allowance",
|
|
10776
|
-
args: [
|
|
10838
|
+
args: [owner, opts.spender]
|
|
10777
10839
|
});
|
|
10778
|
-
printOutput({ token: tokenAddr, owner
|
|
10840
|
+
printOutput({ token: tokenAddr, owner, spender: opts.spender, allowance }, getOpts());
|
|
10779
10841
|
});
|
|
10780
10842
|
token.command("transfer").description("Transfer tokens to an address").requiredOption("--token <token>", "Token symbol or address").requiredOption("--to <address>", "Recipient address").requiredOption("--amount <amount>", "Amount to transfer (in wei)").action(async (opts) => {
|
|
10781
10843
|
const executor = makeExecutor2();
|
|
@@ -10794,6 +10856,29 @@ init_dist();
|
|
|
10794
10856
|
var LIFI_API = "https://li.quest/v1";
|
|
10795
10857
|
var DLN_API = "https://dln.debridge.finance/v1.0/dln/order";
|
|
10796
10858
|
var CCTP_FEE_API = "https://iris-api.circle.com/v2/burn/USDC/fees";
|
|
10859
|
+
var DEST_CHAIN_META = {
|
|
10860
|
+
ethereum: { chain_id: 1, name: "Ethereum" },
|
|
10861
|
+
optimism: { chain_id: 10, name: "Optimism" },
|
|
10862
|
+
polygon: { chain_id: 137, name: "Polygon" },
|
|
10863
|
+
arbitrum: { chain_id: 42161, name: "Arbitrum" },
|
|
10864
|
+
avalanche: { chain_id: 43114, name: "Avalanche" },
|
|
10865
|
+
linea: { chain_id: 59144, name: "Linea" },
|
|
10866
|
+
zksync: { chain_id: 324, name: "zkSync" }
|
|
10867
|
+
};
|
|
10868
|
+
function resolveDestChain(registry, slug) {
|
|
10869
|
+
try {
|
|
10870
|
+
const c = registry.getChain(slug);
|
|
10871
|
+
return { chain_id: c.chain_id, name: c.name };
|
|
10872
|
+
} catch {
|
|
10873
|
+
const meta = DEST_CHAIN_META[slug];
|
|
10874
|
+
if (!meta) {
|
|
10875
|
+
throw new Error(
|
|
10876
|
+
`Unknown destination chain '${slug}'. Source chains: hyperevm, mantle, base, bnb, monad. Bridge destinations also include: ${Object.keys(DEST_CHAIN_META).join(", ")}.`
|
|
10877
|
+
);
|
|
10878
|
+
}
|
|
10879
|
+
return meta;
|
|
10880
|
+
}
|
|
10881
|
+
}
|
|
10797
10882
|
var DLN_CHAIN_IDS = {
|
|
10798
10883
|
ethereum: 1,
|
|
10799
10884
|
optimism: 10,
|
|
@@ -10892,7 +10977,13 @@ function registerBridge(parent, getOpts) {
|
|
|
10892
10977
|
if (!chainName) return;
|
|
10893
10978
|
const registry = Registry.loadEmbedded();
|
|
10894
10979
|
const fromChain = registry.getChain(chainName);
|
|
10895
|
-
|
|
10980
|
+
let toChain;
|
|
10981
|
+
try {
|
|
10982
|
+
toChain = resolveDestChain(registry, opts.toChain);
|
|
10983
|
+
} catch (e) {
|
|
10984
|
+
printOutput({ error: errMsg(e) }, getOpts());
|
|
10985
|
+
return;
|
|
10986
|
+
}
|
|
10896
10987
|
const tokenAddr = opts.token.startsWith("0x") ? opts.token : registry.resolveToken(chainName, opts.token).address;
|
|
10897
10988
|
const recipient = resolveWallet(opts.recipient);
|
|
10898
10989
|
const provider = opts.provider.toLowerCase();
|
|
@@ -11649,7 +11740,17 @@ function handleOwsError(e, getOpts) {
|
|
|
11649
11740
|
// src/cli.ts
|
|
11650
11741
|
var _require2 = createRequire2(import.meta.url);
|
|
11651
11742
|
var _pkg = _require2("../package.json");
|
|
11652
|
-
|
|
11743
|
+
function buildBanner() {
|
|
11744
|
+
let chainCount = 0;
|
|
11745
|
+
let protocolCount = 0;
|
|
11746
|
+
try {
|
|
11747
|
+
const reg = Registry.loadEmbedded();
|
|
11748
|
+
chainCount = reg.chains.size;
|
|
11749
|
+
protocolCount = reg.protocols.length;
|
|
11750
|
+
} catch {
|
|
11751
|
+
}
|
|
11752
|
+
const stats = chainCount && protocolCount ? `${chainCount} chains \xB7 ${protocolCount} protocols \xB7 by HypurrQuant` : `by HypurrQuant`;
|
|
11753
|
+
return `
|
|
11653
11754
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
|
|
11654
11755
|
\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
11655
11756
|
\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
|
|
@@ -11657,11 +11758,13 @@ var BANNER = `
|
|
|
11657
11758
|
\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
|
|
11658
11759
|
\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
|
|
11659
11760
|
|
|
11660
|
-
|
|
11761
|
+
${stats}
|
|
11661
11762
|
|
|
11662
11763
|
Lending, LP farming, DEX swap, yield comparison
|
|
11663
11764
|
\u2014 all from your terminal.
|
|
11664
11765
|
`;
|
|
11766
|
+
}
|
|
11767
|
+
var BANNER = buildBanner();
|
|
11665
11768
|
var program = new Command().name("defi").description("DeFi CLI \u2014 Multi-chain DeFi toolkit").version(_pkg.version).addHelpText("before", BANNER).option("--json", "Output as JSON").option("--ndjson", "Output as newline-delimited JSON").option("--fields <fields>", "Select specific output fields (comma-separated)").option("--chain <chain>", "Target chain").option("--dry-run", "Dry-run mode (default, no broadcast)", true).option("--broadcast", "Actually broadcast the transaction");
|
|
11666
11769
|
function getOutputMode() {
|
|
11667
11770
|
const opts = program.opts();
|