@spectratools/aborean-cli 0.7.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 +913 -422
- 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);
|
|
@@ -1382,11 +1540,11 @@ cl.command("pools", {
|
|
|
1382
1540
|
});
|
|
1383
1541
|
cl.command("pool", {
|
|
1384
1542
|
description: "Get detailed state for a Slipstream pool address.",
|
|
1385
|
-
args:
|
|
1386
|
-
pool:
|
|
1543
|
+
args: z2.object({
|
|
1544
|
+
pool: z2.string().describe("Pool address")
|
|
1387
1545
|
}),
|
|
1388
1546
|
env,
|
|
1389
|
-
output:
|
|
1547
|
+
output: z2.object({
|
|
1390
1548
|
pool: poolRowSchema
|
|
1391
1549
|
}),
|
|
1392
1550
|
async run(c) {
|
|
@@ -1397,7 +1555,7 @@ cl.command("pool", {
|
|
|
1397
1555
|
});
|
|
1398
1556
|
}
|
|
1399
1557
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1400
|
-
const checksummedPool =
|
|
1558
|
+
const checksummedPool = checksumAddress2(c.args.pool);
|
|
1401
1559
|
const [poolState] = await readPoolStates(client, [checksummedPool]);
|
|
1402
1560
|
const tokenMeta = await readTokenMetadata(client, [poolState.token0, poolState.token1]);
|
|
1403
1561
|
const row = toPoolRow(poolState, tokenMeta);
|
|
@@ -1431,25 +1589,25 @@ cl.command("pool", {
|
|
|
1431
1589
|
});
|
|
1432
1590
|
cl.command("positions", {
|
|
1433
1591
|
description: "List concentrated liquidity NFT positions for an owner.",
|
|
1434
|
-
args:
|
|
1435
|
-
owner:
|
|
1592
|
+
args: z2.object({
|
|
1593
|
+
owner: z2.string().describe("Owner wallet address")
|
|
1436
1594
|
}),
|
|
1437
1595
|
env,
|
|
1438
|
-
output:
|
|
1439
|
-
owner:
|
|
1440
|
-
count:
|
|
1441
|
-
positions:
|
|
1442
|
-
|
|
1443
|
-
tokenId:
|
|
1444
|
-
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(),
|
|
1445
1603
|
token0: tokenSchema,
|
|
1446
1604
|
token1: tokenSchema,
|
|
1447
|
-
tickSpacing:
|
|
1448
|
-
tickLower:
|
|
1449
|
-
tickUpper:
|
|
1450
|
-
liquidity:
|
|
1451
|
-
tokensOwed0:
|
|
1452
|
-
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() })
|
|
1453
1611
|
})
|
|
1454
1612
|
)
|
|
1455
1613
|
}),
|
|
@@ -1461,7 +1619,7 @@ cl.command("positions", {
|
|
|
1461
1619
|
});
|
|
1462
1620
|
}
|
|
1463
1621
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1464
|
-
const owner =
|
|
1622
|
+
const owner = checksumAddress2(c.args.owner);
|
|
1465
1623
|
const balance = await client.readContract({
|
|
1466
1624
|
abi: nonfungiblePositionManagerAbi,
|
|
1467
1625
|
address: ABOREAN_CL_ADDRESSES.nonfungiblePositionManager,
|
|
@@ -1545,13 +1703,13 @@ cl.command("positions", {
|
|
|
1545
1703
|
});
|
|
1546
1704
|
cl.command("quote", {
|
|
1547
1705
|
description: "Quote a single-hop Slipstream swap via QuoterV2.",
|
|
1548
|
-
args:
|
|
1549
|
-
tokenIn:
|
|
1550
|
-
tokenOut:
|
|
1551
|
-
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")
|
|
1552
1710
|
}),
|
|
1553
|
-
options:
|
|
1554
|
-
fee:
|
|
1711
|
+
options: z2.object({
|
|
1712
|
+
fee: z2.coerce.number().int().positive().optional().describe("Optional fee tier filter")
|
|
1555
1713
|
}),
|
|
1556
1714
|
env,
|
|
1557
1715
|
output: quoteOutputSchema,
|
|
@@ -1564,8 +1722,8 @@ cl.command("quote", {
|
|
|
1564
1722
|
});
|
|
1565
1723
|
}
|
|
1566
1724
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
1567
|
-
const inAddress =
|
|
1568
|
-
const outAddress =
|
|
1725
|
+
const inAddress = checksumAddress2(tokenIn);
|
|
1726
|
+
const outAddress = checksumAddress2(tokenOut);
|
|
1569
1727
|
const allPools = await listPoolAddresses(client);
|
|
1570
1728
|
const poolStates = await readPoolStates(client, allPools);
|
|
1571
1729
|
const pairPools = poolStates.filter((pool) => {
|
|
@@ -1632,7 +1790,7 @@ cl.command("quote", {
|
|
|
1632
1790
|
const priceImpactPct = quotePriceOutPerIn === null || poolMidPriceOutPerIn === null || poolMidPriceOutPerIn === 0 ? null : finiteOrNull((poolMidPriceOutPerIn - quotePriceOutPerIn) / poolMidPriceOutPerIn * 100);
|
|
1633
1791
|
return c.ok(
|
|
1634
1792
|
{
|
|
1635
|
-
pool:
|
|
1793
|
+
pool: checksumAddress2(selectedPool.pool),
|
|
1636
1794
|
selectedFee: selectedPool.fee,
|
|
1637
1795
|
selectedTickSpacing: selectedPool.tickSpacing,
|
|
1638
1796
|
tokenIn: inMeta,
|
|
@@ -1662,7 +1820,7 @@ cl.command("quote", {
|
|
|
1662
1820
|
commands: [
|
|
1663
1821
|
{
|
|
1664
1822
|
command: "cl pool",
|
|
1665
|
-
args: { pool:
|
|
1823
|
+
args: { pool: checksumAddress2(selectedPool.pool) },
|
|
1666
1824
|
description: "Inspect the pool used for this quote"
|
|
1667
1825
|
},
|
|
1668
1826
|
{
|
|
@@ -1680,40 +1838,164 @@ cl.command("quote", {
|
|
|
1680
1838
|
);
|
|
1681
1839
|
}
|
|
1682
1840
|
});
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
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);
|
|
1981
|
+
return c.ok({
|
|
1982
|
+
pool: checksumAddress2(selectedPool.pool),
|
|
1983
|
+
tokenIn: inMeta,
|
|
1984
|
+
tokenOut: outMeta,
|
|
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
|
|
1991
|
+
});
|
|
1695
1992
|
}
|
|
1696
|
-
}
|
|
1697
|
-
function asNum(value) {
|
|
1698
|
-
return Number(value);
|
|
1699
|
-
}
|
|
1700
|
-
function relTime(unixSeconds) {
|
|
1701
|
-
const ts = typeof unixSeconds === "bigint" ? Number(unixSeconds) : unixSeconds;
|
|
1702
|
-
if (!Number.isFinite(ts) || ts <= 0) return "n/a";
|
|
1703
|
-
const delta = ts - Math.floor(Date.now() / 1e3);
|
|
1704
|
-
const abs = Math.abs(delta);
|
|
1705
|
-
const hours = Math.floor(abs / 3600);
|
|
1706
|
-
const minutes = Math.floor(abs % 3600 / 60);
|
|
1707
|
-
const label = hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
|
1708
|
-
return delta >= 0 ? `in ${label}` : `${label} ago`;
|
|
1709
|
-
}
|
|
1710
|
-
function clampPositive(seconds) {
|
|
1711
|
-
return seconds > 0 ? seconds : 0;
|
|
1712
|
-
}
|
|
1993
|
+
});
|
|
1713
1994
|
|
|
1714
1995
|
// src/commands/gauges.ts
|
|
1715
|
-
|
|
1716
|
-
|
|
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")
|
|
1717
1999
|
});
|
|
1718
2000
|
async function discoverGaugePools(client) {
|
|
1719
2001
|
const [v2PoolCount, clPoolCount] = await Promise.all([
|
|
@@ -1769,20 +2051,20 @@ var gauges = Cli2.create("gauges", {
|
|
|
1769
2051
|
gauges.command("list", {
|
|
1770
2052
|
description: "List active gauges with pool, emissions, and staking stats.",
|
|
1771
2053
|
env: env2,
|
|
1772
|
-
output:
|
|
1773
|
-
gauges:
|
|
1774
|
-
|
|
1775
|
-
pool:
|
|
1776
|
-
gauge:
|
|
1777
|
-
rewardToken:
|
|
1778
|
-
rewardRate:
|
|
1779
|
-
totalStaked:
|
|
1780
|
-
claimableEmissions:
|
|
1781
|
-
periodFinish:
|
|
1782
|
-
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()
|
|
1783
2065
|
})
|
|
1784
2066
|
),
|
|
1785
|
-
count:
|
|
2067
|
+
count: z3.number()
|
|
1786
2068
|
}),
|
|
1787
2069
|
examples: [{ description: "List all active gauges and current emissions state" }],
|
|
1788
2070
|
async run(c) {
|
|
@@ -1863,27 +2145,27 @@ gauges.command("list", {
|
|
|
1863
2145
|
});
|
|
1864
2146
|
gauges.command("info", {
|
|
1865
2147
|
description: "Get detailed state for one gauge address.",
|
|
1866
|
-
args:
|
|
1867
|
-
gauge:
|
|
2148
|
+
args: z3.object({
|
|
2149
|
+
gauge: z3.string().describe("Gauge contract address")
|
|
1868
2150
|
}),
|
|
1869
2151
|
env: env2,
|
|
1870
|
-
output:
|
|
1871
|
-
gauge:
|
|
1872
|
-
pool:
|
|
1873
|
-
isAlive:
|
|
1874
|
-
stakingToken:
|
|
1875
|
-
rewardToken:
|
|
1876
|
-
totalStaked:
|
|
1877
|
-
rewardRate:
|
|
1878
|
-
rewardPerTokenStored:
|
|
1879
|
-
fees0:
|
|
1880
|
-
fees1:
|
|
1881
|
-
left:
|
|
1882
|
-
periodFinish:
|
|
1883
|
-
periodFinishRelative:
|
|
1884
|
-
lastUpdateTime:
|
|
1885
|
-
bribeContract:
|
|
1886
|
-
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()
|
|
1887
2169
|
}),
|
|
1888
2170
|
examples: [
|
|
1889
2171
|
{
|
|
@@ -2029,22 +2311,22 @@ gauges.command("info", {
|
|
|
2029
2311
|
});
|
|
2030
2312
|
gauges.command("staked", {
|
|
2031
2313
|
description: "Show one address staking positions across all gauges.",
|
|
2032
|
-
args:
|
|
2033
|
-
address:
|
|
2314
|
+
args: z3.object({
|
|
2315
|
+
address: z3.string().describe("Wallet address to inspect")
|
|
2034
2316
|
}),
|
|
2035
2317
|
env: env2,
|
|
2036
|
-
output:
|
|
2037
|
-
address:
|
|
2038
|
-
positions:
|
|
2039
|
-
|
|
2040
|
-
pool:
|
|
2041
|
-
gauge:
|
|
2042
|
-
rewardToken:
|
|
2043
|
-
staked:
|
|
2044
|
-
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()
|
|
2045
2327
|
})
|
|
2046
2328
|
),
|
|
2047
|
-
count:
|
|
2329
|
+
count: z3.number()
|
|
2048
2330
|
}),
|
|
2049
2331
|
examples: [
|
|
2050
2332
|
{
|
|
@@ -2135,11 +2417,11 @@ gauges.command("staked", {
|
|
|
2135
2417
|
|
|
2136
2418
|
// src/commands/lending.ts
|
|
2137
2419
|
import { checksumAddress as checksumAddress3, isAddress as isAddress2 } from "@spectratools/cli-shared";
|
|
2138
|
-
import { Cli as Cli3, z as
|
|
2420
|
+
import { Cli as Cli3, z as z4 } from "incur";
|
|
2139
2421
|
import { formatUnits as formatUnits2 } from "viem";
|
|
2140
2422
|
var MORPHO_DEPLOY_BLOCK = 13947713n;
|
|
2141
|
-
var env3 =
|
|
2142
|
-
ABSTRACT_RPC_URL:
|
|
2423
|
+
var env3 = z4.object({
|
|
2424
|
+
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
|
|
2143
2425
|
});
|
|
2144
2426
|
var morphoAbi = [
|
|
2145
2427
|
{
|
|
@@ -2220,27 +2502,27 @@ var erc20MetadataAbi2 = [
|
|
|
2220
2502
|
outputs: [{ type: "uint8" }]
|
|
2221
2503
|
}
|
|
2222
2504
|
];
|
|
2223
|
-
var tokenMetaSchema =
|
|
2224
|
-
address:
|
|
2225
|
-
symbol:
|
|
2226
|
-
decimals:
|
|
2505
|
+
var tokenMetaSchema = z4.object({
|
|
2506
|
+
address: z4.string(),
|
|
2507
|
+
symbol: z4.string(),
|
|
2508
|
+
decimals: z4.number()
|
|
2227
2509
|
});
|
|
2228
|
-
var lendingMarketRowSchema =
|
|
2229
|
-
marketId:
|
|
2510
|
+
var lendingMarketRowSchema = z4.object({
|
|
2511
|
+
marketId: z4.string(),
|
|
2230
2512
|
loanToken: tokenMetaSchema,
|
|
2231
2513
|
collateralToken: tokenMetaSchema,
|
|
2232
|
-
oracle:
|
|
2233
|
-
irm:
|
|
2234
|
-
lltvBps:
|
|
2235
|
-
lltvPercent:
|
|
2236
|
-
totalSupplyAssets:
|
|
2237
|
-
totalBorrowAssets:
|
|
2238
|
-
totalSupplyShares:
|
|
2239
|
-
totalBorrowShares:
|
|
2240
|
-
availableLiquidityAssets:
|
|
2241
|
-
utilization:
|
|
2242
|
-
feeWad:
|
|
2243
|
-
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()
|
|
2244
2526
|
});
|
|
2245
2527
|
function isMarketId(value) {
|
|
2246
2528
|
return /^0x[0-9a-fA-F]{64}$/.test(value);
|
|
@@ -2476,21 +2758,21 @@ var lending = Cli3.create("lending", {
|
|
|
2476
2758
|
});
|
|
2477
2759
|
lending.command("markets", {
|
|
2478
2760
|
description: "List Morpho markets discovered from CreateMarket events.",
|
|
2479
|
-
args:
|
|
2480
|
-
limit:
|
|
2761
|
+
args: z4.object({
|
|
2762
|
+
limit: z4.coerce.number().int().positive().max(200).default(25).describe("Max markets to return")
|
|
2481
2763
|
}),
|
|
2482
2764
|
env: env3,
|
|
2483
|
-
output:
|
|
2484
|
-
morpho:
|
|
2485
|
-
marketCount:
|
|
2486
|
-
markets:
|
|
2487
|
-
totalsByLoanToken:
|
|
2488
|
-
|
|
2489
|
-
token:
|
|
2490
|
-
symbol:
|
|
2491
|
-
decimals:
|
|
2492
|
-
totalSupplyAssets:
|
|
2493
|
-
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()
|
|
2494
2776
|
})
|
|
2495
2777
|
)
|
|
2496
2778
|
}),
|
|
@@ -2537,8 +2819,8 @@ lending.command("markets", {
|
|
|
2537
2819
|
});
|
|
2538
2820
|
lending.command("market", {
|
|
2539
2821
|
description: "Get details for one Morpho market id (bytes32).",
|
|
2540
|
-
args:
|
|
2541
|
-
marketId:
|
|
2822
|
+
args: z4.object({
|
|
2823
|
+
marketId: z4.string().describe("Morpho market id (bytes32 hex)")
|
|
2542
2824
|
}),
|
|
2543
2825
|
env: env3,
|
|
2544
2826
|
output: lendingMarketRowSchema,
|
|
@@ -2598,29 +2880,29 @@ lending.command("market", {
|
|
|
2598
2880
|
});
|
|
2599
2881
|
lending.command("position", {
|
|
2600
2882
|
description: "Inspect one user position in a Morpho market.",
|
|
2601
|
-
args:
|
|
2602
|
-
marketId:
|
|
2603
|
-
user:
|
|
2883
|
+
args: z4.object({
|
|
2884
|
+
marketId: z4.string().describe("Morpho market id (bytes32 hex)"),
|
|
2885
|
+
user: z4.string().describe("Position owner address")
|
|
2604
2886
|
}),
|
|
2605
2887
|
env: env3,
|
|
2606
|
-
output:
|
|
2607
|
-
marketId:
|
|
2608
|
-
user:
|
|
2888
|
+
output: z4.object({
|
|
2889
|
+
marketId: z4.string(),
|
|
2890
|
+
user: z4.string(),
|
|
2609
2891
|
loanToken: tokenMetaSchema,
|
|
2610
2892
|
collateralToken: tokenMetaSchema,
|
|
2611
|
-
supplyShares:
|
|
2612
|
-
supplyAssetsEstimate:
|
|
2613
|
-
raw:
|
|
2614
|
-
decimal:
|
|
2893
|
+
supplyShares: z4.string(),
|
|
2894
|
+
supplyAssetsEstimate: z4.object({
|
|
2895
|
+
raw: z4.string(),
|
|
2896
|
+
decimal: z4.string()
|
|
2615
2897
|
}),
|
|
2616
|
-
borrowShares:
|
|
2617
|
-
borrowAssetsEstimate:
|
|
2618
|
-
raw:
|
|
2619
|
-
decimal:
|
|
2898
|
+
borrowShares: z4.string(),
|
|
2899
|
+
borrowAssetsEstimate: z4.object({
|
|
2900
|
+
raw: z4.string(),
|
|
2901
|
+
decimal: z4.string()
|
|
2620
2902
|
}),
|
|
2621
|
-
collateralAssets:
|
|
2622
|
-
raw:
|
|
2623
|
-
decimal:
|
|
2903
|
+
collateralAssets: z4.object({
|
|
2904
|
+
raw: z4.string(),
|
|
2905
|
+
decimal: z4.string()
|
|
2624
2906
|
})
|
|
2625
2907
|
}),
|
|
2626
2908
|
examples: [
|
|
@@ -2751,38 +3033,86 @@ lending.command("position", {
|
|
|
2751
3033
|
|
|
2752
3034
|
// src/commands/pools.ts
|
|
2753
3035
|
import { checksumAddress as checksumAddress4, isAddress as isAddress3 } from "@spectratools/cli-shared";
|
|
2754
|
-
import { Cli as Cli4, z as
|
|
3036
|
+
import { Cli as Cli4, z as z5 } from "incur";
|
|
2755
3037
|
import { formatUnits as formatUnits3, parseUnits as parseUnits2 } from "viem";
|
|
2756
3038
|
var MULTICALL_BATCH_SIZE2 = 100;
|
|
2757
|
-
var
|
|
2758
|
-
|
|
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")
|
|
2759
3089
|
});
|
|
2760
|
-
var tokenSchema2 =
|
|
2761
|
-
address:
|
|
2762
|
-
symbol:
|
|
2763
|
-
decimals:
|
|
3090
|
+
var tokenSchema2 = z5.object({
|
|
3091
|
+
address: z5.string(),
|
|
3092
|
+
symbol: z5.string(),
|
|
3093
|
+
decimals: z5.number()
|
|
2764
3094
|
});
|
|
2765
|
-
var amountSchema =
|
|
2766
|
-
raw:
|
|
2767
|
-
decimal:
|
|
3095
|
+
var amountSchema = z5.object({
|
|
3096
|
+
raw: z5.string(),
|
|
3097
|
+
decimal: z5.string()
|
|
2768
3098
|
});
|
|
2769
|
-
var feeSchema =
|
|
2770
|
-
feeBps:
|
|
2771
|
-
feePercent:
|
|
3099
|
+
var feeSchema = z5.object({
|
|
3100
|
+
feeBps: z5.number(),
|
|
3101
|
+
feePercent: z5.number()
|
|
2772
3102
|
}).nullable();
|
|
2773
|
-
var poolSummarySchema =
|
|
2774
|
-
pool:
|
|
2775
|
-
pair:
|
|
2776
|
-
stable:
|
|
2777
|
-
poolType:
|
|
3103
|
+
var poolSummarySchema = z5.object({
|
|
3104
|
+
pool: z5.string(),
|
|
3105
|
+
pair: z5.string(),
|
|
3106
|
+
stable: z5.boolean(),
|
|
3107
|
+
poolType: z5.enum(["stable", "volatile"]),
|
|
2778
3108
|
token0: tokenSchema2,
|
|
2779
3109
|
token1: tokenSchema2,
|
|
2780
|
-
reserves:
|
|
3110
|
+
reserves: z5.object({
|
|
2781
3111
|
token0: amountSchema,
|
|
2782
3112
|
token1: amountSchema,
|
|
2783
|
-
blockTimestampLast:
|
|
3113
|
+
blockTimestampLast: z5.number()
|
|
2784
3114
|
}),
|
|
2785
|
-
totalSupply:
|
|
3115
|
+
totalSupply: z5.string(),
|
|
2786
3116
|
fee: feeSchema
|
|
2787
3117
|
});
|
|
2788
3118
|
var erc20MetadataAbi3 = [
|
|
@@ -2987,17 +3317,17 @@ var pools = Cli4.create("pools", {
|
|
|
2987
3317
|
});
|
|
2988
3318
|
pools.command("list", {
|
|
2989
3319
|
description: "List V2 pools with token pairs, reserves, and stable/volatile type.",
|
|
2990
|
-
options:
|
|
2991
|
-
offset:
|
|
2992
|
-
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)")
|
|
2993
3323
|
}),
|
|
2994
3324
|
env: env4,
|
|
2995
|
-
output:
|
|
2996
|
-
total:
|
|
2997
|
-
offset:
|
|
2998
|
-
limit:
|
|
2999
|
-
count:
|
|
3000
|
-
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)
|
|
3001
3331
|
}),
|
|
3002
3332
|
async run(c) {
|
|
3003
3333
|
const client = createAboreanPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -3075,14 +3405,14 @@ pools.command("list", {
|
|
|
3075
3405
|
});
|
|
3076
3406
|
pools.command("pool", {
|
|
3077
3407
|
description: "Get detailed state for one V2 pool.",
|
|
3078
|
-
args:
|
|
3079
|
-
address:
|
|
3408
|
+
args: z5.object({
|
|
3409
|
+
address: z5.string().describe("Pool address")
|
|
3080
3410
|
}),
|
|
3081
3411
|
env: env4,
|
|
3082
|
-
output:
|
|
3412
|
+
output: z5.object({
|
|
3083
3413
|
pool: poolSummarySchema.extend({
|
|
3084
|
-
poolFees:
|
|
3085
|
-
factory:
|
|
3414
|
+
poolFees: z5.string(),
|
|
3415
|
+
factory: z5.string()
|
|
3086
3416
|
})
|
|
3087
3417
|
}),
|
|
3088
3418
|
async run(c) {
|
|
@@ -3181,23 +3511,23 @@ pools.command("pool", {
|
|
|
3181
3511
|
});
|
|
3182
3512
|
pools.command("quote", {
|
|
3183
3513
|
description: "Quote a single-hop V2 swap between tokenIn and tokenOut.",
|
|
3184
|
-
args:
|
|
3185
|
-
tokenIn:
|
|
3186
|
-
tokenOut:
|
|
3187
|
-
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")
|
|
3188
3518
|
}),
|
|
3189
|
-
options:
|
|
3190
|
-
stable:
|
|
3519
|
+
options: z5.object({
|
|
3520
|
+
stable: z5.boolean().default(false).describe("Use stable pool route (default: volatile)")
|
|
3191
3521
|
}),
|
|
3192
3522
|
env: env4,
|
|
3193
|
-
output:
|
|
3194
|
-
pool:
|
|
3195
|
-
stable:
|
|
3523
|
+
output: z5.object({
|
|
3524
|
+
pool: z5.string(),
|
|
3525
|
+
stable: z5.boolean(),
|
|
3196
3526
|
tokenIn: tokenSchema2,
|
|
3197
3527
|
tokenOut: tokenSchema2,
|
|
3198
3528
|
amountIn: amountSchema,
|
|
3199
3529
|
amountOut: amountSchema,
|
|
3200
|
-
priceOutPerIn:
|
|
3530
|
+
priceOutPerIn: z5.number().nullable()
|
|
3201
3531
|
}),
|
|
3202
3532
|
async run(c) {
|
|
3203
3533
|
if (!isAddress3(c.args.tokenIn) || !isAddress3(c.args.tokenOut)) {
|
|
@@ -3297,14 +3627,14 @@ pools.command("quote", {
|
|
|
3297
3627
|
});
|
|
3298
3628
|
pools.command("fees", {
|
|
3299
3629
|
description: "Read V2 fee configuration for a pool address.",
|
|
3300
|
-
args:
|
|
3301
|
-
pool:
|
|
3630
|
+
args: z5.object({
|
|
3631
|
+
pool: z5.string().describe("Pool address")
|
|
3302
3632
|
}),
|
|
3303
3633
|
env: env4,
|
|
3304
|
-
output:
|
|
3305
|
-
pool:
|
|
3306
|
-
pair:
|
|
3307
|
-
stable:
|
|
3634
|
+
output: z5.object({
|
|
3635
|
+
pool: z5.string(),
|
|
3636
|
+
pair: z5.string(),
|
|
3637
|
+
stable: z5.boolean(),
|
|
3308
3638
|
activeFee: feeSchema,
|
|
3309
3639
|
stableFee: feeSchema,
|
|
3310
3640
|
volatileFee: feeSchema
|
|
@@ -3377,12 +3707,173 @@ pools.command("fees", {
|
|
|
3377
3707
|
);
|
|
3378
3708
|
}
|
|
3379
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);
|
|
3848
|
+
return c.ok({
|
|
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
|
|
3868
|
+
});
|
|
3869
|
+
}
|
|
3870
|
+
});
|
|
3380
3871
|
|
|
3381
3872
|
// src/commands/vaults.ts
|
|
3382
3873
|
import { checksumAddress as checksumAddress5, isAddress as isAddress4 } from "@spectratools/cli-shared";
|
|
3383
|
-
import { Cli as Cli5, z as
|
|
3384
|
-
var env5 =
|
|
3385
|
-
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")
|
|
3386
3877
|
});
|
|
3387
3878
|
var relayAbi = [
|
|
3388
3879
|
{
|
|
@@ -3446,22 +3937,22 @@ var votingEscrowLiteAbi = [
|
|
|
3446
3937
|
outputs: [{ type: "uint256" }]
|
|
3447
3938
|
}
|
|
3448
3939
|
];
|
|
3449
|
-
var relayRowSchema =
|
|
3450
|
-
label:
|
|
3451
|
-
relay:
|
|
3452
|
-
name:
|
|
3453
|
-
factoryType:
|
|
3454
|
-
managedTokenId:
|
|
3455
|
-
managedVotingPower:
|
|
3456
|
-
relayToken:
|
|
3457
|
-
address:
|
|
3458
|
-
symbol:
|
|
3459
|
-
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()
|
|
3460
3951
|
}),
|
|
3461
|
-
relayTokenBalance:
|
|
3462
|
-
keeperLastRun:
|
|
3463
|
-
keeperLastRunRelative:
|
|
3464
|
-
secondsSinceKeeperRun:
|
|
3952
|
+
relayTokenBalance: z6.string(),
|
|
3953
|
+
keeperLastRun: z6.number(),
|
|
3954
|
+
keeperLastRunRelative: z6.string(),
|
|
3955
|
+
secondsSinceKeeperRun: z6.number()
|
|
3465
3956
|
});
|
|
3466
3957
|
var KNOWN_RELAYS = [
|
|
3467
3958
|
{
|
|
@@ -3587,17 +4078,17 @@ var vaults = Cli5.create("vaults", {
|
|
|
3587
4078
|
vaults.command("list", {
|
|
3588
4079
|
description: "List known Aborean relay vaults with keeper and veNFT state.",
|
|
3589
4080
|
env: env5,
|
|
3590
|
-
output:
|
|
3591
|
-
relayCount:
|
|
3592
|
-
relays:
|
|
3593
|
-
totals:
|
|
3594
|
-
managedVotingPower:
|
|
3595
|
-
relayTokenBalances:
|
|
3596
|
-
|
|
3597
|
-
token:
|
|
3598
|
-
symbol:
|
|
3599
|
-
decimals:
|
|
3600
|
-
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()
|
|
3601
4092
|
})
|
|
3602
4093
|
)
|
|
3603
4094
|
})
|
|
@@ -3636,8 +4127,8 @@ vaults.command("list", {
|
|
|
3636
4127
|
});
|
|
3637
4128
|
vaults.command("relay", {
|
|
3638
4129
|
description: "Inspect one relay vault by address.",
|
|
3639
|
-
args:
|
|
3640
|
-
relay:
|
|
4130
|
+
args: z6.object({
|
|
4131
|
+
relay: z6.string().describe("Relay vault contract address")
|
|
3641
4132
|
}),
|
|
3642
4133
|
env: env5,
|
|
3643
4134
|
output: relayRowSchema,
|
|
@@ -3689,9 +4180,9 @@ vaults.command("relay", {
|
|
|
3689
4180
|
});
|
|
3690
4181
|
|
|
3691
4182
|
// src/commands/ve.ts
|
|
3692
|
-
import { Cli as Cli6, z as
|
|
3693
|
-
var env6 =
|
|
3694
|
-
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")
|
|
3695
4186
|
});
|
|
3696
4187
|
var ve = Cli6.create("ve", {
|
|
3697
4188
|
description: "Inspect Aborean VotingEscrow (veABX) global and per-NFT lock state."
|
|
@@ -3699,16 +4190,16 @@ var ve = Cli6.create("ve", {
|
|
|
3699
4190
|
ve.command("stats", {
|
|
3700
4191
|
description: "Get global VotingEscrow supply, locks, and decay checkpoint data.",
|
|
3701
4192
|
env: env6,
|
|
3702
|
-
output:
|
|
3703
|
-
token:
|
|
3704
|
-
totalVotingPower:
|
|
3705
|
-
totalLocked:
|
|
3706
|
-
permanentLocked:
|
|
3707
|
-
epoch:
|
|
3708
|
-
decayBias:
|
|
3709
|
-
decaySlope:
|
|
3710
|
-
lastCheckpointTimestamp:
|
|
3711
|
-
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()
|
|
3712
4203
|
}),
|
|
3713
4204
|
examples: [{ description: "Show global veABX state and decay metrics" }],
|
|
3714
4205
|
async run(c) {
|
|
@@ -3779,17 +4270,17 @@ ve.command("stats", {
|
|
|
3779
4270
|
});
|
|
3780
4271
|
ve.command("lock", {
|
|
3781
4272
|
description: "Get lock details and voting power for one veNFT token id.",
|
|
3782
|
-
args:
|
|
3783
|
-
tokenId:
|
|
4273
|
+
args: z7.object({
|
|
4274
|
+
tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3784
4275
|
}),
|
|
3785
4276
|
env: env6,
|
|
3786
|
-
output:
|
|
3787
|
-
tokenId:
|
|
3788
|
-
owner:
|
|
3789
|
-
amount:
|
|
3790
|
-
unlockTime:
|
|
3791
|
-
isPermanent:
|
|
3792
|
-
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()
|
|
3793
4284
|
}),
|
|
3794
4285
|
examples: [{ args: { tokenId: 1 }, description: "Inspect lock details for veNFT #1" }],
|
|
3795
4286
|
async run(c) {
|
|
@@ -3846,22 +4337,22 @@ ve.command("lock", {
|
|
|
3846
4337
|
});
|
|
3847
4338
|
ve.command("locks", {
|
|
3848
4339
|
description: "List all veNFT locks owned by an address.",
|
|
3849
|
-
args:
|
|
3850
|
-
address:
|
|
4340
|
+
args: z7.object({
|
|
4341
|
+
address: z7.string().describe("Owner address")
|
|
3851
4342
|
}),
|
|
3852
4343
|
env: env6,
|
|
3853
|
-
output:
|
|
3854
|
-
address:
|
|
3855
|
-
locks:
|
|
3856
|
-
|
|
3857
|
-
tokenId:
|
|
3858
|
-
amount:
|
|
3859
|
-
unlockTime:
|
|
3860
|
-
isPermanent:
|
|
3861
|
-
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()
|
|
3862
4353
|
})
|
|
3863
4354
|
),
|
|
3864
|
-
count:
|
|
4355
|
+
count: z7.number()
|
|
3865
4356
|
}),
|
|
3866
4357
|
examples: [
|
|
3867
4358
|
{
|
|
@@ -3953,13 +4444,13 @@ ve.command("locks", {
|
|
|
3953
4444
|
});
|
|
3954
4445
|
ve.command("voting-power", {
|
|
3955
4446
|
description: "Get current voting power for one veNFT token id.",
|
|
3956
|
-
args:
|
|
3957
|
-
tokenId:
|
|
4447
|
+
args: z7.object({
|
|
4448
|
+
tokenId: z7.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
3958
4449
|
}),
|
|
3959
4450
|
env: env6,
|
|
3960
|
-
output:
|
|
3961
|
-
tokenId:
|
|
3962
|
-
votingPower:
|
|
4451
|
+
output: z7.object({
|
|
4452
|
+
tokenId: z7.number(),
|
|
4453
|
+
votingPower: z7.string()
|
|
3963
4454
|
}),
|
|
3964
4455
|
examples: [{ args: { tokenId: 1 }, description: "Get current voting power for veNFT #1" }],
|
|
3965
4456
|
async run(c) {
|
|
@@ -3997,9 +4488,9 @@ ve.command("voting-power", {
|
|
|
3997
4488
|
});
|
|
3998
4489
|
|
|
3999
4490
|
// src/commands/voter.ts
|
|
4000
|
-
import { Cli as Cli7, z as
|
|
4001
|
-
var env7 =
|
|
4002
|
-
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")
|
|
4003
4494
|
});
|
|
4004
4495
|
async function discoverPools(client) {
|
|
4005
4496
|
const [v2PoolCount, clPoolCount] = await Promise.all([
|
|
@@ -4044,14 +4535,14 @@ var voter = Cli7.create("voter", {
|
|
|
4044
4535
|
voter.command("epoch", {
|
|
4045
4536
|
description: "Show current emissions epoch timing from Minter.",
|
|
4046
4537
|
env: env7,
|
|
4047
|
-
output:
|
|
4048
|
-
activePeriod:
|
|
4049
|
-
epochEnd:
|
|
4050
|
-
secondsRemaining:
|
|
4051
|
-
timeRemaining:
|
|
4052
|
-
weekSeconds:
|
|
4053
|
-
epochCount:
|
|
4054
|
-
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()
|
|
4055
4546
|
}),
|
|
4056
4547
|
examples: [{ description: "Inspect current voter epoch boundaries" }],
|
|
4057
4548
|
async run(c) {
|
|
@@ -4111,16 +4602,16 @@ voter.command("epoch", {
|
|
|
4111
4602
|
voter.command("weights", {
|
|
4112
4603
|
description: "Show current pool voting weight distribution.",
|
|
4113
4604
|
env: env7,
|
|
4114
|
-
output:
|
|
4115
|
-
totalWeight:
|
|
4116
|
-
pools:
|
|
4117
|
-
|
|
4118
|
-
pool:
|
|
4119
|
-
gauge:
|
|
4120
|
-
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()
|
|
4121
4612
|
})
|
|
4122
4613
|
),
|
|
4123
|
-
count:
|
|
4614
|
+
count: z8.number()
|
|
4124
4615
|
}),
|
|
4125
4616
|
examples: [{ description: "List all pools with non-zero voting weight" }],
|
|
4126
4617
|
async run(c) {
|
|
@@ -4199,19 +4690,19 @@ voter.command("weights", {
|
|
|
4199
4690
|
});
|
|
4200
4691
|
voter.command("rewards", {
|
|
4201
4692
|
description: "Show claimable rebase rewards and voting context for a veNFT.",
|
|
4202
|
-
args:
|
|
4203
|
-
tokenId:
|
|
4693
|
+
args: z8.object({
|
|
4694
|
+
tokenId: z8.coerce.number().int().nonnegative().describe("veNFT token id")
|
|
4204
4695
|
}),
|
|
4205
4696
|
env: env7,
|
|
4206
|
-
output:
|
|
4207
|
-
tokenId:
|
|
4208
|
-
rewardToken:
|
|
4209
|
-
claimableRebase:
|
|
4210
|
-
timeCursor:
|
|
4211
|
-
lastTokenTime:
|
|
4212
|
-
distributorStartTime:
|
|
4213
|
-
usedWeight:
|
|
4214
|
-
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()
|
|
4215
4706
|
}),
|
|
4216
4707
|
examples: [{ args: { tokenId: 1 }, description: "Check claimable voter/distributor rewards" }],
|
|
4217
4708
|
async run(c) {
|
|
@@ -4298,22 +4789,22 @@ voter.command("rewards", {
|
|
|
4298
4789
|
});
|
|
4299
4790
|
voter.command("bribes", {
|
|
4300
4791
|
description: "Show active bribe reward tokens and current-epoch amounts for a pool.",
|
|
4301
|
-
args:
|
|
4302
|
-
pool:
|
|
4792
|
+
args: z8.object({
|
|
4793
|
+
pool: z8.string().describe("Pool address")
|
|
4303
4794
|
}),
|
|
4304
4795
|
env: env7,
|
|
4305
|
-
output:
|
|
4306
|
-
pool:
|
|
4307
|
-
gauge:
|
|
4308
|
-
bribeContract:
|
|
4309
|
-
epochStart:
|
|
4310
|
-
rewardTokens:
|
|
4311
|
-
|
|
4312
|
-
token:
|
|
4313
|
-
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()
|
|
4314
4805
|
})
|
|
4315
4806
|
),
|
|
4316
|
-
count:
|
|
4807
|
+
count: z8.number()
|
|
4317
4808
|
}),
|
|
4318
4809
|
examples: [
|
|
4319
4810
|
{
|
|
@@ -4568,8 +5059,8 @@ cli.command(voter);
|
|
|
4568
5059
|
cli.command(cl);
|
|
4569
5060
|
cli.command(vaults);
|
|
4570
5061
|
cli.command(lending);
|
|
4571
|
-
var rootEnv =
|
|
4572
|
-
ABSTRACT_RPC_URL:
|
|
5062
|
+
var rootEnv = z9.object({
|
|
5063
|
+
ABSTRACT_RPC_URL: z9.string().optional().describe("Abstract RPC URL override")
|
|
4573
5064
|
});
|
|
4574
5065
|
var erc20MetadataAbi4 = [
|
|
4575
5066
|
{
|
|
@@ -4774,65 +5265,65 @@ async function readTopV2PoolsSnapshot(client, limit) {
|
|
|
4774
5265
|
cli.command("status", {
|
|
4775
5266
|
description: "Cross-protocol Aborean snapshot (TVL estimates, epoch, top pools, ve lock, vaults, Morpho lending).",
|
|
4776
5267
|
env: rootEnv,
|
|
4777
|
-
output:
|
|
4778
|
-
v2PoolCount:
|
|
4779
|
-
clPoolCount:
|
|
4780
|
-
gaugeCount:
|
|
4781
|
-
totalVotingWeight:
|
|
4782
|
-
veABXTotalSupply:
|
|
4783
|
-
veABXLockedSupply:
|
|
4784
|
-
epoch:
|
|
4785
|
-
activePeriod:
|
|
4786
|
-
epochEnd:
|
|
4787
|
-
secondsRemaining:
|
|
4788
|
-
epochCount:
|
|
4789
|
-
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()
|
|
4790
5281
|
}),
|
|
4791
|
-
topPools:
|
|
4792
|
-
|
|
4793
|
-
pool:
|
|
4794
|
-
pair:
|
|
4795
|
-
poolType:
|
|
4796
|
-
token0:
|
|
4797
|
-
address:
|
|
4798
|
-
symbol:
|
|
4799
|
-
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()
|
|
4800
5291
|
}),
|
|
4801
|
-
token1:
|
|
4802
|
-
address:
|
|
4803
|
-
symbol:
|
|
4804
|
-
decimals:
|
|
5292
|
+
token1: z9.object({
|
|
5293
|
+
address: z9.string(),
|
|
5294
|
+
symbol: z9.string(),
|
|
5295
|
+
decimals: z9.number()
|
|
4805
5296
|
}),
|
|
4806
|
-
reserves:
|
|
4807
|
-
token0:
|
|
4808
|
-
token1:
|
|
5297
|
+
reserves: z9.object({
|
|
5298
|
+
token0: z9.string(),
|
|
5299
|
+
token1: z9.string()
|
|
4809
5300
|
}),
|
|
4810
|
-
tvlEstimateUnits:
|
|
5301
|
+
tvlEstimateUnits: z9.number()
|
|
4811
5302
|
})
|
|
4812
5303
|
),
|
|
4813
|
-
tvl:
|
|
4814
|
-
v2ReserveUnitEstimate:
|
|
4815
|
-
vaultManagedVotingPower:
|
|
5304
|
+
tvl: z9.object({
|
|
5305
|
+
v2ReserveUnitEstimate: z9.number(),
|
|
5306
|
+
vaultManagedVotingPower: z9.string()
|
|
4816
5307
|
}),
|
|
4817
|
-
vaults:
|
|
4818
|
-
relayCount:
|
|
4819
|
-
managedVotingPower:
|
|
4820
|
-
note:
|
|
5308
|
+
vaults: z9.object({
|
|
5309
|
+
relayCount: z9.number(),
|
|
5310
|
+
managedVotingPower: z9.string(),
|
|
5311
|
+
note: z9.string().nullable()
|
|
4821
5312
|
}),
|
|
4822
|
-
lending:
|
|
4823
|
-
available:
|
|
4824
|
-
morpho:
|
|
4825
|
-
marketCount:
|
|
4826
|
-
supplyByLoanToken:
|
|
4827
|
-
|
|
4828
|
-
token:
|
|
4829
|
-
symbol:
|
|
4830
|
-
decimals:
|
|
4831
|
-
totalSupplyAssets:
|
|
4832
|
-
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()
|
|
4833
5324
|
})
|
|
4834
5325
|
),
|
|
4835
|
-
note:
|
|
5326
|
+
note: z9.string().nullable()
|
|
4836
5327
|
})
|
|
4837
5328
|
}),
|
|
4838
5329
|
examples: [{ description: "Fetch the current Aborean protocol status" }],
|