@spectratools/aborean-cli 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1960 -169
- 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 {
|
|
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,8 +1345,8 @@ cl.command("pools", {
|
|
|
1244
1345
|
}),
|
|
1245
1346
|
async run(c) {
|
|
1246
1347
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1247
|
-
const
|
|
1248
|
-
const poolStates = await readPoolStates(client,
|
|
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])
|
|
@@ -1556,18 +1657,18 @@ async function discoverGaugePools(client) {
|
|
|
1556
1657
|
}))
|
|
1557
1658
|
}) : Promise.resolve([])
|
|
1558
1659
|
]);
|
|
1559
|
-
const
|
|
1560
|
-
if (!
|
|
1660
|
+
const pools2 = [...v2Pools, ...clPools];
|
|
1661
|
+
if (!pools2.length) return [];
|
|
1561
1662
|
const gauges2 = await client.multicall({
|
|
1562
1663
|
allowFailure: false,
|
|
1563
|
-
contracts:
|
|
1664
|
+
contracts: pools2.map((pool) => ({
|
|
1564
1665
|
abi: voterAbi,
|
|
1565
1666
|
address: ABOREAN_V2_ADDRESSES.voter,
|
|
1566
1667
|
functionName: "gauges",
|
|
1567
1668
|
args: [pool]
|
|
1568
1669
|
}))
|
|
1569
1670
|
});
|
|
1570
|
-
return
|
|
1671
|
+
return pools2.map((pool, index) => ({ pool, gauge: gauges2[index] })).filter(({ gauge }) => gauge.toLowerCase() !== ZERO_ADDRESS.toLowerCase());
|
|
1571
1672
|
}
|
|
1572
1673
|
var gauges = Cli2.create("gauges", {
|
|
1573
1674
|
description: "Inspect Aborean gauge emissions, staking, and user positions."
|
|
@@ -1880,104 +1981,1461 @@ gauges.command("staked", {
|
|
|
1880
1981
|
}
|
|
1881
1982
|
});
|
|
1882
1983
|
|
|
1883
|
-
// src/commands/
|
|
1984
|
+
// src/commands/lending.ts
|
|
1985
|
+
import { checksumAddress as checksumAddress3, isAddress as isAddress2 } from "@spectratools/cli-shared";
|
|
1884
1986
|
import { Cli as Cli3, z as z3 } from "incur";
|
|
1987
|
+
import { formatUnits as formatUnits2 } from "viem";
|
|
1988
|
+
var MORPHO_DEPLOY_BLOCK = 13947713n;
|
|
1885
1989
|
var env3 = z3.object({
|
|
1886
1990
|
ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
|
|
1887
1991
|
});
|
|
1888
|
-
var
|
|
1889
|
-
|
|
1992
|
+
var morphoAbi = [
|
|
1993
|
+
{
|
|
1994
|
+
type: "event",
|
|
1995
|
+
name: "CreateMarket",
|
|
1996
|
+
inputs: [
|
|
1997
|
+
{ type: "bytes32", name: "id", indexed: true },
|
|
1998
|
+
{
|
|
1999
|
+
type: "tuple",
|
|
2000
|
+
name: "marketParams",
|
|
2001
|
+
indexed: false,
|
|
2002
|
+
components: [
|
|
2003
|
+
{ type: "address", name: "loanToken" },
|
|
2004
|
+
{ type: "address", name: "collateralToken" },
|
|
2005
|
+
{ type: "address", name: "oracle" },
|
|
2006
|
+
{ type: "address", name: "irm" },
|
|
2007
|
+
{ type: "uint256", name: "lltv" }
|
|
2008
|
+
]
|
|
2009
|
+
}
|
|
2010
|
+
],
|
|
2011
|
+
anonymous: false
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
type: "function",
|
|
2015
|
+
name: "idToMarketParams",
|
|
2016
|
+
stateMutability: "view",
|
|
2017
|
+
inputs: [{ type: "bytes32", name: "id" }],
|
|
2018
|
+
outputs: [
|
|
2019
|
+
{ type: "address", name: "loanToken" },
|
|
2020
|
+
{ type: "address", name: "collateralToken" },
|
|
2021
|
+
{ type: "address", name: "oracle" },
|
|
2022
|
+
{ type: "address", name: "irm" },
|
|
2023
|
+
{ type: "uint256", name: "lltv" }
|
|
2024
|
+
]
|
|
2025
|
+
},
|
|
2026
|
+
{
|
|
2027
|
+
type: "function",
|
|
2028
|
+
name: "market",
|
|
2029
|
+
stateMutability: "view",
|
|
2030
|
+
inputs: [{ type: "bytes32", name: "id" }],
|
|
2031
|
+
outputs: [
|
|
2032
|
+
{ type: "uint128", name: "totalSupplyAssets" },
|
|
2033
|
+
{ type: "uint128", name: "totalSupplyShares" },
|
|
2034
|
+
{ type: "uint128", name: "totalBorrowAssets" },
|
|
2035
|
+
{ type: "uint128", name: "totalBorrowShares" },
|
|
2036
|
+
{ type: "uint128", name: "lastUpdate" },
|
|
2037
|
+
{ type: "uint128", name: "fee" }
|
|
2038
|
+
]
|
|
2039
|
+
},
|
|
2040
|
+
{
|
|
2041
|
+
type: "function",
|
|
2042
|
+
name: "position",
|
|
2043
|
+
stateMutability: "view",
|
|
2044
|
+
inputs: [
|
|
2045
|
+
{ type: "bytes32", name: "id" },
|
|
2046
|
+
{ type: "address", name: "user" }
|
|
2047
|
+
],
|
|
2048
|
+
outputs: [
|
|
2049
|
+
{ type: "uint256", name: "supplyShares" },
|
|
2050
|
+
{ type: "uint128", name: "borrowShares" },
|
|
2051
|
+
{ type: "uint128", name: "collateral" }
|
|
2052
|
+
]
|
|
2053
|
+
}
|
|
2054
|
+
];
|
|
2055
|
+
var erc20MetadataAbi2 = [
|
|
2056
|
+
{
|
|
2057
|
+
type: "function",
|
|
2058
|
+
name: "symbol",
|
|
2059
|
+
stateMutability: "view",
|
|
2060
|
+
inputs: [],
|
|
2061
|
+
outputs: [{ type: "string" }]
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
type: "function",
|
|
2065
|
+
name: "decimals",
|
|
2066
|
+
stateMutability: "view",
|
|
2067
|
+
inputs: [],
|
|
2068
|
+
outputs: [{ type: "uint8" }]
|
|
2069
|
+
}
|
|
2070
|
+
];
|
|
2071
|
+
var tokenMetaSchema = z3.object({
|
|
2072
|
+
address: z3.string(),
|
|
2073
|
+
symbol: z3.string(),
|
|
2074
|
+
decimals: z3.number()
|
|
1890
2075
|
});
|
|
1891
|
-
|
|
1892
|
-
|
|
2076
|
+
var lendingMarketRowSchema = z3.object({
|
|
2077
|
+
marketId: z3.string(),
|
|
2078
|
+
loanToken: tokenMetaSchema,
|
|
2079
|
+
collateralToken: tokenMetaSchema,
|
|
2080
|
+
oracle: z3.string(),
|
|
2081
|
+
irm: z3.string(),
|
|
2082
|
+
lltvBps: z3.number(),
|
|
2083
|
+
lltvPercent: z3.number(),
|
|
2084
|
+
totalSupplyAssets: z3.string(),
|
|
2085
|
+
totalBorrowAssets: z3.string(),
|
|
2086
|
+
totalSupplyShares: z3.string(),
|
|
2087
|
+
totalBorrowShares: z3.string(),
|
|
2088
|
+
availableLiquidityAssets: z3.string(),
|
|
2089
|
+
utilization: z3.number().nullable(),
|
|
2090
|
+
feeWad: z3.string(),
|
|
2091
|
+
lastUpdate: z3.number()
|
|
2092
|
+
});
|
|
2093
|
+
function isMarketId(value) {
|
|
2094
|
+
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
2095
|
+
}
|
|
2096
|
+
function shortAddress2(address) {
|
|
2097
|
+
return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
2098
|
+
}
|
|
2099
|
+
function finiteOrNull2(value) {
|
|
2100
|
+
return Number.isFinite(value) ? value : null;
|
|
2101
|
+
}
|
|
2102
|
+
function sharesToAssets(shares, totalShares, totalAssets) {
|
|
2103
|
+
if (shares === 0n || totalShares === 0n) return 0n;
|
|
2104
|
+
return shares * totalAssets / totalShares;
|
|
2105
|
+
}
|
|
2106
|
+
function normalizeMarketParams(value) {
|
|
2107
|
+
if (Array.isArray(value)) {
|
|
2108
|
+
return {
|
|
2109
|
+
loanToken: checksumAddress3(String(value[0])),
|
|
2110
|
+
collateralToken: checksumAddress3(String(value[1])),
|
|
2111
|
+
oracle: checksumAddress3(String(value[2])),
|
|
2112
|
+
irm: checksumAddress3(String(value[3])),
|
|
2113
|
+
lltv: BigInt(value[4])
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
if (typeof value !== "object" || value === null) {
|
|
2117
|
+
throw new Error("invalid market params");
|
|
2118
|
+
}
|
|
2119
|
+
const v = value;
|
|
2120
|
+
return {
|
|
2121
|
+
loanToken: checksumAddress3(String(v.loanToken)),
|
|
2122
|
+
collateralToken: checksumAddress3(String(v.collateralToken)),
|
|
2123
|
+
oracle: checksumAddress3(String(v.oracle)),
|
|
2124
|
+
irm: checksumAddress3(String(v.irm)),
|
|
2125
|
+
lltv: BigInt(v.lltv)
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
function normalizeMarketState(value) {
|
|
2129
|
+
if (Array.isArray(value)) {
|
|
2130
|
+
return {
|
|
2131
|
+
totalSupplyAssets: BigInt(value[0]),
|
|
2132
|
+
totalSupplyShares: BigInt(value[1]),
|
|
2133
|
+
totalBorrowAssets: BigInt(value[2]),
|
|
2134
|
+
totalBorrowShares: BigInt(value[3]),
|
|
2135
|
+
lastUpdate: BigInt(value[4]),
|
|
2136
|
+
fee: BigInt(value[5])
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
if (typeof value !== "object" || value === null) {
|
|
2140
|
+
throw new Error("invalid market state");
|
|
2141
|
+
}
|
|
2142
|
+
const v = value;
|
|
2143
|
+
return {
|
|
2144
|
+
totalSupplyAssets: BigInt(v.totalSupplyAssets),
|
|
2145
|
+
totalSupplyShares: BigInt(v.totalSupplyShares),
|
|
2146
|
+
totalBorrowAssets: BigInt(v.totalBorrowAssets),
|
|
2147
|
+
totalBorrowShares: BigInt(v.totalBorrowShares),
|
|
2148
|
+
lastUpdate: BigInt(v.lastUpdate),
|
|
2149
|
+
fee: BigInt(v.fee)
|
|
2150
|
+
};
|
|
2151
|
+
}
|
|
2152
|
+
function toMarketRow(marketId, params, state, tokenMeta) {
|
|
2153
|
+
const loanMeta = tokenMeta.get(params.loanToken.toLowerCase()) ?? {
|
|
2154
|
+
address: params.loanToken,
|
|
2155
|
+
symbol: shortAddress2(params.loanToken),
|
|
2156
|
+
decimals: 18
|
|
2157
|
+
};
|
|
2158
|
+
const collateralMeta = tokenMeta.get(params.collateralToken.toLowerCase()) ?? {
|
|
2159
|
+
address: params.collateralToken,
|
|
2160
|
+
symbol: shortAddress2(params.collateralToken),
|
|
2161
|
+
decimals: 18
|
|
2162
|
+
};
|
|
2163
|
+
const utilization = state.totalSupplyAssets === 0n ? null : finiteOrNull2(Number(state.totalBorrowAssets) / Number(state.totalSupplyAssets));
|
|
2164
|
+
const lltvPercent = Number(params.lltv) / 1e16;
|
|
2165
|
+
return {
|
|
2166
|
+
marketId,
|
|
2167
|
+
loanToken: {
|
|
2168
|
+
address: toChecksum(loanMeta.address),
|
|
2169
|
+
symbol: loanMeta.symbol,
|
|
2170
|
+
decimals: loanMeta.decimals
|
|
2171
|
+
},
|
|
2172
|
+
collateralToken: {
|
|
2173
|
+
address: toChecksum(collateralMeta.address),
|
|
2174
|
+
symbol: collateralMeta.symbol,
|
|
2175
|
+
decimals: collateralMeta.decimals
|
|
2176
|
+
},
|
|
2177
|
+
oracle: toChecksum(params.oracle),
|
|
2178
|
+
irm: toChecksum(params.irm),
|
|
2179
|
+
lltvBps: Math.round(lltvPercent * 100),
|
|
2180
|
+
lltvPercent,
|
|
2181
|
+
totalSupplyAssets: state.totalSupplyAssets.toString(),
|
|
2182
|
+
totalBorrowAssets: state.totalBorrowAssets.toString(),
|
|
2183
|
+
totalSupplyShares: state.totalSupplyShares.toString(),
|
|
2184
|
+
totalBorrowShares: state.totalBorrowShares.toString(),
|
|
2185
|
+
availableLiquidityAssets: (state.totalSupplyAssets - state.totalBorrowAssets).toString(),
|
|
2186
|
+
utilization,
|
|
2187
|
+
feeWad: state.fee.toString(),
|
|
2188
|
+
lastUpdate: asNum(state.lastUpdate)
|
|
2189
|
+
};
|
|
2190
|
+
}
|
|
2191
|
+
async function readTokenMetadata2(client, addresses) {
|
|
2192
|
+
const unique = [...new Set(addresses.map((address) => address.toLowerCase()))];
|
|
2193
|
+
if (unique.length === 0) {
|
|
2194
|
+
return /* @__PURE__ */ new Map();
|
|
2195
|
+
}
|
|
2196
|
+
const contracts = unique.flatMap((address) => [
|
|
2197
|
+
{
|
|
2198
|
+
abi: erc20MetadataAbi2,
|
|
2199
|
+
address,
|
|
2200
|
+
functionName: "symbol"
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
abi: erc20MetadataAbi2,
|
|
2204
|
+
address,
|
|
2205
|
+
functionName: "decimals"
|
|
2206
|
+
}
|
|
2207
|
+
]);
|
|
2208
|
+
const results = await client.multicall({
|
|
2209
|
+
allowFailure: true,
|
|
2210
|
+
contracts
|
|
2211
|
+
});
|
|
2212
|
+
const map = /* @__PURE__ */ new Map();
|
|
2213
|
+
for (let i = 0; i < unique.length; i += 1) {
|
|
2214
|
+
const address = unique[i];
|
|
2215
|
+
const symbolResult = results[i * 2];
|
|
2216
|
+
const decimalsResult = results[i * 2 + 1];
|
|
2217
|
+
const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : shortAddress2(address);
|
|
2218
|
+
const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : 18;
|
|
2219
|
+
map.set(address.toLowerCase(), {
|
|
2220
|
+
address: checksumAddress3(address),
|
|
2221
|
+
symbol,
|
|
2222
|
+
decimals
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
return map;
|
|
2226
|
+
}
|
|
2227
|
+
async function discoverMarketIds(client) {
|
|
2228
|
+
const logs = await client.getContractEvents({
|
|
2229
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2230
|
+
abi: morphoAbi,
|
|
2231
|
+
eventName: "CreateMarket",
|
|
2232
|
+
fromBlock: MORPHO_DEPLOY_BLOCK,
|
|
2233
|
+
toBlock: "latest"
|
|
2234
|
+
});
|
|
2235
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2236
|
+
const ids = [];
|
|
2237
|
+
for (const log of logs) {
|
|
2238
|
+
const id = log.args.id;
|
|
2239
|
+
if (!id) continue;
|
|
2240
|
+
const key = id.toLowerCase();
|
|
2241
|
+
if (seen.has(key)) continue;
|
|
2242
|
+
seen.add(key);
|
|
2243
|
+
ids.push(id);
|
|
2244
|
+
}
|
|
2245
|
+
return ids;
|
|
2246
|
+
}
|
|
2247
|
+
async function readMarkets(client, marketIds) {
|
|
2248
|
+
if (marketIds.length === 0) return [];
|
|
2249
|
+
const contracts = marketIds.flatMap((marketId) => [
|
|
2250
|
+
{
|
|
2251
|
+
abi: morphoAbi,
|
|
2252
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2253
|
+
functionName: "idToMarketParams",
|
|
2254
|
+
args: [marketId]
|
|
2255
|
+
},
|
|
2256
|
+
{
|
|
2257
|
+
abi: morphoAbi,
|
|
2258
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2259
|
+
functionName: "market",
|
|
2260
|
+
args: [marketId]
|
|
2261
|
+
}
|
|
2262
|
+
]);
|
|
2263
|
+
const values = await client.multicall({
|
|
2264
|
+
allowFailure: false,
|
|
2265
|
+
contracts
|
|
2266
|
+
});
|
|
2267
|
+
return marketIds.map((marketId, index) => {
|
|
2268
|
+
const paramsValue = values[index * 2];
|
|
2269
|
+
const stateValue = values[index * 2 + 1];
|
|
2270
|
+
return {
|
|
2271
|
+
marketId,
|
|
2272
|
+
params: normalizeMarketParams(paramsValue),
|
|
2273
|
+
state: normalizeMarketState(stateValue)
|
|
2274
|
+
};
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
function summarizeByLoanToken(markets, tokenMeta) {
|
|
2278
|
+
const byLoanToken = /* @__PURE__ */ new Map();
|
|
2279
|
+
for (const { params, state } of markets) {
|
|
2280
|
+
const key = params.loanToken.toLowerCase();
|
|
2281
|
+
const prev = byLoanToken.get(key);
|
|
2282
|
+
if (prev) {
|
|
2283
|
+
prev.totalSupply += state.totalSupplyAssets;
|
|
2284
|
+
prev.totalBorrow += state.totalBorrowAssets;
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2287
|
+
byLoanToken.set(key, {
|
|
2288
|
+
token: params.loanToken,
|
|
2289
|
+
totalSupply: state.totalSupplyAssets,
|
|
2290
|
+
totalBorrow: state.totalBorrowAssets
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
return [...byLoanToken.values()].map((entry) => {
|
|
2294
|
+
const meta = tokenMeta.get(entry.token.toLowerCase()) ?? {
|
|
2295
|
+
address: entry.token,
|
|
2296
|
+
symbol: shortAddress2(entry.token),
|
|
2297
|
+
decimals: 18
|
|
2298
|
+
};
|
|
2299
|
+
return {
|
|
2300
|
+
token: toChecksum(entry.token),
|
|
2301
|
+
symbol: meta.symbol,
|
|
2302
|
+
decimals: meta.decimals,
|
|
2303
|
+
totalSupplyAssets: entry.totalSupply.toString(),
|
|
2304
|
+
totalBorrowAssets: entry.totalBorrow.toString()
|
|
2305
|
+
};
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
async function readLendingSummary(client) {
|
|
2309
|
+
const marketIds = await discoverMarketIds(client);
|
|
2310
|
+
const markets = await readMarkets(client, marketIds);
|
|
2311
|
+
const tokenMeta = await readTokenMetadata2(
|
|
2312
|
+
client,
|
|
2313
|
+
markets.flatMap((market) => [market.params.loanToken, market.params.collateralToken])
|
|
2314
|
+
);
|
|
2315
|
+
return {
|
|
2316
|
+
available: true,
|
|
2317
|
+
morpho: toChecksum(ABOREAN_LENDING_ADDRESSES.morphoBlue),
|
|
2318
|
+
marketCount: marketIds.length,
|
|
2319
|
+
supplyByLoanToken: summarizeByLoanToken(markets, tokenMeta)
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
var lending = Cli3.create("lending", {
|
|
2323
|
+
description: "Inspect Morpho lending markets on Abstract."
|
|
2324
|
+
});
|
|
2325
|
+
lending.command("markets", {
|
|
2326
|
+
description: "List Morpho markets discovered from CreateMarket events.",
|
|
2327
|
+
args: z3.object({
|
|
2328
|
+
limit: z3.coerce.number().int().positive().max(200).default(25).describe("Max markets to return")
|
|
2329
|
+
}),
|
|
1893
2330
|
env: env3,
|
|
1894
2331
|
output: z3.object({
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2332
|
+
morpho: z3.string(),
|
|
2333
|
+
marketCount: z3.number(),
|
|
2334
|
+
markets: z3.array(lendingMarketRowSchema),
|
|
2335
|
+
totalsByLoanToken: z3.array(
|
|
2336
|
+
z3.object({
|
|
2337
|
+
token: z3.string(),
|
|
2338
|
+
symbol: z3.string(),
|
|
2339
|
+
decimals: z3.number(),
|
|
2340
|
+
totalSupplyAssets: z3.string(),
|
|
2341
|
+
totalBorrowAssets: z3.string()
|
|
2342
|
+
})
|
|
2343
|
+
)
|
|
1904
2344
|
}),
|
|
1905
|
-
examples: [{ description: "
|
|
2345
|
+
examples: [{ description: "List active Morpho markets on Abstract" }],
|
|
1906
2346
|
async run(c) {
|
|
1907
2347
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
functionName: "totalSupply"
|
|
1918
|
-
}),
|
|
1919
|
-
client.readContract({
|
|
1920
|
-
abi: votingEscrowAbi,
|
|
1921
|
-
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
1922
|
-
functionName: "supply"
|
|
1923
|
-
}),
|
|
1924
|
-
client.readContract({
|
|
1925
|
-
abi: votingEscrowAbi,
|
|
1926
|
-
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
1927
|
-
functionName: "permanentLockBalance"
|
|
1928
|
-
}),
|
|
1929
|
-
client.readContract({
|
|
1930
|
-
abi: votingEscrowAbi,
|
|
1931
|
-
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
1932
|
-
functionName: "epoch"
|
|
1933
|
-
})
|
|
1934
|
-
]);
|
|
1935
|
-
const point = await client.readContract({
|
|
1936
|
-
abi: votingEscrowAbi,
|
|
1937
|
-
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
1938
|
-
functionName: "pointHistory",
|
|
1939
|
-
args: [epoch]
|
|
1940
|
-
});
|
|
2348
|
+
const marketIds = await discoverMarketIds(client);
|
|
2349
|
+
const markets = await readMarkets(client, marketIds);
|
|
2350
|
+
const tokenMeta = await readTokenMetadata2(
|
|
2351
|
+
client,
|
|
2352
|
+
markets.flatMap((market) => [market.params.loanToken, market.params.collateralToken])
|
|
2353
|
+
);
|
|
2354
|
+
const rows = markets.map((market) => toMarketRow(market.marketId, market.params, market.state, tokenMeta)).sort(
|
|
2355
|
+
(a, b) => BigInt(a.totalSupplyAssets) > BigInt(b.totalSupplyAssets) ? -1 : BigInt(a.totalSupplyAssets) < BigInt(b.totalSupplyAssets) ? 1 : 0
|
|
2356
|
+
).slice(0, c.args.limit);
|
|
1941
2357
|
return c.ok({
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
epoch: asNum(epoch),
|
|
1947
|
-
decayBias: point.bias.toString(),
|
|
1948
|
-
decaySlope: point.slope.toString(),
|
|
1949
|
-
lastCheckpointTimestamp: asNum(point.ts),
|
|
1950
|
-
lastCheckpointBlock: asNum(point.blk)
|
|
2358
|
+
morpho: toChecksum(ABOREAN_LENDING_ADDRESSES.morphoBlue),
|
|
2359
|
+
marketCount: marketIds.length,
|
|
2360
|
+
markets: rows,
|
|
2361
|
+
totalsByLoanToken: summarizeByLoanToken(markets, tokenMeta)
|
|
1951
2362
|
});
|
|
1952
2363
|
}
|
|
1953
2364
|
});
|
|
1954
|
-
|
|
1955
|
-
description: "Get
|
|
2365
|
+
lending.command("market", {
|
|
2366
|
+
description: "Get details for one Morpho market id (bytes32).",
|
|
1956
2367
|
args: z3.object({
|
|
1957
|
-
|
|
2368
|
+
marketId: z3.string().describe("Morpho market id (bytes32 hex)")
|
|
1958
2369
|
}),
|
|
1959
2370
|
env: env3,
|
|
1960
|
-
output:
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
}),
|
|
1968
|
-
examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
|
|
2371
|
+
output: lendingMarketRowSchema,
|
|
2372
|
+
examples: [
|
|
2373
|
+
{
|
|
2374
|
+
args: { marketId: "0xfe1d7da2fbde85b1fee120c88df3e6b55164a2442dab97486d3d4f719a5ff1fb" },
|
|
2375
|
+
description: "Inspect one Morpho market by id"
|
|
2376
|
+
}
|
|
2377
|
+
],
|
|
1969
2378
|
async run(c) {
|
|
2379
|
+
if (!isMarketId(c.args.marketId)) {
|
|
2380
|
+
return c.error({
|
|
2381
|
+
code: "INVALID_ARGUMENT",
|
|
2382
|
+
message: "marketId must be a 32-byte hex string (0x + 64 hex chars)"
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
const marketId = c.args.marketId;
|
|
1970
2386
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1971
|
-
const
|
|
1972
|
-
const [owner, locked, votingPower] = await Promise.all([
|
|
2387
|
+
const [paramsRaw, stateRaw] = await Promise.all([
|
|
1973
2388
|
client.readContract({
|
|
1974
|
-
abi:
|
|
1975
|
-
address:
|
|
1976
|
-
functionName: "
|
|
1977
|
-
args: [
|
|
2389
|
+
abi: morphoAbi,
|
|
2390
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2391
|
+
functionName: "idToMarketParams",
|
|
2392
|
+
args: [marketId]
|
|
1978
2393
|
}),
|
|
1979
2394
|
client.readContract({
|
|
1980
|
-
abi:
|
|
2395
|
+
abi: morphoAbi,
|
|
2396
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2397
|
+
functionName: "market",
|
|
2398
|
+
args: [marketId]
|
|
2399
|
+
})
|
|
2400
|
+
]);
|
|
2401
|
+
const params = normalizeMarketParams(paramsRaw);
|
|
2402
|
+
const state = normalizeMarketState(stateRaw);
|
|
2403
|
+
const tokenMeta = await readTokenMetadata2(client, [params.loanToken, params.collateralToken]);
|
|
2404
|
+
return c.ok(toMarketRow(marketId, params, state, tokenMeta));
|
|
2405
|
+
}
|
|
2406
|
+
});
|
|
2407
|
+
lending.command("position", {
|
|
2408
|
+
description: "Inspect one user position in a Morpho market.",
|
|
2409
|
+
args: z3.object({
|
|
2410
|
+
marketId: z3.string().describe("Morpho market id (bytes32 hex)"),
|
|
2411
|
+
user: z3.string().describe("Position owner address")
|
|
2412
|
+
}),
|
|
2413
|
+
env: env3,
|
|
2414
|
+
output: z3.object({
|
|
2415
|
+
marketId: z3.string(),
|
|
2416
|
+
user: z3.string(),
|
|
2417
|
+
loanToken: tokenMetaSchema,
|
|
2418
|
+
collateralToken: tokenMetaSchema,
|
|
2419
|
+
supplyShares: z3.string(),
|
|
2420
|
+
supplyAssetsEstimate: z3.object({
|
|
2421
|
+
raw: z3.string(),
|
|
2422
|
+
decimal: z3.string()
|
|
2423
|
+
}),
|
|
2424
|
+
borrowShares: z3.string(),
|
|
2425
|
+
borrowAssetsEstimate: z3.object({
|
|
2426
|
+
raw: z3.string(),
|
|
2427
|
+
decimal: z3.string()
|
|
2428
|
+
}),
|
|
2429
|
+
collateralAssets: z3.object({
|
|
2430
|
+
raw: z3.string(),
|
|
2431
|
+
decimal: z3.string()
|
|
2432
|
+
})
|
|
2433
|
+
}),
|
|
2434
|
+
examples: [
|
|
2435
|
+
{
|
|
2436
|
+
args: {
|
|
2437
|
+
marketId: "0xfe1d7da2fbde85b1fee120c88df3e6b55164a2442dab97486d3d4f719a5ff1fb",
|
|
2438
|
+
user: "0x0000000000000000000000000000000000000000"
|
|
2439
|
+
},
|
|
2440
|
+
description: "Inspect one user position in a market"
|
|
2441
|
+
}
|
|
2442
|
+
],
|
|
2443
|
+
async run(c) {
|
|
2444
|
+
if (!isMarketId(c.args.marketId)) {
|
|
2445
|
+
return c.error({
|
|
2446
|
+
code: "INVALID_ARGUMENT",
|
|
2447
|
+
message: "marketId must be a 32-byte hex string (0x + 64 hex chars)"
|
|
2448
|
+
});
|
|
2449
|
+
}
|
|
2450
|
+
if (!isAddress2(c.args.user)) {
|
|
2451
|
+
return c.error({
|
|
2452
|
+
code: "INVALID_ARGUMENT",
|
|
2453
|
+
message: "user must be a valid address"
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
const marketId = c.args.marketId;
|
|
2457
|
+
const user = checksumAddress3(c.args.user);
|
|
2458
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
2459
|
+
const [paramsRaw, stateRaw, positionRaw] = await Promise.all([
|
|
2460
|
+
client.readContract({
|
|
2461
|
+
abi: morphoAbi,
|
|
2462
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2463
|
+
functionName: "idToMarketParams",
|
|
2464
|
+
args: [marketId]
|
|
2465
|
+
}),
|
|
2466
|
+
client.readContract({
|
|
2467
|
+
abi: morphoAbi,
|
|
2468
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2469
|
+
functionName: "market",
|
|
2470
|
+
args: [marketId]
|
|
2471
|
+
}),
|
|
2472
|
+
client.readContract({
|
|
2473
|
+
abi: morphoAbi,
|
|
2474
|
+
address: ABOREAN_LENDING_ADDRESSES.morphoBlue,
|
|
2475
|
+
functionName: "position",
|
|
2476
|
+
args: [marketId, user]
|
|
2477
|
+
})
|
|
2478
|
+
]);
|
|
2479
|
+
const params = normalizeMarketParams(paramsRaw);
|
|
2480
|
+
const state = normalizeMarketState(stateRaw);
|
|
2481
|
+
const position = Array.isArray(positionRaw) ? {
|
|
2482
|
+
supplyShares: BigInt(positionRaw[0]),
|
|
2483
|
+
borrowShares: BigInt(positionRaw[1]),
|
|
2484
|
+
collateral: BigInt(positionRaw[2])
|
|
2485
|
+
} : {
|
|
2486
|
+
supplyShares: BigInt(positionRaw.supplyShares),
|
|
2487
|
+
borrowShares: BigInt(positionRaw.borrowShares),
|
|
2488
|
+
collateral: BigInt(positionRaw.collateral)
|
|
2489
|
+
};
|
|
2490
|
+
const tokenMeta = await readTokenMetadata2(client, [params.loanToken, params.collateralToken]);
|
|
2491
|
+
const loanMeta = tokenMeta.get(params.loanToken.toLowerCase()) ?? {
|
|
2492
|
+
address: params.loanToken,
|
|
2493
|
+
symbol: shortAddress2(params.loanToken),
|
|
2494
|
+
decimals: 18
|
|
2495
|
+
};
|
|
2496
|
+
const collateralMeta = tokenMeta.get(params.collateralToken.toLowerCase()) ?? {
|
|
2497
|
+
address: params.collateralToken,
|
|
2498
|
+
symbol: shortAddress2(params.collateralToken),
|
|
2499
|
+
decimals: 18
|
|
2500
|
+
};
|
|
2501
|
+
const supplyAssetsEstimate = sharesToAssets(
|
|
2502
|
+
BigInt(position.supplyShares),
|
|
2503
|
+
state.totalSupplyShares,
|
|
2504
|
+
state.totalSupplyAssets
|
|
2505
|
+
);
|
|
2506
|
+
const borrowAssetsEstimate = sharesToAssets(
|
|
2507
|
+
BigInt(position.borrowShares),
|
|
2508
|
+
state.totalBorrowShares,
|
|
2509
|
+
state.totalBorrowAssets
|
|
2510
|
+
);
|
|
2511
|
+
return c.ok({
|
|
2512
|
+
marketId,
|
|
2513
|
+
user: toChecksum(user),
|
|
2514
|
+
loanToken: {
|
|
2515
|
+
address: toChecksum(loanMeta.address),
|
|
2516
|
+
symbol: loanMeta.symbol,
|
|
2517
|
+
decimals: loanMeta.decimals
|
|
2518
|
+
},
|
|
2519
|
+
collateralToken: {
|
|
2520
|
+
address: toChecksum(collateralMeta.address),
|
|
2521
|
+
symbol: collateralMeta.symbol,
|
|
2522
|
+
decimals: collateralMeta.decimals
|
|
2523
|
+
},
|
|
2524
|
+
supplyShares: position.supplyShares.toString(),
|
|
2525
|
+
supplyAssetsEstimate: {
|
|
2526
|
+
raw: supplyAssetsEstimate.toString(),
|
|
2527
|
+
decimal: formatUnits2(supplyAssetsEstimate, loanMeta.decimals)
|
|
2528
|
+
},
|
|
2529
|
+
borrowShares: position.borrowShares.toString(),
|
|
2530
|
+
borrowAssetsEstimate: {
|
|
2531
|
+
raw: borrowAssetsEstimate.toString(),
|
|
2532
|
+
decimal: formatUnits2(borrowAssetsEstimate, loanMeta.decimals)
|
|
2533
|
+
},
|
|
2534
|
+
collateralAssets: {
|
|
2535
|
+
raw: position.collateral.toString(),
|
|
2536
|
+
decimal: formatUnits2(BigInt(position.collateral), collateralMeta.decimals)
|
|
2537
|
+
}
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
|
|
2542
|
+
// src/commands/pools.ts
|
|
2543
|
+
import { checksumAddress as checksumAddress4, isAddress as isAddress3 } from "@spectratools/cli-shared";
|
|
2544
|
+
import { Cli as Cli4, z as z4 } from "incur";
|
|
2545
|
+
import { formatUnits as formatUnits3, parseUnits as parseUnits2 } from "viem";
|
|
2546
|
+
var MULTICALL_BATCH_SIZE2 = 100;
|
|
2547
|
+
var env4 = z4.object({
|
|
2548
|
+
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
|
|
2549
|
+
});
|
|
2550
|
+
var tokenSchema2 = z4.object({
|
|
2551
|
+
address: z4.string(),
|
|
2552
|
+
symbol: z4.string(),
|
|
2553
|
+
decimals: z4.number()
|
|
2554
|
+
});
|
|
2555
|
+
var amountSchema = z4.object({
|
|
2556
|
+
raw: z4.string(),
|
|
2557
|
+
decimal: z4.string()
|
|
2558
|
+
});
|
|
2559
|
+
var feeSchema = z4.object({
|
|
2560
|
+
feeBps: z4.number(),
|
|
2561
|
+
feePercent: z4.number()
|
|
2562
|
+
}).nullable();
|
|
2563
|
+
var poolSummarySchema = z4.object({
|
|
2564
|
+
pool: z4.string(),
|
|
2565
|
+
pair: z4.string(),
|
|
2566
|
+
stable: z4.boolean(),
|
|
2567
|
+
poolType: z4.enum(["stable", "volatile"]),
|
|
2568
|
+
token0: tokenSchema2,
|
|
2569
|
+
token1: tokenSchema2,
|
|
2570
|
+
reserves: z4.object({
|
|
2571
|
+
token0: amountSchema,
|
|
2572
|
+
token1: amountSchema,
|
|
2573
|
+
blockTimestampLast: z4.number()
|
|
2574
|
+
}),
|
|
2575
|
+
totalSupply: z4.string(),
|
|
2576
|
+
fee: feeSchema
|
|
2577
|
+
});
|
|
2578
|
+
var erc20MetadataAbi3 = [
|
|
2579
|
+
{
|
|
2580
|
+
type: "function",
|
|
2581
|
+
name: "symbol",
|
|
2582
|
+
stateMutability: "view",
|
|
2583
|
+
inputs: [],
|
|
2584
|
+
outputs: [{ type: "string" }]
|
|
2585
|
+
},
|
|
2586
|
+
{
|
|
2587
|
+
type: "function",
|
|
2588
|
+
name: "decimals",
|
|
2589
|
+
stateMutability: "view",
|
|
2590
|
+
inputs: [],
|
|
2591
|
+
outputs: [{ type: "uint8" }]
|
|
2592
|
+
}
|
|
2593
|
+
];
|
|
2594
|
+
function shortAddress3(address) {
|
|
2595
|
+
return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
2596
|
+
}
|
|
2597
|
+
function toAddress(address) {
|
|
2598
|
+
return checksumAddress4(address);
|
|
2599
|
+
}
|
|
2600
|
+
function finiteOrNull3(value) {
|
|
2601
|
+
return Number.isFinite(value) ? value : null;
|
|
2602
|
+
}
|
|
2603
|
+
function toFeeInfo(value) {
|
|
2604
|
+
if (value === null) return null;
|
|
2605
|
+
const feeBps = Number(value);
|
|
2606
|
+
return {
|
|
2607
|
+
feeBps,
|
|
2608
|
+
feePercent: feeBps / 1e4
|
|
2609
|
+
};
|
|
2610
|
+
}
|
|
2611
|
+
function chunk2(items, size) {
|
|
2612
|
+
const output = [];
|
|
2613
|
+
for (let i = 0; i < items.length; i += size) {
|
|
2614
|
+
output.push(items.slice(i, i + size));
|
|
2615
|
+
}
|
|
2616
|
+
return output;
|
|
2617
|
+
}
|
|
2618
|
+
async function multicallStrict2(client, contracts) {
|
|
2619
|
+
if (contracts.length === 0) return [];
|
|
2620
|
+
const batches = chunk2(contracts, MULTICALL_BATCH_SIZE2);
|
|
2621
|
+
const output = [];
|
|
2622
|
+
for (const batch of batches) {
|
|
2623
|
+
const values = await client.multicall({
|
|
2624
|
+
allowFailure: false,
|
|
2625
|
+
contracts: batch
|
|
2626
|
+
});
|
|
2627
|
+
output.push(...values);
|
|
2628
|
+
}
|
|
2629
|
+
return output;
|
|
2630
|
+
}
|
|
2631
|
+
async function multicallAllowFailure2(client, contracts) {
|
|
2632
|
+
if (contracts.length === 0) return [];
|
|
2633
|
+
const batches = chunk2(contracts, MULTICALL_BATCH_SIZE2);
|
|
2634
|
+
const output = [];
|
|
2635
|
+
for (const batch of batches) {
|
|
2636
|
+
const values = await client.multicall({
|
|
2637
|
+
allowFailure: true,
|
|
2638
|
+
contracts: batch
|
|
2639
|
+
});
|
|
2640
|
+
output.push(...values);
|
|
2641
|
+
}
|
|
2642
|
+
return output;
|
|
2643
|
+
}
|
|
2644
|
+
function fallbackTokenMeta(address) {
|
|
2645
|
+
const checksummed = checksumAddress4(address);
|
|
2646
|
+
return {
|
|
2647
|
+
address: checksummed,
|
|
2648
|
+
symbol: shortAddress3(checksummed),
|
|
2649
|
+
decimals: 18
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
async function readTokenMetadata3(client, tokenAddresses) {
|
|
2653
|
+
const unique = [
|
|
2654
|
+
...new Set(tokenAddresses.map((address) => checksumAddress4(address).toLowerCase()))
|
|
2655
|
+
];
|
|
2656
|
+
if (unique.length === 0) {
|
|
2657
|
+
return /* @__PURE__ */ new Map();
|
|
2658
|
+
}
|
|
2659
|
+
const contracts = unique.flatMap((address) => [
|
|
2660
|
+
{
|
|
2661
|
+
abi: erc20MetadataAbi3,
|
|
2662
|
+
address,
|
|
2663
|
+
functionName: "symbol"
|
|
2664
|
+
},
|
|
2665
|
+
{
|
|
2666
|
+
abi: erc20MetadataAbi3,
|
|
2667
|
+
address,
|
|
2668
|
+
functionName: "decimals"
|
|
2669
|
+
}
|
|
2670
|
+
]);
|
|
2671
|
+
const values = await multicallAllowFailure2(client, contracts);
|
|
2672
|
+
const map = /* @__PURE__ */ new Map();
|
|
2673
|
+
for (let i = 0; i < unique.length; i += 1) {
|
|
2674
|
+
const address = unique[i];
|
|
2675
|
+
const symbolResult = values[i * 2];
|
|
2676
|
+
const decimalsResult = values[i * 2 + 1];
|
|
2677
|
+
const fallback = fallbackTokenMeta(address);
|
|
2678
|
+
const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : fallback.symbol;
|
|
2679
|
+
const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : fallback.decimals;
|
|
2680
|
+
map.set(address.toLowerCase(), {
|
|
2681
|
+
address: checksumAddress4(address),
|
|
2682
|
+
symbol,
|
|
2683
|
+
decimals
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2686
|
+
return map;
|
|
2687
|
+
}
|
|
2688
|
+
async function readPoolStates2(client, pools2) {
|
|
2689
|
+
if (pools2.length === 0) {
|
|
2690
|
+
return [];
|
|
2691
|
+
}
|
|
2692
|
+
const contracts = pools2.flatMap((pool) => [
|
|
2693
|
+
{
|
|
2694
|
+
abi: v2PoolAbi,
|
|
2695
|
+
address: pool,
|
|
2696
|
+
functionName: "token0"
|
|
2697
|
+
},
|
|
2698
|
+
{
|
|
2699
|
+
abi: v2PoolAbi,
|
|
2700
|
+
address: pool,
|
|
2701
|
+
functionName: "token1"
|
|
2702
|
+
},
|
|
2703
|
+
{
|
|
2704
|
+
abi: v2PoolAbi,
|
|
2705
|
+
address: pool,
|
|
2706
|
+
functionName: "stable"
|
|
2707
|
+
},
|
|
2708
|
+
{
|
|
2709
|
+
abi: v2PoolAbi,
|
|
2710
|
+
address: pool,
|
|
2711
|
+
functionName: "getReserves"
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
abi: v2PoolAbi,
|
|
2715
|
+
address: pool,
|
|
2716
|
+
functionName: "totalSupply"
|
|
2717
|
+
}
|
|
2718
|
+
]);
|
|
2719
|
+
const values = await multicallStrict2(client, contracts);
|
|
2720
|
+
return pools2.map((pool, index) => {
|
|
2721
|
+
const offset = index * 5;
|
|
2722
|
+
const reserves = values[offset + 3];
|
|
2723
|
+
return {
|
|
2724
|
+
pool,
|
|
2725
|
+
token0: values[offset],
|
|
2726
|
+
token1: values[offset + 1],
|
|
2727
|
+
stable: values[offset + 2],
|
|
2728
|
+
reserve0: reserves[0],
|
|
2729
|
+
reserve1: reserves[1],
|
|
2730
|
+
blockTimestampLast: reserves[2],
|
|
2731
|
+
totalSupply: values[offset + 4]
|
|
2732
|
+
};
|
|
2733
|
+
});
|
|
2734
|
+
}
|
|
2735
|
+
async function readPoolFees(client, pools2) {
|
|
2736
|
+
if (pools2.length === 0) {
|
|
2737
|
+
return [];
|
|
2738
|
+
}
|
|
2739
|
+
const contracts = pools2.map(({ pool, stable }) => ({
|
|
2740
|
+
abi: poolFactoryAbi,
|
|
2741
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
2742
|
+
functionName: "getFee",
|
|
2743
|
+
args: [pool, stable]
|
|
2744
|
+
}));
|
|
2745
|
+
const values = await multicallAllowFailure2(client, contracts);
|
|
2746
|
+
return values.map(
|
|
2747
|
+
(value) => value.status === "success" && typeof value.result === "bigint" ? value.result : null
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
function toAmount(raw, decimals) {
|
|
2751
|
+
return {
|
|
2752
|
+
raw: raw.toString(),
|
|
2753
|
+
decimal: formatUnits3(raw, decimals)
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
function toPoolSummary(state, tokens, fee) {
|
|
2757
|
+
const token0 = tokens.get(state.token0.toLowerCase()) ?? fallbackTokenMeta(state.token0);
|
|
2758
|
+
const token1 = tokens.get(state.token1.toLowerCase()) ?? fallbackTokenMeta(state.token1);
|
|
2759
|
+
return {
|
|
2760
|
+
pool: checksumAddress4(state.pool),
|
|
2761
|
+
pair: `${token0.symbol}/${token1.symbol}`,
|
|
2762
|
+
stable: state.stable,
|
|
2763
|
+
poolType: state.stable ? "stable" : "volatile",
|
|
2764
|
+
token0,
|
|
2765
|
+
token1,
|
|
2766
|
+
reserves: {
|
|
2767
|
+
token0: toAmount(state.reserve0, token0.decimals),
|
|
2768
|
+
token1: toAmount(state.reserve1, token1.decimals),
|
|
2769
|
+
blockTimestampLast: Number(state.blockTimestampLast)
|
|
2770
|
+
},
|
|
2771
|
+
totalSupply: state.totalSupply.toString(),
|
|
2772
|
+
fee: toFeeInfo(fee)
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
var pools = Cli4.create("pools", {
|
|
2776
|
+
description: "Inspect V2 AMM pools, reserves, quotes, and fee configuration."
|
|
2777
|
+
});
|
|
2778
|
+
pools.command("list", {
|
|
2779
|
+
description: "List V2 pools with token pairs, reserves, and stable/volatile type.",
|
|
2780
|
+
options: z4.object({
|
|
2781
|
+
offset: z4.coerce.number().int().nonnegative().default(0).describe("Pool index offset"),
|
|
2782
|
+
limit: z4.coerce.number().int().positive().max(500).default(50).describe("Maximum pools to return (max 500)")
|
|
2783
|
+
}),
|
|
2784
|
+
env: env4,
|
|
2785
|
+
output: z4.object({
|
|
2786
|
+
total: z4.number(),
|
|
2787
|
+
offset: z4.number(),
|
|
2788
|
+
limit: z4.number(),
|
|
2789
|
+
count: z4.number(),
|
|
2790
|
+
pools: z4.array(poolSummarySchema)
|
|
2791
|
+
}),
|
|
2792
|
+
async run(c) {
|
|
2793
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
2794
|
+
const totalRaw = await client.readContract({
|
|
2795
|
+
abi: poolFactoryAbi,
|
|
2796
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
2797
|
+
functionName: "allPoolsLength"
|
|
2798
|
+
});
|
|
2799
|
+
const total = Number(totalRaw);
|
|
2800
|
+
const offset = Math.min(c.options.offset, total);
|
|
2801
|
+
const end = Math.min(total, offset + c.options.limit);
|
|
2802
|
+
if (offset >= end) {
|
|
2803
|
+
return c.ok({
|
|
2804
|
+
total,
|
|
2805
|
+
offset,
|
|
2806
|
+
limit: c.options.limit,
|
|
2807
|
+
count: 0,
|
|
2808
|
+
pools: []
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2811
|
+
const indices = Array.from({ length: end - offset }, (_, i) => BigInt(offset + i));
|
|
2812
|
+
const poolAddresses = await multicallStrict2(
|
|
2813
|
+
client,
|
|
2814
|
+
indices.map((index) => ({
|
|
2815
|
+
abi: poolFactoryAbi,
|
|
2816
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
2817
|
+
functionName: "allPools",
|
|
2818
|
+
args: [index]
|
|
2819
|
+
}))
|
|
2820
|
+
);
|
|
2821
|
+
const poolStates = await readPoolStates2(client, poolAddresses);
|
|
2822
|
+
const tokenMeta = await readTokenMetadata3(
|
|
2823
|
+
client,
|
|
2824
|
+
poolStates.flatMap((pool) => [pool.token0, pool.token1])
|
|
2825
|
+
);
|
|
2826
|
+
const fees = await readPoolFees(
|
|
2827
|
+
client,
|
|
2828
|
+
poolStates.map((pool) => ({ pool: pool.pool, stable: pool.stable }))
|
|
2829
|
+
);
|
|
2830
|
+
return c.ok({
|
|
2831
|
+
total,
|
|
2832
|
+
offset,
|
|
2833
|
+
limit: c.options.limit,
|
|
2834
|
+
count: poolStates.length,
|
|
2835
|
+
pools: poolStates.map((pool, index) => toPoolSummary(pool, tokenMeta, fees[index] ?? null))
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
});
|
|
2839
|
+
pools.command("pool", {
|
|
2840
|
+
description: "Get detailed state for one V2 pool.",
|
|
2841
|
+
args: z4.object({
|
|
2842
|
+
address: z4.string().describe("Pool address")
|
|
2843
|
+
}),
|
|
2844
|
+
env: env4,
|
|
2845
|
+
output: z4.object({
|
|
2846
|
+
pool: poolSummarySchema.extend({
|
|
2847
|
+
poolFees: z4.string(),
|
|
2848
|
+
factory: z4.string()
|
|
2849
|
+
})
|
|
2850
|
+
}),
|
|
2851
|
+
async run(c) {
|
|
2852
|
+
if (!isAddress3(c.args.address)) {
|
|
2853
|
+
return c.error({
|
|
2854
|
+
code: "INVALID_ADDRESS",
|
|
2855
|
+
message: `Invalid pool address: "${c.args.address}". Use a valid 0x-prefixed 20-byte hex address.`
|
|
2856
|
+
});
|
|
2857
|
+
}
|
|
2858
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
2859
|
+
const poolAddress = toAddress(c.args.address);
|
|
2860
|
+
const [token0, token1, stable, reserves, totalSupply, poolFees, factory] = await multicallStrict2(client, [
|
|
2861
|
+
{
|
|
2862
|
+
abi: v2PoolAbi,
|
|
2863
|
+
address: poolAddress,
|
|
2864
|
+
functionName: "token0"
|
|
2865
|
+
},
|
|
2866
|
+
{
|
|
2867
|
+
abi: v2PoolAbi,
|
|
2868
|
+
address: poolAddress,
|
|
2869
|
+
functionName: "token1"
|
|
2870
|
+
},
|
|
2871
|
+
{
|
|
2872
|
+
abi: v2PoolAbi,
|
|
2873
|
+
address: poolAddress,
|
|
2874
|
+
functionName: "stable"
|
|
2875
|
+
},
|
|
2876
|
+
{
|
|
2877
|
+
abi: v2PoolAbi,
|
|
2878
|
+
address: poolAddress,
|
|
2879
|
+
functionName: "getReserves"
|
|
2880
|
+
},
|
|
2881
|
+
{
|
|
2882
|
+
abi: v2PoolAbi,
|
|
2883
|
+
address: poolAddress,
|
|
2884
|
+
functionName: "totalSupply"
|
|
2885
|
+
},
|
|
2886
|
+
{
|
|
2887
|
+
abi: v2PoolAbi,
|
|
2888
|
+
address: poolAddress,
|
|
2889
|
+
functionName: "poolFees"
|
|
2890
|
+
},
|
|
2891
|
+
{
|
|
2892
|
+
abi: v2PoolAbi,
|
|
2893
|
+
address: poolAddress,
|
|
2894
|
+
functionName: "factory"
|
|
2895
|
+
}
|
|
2896
|
+
]);
|
|
2897
|
+
const tokenMeta = await readTokenMetadata3(client, [token0, token1]);
|
|
2898
|
+
const [fee] = await readPoolFees(client, [{ pool: poolAddress, stable }]);
|
|
2899
|
+
return c.ok({
|
|
2900
|
+
pool: {
|
|
2901
|
+
...toPoolSummary(
|
|
2902
|
+
{
|
|
2903
|
+
pool: poolAddress,
|
|
2904
|
+
token0,
|
|
2905
|
+
token1,
|
|
2906
|
+
stable,
|
|
2907
|
+
reserve0: reserves[0],
|
|
2908
|
+
reserve1: reserves[1],
|
|
2909
|
+
blockTimestampLast: reserves[2],
|
|
2910
|
+
totalSupply
|
|
2911
|
+
},
|
|
2912
|
+
tokenMeta,
|
|
2913
|
+
fee ?? null
|
|
2914
|
+
),
|
|
2915
|
+
poolFees: checksumAddress4(poolFees),
|
|
2916
|
+
factory: checksumAddress4(factory)
|
|
2917
|
+
}
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
pools.command("quote", {
|
|
2922
|
+
description: "Quote a single-hop V2 swap between tokenIn and tokenOut.",
|
|
2923
|
+
args: z4.object({
|
|
2924
|
+
tokenIn: z4.string().describe("Input token address"),
|
|
2925
|
+
tokenOut: z4.string().describe("Output token address"),
|
|
2926
|
+
amountIn: z4.string().describe("Input amount in human-readable decimal units")
|
|
2927
|
+
}),
|
|
2928
|
+
options: z4.object({
|
|
2929
|
+
stable: z4.boolean().default(false).describe("Use stable pool route (default: volatile)")
|
|
2930
|
+
}),
|
|
2931
|
+
env: env4,
|
|
2932
|
+
output: z4.object({
|
|
2933
|
+
pool: z4.string(),
|
|
2934
|
+
stable: z4.boolean(),
|
|
2935
|
+
tokenIn: tokenSchema2,
|
|
2936
|
+
tokenOut: tokenSchema2,
|
|
2937
|
+
amountIn: amountSchema,
|
|
2938
|
+
amountOut: amountSchema,
|
|
2939
|
+
priceOutPerIn: z4.number().nullable()
|
|
2940
|
+
}),
|
|
2941
|
+
async run(c) {
|
|
2942
|
+
if (!isAddress3(c.args.tokenIn) || !isAddress3(c.args.tokenOut)) {
|
|
2943
|
+
return c.error({
|
|
2944
|
+
code: "INVALID_ADDRESS",
|
|
2945
|
+
message: "tokenIn and tokenOut must both be valid 0x-prefixed 20-byte addresses."
|
|
2946
|
+
});
|
|
2947
|
+
}
|
|
2948
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
2949
|
+
const tokenIn = toAddress(c.args.tokenIn);
|
|
2950
|
+
const tokenOut = toAddress(c.args.tokenOut);
|
|
2951
|
+
const tokenMeta = await readTokenMetadata3(client, [tokenIn, tokenOut]);
|
|
2952
|
+
const inMeta = tokenMeta.get(tokenIn.toLowerCase()) ?? fallbackTokenMeta(tokenIn);
|
|
2953
|
+
const outMeta = tokenMeta.get(tokenOut.toLowerCase()) ?? fallbackTokenMeta(tokenOut);
|
|
2954
|
+
let amountInRaw;
|
|
2955
|
+
try {
|
|
2956
|
+
amountInRaw = parseUnits2(c.args.amountIn, inMeta.decimals);
|
|
2957
|
+
} catch {
|
|
2958
|
+
return c.error({
|
|
2959
|
+
code: "INVALID_AMOUNT",
|
|
2960
|
+
message: `Invalid amountIn: "${c.args.amountIn}" for token ${inMeta.symbol} (${inMeta.decimals} decimals).`
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2963
|
+
const poolAddress = await client.readContract({
|
|
2964
|
+
abi: poolFactoryAbi,
|
|
2965
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
2966
|
+
functionName: "getPool",
|
|
2967
|
+
args: [tokenIn, tokenOut, c.options.stable]
|
|
2968
|
+
});
|
|
2969
|
+
if (poolAddress.toLowerCase() === ZERO_ADDRESS.toLowerCase()) {
|
|
2970
|
+
return c.error({
|
|
2971
|
+
code: "POOL_NOT_FOUND",
|
|
2972
|
+
message: `No ${c.options.stable ? "stable" : "volatile"} V2 pool found for pair ${checksumAddress4(
|
|
2973
|
+
tokenIn
|
|
2974
|
+
)}/${checksumAddress4(tokenOut)}.`
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
const amounts = await client.readContract({
|
|
2978
|
+
abi: v2RouterAbi,
|
|
2979
|
+
address: ABOREAN_V2_ADDRESSES.router,
|
|
2980
|
+
functionName: "getAmountsOut",
|
|
2981
|
+
args: [
|
|
2982
|
+
amountInRaw,
|
|
2983
|
+
[
|
|
2984
|
+
{
|
|
2985
|
+
from: tokenIn,
|
|
2986
|
+
to: tokenOut,
|
|
2987
|
+
stable: c.options.stable,
|
|
2988
|
+
factory: ABOREAN_V2_ADDRESSES.poolFactory
|
|
2989
|
+
}
|
|
2990
|
+
]
|
|
2991
|
+
]
|
|
2992
|
+
});
|
|
2993
|
+
const amountOutRaw = amounts[amounts.length - 1] ?? 0n;
|
|
2994
|
+
const amountInDecimal = formatUnits3(amountInRaw, inMeta.decimals);
|
|
2995
|
+
const amountOutDecimal = formatUnits3(amountOutRaw, outMeta.decimals);
|
|
2996
|
+
const ratio = Number(amountOutDecimal) / Number(amountInDecimal);
|
|
2997
|
+
return c.ok({
|
|
2998
|
+
pool: checksumAddress4(poolAddress),
|
|
2999
|
+
stable: c.options.stable,
|
|
3000
|
+
tokenIn: inMeta,
|
|
3001
|
+
tokenOut: outMeta,
|
|
3002
|
+
amountIn: {
|
|
3003
|
+
raw: amountInRaw.toString(),
|
|
3004
|
+
decimal: amountInDecimal
|
|
3005
|
+
},
|
|
3006
|
+
amountOut: {
|
|
3007
|
+
raw: amountOutRaw.toString(),
|
|
3008
|
+
decimal: amountOutDecimal
|
|
3009
|
+
},
|
|
3010
|
+
priceOutPerIn: Number(amountInDecimal) === 0 ? null : finiteOrNull3(ratio)
|
|
3011
|
+
});
|
|
3012
|
+
}
|
|
3013
|
+
});
|
|
3014
|
+
pools.command("fees", {
|
|
3015
|
+
description: "Read V2 fee configuration for a pool address.",
|
|
3016
|
+
args: z4.object({
|
|
3017
|
+
pool: z4.string().describe("Pool address")
|
|
3018
|
+
}),
|
|
3019
|
+
env: env4,
|
|
3020
|
+
output: z4.object({
|
|
3021
|
+
pool: z4.string(),
|
|
3022
|
+
pair: z4.string(),
|
|
3023
|
+
stable: z4.boolean(),
|
|
3024
|
+
activeFee: feeSchema,
|
|
3025
|
+
stableFee: feeSchema,
|
|
3026
|
+
volatileFee: feeSchema
|
|
3027
|
+
}),
|
|
3028
|
+
async run(c) {
|
|
3029
|
+
if (!isAddress3(c.args.pool)) {
|
|
3030
|
+
return c.error({
|
|
3031
|
+
code: "INVALID_ADDRESS",
|
|
3032
|
+
message: `Invalid pool address: "${c.args.pool}". Use a valid 0x-prefixed 20-byte hex address.`
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3036
|
+
const pool = toAddress(c.args.pool);
|
|
3037
|
+
const [token0, token1, stable] = await multicallStrict2(client, [
|
|
3038
|
+
{
|
|
3039
|
+
abi: v2PoolAbi,
|
|
3040
|
+
address: pool,
|
|
3041
|
+
functionName: "token0"
|
|
3042
|
+
},
|
|
3043
|
+
{
|
|
3044
|
+
abi: v2PoolAbi,
|
|
3045
|
+
address: pool,
|
|
3046
|
+
functionName: "token1"
|
|
3047
|
+
},
|
|
3048
|
+
{
|
|
3049
|
+
abi: v2PoolAbi,
|
|
3050
|
+
address: pool,
|
|
3051
|
+
functionName: "stable"
|
|
3052
|
+
}
|
|
3053
|
+
]);
|
|
3054
|
+
const tokenMeta = await readTokenMetadata3(client, [token0, token1]);
|
|
3055
|
+
const token0Meta = tokenMeta.get(token0.toLowerCase()) ?? fallbackTokenMeta(token0);
|
|
3056
|
+
const token1Meta = tokenMeta.get(token1.toLowerCase()) ?? fallbackTokenMeta(token1);
|
|
3057
|
+
const [stableFeeRaw, volatileFeeRaw] = await readPoolFees(client, [
|
|
3058
|
+
{ pool, stable: true },
|
|
3059
|
+
{ pool, stable: false }
|
|
3060
|
+
]);
|
|
3061
|
+
const stableFee = toFeeInfo(stableFeeRaw ?? null);
|
|
3062
|
+
const volatileFee = toFeeInfo(volatileFeeRaw ?? null);
|
|
3063
|
+
return c.ok({
|
|
3064
|
+
pool: checksumAddress4(pool),
|
|
3065
|
+
pair: `${token0Meta.symbol}/${token1Meta.symbol}`,
|
|
3066
|
+
stable,
|
|
3067
|
+
activeFee: stable ? stableFee : volatileFee,
|
|
3068
|
+
stableFee,
|
|
3069
|
+
volatileFee
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
});
|
|
3073
|
+
|
|
3074
|
+
// src/commands/vaults.ts
|
|
3075
|
+
import { checksumAddress as checksumAddress5, isAddress as isAddress4 } from "@spectratools/cli-shared";
|
|
3076
|
+
import { Cli as Cli5, z as z5 } from "incur";
|
|
3077
|
+
var env5 = z5.object({
|
|
3078
|
+
ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
|
|
3079
|
+
});
|
|
3080
|
+
var relayAbi = [
|
|
3081
|
+
{
|
|
3082
|
+
type: "function",
|
|
3083
|
+
name: "name",
|
|
3084
|
+
stateMutability: "view",
|
|
3085
|
+
inputs: [],
|
|
3086
|
+
outputs: [{ type: "string" }]
|
|
3087
|
+
},
|
|
3088
|
+
{
|
|
3089
|
+
type: "function",
|
|
3090
|
+
name: "mTokenId",
|
|
3091
|
+
stateMutability: "view",
|
|
3092
|
+
inputs: [],
|
|
3093
|
+
outputs: [{ type: "uint256" }]
|
|
3094
|
+
},
|
|
3095
|
+
{
|
|
3096
|
+
type: "function",
|
|
3097
|
+
name: "token",
|
|
3098
|
+
stateMutability: "view",
|
|
3099
|
+
inputs: [],
|
|
3100
|
+
outputs: [{ type: "address" }]
|
|
3101
|
+
},
|
|
3102
|
+
{
|
|
3103
|
+
type: "function",
|
|
3104
|
+
name: "keeperLastRun",
|
|
3105
|
+
stateMutability: "view",
|
|
3106
|
+
inputs: [],
|
|
3107
|
+
outputs: [{ type: "uint256" }]
|
|
3108
|
+
}
|
|
3109
|
+
];
|
|
3110
|
+
var erc20Abi = [
|
|
3111
|
+
{
|
|
3112
|
+
type: "function",
|
|
3113
|
+
name: "symbol",
|
|
3114
|
+
stateMutability: "view",
|
|
3115
|
+
inputs: [],
|
|
3116
|
+
outputs: [{ type: "string" }]
|
|
3117
|
+
},
|
|
3118
|
+
{
|
|
3119
|
+
type: "function",
|
|
3120
|
+
name: "decimals",
|
|
3121
|
+
stateMutability: "view",
|
|
3122
|
+
inputs: [],
|
|
3123
|
+
outputs: [{ type: "uint8" }]
|
|
3124
|
+
},
|
|
3125
|
+
{
|
|
3126
|
+
type: "function",
|
|
3127
|
+
name: "balanceOf",
|
|
3128
|
+
stateMutability: "view",
|
|
3129
|
+
inputs: [{ type: "address", name: "owner" }],
|
|
3130
|
+
outputs: [{ type: "uint256" }]
|
|
3131
|
+
}
|
|
3132
|
+
];
|
|
3133
|
+
var votingEscrowLiteAbi = [
|
|
3134
|
+
{
|
|
3135
|
+
type: "function",
|
|
3136
|
+
name: "balanceOfNFT",
|
|
3137
|
+
stateMutability: "view",
|
|
3138
|
+
inputs: [{ type: "uint256", name: "tokenId" }],
|
|
3139
|
+
outputs: [{ type: "uint256" }]
|
|
3140
|
+
}
|
|
3141
|
+
];
|
|
3142
|
+
var relayRowSchema = z5.object({
|
|
3143
|
+
label: z5.string(),
|
|
3144
|
+
relay: z5.string(),
|
|
3145
|
+
name: z5.string(),
|
|
3146
|
+
factoryType: z5.enum(["autoCompounder", "autoConverter"]),
|
|
3147
|
+
managedTokenId: z5.string(),
|
|
3148
|
+
managedVotingPower: z5.string(),
|
|
3149
|
+
relayToken: z5.object({
|
|
3150
|
+
address: z5.string(),
|
|
3151
|
+
symbol: z5.string(),
|
|
3152
|
+
decimals: z5.number()
|
|
3153
|
+
}),
|
|
3154
|
+
relayTokenBalance: z5.string(),
|
|
3155
|
+
keeperLastRun: z5.number(),
|
|
3156
|
+
keeperLastRunRelative: z5.string(),
|
|
3157
|
+
secondsSinceKeeperRun: z5.number()
|
|
3158
|
+
});
|
|
3159
|
+
var KNOWN_RELAYS = [
|
|
3160
|
+
{
|
|
3161
|
+
label: "veABX Maxi Relay",
|
|
3162
|
+
relay: checksumAddress5(ABOREAN_VAULT_ADDRESSES.veAbxMaxiRelay),
|
|
3163
|
+
factoryType: "autoCompounder"
|
|
3164
|
+
},
|
|
3165
|
+
{
|
|
3166
|
+
label: "ABX Rewards Relay",
|
|
3167
|
+
relay: checksumAddress5(ABOREAN_VAULT_ADDRESSES.abxRewardsRelay),
|
|
3168
|
+
factoryType: "autoConverter"
|
|
3169
|
+
}
|
|
3170
|
+
];
|
|
3171
|
+
function shortAddress4(address) {
|
|
3172
|
+
return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
3173
|
+
}
|
|
3174
|
+
async function readRelaySnapshot(client, relay) {
|
|
3175
|
+
const [name, managedTokenId, relayTokenAddress, keeperLastRun] = await Promise.all([
|
|
3176
|
+
client.readContract({
|
|
3177
|
+
abi: relayAbi,
|
|
3178
|
+
address: relay.relay,
|
|
3179
|
+
functionName: "name"
|
|
3180
|
+
}),
|
|
3181
|
+
client.readContract({
|
|
3182
|
+
abi: relayAbi,
|
|
3183
|
+
address: relay.relay,
|
|
3184
|
+
functionName: "mTokenId"
|
|
3185
|
+
}),
|
|
3186
|
+
client.readContract({
|
|
3187
|
+
abi: relayAbi,
|
|
3188
|
+
address: relay.relay,
|
|
3189
|
+
functionName: "token"
|
|
3190
|
+
}),
|
|
3191
|
+
client.readContract({
|
|
3192
|
+
abi: relayAbi,
|
|
3193
|
+
address: relay.relay,
|
|
3194
|
+
functionName: "keeperLastRun"
|
|
3195
|
+
})
|
|
3196
|
+
]);
|
|
3197
|
+
const tokenAddress = checksumAddress5(relayTokenAddress);
|
|
3198
|
+
const [symbol, decimals, relayTokenBalance, managedVotingPower] = await Promise.all([
|
|
3199
|
+
client.readContract({
|
|
3200
|
+
abi: erc20Abi,
|
|
3201
|
+
address: tokenAddress,
|
|
3202
|
+
functionName: "symbol"
|
|
3203
|
+
}),
|
|
3204
|
+
client.readContract({
|
|
3205
|
+
abi: erc20Abi,
|
|
3206
|
+
address: tokenAddress,
|
|
3207
|
+
functionName: "decimals"
|
|
3208
|
+
}),
|
|
3209
|
+
client.readContract({
|
|
3210
|
+
abi: erc20Abi,
|
|
3211
|
+
address: tokenAddress,
|
|
3212
|
+
functionName: "balanceOf",
|
|
3213
|
+
args: [relay.relay]
|
|
3214
|
+
}),
|
|
3215
|
+
client.readContract({
|
|
3216
|
+
abi: votingEscrowLiteAbi,
|
|
3217
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3218
|
+
functionName: "balanceOfNFT",
|
|
3219
|
+
args: [managedTokenId]
|
|
3220
|
+
})
|
|
3221
|
+
]);
|
|
3222
|
+
const keeperTs = asNum(keeperLastRun);
|
|
3223
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
3224
|
+
return {
|
|
3225
|
+
label: relay.label,
|
|
3226
|
+
relay: toChecksum(relay.relay),
|
|
3227
|
+
name,
|
|
3228
|
+
factoryType: relay.factoryType,
|
|
3229
|
+
managedTokenId: managedTokenId.toString(),
|
|
3230
|
+
managedVotingPower: managedVotingPower.toString(),
|
|
3231
|
+
relayToken: {
|
|
3232
|
+
address: toChecksum(tokenAddress),
|
|
3233
|
+
symbol,
|
|
3234
|
+
decimals
|
|
3235
|
+
},
|
|
3236
|
+
relayTokenBalance: relayTokenBalance.toString(),
|
|
3237
|
+
keeperLastRun: keeperTs,
|
|
3238
|
+
keeperLastRunRelative: relTime(keeperLastRun),
|
|
3239
|
+
secondsSinceKeeperRun: Math.max(0, now - keeperTs)
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
async function readVaultSummary(client) {
|
|
3243
|
+
const relays = await Promise.all(KNOWN_RELAYS.map((relay) => readRelaySnapshot(client, relay)));
|
|
3244
|
+
const tokenTotals = /* @__PURE__ */ new Map();
|
|
3245
|
+
let managedVotingPowerTotal = 0n;
|
|
3246
|
+
for (const relay of relays) {
|
|
3247
|
+
managedVotingPowerTotal += BigInt(relay.managedVotingPower);
|
|
3248
|
+
const key = relay.relayToken.address.toLowerCase();
|
|
3249
|
+
const prev = tokenTotals.get(key);
|
|
3250
|
+
const balance = BigInt(relay.relayTokenBalance);
|
|
3251
|
+
if (prev) {
|
|
3252
|
+
prev.balance += balance;
|
|
3253
|
+
continue;
|
|
3254
|
+
}
|
|
3255
|
+
tokenTotals.set(key, {
|
|
3256
|
+
token: relay.relayToken.address,
|
|
3257
|
+
symbol: relay.relayToken.symbol,
|
|
3258
|
+
decimals: relay.relayToken.decimals,
|
|
3259
|
+
balance
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
const relayTokenBalances = [...tokenTotals.values()].map((row) => ({
|
|
3263
|
+
token: row.token,
|
|
3264
|
+
symbol: row.symbol,
|
|
3265
|
+
decimals: row.decimals,
|
|
3266
|
+
balance: row.balance.toString()
|
|
3267
|
+
}));
|
|
3268
|
+
return {
|
|
3269
|
+
relayCount: relays.length,
|
|
3270
|
+
relays,
|
|
3271
|
+
totals: {
|
|
3272
|
+
managedVotingPower: managedVotingPowerTotal.toString(),
|
|
3273
|
+
relayTokenBalances
|
|
3274
|
+
}
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
var vaults = Cli5.create("vaults", {
|
|
3278
|
+
description: "Inspect Aborean relay vaults (auto-compounder / auto-converter)."
|
|
3279
|
+
});
|
|
3280
|
+
vaults.command("list", {
|
|
3281
|
+
description: "List known Aborean relay vaults with keeper and veNFT state.",
|
|
3282
|
+
env: env5,
|
|
3283
|
+
output: z5.object({
|
|
3284
|
+
relayCount: z5.number(),
|
|
3285
|
+
relays: z5.array(relayRowSchema),
|
|
3286
|
+
totals: z5.object({
|
|
3287
|
+
managedVotingPower: z5.string(),
|
|
3288
|
+
relayTokenBalances: z5.array(
|
|
3289
|
+
z5.object({
|
|
3290
|
+
token: z5.string(),
|
|
3291
|
+
symbol: z5.string(),
|
|
3292
|
+
decimals: z5.number(),
|
|
3293
|
+
balance: z5.string()
|
|
3294
|
+
})
|
|
3295
|
+
)
|
|
3296
|
+
})
|
|
3297
|
+
}),
|
|
3298
|
+
examples: [{ description: "List all known vault relays on Abstract" }],
|
|
3299
|
+
async run(c) {
|
|
3300
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3301
|
+
const snapshot = await readVaultSummary(client);
|
|
3302
|
+
return c.ok(snapshot);
|
|
3303
|
+
}
|
|
3304
|
+
});
|
|
3305
|
+
vaults.command("relay", {
|
|
3306
|
+
description: "Inspect one relay vault by address.",
|
|
3307
|
+
args: z5.object({
|
|
3308
|
+
relay: z5.string().describe("Relay vault contract address")
|
|
3309
|
+
}),
|
|
3310
|
+
env: env5,
|
|
3311
|
+
output: relayRowSchema,
|
|
3312
|
+
examples: [
|
|
3313
|
+
{
|
|
3314
|
+
args: { relay: ABOREAN_VAULT_ADDRESSES.veAbxMaxiRelay },
|
|
3315
|
+
description: "Inspect the veABX maxi relay"
|
|
3316
|
+
}
|
|
3317
|
+
],
|
|
3318
|
+
async run(c) {
|
|
3319
|
+
if (!isAddress4(c.args.relay)) {
|
|
3320
|
+
return c.error({
|
|
3321
|
+
code: "INVALID_ARGUMENT",
|
|
3322
|
+
message: "relay must be a valid address"
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
const relayAddress = checksumAddress5(c.args.relay);
|
|
3326
|
+
const known = KNOWN_RELAYS.find(
|
|
3327
|
+
(relay) => relay.relay.toLowerCase() === relayAddress.toLowerCase()
|
|
3328
|
+
);
|
|
3329
|
+
if (!known) {
|
|
3330
|
+
return c.error({
|
|
3331
|
+
code: "NOT_FOUND",
|
|
3332
|
+
message: `relay ${shortAddress4(relayAddress)} is not in the known Aborean vault set`
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3336
|
+
const snapshot = await readRelaySnapshot(client, known);
|
|
3337
|
+
return c.ok(snapshot);
|
|
3338
|
+
}
|
|
3339
|
+
});
|
|
3340
|
+
|
|
3341
|
+
// src/commands/ve.ts
|
|
3342
|
+
import { Cli as Cli6, z as z6 } from "incur";
|
|
3343
|
+
var env6 = z6.object({
|
|
3344
|
+
ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
|
|
3345
|
+
});
|
|
3346
|
+
var ve = Cli6.create("ve", {
|
|
3347
|
+
description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
|
|
3348
|
+
});
|
|
3349
|
+
ve.command("stats", {
|
|
3350
|
+
description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
|
|
3351
|
+
env: env6,
|
|
3352
|
+
output: z6.object({
|
|
3353
|
+
token: z6.string(),
|
|
3354
|
+
totalVotingPower: z6.string(),
|
|
3355
|
+
totalLocked: z6.string(),
|
|
3356
|
+
permanentLocked: z6.string(),
|
|
3357
|
+
epoch: z6.number(),
|
|
3358
|
+
decayBias: z6.string(),
|
|
3359
|
+
decaySlope: z6.string(),
|
|
3360
|
+
lastCheckpointTimestamp: z6.number(),
|
|
3361
|
+
lastCheckpointBlock: z6.number()
|
|
3362
|
+
}),
|
|
3363
|
+
examples: [{ description: "Show global veABX state and decay metrics" }],
|
|
3364
|
+
async run(c) {
|
|
3365
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3366
|
+
const [token, totalVotingPower, totalLocked, permanentLocked, epoch] = await Promise.all([
|
|
3367
|
+
client.readContract({
|
|
3368
|
+
abi: votingEscrowAbi,
|
|
3369
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3370
|
+
functionName: "token"
|
|
3371
|
+
}),
|
|
3372
|
+
client.readContract({
|
|
3373
|
+
abi: votingEscrowAbi,
|
|
3374
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3375
|
+
functionName: "totalSupply"
|
|
3376
|
+
}),
|
|
3377
|
+
client.readContract({
|
|
3378
|
+
abi: votingEscrowAbi,
|
|
3379
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3380
|
+
functionName: "supply"
|
|
3381
|
+
}),
|
|
3382
|
+
client.readContract({
|
|
3383
|
+
abi: votingEscrowAbi,
|
|
3384
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3385
|
+
functionName: "permanentLockBalance"
|
|
3386
|
+
}),
|
|
3387
|
+
client.readContract({
|
|
3388
|
+
abi: votingEscrowAbi,
|
|
3389
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3390
|
+
functionName: "epoch"
|
|
3391
|
+
})
|
|
3392
|
+
]);
|
|
3393
|
+
const point = await client.readContract({
|
|
3394
|
+
abi: votingEscrowAbi,
|
|
3395
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3396
|
+
functionName: "pointHistory",
|
|
3397
|
+
args: [epoch]
|
|
3398
|
+
});
|
|
3399
|
+
return c.ok({
|
|
3400
|
+
token: toChecksum(token),
|
|
3401
|
+
totalVotingPower: totalVotingPower.toString(),
|
|
3402
|
+
totalLocked: totalLocked.toString(),
|
|
3403
|
+
permanentLocked: permanentLocked.toString(),
|
|
3404
|
+
epoch: asNum(epoch),
|
|
3405
|
+
decayBias: point.bias.toString(),
|
|
3406
|
+
decaySlope: point.slope.toString(),
|
|
3407
|
+
lastCheckpointTimestamp: asNum(point.ts),
|
|
3408
|
+
lastCheckpointBlock: asNum(point.blk)
|
|
3409
|
+
});
|
|
3410
|
+
}
|
|
3411
|
+
});
|
|
3412
|
+
ve.command("lock", {
|
|
3413
|
+
description: "Get lock details and voting power for one veNFT token id.",
|
|
3414
|
+
args: z6.object({
|
|
3415
|
+
tokenId: z6.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3416
|
+
}),
|
|
3417
|
+
env: env6,
|
|
3418
|
+
output: z6.object({
|
|
3419
|
+
tokenId: z6.number(),
|
|
3420
|
+
owner: z6.string(),
|
|
3421
|
+
amount: z6.string(),
|
|
3422
|
+
unlockTime: z6.number(),
|
|
3423
|
+
isPermanent: z6.boolean(),
|
|
3424
|
+
votingPower: z6.string()
|
|
3425
|
+
}),
|
|
3426
|
+
examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
|
|
3427
|
+
async run(c) {
|
|
3428
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3429
|
+
const tokenId = BigInt(c.args.tokenId);
|
|
3430
|
+
const [owner, locked, votingPower] = await Promise.all([
|
|
3431
|
+
client.readContract({
|
|
3432
|
+
abi: votingEscrowAbi,
|
|
3433
|
+
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
3434
|
+
functionName: "ownerOf",
|
|
3435
|
+
args: [tokenId]
|
|
3436
|
+
}),
|
|
3437
|
+
client.readContract({
|
|
3438
|
+
abi: votingEscrowAbi,
|
|
1981
3439
|
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
1982
3440
|
functionName: "locked",
|
|
1983
3441
|
args: [tokenId]
|
|
@@ -2001,22 +3459,22 @@ ve.command("lock", {
|
|
|
2001
3459
|
});
|
|
2002
3460
|
ve.command("locks", {
|
|
2003
3461
|
description: "List all veNFT locks owned by an address.",
|
|
2004
|
-
args:
|
|
2005
|
-
address:
|
|
3462
|
+
args: z6.object({
|
|
3463
|
+
address: z6.string().describe("Owner address")
|
|
2006
3464
|
}),
|
|
2007
|
-
env:
|
|
2008
|
-
output:
|
|
2009
|
-
address:
|
|
2010
|
-
locks:
|
|
2011
|
-
|
|
2012
|
-
tokenId:
|
|
2013
|
-
amount:
|
|
2014
|
-
unlockTime:
|
|
2015
|
-
isPermanent:
|
|
2016
|
-
votingPower:
|
|
3465
|
+
env: env6,
|
|
3466
|
+
output: z6.object({
|
|
3467
|
+
address: z6.string(),
|
|
3468
|
+
locks: z6.array(
|
|
3469
|
+
z6.object({
|
|
3470
|
+
tokenId: z6.string(),
|
|
3471
|
+
amount: z6.string(),
|
|
3472
|
+
unlockTime: z6.number(),
|
|
3473
|
+
isPermanent: z6.boolean(),
|
|
3474
|
+
votingPower: z6.string()
|
|
2017
3475
|
})
|
|
2018
3476
|
),
|
|
2019
|
-
count:
|
|
3477
|
+
count: z6.number()
|
|
2020
3478
|
}),
|
|
2021
3479
|
examples: [
|
|
2022
3480
|
{
|
|
@@ -2088,13 +3546,13 @@ ve.command("locks", {
|
|
|
2088
3546
|
});
|
|
2089
3547
|
ve.command("voting-power", {
|
|
2090
3548
|
description: "Get current voting power for one veNFT token id.",
|
|
2091
|
-
args:
|
|
2092
|
-
tokenId:
|
|
3549
|
+
args: z6.object({
|
|
3550
|
+
tokenId: z6.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
2093
3551
|
}),
|
|
2094
|
-
env:
|
|
2095
|
-
output:
|
|
2096
|
-
tokenId:
|
|
2097
|
-
votingPower:
|
|
3552
|
+
env: env6,
|
|
3553
|
+
output: z6.object({
|
|
3554
|
+
tokenId: z6.number(),
|
|
3555
|
+
votingPower: z6.string()
|
|
2098
3556
|
}),
|
|
2099
3557
|
examples: [{ args: { tokenId: 1 }, description: "Get current voting power for veNFT #1" }],
|
|
2100
3558
|
async run(c) {
|
|
@@ -2113,9 +3571,9 @@ ve.command("voting-power", {
|
|
|
2113
3571
|
});
|
|
2114
3572
|
|
|
2115
3573
|
// src/commands/voter.ts
|
|
2116
|
-
import { Cli as
|
|
2117
|
-
var
|
|
2118
|
-
ABSTRACT_RPC_URL:
|
|
3574
|
+
import { Cli as Cli7, z as z7 } from "incur";
|
|
3575
|
+
var env7 = z7.object({
|
|
3576
|
+
ABSTRACT_RPC_URL: z7.string().optional().describe("Abstract RPC URL override")
|
|
2119
3577
|
});
|
|
2120
3578
|
async function discoverPools(client) {
|
|
2121
3579
|
const [v2PoolCount, clPoolCount] = await Promise.all([
|
|
@@ -2154,20 +3612,20 @@ async function discoverPools(client) {
|
|
|
2154
3612
|
]);
|
|
2155
3613
|
return [...v2Pools, ...clPools];
|
|
2156
3614
|
}
|
|
2157
|
-
var voter =
|
|
3615
|
+
var voter = Cli7.create("voter", {
|
|
2158
3616
|
description: "Inspect Aborean voter epoch, pool weights, and claimable rewards context."
|
|
2159
3617
|
});
|
|
2160
3618
|
voter.command("epoch", {
|
|
2161
3619
|
description: "Show current emissions epoch timing from Minter.",
|
|
2162
|
-
env:
|
|
2163
|
-
output:
|
|
2164
|
-
activePeriod:
|
|
2165
|
-
epochEnd:
|
|
2166
|
-
secondsRemaining:
|
|
2167
|
-
timeRemaining:
|
|
2168
|
-
weekSeconds:
|
|
2169
|
-
epochCount:
|
|
2170
|
-
weeklyEmission:
|
|
3620
|
+
env: env7,
|
|
3621
|
+
output: z7.object({
|
|
3622
|
+
activePeriod: z7.number(),
|
|
3623
|
+
epochEnd: z7.number(),
|
|
3624
|
+
secondsRemaining: z7.number(),
|
|
3625
|
+
timeRemaining: z7.string(),
|
|
3626
|
+
weekSeconds: z7.number(),
|
|
3627
|
+
epochCount: z7.number(),
|
|
3628
|
+
weeklyEmission: z7.string()
|
|
2171
3629
|
}),
|
|
2172
3630
|
examples: [{ description: "Inspect current voter epoch boundaries" }],
|
|
2173
3631
|
async run(c) {
|
|
@@ -2209,23 +3667,23 @@ voter.command("epoch", {
|
|
|
2209
3667
|
});
|
|
2210
3668
|
voter.command("weights", {
|
|
2211
3669
|
description: "Show current pool voting weight distribution.",
|
|
2212
|
-
env:
|
|
2213
|
-
output:
|
|
2214
|
-
totalWeight:
|
|
2215
|
-
pools:
|
|
2216
|
-
|
|
2217
|
-
pool:
|
|
2218
|
-
gauge:
|
|
2219
|
-
weight:
|
|
3670
|
+
env: env7,
|
|
3671
|
+
output: z7.object({
|
|
3672
|
+
totalWeight: z7.string(),
|
|
3673
|
+
pools: z7.array(
|
|
3674
|
+
z7.object({
|
|
3675
|
+
pool: z7.string(),
|
|
3676
|
+
gauge: z7.string(),
|
|
3677
|
+
weight: z7.string()
|
|
2220
3678
|
})
|
|
2221
3679
|
),
|
|
2222
|
-
count:
|
|
3680
|
+
count: z7.number()
|
|
2223
3681
|
}),
|
|
2224
3682
|
examples: [{ description: "List all pools with non-zero voting weight" }],
|
|
2225
3683
|
async run(c) {
|
|
2226
3684
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
2227
|
-
const
|
|
2228
|
-
if (!
|
|
3685
|
+
const pools2 = await discoverPools(client);
|
|
3686
|
+
if (!pools2.length) {
|
|
2229
3687
|
return c.ok({ totalWeight: "0", pools: [], count: 0 });
|
|
2230
3688
|
}
|
|
2231
3689
|
const [totalWeight, poolData] = await Promise.all([
|
|
@@ -2236,7 +3694,7 @@ voter.command("weights", {
|
|
|
2236
3694
|
}),
|
|
2237
3695
|
client.multicall({
|
|
2238
3696
|
allowFailure: false,
|
|
2239
|
-
contracts:
|
|
3697
|
+
contracts: pools2.flatMap((pool) => [
|
|
2240
3698
|
{
|
|
2241
3699
|
abi: voterAbi,
|
|
2242
3700
|
address: ABOREAN_V2_ADDRESSES.voter,
|
|
@@ -2252,7 +3710,7 @@ voter.command("weights", {
|
|
|
2252
3710
|
])
|
|
2253
3711
|
})
|
|
2254
3712
|
]);
|
|
2255
|
-
const entries =
|
|
3713
|
+
const entries = pools2.map((pool, index) => {
|
|
2256
3714
|
const offset = index * 2;
|
|
2257
3715
|
const gauge = poolData[offset] ?? ZERO_ADDRESS;
|
|
2258
3716
|
const weight = poolData[offset + 1] ?? 0n;
|
|
@@ -2277,19 +3735,19 @@ voter.command("weights", {
|
|
|
2277
3735
|
});
|
|
2278
3736
|
voter.command("rewards", {
|
|
2279
3737
|
description: "Show claimable rebase rewards and voting context for a veNFT.",
|
|
2280
|
-
args:
|
|
2281
|
-
tokenId:
|
|
3738
|
+
args: z7.object({
|
|
3739
|
+
tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
2282
3740
|
}),
|
|
2283
|
-
env:
|
|
2284
|
-
output:
|
|
2285
|
-
tokenId:
|
|
2286
|
-
rewardToken:
|
|
2287
|
-
claimableRebase:
|
|
2288
|
-
timeCursor:
|
|
2289
|
-
lastTokenTime:
|
|
2290
|
-
distributorStartTime:
|
|
2291
|
-
usedWeight:
|
|
2292
|
-
lastVoted:
|
|
3741
|
+
env: env7,
|
|
3742
|
+
output: z7.object({
|
|
3743
|
+
tokenId: z7.number(),
|
|
3744
|
+
rewardToken: z7.string(),
|
|
3745
|
+
claimableRebase: z7.string(),
|
|
3746
|
+
timeCursor: z7.number(),
|
|
3747
|
+
lastTokenTime: z7.number(),
|
|
3748
|
+
distributorStartTime: z7.number(),
|
|
3749
|
+
usedWeight: z7.string(),
|
|
3750
|
+
lastVoted: z7.number()
|
|
2293
3751
|
}),
|
|
2294
3752
|
examples: [{ args: { tokenId: 1 }, description: "Check claimable voter/distributor rewards" }],
|
|
2295
3753
|
async run(c) {
|
|
@@ -2358,22 +3816,22 @@ voter.command("rewards", {
|
|
|
2358
3816
|
});
|
|
2359
3817
|
voter.command("bribes", {
|
|
2360
3818
|
description: "Show active bribe reward tokens and current-epoch amounts for a pool.",
|
|
2361
|
-
args:
|
|
2362
|
-
pool:
|
|
3819
|
+
args: z7.object({
|
|
3820
|
+
pool: z7.string().describe("Pool address")
|
|
2363
3821
|
}),
|
|
2364
|
-
env:
|
|
2365
|
-
output:
|
|
2366
|
-
pool:
|
|
2367
|
-
gauge:
|
|
2368
|
-
bribeContract:
|
|
2369
|
-
epochStart:
|
|
2370
|
-
rewardTokens:
|
|
2371
|
-
|
|
2372
|
-
token:
|
|
2373
|
-
epochAmount:
|
|
3822
|
+
env: env7,
|
|
3823
|
+
output: z7.object({
|
|
3824
|
+
pool: z7.string(),
|
|
3825
|
+
gauge: z7.string(),
|
|
3826
|
+
bribeContract: z7.string(),
|
|
3827
|
+
epochStart: z7.number(),
|
|
3828
|
+
rewardTokens: z7.array(
|
|
3829
|
+
z7.object({
|
|
3830
|
+
token: z7.string(),
|
|
3831
|
+
epochAmount: z7.string()
|
|
2374
3832
|
})
|
|
2375
3833
|
),
|
|
2376
|
-
count:
|
|
3834
|
+
count: z7.number()
|
|
2377
3835
|
}),
|
|
2378
3836
|
examples: [
|
|
2379
3837
|
{
|
|
@@ -2599,27 +4057,283 @@ function applyFriendlyErrorHandling(cli2) {
|
|
|
2599
4057
|
// src/cli.ts
|
|
2600
4058
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
2601
4059
|
var pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
|
|
2602
|
-
var cli =
|
|
4060
|
+
var cli = Cli8.create("aborean", {
|
|
2603
4061
|
version: pkg.version,
|
|
2604
4062
|
description: "Aborean Finance DEX CLI for Abstract chain."
|
|
2605
4063
|
});
|
|
2606
4064
|
cli.command(gauges);
|
|
4065
|
+
cli.command(pools);
|
|
2607
4066
|
cli.command(ve);
|
|
2608
4067
|
cli.command(voter);
|
|
2609
|
-
var rootEnv = z5.object({
|
|
2610
|
-
ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
|
|
2611
|
-
});
|
|
2612
4068
|
cli.command(cl);
|
|
4069
|
+
cli.command(vaults);
|
|
4070
|
+
cli.command(lending);
|
|
4071
|
+
var rootEnv = z8.object({
|
|
4072
|
+
ABSTRACT_RPC_URL: z8.string().optional().describe("Abstract RPC URL override")
|
|
4073
|
+
});
|
|
4074
|
+
var erc20MetadataAbi4 = [
|
|
4075
|
+
{
|
|
4076
|
+
type: "function",
|
|
4077
|
+
name: "symbol",
|
|
4078
|
+
stateMutability: "view",
|
|
4079
|
+
inputs: [],
|
|
4080
|
+
outputs: [{ type: "string" }]
|
|
4081
|
+
},
|
|
4082
|
+
{
|
|
4083
|
+
type: "function",
|
|
4084
|
+
name: "decimals",
|
|
4085
|
+
stateMutability: "view",
|
|
4086
|
+
inputs: [],
|
|
4087
|
+
outputs: [{ type: "uint8" }]
|
|
4088
|
+
}
|
|
4089
|
+
];
|
|
4090
|
+
var v2PoolLiteAbi = [
|
|
4091
|
+
{
|
|
4092
|
+
type: "function",
|
|
4093
|
+
name: "token0",
|
|
4094
|
+
stateMutability: "view",
|
|
4095
|
+
inputs: [],
|
|
4096
|
+
outputs: [{ type: "address" }]
|
|
4097
|
+
},
|
|
4098
|
+
{
|
|
4099
|
+
type: "function",
|
|
4100
|
+
name: "token1",
|
|
4101
|
+
stateMutability: "view",
|
|
4102
|
+
inputs: [],
|
|
4103
|
+
outputs: [{ type: "address" }]
|
|
4104
|
+
},
|
|
4105
|
+
{
|
|
4106
|
+
type: "function",
|
|
4107
|
+
name: "stable",
|
|
4108
|
+
stateMutability: "view",
|
|
4109
|
+
inputs: [],
|
|
4110
|
+
outputs: [{ type: "bool" }]
|
|
4111
|
+
},
|
|
4112
|
+
{
|
|
4113
|
+
type: "function",
|
|
4114
|
+
name: "getReserves",
|
|
4115
|
+
stateMutability: "view",
|
|
4116
|
+
inputs: [],
|
|
4117
|
+
outputs: [
|
|
4118
|
+
{ type: "uint256", name: "reserve0" },
|
|
4119
|
+
{ type: "uint256", name: "reserve1" },
|
|
4120
|
+
{ type: "uint256", name: "blockTimestampLast" }
|
|
4121
|
+
]
|
|
4122
|
+
}
|
|
4123
|
+
];
|
|
4124
|
+
function finiteOrZero(value) {
|
|
4125
|
+
return Number.isFinite(value) ? value : 0;
|
|
4126
|
+
}
|
|
4127
|
+
function shortAddress5(address) {
|
|
4128
|
+
return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
4129
|
+
}
|
|
4130
|
+
function normalizeReserveTuple(value) {
|
|
4131
|
+
if (Array.isArray(value)) {
|
|
4132
|
+
return {
|
|
4133
|
+
reserve0: BigInt(value[0]),
|
|
4134
|
+
reserve1: BigInt(value[1])
|
|
4135
|
+
};
|
|
4136
|
+
}
|
|
4137
|
+
const row = value;
|
|
4138
|
+
return {
|
|
4139
|
+
reserve0: BigInt(row.reserve0),
|
|
4140
|
+
reserve1: BigInt(row.reserve1)
|
|
4141
|
+
};
|
|
4142
|
+
}
|
|
4143
|
+
async function readTokenMetadata4(client, tokenAddresses) {
|
|
4144
|
+
const unique = [...new Set(tokenAddresses.map((address) => address.toLowerCase()))];
|
|
4145
|
+
if (!unique.length) {
|
|
4146
|
+
return /* @__PURE__ */ new Map();
|
|
4147
|
+
}
|
|
4148
|
+
const contracts = unique.flatMap((address) => [
|
|
4149
|
+
{
|
|
4150
|
+
abi: erc20MetadataAbi4,
|
|
4151
|
+
address,
|
|
4152
|
+
functionName: "symbol"
|
|
4153
|
+
},
|
|
4154
|
+
{
|
|
4155
|
+
abi: erc20MetadataAbi4,
|
|
4156
|
+
address,
|
|
4157
|
+
functionName: "decimals"
|
|
4158
|
+
}
|
|
4159
|
+
]);
|
|
4160
|
+
const results = await client.multicall({
|
|
4161
|
+
allowFailure: true,
|
|
4162
|
+
contracts
|
|
4163
|
+
});
|
|
4164
|
+
const map = /* @__PURE__ */ new Map();
|
|
4165
|
+
for (let i = 0; i < unique.length; i += 1) {
|
|
4166
|
+
const address = checksumAddress6(unique[i]);
|
|
4167
|
+
const symbolResult = results[i * 2];
|
|
4168
|
+
const decimalsResult = results[i * 2 + 1];
|
|
4169
|
+
const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : shortAddress5(address);
|
|
4170
|
+
const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : 18;
|
|
4171
|
+
map.set(address.toLowerCase(), {
|
|
4172
|
+
address,
|
|
4173
|
+
symbol,
|
|
4174
|
+
decimals
|
|
4175
|
+
});
|
|
4176
|
+
}
|
|
4177
|
+
return map;
|
|
4178
|
+
}
|
|
4179
|
+
async function readTopV2PoolsSnapshot(client, limit) {
|
|
4180
|
+
const v2PoolCount = await client.readContract({
|
|
4181
|
+
abi: poolFactoryAbi,
|
|
4182
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
4183
|
+
functionName: "allPoolsLength"
|
|
4184
|
+
});
|
|
4185
|
+
if (v2PoolCount === 0n) {
|
|
4186
|
+
return { topPools: [], reserveUnitTvl: 0 };
|
|
4187
|
+
}
|
|
4188
|
+
const indices = Array.from({ length: Number(v2PoolCount) }, (_, i) => BigInt(i));
|
|
4189
|
+
const pools2 = await client.multicall({
|
|
4190
|
+
allowFailure: false,
|
|
4191
|
+
contracts: indices.map((index) => ({
|
|
4192
|
+
abi: poolFactoryAbi,
|
|
4193
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
4194
|
+
functionName: "allPools",
|
|
4195
|
+
args: [index]
|
|
4196
|
+
}))
|
|
4197
|
+
});
|
|
4198
|
+
const poolData = await client.multicall({
|
|
4199
|
+
allowFailure: false,
|
|
4200
|
+
contracts: pools2.flatMap((pool) => [
|
|
4201
|
+
{
|
|
4202
|
+
abi: v2PoolLiteAbi,
|
|
4203
|
+
address: pool,
|
|
4204
|
+
functionName: "token0"
|
|
4205
|
+
},
|
|
4206
|
+
{
|
|
4207
|
+
abi: v2PoolLiteAbi,
|
|
4208
|
+
address: pool,
|
|
4209
|
+
functionName: "token1"
|
|
4210
|
+
},
|
|
4211
|
+
{
|
|
4212
|
+
abi: v2PoolLiteAbi,
|
|
4213
|
+
address: pool,
|
|
4214
|
+
functionName: "stable"
|
|
4215
|
+
},
|
|
4216
|
+
{
|
|
4217
|
+
abi: v2PoolLiteAbi,
|
|
4218
|
+
address: pool,
|
|
4219
|
+
functionName: "getReserves"
|
|
4220
|
+
}
|
|
4221
|
+
])
|
|
4222
|
+
});
|
|
4223
|
+
const tokenAddresses = [];
|
|
4224
|
+
for (let i = 0; i < pools2.length; i += 1) {
|
|
4225
|
+
tokenAddresses.push(checksumAddress6(poolData[i * 4]));
|
|
4226
|
+
tokenAddresses.push(checksumAddress6(poolData[i * 4 + 1]));
|
|
4227
|
+
}
|
|
4228
|
+
const tokenMeta = await readTokenMetadata4(client, tokenAddresses);
|
|
4229
|
+
const rows = pools2.map((pool, index) => {
|
|
4230
|
+
const token0Address = checksumAddress6(poolData[index * 4]);
|
|
4231
|
+
const token1Address = checksumAddress6(poolData[index * 4 + 1]);
|
|
4232
|
+
const stable = Boolean(poolData[index * 4 + 2]);
|
|
4233
|
+
const reserves = normalizeReserveTuple(poolData[index * 4 + 3]);
|
|
4234
|
+
const token0 = tokenMeta.get(token0Address.toLowerCase()) ?? {
|
|
4235
|
+
address: token0Address,
|
|
4236
|
+
symbol: shortAddress5(token0Address),
|
|
4237
|
+
decimals: 18
|
|
4238
|
+
};
|
|
4239
|
+
const token1 = tokenMeta.get(token1Address.toLowerCase()) ?? {
|
|
4240
|
+
address: token1Address,
|
|
4241
|
+
symbol: shortAddress5(token1Address),
|
|
4242
|
+
decimals: 18
|
|
4243
|
+
};
|
|
4244
|
+
const reserve0Decimal = finiteOrZero(Number(formatUnits4(reserves.reserve0, token0.decimals)));
|
|
4245
|
+
const reserve1Decimal = finiteOrZero(Number(formatUnits4(reserves.reserve1, token1.decimals)));
|
|
4246
|
+
const tvlUnits = reserve0Decimal + reserve1Decimal;
|
|
4247
|
+
return {
|
|
4248
|
+
pool: checksumAddress6(pool),
|
|
4249
|
+
pair: `${token0.symbol}/${token1.symbol}`,
|
|
4250
|
+
poolType: stable ? "stable" : "volatile",
|
|
4251
|
+
token0: {
|
|
4252
|
+
address: checksumAddress6(token0.address),
|
|
4253
|
+
symbol: token0.symbol,
|
|
4254
|
+
decimals: token0.decimals
|
|
4255
|
+
},
|
|
4256
|
+
token1: {
|
|
4257
|
+
address: checksumAddress6(token1.address),
|
|
4258
|
+
symbol: token1.symbol,
|
|
4259
|
+
decimals: token1.decimals
|
|
4260
|
+
},
|
|
4261
|
+
reserves: {
|
|
4262
|
+
token0: formatUnits4(reserves.reserve0, token0.decimals),
|
|
4263
|
+
token1: formatUnits4(reserves.reserve1, token1.decimals)
|
|
4264
|
+
},
|
|
4265
|
+
tvlEstimateUnits: tvlUnits
|
|
4266
|
+
};
|
|
4267
|
+
});
|
|
4268
|
+
const reserveUnitTvl = rows.reduce((sum, row) => sum + Number(row.tvlEstimateUnits), 0);
|
|
4269
|
+
return {
|
|
4270
|
+
topPools: rows.sort((a, b) => Number(b.tvlEstimateUnits) - Number(a.tvlEstimateUnits)).slice(0, limit),
|
|
4271
|
+
reserveUnitTvl
|
|
4272
|
+
};
|
|
4273
|
+
}
|
|
2613
4274
|
cli.command("status", {
|
|
2614
|
-
description: "
|
|
4275
|
+
description: "Cross-protocol Aborean snapshot (TVL estimates, epoch, top pools, ve lock, vaults, Morpho lending).",
|
|
2615
4276
|
env: rootEnv,
|
|
2616
|
-
output:
|
|
2617
|
-
v2PoolCount:
|
|
2618
|
-
clPoolCount:
|
|
2619
|
-
gaugeCount:
|
|
2620
|
-
totalVotingWeight:
|
|
2621
|
-
veABXTotalSupply:
|
|
2622
|
-
veABXLockedSupply:
|
|
4277
|
+
output: z8.object({
|
|
4278
|
+
v2PoolCount: z8.number().describe("Number of V2 AMM pools"),
|
|
4279
|
+
clPoolCount: z8.number().describe("Number of Slipstream (CL) pools"),
|
|
4280
|
+
gaugeCount: z8.number().describe("Number of pools with gauges"),
|
|
4281
|
+
totalVotingWeight: z8.string().describe("Total voting weight (wei)"),
|
|
4282
|
+
veABXTotalSupply: z8.string().describe("Total veABX supply (wei)"),
|
|
4283
|
+
veABXLockedSupply: z8.string().describe("Total ABX locked in VotingEscrow (wei)"),
|
|
4284
|
+
epoch: z8.object({
|
|
4285
|
+
activePeriod: z8.number(),
|
|
4286
|
+
epochEnd: z8.number(),
|
|
4287
|
+
secondsRemaining: z8.number(),
|
|
4288
|
+
epochCount: z8.number(),
|
|
4289
|
+
weeklyEmission: z8.string()
|
|
4290
|
+
}),
|
|
4291
|
+
topPools: z8.array(
|
|
4292
|
+
z8.object({
|
|
4293
|
+
pool: z8.string(),
|
|
4294
|
+
pair: z8.string(),
|
|
4295
|
+
poolType: z8.enum(["stable", "volatile"]),
|
|
4296
|
+
token0: z8.object({
|
|
4297
|
+
address: z8.string(),
|
|
4298
|
+
symbol: z8.string(),
|
|
4299
|
+
decimals: z8.number()
|
|
4300
|
+
}),
|
|
4301
|
+
token1: z8.object({
|
|
4302
|
+
address: z8.string(),
|
|
4303
|
+
symbol: z8.string(),
|
|
4304
|
+
decimals: z8.number()
|
|
4305
|
+
}),
|
|
4306
|
+
reserves: z8.object({
|
|
4307
|
+
token0: z8.string(),
|
|
4308
|
+
token1: z8.string()
|
|
4309
|
+
}),
|
|
4310
|
+
tvlEstimateUnits: z8.number()
|
|
4311
|
+
})
|
|
4312
|
+
),
|
|
4313
|
+
tvl: z8.object({
|
|
4314
|
+
v2ReserveUnitEstimate: z8.number(),
|
|
4315
|
+
vaultManagedVotingPower: z8.string()
|
|
4316
|
+
}),
|
|
4317
|
+
vaults: z8.object({
|
|
4318
|
+
relayCount: z8.number(),
|
|
4319
|
+
managedVotingPower: z8.string(),
|
|
4320
|
+
note: z8.string().nullable()
|
|
4321
|
+
}),
|
|
4322
|
+
lending: z8.object({
|
|
4323
|
+
available: z8.boolean(),
|
|
4324
|
+
morpho: z8.string(),
|
|
4325
|
+
marketCount: z8.number(),
|
|
4326
|
+
supplyByLoanToken: z8.array(
|
|
4327
|
+
z8.object({
|
|
4328
|
+
token: z8.string(),
|
|
4329
|
+
symbol: z8.string(),
|
|
4330
|
+
decimals: z8.number(),
|
|
4331
|
+
totalSupplyAssets: z8.string(),
|
|
4332
|
+
totalBorrowAssets: z8.string()
|
|
4333
|
+
})
|
|
4334
|
+
),
|
|
4335
|
+
note: z8.string().nullable()
|
|
4336
|
+
})
|
|
2623
4337
|
}),
|
|
2624
4338
|
examples: [{ description: "Fetch the current Aborean protocol status" }],
|
|
2625
4339
|
async run(c) {
|
|
@@ -2630,7 +4344,12 @@ cli.command("status", {
|
|
|
2630
4344
|
gaugeCount,
|
|
2631
4345
|
totalVotingWeight,
|
|
2632
4346
|
veABXTotalSupply,
|
|
2633
|
-
veABXLockedSupply
|
|
4347
|
+
veABXLockedSupply,
|
|
4348
|
+
activePeriod,
|
|
4349
|
+
weekSeconds,
|
|
4350
|
+
epochCount,
|
|
4351
|
+
weeklyEmission,
|
|
4352
|
+
v2PoolSnapshot
|
|
2634
4353
|
] = await Promise.all([
|
|
2635
4354
|
client.readContract({
|
|
2636
4355
|
abi: poolFactoryAbi,
|
|
@@ -2661,15 +4380,87 @@ cli.command("status", {
|
|
|
2661
4380
|
abi: votingEscrowAbi,
|
|
2662
4381
|
address: ABOREAN_V2_ADDRESSES.votingEscrow,
|
|
2663
4382
|
functionName: "supply"
|
|
2664
|
-
})
|
|
4383
|
+
}),
|
|
4384
|
+
client.readContract({
|
|
4385
|
+
abi: minterAbi,
|
|
4386
|
+
address: ABOREAN_V2_ADDRESSES.minter,
|
|
4387
|
+
functionName: "activePeriod"
|
|
4388
|
+
}),
|
|
4389
|
+
client.readContract({
|
|
4390
|
+
abi: minterAbi,
|
|
4391
|
+
address: ABOREAN_V2_ADDRESSES.minter,
|
|
4392
|
+
functionName: "WEEK"
|
|
4393
|
+
}),
|
|
4394
|
+
client.readContract({
|
|
4395
|
+
abi: minterAbi,
|
|
4396
|
+
address: ABOREAN_V2_ADDRESSES.minter,
|
|
4397
|
+
functionName: "epochCount"
|
|
4398
|
+
}),
|
|
4399
|
+
client.readContract({
|
|
4400
|
+
abi: minterAbi,
|
|
4401
|
+
address: ABOREAN_V2_ADDRESSES.minter,
|
|
4402
|
+
functionName: "weekly"
|
|
4403
|
+
}),
|
|
4404
|
+
readTopV2PoolsSnapshot(client, 5)
|
|
2665
4405
|
]);
|
|
4406
|
+
let vaultRelayCount = 0;
|
|
4407
|
+
let vaultManagedVotingPower = "0";
|
|
4408
|
+
let vaultNote = null;
|
|
4409
|
+
try {
|
|
4410
|
+
const vaultSnapshot = await readVaultSummary(client);
|
|
4411
|
+
vaultRelayCount = vaultSnapshot.relayCount;
|
|
4412
|
+
vaultManagedVotingPower = vaultSnapshot.totals.managedVotingPower;
|
|
4413
|
+
} catch (error) {
|
|
4414
|
+
vaultNote = error instanceof Error ? error.message : "vault snapshot unavailable";
|
|
4415
|
+
}
|
|
4416
|
+
let lendingAvailable = false;
|
|
4417
|
+
let lendingMarketCount = 0;
|
|
4418
|
+
let lendingMorpho = "";
|
|
4419
|
+
let lendingSupplyByLoanToken = [];
|
|
4420
|
+
let lendingNote = null;
|
|
4421
|
+
try {
|
|
4422
|
+
const lendingSnapshot = await readLendingSummary(client);
|
|
4423
|
+
lendingAvailable = lendingSnapshot.available;
|
|
4424
|
+
lendingMarketCount = lendingSnapshot.marketCount;
|
|
4425
|
+
lendingMorpho = lendingSnapshot.morpho;
|
|
4426
|
+
lendingSupplyByLoanToken = lendingSnapshot.supplyByLoanToken;
|
|
4427
|
+
} catch (error) {
|
|
4428
|
+
lendingMorpho = "";
|
|
4429
|
+
lendingNote = error instanceof Error ? error.message : "lending snapshot unavailable";
|
|
4430
|
+
}
|
|
4431
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
4432
|
+
const epochEnd = Number(activePeriod) + Number(weekSeconds);
|
|
2666
4433
|
return c.ok({
|
|
2667
4434
|
v2PoolCount: Number(v2PoolCount),
|
|
2668
4435
|
clPoolCount: Number(clPoolCount),
|
|
2669
4436
|
gaugeCount: Number(gaugeCount),
|
|
2670
4437
|
totalVotingWeight: String(totalVotingWeight),
|
|
2671
4438
|
veABXTotalSupply: String(veABXTotalSupply),
|
|
2672
|
-
veABXLockedSupply: String(veABXLockedSupply)
|
|
4439
|
+
veABXLockedSupply: String(veABXLockedSupply),
|
|
4440
|
+
epoch: {
|
|
4441
|
+
activePeriod: Number(activePeriod),
|
|
4442
|
+
epochEnd,
|
|
4443
|
+
secondsRemaining: Math.max(0, epochEnd - now),
|
|
4444
|
+
epochCount: Number(epochCount),
|
|
4445
|
+
weeklyEmission: String(weeklyEmission)
|
|
4446
|
+
},
|
|
4447
|
+
topPools: v2PoolSnapshot.topPools,
|
|
4448
|
+
tvl: {
|
|
4449
|
+
v2ReserveUnitEstimate: v2PoolSnapshot.reserveUnitTvl,
|
|
4450
|
+
vaultManagedVotingPower
|
|
4451
|
+
},
|
|
4452
|
+
vaults: {
|
|
4453
|
+
relayCount: vaultRelayCount,
|
|
4454
|
+
managedVotingPower: vaultManagedVotingPower,
|
|
4455
|
+
note: vaultNote
|
|
4456
|
+
},
|
|
4457
|
+
lending: {
|
|
4458
|
+
available: lendingAvailable,
|
|
4459
|
+
morpho: lendingMorpho,
|
|
4460
|
+
marketCount: lendingMarketCount,
|
|
4461
|
+
supplyByLoanToken: lendingSupplyByLoanToken,
|
|
4462
|
+
note: lendingNote
|
|
4463
|
+
}
|
|
2673
4464
|
});
|
|
2674
4465
|
}
|
|
2675
4466
|
});
|