@spectratools/aborean-cli 0.6.0 → 0.9.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 +1668 -652
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -5,12 +5,12 @@ import { readFileSync } from "fs";
|
|
|
5
5
|
import { dirname, resolve } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import { checksumAddress as checksumAddress6 } from "@spectratools/cli-shared";
|
|
8
|
-
import { Cli as Cli8, z as
|
|
8
|
+
import { Cli as Cli8, z as z9 } from "incur";
|
|
9
9
|
import { formatUnits as formatUnits4 } from "viem";
|
|
10
10
|
|
|
11
11
|
// src/commands/cl.ts
|
|
12
|
-
import { checksumAddress, isAddress } from "@spectratools/cli-shared";
|
|
13
|
-
import { Cli, z } from "incur";
|
|
12
|
+
import { checksumAddress as checksumAddress2, isAddress } from "@spectratools/cli-shared";
|
|
13
|
+
import { Cli, z as z2 } from "incur";
|
|
14
14
|
import { formatUnits, parseUnits } from "viem";
|
|
15
15
|
|
|
16
16
|
// src/contracts/abis/CLFactory.abi.json
|
|
@@ -560,6 +560,47 @@ var RewardsDistributor_abi_default = [
|
|
|
560
560
|
}
|
|
561
561
|
];
|
|
562
562
|
|
|
563
|
+
// src/contracts/abis/SwapRouter.abi.json
|
|
564
|
+
var SwapRouter_abi_default = [
|
|
565
|
+
{
|
|
566
|
+
type: "function",
|
|
567
|
+
name: "exactInputSingle",
|
|
568
|
+
inputs: [
|
|
569
|
+
{
|
|
570
|
+
name: "params",
|
|
571
|
+
type: "tuple",
|
|
572
|
+
internalType: "struct ISwapRouter.ExactInputSingleParams",
|
|
573
|
+
components: [
|
|
574
|
+
{ name: "tokenIn", type: "address", internalType: "address" },
|
|
575
|
+
{ name: "tokenOut", type: "address", internalType: "address" },
|
|
576
|
+
{ name: "tickSpacing", type: "int24", internalType: "int24" },
|
|
577
|
+
{ name: "recipient", type: "address", internalType: "address" },
|
|
578
|
+
{ name: "deadline", type: "uint256", internalType: "uint256" },
|
|
579
|
+
{ name: "amountIn", type: "uint256", internalType: "uint256" },
|
|
580
|
+
{ name: "amountOutMinimum", type: "uint256", internalType: "uint256" },
|
|
581
|
+
{ name: "sqrtPriceLimitX96", type: "uint160", internalType: "uint160" }
|
|
582
|
+
]
|
|
583
|
+
}
|
|
584
|
+
],
|
|
585
|
+
outputs: [{ name: "amountOut", type: "uint256", internalType: "uint256" }],
|
|
586
|
+
stateMutability: "payable"
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
type: "function",
|
|
590
|
+
name: "factory",
|
|
591
|
+
inputs: [],
|
|
592
|
+
outputs: [{ name: "", type: "address", internalType: "address" }],
|
|
593
|
+
stateMutability: "view"
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
type: "function",
|
|
597
|
+
name: "WETH9",
|
|
598
|
+
inputs: [],
|
|
599
|
+
outputs: [{ name: "", type: "address", internalType: "address" }],
|
|
600
|
+
stateMutability: "view"
|
|
601
|
+
}
|
|
602
|
+
];
|
|
603
|
+
|
|
563
604
|
// src/contracts/abis/V2Pool.abi.json
|
|
564
605
|
var V2Pool_abi_default = [
|
|
565
606
|
{
|
|
@@ -947,6 +988,7 @@ var nonfungiblePositionManagerAbi = NonfungiblePositionManager_abi_default;
|
|
|
947
988
|
var poolFactoryAbi = PoolFactory_abi_default;
|
|
948
989
|
var quoterV2Abi = QuoterV2_abi_default;
|
|
949
990
|
var rewardsDistributorAbi = RewardsDistributor_abi_default;
|
|
991
|
+
var swapRouterAbi = SwapRouter_abi_default;
|
|
950
992
|
var v2PoolAbi = V2Pool_abi_default;
|
|
951
993
|
var v2RouterAbi = V2Router_abi_default;
|
|
952
994
|
var voterAbi = Voter_abi_default;
|
|
@@ -1032,7 +1074,12 @@ var ABOREAN_ADDRESSES = {
|
|
|
1032
1074
|
};
|
|
1033
1075
|
|
|
1034
1076
|
// src/contracts/client.ts
|
|
1035
|
-
import {
|
|
1077
|
+
import {
|
|
1078
|
+
http,
|
|
1079
|
+
createPublicClient,
|
|
1080
|
+
createWalletClient,
|
|
1081
|
+
defineChain
|
|
1082
|
+
} from "viem";
|
|
1036
1083
|
var abstractMainnet = defineChain({
|
|
1037
1084
|
id: 2741,
|
|
1038
1085
|
name: "Abstract Mainnet",
|
|
@@ -1053,63 +1100,174 @@ function createAboreanPublicClient(rpcUrl) {
|
|
|
1053
1100
|
transport: http(rpcUrl ?? process.env.ABSTRACT_RPC_URL ?? "https://api.mainnet.abs.xyz")
|
|
1054
1101
|
});
|
|
1055
1102
|
}
|
|
1103
|
+
function createAboreanWalletClient(account, rpcUrl) {
|
|
1104
|
+
return createWalletClient({
|
|
1105
|
+
account,
|
|
1106
|
+
chain: abstractMainnet,
|
|
1107
|
+
transport: http(rpcUrl ?? process.env.ABSTRACT_RPC_URL ?? "https://api.mainnet.abs.xyz")
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/commands/_write-utils.ts
|
|
1112
|
+
import {
|
|
1113
|
+
createPrivateKeySigner,
|
|
1114
|
+
executeTx
|
|
1115
|
+
} from "@spectratools/tx-shared";
|
|
1116
|
+
import { z } from "incur";
|
|
1117
|
+
|
|
1118
|
+
// src/commands/_common.ts
|
|
1119
|
+
import { checksumAddress, weiToEth } from "@spectratools/cli-shared";
|
|
1120
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1121
|
+
function toChecksum(address) {
|
|
1122
|
+
try {
|
|
1123
|
+
return checksumAddress(address);
|
|
1124
|
+
} catch {
|
|
1125
|
+
return address;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
function asNum(value) {
|
|
1129
|
+
return Number(value);
|
|
1130
|
+
}
|
|
1131
|
+
function relTime(unixSeconds) {
|
|
1132
|
+
const ts = typeof unixSeconds === "bigint" ? Number(unixSeconds) : unixSeconds;
|
|
1133
|
+
if (!Number.isFinite(ts) || ts <= 0) return "n/a";
|
|
1134
|
+
const delta = ts - Math.floor(Date.now() / 1e3);
|
|
1135
|
+
const abs = Math.abs(delta);
|
|
1136
|
+
const hours = Math.floor(abs / 3600);
|
|
1137
|
+
const minutes = Math.floor(abs % 3600 / 60);
|
|
1138
|
+
const label = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1139
|
+
return delta >= 0 ? `in ${label}` : `${label} ago`;
|
|
1140
|
+
}
|
|
1141
|
+
function clampPositive(seconds) {
|
|
1142
|
+
return seconds > 0 ? seconds : 0;
|
|
1143
|
+
}
|
|
1144
|
+
function jsonSafe(value) {
|
|
1145
|
+
if (typeof value === "bigint") return value.toString();
|
|
1146
|
+
if (Array.isArray(value)) return value.map((item) => jsonSafe(item));
|
|
1147
|
+
if (value && typeof value === "object") {
|
|
1148
|
+
return Object.fromEntries(
|
|
1149
|
+
Object.entries(value).map(([key, entry]) => [
|
|
1150
|
+
key,
|
|
1151
|
+
jsonSafe(entry)
|
|
1152
|
+
])
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
return value;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
// src/commands/_write-utils.ts
|
|
1159
|
+
var PRIVATE_KEY_MISSING_MESSAGE = "Missing PRIVATE_KEY env var. Set PRIVATE_KEY to a 0x-prefixed 32-byte hex private key.";
|
|
1160
|
+
var writeEnv = z.object({
|
|
1161
|
+
ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override"),
|
|
1162
|
+
PRIVATE_KEY: z.string().min(1, PRIVATE_KEY_MISSING_MESSAGE).describe("Private key (0x-prefixed 32-byte hex) for signing transactions")
|
|
1163
|
+
});
|
|
1164
|
+
var writeOptions = z.object({
|
|
1165
|
+
"dry-run": z.boolean().default(false).describe("Simulate the transaction without broadcasting"),
|
|
1166
|
+
"gas-limit": z.string().optional().describe("Gas limit override (in gas units)"),
|
|
1167
|
+
"max-fee": z.string().optional().describe("Max fee per gas override in wei (EIP-1559)"),
|
|
1168
|
+
nonce: z.number().optional().describe("Nonce override")
|
|
1169
|
+
});
|
|
1170
|
+
function resolveAccount(env8) {
|
|
1171
|
+
const privateKey = env8.PRIVATE_KEY?.trim();
|
|
1172
|
+
if (!privateKey) {
|
|
1173
|
+
throw new Error(PRIVATE_KEY_MISSING_MESSAGE);
|
|
1174
|
+
}
|
|
1175
|
+
const signer = createPrivateKeySigner(privateKey);
|
|
1176
|
+
return signer.account;
|
|
1177
|
+
}
|
|
1178
|
+
function formatTxResult(result) {
|
|
1179
|
+
if (result.status === "dry-run") {
|
|
1180
|
+
return {
|
|
1181
|
+
dryRun: true,
|
|
1182
|
+
estimatedGas: result.estimatedGas.toString(),
|
|
1183
|
+
simulationResult: jsonSafe(result.simulationResult),
|
|
1184
|
+
...result.privyPolicy !== void 0 ? { privyPolicy: jsonSafe(result.privyPolicy) } : {}
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
txHash: result.hash,
|
|
1189
|
+
blockNumber: Number(result.blockNumber),
|
|
1190
|
+
gasUsed: result.gasUsed.toString()
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
async function aboreanWriteTx(opts) {
|
|
1194
|
+
const { env: env8, options, address, abi, functionName, args, value } = opts;
|
|
1195
|
+
const account = resolveAccount(env8);
|
|
1196
|
+
const publicClient = createAboreanPublicClient(env8.ABSTRACT_RPC_URL);
|
|
1197
|
+
const walletClient = createAboreanWalletClient(account, env8.ABSTRACT_RPC_URL);
|
|
1198
|
+
const result = await executeTx({
|
|
1199
|
+
publicClient,
|
|
1200
|
+
walletClient,
|
|
1201
|
+
account,
|
|
1202
|
+
address,
|
|
1203
|
+
abi,
|
|
1204
|
+
functionName,
|
|
1205
|
+
...args !== void 0 ? { args } : {},
|
|
1206
|
+
...value !== void 0 ? { value } : {},
|
|
1207
|
+
dryRun: options["dry-run"],
|
|
1208
|
+
...options["gas-limit"] ? { gasLimit: BigInt(options["gas-limit"]) } : {},
|
|
1209
|
+
...options["max-fee"] ? { maxFeePerGas: BigInt(options["max-fee"]) } : {},
|
|
1210
|
+
...options.nonce !== void 0 ? { nonce: options.nonce } : {}
|
|
1211
|
+
});
|
|
1212
|
+
return formatTxResult(result);
|
|
1213
|
+
}
|
|
1056
1214
|
|
|
1057
1215
|
// src/commands/cl.ts
|
|
1058
1216
|
var Q96 = 2n ** 96n;
|
|
1059
1217
|
var MULTICALL_BATCH_SIZE = 100;
|
|
1060
|
-
var env =
|
|
1061
|
-
ABSTRACT_RPC_URL:
|
|
1218
|
+
var env = z2.object({
|
|
1219
|
+
ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
|
|
1062
1220
|
});
|
|
1063
|
-
var tokenSchema =
|
|
1064
|
-
address:
|
|
1065
|
-
symbol:
|
|
1066
|
-
decimals:
|
|
1221
|
+
var tokenSchema = z2.object({
|
|
1222
|
+
address: z2.string(),
|
|
1223
|
+
symbol: z2.string(),
|
|
1224
|
+
decimals: z2.number()
|
|
1067
1225
|
});
|
|
1068
|
-
var poolRowSchema =
|
|
1069
|
-
pool:
|
|
1070
|
-
pair:
|
|
1226
|
+
var poolRowSchema = z2.object({
|
|
1227
|
+
pool: z2.string(),
|
|
1228
|
+
pair: z2.string(),
|
|
1071
1229
|
token0: tokenSchema,
|
|
1072
1230
|
token1: tokenSchema,
|
|
1073
|
-
fee:
|
|
1074
|
-
feePercent:
|
|
1075
|
-
tickSpacing:
|
|
1076
|
-
liquidity:
|
|
1077
|
-
currentTick:
|
|
1078
|
-
sqrtPriceX96:
|
|
1079
|
-
activeLiquidityEstimate:
|
|
1080
|
-
token0:
|
|
1081
|
-
token1:
|
|
1082
|
-
totalInToken0:
|
|
1083
|
-
totalInToken1:
|
|
1231
|
+
fee: z2.number(),
|
|
1232
|
+
feePercent: z2.number(),
|
|
1233
|
+
tickSpacing: z2.number(),
|
|
1234
|
+
liquidity: z2.string(),
|
|
1235
|
+
currentTick: z2.number(),
|
|
1236
|
+
sqrtPriceX96: z2.string(),
|
|
1237
|
+
activeLiquidityEstimate: z2.object({
|
|
1238
|
+
token0: z2.string(),
|
|
1239
|
+
token1: z2.string(),
|
|
1240
|
+
totalInToken0: z2.number().nullable(),
|
|
1241
|
+
totalInToken1: z2.number().nullable()
|
|
1084
1242
|
}),
|
|
1085
|
-
price:
|
|
1086
|
-
token1PerToken0:
|
|
1087
|
-
token0PerToken1:
|
|
1243
|
+
price: z2.object({
|
|
1244
|
+
token1PerToken0: z2.number().nullable(),
|
|
1245
|
+
token0PerToken1: z2.number().nullable()
|
|
1088
1246
|
})
|
|
1089
1247
|
});
|
|
1090
|
-
var quoteOutputSchema =
|
|
1091
|
-
pool:
|
|
1092
|
-
selectedFee:
|
|
1093
|
-
selectedTickSpacing:
|
|
1248
|
+
var quoteOutputSchema = z2.object({
|
|
1249
|
+
pool: z2.string(),
|
|
1250
|
+
selectedFee: z2.number(),
|
|
1251
|
+
selectedTickSpacing: z2.number(),
|
|
1094
1252
|
tokenIn: tokenSchema,
|
|
1095
1253
|
tokenOut: tokenSchema,
|
|
1096
|
-
amountIn:
|
|
1097
|
-
raw:
|
|
1098
|
-
decimal:
|
|
1254
|
+
amountIn: z2.object({
|
|
1255
|
+
raw: z2.string(),
|
|
1256
|
+
decimal: z2.string()
|
|
1099
1257
|
}),
|
|
1100
|
-
amountOut:
|
|
1101
|
-
raw:
|
|
1102
|
-
decimal:
|
|
1258
|
+
amountOut: z2.object({
|
|
1259
|
+
raw: z2.string(),
|
|
1260
|
+
decimal: z2.string()
|
|
1103
1261
|
}),
|
|
1104
|
-
execution:
|
|
1105
|
-
sqrtPriceX96After:
|
|
1106
|
-
initializedTicksCrossed:
|
|
1107
|
-
gasEstimate:
|
|
1262
|
+
execution: z2.object({
|
|
1263
|
+
sqrtPriceX96After: z2.string(),
|
|
1264
|
+
initializedTicksCrossed: z2.number(),
|
|
1265
|
+
gasEstimate: z2.string()
|
|
1108
1266
|
}),
|
|
1109
|
-
prices:
|
|
1110
|
-
poolMidPriceOutPerIn:
|
|
1111
|
-
quotePriceOutPerIn:
|
|
1112
|
-
priceImpactPct:
|
|
1267
|
+
prices: z2.object({
|
|
1268
|
+
poolMidPriceOutPerIn: z2.number().nullable(),
|
|
1269
|
+
quotePriceOutPerIn: z2.number().nullable(),
|
|
1270
|
+
priceImpactPct: z2.number().nullable()
|
|
1113
1271
|
})
|
|
1114
1272
|
});
|
|
1115
1273
|
var erc20MetadataAbi = [
|
|
@@ -1137,7 +1295,7 @@ function finiteOrNull(value) {
|
|
|
1137
1295
|
function toTokenMetaFallback(address) {
|
|
1138
1296
|
return {
|
|
1139
1297
|
address,
|
|
1140
|
-
symbol: shortAddress(
|
|
1298
|
+
symbol: shortAddress(checksumAddress2(address)),
|
|
1141
1299
|
decimals: 18
|
|
1142
1300
|
};
|
|
1143
1301
|
}
|
|
@@ -1232,7 +1390,7 @@ async function readTokenMetadata(client, tokenAddresses) {
|
|
|
1232
1390
|
const symbol = symbolResult && symbolResult.status === "success" && typeof symbolResult.result === "string" ? symbolResult.result : fallback.symbol;
|
|
1233
1391
|
const decimals = decimalsResult && decimalsResult.status === "success" && typeof decimalsResult.result === "number" ? decimalsResult.result : fallback.decimals;
|
|
1234
1392
|
out.set(address, {
|
|
1235
|
-
address:
|
|
1393
|
+
address: checksumAddress2(address),
|
|
1236
1394
|
symbol,
|
|
1237
1395
|
decimals
|
|
1238
1396
|
});
|
|
@@ -1316,7 +1474,7 @@ function toPoolRow(pool, tokenMeta) {
|
|
|
1316
1474
|
prices
|
|
1317
1475
|
);
|
|
1318
1476
|
return {
|
|
1319
|
-
pool:
|
|
1477
|
+
pool: checksumAddress2(pool.pool),
|
|
1320
1478
|
pair: `${token0.symbol}/${token1.symbol}`,
|
|
1321
1479
|
token0,
|
|
1322
1480
|
token1,
|
|
@@ -1339,9 +1497,9 @@ var cl = Cli.create("cl", {
|
|
|
1339
1497
|
cl.command("pools", {
|
|
1340
1498
|
description: "List Slipstream pools with current state, prices, and active liquidity estimate.",
|
|
1341
1499
|
env,
|
|
1342
|
-
output:
|
|
1343
|
-
count:
|
|
1344
|
-
pools:
|
|
1500
|
+
output: z2.object({
|
|
1501
|
+
count: z2.number(),
|
|
1502
|
+
pools: z2.array(poolRowSchema)
|
|
1345
1503
|
}),
|
|
1346
1504
|
async run(c) {
|
|
1347
1505
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -1352,19 +1510,41 @@ cl.command("pools", {
|
|
|
1352
1510
|
poolStates.flatMap((pool) => [pool.token0, pool.token1])
|
|
1353
1511
|
);
|
|
1354
1512
|
const rows = poolStates.map((pool) => toPoolRow(pool, tokenMeta));
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1513
|
+
const firstPool = rows[0];
|
|
1514
|
+
return c.ok(
|
|
1515
|
+
{
|
|
1516
|
+
count: rows.length,
|
|
1517
|
+
pools: rows
|
|
1518
|
+
},
|
|
1519
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
1520
|
+
cta: {
|
|
1521
|
+
description: "Explore CL pools:",
|
|
1522
|
+
commands: [
|
|
1523
|
+
...firstPool ? [
|
|
1524
|
+
{
|
|
1525
|
+
command: "cl pool",
|
|
1526
|
+
args: { pool: firstPool.pool },
|
|
1527
|
+
description: `Inspect ${firstPool.pair}`
|
|
1528
|
+
}
|
|
1529
|
+
] : [],
|
|
1530
|
+
{
|
|
1531
|
+
command: "cl positions",
|
|
1532
|
+
args: { owner: "<address>" },
|
|
1533
|
+
description: "List CL positions for an address"
|
|
1534
|
+
}
|
|
1535
|
+
]
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
);
|
|
1359
1539
|
}
|
|
1360
1540
|
});
|
|
1361
1541
|
cl.command("pool", {
|
|
1362
1542
|
description: "Get detailed state for a Slipstream pool address.",
|
|
1363
|
-
args:
|
|
1364
|
-
pool:
|
|
1543
|
+
args: z2.object({
|
|
1544
|
+
pool: z2.string().describe("Pool address")
|
|
1365
1545
|
}),
|
|
1366
1546
|
env,
|
|
1367
|
-
output:
|
|
1547
|
+
output: z2.object({
|
|
1368
1548
|
pool: poolRowSchema
|
|
1369
1549
|
}),
|
|
1370
1550
|
async run(c) {
|
|
@@ -1375,35 +1555,59 @@ cl.command("pool", {
|
|
|
1375
1555
|
});
|
|
1376
1556
|
}
|
|
1377
1557
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1378
|
-
const checksummedPool =
|
|
1558
|
+
const checksummedPool = checksumAddress2(c.args.pool);
|
|
1379
1559
|
const [poolState] = await readPoolStates(client, [checksummedPool]);
|
|
1380
1560
|
const tokenMeta = await readTokenMetadata(client, [poolState.token0, poolState.token1]);
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1561
|
+
const row = toPoolRow(poolState, tokenMeta);
|
|
1562
|
+
return c.ok(
|
|
1563
|
+
{
|
|
1564
|
+
pool: row
|
|
1565
|
+
},
|
|
1566
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
1567
|
+
cta: {
|
|
1568
|
+
description: "Next steps:",
|
|
1569
|
+
commands: [
|
|
1570
|
+
{
|
|
1571
|
+
command: "cl quote",
|
|
1572
|
+
args: {
|
|
1573
|
+
tokenIn: row.token0.address,
|
|
1574
|
+
tokenOut: row.token1.address,
|
|
1575
|
+
amountIn: "1"
|
|
1576
|
+
},
|
|
1577
|
+
description: `Quote a ${row.token0.symbol} \u2192 ${row.token1.symbol} swap`
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
command: "cl positions",
|
|
1581
|
+
args: { owner: "<address>" },
|
|
1582
|
+
description: "List positions in this pool"
|
|
1583
|
+
}
|
|
1584
|
+
]
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
);
|
|
1384
1588
|
}
|
|
1385
1589
|
});
|
|
1386
1590
|
cl.command("positions", {
|
|
1387
1591
|
description: "List concentrated liquidity NFT positions for an owner.",
|
|
1388
|
-
args:
|
|
1389
|
-
owner:
|
|
1592
|
+
args: z2.object({
|
|
1593
|
+
owner: z2.string().describe("Owner wallet address")
|
|
1390
1594
|
}),
|
|
1391
1595
|
env,
|
|
1392
|
-
output:
|
|
1393
|
-
owner:
|
|
1394
|
-
count:
|
|
1395
|
-
positions:
|
|
1396
|
-
|
|
1397
|
-
tokenId:
|
|
1398
|
-
pair:
|
|
1596
|
+
output: z2.object({
|
|
1597
|
+
owner: z2.string(),
|
|
1598
|
+
count: z2.number(),
|
|
1599
|
+
positions: z2.array(
|
|
1600
|
+
z2.object({
|
|
1601
|
+
tokenId: z2.string(),
|
|
1602
|
+
pair: z2.string(),
|
|
1399
1603
|
token0: tokenSchema,
|
|
1400
1604
|
token1: tokenSchema,
|
|
1401
|
-
tickSpacing:
|
|
1402
|
-
tickLower:
|
|
1403
|
-
tickUpper:
|
|
1404
|
-
liquidity:
|
|
1405
|
-
tokensOwed0:
|
|
1406
|
-
tokensOwed1:
|
|
1605
|
+
tickSpacing: z2.number(),
|
|
1606
|
+
tickLower: z2.number(),
|
|
1607
|
+
tickUpper: z2.number(),
|
|
1608
|
+
liquidity: z2.string(),
|
|
1609
|
+
tokensOwed0: z2.object({ raw: z2.string(), decimal: z2.string() }),
|
|
1610
|
+
tokensOwed1: z2.object({ raw: z2.string(), decimal: z2.string() })
|
|
1407
1611
|
})
|
|
1408
1612
|
)
|
|
1409
1613
|
}),
|
|
@@ -1415,7 +1619,7 @@ cl.command("positions", {
|
|
|
1415
1619
|
});
|
|
1416
1620
|
}
|
|
1417
1621
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1418
|
-
const owner =
|
|
1622
|
+
const owner = checksumAddress2(c.args.owner);
|
|
1419
1623
|
const balance = await client.readContract({
|
|
1420
1624
|
abi: nonfungiblePositionManagerAbi,
|
|
1421
1625
|
address: ABOREAN_CL_ADDRESSES.nonfungiblePositionManager,
|
|
@@ -1466,22 +1670,46 @@ cl.command("positions", {
|
|
|
1466
1670
|
}
|
|
1467
1671
|
};
|
|
1468
1672
|
});
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1673
|
+
const firstPosition = positions[0];
|
|
1674
|
+
return c.ok(
|
|
1675
|
+
{
|
|
1676
|
+
owner,
|
|
1677
|
+
count: positions.length,
|
|
1678
|
+
positions
|
|
1679
|
+
},
|
|
1680
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
1681
|
+
cta: {
|
|
1682
|
+
description: "Related commands:",
|
|
1683
|
+
commands: firstPosition ? [
|
|
1684
|
+
{
|
|
1685
|
+
command: "cl pool",
|
|
1686
|
+
args: { pool: "<poolAddress>" },
|
|
1687
|
+
description: `Inspect pool for ${firstPosition.pair}`
|
|
1688
|
+
},
|
|
1689
|
+
{
|
|
1690
|
+
command: "cl quote",
|
|
1691
|
+
args: {
|
|
1692
|
+
tokenIn: firstPosition.token0.address,
|
|
1693
|
+
tokenOut: firstPosition.token1.address,
|
|
1694
|
+
amountIn: "1"
|
|
1695
|
+
},
|
|
1696
|
+
description: `Quote a ${firstPosition.token0.symbol} \u2192 ${firstPosition.token1.symbol} swap`
|
|
1697
|
+
}
|
|
1698
|
+
] : []
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
);
|
|
1474
1702
|
}
|
|
1475
1703
|
});
|
|
1476
1704
|
cl.command("quote", {
|
|
1477
1705
|
description: "Quote a single-hop Slipstream swap via QuoterV2.",
|
|
1478
|
-
args:
|
|
1479
|
-
tokenIn:
|
|
1480
|
-
tokenOut:
|
|
1481
|
-
amountIn:
|
|
1706
|
+
args: z2.object({
|
|
1707
|
+
tokenIn: z2.string().describe("Input token address"),
|
|
1708
|
+
tokenOut: z2.string().describe("Output token address"),
|
|
1709
|
+
amountIn: z2.string().describe("Input amount in human-readable decimal units")
|
|
1482
1710
|
}),
|
|
1483
|
-
options:
|
|
1484
|
-
fee:
|
|
1711
|
+
options: z2.object({
|
|
1712
|
+
fee: z2.coerce.number().int().positive().optional().describe("Optional fee tier filter")
|
|
1485
1713
|
}),
|
|
1486
1714
|
env,
|
|
1487
1715
|
output: quoteOutputSchema,
|
|
@@ -1494,8 +1722,8 @@ cl.command("quote", {
|
|
|
1494
1722
|
});
|
|
1495
1723
|
}
|
|
1496
1724
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1497
|
-
const inAddress =
|
|
1498
|
-
const outAddress =
|
|
1725
|
+
const inAddress = checksumAddress2(tokenIn);
|
|
1726
|
+
const outAddress = checksumAddress2(tokenOut);
|
|
1499
1727
|
const allPools = await listPoolAddresses(client);
|
|
1500
1728
|
const poolStates = await readPoolStates(client, allPools);
|
|
1501
1729
|
const pairPools = poolStates.filter((pool) => {
|
|
@@ -1560,67 +1788,214 @@ cl.command("quote", {
|
|
|
1560
1788
|
const inIsToken0 = normalizeAddress(inAddress) === normalizeAddress(selectedPool.token0);
|
|
1561
1789
|
const poolMidPriceOutPerIn = inIsToken0 ? poolPrices.token1PerToken0 : poolPrices.token0PerToken1;
|
|
1562
1790
|
const priceImpactPct = quotePriceOutPerIn === null || poolMidPriceOutPerIn === null || poolMidPriceOutPerIn === 0 ? null : finiteOrNull((poolMidPriceOutPerIn - quotePriceOutPerIn) / poolMidPriceOutPerIn * 100);
|
|
1791
|
+
return c.ok(
|
|
1792
|
+
{
|
|
1793
|
+
pool: checksumAddress2(selectedPool.pool),
|
|
1794
|
+
selectedFee: selectedPool.fee,
|
|
1795
|
+
selectedTickSpacing: selectedPool.tickSpacing,
|
|
1796
|
+
tokenIn: inMeta,
|
|
1797
|
+
tokenOut: outMeta,
|
|
1798
|
+
amountIn: {
|
|
1799
|
+
raw: amountInRaw.toString(),
|
|
1800
|
+
decimal: amountInDecimal
|
|
1801
|
+
},
|
|
1802
|
+
amountOut: {
|
|
1803
|
+
raw: amountOutRaw.toString(),
|
|
1804
|
+
decimal: amountOutDecimal
|
|
1805
|
+
},
|
|
1806
|
+
execution: {
|
|
1807
|
+
sqrtPriceX96After: quote[1].toString(),
|
|
1808
|
+
initializedTicksCrossed: quote[2],
|
|
1809
|
+
gasEstimate: quote[3].toString()
|
|
1810
|
+
},
|
|
1811
|
+
prices: {
|
|
1812
|
+
poolMidPriceOutPerIn,
|
|
1813
|
+
quotePriceOutPerIn,
|
|
1814
|
+
priceImpactPct
|
|
1815
|
+
}
|
|
1816
|
+
},
|
|
1817
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
1818
|
+
cta: {
|
|
1819
|
+
description: "Related commands:",
|
|
1820
|
+
commands: [
|
|
1821
|
+
{
|
|
1822
|
+
command: "cl pool",
|
|
1823
|
+
args: { pool: checksumAddress2(selectedPool.pool) },
|
|
1824
|
+
description: "Inspect the pool used for this quote"
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
command: "cl quote",
|
|
1828
|
+
args: {
|
|
1829
|
+
tokenIn: outMeta.address,
|
|
1830
|
+
tokenOut: inMeta.address,
|
|
1831
|
+
amountIn: amountOutDecimal
|
|
1832
|
+
},
|
|
1833
|
+
description: `Reverse quote ${outMeta.symbol} \u2192 ${inMeta.symbol}`
|
|
1834
|
+
}
|
|
1835
|
+
]
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
);
|
|
1839
|
+
}
|
|
1840
|
+
});
|
|
1841
|
+
var DEFAULT_SLIPPAGE_PERCENT = 0.5;
|
|
1842
|
+
var DEFAULT_DEADLINE_SECONDS = 300;
|
|
1843
|
+
var swapOutputSchema = z2.object({
|
|
1844
|
+
pool: z2.string(),
|
|
1845
|
+
tokenIn: tokenSchema,
|
|
1846
|
+
tokenOut: tokenSchema,
|
|
1847
|
+
amountIn: z2.object({ raw: z2.string(), decimal: z2.string() }),
|
|
1848
|
+
quotedAmountOut: z2.object({ raw: z2.string(), decimal: z2.string() }),
|
|
1849
|
+
amountOutMinimum: z2.object({ raw: z2.string(), decimal: z2.string() }),
|
|
1850
|
+
slippagePercent: z2.number(),
|
|
1851
|
+
deadlineSeconds: z2.number(),
|
|
1852
|
+
tx: z2.union([
|
|
1853
|
+
z2.object({
|
|
1854
|
+
txHash: z2.string(),
|
|
1855
|
+
blockNumber: z2.number(),
|
|
1856
|
+
gasUsed: z2.string()
|
|
1857
|
+
}),
|
|
1858
|
+
z2.object({
|
|
1859
|
+
dryRun: z2.literal(true),
|
|
1860
|
+
estimatedGas: z2.string(),
|
|
1861
|
+
simulationResult: z2.unknown()
|
|
1862
|
+
})
|
|
1863
|
+
])
|
|
1864
|
+
});
|
|
1865
|
+
cl.command("swap", {
|
|
1866
|
+
description: "Execute a single-hop Slipstream swap via the CL SwapRouter.",
|
|
1867
|
+
options: z2.object({
|
|
1868
|
+
"token-in": z2.string().describe("Input token address"),
|
|
1869
|
+
"token-out": z2.string().describe("Output token address"),
|
|
1870
|
+
"amount-in": z2.string().describe("Input amount in wei"),
|
|
1871
|
+
slippage: z2.coerce.number().default(DEFAULT_SLIPPAGE_PERCENT).describe("Slippage tolerance in percent (default: 0.5)"),
|
|
1872
|
+
deadline: z2.coerce.number().int().default(DEFAULT_DEADLINE_SECONDS).describe("Transaction deadline in seconds from now (default: 300)"),
|
|
1873
|
+
...writeOptions.shape
|
|
1874
|
+
}),
|
|
1875
|
+
env: writeEnv,
|
|
1876
|
+
output: swapOutputSchema,
|
|
1877
|
+
async run(c) {
|
|
1878
|
+
const tokenIn = c.options["token-in"];
|
|
1879
|
+
const tokenOut = c.options["token-out"];
|
|
1880
|
+
const amountInWei = c.options["amount-in"];
|
|
1881
|
+
const slippage = c.options.slippage;
|
|
1882
|
+
const deadlineSeconds = c.options.deadline;
|
|
1883
|
+
if (!isAddress(tokenIn) || !isAddress(tokenOut)) {
|
|
1884
|
+
return c.error({
|
|
1885
|
+
code: "INVALID_ADDRESS",
|
|
1886
|
+
message: "token-in and token-out must both be valid 0x-prefixed 20-byte addresses."
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1889
|
+
const inAddress = checksumAddress2(tokenIn);
|
|
1890
|
+
const outAddress = checksumAddress2(tokenOut);
|
|
1891
|
+
let amountInRaw;
|
|
1892
|
+
try {
|
|
1893
|
+
amountInRaw = BigInt(amountInWei);
|
|
1894
|
+
} catch {
|
|
1895
|
+
return c.error({
|
|
1896
|
+
code: "INVALID_AMOUNT",
|
|
1897
|
+
message: `Invalid amount-in: "${amountInWei}". Provide a valid integer in wei.`
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
if (amountInRaw <= 0n) {
|
|
1901
|
+
return c.error({
|
|
1902
|
+
code: "INVALID_AMOUNT",
|
|
1903
|
+
message: "amount-in must be a positive integer."
|
|
1904
|
+
});
|
|
1905
|
+
}
|
|
1906
|
+
if (slippage < 0 || slippage > 100) {
|
|
1907
|
+
return c.error({
|
|
1908
|
+
code: "INVALID_SLIPPAGE",
|
|
1909
|
+
message: `Slippage must be between 0 and 100. Got: ${slippage}`
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1913
|
+
const allPools = await listPoolAddresses(client);
|
|
1914
|
+
const poolStates = await readPoolStates(client, allPools);
|
|
1915
|
+
const pairPools = poolStates.filter((pool) => {
|
|
1916
|
+
const a = normalizeAddress(pool.token0);
|
|
1917
|
+
const b = normalizeAddress(pool.token1);
|
|
1918
|
+
const tokenInNorm = normalizeAddress(inAddress);
|
|
1919
|
+
const tokenOutNorm = normalizeAddress(outAddress);
|
|
1920
|
+
return a === tokenInNorm && b === tokenOutNorm || a === tokenOutNorm && b === tokenInNorm;
|
|
1921
|
+
});
|
|
1922
|
+
if (pairPools.length === 0) {
|
|
1923
|
+
return c.error({
|
|
1924
|
+
code: "POOL_NOT_FOUND",
|
|
1925
|
+
message: `No Slipstream pool found for pair ${inAddress}/${outAddress}.`
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
const selectedPool = [...pairPools].sort((a, b) => {
|
|
1929
|
+
if (a.liquidity === b.liquidity) return 0;
|
|
1930
|
+
return a.liquidity > b.liquidity ? -1 : 1;
|
|
1931
|
+
})[0];
|
|
1932
|
+
const tokenMeta = await readTokenMetadata(client, [inAddress, outAddress]);
|
|
1933
|
+
const inMeta = tokenMeta.get(inAddress) ?? toTokenMetaFallback(inAddress);
|
|
1934
|
+
const outMeta = tokenMeta.get(outAddress) ?? toTokenMetaFallback(outAddress);
|
|
1935
|
+
const quote = await client.readContract({
|
|
1936
|
+
abi: quoterV2Abi,
|
|
1937
|
+
address: ABOREAN_CL_ADDRESSES.quoterV2,
|
|
1938
|
+
functionName: "quoteExactInputSingle",
|
|
1939
|
+
args: [
|
|
1940
|
+
{
|
|
1941
|
+
tokenIn: inAddress,
|
|
1942
|
+
tokenOut: outAddress,
|
|
1943
|
+
amountIn: amountInRaw,
|
|
1944
|
+
tickSpacing: selectedPool.tickSpacing,
|
|
1945
|
+
sqrtPriceLimitX96: 0n
|
|
1946
|
+
}
|
|
1947
|
+
]
|
|
1948
|
+
});
|
|
1949
|
+
const quotedAmountOut = quote[0];
|
|
1950
|
+
const slippageBps = BigInt(Math.round(slippage * 100));
|
|
1951
|
+
const amountOutMinimum = quotedAmountOut - quotedAmountOut * slippageBps / 10000n;
|
|
1952
|
+
const account = resolveAccount(c.env);
|
|
1953
|
+
const deadlineTimestamp = BigInt(Math.floor(Date.now() / 1e3) + deadlineSeconds);
|
|
1954
|
+
const txResult = await aboreanWriteTx({
|
|
1955
|
+
env: c.env,
|
|
1956
|
+
options: {
|
|
1957
|
+
"dry-run": c.options["dry-run"],
|
|
1958
|
+
"gas-limit": c.options["gas-limit"],
|
|
1959
|
+
"max-fee": c.options["max-fee"],
|
|
1960
|
+
nonce: c.options.nonce
|
|
1961
|
+
},
|
|
1962
|
+
address: ABOREAN_CL_ADDRESSES.swapRouter,
|
|
1963
|
+
abi: swapRouterAbi,
|
|
1964
|
+
functionName: "exactInputSingle",
|
|
1965
|
+
args: [
|
|
1966
|
+
{
|
|
1967
|
+
tokenIn: inAddress,
|
|
1968
|
+
tokenOut: outAddress,
|
|
1969
|
+
tickSpacing: selectedPool.tickSpacing,
|
|
1970
|
+
recipient: account.address,
|
|
1971
|
+
deadline: deadlineTimestamp,
|
|
1972
|
+
amountIn: amountInRaw,
|
|
1973
|
+
amountOutMinimum,
|
|
1974
|
+
sqrtPriceLimitX96: 0n
|
|
1975
|
+
}
|
|
1976
|
+
]
|
|
1977
|
+
});
|
|
1978
|
+
const amountInDecimal = formatUnits(amountInRaw, inMeta.decimals);
|
|
1979
|
+
const quotedOutDecimal = formatUnits(quotedAmountOut, outMeta.decimals);
|
|
1980
|
+
const minOutDecimal = formatUnits(amountOutMinimum, outMeta.decimals);
|
|
1563
1981
|
return c.ok({
|
|
1564
|
-
pool:
|
|
1565
|
-
selectedFee: selectedPool.fee,
|
|
1566
|
-
selectedTickSpacing: selectedPool.tickSpacing,
|
|
1982
|
+
pool: checksumAddress2(selectedPool.pool),
|
|
1567
1983
|
tokenIn: inMeta,
|
|
1568
1984
|
tokenOut: outMeta,
|
|
1569
|
-
amountIn: {
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
decimal: amountOutDecimal
|
|
1576
|
-
},
|
|
1577
|
-
execution: {
|
|
1578
|
-
sqrtPriceX96After: quote[1].toString(),
|
|
1579
|
-
initializedTicksCrossed: quote[2],
|
|
1580
|
-
gasEstimate: quote[3].toString()
|
|
1581
|
-
},
|
|
1582
|
-
prices: {
|
|
1583
|
-
poolMidPriceOutPerIn,
|
|
1584
|
-
quotePriceOutPerIn,
|
|
1585
|
-
priceImpactPct
|
|
1586
|
-
}
|
|
1985
|
+
amountIn: { raw: amountInRaw.toString(), decimal: amountInDecimal },
|
|
1986
|
+
quotedAmountOut: { raw: quotedAmountOut.toString(), decimal: quotedOutDecimal },
|
|
1987
|
+
amountOutMinimum: { raw: amountOutMinimum.toString(), decimal: minOutDecimal },
|
|
1988
|
+
slippagePercent: slippage,
|
|
1989
|
+
deadlineSeconds,
|
|
1990
|
+
tx: txResult
|
|
1587
1991
|
});
|
|
1588
1992
|
}
|
|
1589
1993
|
});
|
|
1590
1994
|
|
|
1591
1995
|
// src/commands/gauges.ts
|
|
1592
|
-
import { Cli as Cli2, z as
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
import { checksumAddress as checksumAddress2, weiToEth } from "@spectratools/cli-shared";
|
|
1596
|
-
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1597
|
-
function toChecksum(address) {
|
|
1598
|
-
try {
|
|
1599
|
-
return checksumAddress2(address);
|
|
1600
|
-
} catch {
|
|
1601
|
-
return address;
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
function asNum(value) {
|
|
1605
|
-
return Number(value);
|
|
1606
|
-
}
|
|
1607
|
-
function relTime(unixSeconds) {
|
|
1608
|
-
const ts = typeof unixSeconds === "bigint" ? Number(unixSeconds) : unixSeconds;
|
|
1609
|
-
if (!Number.isFinite(ts) || ts <= 0) return "n/a";
|
|
1610
|
-
const delta = ts - Math.floor(Date.now() / 1e3);
|
|
1611
|
-
const abs = Math.abs(delta);
|
|
1612
|
-
const hours = Math.floor(abs / 3600);
|
|
1613
|
-
const minutes = Math.floor(abs % 3600 / 60);
|
|
1614
|
-
const label = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1615
|
-
return delta >= 0 ? `in ${label}` : `${label} ago`;
|
|
1616
|
-
}
|
|
1617
|
-
function clampPositive(seconds) {
|
|
1618
|
-
return seconds > 0 ? seconds : 0;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
// src/commands/gauges.ts
|
|
1622
|
-
var env2 = z2.object({
|
|
1623
|
-
ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
|
|
1996
|
+
import { Cli as Cli2, z as z3 } from "incur";
|
|
1997
|
+
var env2 = z3.object({
|
|
1998
|
+
ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
|
|
1624
1999
|
});
|
|
1625
2000
|
async function discoverGaugePools(client) {
|
|
1626
2001
|
const [v2PoolCount, clPoolCount] = await Promise.all([
|
|
@@ -1676,20 +2051,20 @@ var gauges = Cli2.create("gauges", {
|
|
|
1676
2051
|
gauges.command("list", {
|
|
1677
2052
|
description: "List active gauges with pool, emissions, and staking stats.",
|
|
1678
2053
|
env: env2,
|
|
1679
|
-
output:
|
|
1680
|
-
gauges:
|
|
1681
|
-
|
|
1682
|
-
pool:
|
|
1683
|
-
gauge:
|
|
1684
|
-
rewardToken:
|
|
1685
|
-
rewardRate:
|
|
1686
|
-
totalStaked:
|
|
1687
|
-
claimableEmissions:
|
|
1688
|
-
periodFinish:
|
|
1689
|
-
periodFinishRelative:
|
|
2054
|
+
output: z3.object({
|
|
2055
|
+
gauges: z3.array(
|
|
2056
|
+
z3.object({
|
|
2057
|
+
pool: z3.string(),
|
|
2058
|
+
gauge: z3.string(),
|
|
2059
|
+
rewardToken: z3.string(),
|
|
2060
|
+
rewardRate: z3.string(),
|
|
2061
|
+
totalStaked: z3.string(),
|
|
2062
|
+
claimableEmissions: z3.string(),
|
|
2063
|
+
periodFinish: z3.number(),
|
|
2064
|
+
periodFinishRelative: z3.string()
|
|
1690
2065
|
})
|
|
1691
2066
|
),
|
|
1692
|
-
count:
|
|
2067
|
+
count: z3.number()
|
|
1693
2068
|
}),
|
|
1694
2069
|
examples: [{ description: "List all active gauges and current emissions state" }],
|
|
1695
2070
|
async run(c) {
|
|
@@ -1747,35 +2122,50 @@ gauges.command("list", {
|
|
|
1747
2122
|
periodFinishRelative: relTime(periodFinish)
|
|
1748
2123
|
};
|
|
1749
2124
|
});
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
2125
|
+
const firstGauge = items[0];
|
|
2126
|
+
return c.ok(
|
|
2127
|
+
{
|
|
2128
|
+
gauges: items,
|
|
2129
|
+
count: items.length
|
|
2130
|
+
},
|
|
2131
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
2132
|
+
cta: {
|
|
2133
|
+
description: "Explore gauges:",
|
|
2134
|
+
commands: firstGauge ? [
|
|
2135
|
+
{
|
|
2136
|
+
command: "gauges info",
|
|
2137
|
+
args: { gauge: firstGauge.gauge },
|
|
2138
|
+
description: "Inspect top gauge details"
|
|
2139
|
+
}
|
|
2140
|
+
] : []
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
);
|
|
1754
2144
|
}
|
|
1755
2145
|
});
|
|
1756
2146
|
gauges.command("info", {
|
|
1757
2147
|
description: "Get detailed state for one gauge address.",
|
|
1758
|
-
args:
|
|
1759
|
-
gauge:
|
|
2148
|
+
args: z3.object({
|
|
2149
|
+
gauge: z3.string().describe("Gauge contract address")
|
|
1760
2150
|
}),
|
|
1761
2151
|
env: env2,
|
|
1762
|
-
output:
|
|
1763
|
-
gauge:
|
|
1764
|
-
pool:
|
|
1765
|
-
isAlive:
|
|
1766
|
-
stakingToken:
|
|
1767
|
-
rewardToken:
|
|
1768
|
-
totalStaked:
|
|
1769
|
-
rewardRate:
|
|
1770
|
-
rewardPerTokenStored:
|
|
1771
|
-
fees0:
|
|
1772
|
-
fees1:
|
|
1773
|
-
left:
|
|
1774
|
-
periodFinish:
|
|
1775
|
-
periodFinishRelative:
|
|
1776
|
-
lastUpdateTime:
|
|
1777
|
-
bribeContract:
|
|
1778
|
-
feeContract:
|
|
2152
|
+
output: z3.object({
|
|
2153
|
+
gauge: z3.string(),
|
|
2154
|
+
pool: z3.string(),
|
|
2155
|
+
isAlive: z3.boolean(),
|
|
2156
|
+
stakingToken: z3.string(),
|
|
2157
|
+
rewardToken: z3.string(),
|
|
2158
|
+
totalStaked: z3.string(),
|
|
2159
|
+
rewardRate: z3.string(),
|
|
2160
|
+
rewardPerTokenStored: z3.string(),
|
|
2161
|
+
fees0: z3.string(),
|
|
2162
|
+
fees1: z3.string(),
|
|
2163
|
+
left: z3.string(),
|
|
2164
|
+
periodFinish: z3.number(),
|
|
2165
|
+
periodFinishRelative: z3.string(),
|
|
2166
|
+
lastUpdateTime: z3.number(),
|
|
2167
|
+
bribeContract: z3.string(),
|
|
2168
|
+
feeContract: z3.string()
|
|
1779
2169
|
}),
|
|
1780
2170
|
examples: [
|
|
1781
2171
|
{
|
|
@@ -1877,44 +2267,66 @@ gauges.command("info", {
|
|
|
1877
2267
|
functionName: "left"
|
|
1878
2268
|
})
|
|
1879
2269
|
]);
|
|
1880
|
-
return c.ok(
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2270
|
+
return c.ok(
|
|
2271
|
+
{
|
|
2272
|
+
gauge: toChecksum(gauge),
|
|
2273
|
+
pool: toChecksum(pool),
|
|
2274
|
+
isAlive,
|
|
2275
|
+
stakingToken: toChecksum(stakingToken),
|
|
2276
|
+
rewardToken: toChecksum(rewardToken),
|
|
2277
|
+
totalStaked: totalStaked.toString(),
|
|
2278
|
+
rewardRate: rewardRate.toString(),
|
|
2279
|
+
rewardPerTokenStored: rewardPerTokenStored.toString(),
|
|
2280
|
+
fees0: fees0.toString(),
|
|
2281
|
+
fees1: fees1.toString(),
|
|
2282
|
+
left: left.toString(),
|
|
2283
|
+
periodFinish: asNum(periodFinish),
|
|
2284
|
+
periodFinishRelative: relTime(periodFinish),
|
|
2285
|
+
lastUpdateTime: asNum(lastUpdateTime),
|
|
2286
|
+
bribeContract: toChecksum(bribeContract),
|
|
2287
|
+
feeContract: toChecksum(feeContract)
|
|
2288
|
+
},
|
|
2289
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
2290
|
+
cta: {
|
|
2291
|
+
description: "Related commands:",
|
|
2292
|
+
commands: [
|
|
2293
|
+
{
|
|
2294
|
+
command: "ve stats",
|
|
2295
|
+
description: "View veABX global stats"
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
command: "voter weights",
|
|
2299
|
+
description: "Check pool voting weight distribution"
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
command: "voter bribes",
|
|
2303
|
+
args: { pool: toChecksum(pool) },
|
|
2304
|
+
description: "View bribe rewards for this pool"
|
|
2305
|
+
}
|
|
2306
|
+
]
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
);
|
|
1898
2310
|
}
|
|
1899
2311
|
});
|
|
1900
2312
|
gauges.command("staked", {
|
|
1901
2313
|
description: "Show one address staking positions across all gauges.",
|
|
1902
|
-
args:
|
|
1903
|
-
address:
|
|
2314
|
+
args: z3.object({
|
|
2315
|
+
address: z3.string().describe("Wallet address to inspect")
|
|
1904
2316
|
}),
|
|
1905
2317
|
env: env2,
|
|
1906
|
-
output:
|
|
1907
|
-
address:
|
|
1908
|
-
positions:
|
|
1909
|
-
|
|
1910
|
-
pool:
|
|
1911
|
-
gauge:
|
|
1912
|
-
rewardToken:
|
|
1913
|
-
staked:
|
|
1914
|
-
earned:
|
|
2318
|
+
output: z3.object({
|
|
2319
|
+
address: z3.string(),
|
|
2320
|
+
positions: z3.array(
|
|
2321
|
+
z3.object({
|
|
2322
|
+
pool: z3.string(),
|
|
2323
|
+
gauge: z3.string(),
|
|
2324
|
+
rewardToken: z3.string(),
|
|
2325
|
+
staked: z3.string(),
|
|
2326
|
+
earned: z3.string()
|
|
1915
2327
|
})
|
|
1916
2328
|
),
|
|
1917
|
-
count:
|
|
2329
|
+
count: z3.number()
|
|
1918
2330
|
}),
|
|
1919
2331
|
examples: [
|
|
1920
2332
|
{
|
|
@@ -1973,21 +2385,43 @@ gauges.command("staked", {
|
|
|
1973
2385
|
staked: position.staked.toString(),
|
|
1974
2386
|
earned: position.earned.toString()
|
|
1975
2387
|
}));
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2388
|
+
const firstPosition = positions[0];
|
|
2389
|
+
return c.ok(
|
|
2390
|
+
{
|
|
2391
|
+
address: toChecksum(c.args.address),
|
|
2392
|
+
positions,
|
|
2393
|
+
count: positions.length
|
|
2394
|
+
},
|
|
2395
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
2396
|
+
cta: {
|
|
2397
|
+
description: "Related commands:",
|
|
2398
|
+
commands: [
|
|
2399
|
+
...firstPosition ? [
|
|
2400
|
+
{
|
|
2401
|
+
command: "gauges info",
|
|
2402
|
+
args: { gauge: firstPosition.gauge },
|
|
2403
|
+
description: "Inspect gauge details"
|
|
2404
|
+
}
|
|
2405
|
+
] : [],
|
|
2406
|
+
{
|
|
2407
|
+
command: "ve locks",
|
|
2408
|
+
args: { address: toChecksum(c.args.address) },
|
|
2409
|
+
description: "View veNFT locks for this address"
|
|
2410
|
+
}
|
|
2411
|
+
]
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
);
|
|
1981
2415
|
}
|
|
1982
2416
|
});
|
|
1983
2417
|
|
|
1984
2418
|
// src/commands/lending.ts
|
|
1985
2419
|
import { checksumAddress as checksumAddress3, isAddress as isAddress2 } from "@spectratools/cli-shared";
|
|
1986
|
-
import { Cli as Cli3, z as
|
|
2420
|
+
import { Cli as Cli3, z as z4 } from "incur";
|
|
1987
2421
|
import { formatUnits as formatUnits2 } from "viem";
|
|
1988
2422
|
var MORPHO_DEPLOY_BLOCK = 13947713n;
|
|
1989
|
-
var env3 =
|
|
1990
|
-
ABSTRACT_RPC_URL:
|
|
2423
|
+
var env3 = z4.object({
|
|
2424
|
+
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
|
|
1991
2425
|
});
|
|
1992
2426
|
var morphoAbi = [
|
|
1993
2427
|
{
|
|
@@ -2068,27 +2502,27 @@ var erc20MetadataAbi2 = [
|
|
|
2068
2502
|
outputs: [{ type: "uint8" }]
|
|
2069
2503
|
}
|
|
2070
2504
|
];
|
|
2071
|
-
var tokenMetaSchema =
|
|
2072
|
-
address:
|
|
2073
|
-
symbol:
|
|
2074
|
-
decimals:
|
|
2505
|
+
var tokenMetaSchema = z4.object({
|
|
2506
|
+
address: z4.string(),
|
|
2507
|
+
symbol: z4.string(),
|
|
2508
|
+
decimals: z4.number()
|
|
2075
2509
|
});
|
|
2076
|
-
var lendingMarketRowSchema =
|
|
2077
|
-
marketId:
|
|
2510
|
+
var lendingMarketRowSchema = z4.object({
|
|
2511
|
+
marketId: z4.string(),
|
|
2078
2512
|
loanToken: tokenMetaSchema,
|
|
2079
2513
|
collateralToken: tokenMetaSchema,
|
|
2080
|
-
oracle:
|
|
2081
|
-
irm:
|
|
2082
|
-
lltvBps:
|
|
2083
|
-
lltvPercent:
|
|
2084
|
-
totalSupplyAssets:
|
|
2085
|
-
totalBorrowAssets:
|
|
2086
|
-
totalSupplyShares:
|
|
2087
|
-
totalBorrowShares:
|
|
2088
|
-
availableLiquidityAssets:
|
|
2089
|
-
utilization:
|
|
2090
|
-
feeWad:
|
|
2091
|
-
lastUpdate:
|
|
2514
|
+
oracle: z4.string(),
|
|
2515
|
+
irm: z4.string(),
|
|
2516
|
+
lltvBps: z4.number(),
|
|
2517
|
+
lltvPercent: z4.number(),
|
|
2518
|
+
totalSupplyAssets: z4.string(),
|
|
2519
|
+
totalBorrowAssets: z4.string(),
|
|
2520
|
+
totalSupplyShares: z4.string(),
|
|
2521
|
+
totalBorrowShares: z4.string(),
|
|
2522
|
+
availableLiquidityAssets: z4.string(),
|
|
2523
|
+
utilization: z4.number().nullable(),
|
|
2524
|
+
feeWad: z4.string(),
|
|
2525
|
+
lastUpdate: z4.number()
|
|
2092
2526
|
});
|
|
2093
2527
|
function isMarketId(value) {
|
|
2094
2528
|
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
@@ -2324,21 +2758,21 @@ var lending = Cli3.create("lending", {
|
|
|
2324
2758
|
});
|
|
2325
2759
|
lending.command("markets", {
|
|
2326
2760
|
description: "List Morpho markets discovered from CreateMarket events.",
|
|
2327
|
-
args:
|
|
2328
|
-
limit:
|
|
2761
|
+
args: z4.object({
|
|
2762
|
+
limit: z4.coerce.number().int().positive().max(200).default(25).describe("Max markets to return")
|
|
2329
2763
|
}),
|
|
2330
2764
|
env: env3,
|
|
2331
|
-
output:
|
|
2332
|
-
morpho:
|
|
2333
|
-
marketCount:
|
|
2334
|
-
markets:
|
|
2335
|
-
totalsByLoanToken:
|
|
2336
|
-
|
|
2337
|
-
token:
|
|
2338
|
-
symbol:
|
|
2339
|
-
decimals:
|
|
2340
|
-
totalSupplyAssets:
|
|
2341
|
-
totalBorrowAssets:
|
|
2765
|
+
output: z4.object({
|
|
2766
|
+
morpho: z4.string(),
|
|
2767
|
+
marketCount: z4.number(),
|
|
2768
|
+
markets: z4.array(lendingMarketRowSchema),
|
|
2769
|
+
totalsByLoanToken: z4.array(
|
|
2770
|
+
z4.object({
|
|
2771
|
+
token: z4.string(),
|
|
2772
|
+
symbol: z4.string(),
|
|
2773
|
+
decimals: z4.number(),
|
|
2774
|
+
totalSupplyAssets: z4.string(),
|
|
2775
|
+
totalBorrowAssets: z4.string()
|
|
2342
2776
|
})
|
|
2343
2777
|
)
|
|
2344
2778
|
}),
|
|
@@ -2354,18 +2788,39 @@ lending.command("markets", {
|
|
|
2354
2788
|
const rows = markets.map((market) => toMarketRow(market.marketId, market.params, market.state, tokenMeta)).sort(
|
|
2355
2789
|
(a, b) => BigInt(a.totalSupplyAssets) > BigInt(b.totalSupplyAssets) ? -1 : BigInt(a.totalSupplyAssets) < BigInt(b.totalSupplyAssets) ? 1 : 0
|
|
2356
2790
|
).slice(0, c.args.limit);
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2791
|
+
const firstMarket = rows[0];
|
|
2792
|
+
return c.ok(
|
|
2793
|
+
{
|
|
2794
|
+
morpho: toChecksum(ABOREAN_LENDING_ADDRESSES.morphoBlue),
|
|
2795
|
+
marketCount: marketIds.length,
|
|
2796
|
+
markets: rows,
|
|
2797
|
+
totalsByLoanToken: summarizeByLoanToken(markets, tokenMeta)
|
|
2798
|
+
},
|
|
2799
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
2800
|
+
cta: {
|
|
2801
|
+
description: "Explore lending:",
|
|
2802
|
+
commands: [
|
|
2803
|
+
...firstMarket ? [
|
|
2804
|
+
{
|
|
2805
|
+
command: "lending market",
|
|
2806
|
+
args: { marketId: firstMarket.marketId },
|
|
2807
|
+
description: `Inspect ${firstMarket.loanToken.symbol}/${firstMarket.collateralToken.symbol} market`
|
|
2808
|
+
}
|
|
2809
|
+
] : [],
|
|
2810
|
+
{
|
|
2811
|
+
command: "pools list",
|
|
2812
|
+
description: "View V2 AMM pools"
|
|
2813
|
+
}
|
|
2814
|
+
]
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
);
|
|
2363
2818
|
}
|
|
2364
2819
|
});
|
|
2365
2820
|
lending.command("market", {
|
|
2366
2821
|
description: "Get details for one Morpho market id (bytes32).",
|
|
2367
|
-
args:
|
|
2368
|
-
marketId:
|
|
2822
|
+
args: z4.object({
|
|
2823
|
+
marketId: z4.string().describe("Morpho market id (bytes32 hex)")
|
|
2369
2824
|
}),
|
|
2370
2825
|
env: env3,
|
|
2371
2826
|
output: lendingMarketRowSchema,
|
|
@@ -2401,34 +2856,53 @@ lending.command("market", {
|
|
|
2401
2856
|
const params = normalizeMarketParams(paramsRaw);
|
|
2402
2857
|
const state = normalizeMarketState(stateRaw);
|
|
2403
2858
|
const tokenMeta = await readTokenMetadata2(client, [params.loanToken, params.collateralToken]);
|
|
2404
|
-
|
|
2859
|
+
const row = toMarketRow(marketId, params, state, tokenMeta);
|
|
2860
|
+
return c.ok(
|
|
2861
|
+
row,
|
|
2862
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
2863
|
+
cta: {
|
|
2864
|
+
description: "Related commands:",
|
|
2865
|
+
commands: [
|
|
2866
|
+
{
|
|
2867
|
+
command: "lending position",
|
|
2868
|
+
args: { marketId, user: "<address>" },
|
|
2869
|
+
description: "Inspect a user position in this market"
|
|
2870
|
+
},
|
|
2871
|
+
{
|
|
2872
|
+
command: "lending markets",
|
|
2873
|
+
description: "List all Morpho markets"
|
|
2874
|
+
}
|
|
2875
|
+
]
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
);
|
|
2405
2879
|
}
|
|
2406
2880
|
});
|
|
2407
2881
|
lending.command("position", {
|
|
2408
2882
|
description: "Inspect one user position in a Morpho market.",
|
|
2409
|
-
args:
|
|
2410
|
-
marketId:
|
|
2411
|
-
user:
|
|
2883
|
+
args: z4.object({
|
|
2884
|
+
marketId: z4.string().describe("Morpho market id (bytes32 hex)"),
|
|
2885
|
+
user: z4.string().describe("Position owner address")
|
|
2412
2886
|
}),
|
|
2413
2887
|
env: env3,
|
|
2414
|
-
output:
|
|
2415
|
-
marketId:
|
|
2416
|
-
user:
|
|
2888
|
+
output: z4.object({
|
|
2889
|
+
marketId: z4.string(),
|
|
2890
|
+
user: z4.string(),
|
|
2417
2891
|
loanToken: tokenMetaSchema,
|
|
2418
2892
|
collateralToken: tokenMetaSchema,
|
|
2419
|
-
supplyShares:
|
|
2420
|
-
supplyAssetsEstimate:
|
|
2421
|
-
raw:
|
|
2422
|
-
decimal:
|
|
2893
|
+
supplyShares: z4.string(),
|
|
2894
|
+
supplyAssetsEstimate: z4.object({
|
|
2895
|
+
raw: z4.string(),
|
|
2896
|
+
decimal: z4.string()
|
|
2423
2897
|
}),
|
|
2424
|
-
borrowShares:
|
|
2425
|
-
borrowAssetsEstimate:
|
|
2426
|
-
raw:
|
|
2427
|
-
decimal:
|
|
2898
|
+
borrowShares: z4.string(),
|
|
2899
|
+
borrowAssetsEstimate: z4.object({
|
|
2900
|
+
raw: z4.string(),
|
|
2901
|
+
decimal: z4.string()
|
|
2428
2902
|
}),
|
|
2429
|
-
collateralAssets:
|
|
2430
|
-
raw:
|
|
2431
|
-
decimal:
|
|
2903
|
+
collateralAssets: z4.object({
|
|
2904
|
+
raw: z4.string(),
|
|
2905
|
+
decimal: z4.string()
|
|
2432
2906
|
})
|
|
2433
2907
|
}),
|
|
2434
2908
|
examples: [
|
|
@@ -2508,71 +2982,137 @@ lending.command("position", {
|
|
|
2508
2982
|
state.totalBorrowShares,
|
|
2509
2983
|
state.totalBorrowAssets
|
|
2510
2984
|
);
|
|
2511
|
-
return c.ok(
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2985
|
+
return c.ok(
|
|
2986
|
+
{
|
|
2987
|
+
marketId,
|
|
2988
|
+
user: toChecksum(user),
|
|
2989
|
+
loanToken: {
|
|
2990
|
+
address: toChecksum(loanMeta.address),
|
|
2991
|
+
symbol: loanMeta.symbol,
|
|
2992
|
+
decimals: loanMeta.decimals
|
|
2993
|
+
},
|
|
2994
|
+
collateralToken: {
|
|
2995
|
+
address: toChecksum(collateralMeta.address),
|
|
2996
|
+
symbol: collateralMeta.symbol,
|
|
2997
|
+
decimals: collateralMeta.decimals
|
|
2998
|
+
},
|
|
2999
|
+
supplyShares: position.supplyShares.toString(),
|
|
3000
|
+
supplyAssetsEstimate: {
|
|
3001
|
+
raw: supplyAssetsEstimate.toString(),
|
|
3002
|
+
decimal: formatUnits2(supplyAssetsEstimate, loanMeta.decimals)
|
|
3003
|
+
},
|
|
3004
|
+
borrowShares: position.borrowShares.toString(),
|
|
3005
|
+
borrowAssetsEstimate: {
|
|
3006
|
+
raw: borrowAssetsEstimate.toString(),
|
|
3007
|
+
decimal: formatUnits2(borrowAssetsEstimate, loanMeta.decimals)
|
|
3008
|
+
},
|
|
3009
|
+
collateralAssets: {
|
|
3010
|
+
raw: position.collateral.toString(),
|
|
3011
|
+
decimal: formatUnits2(BigInt(position.collateral), collateralMeta.decimals)
|
|
3012
|
+
}
|
|
2533
3013
|
},
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
3014
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
3015
|
+
cta: {
|
|
3016
|
+
description: "Related commands:",
|
|
3017
|
+
commands: [
|
|
3018
|
+
{
|
|
3019
|
+
command: "lending market",
|
|
3020
|
+
args: { marketId },
|
|
3021
|
+
description: "View market details"
|
|
3022
|
+
},
|
|
3023
|
+
{
|
|
3024
|
+
command: "lending markets",
|
|
3025
|
+
description: "List all Morpho markets"
|
|
3026
|
+
}
|
|
3027
|
+
]
|
|
3028
|
+
}
|
|
2537
3029
|
}
|
|
2538
|
-
|
|
3030
|
+
);
|
|
2539
3031
|
}
|
|
2540
3032
|
});
|
|
2541
3033
|
|
|
2542
3034
|
// src/commands/pools.ts
|
|
2543
3035
|
import { checksumAddress as checksumAddress4, isAddress as isAddress3 } from "@spectratools/cli-shared";
|
|
2544
|
-
import { Cli as Cli4, z as
|
|
3036
|
+
import { Cli as Cli4, z as z5 } from "incur";
|
|
2545
3037
|
import { formatUnits as formatUnits3, parseUnits as parseUnits2 } from "viem";
|
|
2546
3038
|
var MULTICALL_BATCH_SIZE2 = 100;
|
|
2547
|
-
var
|
|
2548
|
-
|
|
3039
|
+
var DEFAULT_SLIPPAGE_PERCENT2 = 0.5;
|
|
3040
|
+
var DEFAULT_DEADLINE_SECONDS2 = 300;
|
|
3041
|
+
var erc20ApproveAbi = [
|
|
3042
|
+
{
|
|
3043
|
+
type: "function",
|
|
3044
|
+
name: "approve",
|
|
3045
|
+
stateMutability: "nonpayable",
|
|
3046
|
+
inputs: [
|
|
3047
|
+
{ name: "spender", type: "address" },
|
|
3048
|
+
{ name: "amount", type: "uint256" }
|
|
3049
|
+
],
|
|
3050
|
+
outputs: [{ name: "", type: "bool" }]
|
|
3051
|
+
},
|
|
3052
|
+
{
|
|
3053
|
+
type: "function",
|
|
3054
|
+
name: "allowance",
|
|
3055
|
+
stateMutability: "view",
|
|
3056
|
+
inputs: [
|
|
3057
|
+
{ name: "owner", type: "address" },
|
|
3058
|
+
{ name: "account", type: "address" }
|
|
3059
|
+
],
|
|
3060
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
3061
|
+
}
|
|
3062
|
+
];
|
|
3063
|
+
var v2RouterSwapAbi = [
|
|
3064
|
+
{
|
|
3065
|
+
type: "function",
|
|
3066
|
+
name: "swapExactTokensForTokens",
|
|
3067
|
+
stateMutability: "nonpayable",
|
|
3068
|
+
inputs: [
|
|
3069
|
+
{ name: "amountIn", type: "uint256" },
|
|
3070
|
+
{ name: "amountOutMin", type: "uint256" },
|
|
3071
|
+
{
|
|
3072
|
+
name: "routes",
|
|
3073
|
+
type: "tuple[]",
|
|
3074
|
+
components: [
|
|
3075
|
+
{ name: "from", type: "address" },
|
|
3076
|
+
{ name: "to", type: "address" },
|
|
3077
|
+
{ name: "stable", type: "bool" },
|
|
3078
|
+
{ name: "factory", type: "address" }
|
|
3079
|
+
]
|
|
3080
|
+
},
|
|
3081
|
+
{ name: "to", type: "address" },
|
|
3082
|
+
{ name: "deadline", type: "uint256" }
|
|
3083
|
+
],
|
|
3084
|
+
outputs: [{ name: "amounts", type: "uint256[]" }]
|
|
3085
|
+
}
|
|
3086
|
+
];
|
|
3087
|
+
var env4 = z5.object({
|
|
3088
|
+
ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
|
|
2549
3089
|
});
|
|
2550
|
-
var tokenSchema2 =
|
|
2551
|
-
address:
|
|
2552
|
-
symbol:
|
|
2553
|
-
decimals:
|
|
3090
|
+
var tokenSchema2 = z5.object({
|
|
3091
|
+
address: z5.string(),
|
|
3092
|
+
symbol: z5.string(),
|
|
3093
|
+
decimals: z5.number()
|
|
2554
3094
|
});
|
|
2555
|
-
var amountSchema =
|
|
2556
|
-
raw:
|
|
2557
|
-
decimal:
|
|
3095
|
+
var amountSchema = z5.object({
|
|
3096
|
+
raw: z5.string(),
|
|
3097
|
+
decimal: z5.string()
|
|
2558
3098
|
});
|
|
2559
|
-
var feeSchema =
|
|
2560
|
-
feeBps:
|
|
2561
|
-
feePercent:
|
|
3099
|
+
var feeSchema = z5.object({
|
|
3100
|
+
feeBps: z5.number(),
|
|
3101
|
+
feePercent: z5.number()
|
|
2562
3102
|
}).nullable();
|
|
2563
|
-
var poolSummarySchema =
|
|
2564
|
-
pool:
|
|
2565
|
-
pair:
|
|
2566
|
-
stable:
|
|
2567
|
-
poolType:
|
|
3103
|
+
var poolSummarySchema = z5.object({
|
|
3104
|
+
pool: z5.string(),
|
|
3105
|
+
pair: z5.string(),
|
|
3106
|
+
stable: z5.boolean(),
|
|
3107
|
+
poolType: z5.enum(["stable", "volatile"]),
|
|
2568
3108
|
token0: tokenSchema2,
|
|
2569
3109
|
token1: tokenSchema2,
|
|
2570
|
-
reserves:
|
|
3110
|
+
reserves: z5.object({
|
|
2571
3111
|
token0: amountSchema,
|
|
2572
3112
|
token1: amountSchema,
|
|
2573
|
-
blockTimestampLast:
|
|
3113
|
+
blockTimestampLast: z5.number()
|
|
2574
3114
|
}),
|
|
2575
|
-
totalSupply:
|
|
3115
|
+
totalSupply: z5.string(),
|
|
2576
3116
|
fee: feeSchema
|
|
2577
3117
|
});
|
|
2578
3118
|
var erc20MetadataAbi3 = [
|
|
@@ -2777,17 +3317,17 @@ var pools = Cli4.create("pools", {
|
|
|
2777
3317
|
});
|
|
2778
3318
|
pools.command("list", {
|
|
2779
3319
|
description: "List V2 pools with token pairs, reserves, and stable/volatile type.",
|
|
2780
|
-
options:
|
|
2781
|
-
offset:
|
|
2782
|
-
limit:
|
|
3320
|
+
options: z5.object({
|
|
3321
|
+
offset: z5.coerce.number().int().nonnegative().default(0).describe("Pool index offset"),
|
|
3322
|
+
limit: z5.coerce.number().int().positive().max(500).default(50).describe("Maximum pools to return (max 500)")
|
|
2783
3323
|
}),
|
|
2784
3324
|
env: env4,
|
|
2785
|
-
output:
|
|
2786
|
-
total:
|
|
2787
|
-
offset:
|
|
2788
|
-
limit:
|
|
2789
|
-
count:
|
|
2790
|
-
pools:
|
|
3325
|
+
output: z5.object({
|
|
3326
|
+
total: z5.number(),
|
|
3327
|
+
offset: z5.number(),
|
|
3328
|
+
limit: z5.number(),
|
|
3329
|
+
count: z5.number(),
|
|
3330
|
+
pools: z5.array(poolSummarySchema)
|
|
2791
3331
|
}),
|
|
2792
3332
|
async run(c) {
|
|
2793
3333
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -2827,25 +3367,52 @@ pools.command("list", {
|
|
|
2827
3367
|
client,
|
|
2828
3368
|
poolStates.map((pool) => ({ pool: pool.pool, stable: pool.stable }))
|
|
2829
3369
|
);
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
3370
|
+
const summaries = poolStates.map(
|
|
3371
|
+
(pool, index) => toPoolSummary(pool, tokenMeta, fees[index] ?? null)
|
|
3372
|
+
);
|
|
3373
|
+
const firstPool = summaries[0];
|
|
3374
|
+
return c.ok(
|
|
3375
|
+
{
|
|
3376
|
+
total,
|
|
3377
|
+
offset,
|
|
3378
|
+
limit: c.options.limit,
|
|
3379
|
+
count: summaries.length,
|
|
3380
|
+
pools: summaries
|
|
3381
|
+
},
|
|
3382
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
3383
|
+
cta: {
|
|
3384
|
+
description: "Explore pools:",
|
|
3385
|
+
commands: [
|
|
3386
|
+
...firstPool ? [
|
|
3387
|
+
{
|
|
3388
|
+
command: "pools pool",
|
|
3389
|
+
args: { address: firstPool.pool },
|
|
3390
|
+
description: `Inspect ${firstPool.pair}`
|
|
3391
|
+
}
|
|
3392
|
+
] : [],
|
|
3393
|
+
...firstPool ? [
|
|
3394
|
+
{
|
|
3395
|
+
command: "pools fees",
|
|
3396
|
+
args: { pool: firstPool.pool },
|
|
3397
|
+
description: `Check fees for ${firstPool.pair}`
|
|
3398
|
+
}
|
|
3399
|
+
] : []
|
|
3400
|
+
]
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
);
|
|
2837
3404
|
}
|
|
2838
3405
|
});
|
|
2839
3406
|
pools.command("pool", {
|
|
2840
3407
|
description: "Get detailed state for one V2 pool.",
|
|
2841
|
-
args:
|
|
2842
|
-
address:
|
|
3408
|
+
args: z5.object({
|
|
3409
|
+
address: z5.string().describe("Pool address")
|
|
2843
3410
|
}),
|
|
2844
3411
|
env: env4,
|
|
2845
|
-
output:
|
|
3412
|
+
output: z5.object({
|
|
2846
3413
|
pool: poolSummarySchema.extend({
|
|
2847
|
-
poolFees:
|
|
2848
|
-
factory:
|
|
3414
|
+
poolFees: z5.string(),
|
|
3415
|
+
factory: z5.string()
|
|
2849
3416
|
})
|
|
2850
3417
|
}),
|
|
2851
3418
|
async run(c) {
|
|
@@ -2896,47 +3463,71 @@ pools.command("pool", {
|
|
|
2896
3463
|
]);
|
|
2897
3464
|
const tokenMeta = await readTokenMetadata3(client, [token0, token1]);
|
|
2898
3465
|
const [fee] = await readPoolFees(client, [{ pool: poolAddress, stable }]);
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
3466
|
+
const summary = toPoolSummary(
|
|
3467
|
+
{
|
|
3468
|
+
pool: poolAddress,
|
|
3469
|
+
token0,
|
|
3470
|
+
token1,
|
|
3471
|
+
stable,
|
|
3472
|
+
reserve0: reserves[0],
|
|
3473
|
+
reserve1: reserves[1],
|
|
3474
|
+
blockTimestampLast: reserves[2],
|
|
3475
|
+
totalSupply
|
|
3476
|
+
},
|
|
3477
|
+
tokenMeta,
|
|
3478
|
+
fee ?? null
|
|
3479
|
+
);
|
|
3480
|
+
return c.ok(
|
|
3481
|
+
{
|
|
3482
|
+
pool: {
|
|
3483
|
+
...summary,
|
|
3484
|
+
poolFees: checksumAddress4(poolFees),
|
|
3485
|
+
factory: checksumAddress4(factory)
|
|
3486
|
+
}
|
|
3487
|
+
},
|
|
3488
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
3489
|
+
cta: {
|
|
3490
|
+
description: "Next steps:",
|
|
3491
|
+
commands: [
|
|
3492
|
+
{
|
|
3493
|
+
command: "pools quote",
|
|
3494
|
+
args: {
|
|
3495
|
+
tokenIn: summary.token0.address,
|
|
3496
|
+
tokenOut: summary.token1.address,
|
|
3497
|
+
amountIn: "1"
|
|
3498
|
+
},
|
|
3499
|
+
description: `Quote a ${summary.token0.symbol} \u2192 ${summary.token1.symbol} swap`
|
|
3500
|
+
},
|
|
3501
|
+
{
|
|
3502
|
+
command: "pools fees",
|
|
3503
|
+
args: { pool: checksumAddress4(poolAddress) },
|
|
3504
|
+
description: "Check fee configuration"
|
|
3505
|
+
}
|
|
3506
|
+
]
|
|
3507
|
+
}
|
|
2917
3508
|
}
|
|
2918
|
-
|
|
3509
|
+
);
|
|
2919
3510
|
}
|
|
2920
3511
|
});
|
|
2921
3512
|
pools.command("quote", {
|
|
2922
3513
|
description: "Quote a single-hop V2 swap between tokenIn and tokenOut.",
|
|
2923
|
-
args:
|
|
2924
|
-
tokenIn:
|
|
2925
|
-
tokenOut:
|
|
2926
|
-
amountIn:
|
|
3514
|
+
args: z5.object({
|
|
3515
|
+
tokenIn: z5.string().describe("Input token address"),
|
|
3516
|
+
tokenOut: z5.string().describe("Output token address"),
|
|
3517
|
+
amountIn: z5.string().describe("Input amount in human-readable decimal units")
|
|
2927
3518
|
}),
|
|
2928
|
-
options:
|
|
2929
|
-
stable:
|
|
3519
|
+
options: z5.object({
|
|
3520
|
+
stable: z5.boolean().default(false).describe("Use stable pool route (default: volatile)")
|
|
2930
3521
|
}),
|
|
2931
3522
|
env: env4,
|
|
2932
|
-
output:
|
|
2933
|
-
pool:
|
|
2934
|
-
stable:
|
|
3523
|
+
output: z5.object({
|
|
3524
|
+
pool: z5.string(),
|
|
3525
|
+
stable: z5.boolean(),
|
|
2935
3526
|
tokenIn: tokenSchema2,
|
|
2936
3527
|
tokenOut: tokenSchema2,
|
|
2937
3528
|
amountIn: amountSchema,
|
|
2938
3529
|
amountOut: amountSchema,
|
|
2939
|
-
priceOutPerIn:
|
|
3530
|
+
priceOutPerIn: z5.number().nullable()
|
|
2940
3531
|
}),
|
|
2941
3532
|
async run(c) {
|
|
2942
3533
|
if (!isAddress3(c.args.tokenIn) || !isAddress3(c.args.tokenOut)) {
|
|
@@ -2994,33 +3585,56 @@ pools.command("quote", {
|
|
|
2994
3585
|
const amountInDecimal = formatUnits3(amountInRaw, inMeta.decimals);
|
|
2995
3586
|
const amountOutDecimal = formatUnits3(amountOutRaw, outMeta.decimals);
|
|
2996
3587
|
const ratio = Number(amountOutDecimal) / Number(amountInDecimal);
|
|
2997
|
-
return c.ok(
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3588
|
+
return c.ok(
|
|
3589
|
+
{
|
|
3590
|
+
pool: checksumAddress4(poolAddress),
|
|
3591
|
+
stable: c.options.stable,
|
|
3592
|
+
tokenIn: inMeta,
|
|
3593
|
+
tokenOut: outMeta,
|
|
3594
|
+
amountIn: {
|
|
3595
|
+
raw: amountInRaw.toString(),
|
|
3596
|
+
decimal: amountInDecimal
|
|
3597
|
+
},
|
|
3598
|
+
amountOut: {
|
|
3599
|
+
raw: amountOutRaw.toString(),
|
|
3600
|
+
decimal: amountOutDecimal
|
|
3601
|
+
},
|
|
3602
|
+
priceOutPerIn: Number(amountInDecimal) === 0 ? null : finiteOrNull3(ratio)
|
|
3009
3603
|
},
|
|
3010
|
-
|
|
3011
|
-
|
|
3604
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
3605
|
+
cta: {
|
|
3606
|
+
description: "Related commands:",
|
|
3607
|
+
commands: [
|
|
3608
|
+
{
|
|
3609
|
+
command: "pools pool",
|
|
3610
|
+
args: { address: checksumAddress4(poolAddress) },
|
|
3611
|
+
description: "Inspect the pool used for this quote"
|
|
3612
|
+
},
|
|
3613
|
+
{
|
|
3614
|
+
command: "pools quote",
|
|
3615
|
+
args: {
|
|
3616
|
+
tokenIn: outMeta.address,
|
|
3617
|
+
tokenOut: inMeta.address,
|
|
3618
|
+
amountIn: amountOutDecimal
|
|
3619
|
+
},
|
|
3620
|
+
description: `Reverse quote ${outMeta.symbol} \u2192 ${inMeta.symbol}`
|
|
3621
|
+
}
|
|
3622
|
+
]
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
);
|
|
3012
3626
|
}
|
|
3013
3627
|
});
|
|
3014
3628
|
pools.command("fees", {
|
|
3015
3629
|
description: "Read V2 fee configuration for a pool address.",
|
|
3016
|
-
args:
|
|
3017
|
-
pool:
|
|
3630
|
+
args: z5.object({
|
|
3631
|
+
pool: z5.string().describe("Pool address")
|
|
3018
3632
|
}),
|
|
3019
3633
|
env: env4,
|
|
3020
|
-
output:
|
|
3021
|
-
pool:
|
|
3022
|
-
pair:
|
|
3023
|
-
stable:
|
|
3634
|
+
output: z5.object({
|
|
3635
|
+
pool: z5.string(),
|
|
3636
|
+
pair: z5.string(),
|
|
3637
|
+
stable: z5.boolean(),
|
|
3024
3638
|
activeFee: feeSchema,
|
|
3025
3639
|
stableFee: feeSchema,
|
|
3026
3640
|
volatileFee: feeSchema
|
|
@@ -3060,22 +3674,206 @@ pools.command("fees", {
|
|
|
3060
3674
|
]);
|
|
3061
3675
|
const stableFee = toFeeInfo(stableFeeRaw ?? null);
|
|
3062
3676
|
const volatileFee = toFeeInfo(volatileFeeRaw ?? null);
|
|
3677
|
+
return c.ok(
|
|
3678
|
+
{
|
|
3679
|
+
pool: checksumAddress4(pool),
|
|
3680
|
+
pair: `${token0Meta.symbol}/${token1Meta.symbol}`,
|
|
3681
|
+
stable,
|
|
3682
|
+
activeFee: stable ? stableFee : volatileFee,
|
|
3683
|
+
stableFee,
|
|
3684
|
+
volatileFee
|
|
3685
|
+
},
|
|
3686
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
3687
|
+
cta: {
|
|
3688
|
+
description: "Related commands:",
|
|
3689
|
+
commands: [
|
|
3690
|
+
{
|
|
3691
|
+
command: "pools pool",
|
|
3692
|
+
args: { address: checksumAddress4(pool) },
|
|
3693
|
+
description: "View full pool state"
|
|
3694
|
+
},
|
|
3695
|
+
{
|
|
3696
|
+
command: "pools quote",
|
|
3697
|
+
args: {
|
|
3698
|
+
tokenIn: token0Meta.address,
|
|
3699
|
+
tokenOut: token1Meta.address,
|
|
3700
|
+
amountIn: "1"
|
|
3701
|
+
},
|
|
3702
|
+
description: `Quote a ${token0Meta.symbol} \u2192 ${token1Meta.symbol} swap`
|
|
3703
|
+
}
|
|
3704
|
+
]
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
);
|
|
3708
|
+
}
|
|
3709
|
+
});
|
|
3710
|
+
pools.command("swap", {
|
|
3711
|
+
description: "Execute a single-hop V2 AMM swap. Quotes the expected output, applies slippage tolerance, approves the router if needed, and broadcasts the swap transaction.",
|
|
3712
|
+
options: z5.object({
|
|
3713
|
+
"token-in": z5.string().describe("Input token address"),
|
|
3714
|
+
"token-out": z5.string().describe("Output token address"),
|
|
3715
|
+
"amount-in": z5.string().describe("Input amount in wei"),
|
|
3716
|
+
slippage: z5.coerce.number().min(0).max(100).default(DEFAULT_SLIPPAGE_PERCENT2).describe("Slippage tolerance in percent (default: 0.5)"),
|
|
3717
|
+
deadline: z5.coerce.number().int().positive().default(DEFAULT_DEADLINE_SECONDS2).describe("Transaction deadline in seconds from now (default: 300)"),
|
|
3718
|
+
stable: z5.boolean().default(false).describe("Use stable pool route (default: volatile)")
|
|
3719
|
+
}).merge(writeOptions),
|
|
3720
|
+
env: writeEnv,
|
|
3721
|
+
output: z5.object({
|
|
3722
|
+
pool: z5.string(),
|
|
3723
|
+
stable: z5.boolean(),
|
|
3724
|
+
tokenIn: tokenSchema2,
|
|
3725
|
+
tokenOut: tokenSchema2,
|
|
3726
|
+
amountIn: amountSchema,
|
|
3727
|
+
expectedAmountOut: amountSchema,
|
|
3728
|
+
minAmountOut: amountSchema,
|
|
3729
|
+
slippagePercent: z5.number(),
|
|
3730
|
+
effectivePrice: z5.number().nullable(),
|
|
3731
|
+
tx: z5.union([
|
|
3732
|
+
z5.object({
|
|
3733
|
+
txHash: z5.string(),
|
|
3734
|
+
blockNumber: z5.number(),
|
|
3735
|
+
gasUsed: z5.string()
|
|
3736
|
+
}),
|
|
3737
|
+
z5.object({
|
|
3738
|
+
dryRun: z5.literal(true),
|
|
3739
|
+
estimatedGas: z5.string(),
|
|
3740
|
+
simulationResult: z5.unknown()
|
|
3741
|
+
})
|
|
3742
|
+
])
|
|
3743
|
+
}),
|
|
3744
|
+
async run(c) {
|
|
3745
|
+
const tokenInRaw = c.options["token-in"];
|
|
3746
|
+
const tokenOutRaw = c.options["token-out"];
|
|
3747
|
+
if (!isAddress3(tokenInRaw) || !isAddress3(tokenOutRaw)) {
|
|
3748
|
+
return c.error({
|
|
3749
|
+
code: "INVALID_ADDRESS",
|
|
3750
|
+
message: "token-in and token-out must both be valid 0x-prefixed 20-byte addresses."
|
|
3751
|
+
});
|
|
3752
|
+
}
|
|
3753
|
+
const tokenIn = toAddress(tokenInRaw);
|
|
3754
|
+
const tokenOut = toAddress(tokenOutRaw);
|
|
3755
|
+
const amountInRaw = BigInt(c.options["amount-in"]);
|
|
3756
|
+
if (amountInRaw <= 0n) {
|
|
3757
|
+
return c.error({
|
|
3758
|
+
code: "INVALID_AMOUNT",
|
|
3759
|
+
message: "amount-in must be a positive integer in wei."
|
|
3760
|
+
});
|
|
3761
|
+
}
|
|
3762
|
+
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3763
|
+
const tokenMeta = await readTokenMetadata3(client, [tokenIn, tokenOut]);
|
|
3764
|
+
const inMeta = tokenMeta.get(tokenIn.toLowerCase()) ?? fallbackTokenMeta(tokenIn);
|
|
3765
|
+
const outMeta = tokenMeta.get(tokenOut.toLowerCase()) ?? fallbackTokenMeta(tokenOut);
|
|
3766
|
+
const poolAddress = await client.readContract({
|
|
3767
|
+
abi: poolFactoryAbi,
|
|
3768
|
+
address: ABOREAN_V2_ADDRESSES.poolFactory,
|
|
3769
|
+
functionName: "getPool",
|
|
3770
|
+
args: [tokenIn, tokenOut, c.options.stable]
|
|
3771
|
+
});
|
|
3772
|
+
if (poolAddress.toLowerCase() === ZERO_ADDRESS.toLowerCase()) {
|
|
3773
|
+
return c.error({
|
|
3774
|
+
code: "POOL_NOT_FOUND",
|
|
3775
|
+
message: `No ${c.options.stable ? "stable" : "volatile"} V2 pool found for pair ${checksumAddress4(tokenIn)}/${checksumAddress4(tokenOut)}.`
|
|
3776
|
+
});
|
|
3777
|
+
}
|
|
3778
|
+
const amounts = await client.readContract({
|
|
3779
|
+
abi: v2RouterAbi,
|
|
3780
|
+
address: ABOREAN_V2_ADDRESSES.router,
|
|
3781
|
+
functionName: "getAmountsOut",
|
|
3782
|
+
args: [
|
|
3783
|
+
amountInRaw,
|
|
3784
|
+
[
|
|
3785
|
+
{
|
|
3786
|
+
from: tokenIn,
|
|
3787
|
+
to: tokenOut,
|
|
3788
|
+
stable: c.options.stable,
|
|
3789
|
+
factory: ABOREAN_V2_ADDRESSES.poolFactory
|
|
3790
|
+
}
|
|
3791
|
+
]
|
|
3792
|
+
]
|
|
3793
|
+
});
|
|
3794
|
+
const expectedAmountOut = amounts[amounts.length - 1] ?? 0n;
|
|
3795
|
+
if (expectedAmountOut === 0n) {
|
|
3796
|
+
return c.error({
|
|
3797
|
+
code: "ZERO_QUOTE",
|
|
3798
|
+
message: "Router returned zero output amount. The pool may have insufficient liquidity."
|
|
3799
|
+
});
|
|
3800
|
+
}
|
|
3801
|
+
const slippageBps = Math.round(c.options.slippage * 100);
|
|
3802
|
+
const minAmountOut = expectedAmountOut * BigInt(1e4 - slippageBps) / 10000n;
|
|
3803
|
+
const deadlineTimestamp = BigInt(Math.floor(Date.now() / 1e3) + c.options.deadline);
|
|
3804
|
+
const account = resolveAccount(c.env);
|
|
3805
|
+
if (!c.options["dry-run"]) {
|
|
3806
|
+
const currentAllowance = await client.readContract({
|
|
3807
|
+
abi: erc20ApproveAbi,
|
|
3808
|
+
address: tokenIn,
|
|
3809
|
+
functionName: "allowance",
|
|
3810
|
+
args: [account.address, ABOREAN_V2_ADDRESSES.router]
|
|
3811
|
+
});
|
|
3812
|
+
if (currentAllowance < amountInRaw) {
|
|
3813
|
+
await aboreanWriteTx({
|
|
3814
|
+
env: c.env,
|
|
3815
|
+
options: { ...c.options, "dry-run": false },
|
|
3816
|
+
address: tokenIn,
|
|
3817
|
+
abi: erc20ApproveAbi,
|
|
3818
|
+
functionName: "approve",
|
|
3819
|
+
args: [ABOREAN_V2_ADDRESSES.router, amountInRaw]
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
const tx = await aboreanWriteTx({
|
|
3824
|
+
env: c.env,
|
|
3825
|
+
options: c.options,
|
|
3826
|
+
address: ABOREAN_V2_ADDRESSES.router,
|
|
3827
|
+
abi: v2RouterSwapAbi,
|
|
3828
|
+
functionName: "swapExactTokensForTokens",
|
|
3829
|
+
args: [
|
|
3830
|
+
amountInRaw,
|
|
3831
|
+
minAmountOut,
|
|
3832
|
+
[
|
|
3833
|
+
{
|
|
3834
|
+
from: tokenIn,
|
|
3835
|
+
to: tokenOut,
|
|
3836
|
+
stable: c.options.stable,
|
|
3837
|
+
factory: ABOREAN_V2_ADDRESSES.poolFactory
|
|
3838
|
+
}
|
|
3839
|
+
],
|
|
3840
|
+
account.address,
|
|
3841
|
+
deadlineTimestamp
|
|
3842
|
+
]
|
|
3843
|
+
});
|
|
3844
|
+
const amountInDecimal = formatUnits3(amountInRaw, inMeta.decimals);
|
|
3845
|
+
const expectedOutDecimal = formatUnits3(expectedAmountOut, outMeta.decimals);
|
|
3846
|
+
const minOutDecimal = formatUnits3(minAmountOut, outMeta.decimals);
|
|
3847
|
+
const ratio = Number(expectedOutDecimal) / Number(amountInDecimal);
|
|
3063
3848
|
return c.ok({
|
|
3064
|
-
pool: checksumAddress4(
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3849
|
+
pool: checksumAddress4(poolAddress),
|
|
3850
|
+
stable: c.options.stable,
|
|
3851
|
+
tokenIn: inMeta,
|
|
3852
|
+
tokenOut: outMeta,
|
|
3853
|
+
amountIn: {
|
|
3854
|
+
raw: amountInRaw.toString(),
|
|
3855
|
+
decimal: amountInDecimal
|
|
3856
|
+
},
|
|
3857
|
+
expectedAmountOut: {
|
|
3858
|
+
raw: expectedAmountOut.toString(),
|
|
3859
|
+
decimal: expectedOutDecimal
|
|
3860
|
+
},
|
|
3861
|
+
minAmountOut: {
|
|
3862
|
+
raw: minAmountOut.toString(),
|
|
3863
|
+
decimal: minOutDecimal
|
|
3864
|
+
},
|
|
3865
|
+
slippagePercent: c.options.slippage,
|
|
3866
|
+
effectivePrice: Number(amountInDecimal) === 0 ? null : finiteOrNull3(ratio),
|
|
3867
|
+
tx
|
|
3070
3868
|
});
|
|
3071
3869
|
}
|
|
3072
3870
|
});
|
|
3073
3871
|
|
|
3074
3872
|
// src/commands/vaults.ts
|
|
3075
3873
|
import { checksumAddress as checksumAddress5, isAddress as isAddress4 } from "@spectratools/cli-shared";
|
|
3076
|
-
import { Cli as Cli5, z as
|
|
3077
|
-
var env5 =
|
|
3078
|
-
ABSTRACT_RPC_URL:
|
|
3874
|
+
import { Cli as Cli5, z as z6 } from "incur";
|
|
3875
|
+
var env5 = z6.object({
|
|
3876
|
+
ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
|
|
3079
3877
|
});
|
|
3080
3878
|
var relayAbi = [
|
|
3081
3879
|
{
|
|
@@ -3139,22 +3937,22 @@ var votingEscrowLiteAbi = [
|
|
|
3139
3937
|
outputs: [{ type: "uint256" }]
|
|
3140
3938
|
}
|
|
3141
3939
|
];
|
|
3142
|
-
var relayRowSchema =
|
|
3143
|
-
label:
|
|
3144
|
-
relay:
|
|
3145
|
-
name:
|
|
3146
|
-
factoryType:
|
|
3147
|
-
managedTokenId:
|
|
3148
|
-
managedVotingPower:
|
|
3149
|
-
relayToken:
|
|
3150
|
-
address:
|
|
3151
|
-
symbol:
|
|
3152
|
-
decimals:
|
|
3940
|
+
var relayRowSchema = z6.object({
|
|
3941
|
+
label: z6.string(),
|
|
3942
|
+
relay: z6.string(),
|
|
3943
|
+
name: z6.string(),
|
|
3944
|
+
factoryType: z6.enum(["autoCompounder", "autoConverter"]),
|
|
3945
|
+
managedTokenId: z6.string(),
|
|
3946
|
+
managedVotingPower: z6.string(),
|
|
3947
|
+
relayToken: z6.object({
|
|
3948
|
+
address: z6.string(),
|
|
3949
|
+
symbol: z6.string(),
|
|
3950
|
+
decimals: z6.number()
|
|
3153
3951
|
}),
|
|
3154
|
-
relayTokenBalance:
|
|
3155
|
-
keeperLastRun:
|
|
3156
|
-
keeperLastRunRelative:
|
|
3157
|
-
secondsSinceKeeperRun:
|
|
3952
|
+
relayTokenBalance: z6.string(),
|
|
3953
|
+
keeperLastRun: z6.number(),
|
|
3954
|
+
keeperLastRunRelative: z6.string(),
|
|
3955
|
+
secondsSinceKeeperRun: z6.number()
|
|
3158
3956
|
});
|
|
3159
3957
|
var KNOWN_RELAYS = [
|
|
3160
3958
|
{
|
|
@@ -3280,17 +4078,17 @@ var vaults = Cli5.create("vaults", {
|
|
|
3280
4078
|
vaults.command("list", {
|
|
3281
4079
|
description: "List known Aborean relay vaults with keeper and veNFT state.",
|
|
3282
4080
|
env: env5,
|
|
3283
|
-
output:
|
|
3284
|
-
relayCount:
|
|
3285
|
-
relays:
|
|
3286
|
-
totals:
|
|
3287
|
-
managedVotingPower:
|
|
3288
|
-
relayTokenBalances:
|
|
3289
|
-
|
|
3290
|
-
token:
|
|
3291
|
-
symbol:
|
|
3292
|
-
decimals:
|
|
3293
|
-
balance:
|
|
4081
|
+
output: z6.object({
|
|
4082
|
+
relayCount: z6.number(),
|
|
4083
|
+
relays: z6.array(relayRowSchema),
|
|
4084
|
+
totals: z6.object({
|
|
4085
|
+
managedVotingPower: z6.string(),
|
|
4086
|
+
relayTokenBalances: z6.array(
|
|
4087
|
+
z6.object({
|
|
4088
|
+
token: z6.string(),
|
|
4089
|
+
symbol: z6.string(),
|
|
4090
|
+
decimals: z6.number(),
|
|
4091
|
+
balance: z6.string()
|
|
3294
4092
|
})
|
|
3295
4093
|
)
|
|
3296
4094
|
})
|
|
@@ -3299,13 +4097,38 @@ vaults.command("list", {
|
|
|
3299
4097
|
async run(c) {
|
|
3300
4098
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3301
4099
|
const snapshot = await readVaultSummary(client);
|
|
3302
|
-
|
|
4100
|
+
const firstRelay = snapshot.relays[0];
|
|
4101
|
+
return c.ok(
|
|
4102
|
+
snapshot,
|
|
4103
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4104
|
+
cta: {
|
|
4105
|
+
description: "Related commands:",
|
|
4106
|
+
commands: [
|
|
4107
|
+
...firstRelay ? [
|
|
4108
|
+
{
|
|
4109
|
+
command: "vaults relay",
|
|
4110
|
+
args: { relay: firstRelay.relay },
|
|
4111
|
+
description: `Inspect ${firstRelay.label}`
|
|
4112
|
+
}
|
|
4113
|
+
] : [],
|
|
4114
|
+
{
|
|
4115
|
+
command: "lending markets",
|
|
4116
|
+
description: "View Morpho lending markets"
|
|
4117
|
+
},
|
|
4118
|
+
{
|
|
4119
|
+
command: "ve stats",
|
|
4120
|
+
description: "View veABX global stats"
|
|
4121
|
+
}
|
|
4122
|
+
]
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
);
|
|
3303
4126
|
}
|
|
3304
4127
|
});
|
|
3305
4128
|
vaults.command("relay", {
|
|
3306
4129
|
description: "Inspect one relay vault by address.",
|
|
3307
|
-
args:
|
|
3308
|
-
relay:
|
|
4130
|
+
args: z6.object({
|
|
4131
|
+
relay: z6.string().describe("Relay vault contract address")
|
|
3309
4132
|
}),
|
|
3310
4133
|
env: env5,
|
|
3311
4134
|
output: relayRowSchema,
|
|
@@ -3334,14 +4157,32 @@ vaults.command("relay", {
|
|
|
3334
4157
|
}
|
|
3335
4158
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
3336
4159
|
const snapshot = await readRelaySnapshot(client, known);
|
|
3337
|
-
return c.ok(
|
|
4160
|
+
return c.ok(
|
|
4161
|
+
snapshot,
|
|
4162
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4163
|
+
cta: {
|
|
4164
|
+
description: "Related commands:",
|
|
4165
|
+
commands: [
|
|
4166
|
+
{
|
|
4167
|
+
command: "vaults list",
|
|
4168
|
+
description: "List all relay vaults"
|
|
4169
|
+
},
|
|
4170
|
+
{
|
|
4171
|
+
command: "ve lock",
|
|
4172
|
+
args: { tokenId: Number(snapshot.managedTokenId) },
|
|
4173
|
+
description: `Inspect managed veNFT #${snapshot.managedTokenId}`
|
|
4174
|
+
}
|
|
4175
|
+
]
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
);
|
|
3338
4179
|
}
|
|
3339
4180
|
});
|
|
3340
4181
|
|
|
3341
4182
|
// src/commands/ve.ts
|
|
3342
|
-
import { Cli as Cli6, z as
|
|
3343
|
-
var env6 =
|
|
3344
|
-
ABSTRACT_RPC_URL:
|
|
4183
|
+
import { Cli as Cli6, z as z7 } from "incur";
|
|
4184
|
+
var env6 = z7.object({
|
|
4185
|
+
ABSTRACT_RPC_URL: z7.string().optional().describe("Abstract RPC URL override")
|
|
3345
4186
|
});
|
|
3346
4187
|
var ve = Cli6.create("ve", {
|
|
3347
4188
|
description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
|
|
@@ -3349,16 +4190,16 @@ var ve = Cli6.create("ve", {
|
|
|
3349
4190
|
ve.command("stats", {
|
|
3350
4191
|
description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
|
|
3351
4192
|
env: env6,
|
|
3352
|
-
output:
|
|
3353
|
-
token:
|
|
3354
|
-
totalVotingPower:
|
|
3355
|
-
totalLocked:
|
|
3356
|
-
permanentLocked:
|
|
3357
|
-
epoch:
|
|
3358
|
-
decayBias:
|
|
3359
|
-
decaySlope:
|
|
3360
|
-
lastCheckpointTimestamp:
|
|
3361
|
-
lastCheckpointBlock:
|
|
4193
|
+
output: z7.object({
|
|
4194
|
+
token: z7.string(),
|
|
4195
|
+
totalVotingPower: z7.string(),
|
|
4196
|
+
totalLocked: z7.string(),
|
|
4197
|
+
permanentLocked: z7.string(),
|
|
4198
|
+
epoch: z7.number(),
|
|
4199
|
+
decayBias: z7.string(),
|
|
4200
|
+
decaySlope: z7.string(),
|
|
4201
|
+
lastCheckpointTimestamp: z7.number(),
|
|
4202
|
+
lastCheckpointBlock: z7.number()
|
|
3362
4203
|
}),
|
|
3363
4204
|
examples: [{ description: "Show global veABX state and decay metrics" }],
|
|
3364
4205
|
async run(c) {
|
|
@@ -3396,32 +4237,50 @@ ve.command("stats", {
|
|
|
3396
4237
|
functionName: "pointHistory",
|
|
3397
4238
|
args: [epoch]
|
|
3398
4239
|
});
|
|
3399
|
-
return c.ok(
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
4240
|
+
return c.ok(
|
|
4241
|
+
{
|
|
4242
|
+
token: toChecksum(token),
|
|
4243
|
+
totalVotingPower: totalVotingPower.toString(),
|
|
4244
|
+
totalLocked: totalLocked.toString(),
|
|
4245
|
+
permanentLocked: permanentLocked.toString(),
|
|
4246
|
+
epoch: asNum(epoch),
|
|
4247
|
+
decayBias: point.bias.toString(),
|
|
4248
|
+
decaySlope: point.slope.toString(),
|
|
4249
|
+
lastCheckpointTimestamp: asNum(point.ts),
|
|
4250
|
+
lastCheckpointBlock: asNum(point.blk)
|
|
4251
|
+
},
|
|
4252
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4253
|
+
cta: {
|
|
4254
|
+
description: "Explore veABX:",
|
|
4255
|
+
commands: [
|
|
4256
|
+
{
|
|
4257
|
+
command: "ve locks",
|
|
4258
|
+
args: { address: "<owner>" },
|
|
4259
|
+
description: "List veNFT locks for an address"
|
|
4260
|
+
},
|
|
4261
|
+
{
|
|
4262
|
+
command: "voter epoch",
|
|
4263
|
+
description: "View current emissions epoch timing"
|
|
4264
|
+
}
|
|
4265
|
+
]
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
);
|
|
3410
4269
|
}
|
|
3411
4270
|
});
|
|
3412
4271
|
ve.command("lock", {
|
|
3413
4272
|
description: "Get lock details and voting power for one veNFT token id.",
|
|
3414
|
-
args:
|
|
3415
|
-
tokenId:
|
|
4273
|
+
args: z7.object({
|
|
4274
|
+
tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3416
4275
|
}),
|
|
3417
4276
|
env: env6,
|
|
3418
|
-
output:
|
|
3419
|
-
tokenId:
|
|
3420
|
-
owner:
|
|
3421
|
-
amount:
|
|
3422
|
-
unlockTime:
|
|
3423
|
-
isPermanent:
|
|
3424
|
-
votingPower:
|
|
4277
|
+
output: z7.object({
|
|
4278
|
+
tokenId: z7.number(),
|
|
4279
|
+
owner: z7.string(),
|
|
4280
|
+
amount: z7.string(),
|
|
4281
|
+
unlockTime: z7.number(),
|
|
4282
|
+
isPermanent: z7.boolean(),
|
|
4283
|
+
votingPower: z7.string()
|
|
3425
4284
|
}),
|
|
3426
4285
|
examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
|
|
3427
4286
|
async run(c) {
|
|
@@ -3447,34 +4306,53 @@ ve.command("lock", {
|
|
|
3447
4306
|
args: [tokenId]
|
|
3448
4307
|
})
|
|
3449
4308
|
]);
|
|
3450
|
-
return c.ok(
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
4309
|
+
return c.ok(
|
|
4310
|
+
{
|
|
4311
|
+
tokenId: c.args.tokenId,
|
|
4312
|
+
owner: toChecksum(owner),
|
|
4313
|
+
amount: locked.amount.toString(),
|
|
4314
|
+
unlockTime: asNum(locked.end),
|
|
4315
|
+
isPermanent: locked.isPermanent,
|
|
4316
|
+
votingPower: votingPower.toString()
|
|
4317
|
+
},
|
|
4318
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4319
|
+
cta: {
|
|
4320
|
+
description: "Related commands:",
|
|
4321
|
+
commands: [
|
|
4322
|
+
{
|
|
4323
|
+
command: "ve voting-power",
|
|
4324
|
+
args: { tokenId: c.args.tokenId },
|
|
4325
|
+
description: "Check current voting power"
|
|
4326
|
+
},
|
|
4327
|
+
{
|
|
4328
|
+
command: "voter rewards",
|
|
4329
|
+
args: { tokenId: c.args.tokenId },
|
|
4330
|
+
description: "Check claimable rewards for this veNFT"
|
|
4331
|
+
}
|
|
4332
|
+
]
|
|
4333
|
+
}
|
|
4334
|
+
}
|
|
4335
|
+
);
|
|
3458
4336
|
}
|
|
3459
4337
|
});
|
|
3460
4338
|
ve.command("locks", {
|
|
3461
4339
|
description: "List all veNFT locks owned by an address.",
|
|
3462
|
-
args:
|
|
3463
|
-
address:
|
|
4340
|
+
args: z7.object({
|
|
4341
|
+
address: z7.string().describe("Owner address")
|
|
3464
4342
|
}),
|
|
3465
4343
|
env: env6,
|
|
3466
|
-
output:
|
|
3467
|
-
address:
|
|
3468
|
-
locks:
|
|
3469
|
-
|
|
3470
|
-
tokenId:
|
|
3471
|
-
amount:
|
|
3472
|
-
unlockTime:
|
|
3473
|
-
isPermanent:
|
|
3474
|
-
votingPower:
|
|
4344
|
+
output: z7.object({
|
|
4345
|
+
address: z7.string(),
|
|
4346
|
+
locks: z7.array(
|
|
4347
|
+
z7.object({
|
|
4348
|
+
tokenId: z7.string(),
|
|
4349
|
+
amount: z7.string(),
|
|
4350
|
+
unlockTime: z7.number(),
|
|
4351
|
+
isPermanent: z7.boolean(),
|
|
4352
|
+
votingPower: z7.string()
|
|
3475
4353
|
})
|
|
3476
4354
|
),
|
|
3477
|
-
count:
|
|
4355
|
+
count: z7.number()
|
|
3478
4356
|
}),
|
|
3479
4357
|
examples: [
|
|
3480
4358
|
{
|
|
@@ -3537,22 +4415,42 @@ ve.command("locks", {
|
|
|
3537
4415
|
votingPower: votingPower.toString()
|
|
3538
4416
|
};
|
|
3539
4417
|
});
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
4418
|
+
const firstLock = locks[0];
|
|
4419
|
+
return c.ok(
|
|
4420
|
+
{
|
|
4421
|
+
address: toChecksum(c.args.address),
|
|
4422
|
+
locks,
|
|
4423
|
+
count: locks.length
|
|
4424
|
+
},
|
|
4425
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4426
|
+
cta: {
|
|
4427
|
+
description: "Explore locks:",
|
|
4428
|
+
commands: firstLock ? [
|
|
4429
|
+
{
|
|
4430
|
+
command: "ve lock",
|
|
4431
|
+
args: { tokenId: Number(firstLock.tokenId) },
|
|
4432
|
+
description: `Inspect veNFT #${firstLock.tokenId}`
|
|
4433
|
+
},
|
|
4434
|
+
{
|
|
4435
|
+
command: "voter rewards",
|
|
4436
|
+
args: { tokenId: Number(firstLock.tokenId) },
|
|
4437
|
+
description: `Check rewards for veNFT #${firstLock.tokenId}`
|
|
4438
|
+
}
|
|
4439
|
+
] : []
|
|
4440
|
+
}
|
|
4441
|
+
}
|
|
4442
|
+
);
|
|
3545
4443
|
}
|
|
3546
4444
|
});
|
|
3547
4445
|
ve.command("voting-power", {
|
|
3548
4446
|
description: "Get current voting power for one veNFT token id.",
|
|
3549
|
-
args:
|
|
3550
|
-
tokenId:
|
|
4447
|
+
args: z7.object({
|
|
4448
|
+
tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3551
4449
|
}),
|
|
3552
4450
|
env: env6,
|
|
3553
|
-
output:
|
|
3554
|
-
tokenId:
|
|
3555
|
-
votingPower:
|
|
4451
|
+
output: z7.object({
|
|
4452
|
+
tokenId: z7.number(),
|
|
4453
|
+
votingPower: z7.string()
|
|
3556
4454
|
}),
|
|
3557
4455
|
examples: [{ args: { tokenId: 1 }, description: "Get current voting power for veNFT #1" }],
|
|
3558
4456
|
async run(c) {
|
|
@@ -3563,17 +4461,36 @@ ve.command("voting-power", {
|
|
|
3563
4461
|
functionName: "balanceOfNFT",
|
|
3564
4462
|
args: [BigInt(c.args.tokenId)]
|
|
3565
4463
|
});
|
|
3566
|
-
return c.ok(
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
4464
|
+
return c.ok(
|
|
4465
|
+
{
|
|
4466
|
+
tokenId: c.args.tokenId,
|
|
4467
|
+
votingPower: votingPower.toString()
|
|
4468
|
+
},
|
|
4469
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4470
|
+
cta: {
|
|
4471
|
+
description: "Related commands:",
|
|
4472
|
+
commands: [
|
|
4473
|
+
{
|
|
4474
|
+
command: "ve lock",
|
|
4475
|
+
args: { tokenId: c.args.tokenId },
|
|
4476
|
+
description: "View full lock details"
|
|
4477
|
+
},
|
|
4478
|
+
{
|
|
4479
|
+
command: "voter rewards",
|
|
4480
|
+
args: { tokenId: c.args.tokenId },
|
|
4481
|
+
description: "Check claimable rewards"
|
|
4482
|
+
}
|
|
4483
|
+
]
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
);
|
|
3570
4487
|
}
|
|
3571
4488
|
});
|
|
3572
4489
|
|
|
3573
4490
|
// src/commands/voter.ts
|
|
3574
|
-
import { Cli as Cli7, z as
|
|
3575
|
-
var env7 =
|
|
3576
|
-
ABSTRACT_RPC_URL:
|
|
4491
|
+
import { Cli as Cli7, z as z8 } from "incur";
|
|
4492
|
+
var env7 = z8.object({
|
|
4493
|
+
ABSTRACT_RPC_URL: z8.string().optional().describe("Abstract RPC URL override")
|
|
3577
4494
|
});
|
|
3578
4495
|
async function discoverPools(client) {
|
|
3579
4496
|
const [v2PoolCount, clPoolCount] = await Promise.all([
|
|
@@ -3618,14 +4535,14 @@ var voter = Cli7.create("voter", {
|
|
|
3618
4535
|
voter.command("epoch", {
|
|
3619
4536
|
description: "Show current emissions epoch timing from Minter.",
|
|
3620
4537
|
env: env7,
|
|
3621
|
-
output:
|
|
3622
|
-
activePeriod:
|
|
3623
|
-
epochEnd:
|
|
3624
|
-
secondsRemaining:
|
|
3625
|
-
timeRemaining:
|
|
3626
|
-
weekSeconds:
|
|
3627
|
-
epochCount:
|
|
3628
|
-
weeklyEmission:
|
|
4538
|
+
output: z8.object({
|
|
4539
|
+
activePeriod: z8.number(),
|
|
4540
|
+
epochEnd: z8.number(),
|
|
4541
|
+
secondsRemaining: z8.number(),
|
|
4542
|
+
timeRemaining: z8.string(),
|
|
4543
|
+
weekSeconds: z8.number(),
|
|
4544
|
+
epochCount: z8.number(),
|
|
4545
|
+
weeklyEmission: z8.string()
|
|
3629
4546
|
}),
|
|
3630
4547
|
examples: [{ description: "Inspect current voter epoch boundaries" }],
|
|
3631
4548
|
async run(c) {
|
|
@@ -3654,30 +4571,47 @@ voter.command("epoch", {
|
|
|
3654
4571
|
]);
|
|
3655
4572
|
const now = Math.floor(Date.now() / 1e3);
|
|
3656
4573
|
const epochEnd = asNum(activePeriod + weekSeconds);
|
|
3657
|
-
return c.ok(
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4574
|
+
return c.ok(
|
|
4575
|
+
{
|
|
4576
|
+
activePeriod: asNum(activePeriod),
|
|
4577
|
+
epochEnd,
|
|
4578
|
+
secondsRemaining: clampPositive(epochEnd - now),
|
|
4579
|
+
timeRemaining: relTime(activePeriod + weekSeconds),
|
|
4580
|
+
weekSeconds: asNum(weekSeconds),
|
|
4581
|
+
epochCount: asNum(epochCount),
|
|
4582
|
+
weeklyEmission: weeklyEmission.toString()
|
|
4583
|
+
},
|
|
4584
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4585
|
+
cta: {
|
|
4586
|
+
description: "Related commands:",
|
|
4587
|
+
commands: [
|
|
4588
|
+
{
|
|
4589
|
+
command: "voter weights",
|
|
4590
|
+
description: "View pool voting weight distribution"
|
|
4591
|
+
},
|
|
4592
|
+
{
|
|
4593
|
+
command: "gauges list",
|
|
4594
|
+
description: "List active gauges"
|
|
4595
|
+
}
|
|
4596
|
+
]
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
);
|
|
3666
4600
|
}
|
|
3667
4601
|
});
|
|
3668
4602
|
voter.command("weights", {
|
|
3669
4603
|
description: "Show current pool voting weight distribution.",
|
|
3670
4604
|
env: env7,
|
|
3671
|
-
output:
|
|
3672
|
-
totalWeight:
|
|
3673
|
-
pools:
|
|
3674
|
-
|
|
3675
|
-
pool:
|
|
3676
|
-
gauge:
|
|
3677
|
-
weight:
|
|
4605
|
+
output: z8.object({
|
|
4606
|
+
totalWeight: z8.string(),
|
|
4607
|
+
pools: z8.array(
|
|
4608
|
+
z8.object({
|
|
4609
|
+
pool: z8.string(),
|
|
4610
|
+
gauge: z8.string(),
|
|
4611
|
+
weight: z8.string()
|
|
3678
4612
|
})
|
|
3679
4613
|
),
|
|
3680
|
-
count:
|
|
4614
|
+
count: z8.number()
|
|
3681
4615
|
}),
|
|
3682
4616
|
examples: [{ description: "List all pools with non-zero voting weight" }],
|
|
3683
4617
|
async run(c) {
|
|
@@ -3726,28 +4660,49 @@ voter.command("weights", {
|
|
|
3726
4660
|
gauge: toChecksum(entry.gauge),
|
|
3727
4661
|
weight: entry.weight.toString()
|
|
3728
4662
|
}));
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
4663
|
+
const firstEntry = entries[0];
|
|
4664
|
+
return c.ok(
|
|
4665
|
+
{
|
|
4666
|
+
totalWeight: totalWeight.toString(),
|
|
4667
|
+
pools: entries,
|
|
4668
|
+
count: entries.length
|
|
4669
|
+
},
|
|
4670
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4671
|
+
cta: {
|
|
4672
|
+
description: "Related commands:",
|
|
4673
|
+
commands: [
|
|
4674
|
+
{
|
|
4675
|
+
command: "voter epoch",
|
|
4676
|
+
description: "View current epoch timing"
|
|
4677
|
+
},
|
|
4678
|
+
...firstEntry ? [
|
|
4679
|
+
{
|
|
4680
|
+
command: "voter bribes",
|
|
4681
|
+
args: { pool: firstEntry.pool },
|
|
4682
|
+
description: "View bribe rewards for top-weighted pool"
|
|
4683
|
+
}
|
|
4684
|
+
] : []
|
|
4685
|
+
]
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
);
|
|
3734
4689
|
}
|
|
3735
4690
|
});
|
|
3736
4691
|
voter.command("rewards", {
|
|
3737
4692
|
description: "Show claimable rebase rewards and voting context for a veNFT.",
|
|
3738
|
-
args:
|
|
3739
|
-
tokenId:
|
|
4693
|
+
args: z8.object({
|
|
4694
|
+
tokenId: z8.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3740
4695
|
}),
|
|
3741
4696
|
env: env7,
|
|
3742
|
-
output:
|
|
3743
|
-
tokenId:
|
|
3744
|
-
rewardToken:
|
|
3745
|
-
claimableRebase:
|
|
3746
|
-
timeCursor:
|
|
3747
|
-
lastTokenTime:
|
|
3748
|
-
distributorStartTime:
|
|
3749
|
-
usedWeight:
|
|
3750
|
-
lastVoted:
|
|
4697
|
+
output: z8.object({
|
|
4698
|
+
tokenId: z8.number(),
|
|
4699
|
+
rewardToken: z8.string(),
|
|
4700
|
+
claimableRebase: z8.string(),
|
|
4701
|
+
timeCursor: z8.number(),
|
|
4702
|
+
lastTokenTime: z8.number(),
|
|
4703
|
+
distributorStartTime: z8.number(),
|
|
4704
|
+
usedWeight: z8.string(),
|
|
4705
|
+
lastVoted: z8.number()
|
|
3751
4706
|
}),
|
|
3752
4707
|
examples: [{ args: { tokenId: 1 }, description: "Check claimable voter/distributor rewards" }],
|
|
3753
4708
|
async run(c) {
|
|
@@ -3802,36 +4757,54 @@ voter.command("rewards", {
|
|
|
3802
4757
|
args: [tokenId]
|
|
3803
4758
|
})
|
|
3804
4759
|
]);
|
|
3805
|
-
return c.ok(
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
4760
|
+
return c.ok(
|
|
4761
|
+
{
|
|
4762
|
+
tokenId: c.args.tokenId,
|
|
4763
|
+
rewardToken: toChecksum(rewardToken),
|
|
4764
|
+
claimableRebase: claimableRebase.toString(),
|
|
4765
|
+
timeCursor: asNum(timeCursor),
|
|
4766
|
+
lastTokenTime: asNum(lastTokenTime),
|
|
4767
|
+
distributorStartTime: asNum(distributorStartTime),
|
|
4768
|
+
usedWeight: usedWeight.toString(),
|
|
4769
|
+
lastVoted: asNum(lastVoted)
|
|
4770
|
+
},
|
|
4771
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4772
|
+
cta: {
|
|
4773
|
+
description: "Related commands:",
|
|
4774
|
+
commands: [
|
|
4775
|
+
{
|
|
4776
|
+
command: "ve lock",
|
|
4777
|
+
args: { tokenId: c.args.tokenId },
|
|
4778
|
+
description: "View lock details for this veNFT"
|
|
4779
|
+
},
|
|
4780
|
+
{
|
|
4781
|
+
command: "voter weights",
|
|
4782
|
+
description: "Check pool voting weight distribution"
|
|
4783
|
+
}
|
|
4784
|
+
]
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
);
|
|
3815
4788
|
}
|
|
3816
4789
|
});
|
|
3817
4790
|
voter.command("bribes", {
|
|
3818
4791
|
description: "Show active bribe reward tokens and current-epoch amounts for a pool.",
|
|
3819
|
-
args:
|
|
3820
|
-
pool:
|
|
4792
|
+
args: z8.object({
|
|
4793
|
+
pool: z8.string().describe("Pool address")
|
|
3821
4794
|
}),
|
|
3822
4795
|
env: env7,
|
|
3823
|
-
output:
|
|
3824
|
-
pool:
|
|
3825
|
-
gauge:
|
|
3826
|
-
bribeContract:
|
|
3827
|
-
epochStart:
|
|
3828
|
-
rewardTokens:
|
|
3829
|
-
|
|
3830
|
-
token:
|
|
3831
|
-
epochAmount:
|
|
4796
|
+
output: z8.object({
|
|
4797
|
+
pool: z8.string(),
|
|
4798
|
+
gauge: z8.string(),
|
|
4799
|
+
bribeContract: z8.string(),
|
|
4800
|
+
epochStart: z8.number(),
|
|
4801
|
+
rewardTokens: z8.array(
|
|
4802
|
+
z8.object({
|
|
4803
|
+
token: z8.string(),
|
|
4804
|
+
epochAmount: z8.string()
|
|
3832
4805
|
})
|
|
3833
4806
|
),
|
|
3834
|
-
count:
|
|
4807
|
+
count: z8.number()
|
|
3835
4808
|
}),
|
|
3836
4809
|
examples: [
|
|
3837
4810
|
{
|
|
@@ -3916,14 +4889,32 @@ voter.command("bribes", {
|
|
|
3916
4889
|
token: toChecksum(token),
|
|
3917
4890
|
epochAmount: epochAmounts[index].toString()
|
|
3918
4891
|
}));
|
|
3919
|
-
return c.ok(
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
4892
|
+
return c.ok(
|
|
4893
|
+
{
|
|
4894
|
+
pool: toChecksum(c.args.pool),
|
|
4895
|
+
gauge: toChecksum(gauge),
|
|
4896
|
+
bribeContract: toChecksum(bribeContract),
|
|
4897
|
+
epochStart: asNum(epochStart),
|
|
4898
|
+
rewardTokens: items,
|
|
4899
|
+
count: items.length
|
|
4900
|
+
},
|
|
4901
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
4902
|
+
cta: {
|
|
4903
|
+
description: "Related commands:",
|
|
4904
|
+
commands: [
|
|
4905
|
+
{
|
|
4906
|
+
command: "gauges info",
|
|
4907
|
+
args: { gauge: toChecksum(gauge) },
|
|
4908
|
+
description: "Inspect gauge details"
|
|
4909
|
+
},
|
|
4910
|
+
{
|
|
4911
|
+
command: "voter epoch",
|
|
4912
|
+
description: "View current epoch timing"
|
|
4913
|
+
}
|
|
4914
|
+
]
|
|
4915
|
+
}
|
|
4916
|
+
}
|
|
4917
|
+
);
|
|
3927
4918
|
}
|
|
3928
4919
|
});
|
|
3929
4920
|
|
|
@@ -4068,8 +5059,8 @@ cli.command(voter);
|
|
|
4068
5059
|
cli.command(cl);
|
|
4069
5060
|
cli.command(vaults);
|
|
4070
5061
|
cli.command(lending);
|
|
4071
|
-
var rootEnv =
|
|
4072
|
-
ABSTRACT_RPC_URL:
|
|
5062
|
+
var rootEnv = z9.object({
|
|
5063
|
+
ABSTRACT_RPC_URL: z9.string().optional().describe("Abstract RPC URL override")
|
|
4073
5064
|
});
|
|
4074
5065
|
var erc20MetadataAbi4 = [
|
|
4075
5066
|
{
|
|
@@ -4274,65 +5265,65 @@ async function readTopV2PoolsSnapshot(client, limit) {
|
|
|
4274
5265
|
cli.command("status", {
|
|
4275
5266
|
description: "Cross-protocol Aborean snapshot (TVL estimates, epoch, top pools, ve lock, vaults, Morpho lending).",
|
|
4276
5267
|
env: rootEnv,
|
|
4277
|
-
output:
|
|
4278
|
-
v2PoolCount:
|
|
4279
|
-
clPoolCount:
|
|
4280
|
-
gaugeCount:
|
|
4281
|
-
totalVotingWeight:
|
|
4282
|
-
veABXTotalSupply:
|
|
4283
|
-
veABXLockedSupply:
|
|
4284
|
-
epoch:
|
|
4285
|
-
activePeriod:
|
|
4286
|
-
epochEnd:
|
|
4287
|
-
secondsRemaining:
|
|
4288
|
-
epochCount:
|
|
4289
|
-
weeklyEmission:
|
|
5268
|
+
output: z9.object({
|
|
5269
|
+
v2PoolCount: z9.number().describe("Number of V2 AMM pools"),
|
|
5270
|
+
clPoolCount: z9.number().describe("Number of Slipstream (CL) pools"),
|
|
5271
|
+
gaugeCount: z9.number().describe("Number of pools with gauges"),
|
|
5272
|
+
totalVotingWeight: z9.string().describe("Total voting weight (wei)"),
|
|
5273
|
+
veABXTotalSupply: z9.string().describe("Total veABX supply (wei)"),
|
|
5274
|
+
veABXLockedSupply: z9.string().describe("Total ABX locked in VotingEscrow (wei)"),
|
|
5275
|
+
epoch: z9.object({
|
|
5276
|
+
activePeriod: z9.number(),
|
|
5277
|
+
epochEnd: z9.number(),
|
|
5278
|
+
secondsRemaining: z9.number(),
|
|
5279
|
+
epochCount: z9.number(),
|
|
5280
|
+
weeklyEmission: z9.string()
|
|
4290
5281
|
}),
|
|
4291
|
-
topPools:
|
|
4292
|
-
|
|
4293
|
-
pool:
|
|
4294
|
-
pair:
|
|
4295
|
-
poolType:
|
|
4296
|
-
token0:
|
|
4297
|
-
address:
|
|
4298
|
-
symbol:
|
|
4299
|
-
decimals:
|
|
5282
|
+
topPools: z9.array(
|
|
5283
|
+
z9.object({
|
|
5284
|
+
pool: z9.string(),
|
|
5285
|
+
pair: z9.string(),
|
|
5286
|
+
poolType: z9.enum(["stable", "volatile"]),
|
|
5287
|
+
token0: z9.object({
|
|
5288
|
+
address: z9.string(),
|
|
5289
|
+
symbol: z9.string(),
|
|
5290
|
+
decimals: z9.number()
|
|
4300
5291
|
}),
|
|
4301
|
-
token1:
|
|
4302
|
-
address:
|
|
4303
|
-
symbol:
|
|
4304
|
-
decimals:
|
|
5292
|
+
token1: z9.object({
|
|
5293
|
+
address: z9.string(),
|
|
5294
|
+
symbol: z9.string(),
|
|
5295
|
+
decimals: z9.number()
|
|
4305
5296
|
}),
|
|
4306
|
-
reserves:
|
|
4307
|
-
token0:
|
|
4308
|
-
token1:
|
|
5297
|
+
reserves: z9.object({
|
|
5298
|
+
token0: z9.string(),
|
|
5299
|
+
token1: z9.string()
|
|
4309
5300
|
}),
|
|
4310
|
-
tvlEstimateUnits:
|
|
5301
|
+
tvlEstimateUnits: z9.number()
|
|
4311
5302
|
})
|
|
4312
5303
|
),
|
|
4313
|
-
tvl:
|
|
4314
|
-
v2ReserveUnitEstimate:
|
|
4315
|
-
vaultManagedVotingPower:
|
|
5304
|
+
tvl: z9.object({
|
|
5305
|
+
v2ReserveUnitEstimate: z9.number(),
|
|
5306
|
+
vaultManagedVotingPower: z9.string()
|
|
4316
5307
|
}),
|
|
4317
|
-
vaults:
|
|
4318
|
-
relayCount:
|
|
4319
|
-
managedVotingPower:
|
|
4320
|
-
note:
|
|
5308
|
+
vaults: z9.object({
|
|
5309
|
+
relayCount: z9.number(),
|
|
5310
|
+
managedVotingPower: z9.string(),
|
|
5311
|
+
note: z9.string().nullable()
|
|
4321
5312
|
}),
|
|
4322
|
-
lending:
|
|
4323
|
-
available:
|
|
4324
|
-
morpho:
|
|
4325
|
-
marketCount:
|
|
4326
|
-
supplyByLoanToken:
|
|
4327
|
-
|
|
4328
|
-
token:
|
|
4329
|
-
symbol:
|
|
4330
|
-
decimals:
|
|
4331
|
-
totalSupplyAssets:
|
|
4332
|
-
totalBorrowAssets:
|
|
5313
|
+
lending: z9.object({
|
|
5314
|
+
available: z9.boolean(),
|
|
5315
|
+
morpho: z9.string(),
|
|
5316
|
+
marketCount: z9.number(),
|
|
5317
|
+
supplyByLoanToken: z9.array(
|
|
5318
|
+
z9.object({
|
|
5319
|
+
token: z9.string(),
|
|
5320
|
+
symbol: z9.string(),
|
|
5321
|
+
decimals: z9.number(),
|
|
5322
|
+
totalSupplyAssets: z9.string(),
|
|
5323
|
+
totalBorrowAssets: z9.string()
|
|
4333
5324
|
})
|
|
4334
5325
|
),
|
|
4335
|
-
note:
|
|
5326
|
+
note: z9.string().nullable()
|
|
4336
5327
|
})
|
|
4337
5328
|
}),
|
|
4338
5329
|
examples: [{ description: "Fetch the current Aborean protocol status" }],
|
|
@@ -4430,38 +5421,63 @@ cli.command("status", {
|
|
|
4430
5421
|
}
|
|
4431
5422
|
const now = Math.floor(Date.now() / 1e3);
|
|
4432
5423
|
const epochEnd = Number(activePeriod) + Number(weekSeconds);
|
|
4433
|
-
return c.ok(
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
5424
|
+
return c.ok(
|
|
5425
|
+
{
|
|
5426
|
+
v2PoolCount: Number(v2PoolCount),
|
|
5427
|
+
clPoolCount: Number(clPoolCount),
|
|
5428
|
+
gaugeCount: Number(gaugeCount),
|
|
5429
|
+
totalVotingWeight: String(totalVotingWeight),
|
|
5430
|
+
veABXTotalSupply: String(veABXTotalSupply),
|
|
5431
|
+
veABXLockedSupply: String(veABXLockedSupply),
|
|
5432
|
+
epoch: {
|
|
5433
|
+
activePeriod: Number(activePeriod),
|
|
5434
|
+
epochEnd,
|
|
5435
|
+
secondsRemaining: Math.max(0, epochEnd - now),
|
|
5436
|
+
epochCount: Number(epochCount),
|
|
5437
|
+
weeklyEmission: String(weeklyEmission)
|
|
5438
|
+
},
|
|
5439
|
+
topPools: v2PoolSnapshot.topPools,
|
|
5440
|
+
tvl: {
|
|
5441
|
+
v2ReserveUnitEstimate: v2PoolSnapshot.reserveUnitTvl,
|
|
5442
|
+
vaultManagedVotingPower
|
|
5443
|
+
},
|
|
5444
|
+
vaults: {
|
|
5445
|
+
relayCount: vaultRelayCount,
|
|
5446
|
+
managedVotingPower: vaultManagedVotingPower,
|
|
5447
|
+
note: vaultNote
|
|
5448
|
+
},
|
|
5449
|
+
lending: {
|
|
5450
|
+
available: lendingAvailable,
|
|
5451
|
+
morpho: lendingMorpho,
|
|
5452
|
+
marketCount: lendingMarketCount,
|
|
5453
|
+
supplyByLoanToken: lendingSupplyByLoanToken,
|
|
5454
|
+
note: lendingNote
|
|
5455
|
+
}
|
|
4456
5456
|
},
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
5457
|
+
c.format === "json" || c.format === "jsonl" ? void 0 : {
|
|
5458
|
+
cta: {
|
|
5459
|
+
description: "Drill down:",
|
|
5460
|
+
commands: [
|
|
5461
|
+
{
|
|
5462
|
+
command: "pools list",
|
|
5463
|
+
description: "List V2 AMM pools"
|
|
5464
|
+
},
|
|
5465
|
+
{
|
|
5466
|
+
command: "cl pools",
|
|
5467
|
+
description: "List Slipstream CL pools"
|
|
5468
|
+
},
|
|
5469
|
+
{
|
|
5470
|
+
command: "gauges list",
|
|
5471
|
+
description: "List active gauges"
|
|
5472
|
+
},
|
|
5473
|
+
{
|
|
5474
|
+
command: "ve stats",
|
|
5475
|
+
description: "View veABX global stats"
|
|
5476
|
+
}
|
|
5477
|
+
]
|
|
5478
|
+
}
|
|
4463
5479
|
}
|
|
4464
|
-
|
|
5480
|
+
);
|
|
4465
5481
|
}
|
|
4466
5482
|
});
|
|
4467
5483
|
applyFriendlyErrorHandling(cli);
|