@spectratools/aborean-cli 0.4.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +2571 -255
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4,7 +4,9 @@
4
4
  import { readFileSync } from "fs";
5
5
  import { dirname, resolve } from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { Cli as Cli5, z as z5 } from "incur";
7
+ import { checksumAddress as checksumAddress6 } from "@spectratools/cli-shared";
8
+ import { Cli as Cli8, z as z8 } from "incur";
9
+ import { formatUnits as formatUnits4 } from "viem";
8
10
 
9
11
  // src/commands/cl.ts
10
12
  import { checksumAddress, isAddress } from "@spectratools/cli-shared";
@@ -558,6 +560,87 @@ var RewardsDistributor_abi_default = [
558
560
  }
559
561
  ];
560
562
 
563
+ // src/contracts/abis/V2Pool.abi.json
564
+ var V2Pool_abi_default = [
565
+ {
566
+ type: "function",
567
+ name: "token0",
568
+ inputs: [],
569
+ outputs: [{ name: "", type: "address", internalType: "address" }],
570
+ stateMutability: "view"
571
+ },
572
+ {
573
+ type: "function",
574
+ name: "token1",
575
+ inputs: [],
576
+ outputs: [{ name: "", type: "address", internalType: "address" }],
577
+ stateMutability: "view"
578
+ },
579
+ {
580
+ type: "function",
581
+ name: "stable",
582
+ inputs: [],
583
+ outputs: [{ name: "", type: "bool", internalType: "bool" }],
584
+ stateMutability: "view"
585
+ },
586
+ {
587
+ type: "function",
588
+ name: "getReserves",
589
+ inputs: [],
590
+ outputs: [
591
+ { name: "_reserve0", type: "uint256", internalType: "uint256" },
592
+ { name: "_reserve1", type: "uint256", internalType: "uint256" },
593
+ { name: "_blockTimestampLast", type: "uint256", internalType: "uint256" }
594
+ ],
595
+ stateMutability: "view"
596
+ },
597
+ {
598
+ type: "function",
599
+ name: "totalSupply",
600
+ inputs: [],
601
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
602
+ stateMutability: "view"
603
+ },
604
+ {
605
+ type: "function",
606
+ name: "poolFees",
607
+ inputs: [],
608
+ outputs: [{ name: "", type: "address", internalType: "address" }],
609
+ stateMutability: "view"
610
+ },
611
+ {
612
+ type: "function",
613
+ name: "factory",
614
+ inputs: [],
615
+ outputs: [{ name: "", type: "address", internalType: "address" }],
616
+ stateMutability: "view"
617
+ }
618
+ ];
619
+
620
+ // src/contracts/abis/V2Router.abi.json
621
+ var V2Router_abi_default = [
622
+ {
623
+ type: "function",
624
+ name: "getAmountsOut",
625
+ inputs: [
626
+ { name: "amountIn", type: "uint256", internalType: "uint256" },
627
+ {
628
+ name: "routes",
629
+ type: "tuple[]",
630
+ internalType: "struct IRouter.Route[]",
631
+ components: [
632
+ { name: "from", type: "address", internalType: "address" },
633
+ { name: "to", type: "address", internalType: "address" },
634
+ { name: "stable", type: "bool", internalType: "bool" },
635
+ { name: "factory", type: "address", internalType: "address" }
636
+ ]
637
+ }
638
+ ],
639
+ outputs: [{ name: "amounts", type: "uint256[]", internalType: "uint256[]" }],
640
+ stateMutability: "view"
641
+ }
642
+ ];
643
+
561
644
  // src/contracts/abis/Voter.abi.json
562
645
  var Voter_abi_default = [
563
646
  {
@@ -864,6 +947,8 @@ var nonfungiblePositionManagerAbi = NonfungiblePositionManager_abi_default;
864
947
  var poolFactoryAbi = PoolFactory_abi_default;
865
948
  var quoterV2Abi = QuoterV2_abi_default;
866
949
  var rewardsDistributorAbi = RewardsDistributor_abi_default;
950
+ var v2PoolAbi = V2Pool_abi_default;
951
+ var v2RouterAbi = V2Router_abi_default;
867
952
  var voterAbi = Voter_abi_default;
868
953
  var votingEscrowAbi = VotingEscrow_abi_default;
869
954
  var votingRewardAbi = VotingReward_abi_default;
@@ -925,9 +1010,25 @@ var ABOREAN_CL_ADDRESSES = {
925
1010
  /** CL swap router */
926
1011
  swapRouter: "0xAda5d0E79681038A9547fe6a59f1413F3E720839"
927
1012
  };
1013
+ var ABOREAN_VAULT_ADDRESSES = {
1014
+ /** Factory for AutoCompounder relay vaults */
1015
+ autoCompounderFactory: "0x35b320599C1434291a0003E40Fcd1e40fA9E0222",
1016
+ /** Factory for AutoConverter relay vaults */
1017
+ autoConverterFactory: "0xf114D2aCF8aAFDde833e0a8ba2dc5A3946614354",
1018
+ /** veABX Maxi relay vault */
1019
+ veAbxMaxiRelay: "0xcbeB1A72A31670AE5ba27798c124Fcf3Ca1971df",
1020
+ /** ABX rewards relay vault */
1021
+ abxRewardsRelay: "0x3E8D887Bba5D4A757FaE757883CA35882AB4a0ee"
1022
+ };
1023
+ var ABOREAN_LENDING_ADDRESSES = {
1024
+ /** Morpho Blue core contract on Abstract */
1025
+ morphoBlue: "0xc85CE8ffdA27b646D269516B8d0Fa6ec2E958B55"
1026
+ };
928
1027
  var ABOREAN_ADDRESSES = {
929
1028
  ...ABOREAN_V2_ADDRESSES,
930
- ...ABOREAN_CL_ADDRESSES
1029
+ ...ABOREAN_CL_ADDRESSES,
1030
+ ...ABOREAN_VAULT_ADDRESSES,
1031
+ ...ABOREAN_LENDING_ADDRESSES
931
1032
  };
932
1033
 
933
1034
  // src/contracts/client.ts
@@ -1244,17 +1345,39 @@ cl.command("pools", {
1244
1345
  }),
1245
1346
  async run(c) {
1246
1347
  const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1247
- const pools = await listPoolAddresses(client);
1248
- const poolStates = await readPoolStates(client, pools);
1348
+ const pools2 = await listPoolAddresses(client);
1349
+ const poolStates = await readPoolStates(client, pools2);
1249
1350
  const tokenMeta = await readTokenMetadata(
1250
1351
  client,
1251
1352
  poolStates.flatMap((pool) => [pool.token0, pool.token1])
1252
1353
  );
1253
1354
  const rows = poolStates.map((pool) => toPoolRow(pool, tokenMeta));
1254
- return c.ok({
1255
- count: rows.length,
1256
- pools: rows
1257
- });
1355
+ const firstPool = rows[0];
1356
+ return c.ok(
1357
+ {
1358
+ count: rows.length,
1359
+ pools: rows
1360
+ },
1361
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
1362
+ cta: {
1363
+ description: "Explore CL pools:",
1364
+ commands: [
1365
+ ...firstPool ? [
1366
+ {
1367
+ command: "cl pool",
1368
+ args: { pool: firstPool.pool },
1369
+ description: `Inspect ${firstPool.pair}`
1370
+ }
1371
+ ] : [],
1372
+ {
1373
+ command: "cl positions",
1374
+ args: { owner: "<address>" },
1375
+ description: "List CL positions for an address"
1376
+ }
1377
+ ]
1378
+ }
1379
+ }
1380
+ );
1258
1381
  }
1259
1382
  });
1260
1383
  cl.command("pool", {
@@ -1277,9 +1400,33 @@ cl.command("pool", {
1277
1400
  const checksummedPool = checksumAddress(c.args.pool);
1278
1401
  const [poolState] = await readPoolStates(client, [checksummedPool]);
1279
1402
  const tokenMeta = await readTokenMetadata(client, [poolState.token0, poolState.token1]);
1280
- return c.ok({
1281
- pool: toPoolRow(poolState, tokenMeta)
1282
- });
1403
+ const row = toPoolRow(poolState, tokenMeta);
1404
+ return c.ok(
1405
+ {
1406
+ pool: row
1407
+ },
1408
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
1409
+ cta: {
1410
+ description: "Next steps:",
1411
+ commands: [
1412
+ {
1413
+ command: "cl quote",
1414
+ args: {
1415
+ tokenIn: row.token0.address,
1416
+ tokenOut: row.token1.address,
1417
+ amountIn: "1"
1418
+ },
1419
+ description: `Quote a ${row.token0.symbol} \u2192 ${row.token1.symbol} swap`
1420
+ },
1421
+ {
1422
+ command: "cl positions",
1423
+ args: { owner: "<address>" },
1424
+ description: "List positions in this pool"
1425
+ }
1426
+ ]
1427
+ }
1428
+ }
1429
+ );
1283
1430
  }
1284
1431
  });
1285
1432
  cl.command("positions", {
@@ -1365,11 +1512,35 @@ cl.command("positions", {
1365
1512
  }
1366
1513
  };
1367
1514
  });
1368
- return c.ok({
1369
- owner,
1370
- count: positions.length,
1371
- positions
1372
- });
1515
+ const firstPosition = positions[0];
1516
+ return c.ok(
1517
+ {
1518
+ owner,
1519
+ count: positions.length,
1520
+ positions
1521
+ },
1522
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
1523
+ cta: {
1524
+ description: "Related commands:",
1525
+ commands: firstPosition ? [
1526
+ {
1527
+ command: "cl pool",
1528
+ args: { pool: "<poolAddress>" },
1529
+ description: `Inspect pool for ${firstPosition.pair}`
1530
+ },
1531
+ {
1532
+ command: "cl quote",
1533
+ args: {
1534
+ tokenIn: firstPosition.token0.address,
1535
+ tokenOut: firstPosition.token1.address,
1536
+ amountIn: "1"
1537
+ },
1538
+ description: `Quote a ${firstPosition.token0.symbol} \u2192 ${firstPosition.token1.symbol} swap`
1539
+ }
1540
+ ] : []
1541
+ }
1542
+ }
1543
+ );
1373
1544
  }
1374
1545
  });
1375
1546
  cl.command("quote", {
@@ -1459,31 +1630,54 @@ cl.command("quote", {
1459
1630
  const inIsToken0 = normalizeAddress(inAddress) === normalizeAddress(selectedPool.token0);
1460
1631
  const poolMidPriceOutPerIn = inIsToken0 ? poolPrices.token1PerToken0 : poolPrices.token0PerToken1;
1461
1632
  const priceImpactPct = quotePriceOutPerIn === null || poolMidPriceOutPerIn === null || poolMidPriceOutPerIn === 0 ? null : finiteOrNull((poolMidPriceOutPerIn - quotePriceOutPerIn) / poolMidPriceOutPerIn * 100);
1462
- return c.ok({
1463
- pool: checksumAddress(selectedPool.pool),
1464
- selectedFee: selectedPool.fee,
1465
- selectedTickSpacing: selectedPool.tickSpacing,
1466
- tokenIn: inMeta,
1467
- tokenOut: outMeta,
1468
- amountIn: {
1469
- raw: amountInRaw.toString(),
1470
- decimal: amountInDecimal
1471
- },
1472
- amountOut: {
1473
- raw: amountOutRaw.toString(),
1474
- decimal: amountOutDecimal
1475
- },
1476
- execution: {
1477
- sqrtPriceX96After: quote[1].toString(),
1478
- initializedTicksCrossed: quote[2],
1479
- gasEstimate: quote[3].toString()
1633
+ return c.ok(
1634
+ {
1635
+ pool: checksumAddress(selectedPool.pool),
1636
+ selectedFee: selectedPool.fee,
1637
+ selectedTickSpacing: selectedPool.tickSpacing,
1638
+ tokenIn: inMeta,
1639
+ tokenOut: outMeta,
1640
+ amountIn: {
1641
+ raw: amountInRaw.toString(),
1642
+ decimal: amountInDecimal
1643
+ },
1644
+ amountOut: {
1645
+ raw: amountOutRaw.toString(),
1646
+ decimal: amountOutDecimal
1647
+ },
1648
+ execution: {
1649
+ sqrtPriceX96After: quote[1].toString(),
1650
+ initializedTicksCrossed: quote[2],
1651
+ gasEstimate: quote[3].toString()
1652
+ },
1653
+ prices: {
1654
+ poolMidPriceOutPerIn,
1655
+ quotePriceOutPerIn,
1656
+ priceImpactPct
1657
+ }
1480
1658
  },
1481
- prices: {
1482
- poolMidPriceOutPerIn,
1483
- quotePriceOutPerIn,
1484
- priceImpactPct
1659
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
1660
+ cta: {
1661
+ description: "Related commands:",
1662
+ commands: [
1663
+ {
1664
+ command: "cl pool",
1665
+ args: { pool: checksumAddress(selectedPool.pool) },
1666
+ description: "Inspect the pool used for this quote"
1667
+ },
1668
+ {
1669
+ command: "cl quote",
1670
+ args: {
1671
+ tokenIn: outMeta.address,
1672
+ tokenOut: inMeta.address,
1673
+ amountIn: amountOutDecimal
1674
+ },
1675
+ description: `Reverse quote ${outMeta.symbol} \u2192 ${inMeta.symbol}`
1676
+ }
1677
+ ]
1678
+ }
1485
1679
  }
1486
- });
1680
+ );
1487
1681
  }
1488
1682
  });
1489
1683
 
@@ -1556,18 +1750,18 @@ async function discoverGaugePools(client) {
1556
1750
  }))
1557
1751
  }) : Promise.resolve([])
1558
1752
  ]);
1559
- const pools = [...v2Pools, ...clPools];
1560
- if (!pools.length) return [];
1753
+ const pools2 = [...v2Pools, ...clPools];
1754
+ if (!pools2.length) return [];
1561
1755
  const gauges2 = await client.multicall({
1562
1756
  allowFailure: false,
1563
- contracts: pools.map((pool) => ({
1757
+ contracts: pools2.map((pool) => ({
1564
1758
  abi: voterAbi,
1565
1759
  address: ABOREAN_V2_ADDRESSES.voter,
1566
1760
  functionName: "gauges",
1567
1761
  args: [pool]
1568
1762
  }))
1569
1763
  });
1570
- return pools.map((pool, index) => ({ pool, gauge: gauges2[index] })).filter(({ gauge }) => gauge.toLowerCase() !== ZERO_ADDRESS.toLowerCase());
1764
+ return pools2.map((pool, index) => ({ pool, gauge: gauges2[index] })).filter(({ gauge }) => gauge.toLowerCase() !== ZERO_ADDRESS.toLowerCase());
1571
1765
  }
1572
1766
  var gauges = Cli2.create("gauges", {
1573
1767
  description: "Inspect Aborean gauge emissions, staking, and user positions."
@@ -1646,10 +1840,25 @@ gauges.command("list", {
1646
1840
  periodFinishRelative: relTime(periodFinish)
1647
1841
  };
1648
1842
  });
1649
- return c.ok({
1650
- gauges: items,
1651
- count: items.length
1652
- });
1843
+ const firstGauge = items[0];
1844
+ return c.ok(
1845
+ {
1846
+ gauges: items,
1847
+ count: items.length
1848
+ },
1849
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
1850
+ cta: {
1851
+ description: "Explore gauges:",
1852
+ commands: firstGauge ? [
1853
+ {
1854
+ command: "gauges info",
1855
+ args: { gauge: firstGauge.gauge },
1856
+ description: "Inspect top gauge details"
1857
+ }
1858
+ ] : []
1859
+ }
1860
+ }
1861
+ );
1653
1862
  }
1654
1863
  });
1655
1864
  gauges.command("info", {
@@ -1776,24 +1985,46 @@ gauges.command("info", {
1776
1985
  functionName: "left"
1777
1986
  })
1778
1987
  ]);
1779
- return c.ok({
1780
- gauge: toChecksum(gauge),
1781
- pool: toChecksum(pool),
1782
- isAlive,
1783
- stakingToken: toChecksum(stakingToken),
1784
- rewardToken: toChecksum(rewardToken),
1785
- totalStaked: totalStaked.toString(),
1786
- rewardRate: rewardRate.toString(),
1787
- rewardPerTokenStored: rewardPerTokenStored.toString(),
1788
- fees0: fees0.toString(),
1789
- fees1: fees1.toString(),
1790
- left: left.toString(),
1791
- periodFinish: asNum(periodFinish),
1792
- periodFinishRelative: relTime(periodFinish),
1793
- lastUpdateTime: asNum(lastUpdateTime),
1794
- bribeContract: toChecksum(bribeContract),
1795
- feeContract: toChecksum(feeContract)
1796
- });
1988
+ return c.ok(
1989
+ {
1990
+ gauge: toChecksum(gauge),
1991
+ pool: toChecksum(pool),
1992
+ isAlive,
1993
+ stakingToken: toChecksum(stakingToken),
1994
+ rewardToken: toChecksum(rewardToken),
1995
+ totalStaked: totalStaked.toString(),
1996
+ rewardRate: rewardRate.toString(),
1997
+ rewardPerTokenStored: rewardPerTokenStored.toString(),
1998
+ fees0: fees0.toString(),
1999
+ fees1: fees1.toString(),
2000
+ left: left.toString(),
2001
+ periodFinish: asNum(periodFinish),
2002
+ periodFinishRelative: relTime(periodFinish),
2003
+ lastUpdateTime: asNum(lastUpdateTime),
2004
+ bribeContract: toChecksum(bribeContract),
2005
+ feeContract: toChecksum(feeContract)
2006
+ },
2007
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
2008
+ cta: {
2009
+ description: "Related commands:",
2010
+ commands: [
2011
+ {
2012
+ command: "ve stats",
2013
+ description: "View veABX global stats"
2014
+ },
2015
+ {
2016
+ command: "voter weights",
2017
+ description: "Check pool voting weight distribution"
2018
+ },
2019
+ {
2020
+ command: "voter bribes",
2021
+ args: { pool: toChecksum(pool) },
2022
+ description: "View bribe rewards for this pool"
2023
+ }
2024
+ ]
2025
+ }
2026
+ }
2027
+ );
1797
2028
  }
1798
2029
  });
1799
2030
  gauges.command("staked", {
@@ -1872,47 +2103,1624 @@ gauges.command("staked", {
1872
2103
  staked: position.staked.toString(),
1873
2104
  earned: position.earned.toString()
1874
2105
  }));
1875
- return c.ok({
1876
- address: toChecksum(c.args.address),
1877
- positions,
1878
- count: positions.length
1879
- });
2106
+ const firstPosition = positions[0];
2107
+ return c.ok(
2108
+ {
2109
+ address: toChecksum(c.args.address),
2110
+ positions,
2111
+ count: positions.length
2112
+ },
2113
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
2114
+ cta: {
2115
+ description: "Related commands:",
2116
+ commands: [
2117
+ ...firstPosition ? [
2118
+ {
2119
+ command: "gauges info",
2120
+ args: { gauge: firstPosition.gauge },
2121
+ description: "Inspect gauge details"
2122
+ }
2123
+ ] : [],
2124
+ {
2125
+ command: "ve locks",
2126
+ args: { address: toChecksum(c.args.address) },
2127
+ description: "View veNFT locks for this address"
2128
+ }
2129
+ ]
2130
+ }
2131
+ }
2132
+ );
1880
2133
  }
1881
2134
  });
1882
2135
 
1883
- // src/commands/ve.ts
2136
+ // src/commands/lending.ts
2137
+ import { checksumAddress as checksumAddress3, isAddress as isAddress2 } from "@spectratools/cli-shared";
1884
2138
  import { Cli as Cli3, z as z3 } from "incur";
2139
+ import { formatUnits as formatUnits2 } from "viem";
2140
+ var MORPHO_DEPLOY_BLOCK = 13947713n;
1885
2141
  var env3 = z3.object({
1886
2142
  ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
1887
2143
  });
1888
- var ve = Cli3.create("ve", {
1889
- description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
2144
+ var morphoAbi = [
2145
+ {
2146
+ type: "event",
2147
+ name: "CreateMarket",
2148
+ inputs: [
2149
+ { type: "bytes32", name: "id", indexed: true },
2150
+ {
2151
+ type: "tuple",
2152
+ name: "marketParams",
2153
+ indexed: false,
2154
+ components: [
2155
+ { type: "address", name: "loanToken" },
2156
+ { type: "address", name: "collateralToken" },
2157
+ { type: "address", name: "oracle" },
2158
+ { type: "address", name: "irm" },
2159
+ { type: "uint256", name: "lltv" }
2160
+ ]
2161
+ }
2162
+ ],
2163
+ anonymous: false
2164
+ },
2165
+ {
2166
+ type: "function",
2167
+ name: "idToMarketParams",
2168
+ stateMutability: "view",
2169
+ inputs: [{ type: "bytes32", name: "id" }],
2170
+ outputs: [
2171
+ { type: "address", name: "loanToken" },
2172
+ { type: "address", name: "collateralToken" },
2173
+ { type: "address", name: "oracle" },
2174
+ { type: "address", name: "irm" },
2175
+ { type: "uint256", name: "lltv" }
2176
+ ]
2177
+ },
2178
+ {
2179
+ type: "function",
2180
+ name: "market",
2181
+ stateMutability: "view",
2182
+ inputs: [{ type: "bytes32", name: "id" }],
2183
+ outputs: [
2184
+ { type: "uint128", name: "totalSupplyAssets" },
2185
+ { type: "uint128", name: "totalSupplyShares" },
2186
+ { type: "uint128", name: "totalBorrowAssets" },
2187
+ { type: "uint128", name: "totalBorrowShares" },
2188
+ { type: "uint128", name: "lastUpdate" },
2189
+ { type: "uint128", name: "fee" }
2190
+ ]
2191
+ },
2192
+ {
2193
+ type: "function",
2194
+ name: "position",
2195
+ stateMutability: "view",
2196
+ inputs: [
2197
+ { type: "bytes32", name: "id" },
2198
+ { type: "address", name: "user" }
2199
+ ],
2200
+ outputs: [
2201
+ { type: "uint256", name: "supplyShares" },
2202
+ { type: "uint128", name: "borrowShares" },
2203
+ { type: "uint128", name: "collateral" }
2204
+ ]
2205
+ }
2206
+ ];
2207
+ var erc20MetadataAbi2 = [
2208
+ {
2209
+ type: "function",
2210
+ name: "symbol",
2211
+ stateMutability: "view",
2212
+ inputs: [],
2213
+ outputs: [{ type: "string" }]
2214
+ },
2215
+ {
2216
+ type: "function",
2217
+ name: "decimals",
2218
+ stateMutability: "view",
2219
+ inputs: [],
2220
+ outputs: [{ type: "uint8" }]
2221
+ }
2222
+ ];
2223
+ var tokenMetaSchema = z3.object({
2224
+ address: z3.string(),
2225
+ symbol: z3.string(),
2226
+ decimals: z3.number()
1890
2227
  });
1891
- ve.command("stats", {
1892
- description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
2228
+ var lendingMarketRowSchema = z3.object({
2229
+ marketId: z3.string(),
2230
+ loanToken: tokenMetaSchema,
2231
+ collateralToken: tokenMetaSchema,
2232
+ oracle: z3.string(),
2233
+ irm: z3.string(),
2234
+ lltvBps: z3.number(),
2235
+ lltvPercent: z3.number(),
2236
+ totalSupplyAssets: z3.string(),
2237
+ totalBorrowAssets: z3.string(),
2238
+ totalSupplyShares: z3.string(),
2239
+ totalBorrowShares: z3.string(),
2240
+ availableLiquidityAssets: z3.string(),
2241
+ utilization: z3.number().nullable(),
2242
+ feeWad: z3.string(),
2243
+ lastUpdate: z3.number()
2244
+ });
2245
+ function isMarketId(value) {
2246
+ return /^0x[0-9a-fA-F]{64}$/.test(value);
2247
+ }
2248
+ function shortAddress2(address) {
2249
+ return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
2250
+ }
2251
+ function finiteOrNull2(value) {
2252
+ return Number.isFinite(value) ? value : null;
2253
+ }
2254
+ function sharesToAssets(shares, totalShares, totalAssets) {
2255
+ if (shares === 0n || totalShares === 0n) return 0n;
2256
+ return shares * totalAssets / totalShares;
2257
+ }
2258
+ function normalizeMarketParams(value) {
2259
+ if (Array.isArray(value)) {
2260
+ return {
2261
+ loanToken: checksumAddress3(String(value[0])),
2262
+ collateralToken: checksumAddress3(String(value[1])),
2263
+ oracle: checksumAddress3(String(value[2])),
2264
+ irm: checksumAddress3(String(value[3])),
2265
+ lltv: BigInt(value[4])
2266
+ };
2267
+ }
2268
+ if (typeof value !== "object" || value === null) {
2269
+ throw new Error("invalid market params");
2270
+ }
2271
+ const v = value;
2272
+ return {
2273
+ loanToken: checksumAddress3(String(v.loanToken)),
2274
+ collateralToken: checksumAddress3(String(v.collateralToken)),
2275
+ oracle: checksumAddress3(String(v.oracle)),
2276
+ irm: checksumAddress3(String(v.irm)),
2277
+ lltv: BigInt(v.lltv)
2278
+ };
2279
+ }
2280
+ function normalizeMarketState(value) {
2281
+ if (Array.isArray(value)) {
2282
+ return {
2283
+ totalSupplyAssets: BigInt(value[0]),
2284
+ totalSupplyShares: BigInt(value[1]),
2285
+ totalBorrowAssets: BigInt(value[2]),
2286
+ totalBorrowShares: BigInt(value[3]),
2287
+ lastUpdate: BigInt(value[4]),
2288
+ fee: BigInt(value[5])
2289
+ };
2290
+ }
2291
+ if (typeof value !== "object" || value === null) {
2292
+ throw new Error("invalid market state");
2293
+ }
2294
+ const v = value;
2295
+ return {
2296
+ totalSupplyAssets: BigInt(v.totalSupplyAssets),
2297
+ totalSupplyShares: BigInt(v.totalSupplyShares),
2298
+ totalBorrowAssets: BigInt(v.totalBorrowAssets),
2299
+ totalBorrowShares: BigInt(v.totalBorrowShares),
2300
+ lastUpdate: BigInt(v.lastUpdate),
2301
+ fee: BigInt(v.fee)
2302
+ };
2303
+ }
2304
+ function toMarketRow(marketId, params, state, tokenMeta) {
2305
+ const loanMeta = tokenMeta.get(params.loanToken.toLowerCase()) ?? {
2306
+ address: params.loanToken,
2307
+ symbol: shortAddress2(params.loanToken),
2308
+ decimals: 18
2309
+ };
2310
+ const collateralMeta = tokenMeta.get(params.collateralToken.toLowerCase()) ?? {
2311
+ address: params.collateralToken,
2312
+ symbol: shortAddress2(params.collateralToken),
2313
+ decimals: 18
2314
+ };
2315
+ const utilization = state.totalSupplyAssets === 0n ? null : finiteOrNull2(Number(state.totalBorrowAssets) / Number(state.totalSupplyAssets));
2316
+ const lltvPercent = Number(params.lltv) / 1e16;
2317
+ return {
2318
+ marketId,
2319
+ loanToken: {
2320
+ address: toChecksum(loanMeta.address),
2321
+ symbol: loanMeta.symbol,
2322
+ decimals: loanMeta.decimals
2323
+ },
2324
+ collateralToken: {
2325
+ address: toChecksum(collateralMeta.address),
2326
+ symbol: collateralMeta.symbol,
2327
+ decimals: collateralMeta.decimals
2328
+ },
2329
+ oracle: toChecksum(params.oracle),
2330
+ irm: toChecksum(params.irm),
2331
+ lltvBps: Math.round(lltvPercent * 100),
2332
+ lltvPercent,
2333
+ totalSupplyAssets: state.totalSupplyAssets.toString(),
2334
+ totalBorrowAssets: state.totalBorrowAssets.toString(),
2335
+ totalSupplyShares: state.totalSupplyShares.toString(),
2336
+ totalBorrowShares: state.totalBorrowShares.toString(),
2337
+ availableLiquidityAssets: (state.totalSupplyAssets - state.totalBorrowAssets).toString(),
2338
+ utilization,
2339
+ feeWad: state.fee.toString(),
2340
+ lastUpdate: asNum(state.lastUpdate)
2341
+ };
2342
+ }
2343
+ async function readTokenMetadata2(client, addresses) {
2344
+ const unique = [...new Set(addresses.map((address) => address.toLowerCase()))];
2345
+ if (unique.length === 0) {
2346
+ return /* @__PURE__ */ new Map();
2347
+ }
2348
+ const contracts = unique.flatMap((address) => [
2349
+ {
2350
+ abi: erc20MetadataAbi2,
2351
+ address,
2352
+ functionName: "symbol"
2353
+ },
2354
+ {
2355
+ abi: erc20MetadataAbi2,
2356
+ address,
2357
+ functionName: "decimals"
2358
+ }
2359
+ ]);
2360
+ const results = await client.multicall({
2361
+ allowFailure: true,
2362
+ contracts
2363
+ });
2364
+ const map = /* @__PURE__ */ new Map();
2365
+ for (let i = 0; i < unique.length; i += 1) {
2366
+ const address = unique[i];
2367
+ const symbolResult = results[i * 2];
2368
+ const decimalsResult = results[i * 2 + 1];
2369
+ const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : shortAddress2(address);
2370
+ const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : 18;
2371
+ map.set(address.toLowerCase(), {
2372
+ address: checksumAddress3(address),
2373
+ symbol,
2374
+ decimals
2375
+ });
2376
+ }
2377
+ return map;
2378
+ }
2379
+ async function discoverMarketIds(client) {
2380
+ const logs = await client.getContractEvents({
2381
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2382
+ abi: morphoAbi,
2383
+ eventName: "CreateMarket",
2384
+ fromBlock: MORPHO_DEPLOY_BLOCK,
2385
+ toBlock: "latest"
2386
+ });
2387
+ const seen = /* @__PURE__ */ new Set();
2388
+ const ids = [];
2389
+ for (const log of logs) {
2390
+ const id = log.args.id;
2391
+ if (!id) continue;
2392
+ const key = id.toLowerCase();
2393
+ if (seen.has(key)) continue;
2394
+ seen.add(key);
2395
+ ids.push(id);
2396
+ }
2397
+ return ids;
2398
+ }
2399
+ async function readMarkets(client, marketIds) {
2400
+ if (marketIds.length === 0) return [];
2401
+ const contracts = marketIds.flatMap((marketId) => [
2402
+ {
2403
+ abi: morphoAbi,
2404
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2405
+ functionName: "idToMarketParams",
2406
+ args: [marketId]
2407
+ },
2408
+ {
2409
+ abi: morphoAbi,
2410
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2411
+ functionName: "market",
2412
+ args: [marketId]
2413
+ }
2414
+ ]);
2415
+ const values = await client.multicall({
2416
+ allowFailure: false,
2417
+ contracts
2418
+ });
2419
+ return marketIds.map((marketId, index) => {
2420
+ const paramsValue = values[index * 2];
2421
+ const stateValue = values[index * 2 + 1];
2422
+ return {
2423
+ marketId,
2424
+ params: normalizeMarketParams(paramsValue),
2425
+ state: normalizeMarketState(stateValue)
2426
+ };
2427
+ });
2428
+ }
2429
+ function summarizeByLoanToken(markets, tokenMeta) {
2430
+ const byLoanToken = /* @__PURE__ */ new Map();
2431
+ for (const { params, state } of markets) {
2432
+ const key = params.loanToken.toLowerCase();
2433
+ const prev = byLoanToken.get(key);
2434
+ if (prev) {
2435
+ prev.totalSupply += state.totalSupplyAssets;
2436
+ prev.totalBorrow += state.totalBorrowAssets;
2437
+ continue;
2438
+ }
2439
+ byLoanToken.set(key, {
2440
+ token: params.loanToken,
2441
+ totalSupply: state.totalSupplyAssets,
2442
+ totalBorrow: state.totalBorrowAssets
2443
+ });
2444
+ }
2445
+ return [...byLoanToken.values()].map((entry) => {
2446
+ const meta = tokenMeta.get(entry.token.toLowerCase()) ?? {
2447
+ address: entry.token,
2448
+ symbol: shortAddress2(entry.token),
2449
+ decimals: 18
2450
+ };
2451
+ return {
2452
+ token: toChecksum(entry.token),
2453
+ symbol: meta.symbol,
2454
+ decimals: meta.decimals,
2455
+ totalSupplyAssets: entry.totalSupply.toString(),
2456
+ totalBorrowAssets: entry.totalBorrow.toString()
2457
+ };
2458
+ });
2459
+ }
2460
+ async function readLendingSummary(client) {
2461
+ const marketIds = await discoverMarketIds(client);
2462
+ const markets = await readMarkets(client, marketIds);
2463
+ const tokenMeta = await readTokenMetadata2(
2464
+ client,
2465
+ markets.flatMap((market) => [market.params.loanToken, market.params.collateralToken])
2466
+ );
2467
+ return {
2468
+ available: true,
2469
+ morpho: toChecksum(ABOREAN_LENDING_ADDRESSES.morphoBlue),
2470
+ marketCount: marketIds.length,
2471
+ supplyByLoanToken: summarizeByLoanToken(markets, tokenMeta)
2472
+ };
2473
+ }
2474
+ var lending = Cli3.create("lending", {
2475
+ description: "Inspect Morpho lending markets on Abstract."
2476
+ });
2477
+ lending.command("markets", {
2478
+ description: "List Morpho markets discovered from CreateMarket events.",
2479
+ args: z3.object({
2480
+ limit: z3.coerce.number().int().positive().max(200).default(25).describe("Max markets to return")
2481
+ }),
1893
2482
  env: env3,
1894
2483
  output: z3.object({
1895
- token: z3.string(),
1896
- totalVotingPower: z3.string(),
1897
- totalLocked: z3.string(),
1898
- permanentLocked: z3.string(),
1899
- epoch: z3.number(),
1900
- decayBias: z3.string(),
1901
- decaySlope: z3.string(),
1902
- lastCheckpointTimestamp: z3.number(),
1903
- lastCheckpointBlock: z3.number()
2484
+ morpho: z3.string(),
2485
+ marketCount: z3.number(),
2486
+ markets: z3.array(lendingMarketRowSchema),
2487
+ totalsByLoanToken: z3.array(
2488
+ z3.object({
2489
+ token: z3.string(),
2490
+ symbol: z3.string(),
2491
+ decimals: z3.number(),
2492
+ totalSupplyAssets: z3.string(),
2493
+ totalBorrowAssets: z3.string()
2494
+ })
2495
+ )
1904
2496
  }),
1905
- examples: [{ description: "Show global veABX state and decay metrics" }],
2497
+ examples: [{ description: "List active Morpho markets on Abstract" }],
1906
2498
  async run(c) {
1907
2499
  const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
1908
- const [token, totalVotingPower, totalLocked, permanentLocked, epoch] = await Promise.all([
1909
- client.readContract({
1910
- abi: votingEscrowAbi,
1911
- address: ABOREAN_V2_ADDRESSES.votingEscrow,
1912
- functionName: "token"
1913
- }),
1914
- client.readContract({
1915
- abi: votingEscrowAbi,
2500
+ const marketIds = await discoverMarketIds(client);
2501
+ const markets = await readMarkets(client, marketIds);
2502
+ const tokenMeta = await readTokenMetadata2(
2503
+ client,
2504
+ markets.flatMap((market) => [market.params.loanToken, market.params.collateralToken])
2505
+ );
2506
+ const rows = markets.map((market) => toMarketRow(market.marketId, market.params, market.state, tokenMeta)).sort(
2507
+ (a, b) => BigInt(a.totalSupplyAssets) > BigInt(b.totalSupplyAssets) ? -1 : BigInt(a.totalSupplyAssets) < BigInt(b.totalSupplyAssets) ? 1 : 0
2508
+ ).slice(0, c.args.limit);
2509
+ const firstMarket = rows[0];
2510
+ return c.ok(
2511
+ {
2512
+ morpho: toChecksum(ABOREAN_LENDING_ADDRESSES.morphoBlue),
2513
+ marketCount: marketIds.length,
2514
+ markets: rows,
2515
+ totalsByLoanToken: summarizeByLoanToken(markets, tokenMeta)
2516
+ },
2517
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
2518
+ cta: {
2519
+ description: "Explore lending:",
2520
+ commands: [
2521
+ ...firstMarket ? [
2522
+ {
2523
+ command: "lending market",
2524
+ args: { marketId: firstMarket.marketId },
2525
+ description: `Inspect ${firstMarket.loanToken.symbol}/${firstMarket.collateralToken.symbol} market`
2526
+ }
2527
+ ] : [],
2528
+ {
2529
+ command: "pools list",
2530
+ description: "View V2 AMM pools"
2531
+ }
2532
+ ]
2533
+ }
2534
+ }
2535
+ );
2536
+ }
2537
+ });
2538
+ lending.command("market", {
2539
+ description: "Get details for one Morpho market id (bytes32).",
2540
+ args: z3.object({
2541
+ marketId: z3.string().describe("Morpho market id (bytes32 hex)")
2542
+ }),
2543
+ env: env3,
2544
+ output: lendingMarketRowSchema,
2545
+ examples: [
2546
+ {
2547
+ args: { marketId: "0xfe1d7da2fbde85b1fee120c88df3e6b55164a2442dab97486d3d4f719a5ff1fb" },
2548
+ description: "Inspect one Morpho market by id"
2549
+ }
2550
+ ],
2551
+ async run(c) {
2552
+ if (!isMarketId(c.args.marketId)) {
2553
+ return c.error({
2554
+ code: "INVALID_ARGUMENT",
2555
+ message: "marketId must be a 32-byte hex string (0x + 64 hex chars)"
2556
+ });
2557
+ }
2558
+ const marketId = c.args.marketId;
2559
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
2560
+ const [paramsRaw, stateRaw] = await Promise.all([
2561
+ client.readContract({
2562
+ abi: morphoAbi,
2563
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2564
+ functionName: "idToMarketParams",
2565
+ args: [marketId]
2566
+ }),
2567
+ client.readContract({
2568
+ abi: morphoAbi,
2569
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2570
+ functionName: "market",
2571
+ args: [marketId]
2572
+ })
2573
+ ]);
2574
+ const params = normalizeMarketParams(paramsRaw);
2575
+ const state = normalizeMarketState(stateRaw);
2576
+ const tokenMeta = await readTokenMetadata2(client, [params.loanToken, params.collateralToken]);
2577
+ const row = toMarketRow(marketId, params, state, tokenMeta);
2578
+ return c.ok(
2579
+ row,
2580
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
2581
+ cta: {
2582
+ description: "Related commands:",
2583
+ commands: [
2584
+ {
2585
+ command: "lending position",
2586
+ args: { marketId, user: "<address>" },
2587
+ description: "Inspect a user position in this market"
2588
+ },
2589
+ {
2590
+ command: "lending markets",
2591
+ description: "List all Morpho markets"
2592
+ }
2593
+ ]
2594
+ }
2595
+ }
2596
+ );
2597
+ }
2598
+ });
2599
+ lending.command("position", {
2600
+ description: "Inspect one user position in a Morpho market.",
2601
+ args: z3.object({
2602
+ marketId: z3.string().describe("Morpho market id (bytes32 hex)"),
2603
+ user: z3.string().describe("Position owner address")
2604
+ }),
2605
+ env: env3,
2606
+ output: z3.object({
2607
+ marketId: z3.string(),
2608
+ user: z3.string(),
2609
+ loanToken: tokenMetaSchema,
2610
+ collateralToken: tokenMetaSchema,
2611
+ supplyShares: z3.string(),
2612
+ supplyAssetsEstimate: z3.object({
2613
+ raw: z3.string(),
2614
+ decimal: z3.string()
2615
+ }),
2616
+ borrowShares: z3.string(),
2617
+ borrowAssetsEstimate: z3.object({
2618
+ raw: z3.string(),
2619
+ decimal: z3.string()
2620
+ }),
2621
+ collateralAssets: z3.object({
2622
+ raw: z3.string(),
2623
+ decimal: z3.string()
2624
+ })
2625
+ }),
2626
+ examples: [
2627
+ {
2628
+ args: {
2629
+ marketId: "0xfe1d7da2fbde85b1fee120c88df3e6b55164a2442dab97486d3d4f719a5ff1fb",
2630
+ user: "0x0000000000000000000000000000000000000000"
2631
+ },
2632
+ description: "Inspect one user position in a market"
2633
+ }
2634
+ ],
2635
+ async run(c) {
2636
+ if (!isMarketId(c.args.marketId)) {
2637
+ return c.error({
2638
+ code: "INVALID_ARGUMENT",
2639
+ message: "marketId must be a 32-byte hex string (0x + 64 hex chars)"
2640
+ });
2641
+ }
2642
+ if (!isAddress2(c.args.user)) {
2643
+ return c.error({
2644
+ code: "INVALID_ARGUMENT",
2645
+ message: "user must be a valid address"
2646
+ });
2647
+ }
2648
+ const marketId = c.args.marketId;
2649
+ const user = checksumAddress3(c.args.user);
2650
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
2651
+ const [paramsRaw, stateRaw, positionRaw] = await Promise.all([
2652
+ client.readContract({
2653
+ abi: morphoAbi,
2654
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2655
+ functionName: "idToMarketParams",
2656
+ args: [marketId]
2657
+ }),
2658
+ client.readContract({
2659
+ abi: morphoAbi,
2660
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2661
+ functionName: "market",
2662
+ args: [marketId]
2663
+ }),
2664
+ client.readContract({
2665
+ abi: morphoAbi,
2666
+ address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
2667
+ functionName: "position",
2668
+ args: [marketId, user]
2669
+ })
2670
+ ]);
2671
+ const params = normalizeMarketParams(paramsRaw);
2672
+ const state = normalizeMarketState(stateRaw);
2673
+ const position = Array.isArray(positionRaw) ? {
2674
+ supplyShares: BigInt(positionRaw[0]),
2675
+ borrowShares: BigInt(positionRaw[1]),
2676
+ collateral: BigInt(positionRaw[2])
2677
+ } : {
2678
+ supplyShares: BigInt(positionRaw.supplyShares),
2679
+ borrowShares: BigInt(positionRaw.borrowShares),
2680
+ collateral: BigInt(positionRaw.collateral)
2681
+ };
2682
+ const tokenMeta = await readTokenMetadata2(client, [params.loanToken, params.collateralToken]);
2683
+ const loanMeta = tokenMeta.get(params.loanToken.toLowerCase()) ?? {
2684
+ address: params.loanToken,
2685
+ symbol: shortAddress2(params.loanToken),
2686
+ decimals: 18
2687
+ };
2688
+ const collateralMeta = tokenMeta.get(params.collateralToken.toLowerCase()) ?? {
2689
+ address: params.collateralToken,
2690
+ symbol: shortAddress2(params.collateralToken),
2691
+ decimals: 18
2692
+ };
2693
+ const supplyAssetsEstimate = sharesToAssets(
2694
+ BigInt(position.supplyShares),
2695
+ state.totalSupplyShares,
2696
+ state.totalSupplyAssets
2697
+ );
2698
+ const borrowAssetsEstimate = sharesToAssets(
2699
+ BigInt(position.borrowShares),
2700
+ state.totalBorrowShares,
2701
+ state.totalBorrowAssets
2702
+ );
2703
+ return c.ok(
2704
+ {
2705
+ marketId,
2706
+ user: toChecksum(user),
2707
+ loanToken: {
2708
+ address: toChecksum(loanMeta.address),
2709
+ symbol: loanMeta.symbol,
2710
+ decimals: loanMeta.decimals
2711
+ },
2712
+ collateralToken: {
2713
+ address: toChecksum(collateralMeta.address),
2714
+ symbol: collateralMeta.symbol,
2715
+ decimals: collateralMeta.decimals
2716
+ },
2717
+ supplyShares: position.supplyShares.toString(),
2718
+ supplyAssetsEstimate: {
2719
+ raw: supplyAssetsEstimate.toString(),
2720
+ decimal: formatUnits2(supplyAssetsEstimate, loanMeta.decimals)
2721
+ },
2722
+ borrowShares: position.borrowShares.toString(),
2723
+ borrowAssetsEstimate: {
2724
+ raw: borrowAssetsEstimate.toString(),
2725
+ decimal: formatUnits2(borrowAssetsEstimate, loanMeta.decimals)
2726
+ },
2727
+ collateralAssets: {
2728
+ raw: position.collateral.toString(),
2729
+ decimal: formatUnits2(BigInt(position.collateral), collateralMeta.decimals)
2730
+ }
2731
+ },
2732
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
2733
+ cta: {
2734
+ description: "Related commands:",
2735
+ commands: [
2736
+ {
2737
+ command: "lending market",
2738
+ args: { marketId },
2739
+ description: "View market details"
2740
+ },
2741
+ {
2742
+ command: "lending markets",
2743
+ description: "List all Morpho markets"
2744
+ }
2745
+ ]
2746
+ }
2747
+ }
2748
+ );
2749
+ }
2750
+ });
2751
+
2752
+ // src/commands/pools.ts
2753
+ import { checksumAddress as checksumAddress4, isAddress as isAddress3 } from "@spectratools/cli-shared";
2754
+ import { Cli as Cli4, z as z4 } from "incur";
2755
+ import { formatUnits as formatUnits3, parseUnits as parseUnits2 } from "viem";
2756
+ var MULTICALL_BATCH_SIZE2 = 100;
2757
+ var env4 = z4.object({
2758
+ ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
2759
+ });
2760
+ var tokenSchema2 = z4.object({
2761
+ address: z4.string(),
2762
+ symbol: z4.string(),
2763
+ decimals: z4.number()
2764
+ });
2765
+ var amountSchema = z4.object({
2766
+ raw: z4.string(),
2767
+ decimal: z4.string()
2768
+ });
2769
+ var feeSchema = z4.object({
2770
+ feeBps: z4.number(),
2771
+ feePercent: z4.number()
2772
+ }).nullable();
2773
+ var poolSummarySchema = z4.object({
2774
+ pool: z4.string(),
2775
+ pair: z4.string(),
2776
+ stable: z4.boolean(),
2777
+ poolType: z4.enum(["stable", "volatile"]),
2778
+ token0: tokenSchema2,
2779
+ token1: tokenSchema2,
2780
+ reserves: z4.object({
2781
+ token0: amountSchema,
2782
+ token1: amountSchema,
2783
+ blockTimestampLast: z4.number()
2784
+ }),
2785
+ totalSupply: z4.string(),
2786
+ fee: feeSchema
2787
+ });
2788
+ var erc20MetadataAbi3 = [
2789
+ {
2790
+ type: "function",
2791
+ name: "symbol",
2792
+ stateMutability: "view",
2793
+ inputs: [],
2794
+ outputs: [{ type: "string" }]
2795
+ },
2796
+ {
2797
+ type: "function",
2798
+ name: "decimals",
2799
+ stateMutability: "view",
2800
+ inputs: [],
2801
+ outputs: [{ type: "uint8" }]
2802
+ }
2803
+ ];
2804
+ function shortAddress3(address) {
2805
+ return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
2806
+ }
2807
+ function toAddress(address) {
2808
+ return checksumAddress4(address);
2809
+ }
2810
+ function finiteOrNull3(value) {
2811
+ return Number.isFinite(value) ? value : null;
2812
+ }
2813
+ function toFeeInfo(value) {
2814
+ if (value === null) return null;
2815
+ const feeBps = Number(value);
2816
+ return {
2817
+ feeBps,
2818
+ feePercent: feeBps / 1e4
2819
+ };
2820
+ }
2821
+ function chunk2(items, size) {
2822
+ const output = [];
2823
+ for (let i = 0; i < items.length; i += size) {
2824
+ output.push(items.slice(i, i + size));
2825
+ }
2826
+ return output;
2827
+ }
2828
+ async function multicallStrict2(client, contracts) {
2829
+ if (contracts.length === 0) return [];
2830
+ const batches = chunk2(contracts, MULTICALL_BATCH_SIZE2);
2831
+ const output = [];
2832
+ for (const batch of batches) {
2833
+ const values = await client.multicall({
2834
+ allowFailure: false,
2835
+ contracts: batch
2836
+ });
2837
+ output.push(...values);
2838
+ }
2839
+ return output;
2840
+ }
2841
+ async function multicallAllowFailure2(client, contracts) {
2842
+ if (contracts.length === 0) return [];
2843
+ const batches = chunk2(contracts, MULTICALL_BATCH_SIZE2);
2844
+ const output = [];
2845
+ for (const batch of batches) {
2846
+ const values = await client.multicall({
2847
+ allowFailure: true,
2848
+ contracts: batch
2849
+ });
2850
+ output.push(...values);
2851
+ }
2852
+ return output;
2853
+ }
2854
+ function fallbackTokenMeta(address) {
2855
+ const checksummed = checksumAddress4(address);
2856
+ return {
2857
+ address: checksummed,
2858
+ symbol: shortAddress3(checksummed),
2859
+ decimals: 18
2860
+ };
2861
+ }
2862
+ async function readTokenMetadata3(client, tokenAddresses) {
2863
+ const unique = [
2864
+ ...new Set(tokenAddresses.map((address) => checksumAddress4(address).toLowerCase()))
2865
+ ];
2866
+ if (unique.length === 0) {
2867
+ return /* @__PURE__ */ new Map();
2868
+ }
2869
+ const contracts = unique.flatMap((address) => [
2870
+ {
2871
+ abi: erc20MetadataAbi3,
2872
+ address,
2873
+ functionName: "symbol"
2874
+ },
2875
+ {
2876
+ abi: erc20MetadataAbi3,
2877
+ address,
2878
+ functionName: "decimals"
2879
+ }
2880
+ ]);
2881
+ const values = await multicallAllowFailure2(client, contracts);
2882
+ const map = /* @__PURE__ */ new Map();
2883
+ for (let i = 0; i < unique.length; i += 1) {
2884
+ const address = unique[i];
2885
+ const symbolResult = values[i * 2];
2886
+ const decimalsResult = values[i * 2 + 1];
2887
+ const fallback = fallbackTokenMeta(address);
2888
+ const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : fallback.symbol;
2889
+ const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : fallback.decimals;
2890
+ map.set(address.toLowerCase(), {
2891
+ address: checksumAddress4(address),
2892
+ symbol,
2893
+ decimals
2894
+ });
2895
+ }
2896
+ return map;
2897
+ }
2898
+ async function readPoolStates2(client, pools2) {
2899
+ if (pools2.length === 0) {
2900
+ return [];
2901
+ }
2902
+ const contracts = pools2.flatMap((pool) => [
2903
+ {
2904
+ abi: v2PoolAbi,
2905
+ address: pool,
2906
+ functionName: "token0"
2907
+ },
2908
+ {
2909
+ abi: v2PoolAbi,
2910
+ address: pool,
2911
+ functionName: "token1"
2912
+ },
2913
+ {
2914
+ abi: v2PoolAbi,
2915
+ address: pool,
2916
+ functionName: "stable"
2917
+ },
2918
+ {
2919
+ abi: v2PoolAbi,
2920
+ address: pool,
2921
+ functionName: "getReserves"
2922
+ },
2923
+ {
2924
+ abi: v2PoolAbi,
2925
+ address: pool,
2926
+ functionName: "totalSupply"
2927
+ }
2928
+ ]);
2929
+ const values = await multicallStrict2(client, contracts);
2930
+ return pools2.map((pool, index) => {
2931
+ const offset = index * 5;
2932
+ const reserves = values[offset + 3];
2933
+ return {
2934
+ pool,
2935
+ token0: values[offset],
2936
+ token1: values[offset + 1],
2937
+ stable: values[offset + 2],
2938
+ reserve0: reserves[0],
2939
+ reserve1: reserves[1],
2940
+ blockTimestampLast: reserves[2],
2941
+ totalSupply: values[offset + 4]
2942
+ };
2943
+ });
2944
+ }
2945
+ async function readPoolFees(client, pools2) {
2946
+ if (pools2.length === 0) {
2947
+ return [];
2948
+ }
2949
+ const contracts = pools2.map(({ pool, stable }) => ({
2950
+ abi: poolFactoryAbi,
2951
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
2952
+ functionName: "getFee",
2953
+ args: [pool, stable]
2954
+ }));
2955
+ const values = await multicallAllowFailure2(client, contracts);
2956
+ return values.map(
2957
+ (value) => value.status === "success" && typeof value.result === "bigint" ? value.result : null
2958
+ );
2959
+ }
2960
+ function toAmount(raw, decimals) {
2961
+ return {
2962
+ raw: raw.toString(),
2963
+ decimal: formatUnits3(raw, decimals)
2964
+ };
2965
+ }
2966
+ function toPoolSummary(state, tokens, fee) {
2967
+ const token0 = tokens.get(state.token0.toLowerCase()) ?? fallbackTokenMeta(state.token0);
2968
+ const token1 = tokens.get(state.token1.toLowerCase()) ?? fallbackTokenMeta(state.token1);
2969
+ return {
2970
+ pool: checksumAddress4(state.pool),
2971
+ pair: `${token0.symbol}/${token1.symbol}`,
2972
+ stable: state.stable,
2973
+ poolType: state.stable ? "stable" : "volatile",
2974
+ token0,
2975
+ token1,
2976
+ reserves: {
2977
+ token0: toAmount(state.reserve0, token0.decimals),
2978
+ token1: toAmount(state.reserve1, token1.decimals),
2979
+ blockTimestampLast: Number(state.blockTimestampLast)
2980
+ },
2981
+ totalSupply: state.totalSupply.toString(),
2982
+ fee: toFeeInfo(fee)
2983
+ };
2984
+ }
2985
+ var pools = Cli4.create("pools", {
2986
+ description: "Inspect V2 AMM pools, reserves, quotes, and fee configuration."
2987
+ });
2988
+ pools.command("list", {
2989
+ description: "List V2 pools with token pairs, reserves, and stable/volatile type.",
2990
+ options: z4.object({
2991
+ offset: z4.coerce.number().int().nonnegative().default(0).describe("Pool index offset"),
2992
+ limit: z4.coerce.number().int().positive().max(500).default(50).describe("Maximum pools to return (max 500)")
2993
+ }),
2994
+ env: env4,
2995
+ output: z4.object({
2996
+ total: z4.number(),
2997
+ offset: z4.number(),
2998
+ limit: z4.number(),
2999
+ count: z4.number(),
3000
+ pools: z4.array(poolSummarySchema)
3001
+ }),
3002
+ async run(c) {
3003
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3004
+ const totalRaw = await client.readContract({
3005
+ abi: poolFactoryAbi,
3006
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
3007
+ functionName: "allPoolsLength"
3008
+ });
3009
+ const total = Number(totalRaw);
3010
+ const offset = Math.min(c.options.offset, total);
3011
+ const end = Math.min(total, offset + c.options.limit);
3012
+ if (offset >= end) {
3013
+ return c.ok({
3014
+ total,
3015
+ offset,
3016
+ limit: c.options.limit,
3017
+ count: 0,
3018
+ pools: []
3019
+ });
3020
+ }
3021
+ const indices = Array.from({ length: end - offset }, (_, i) => BigInt(offset + i));
3022
+ const poolAddresses = await multicallStrict2(
3023
+ client,
3024
+ indices.map((index) => ({
3025
+ abi: poolFactoryAbi,
3026
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
3027
+ functionName: "allPools",
3028
+ args: [index]
3029
+ }))
3030
+ );
3031
+ const poolStates = await readPoolStates2(client, poolAddresses);
3032
+ const tokenMeta = await readTokenMetadata3(
3033
+ client,
3034
+ poolStates.flatMap((pool) => [pool.token0, pool.token1])
3035
+ );
3036
+ const fees = await readPoolFees(
3037
+ client,
3038
+ poolStates.map((pool) => ({ pool: pool.pool, stable: pool.stable }))
3039
+ );
3040
+ const summaries = poolStates.map(
3041
+ (pool, index) => toPoolSummary(pool, tokenMeta, fees[index] ?? null)
3042
+ );
3043
+ const firstPool = summaries[0];
3044
+ return c.ok(
3045
+ {
3046
+ total,
3047
+ offset,
3048
+ limit: c.options.limit,
3049
+ count: summaries.length,
3050
+ pools: summaries
3051
+ },
3052
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3053
+ cta: {
3054
+ description: "Explore pools:",
3055
+ commands: [
3056
+ ...firstPool ? [
3057
+ {
3058
+ command: "pools pool",
3059
+ args: { address: firstPool.pool },
3060
+ description: `Inspect ${firstPool.pair}`
3061
+ }
3062
+ ] : [],
3063
+ ...firstPool ? [
3064
+ {
3065
+ command: "pools fees",
3066
+ args: { pool: firstPool.pool },
3067
+ description: `Check fees for ${firstPool.pair}`
3068
+ }
3069
+ ] : []
3070
+ ]
3071
+ }
3072
+ }
3073
+ );
3074
+ }
3075
+ });
3076
+ pools.command("pool", {
3077
+ description: "Get detailed state for one V2 pool.",
3078
+ args: z4.object({
3079
+ address: z4.string().describe("Pool address")
3080
+ }),
3081
+ env: env4,
3082
+ output: z4.object({
3083
+ pool: poolSummarySchema.extend({
3084
+ poolFees: z4.string(),
3085
+ factory: z4.string()
3086
+ })
3087
+ }),
3088
+ async run(c) {
3089
+ if (!isAddress3(c.args.address)) {
3090
+ return c.error({
3091
+ code: "INVALID_ADDRESS",
3092
+ message: `Invalid pool address: "${c.args.address}". Use a valid 0x-prefixed 20-byte hex address.`
3093
+ });
3094
+ }
3095
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3096
+ const poolAddress = toAddress(c.args.address);
3097
+ const [token0, token1, stable, reserves, totalSupply, poolFees, factory] = await multicallStrict2(client, [
3098
+ {
3099
+ abi: v2PoolAbi,
3100
+ address: poolAddress,
3101
+ functionName: "token0"
3102
+ },
3103
+ {
3104
+ abi: v2PoolAbi,
3105
+ address: poolAddress,
3106
+ functionName: "token1"
3107
+ },
3108
+ {
3109
+ abi: v2PoolAbi,
3110
+ address: poolAddress,
3111
+ functionName: "stable"
3112
+ },
3113
+ {
3114
+ abi: v2PoolAbi,
3115
+ address: poolAddress,
3116
+ functionName: "getReserves"
3117
+ },
3118
+ {
3119
+ abi: v2PoolAbi,
3120
+ address: poolAddress,
3121
+ functionName: "totalSupply"
3122
+ },
3123
+ {
3124
+ abi: v2PoolAbi,
3125
+ address: poolAddress,
3126
+ functionName: "poolFees"
3127
+ },
3128
+ {
3129
+ abi: v2PoolAbi,
3130
+ address: poolAddress,
3131
+ functionName: "factory"
3132
+ }
3133
+ ]);
3134
+ const tokenMeta = await readTokenMetadata3(client, [token0, token1]);
3135
+ const [fee] = await readPoolFees(client, [{ pool: poolAddress, stable }]);
3136
+ const summary = toPoolSummary(
3137
+ {
3138
+ pool: poolAddress,
3139
+ token0,
3140
+ token1,
3141
+ stable,
3142
+ reserve0: reserves[0],
3143
+ reserve1: reserves[1],
3144
+ blockTimestampLast: reserves[2],
3145
+ totalSupply
3146
+ },
3147
+ tokenMeta,
3148
+ fee ?? null
3149
+ );
3150
+ return c.ok(
3151
+ {
3152
+ pool: {
3153
+ ...summary,
3154
+ poolFees: checksumAddress4(poolFees),
3155
+ factory: checksumAddress4(factory)
3156
+ }
3157
+ },
3158
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3159
+ cta: {
3160
+ description: "Next steps:",
3161
+ commands: [
3162
+ {
3163
+ command: "pools quote",
3164
+ args: {
3165
+ tokenIn: summary.token0.address,
3166
+ tokenOut: summary.token1.address,
3167
+ amountIn: "1"
3168
+ },
3169
+ description: `Quote a ${summary.token0.symbol} \u2192 ${summary.token1.symbol} swap`
3170
+ },
3171
+ {
3172
+ command: "pools fees",
3173
+ args: { pool: checksumAddress4(poolAddress) },
3174
+ description: "Check fee configuration"
3175
+ }
3176
+ ]
3177
+ }
3178
+ }
3179
+ );
3180
+ }
3181
+ });
3182
+ pools.command("quote", {
3183
+ description: "Quote a single-hop V2 swap between tokenIn and tokenOut.",
3184
+ args: z4.object({
3185
+ tokenIn: z4.string().describe("Input token address"),
3186
+ tokenOut: z4.string().describe("Output token address"),
3187
+ amountIn: z4.string().describe("Input amount in human-readable decimal units")
3188
+ }),
3189
+ options: z4.object({
3190
+ stable: z4.boolean().default(false).describe("Use stable pool route (default: volatile)")
3191
+ }),
3192
+ env: env4,
3193
+ output: z4.object({
3194
+ pool: z4.string(),
3195
+ stable: z4.boolean(),
3196
+ tokenIn: tokenSchema2,
3197
+ tokenOut: tokenSchema2,
3198
+ amountIn: amountSchema,
3199
+ amountOut: amountSchema,
3200
+ priceOutPerIn: z4.number().nullable()
3201
+ }),
3202
+ async run(c) {
3203
+ if (!isAddress3(c.args.tokenIn) || !isAddress3(c.args.tokenOut)) {
3204
+ return c.error({
3205
+ code: "INVALID_ADDRESS",
3206
+ message: "tokenIn and tokenOut must both be valid 0x-prefixed 20-byte addresses."
3207
+ });
3208
+ }
3209
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3210
+ const tokenIn = toAddress(c.args.tokenIn);
3211
+ const tokenOut = toAddress(c.args.tokenOut);
3212
+ const tokenMeta = await readTokenMetadata3(client, [tokenIn, tokenOut]);
3213
+ const inMeta = tokenMeta.get(tokenIn.toLowerCase()) ?? fallbackTokenMeta(tokenIn);
3214
+ const outMeta = tokenMeta.get(tokenOut.toLowerCase()) ?? fallbackTokenMeta(tokenOut);
3215
+ let amountInRaw;
3216
+ try {
3217
+ amountInRaw = parseUnits2(c.args.amountIn, inMeta.decimals);
3218
+ } catch {
3219
+ return c.error({
3220
+ code: "INVALID_AMOUNT",
3221
+ message: `Invalid amountIn: "${c.args.amountIn}" for token ${inMeta.symbol} (${inMeta.decimals} decimals).`
3222
+ });
3223
+ }
3224
+ const poolAddress = await client.readContract({
3225
+ abi: poolFactoryAbi,
3226
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
3227
+ functionName: "getPool",
3228
+ args: [tokenIn, tokenOut, c.options.stable]
3229
+ });
3230
+ if (poolAddress.toLowerCase() === ZERO_ADDRESS.toLowerCase()) {
3231
+ return c.error({
3232
+ code: "POOL_NOT_FOUND",
3233
+ message: `No ${c.options.stable ? "stable" : "volatile"} V2 pool found for pair ${checksumAddress4(
3234
+ tokenIn
3235
+ )}/${checksumAddress4(tokenOut)}.`
3236
+ });
3237
+ }
3238
+ const amounts = await client.readContract({
3239
+ abi: v2RouterAbi,
3240
+ address: ABOREAN_V2_ADDRESSES.router,
3241
+ functionName: "getAmountsOut",
3242
+ args: [
3243
+ amountInRaw,
3244
+ [
3245
+ {
3246
+ from: tokenIn,
3247
+ to: tokenOut,
3248
+ stable: c.options.stable,
3249
+ factory: ABOREAN_V2_ADDRESSES.poolFactory
3250
+ }
3251
+ ]
3252
+ ]
3253
+ });
3254
+ const amountOutRaw = amounts[amounts.length - 1] ?? 0n;
3255
+ const amountInDecimal = formatUnits3(amountInRaw, inMeta.decimals);
3256
+ const amountOutDecimal = formatUnits3(amountOutRaw, outMeta.decimals);
3257
+ const ratio = Number(amountOutDecimal) / Number(amountInDecimal);
3258
+ return c.ok(
3259
+ {
3260
+ pool: checksumAddress4(poolAddress),
3261
+ stable: c.options.stable,
3262
+ tokenIn: inMeta,
3263
+ tokenOut: outMeta,
3264
+ amountIn: {
3265
+ raw: amountInRaw.toString(),
3266
+ decimal: amountInDecimal
3267
+ },
3268
+ amountOut: {
3269
+ raw: amountOutRaw.toString(),
3270
+ decimal: amountOutDecimal
3271
+ },
3272
+ priceOutPerIn: Number(amountInDecimal) === 0 ? null : finiteOrNull3(ratio)
3273
+ },
3274
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3275
+ cta: {
3276
+ description: "Related commands:",
3277
+ commands: [
3278
+ {
3279
+ command: "pools pool",
3280
+ args: { address: checksumAddress4(poolAddress) },
3281
+ description: "Inspect the pool used for this quote"
3282
+ },
3283
+ {
3284
+ command: "pools quote",
3285
+ args: {
3286
+ tokenIn: outMeta.address,
3287
+ tokenOut: inMeta.address,
3288
+ amountIn: amountOutDecimal
3289
+ },
3290
+ description: `Reverse quote ${outMeta.symbol} \u2192 ${inMeta.symbol}`
3291
+ }
3292
+ ]
3293
+ }
3294
+ }
3295
+ );
3296
+ }
3297
+ });
3298
+ pools.command("fees", {
3299
+ description: "Read V2 fee configuration for a pool address.",
3300
+ args: z4.object({
3301
+ pool: z4.string().describe("Pool address")
3302
+ }),
3303
+ env: env4,
3304
+ output: z4.object({
3305
+ pool: z4.string(),
3306
+ pair: z4.string(),
3307
+ stable: z4.boolean(),
3308
+ activeFee: feeSchema,
3309
+ stableFee: feeSchema,
3310
+ volatileFee: feeSchema
3311
+ }),
3312
+ async run(c) {
3313
+ if (!isAddress3(c.args.pool)) {
3314
+ return c.error({
3315
+ code: "INVALID_ADDRESS",
3316
+ message: `Invalid pool address: "${c.args.pool}". Use a valid 0x-prefixed 20-byte hex address.`
3317
+ });
3318
+ }
3319
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3320
+ const pool = toAddress(c.args.pool);
3321
+ const [token0, token1, stable] = await multicallStrict2(client, [
3322
+ {
3323
+ abi: v2PoolAbi,
3324
+ address: pool,
3325
+ functionName: "token0"
3326
+ },
3327
+ {
3328
+ abi: v2PoolAbi,
3329
+ address: pool,
3330
+ functionName: "token1"
3331
+ },
3332
+ {
3333
+ abi: v2PoolAbi,
3334
+ address: pool,
3335
+ functionName: "stable"
3336
+ }
3337
+ ]);
3338
+ const tokenMeta = await readTokenMetadata3(client, [token0, token1]);
3339
+ const token0Meta = tokenMeta.get(token0.toLowerCase()) ?? fallbackTokenMeta(token0);
3340
+ const token1Meta = tokenMeta.get(token1.toLowerCase()) ?? fallbackTokenMeta(token1);
3341
+ const [stableFeeRaw, volatileFeeRaw] = await readPoolFees(client, [
3342
+ { pool, stable: true },
3343
+ { pool, stable: false }
3344
+ ]);
3345
+ const stableFee = toFeeInfo(stableFeeRaw ?? null);
3346
+ const volatileFee = toFeeInfo(volatileFeeRaw ?? null);
3347
+ return c.ok(
3348
+ {
3349
+ pool: checksumAddress4(pool),
3350
+ pair: `${token0Meta.symbol}/${token1Meta.symbol}`,
3351
+ stable,
3352
+ activeFee: stable ? stableFee : volatileFee,
3353
+ stableFee,
3354
+ volatileFee
3355
+ },
3356
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3357
+ cta: {
3358
+ description: "Related commands:",
3359
+ commands: [
3360
+ {
3361
+ command: "pools pool",
3362
+ args: { address: checksumAddress4(pool) },
3363
+ description: "View full pool state"
3364
+ },
3365
+ {
3366
+ command: "pools quote",
3367
+ args: {
3368
+ tokenIn: token0Meta.address,
3369
+ tokenOut: token1Meta.address,
3370
+ amountIn: "1"
3371
+ },
3372
+ description: `Quote a ${token0Meta.symbol} \u2192 ${token1Meta.symbol} swap`
3373
+ }
3374
+ ]
3375
+ }
3376
+ }
3377
+ );
3378
+ }
3379
+ });
3380
+
3381
+ // src/commands/vaults.ts
3382
+ import { checksumAddress as checksumAddress5, isAddress as isAddress4 } from "@spectratools/cli-shared";
3383
+ import { Cli as Cli5, z as z5 } from "incur";
3384
+ var env5 = z5.object({
3385
+ ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
3386
+ });
3387
+ var relayAbi = [
3388
+ {
3389
+ type: "function",
3390
+ name: "name",
3391
+ stateMutability: "view",
3392
+ inputs: [],
3393
+ outputs: [{ type: "string" }]
3394
+ },
3395
+ {
3396
+ type: "function",
3397
+ name: "mTokenId",
3398
+ stateMutability: "view",
3399
+ inputs: [],
3400
+ outputs: [{ type: "uint256" }]
3401
+ },
3402
+ {
3403
+ type: "function",
3404
+ name: "token",
3405
+ stateMutability: "view",
3406
+ inputs: [],
3407
+ outputs: [{ type: "address" }]
3408
+ },
3409
+ {
3410
+ type: "function",
3411
+ name: "keeperLastRun",
3412
+ stateMutability: "view",
3413
+ inputs: [],
3414
+ outputs: [{ type: "uint256" }]
3415
+ }
3416
+ ];
3417
+ var erc20Abi = [
3418
+ {
3419
+ type: "function",
3420
+ name: "symbol",
3421
+ stateMutability: "view",
3422
+ inputs: [],
3423
+ outputs: [{ type: "string" }]
3424
+ },
3425
+ {
3426
+ type: "function",
3427
+ name: "decimals",
3428
+ stateMutability: "view",
3429
+ inputs: [],
3430
+ outputs: [{ type: "uint8" }]
3431
+ },
3432
+ {
3433
+ type: "function",
3434
+ name: "balanceOf",
3435
+ stateMutability: "view",
3436
+ inputs: [{ type: "address", name: "owner" }],
3437
+ outputs: [{ type: "uint256" }]
3438
+ }
3439
+ ];
3440
+ var votingEscrowLiteAbi = [
3441
+ {
3442
+ type: "function",
3443
+ name: "balanceOfNFT",
3444
+ stateMutability: "view",
3445
+ inputs: [{ type: "uint256", name: "tokenId" }],
3446
+ outputs: [{ type: "uint256" }]
3447
+ }
3448
+ ];
3449
+ var relayRowSchema = z5.object({
3450
+ label: z5.string(),
3451
+ relay: z5.string(),
3452
+ name: z5.string(),
3453
+ factoryType: z5.enum(["autoCompounder", "autoConverter"]),
3454
+ managedTokenId: z5.string(),
3455
+ managedVotingPower: z5.string(),
3456
+ relayToken: z5.object({
3457
+ address: z5.string(),
3458
+ symbol: z5.string(),
3459
+ decimals: z5.number()
3460
+ }),
3461
+ relayTokenBalance: z5.string(),
3462
+ keeperLastRun: z5.number(),
3463
+ keeperLastRunRelative: z5.string(),
3464
+ secondsSinceKeeperRun: z5.number()
3465
+ });
3466
+ var KNOWN_RELAYS = [
3467
+ {
3468
+ label: "veABX Maxi Relay",
3469
+ relay: checksumAddress5(ABOREAN_VAULT_ADDRESSES.veAbxMaxiRelay),
3470
+ factoryType: "autoCompounder"
3471
+ },
3472
+ {
3473
+ label: "ABX Rewards Relay",
3474
+ relay: checksumAddress5(ABOREAN_VAULT_ADDRESSES.abxRewardsRelay),
3475
+ factoryType: "autoConverter"
3476
+ }
3477
+ ];
3478
+ function shortAddress4(address) {
3479
+ return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
3480
+ }
3481
+ async function readRelaySnapshot(client, relay) {
3482
+ const [name, managedTokenId, relayTokenAddress, keeperLastRun] = await Promise.all([
3483
+ client.readContract({
3484
+ abi: relayAbi,
3485
+ address: relay.relay,
3486
+ functionName: "name"
3487
+ }),
3488
+ client.readContract({
3489
+ abi: relayAbi,
3490
+ address: relay.relay,
3491
+ functionName: "mTokenId"
3492
+ }),
3493
+ client.readContract({
3494
+ abi: relayAbi,
3495
+ address: relay.relay,
3496
+ functionName: "token"
3497
+ }),
3498
+ client.readContract({
3499
+ abi: relayAbi,
3500
+ address: relay.relay,
3501
+ functionName: "keeperLastRun"
3502
+ })
3503
+ ]);
3504
+ const tokenAddress = checksumAddress5(relayTokenAddress);
3505
+ const [symbol, decimals, relayTokenBalance, managedVotingPower] = await Promise.all([
3506
+ client.readContract({
3507
+ abi: erc20Abi,
3508
+ address: tokenAddress,
3509
+ functionName: "symbol"
3510
+ }),
3511
+ client.readContract({
3512
+ abi: erc20Abi,
3513
+ address: tokenAddress,
3514
+ functionName: "decimals"
3515
+ }),
3516
+ client.readContract({
3517
+ abi: erc20Abi,
3518
+ address: tokenAddress,
3519
+ functionName: "balanceOf",
3520
+ args: [relay.relay]
3521
+ }),
3522
+ client.readContract({
3523
+ abi: votingEscrowLiteAbi,
3524
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
3525
+ functionName: "balanceOfNFT",
3526
+ args: [managedTokenId]
3527
+ })
3528
+ ]);
3529
+ const keeperTs = asNum(keeperLastRun);
3530
+ const now = Math.floor(Date.now() / 1e3);
3531
+ return {
3532
+ label: relay.label,
3533
+ relay: toChecksum(relay.relay),
3534
+ name,
3535
+ factoryType: relay.factoryType,
3536
+ managedTokenId: managedTokenId.toString(),
3537
+ managedVotingPower: managedVotingPower.toString(),
3538
+ relayToken: {
3539
+ address: toChecksum(tokenAddress),
3540
+ symbol,
3541
+ decimals
3542
+ },
3543
+ relayTokenBalance: relayTokenBalance.toString(),
3544
+ keeperLastRun: keeperTs,
3545
+ keeperLastRunRelative: relTime(keeperLastRun),
3546
+ secondsSinceKeeperRun: Math.max(0, now - keeperTs)
3547
+ };
3548
+ }
3549
+ async function readVaultSummary(client) {
3550
+ const relays = await Promise.all(KNOWN_RELAYS.map((relay) => readRelaySnapshot(client, relay)));
3551
+ const tokenTotals = /* @__PURE__ */ new Map();
3552
+ let managedVotingPowerTotal = 0n;
3553
+ for (const relay of relays) {
3554
+ managedVotingPowerTotal += BigInt(relay.managedVotingPower);
3555
+ const key = relay.relayToken.address.toLowerCase();
3556
+ const prev = tokenTotals.get(key);
3557
+ const balance = BigInt(relay.relayTokenBalance);
3558
+ if (prev) {
3559
+ prev.balance += balance;
3560
+ continue;
3561
+ }
3562
+ tokenTotals.set(key, {
3563
+ token: relay.relayToken.address,
3564
+ symbol: relay.relayToken.symbol,
3565
+ decimals: relay.relayToken.decimals,
3566
+ balance
3567
+ });
3568
+ }
3569
+ const relayTokenBalances = [...tokenTotals.values()].map((row) => ({
3570
+ token: row.token,
3571
+ symbol: row.symbol,
3572
+ decimals: row.decimals,
3573
+ balance: row.balance.toString()
3574
+ }));
3575
+ return {
3576
+ relayCount: relays.length,
3577
+ relays,
3578
+ totals: {
3579
+ managedVotingPower: managedVotingPowerTotal.toString(),
3580
+ relayTokenBalances
3581
+ }
3582
+ };
3583
+ }
3584
+ var vaults = Cli5.create("vaults", {
3585
+ description: "Inspect Aborean relay vaults (auto-compounder / auto-converter)."
3586
+ });
3587
+ vaults.command("list", {
3588
+ description: "List known Aborean relay vaults with keeper and veNFT state.",
3589
+ env: env5,
3590
+ output: z5.object({
3591
+ relayCount: z5.number(),
3592
+ relays: z5.array(relayRowSchema),
3593
+ totals: z5.object({
3594
+ managedVotingPower: z5.string(),
3595
+ relayTokenBalances: z5.array(
3596
+ z5.object({
3597
+ token: z5.string(),
3598
+ symbol: z5.string(),
3599
+ decimals: z5.number(),
3600
+ balance: z5.string()
3601
+ })
3602
+ )
3603
+ })
3604
+ }),
3605
+ examples: [{ description: "List all known vault relays on Abstract" }],
3606
+ async run(c) {
3607
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3608
+ const snapshot = await readVaultSummary(client);
3609
+ const firstRelay = snapshot.relays[0];
3610
+ return c.ok(
3611
+ snapshot,
3612
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3613
+ cta: {
3614
+ description: "Related commands:",
3615
+ commands: [
3616
+ ...firstRelay ? [
3617
+ {
3618
+ command: "vaults relay",
3619
+ args: { relay: firstRelay.relay },
3620
+ description: `Inspect ${firstRelay.label}`
3621
+ }
3622
+ ] : [],
3623
+ {
3624
+ command: "lending markets",
3625
+ description: "View Morpho lending markets"
3626
+ },
3627
+ {
3628
+ command: "ve stats",
3629
+ description: "View veABX global stats"
3630
+ }
3631
+ ]
3632
+ }
3633
+ }
3634
+ );
3635
+ }
3636
+ });
3637
+ vaults.command("relay", {
3638
+ description: "Inspect one relay vault by address.",
3639
+ args: z5.object({
3640
+ relay: z5.string().describe("Relay vault contract address")
3641
+ }),
3642
+ env: env5,
3643
+ output: relayRowSchema,
3644
+ examples: [
3645
+ {
3646
+ args: { relay: ABOREAN_VAULT_ADDRESSES.veAbxMaxiRelay },
3647
+ description: "Inspect the veABX maxi relay"
3648
+ }
3649
+ ],
3650
+ async run(c) {
3651
+ if (!isAddress4(c.args.relay)) {
3652
+ return c.error({
3653
+ code: "INVALID_ARGUMENT",
3654
+ message: "relay must be a valid address"
3655
+ });
3656
+ }
3657
+ const relayAddress = checksumAddress5(c.args.relay);
3658
+ const known = KNOWN_RELAYS.find(
3659
+ (relay) => relay.relay.toLowerCase() === relayAddress.toLowerCase()
3660
+ );
3661
+ if (!known) {
3662
+ return c.error({
3663
+ code: "NOT_FOUND",
3664
+ message: `relay ${shortAddress4(relayAddress)} is not in the known Aborean vault set`
3665
+ });
3666
+ }
3667
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3668
+ const snapshot = await readRelaySnapshot(client, known);
3669
+ return c.ok(
3670
+ snapshot,
3671
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3672
+ cta: {
3673
+ description: "Related commands:",
3674
+ commands: [
3675
+ {
3676
+ command: "vaults list",
3677
+ description: "List all relay vaults"
3678
+ },
3679
+ {
3680
+ command: "ve lock",
3681
+ args: { tokenId: Number(snapshot.managedTokenId) },
3682
+ description: `Inspect managed veNFT #${snapshot.managedTokenId}`
3683
+ }
3684
+ ]
3685
+ }
3686
+ }
3687
+ );
3688
+ }
3689
+ });
3690
+
3691
+ // src/commands/ve.ts
3692
+ import { Cli as Cli6, z as z6 } from "incur";
3693
+ var env6 = z6.object({
3694
+ ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
3695
+ });
3696
+ var ve = Cli6.create("ve", {
3697
+ description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
3698
+ });
3699
+ ve.command("stats", {
3700
+ description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
3701
+ env: env6,
3702
+ output: z6.object({
3703
+ token: z6.string(),
3704
+ totalVotingPower: z6.string(),
3705
+ totalLocked: z6.string(),
3706
+ permanentLocked: z6.string(),
3707
+ epoch: z6.number(),
3708
+ decayBias: z6.string(),
3709
+ decaySlope: z6.string(),
3710
+ lastCheckpointTimestamp: z6.number(),
3711
+ lastCheckpointBlock: z6.number()
3712
+ }),
3713
+ examples: [{ description: "Show global veABX state and decay metrics" }],
3714
+ async run(c) {
3715
+ const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
3716
+ const [token, totalVotingPower, totalLocked, permanentLocked, epoch] = await Promise.all([
3717
+ client.readContract({
3718
+ abi: votingEscrowAbi,
3719
+ address: ABOREAN_V2_ADDRESSES.votingEscrow,
3720
+ functionName: "token"
3721
+ }),
3722
+ client.readContract({
3723
+ abi: votingEscrowAbi,
1916
3724
  address: ABOREAN_V2_ADDRESSES.votingEscrow,
1917
3725
  functionName: "totalSupply"
1918
3726
  }),
@@ -1938,32 +3746,50 @@ ve.command("stats", {
1938
3746
  functionName: "pointHistory",
1939
3747
  args: [epoch]
1940
3748
  });
1941
- return c.ok({
1942
- token: toChecksum(token),
1943
- totalVotingPower: totalVotingPower.toString(),
1944
- totalLocked: totalLocked.toString(),
1945
- permanentLocked: permanentLocked.toString(),
1946
- epoch: asNum(epoch),
1947
- decayBias: point.bias.toString(),
1948
- decaySlope: point.slope.toString(),
1949
- lastCheckpointTimestamp: asNum(point.ts),
1950
- lastCheckpointBlock: asNum(point.blk)
1951
- });
3749
+ return c.ok(
3750
+ {
3751
+ token: toChecksum(token),
3752
+ totalVotingPower: totalVotingPower.toString(),
3753
+ totalLocked: totalLocked.toString(),
3754
+ permanentLocked: permanentLocked.toString(),
3755
+ epoch: asNum(epoch),
3756
+ decayBias: point.bias.toString(),
3757
+ decaySlope: point.slope.toString(),
3758
+ lastCheckpointTimestamp: asNum(point.ts),
3759
+ lastCheckpointBlock: asNum(point.blk)
3760
+ },
3761
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3762
+ cta: {
3763
+ description: "Explore veABX:",
3764
+ commands: [
3765
+ {
3766
+ command: "ve locks",
3767
+ args: { address: "<owner>" },
3768
+ description: "List veNFT locks for an address"
3769
+ },
3770
+ {
3771
+ command: "voter epoch",
3772
+ description: "View current emissions epoch timing"
3773
+ }
3774
+ ]
3775
+ }
3776
+ }
3777
+ );
1952
3778
  }
1953
3779
  });
1954
3780
  ve.command("lock", {
1955
3781
  description: "Get lock details and voting power for one veNFT token id.",
1956
- args: z3.object({
1957
- tokenId: z3.coerce.number().int().nonnegative().describe("veNFT token id")
3782
+ args: z6.object({
3783
+ tokenId: z6.coerce.number().int().nonnegative().describe("veNFT token id")
1958
3784
  }),
1959
- env: env3,
1960
- output: z3.object({
1961
- tokenId: z3.number(),
1962
- owner: z3.string(),
1963
- amount: z3.string(),
1964
- unlockTime: z3.number(),
1965
- isPermanent: z3.boolean(),
1966
- votingPower: z3.string()
3785
+ env: env6,
3786
+ output: z6.object({
3787
+ tokenId: z6.number(),
3788
+ owner: z6.string(),
3789
+ amount: z6.string(),
3790
+ unlockTime: z6.number(),
3791
+ isPermanent: z6.boolean(),
3792
+ votingPower: z6.string()
1967
3793
  }),
1968
3794
  examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
1969
3795
  async run(c) {
@@ -1989,34 +3815,53 @@ ve.command("lock", {
1989
3815
  args: [tokenId]
1990
3816
  })
1991
3817
  ]);
1992
- return c.ok({
1993
- tokenId: c.args.tokenId,
1994
- owner: toChecksum(owner),
1995
- amount: locked.amount.toString(),
1996
- unlockTime: asNum(locked.end),
1997
- isPermanent: locked.isPermanent,
1998
- votingPower: votingPower.toString()
1999
- });
3818
+ return c.ok(
3819
+ {
3820
+ tokenId: c.args.tokenId,
3821
+ owner: toChecksum(owner),
3822
+ amount: locked.amount.toString(),
3823
+ unlockTime: asNum(locked.end),
3824
+ isPermanent: locked.isPermanent,
3825
+ votingPower: votingPower.toString()
3826
+ },
3827
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3828
+ cta: {
3829
+ description: "Related commands:",
3830
+ commands: [
3831
+ {
3832
+ command: "ve voting-power",
3833
+ args: { tokenId: c.args.tokenId },
3834
+ description: "Check current voting power"
3835
+ },
3836
+ {
3837
+ command: "voter rewards",
3838
+ args: { tokenId: c.args.tokenId },
3839
+ description: "Check claimable rewards for this veNFT"
3840
+ }
3841
+ ]
3842
+ }
3843
+ }
3844
+ );
2000
3845
  }
2001
3846
  });
2002
3847
  ve.command("locks", {
2003
3848
  description: "List all veNFT locks owned by an address.",
2004
- args: z3.object({
2005
- address: z3.string().describe("Owner address")
3849
+ args: z6.object({
3850
+ address: z6.string().describe("Owner address")
2006
3851
  }),
2007
- env: env3,
2008
- output: z3.object({
2009
- address: z3.string(),
2010
- locks: z3.array(
2011
- z3.object({
2012
- tokenId: z3.string(),
2013
- amount: z3.string(),
2014
- unlockTime: z3.number(),
2015
- isPermanent: z3.boolean(),
2016
- votingPower: z3.string()
3852
+ env: env6,
3853
+ output: z6.object({
3854
+ address: z6.string(),
3855
+ locks: z6.array(
3856
+ z6.object({
3857
+ tokenId: z6.string(),
3858
+ amount: z6.string(),
3859
+ unlockTime: z6.number(),
3860
+ isPermanent: z6.boolean(),
3861
+ votingPower: z6.string()
2017
3862
  })
2018
3863
  ),
2019
- count: z3.number()
3864
+ count: z6.number()
2020
3865
  }),
2021
3866
  examples: [
2022
3867
  {
@@ -2079,22 +3924,42 @@ ve.command("locks", {
2079
3924
  votingPower: votingPower.toString()
2080
3925
  };
2081
3926
  });
2082
- return c.ok({
2083
- address: toChecksum(c.args.address),
2084
- locks,
2085
- count: locks.length
2086
- });
3927
+ const firstLock = locks[0];
3928
+ return c.ok(
3929
+ {
3930
+ address: toChecksum(c.args.address),
3931
+ locks,
3932
+ count: locks.length
3933
+ },
3934
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3935
+ cta: {
3936
+ description: "Explore locks:",
3937
+ commands: firstLock ? [
3938
+ {
3939
+ command: "ve lock",
3940
+ args: { tokenId: Number(firstLock.tokenId) },
3941
+ description: `Inspect veNFT #${firstLock.tokenId}`
3942
+ },
3943
+ {
3944
+ command: "voter rewards",
3945
+ args: { tokenId: Number(firstLock.tokenId) },
3946
+ description: `Check rewards for veNFT #${firstLock.tokenId}`
3947
+ }
3948
+ ] : []
3949
+ }
3950
+ }
3951
+ );
2087
3952
  }
2088
3953
  });
2089
3954
  ve.command("voting-power", {
2090
3955
  description: "Get current voting power for one veNFT token id.",
2091
- args: z3.object({
2092
- tokenId: z3.coerce.number().int().nonnegative().describe("veNFT token id")
3956
+ args: z6.object({
3957
+ tokenId: z6.coerce.number().int().nonnegative().describe("veNFT token id")
2093
3958
  }),
2094
- env: env3,
2095
- output: z3.object({
2096
- tokenId: z3.number(),
2097
- votingPower: z3.string()
3959
+ env: env6,
3960
+ output: z6.object({
3961
+ tokenId: z6.number(),
3962
+ votingPower: z6.string()
2098
3963
  }),
2099
3964
  examples: [{ args: { tokenId: 1 }, description: "Get current voting power for veNFT #1" }],
2100
3965
  async run(c) {
@@ -2105,17 +3970,36 @@ ve.command("voting-power", {
2105
3970
  functionName: "balanceOfNFT",
2106
3971
  args: [BigInt(c.args.tokenId)]
2107
3972
  });
2108
- return c.ok({
2109
- tokenId: c.args.tokenId,
2110
- votingPower: votingPower.toString()
2111
- });
3973
+ return c.ok(
3974
+ {
3975
+ tokenId: c.args.tokenId,
3976
+ votingPower: votingPower.toString()
3977
+ },
3978
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
3979
+ cta: {
3980
+ description: "Related commands:",
3981
+ commands: [
3982
+ {
3983
+ command: "ve lock",
3984
+ args: { tokenId: c.args.tokenId },
3985
+ description: "View full lock details"
3986
+ },
3987
+ {
3988
+ command: "voter rewards",
3989
+ args: { tokenId: c.args.tokenId },
3990
+ description: "Check claimable rewards"
3991
+ }
3992
+ ]
3993
+ }
3994
+ }
3995
+ );
2112
3996
  }
2113
3997
  });
2114
3998
 
2115
3999
  // src/commands/voter.ts
2116
- import { Cli as Cli4, z as z4 } from "incur";
2117
- var env4 = z4.object({
2118
- ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
4000
+ import { Cli as Cli7, z as z7 } from "incur";
4001
+ var env7 = z7.object({
4002
+ ABSTRACT_RPC_URL: z7.string().optional().describe("Abstract RPC URL override")
2119
4003
  });
2120
4004
  async function discoverPools(client) {
2121
4005
  const [v2PoolCount, clPoolCount] = await Promise.all([
@@ -2154,20 +4038,20 @@ async function discoverPools(client) {
2154
4038
  ]);
2155
4039
  return [...v2Pools, ...clPools];
2156
4040
  }
2157
- var voter = Cli4.create("voter", {
4041
+ var voter = Cli7.create("voter", {
2158
4042
  description: "Inspect Aborean voter epoch, pool weights, and claimable rewards context."
2159
4043
  });
2160
4044
  voter.command("epoch", {
2161
4045
  description: "Show current emissions epoch timing from Minter.",
2162
- env: env4,
2163
- output: z4.object({
2164
- activePeriod: z4.number(),
2165
- epochEnd: z4.number(),
2166
- secondsRemaining: z4.number(),
2167
- timeRemaining: z4.string(),
2168
- weekSeconds: z4.number(),
2169
- epochCount: z4.number(),
2170
- weeklyEmission: z4.string()
4046
+ env: env7,
4047
+ output: z7.object({
4048
+ activePeriod: z7.number(),
4049
+ epochEnd: z7.number(),
4050
+ secondsRemaining: z7.number(),
4051
+ timeRemaining: z7.string(),
4052
+ weekSeconds: z7.number(),
4053
+ epochCount: z7.number(),
4054
+ weeklyEmission: z7.string()
2171
4055
  }),
2172
4056
  examples: [{ description: "Inspect current voter epoch boundaries" }],
2173
4057
  async run(c) {
@@ -2196,36 +4080,53 @@ voter.command("epoch", {
2196
4080
  ]);
2197
4081
  const now = Math.floor(Date.now() / 1e3);
2198
4082
  const epochEnd = asNum(activePeriod + weekSeconds);
2199
- return c.ok({
2200
- activePeriod: asNum(activePeriod),
2201
- epochEnd,
2202
- secondsRemaining: clampPositive(epochEnd - now),
2203
- timeRemaining: relTime(activePeriod + weekSeconds),
2204
- weekSeconds: asNum(weekSeconds),
2205
- epochCount: asNum(epochCount),
2206
- weeklyEmission: weeklyEmission.toString()
2207
- });
4083
+ return c.ok(
4084
+ {
4085
+ activePeriod: asNum(activePeriod),
4086
+ epochEnd,
4087
+ secondsRemaining: clampPositive(epochEnd - now),
4088
+ timeRemaining: relTime(activePeriod + weekSeconds),
4089
+ weekSeconds: asNum(weekSeconds),
4090
+ epochCount: asNum(epochCount),
4091
+ weeklyEmission: weeklyEmission.toString()
4092
+ },
4093
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
4094
+ cta: {
4095
+ description: "Related commands:",
4096
+ commands: [
4097
+ {
4098
+ command: "voter weights",
4099
+ description: "View pool voting weight distribution"
4100
+ },
4101
+ {
4102
+ command: "gauges list",
4103
+ description: "List active gauges"
4104
+ }
4105
+ ]
4106
+ }
4107
+ }
4108
+ );
2208
4109
  }
2209
4110
  });
2210
4111
  voter.command("weights", {
2211
4112
  description: "Show current pool voting weight distribution.",
2212
- env: env4,
2213
- output: z4.object({
2214
- totalWeight: z4.string(),
2215
- pools: z4.array(
2216
- z4.object({
2217
- pool: z4.string(),
2218
- gauge: z4.string(),
2219
- weight: z4.string()
4113
+ env: env7,
4114
+ output: z7.object({
4115
+ totalWeight: z7.string(),
4116
+ pools: z7.array(
4117
+ z7.object({
4118
+ pool: z7.string(),
4119
+ gauge: z7.string(),
4120
+ weight: z7.string()
2220
4121
  })
2221
4122
  ),
2222
- count: z4.number()
4123
+ count: z7.number()
2223
4124
  }),
2224
4125
  examples: [{ description: "List all pools with non-zero voting weight" }],
2225
4126
  async run(c) {
2226
4127
  const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
2227
- const pools = await discoverPools(client);
2228
- if (!pools.length) {
4128
+ const pools2 = await discoverPools(client);
4129
+ if (!pools2.length) {
2229
4130
  return c.ok({ totalWeight: "0", pools: [], count: 0 });
2230
4131
  }
2231
4132
  const [totalWeight, poolData] = await Promise.all([
@@ -2236,7 +4137,7 @@ voter.command("weights", {
2236
4137
  }),
2237
4138
  client.multicall({
2238
4139
  allowFailure: false,
2239
- contracts: pools.flatMap((pool) => [
4140
+ contracts: pools2.flatMap((pool) => [
2240
4141
  {
2241
4142
  abi: voterAbi,
2242
4143
  address: ABOREAN_V2_ADDRESSES.voter,
@@ -2252,7 +4153,7 @@ voter.command("weights", {
2252
4153
  ])
2253
4154
  })
2254
4155
  ]);
2255
- const entries = pools.map((pool, index) => {
4156
+ const entries = pools2.map((pool, index) => {
2256
4157
  const offset = index * 2;
2257
4158
  const gauge = poolData[offset] ?? ZERO_ADDRESS;
2258
4159
  const weight = poolData[offset + 1] ?? 0n;
@@ -2268,28 +4169,49 @@ voter.command("weights", {
2268
4169
  gauge: toChecksum(entry.gauge),
2269
4170
  weight: entry.weight.toString()
2270
4171
  }));
2271
- return c.ok({
2272
- totalWeight: totalWeight.toString(),
2273
- pools: entries,
2274
- count: entries.length
2275
- });
4172
+ const firstEntry = entries[0];
4173
+ return c.ok(
4174
+ {
4175
+ totalWeight: totalWeight.toString(),
4176
+ pools: entries,
4177
+ count: entries.length
4178
+ },
4179
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
4180
+ cta: {
4181
+ description: "Related commands:",
4182
+ commands: [
4183
+ {
4184
+ command: "voter epoch",
4185
+ description: "View current epoch timing"
4186
+ },
4187
+ ...firstEntry ? [
4188
+ {
4189
+ command: "voter bribes",
4190
+ args: { pool: firstEntry.pool },
4191
+ description: "View bribe rewards for top-weighted pool"
4192
+ }
4193
+ ] : []
4194
+ ]
4195
+ }
4196
+ }
4197
+ );
2276
4198
  }
2277
4199
  });
2278
4200
  voter.command("rewards", {
2279
4201
  description: "Show claimable rebase rewards and voting context for a veNFT.",
2280
- args: z4.object({
2281
- tokenId: z4.coerce.number().int().nonnegative().describe("veNFT token id")
4202
+ args: z7.object({
4203
+ tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
2282
4204
  }),
2283
- env: env4,
2284
- output: z4.object({
2285
- tokenId: z4.number(),
2286
- rewardToken: z4.string(),
2287
- claimableRebase: z4.string(),
2288
- timeCursor: z4.number(),
2289
- lastTokenTime: z4.number(),
2290
- distributorStartTime: z4.number(),
2291
- usedWeight: z4.string(),
2292
- lastVoted: z4.number()
4205
+ env: env7,
4206
+ output: z7.object({
4207
+ tokenId: z7.number(),
4208
+ rewardToken: z7.string(),
4209
+ claimableRebase: z7.string(),
4210
+ timeCursor: z7.number(),
4211
+ lastTokenTime: z7.number(),
4212
+ distributorStartTime: z7.number(),
4213
+ usedWeight: z7.string(),
4214
+ lastVoted: z7.number()
2293
4215
  }),
2294
4216
  examples: [{ args: { tokenId: 1 }, description: "Check claimable voter/distributor rewards" }],
2295
4217
  async run(c) {
@@ -2344,36 +4266,54 @@ voter.command("rewards", {
2344
4266
  args: [tokenId]
2345
4267
  })
2346
4268
  ]);
2347
- return c.ok({
2348
- tokenId: c.args.tokenId,
2349
- rewardToken: toChecksum(rewardToken),
2350
- claimableRebase: claimableRebase.toString(),
2351
- timeCursor: asNum(timeCursor),
2352
- lastTokenTime: asNum(lastTokenTime),
2353
- distributorStartTime: asNum(distributorStartTime),
2354
- usedWeight: usedWeight.toString(),
2355
- lastVoted: asNum(lastVoted)
2356
- });
4269
+ return c.ok(
4270
+ {
4271
+ tokenId: c.args.tokenId,
4272
+ rewardToken: toChecksum(rewardToken),
4273
+ claimableRebase: claimableRebase.toString(),
4274
+ timeCursor: asNum(timeCursor),
4275
+ lastTokenTime: asNum(lastTokenTime),
4276
+ distributorStartTime: asNum(distributorStartTime),
4277
+ usedWeight: usedWeight.toString(),
4278
+ lastVoted: asNum(lastVoted)
4279
+ },
4280
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
4281
+ cta: {
4282
+ description: "Related commands:",
4283
+ commands: [
4284
+ {
4285
+ command: "ve lock",
4286
+ args: { tokenId: c.args.tokenId },
4287
+ description: "View lock details for this veNFT"
4288
+ },
4289
+ {
4290
+ command: "voter weights",
4291
+ description: "Check pool voting weight distribution"
4292
+ }
4293
+ ]
4294
+ }
4295
+ }
4296
+ );
2357
4297
  }
2358
4298
  });
2359
4299
  voter.command("bribes", {
2360
4300
  description: "Show active bribe reward tokens and current-epoch amounts for a pool.",
2361
- args: z4.object({
2362
- pool: z4.string().describe("Pool address")
4301
+ args: z7.object({
4302
+ pool: z7.string().describe("Pool address")
2363
4303
  }),
2364
- env: env4,
2365
- output: z4.object({
2366
- pool: z4.string(),
2367
- gauge: z4.string(),
2368
- bribeContract: z4.string(),
2369
- epochStart: z4.number(),
2370
- rewardTokens: z4.array(
2371
- z4.object({
2372
- token: z4.string(),
2373
- epochAmount: z4.string()
4304
+ env: env7,
4305
+ output: z7.object({
4306
+ pool: z7.string(),
4307
+ gauge: z7.string(),
4308
+ bribeContract: z7.string(),
4309
+ epochStart: z7.number(),
4310
+ rewardTokens: z7.array(
4311
+ z7.object({
4312
+ token: z7.string(),
4313
+ epochAmount: z7.string()
2374
4314
  })
2375
4315
  ),
2376
- count: z4.number()
4316
+ count: z7.number()
2377
4317
  }),
2378
4318
  examples: [
2379
4319
  {
@@ -2458,14 +4398,32 @@ voter.command("bribes", {
2458
4398
  token: toChecksum(token),
2459
4399
  epochAmount: epochAmounts[index].toString()
2460
4400
  }));
2461
- return c.ok({
2462
- pool: toChecksum(c.args.pool),
2463
- gauge: toChecksum(gauge),
2464
- bribeContract: toChecksum(bribeContract),
2465
- epochStart: asNum(epochStart),
2466
- rewardTokens: items,
2467
- count: items.length
2468
- });
4401
+ return c.ok(
4402
+ {
4403
+ pool: toChecksum(c.args.pool),
4404
+ gauge: toChecksum(gauge),
4405
+ bribeContract: toChecksum(bribeContract),
4406
+ epochStart: asNum(epochStart),
4407
+ rewardTokens: items,
4408
+ count: items.length
4409
+ },
4410
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
4411
+ cta: {
4412
+ description: "Related commands:",
4413
+ commands: [
4414
+ {
4415
+ command: "gauges info",
4416
+ args: { gauge: toChecksum(gauge) },
4417
+ description: "Inspect gauge details"
4418
+ },
4419
+ {
4420
+ command: "voter epoch",
4421
+ description: "View current epoch timing"
4422
+ }
4423
+ ]
4424
+ }
4425
+ }
4426
+ );
2469
4427
  }
2470
4428
  });
2471
4429
 
@@ -2599,27 +4557,283 @@ function applyFriendlyErrorHandling(cli2) {
2599
4557
  // src/cli.ts
2600
4558
  var __dirname = dirname(fileURLToPath(import.meta.url));
2601
4559
  var pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
2602
- var cli = Cli5.create("aborean", {
4560
+ var cli = Cli8.create("aborean", {
2603
4561
  version: pkg.version,
2604
4562
  description: "Aborean Finance DEX CLI for Abstract chain."
2605
4563
  });
2606
4564
  cli.command(gauges);
4565
+ cli.command(pools);
2607
4566
  cli.command(ve);
2608
4567
  cli.command(voter);
2609
- var rootEnv = z5.object({
2610
- ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
2611
- });
2612
4568
  cli.command(cl);
4569
+ cli.command(vaults);
4570
+ cli.command(lending);
4571
+ var rootEnv = z8.object({
4572
+ ABSTRACT_RPC_URL: z8.string().optional().describe("Abstract RPC URL override")
4573
+ });
4574
+ var erc20MetadataAbi4 = [
4575
+ {
4576
+ type: "function",
4577
+ name: "symbol",
4578
+ stateMutability: "view",
4579
+ inputs: [],
4580
+ outputs: [{ type: "string" }]
4581
+ },
4582
+ {
4583
+ type: "function",
4584
+ name: "decimals",
4585
+ stateMutability: "view",
4586
+ inputs: [],
4587
+ outputs: [{ type: "uint8" }]
4588
+ }
4589
+ ];
4590
+ var v2PoolLiteAbi = [
4591
+ {
4592
+ type: "function",
4593
+ name: "token0",
4594
+ stateMutability: "view",
4595
+ inputs: [],
4596
+ outputs: [{ type: "address" }]
4597
+ },
4598
+ {
4599
+ type: "function",
4600
+ name: "token1",
4601
+ stateMutability: "view",
4602
+ inputs: [],
4603
+ outputs: [{ type: "address" }]
4604
+ },
4605
+ {
4606
+ type: "function",
4607
+ name: "stable",
4608
+ stateMutability: "view",
4609
+ inputs: [],
4610
+ outputs: [{ type: "bool" }]
4611
+ },
4612
+ {
4613
+ type: "function",
4614
+ name: "getReserves",
4615
+ stateMutability: "view",
4616
+ inputs: [],
4617
+ outputs: [
4618
+ { type: "uint256", name: "reserve0" },
4619
+ { type: "uint256", name: "reserve1" },
4620
+ { type: "uint256", name: "blockTimestampLast" }
4621
+ ]
4622
+ }
4623
+ ];
4624
+ function finiteOrZero(value) {
4625
+ return Number.isFinite(value) ? value : 0;
4626
+ }
4627
+ function shortAddress5(address) {
4628
+ return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
4629
+ }
4630
+ function normalizeReserveTuple(value) {
4631
+ if (Array.isArray(value)) {
4632
+ return {
4633
+ reserve0: BigInt(value[0]),
4634
+ reserve1: BigInt(value[1])
4635
+ };
4636
+ }
4637
+ const row = value;
4638
+ return {
4639
+ reserve0: BigInt(row.reserve0),
4640
+ reserve1: BigInt(row.reserve1)
4641
+ };
4642
+ }
4643
+ async function readTokenMetadata4(client, tokenAddresses) {
4644
+ const unique = [...new Set(tokenAddresses.map((address) => address.toLowerCase()))];
4645
+ if (!unique.length) {
4646
+ return /* @__PURE__ */ new Map();
4647
+ }
4648
+ const contracts = unique.flatMap((address) => [
4649
+ {
4650
+ abi: erc20MetadataAbi4,
4651
+ address,
4652
+ functionName: "symbol"
4653
+ },
4654
+ {
4655
+ abi: erc20MetadataAbi4,
4656
+ address,
4657
+ functionName: "decimals"
4658
+ }
4659
+ ]);
4660
+ const results = await client.multicall({
4661
+ allowFailure: true,
4662
+ contracts
4663
+ });
4664
+ const map = /* @__PURE__ */ new Map();
4665
+ for (let i = 0; i < unique.length; i += 1) {
4666
+ const address = checksumAddress6(unique[i]);
4667
+ const symbolResult = results[i * 2];
4668
+ const decimalsResult = results[i * 2 + 1];
4669
+ const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : shortAddress5(address);
4670
+ const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : 18;
4671
+ map.set(address.toLowerCase(), {
4672
+ address,
4673
+ symbol,
4674
+ decimals
4675
+ });
4676
+ }
4677
+ return map;
4678
+ }
4679
+ async function readTopV2PoolsSnapshot(client, limit) {
4680
+ const v2PoolCount = await client.readContract({
4681
+ abi: poolFactoryAbi,
4682
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
4683
+ functionName: "allPoolsLength"
4684
+ });
4685
+ if (v2PoolCount === 0n) {
4686
+ return { topPools: [], reserveUnitTvl: 0 };
4687
+ }
4688
+ const indices = Array.from({ length: Number(v2PoolCount) }, (_, i) => BigInt(i));
4689
+ const pools2 = await client.multicall({
4690
+ allowFailure: false,
4691
+ contracts: indices.map((index) => ({
4692
+ abi: poolFactoryAbi,
4693
+ address: ABOREAN_V2_ADDRESSES.poolFactory,
4694
+ functionName: "allPools",
4695
+ args: [index]
4696
+ }))
4697
+ });
4698
+ const poolData = await client.multicall({
4699
+ allowFailure: false,
4700
+ contracts: pools2.flatMap((pool) => [
4701
+ {
4702
+ abi: v2PoolLiteAbi,
4703
+ address: pool,
4704
+ functionName: "token0"
4705
+ },
4706
+ {
4707
+ abi: v2PoolLiteAbi,
4708
+ address: pool,
4709
+ functionName: "token1"
4710
+ },
4711
+ {
4712
+ abi: v2PoolLiteAbi,
4713
+ address: pool,
4714
+ functionName: "stable"
4715
+ },
4716
+ {
4717
+ abi: v2PoolLiteAbi,
4718
+ address: pool,
4719
+ functionName: "getReserves"
4720
+ }
4721
+ ])
4722
+ });
4723
+ const tokenAddresses = [];
4724
+ for (let i = 0; i < pools2.length; i += 1) {
4725
+ tokenAddresses.push(checksumAddress6(poolData[i * 4]));
4726
+ tokenAddresses.push(checksumAddress6(poolData[i * 4 + 1]));
4727
+ }
4728
+ const tokenMeta = await readTokenMetadata4(client, tokenAddresses);
4729
+ const rows = pools2.map((pool, index) => {
4730
+ const token0Address = checksumAddress6(poolData[index * 4]);
4731
+ const token1Address = checksumAddress6(poolData[index * 4 + 1]);
4732
+ const stable = Boolean(poolData[index * 4 + 2]);
4733
+ const reserves = normalizeReserveTuple(poolData[index * 4 + 3]);
4734
+ const token0 = tokenMeta.get(token0Address.toLowerCase()) ?? {
4735
+ address: token0Address,
4736
+ symbol: shortAddress5(token0Address),
4737
+ decimals: 18
4738
+ };
4739
+ const token1 = tokenMeta.get(token1Address.toLowerCase()) ?? {
4740
+ address: token1Address,
4741
+ symbol: shortAddress5(token1Address),
4742
+ decimals: 18
4743
+ };
4744
+ const reserve0Decimal = finiteOrZero(Number(formatUnits4(reserves.reserve0, token0.decimals)));
4745
+ const reserve1Decimal = finiteOrZero(Number(formatUnits4(reserves.reserve1, token1.decimals)));
4746
+ const tvlUnits = reserve0Decimal + reserve1Decimal;
4747
+ return {
4748
+ pool: checksumAddress6(pool),
4749
+ pair: `${token0.symbol}/${token1.symbol}`,
4750
+ poolType: stable ? "stable" : "volatile",
4751
+ token0: {
4752
+ address: checksumAddress6(token0.address),
4753
+ symbol: token0.symbol,
4754
+ decimals: token0.decimals
4755
+ },
4756
+ token1: {
4757
+ address: checksumAddress6(token1.address),
4758
+ symbol: token1.symbol,
4759
+ decimals: token1.decimals
4760
+ },
4761
+ reserves: {
4762
+ token0: formatUnits4(reserves.reserve0, token0.decimals),
4763
+ token1: formatUnits4(reserves.reserve1, token1.decimals)
4764
+ },
4765
+ tvlEstimateUnits: tvlUnits
4766
+ };
4767
+ });
4768
+ const reserveUnitTvl = rows.reduce((sum, row) => sum + Number(row.tvlEstimateUnits), 0);
4769
+ return {
4770
+ topPools: rows.sort((a, b) => Number(b.tvlEstimateUnits) - Number(a.tvlEstimateUnits)).slice(0, limit),
4771
+ reserveUnitTvl
4772
+ };
4773
+ }
2613
4774
  cli.command("status", {
2614
- description: "Get a cross-contract Aborean protocol snapshot (pool counts, gauge count, veABX supply).",
4775
+ description: "Cross-protocol Aborean snapshot (TVL estimates, epoch, top pools, ve lock, vaults, Morpho lending).",
2615
4776
  env: rootEnv,
2616
- output: z5.object({
2617
- v2PoolCount: z5.number().describe("Number of V2 AMM pools"),
2618
- clPoolCount: z5.number().describe("Number of Slipstream (CL) pools"),
2619
- gaugeCount: z5.number().describe("Number of pools with gauges"),
2620
- totalVotingWeight: z5.string().describe("Total voting weight (wei)"),
2621
- veABXTotalSupply: z5.string().describe("Total veABX supply (wei)"),
2622
- veABXLockedSupply: z5.string().describe("Total ABX locked in VotingEscrow (wei)")
4777
+ output: z8.object({
4778
+ v2PoolCount: z8.number().describe("Number of V2 AMM pools"),
4779
+ clPoolCount: z8.number().describe("Number of Slipstream (CL) pools"),
4780
+ gaugeCount: z8.number().describe("Number of pools with gauges"),
4781
+ totalVotingWeight: z8.string().describe("Total voting weight (wei)"),
4782
+ veABXTotalSupply: z8.string().describe("Total veABX supply (wei)"),
4783
+ veABXLockedSupply: z8.string().describe("Total ABX locked in VotingEscrow (wei)"),
4784
+ epoch: z8.object({
4785
+ activePeriod: z8.number(),
4786
+ epochEnd: z8.number(),
4787
+ secondsRemaining: z8.number(),
4788
+ epochCount: z8.number(),
4789
+ weeklyEmission: z8.string()
4790
+ }),
4791
+ topPools: z8.array(
4792
+ z8.object({
4793
+ pool: z8.string(),
4794
+ pair: z8.string(),
4795
+ poolType: z8.enum(["stable", "volatile"]),
4796
+ token0: z8.object({
4797
+ address: z8.string(),
4798
+ symbol: z8.string(),
4799
+ decimals: z8.number()
4800
+ }),
4801
+ token1: z8.object({
4802
+ address: z8.string(),
4803
+ symbol: z8.string(),
4804
+ decimals: z8.number()
4805
+ }),
4806
+ reserves: z8.object({
4807
+ token0: z8.string(),
4808
+ token1: z8.string()
4809
+ }),
4810
+ tvlEstimateUnits: z8.number()
4811
+ })
4812
+ ),
4813
+ tvl: z8.object({
4814
+ v2ReserveUnitEstimate: z8.number(),
4815
+ vaultManagedVotingPower: z8.string()
4816
+ }),
4817
+ vaults: z8.object({
4818
+ relayCount: z8.number(),
4819
+ managedVotingPower: z8.string(),
4820
+ note: z8.string().nullable()
4821
+ }),
4822
+ lending: z8.object({
4823
+ available: z8.boolean(),
4824
+ morpho: z8.string(),
4825
+ marketCount: z8.number(),
4826
+ supplyByLoanToken: z8.array(
4827
+ z8.object({
4828
+ token: z8.string(),
4829
+ symbol: z8.string(),
4830
+ decimals: z8.number(),
4831
+ totalSupplyAssets: z8.string(),
4832
+ totalBorrowAssets: z8.string()
4833
+ })
4834
+ ),
4835
+ note: z8.string().nullable()
4836
+ })
2623
4837
  }),
2624
4838
  examples: [{ description: "Fetch the current Aborean protocol status" }],
2625
4839
  async run(c) {
@@ -2630,7 +4844,12 @@ cli.command("status", {
2630
4844
  gaugeCount,
2631
4845
  totalVotingWeight,
2632
4846
  veABXTotalSupply,
2633
- veABXLockedSupply
4847
+ veABXLockedSupply,
4848
+ activePeriod,
4849
+ weekSeconds,
4850
+ epochCount,
4851
+ weeklyEmission,
4852
+ v2PoolSnapshot
2634
4853
  ] = await Promise.all([
2635
4854
  client.readContract({
2636
4855
  abi: poolFactoryAbi,
@@ -2661,16 +4880,113 @@ cli.command("status", {
2661
4880
  abi: votingEscrowAbi,
2662
4881
  address: ABOREAN_V2_ADDRESSES.votingEscrow,
2663
4882
  functionName: "supply"
2664
- })
4883
+ }),
4884
+ client.readContract({
4885
+ abi: minterAbi,
4886
+ address: ABOREAN_V2_ADDRESSES.minter,
4887
+ functionName: "activePeriod"
4888
+ }),
4889
+ client.readContract({
4890
+ abi: minterAbi,
4891
+ address: ABOREAN_V2_ADDRESSES.minter,
4892
+ functionName: "WEEK"
4893
+ }),
4894
+ client.readContract({
4895
+ abi: minterAbi,
4896
+ address: ABOREAN_V2_ADDRESSES.minter,
4897
+ functionName: "epochCount"
4898
+ }),
4899
+ client.readContract({
4900
+ abi: minterAbi,
4901
+ address: ABOREAN_V2_ADDRESSES.minter,
4902
+ functionName: "weekly"
4903
+ }),
4904
+ readTopV2PoolsSnapshot(client, 5)
2665
4905
  ]);
2666
- return c.ok({
2667
- v2PoolCount: Number(v2PoolCount),
2668
- clPoolCount: Number(clPoolCount),
2669
- gaugeCount: Number(gaugeCount),
2670
- totalVotingWeight: String(totalVotingWeight),
2671
- veABXTotalSupply: String(veABXTotalSupply),
2672
- veABXLockedSupply: String(veABXLockedSupply)
2673
- });
4906
+ let vaultRelayCount = 0;
4907
+ let vaultManagedVotingPower = "0";
4908
+ let vaultNote = null;
4909
+ try {
4910
+ const vaultSnapshot = await readVaultSummary(client);
4911
+ vaultRelayCount = vaultSnapshot.relayCount;
4912
+ vaultManagedVotingPower = vaultSnapshot.totals.managedVotingPower;
4913
+ } catch (error) {
4914
+ vaultNote = error instanceof Error ? error.message : "vault snapshot unavailable";
4915
+ }
4916
+ let lendingAvailable = false;
4917
+ let lendingMarketCount = 0;
4918
+ let lendingMorpho = "";
4919
+ let lendingSupplyByLoanToken = [];
4920
+ let lendingNote = null;
4921
+ try {
4922
+ const lendingSnapshot = await readLendingSummary(client);
4923
+ lendingAvailable = lendingSnapshot.available;
4924
+ lendingMarketCount = lendingSnapshot.marketCount;
4925
+ lendingMorpho = lendingSnapshot.morpho;
4926
+ lendingSupplyByLoanToken = lendingSnapshot.supplyByLoanToken;
4927
+ } catch (error) {
4928
+ lendingMorpho = "";
4929
+ lendingNote = error instanceof Error ? error.message : "lending snapshot unavailable";
4930
+ }
4931
+ const now = Math.floor(Date.now() / 1e3);
4932
+ const epochEnd = Number(activePeriod) + Number(weekSeconds);
4933
+ return c.ok(
4934
+ {
4935
+ v2PoolCount: Number(v2PoolCount),
4936
+ clPoolCount: Number(clPoolCount),
4937
+ gaugeCount: Number(gaugeCount),
4938
+ totalVotingWeight: String(totalVotingWeight),
4939
+ veABXTotalSupply: String(veABXTotalSupply),
4940
+ veABXLockedSupply: String(veABXLockedSupply),
4941
+ epoch: {
4942
+ activePeriod: Number(activePeriod),
4943
+ epochEnd,
4944
+ secondsRemaining: Math.max(0, epochEnd - now),
4945
+ epochCount: Number(epochCount),
4946
+ weeklyEmission: String(weeklyEmission)
4947
+ },
4948
+ topPools: v2PoolSnapshot.topPools,
4949
+ tvl: {
4950
+ v2ReserveUnitEstimate: v2PoolSnapshot.reserveUnitTvl,
4951
+ vaultManagedVotingPower
4952
+ },
4953
+ vaults: {
4954
+ relayCount: vaultRelayCount,
4955
+ managedVotingPower: vaultManagedVotingPower,
4956
+ note: vaultNote
4957
+ },
4958
+ lending: {
4959
+ available: lendingAvailable,
4960
+ morpho: lendingMorpho,
4961
+ marketCount: lendingMarketCount,
4962
+ supplyByLoanToken: lendingSupplyByLoanToken,
4963
+ note: lendingNote
4964
+ }
4965
+ },
4966
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
4967
+ cta: {
4968
+ description: "Drill down:",
4969
+ commands: [
4970
+ {
4971
+ command: "pools list",
4972
+ description: "List V2 AMM pools"
4973
+ },
4974
+ {
4975
+ command: "cl pools",
4976
+ description: "List Slipstream CL pools"
4977
+ },
4978
+ {
4979
+ command: "gauges list",
4980
+ description: "List active gauges"
4981
+ },
4982
+ {
4983
+ command: "ve stats",
4984
+ description: "View veABX global stats"
4985
+ }
4986
+ ]
4987
+ }
4988
+ }
4989
+ );
2674
4990
  }
2675
4991
  });
2676
4992
  applyFriendlyErrorHandling(cli);