@spectratools/assembly-cli 0.1.0 → 0.2.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/README.md +41 -199
- package/dist/cli.js +730 -89
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -29,6 +29,19 @@ function relTime(unixSeconds) {
|
|
|
29
29
|
function asNum(value) {
|
|
30
30
|
return Number(value);
|
|
31
31
|
}
|
|
32
|
+
function jsonSafe(value) {
|
|
33
|
+
if (typeof value === "bigint") return value.toString();
|
|
34
|
+
if (Array.isArray(value)) return value.map((item) => jsonSafe(item));
|
|
35
|
+
if (value && typeof value === "object") {
|
|
36
|
+
return Object.fromEntries(
|
|
37
|
+
Object.entries(value).map(([key, entry]) => [
|
|
38
|
+
key,
|
|
39
|
+
jsonSafe(entry)
|
|
40
|
+
])
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
32
45
|
|
|
33
46
|
// src/commands/council.ts
|
|
34
47
|
import { Cli, z } from "incur";
|
|
@@ -4293,12 +4306,35 @@ function createAssemblyPublicClient(rpcUrl) {
|
|
|
4293
4306
|
}
|
|
4294
4307
|
|
|
4295
4308
|
// src/commands/council.ts
|
|
4296
|
-
var env = z.object({
|
|
4309
|
+
var env = z.object({
|
|
4310
|
+
ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override")
|
|
4311
|
+
});
|
|
4312
|
+
function decodeSeat(value) {
|
|
4313
|
+
const [owner, startAt, endAt, forfeited] = value;
|
|
4314
|
+
return { owner, startAt, endAt, forfeited };
|
|
4315
|
+
}
|
|
4316
|
+
function decodeAuction(value) {
|
|
4317
|
+
const [highestBidder, highestBid, settled] = value;
|
|
4318
|
+
return { highestBidder, highestBid, settled };
|
|
4319
|
+
}
|
|
4297
4320
|
var council = Cli.create("council", {
|
|
4298
|
-
description: "
|
|
4321
|
+
description: "Inspect council seats, members, auctions, and seat parameters."
|
|
4299
4322
|
});
|
|
4300
4323
|
council.command("seats", {
|
|
4324
|
+
description: "List all council seats and their occupancy windows.",
|
|
4301
4325
|
env,
|
|
4326
|
+
output: z.array(
|
|
4327
|
+
z.object({
|
|
4328
|
+
id: z.number(),
|
|
4329
|
+
owner: z.string(),
|
|
4330
|
+
startAt: z.number(),
|
|
4331
|
+
startAtRelative: z.string(),
|
|
4332
|
+
endAt: z.number(),
|
|
4333
|
+
endAtRelative: z.string(),
|
|
4334
|
+
forfeited: z.boolean()
|
|
4335
|
+
})
|
|
4336
|
+
),
|
|
4337
|
+
examples: [{ description: "List all council seats" }],
|
|
4302
4338
|
async run(c) {
|
|
4303
4339
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4304
4340
|
const count = await client.readContract({
|
|
@@ -4307,7 +4343,7 @@ council.command("seats", {
|
|
|
4307
4343
|
functionName: "seatCount"
|
|
4308
4344
|
});
|
|
4309
4345
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i));
|
|
4310
|
-
const
|
|
4346
|
+
const seatTuples = ids.length ? await client.multicall({
|
|
4311
4347
|
allowFailure: false,
|
|
4312
4348
|
contracts: ids.map((id) => ({
|
|
4313
4349
|
abi: councilSeatsAbi,
|
|
@@ -4316,13 +4352,14 @@ council.command("seats", {
|
|
|
4316
4352
|
args: [id]
|
|
4317
4353
|
}))
|
|
4318
4354
|
}) : [];
|
|
4355
|
+
const seats = seatTuples.map(decodeSeat);
|
|
4319
4356
|
return c.ok(
|
|
4320
4357
|
seats.map((seat, idx) => ({
|
|
4321
4358
|
id: idx,
|
|
4322
4359
|
owner: toChecksum(seat.owner),
|
|
4323
|
-
startAt:
|
|
4360
|
+
startAt: asNum(seat.startAt),
|
|
4324
4361
|
startAtRelative: relTime(seat.startAt),
|
|
4325
|
-
endAt:
|
|
4362
|
+
endAt: asNum(seat.endAt),
|
|
4326
4363
|
endAtRelative: relTime(seat.endAt),
|
|
4327
4364
|
forfeited: seat.forfeited
|
|
4328
4365
|
}))
|
|
@@ -4330,26 +4367,49 @@ council.command("seats", {
|
|
|
4330
4367
|
}
|
|
4331
4368
|
});
|
|
4332
4369
|
council.command("seat", {
|
|
4333
|
-
|
|
4370
|
+
description: "Get detailed seat information for a specific seat id.",
|
|
4371
|
+
args: z.object({
|
|
4372
|
+
id: z.coerce.number().int().nonnegative().describe("Seat id (0-indexed)")
|
|
4373
|
+
}),
|
|
4334
4374
|
env,
|
|
4375
|
+
output: z.object({
|
|
4376
|
+
id: z.number(),
|
|
4377
|
+
owner: z.string(),
|
|
4378
|
+
startAt: z.number(),
|
|
4379
|
+
endAt: z.number(),
|
|
4380
|
+
forfeited: z.boolean(),
|
|
4381
|
+
endAtRelative: z.string()
|
|
4382
|
+
}),
|
|
4383
|
+
examples: [{ args: { id: 0 }, description: "Inspect seat #0" }],
|
|
4335
4384
|
async run(c) {
|
|
4336
4385
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4337
|
-
const
|
|
4386
|
+
const seatTuple = await client.readContract({
|
|
4338
4387
|
abi: councilSeatsAbi,
|
|
4339
4388
|
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4340
4389
|
functionName: "seats",
|
|
4341
4390
|
args: [BigInt(c.args.id)]
|
|
4342
4391
|
});
|
|
4392
|
+
const seat = decodeSeat(seatTuple);
|
|
4343
4393
|
return c.ok({
|
|
4344
4394
|
id: c.args.id,
|
|
4345
|
-
...seat,
|
|
4346
4395
|
owner: toChecksum(seat.owner),
|
|
4396
|
+
startAt: asNum(seat.startAt),
|
|
4397
|
+
endAt: asNum(seat.endAt),
|
|
4398
|
+
forfeited: seat.forfeited,
|
|
4347
4399
|
endAtRelative: relTime(seat.endAt)
|
|
4348
4400
|
});
|
|
4349
4401
|
}
|
|
4350
4402
|
});
|
|
4351
4403
|
council.command("members", {
|
|
4404
|
+
description: "List currently active council members and voting power.",
|
|
4352
4405
|
env,
|
|
4406
|
+
output: z.array(
|
|
4407
|
+
z.object({
|
|
4408
|
+
address: z.string(),
|
|
4409
|
+
votingPower: z.number()
|
|
4410
|
+
})
|
|
4411
|
+
),
|
|
4412
|
+
examples: [{ description: "List active council members" }],
|
|
4353
4413
|
async run(c) {
|
|
4354
4414
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4355
4415
|
const count = await client.readContract({
|
|
@@ -4358,7 +4418,7 @@ council.command("members", {
|
|
|
4358
4418
|
functionName: "seatCount"
|
|
4359
4419
|
});
|
|
4360
4420
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i));
|
|
4361
|
-
const
|
|
4421
|
+
const seatTuples = ids.length ? await client.multicall({
|
|
4362
4422
|
allowFailure: false,
|
|
4363
4423
|
contracts: ids.map((id) => ({
|
|
4364
4424
|
abi: councilSeatsAbi,
|
|
@@ -4367,9 +4427,10 @@ council.command("members", {
|
|
|
4367
4427
|
args: [id]
|
|
4368
4428
|
}))
|
|
4369
4429
|
}) : [];
|
|
4430
|
+
const seats = seatTuples.map(decodeSeat);
|
|
4370
4431
|
const activeOwners = [
|
|
4371
4432
|
...new Set(
|
|
4372
|
-
seats.filter((x) => !x.forfeited &&
|
|
4433
|
+
seats.filter((x) => !x.forfeited && asNum(x.endAt) > Math.floor(Date.now() / 1e3)).map((x) => x.owner)
|
|
4373
4434
|
)
|
|
4374
4435
|
];
|
|
4375
4436
|
const powers = activeOwners.length ? await client.multicall({
|
|
@@ -4390,8 +4451,21 @@ council.command("members", {
|
|
|
4390
4451
|
}
|
|
4391
4452
|
});
|
|
4392
4453
|
council.command("is-member", {
|
|
4393
|
-
|
|
4454
|
+
description: "Check whether an address is currently a council member.",
|
|
4455
|
+
args: z.object({
|
|
4456
|
+
address: z.string().describe("Address to check")
|
|
4457
|
+
}),
|
|
4394
4458
|
env,
|
|
4459
|
+
output: z.object({
|
|
4460
|
+
address: z.string(),
|
|
4461
|
+
isMember: z.boolean()
|
|
4462
|
+
}),
|
|
4463
|
+
examples: [
|
|
4464
|
+
{
|
|
4465
|
+
args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
|
|
4466
|
+
description: "Check council status for one address"
|
|
4467
|
+
}
|
|
4468
|
+
],
|
|
4395
4469
|
async run(c) {
|
|
4396
4470
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4397
4471
|
const isMember = await client.readContract({
|
|
@@ -4404,8 +4478,21 @@ council.command("is-member", {
|
|
|
4404
4478
|
}
|
|
4405
4479
|
});
|
|
4406
4480
|
council.command("voting-power", {
|
|
4407
|
-
|
|
4481
|
+
description: "Get the current voting power for an address.",
|
|
4482
|
+
args: z.object({
|
|
4483
|
+
address: z.string().describe("Address to inspect")
|
|
4484
|
+
}),
|
|
4408
4485
|
env,
|
|
4486
|
+
output: z.object({
|
|
4487
|
+
address: z.string(),
|
|
4488
|
+
votingPower: z.number()
|
|
4489
|
+
}),
|
|
4490
|
+
examples: [
|
|
4491
|
+
{
|
|
4492
|
+
args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
|
|
4493
|
+
description: "Get voting power for one address"
|
|
4494
|
+
}
|
|
4495
|
+
],
|
|
4409
4496
|
async run(c) {
|
|
4410
4497
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4411
4498
|
const votingPower = await client.readContract({
|
|
@@ -4418,7 +4505,22 @@ council.command("voting-power", {
|
|
|
4418
4505
|
}
|
|
4419
4506
|
});
|
|
4420
4507
|
council.command("auctions", {
|
|
4508
|
+
description: "List recent and current council auction slots and leading bids.",
|
|
4421
4509
|
env,
|
|
4510
|
+
output: z.object({
|
|
4511
|
+
currentDay: z.number(),
|
|
4512
|
+
currentSlot: z.number(),
|
|
4513
|
+
auctions: z.array(
|
|
4514
|
+
z.object({
|
|
4515
|
+
day: z.number(),
|
|
4516
|
+
slot: z.number(),
|
|
4517
|
+
highestBidder: z.string(),
|
|
4518
|
+
highestBid: z.string(),
|
|
4519
|
+
settled: z.boolean()
|
|
4520
|
+
})
|
|
4521
|
+
)
|
|
4522
|
+
}),
|
|
4523
|
+
examples: [{ description: "Inspect current and recent auction slots" }],
|
|
4422
4524
|
async run(c) {
|
|
4423
4525
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4424
4526
|
const [day, slot, slotsPerDay] = await Promise.all([
|
|
@@ -4443,7 +4545,7 @@ council.command("auctions", {
|
|
|
4443
4545
|
if (d < 0) continue;
|
|
4444
4546
|
for (let s = 0; s < Number(slotsPerDay); s++) recent.push({ day: BigInt(d), slot: s });
|
|
4445
4547
|
}
|
|
4446
|
-
const
|
|
4548
|
+
const auctionTuples = recent.length ? await client.multicall({
|
|
4447
4549
|
allowFailure: false,
|
|
4448
4550
|
contracts: recent.map((x) => ({
|
|
4449
4551
|
abi: councilSeatsAbi,
|
|
@@ -4452,12 +4554,14 @@ council.command("auctions", {
|
|
|
4452
4554
|
args: [x.day, x.slot]
|
|
4453
4555
|
}))
|
|
4454
4556
|
}) : [];
|
|
4557
|
+
const auctions = auctionTuples.map(decodeAuction);
|
|
4455
4558
|
return c.ok(
|
|
4456
4559
|
{
|
|
4457
4560
|
currentDay: asNum(day),
|
|
4458
4561
|
currentSlot: asNum(slot),
|
|
4459
4562
|
auctions: recent.map((x, i) => ({
|
|
4460
|
-
|
|
4563
|
+
day: Number(x.day),
|
|
4564
|
+
slot: x.slot,
|
|
4461
4565
|
highestBidder: toChecksum(auctions[i].highestBidder),
|
|
4462
4566
|
highestBid: eth(auctions[i].highestBid),
|
|
4463
4567
|
settled: auctions[i].settled
|
|
@@ -4476,19 +4580,29 @@ council.command("auctions", {
|
|
|
4476
4580
|
}
|
|
4477
4581
|
});
|
|
4478
4582
|
council.command("auction", {
|
|
4583
|
+
description: "Get one auction slot by day + slot.",
|
|
4479
4584
|
args: z.object({
|
|
4480
|
-
day: z.coerce.number().int().nonnegative(),
|
|
4481
|
-
slot: z.coerce.number().int().nonnegative()
|
|
4585
|
+
day: z.coerce.number().int().nonnegative().describe("Auction day index"),
|
|
4586
|
+
slot: z.coerce.number().int().nonnegative().describe("Slot index within day")
|
|
4482
4587
|
}),
|
|
4483
4588
|
env,
|
|
4589
|
+
output: z.object({
|
|
4590
|
+
day: z.number(),
|
|
4591
|
+
slot: z.number(),
|
|
4592
|
+
highestBidder: z.string(),
|
|
4593
|
+
highestBid: z.string(),
|
|
4594
|
+
settled: z.boolean()
|
|
4595
|
+
}),
|
|
4596
|
+
examples: [{ args: { day: 0, slot: 0 }, description: "Inspect day 0, slot 0 auction" }],
|
|
4484
4597
|
async run(c) {
|
|
4485
4598
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4486
|
-
const
|
|
4599
|
+
const auctionTuple = await client.readContract({
|
|
4487
4600
|
abi: councilSeatsAbi,
|
|
4488
4601
|
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
4489
4602
|
functionName: "auctions",
|
|
4490
4603
|
args: [BigInt(c.args.day), c.args.slot]
|
|
4491
4604
|
});
|
|
4605
|
+
const auction = decodeAuction(auctionTuple);
|
|
4492
4606
|
return c.ok({
|
|
4493
4607
|
day: c.args.day,
|
|
4494
4608
|
slot: c.args.slot,
|
|
@@ -4499,8 +4613,22 @@ council.command("auction", {
|
|
|
4499
4613
|
}
|
|
4500
4614
|
});
|
|
4501
4615
|
council.command("pending-refund", {
|
|
4502
|
-
|
|
4616
|
+
description: "Get pending refundable bid amount for an address.",
|
|
4617
|
+
args: z.object({
|
|
4618
|
+
address: z.string().describe("Bidder address")
|
|
4619
|
+
}),
|
|
4503
4620
|
env,
|
|
4621
|
+
output: z.object({
|
|
4622
|
+
address: z.string(),
|
|
4623
|
+
pendingRefund: z.string(),
|
|
4624
|
+
pendingRefundWei: z.string()
|
|
4625
|
+
}),
|
|
4626
|
+
examples: [
|
|
4627
|
+
{
|
|
4628
|
+
args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
|
|
4629
|
+
description: "Check pending refund for an address"
|
|
4630
|
+
}
|
|
4631
|
+
],
|
|
4504
4632
|
async run(c) {
|
|
4505
4633
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4506
4634
|
const amount = await client.readContract({
|
|
@@ -4517,7 +4645,17 @@ council.command("pending-refund", {
|
|
|
4517
4645
|
}
|
|
4518
4646
|
});
|
|
4519
4647
|
council.command("params", {
|
|
4648
|
+
description: "Read council seat term and auction scheduling parameters.",
|
|
4520
4649
|
env,
|
|
4650
|
+
output: z.object({
|
|
4651
|
+
SEAT_TERM: z.number(),
|
|
4652
|
+
AUCTION_SLOT_DURATION: z.number(),
|
|
4653
|
+
AUCTION_SLOTS_PER_DAY: z.number(),
|
|
4654
|
+
auctionEpochStart: z.number(),
|
|
4655
|
+
auctionWindowStart: z.number(),
|
|
4656
|
+
auctionWindowEnd: z.number()
|
|
4657
|
+
}),
|
|
4658
|
+
examples: [{ description: "Inspect council seat + auction timing constants" }],
|
|
4521
4659
|
async run(c) {
|
|
4522
4660
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4523
4661
|
const [SEAT_TERM, AUCTION_SLOT_DURATION, AUCTION_SLOTS_PER_DAY, auctionEpochStart] = await Promise.all([
|
|
@@ -4569,10 +4707,78 @@ council.command("params", {
|
|
|
4569
4707
|
|
|
4570
4708
|
// src/commands/forum.ts
|
|
4571
4709
|
import { Cli as Cli2, z as z2 } from "incur";
|
|
4572
|
-
var env2 = z2.object({
|
|
4573
|
-
|
|
4710
|
+
var env2 = z2.object({
|
|
4711
|
+
ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
|
|
4712
|
+
});
|
|
4713
|
+
function decodeThread(value) {
|
|
4714
|
+
const [id, kind, author, createdAt, category, title, body, proposalId, petitionId] = value;
|
|
4715
|
+
return {
|
|
4716
|
+
id: asNum(id),
|
|
4717
|
+
kind: asNum(kind),
|
|
4718
|
+
author: toChecksum(author),
|
|
4719
|
+
createdAt: asNum(createdAt),
|
|
4720
|
+
category,
|
|
4721
|
+
title,
|
|
4722
|
+
body,
|
|
4723
|
+
proposalId: asNum(proposalId),
|
|
4724
|
+
petitionId: asNum(petitionId)
|
|
4725
|
+
};
|
|
4726
|
+
}
|
|
4727
|
+
function decodeComment(value) {
|
|
4728
|
+
const [id, threadId, parentId, author, createdAt, body] = value;
|
|
4729
|
+
return {
|
|
4730
|
+
id: asNum(id),
|
|
4731
|
+
threadId: asNum(threadId),
|
|
4732
|
+
parentId: asNum(parentId),
|
|
4733
|
+
author: toChecksum(author),
|
|
4734
|
+
createdAt: asNum(createdAt),
|
|
4735
|
+
body
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4738
|
+
function decodePetition(value) {
|
|
4739
|
+
const [
|
|
4740
|
+
id,
|
|
4741
|
+
proposer,
|
|
4742
|
+
createdAt,
|
|
4743
|
+
category,
|
|
4744
|
+
title,
|
|
4745
|
+
body,
|
|
4746
|
+
signatures,
|
|
4747
|
+
promoted,
|
|
4748
|
+
threadId,
|
|
4749
|
+
proposalInput
|
|
4750
|
+
] = value;
|
|
4751
|
+
return {
|
|
4752
|
+
id: asNum(id),
|
|
4753
|
+
proposer: toChecksum(proposer),
|
|
4754
|
+
createdAt: asNum(createdAt),
|
|
4755
|
+
category,
|
|
4756
|
+
title,
|
|
4757
|
+
body,
|
|
4758
|
+
signatures: asNum(signatures),
|
|
4759
|
+
promoted,
|
|
4760
|
+
threadId: asNum(threadId),
|
|
4761
|
+
proposalInput: jsonSafe(proposalInput)
|
|
4762
|
+
};
|
|
4763
|
+
}
|
|
4764
|
+
var forum = Cli2.create("forum", {
|
|
4765
|
+
description: "Browse Assembly forum threads, comments, and petitions."
|
|
4766
|
+
});
|
|
4574
4767
|
forum.command("threads", {
|
|
4768
|
+
description: "List forum threads with author and creation metadata.",
|
|
4575
4769
|
env: env2,
|
|
4770
|
+
output: z2.array(
|
|
4771
|
+
z2.object({
|
|
4772
|
+
id: z2.number(),
|
|
4773
|
+
kind: z2.number(),
|
|
4774
|
+
author: z2.string(),
|
|
4775
|
+
createdAt: z2.number(),
|
|
4776
|
+
createdAtRelative: z2.string(),
|
|
4777
|
+
category: z2.string().nullable().optional(),
|
|
4778
|
+
title: z2.string().nullable().optional()
|
|
4779
|
+
})
|
|
4780
|
+
),
|
|
4781
|
+
examples: [{ description: "List all forum threads" }],
|
|
4576
4782
|
async run(c) {
|
|
4577
4783
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4578
4784
|
const count = await client.readContract({
|
|
@@ -4581,7 +4787,7 @@ forum.command("threads", {
|
|
|
4581
4787
|
functionName: "threadCount"
|
|
4582
4788
|
});
|
|
4583
4789
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
4584
|
-
const
|
|
4790
|
+
const threadTuples = ids.length ? await client.multicall({
|
|
4585
4791
|
allowFailure: false,
|
|
4586
4792
|
contracts: ids.map((id) => ({
|
|
4587
4793
|
abi: forumAbi,
|
|
@@ -4590,15 +4796,16 @@ forum.command("threads", {
|
|
|
4590
4796
|
args: [id]
|
|
4591
4797
|
}))
|
|
4592
4798
|
}) : [];
|
|
4799
|
+
const items = threadTuples.map(decodeThread);
|
|
4593
4800
|
return c.ok(
|
|
4594
4801
|
items.map((x) => ({
|
|
4595
|
-
id:
|
|
4596
|
-
kind:
|
|
4597
|
-
author:
|
|
4598
|
-
createdAt:
|
|
4802
|
+
id: x.id,
|
|
4803
|
+
kind: x.kind,
|
|
4804
|
+
author: x.author,
|
|
4805
|
+
createdAt: x.createdAt,
|
|
4599
4806
|
createdAtRelative: relTime(x.createdAt),
|
|
4600
|
-
category: x.category,
|
|
4601
|
-
title: x.title
|
|
4807
|
+
category: x.category ?? null,
|
|
4808
|
+
title: x.title ?? null
|
|
4602
4809
|
})),
|
|
4603
4810
|
{
|
|
4604
4811
|
cta: {
|
|
@@ -4613,11 +4820,19 @@ forum.command("threads", {
|
|
|
4613
4820
|
}
|
|
4614
4821
|
});
|
|
4615
4822
|
forum.command("thread", {
|
|
4616
|
-
|
|
4823
|
+
description: "Get one thread and all comments associated with it.",
|
|
4824
|
+
args: z2.object({
|
|
4825
|
+
id: z2.coerce.number().int().positive().describe("Thread id (1-indexed)")
|
|
4826
|
+
}),
|
|
4617
4827
|
env: env2,
|
|
4828
|
+
output: z2.object({
|
|
4829
|
+
thread: z2.record(z2.string(), z2.unknown()),
|
|
4830
|
+
comments: z2.array(z2.record(z2.string(), z2.unknown()))
|
|
4831
|
+
}),
|
|
4832
|
+
examples: [{ args: { id: 1 }, description: "Fetch thread #1 and its comments" }],
|
|
4618
4833
|
async run(c) {
|
|
4619
4834
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4620
|
-
const [
|
|
4835
|
+
const [threadTuple, commentCount] = await Promise.all([
|
|
4621
4836
|
client.readContract({
|
|
4622
4837
|
abi: forumAbi,
|
|
4623
4838
|
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
@@ -4630,8 +4845,9 @@ forum.command("thread", {
|
|
|
4630
4845
|
functionName: "commentCount"
|
|
4631
4846
|
})
|
|
4632
4847
|
]);
|
|
4848
|
+
const thread = decodeThread(threadTuple);
|
|
4633
4849
|
const ids = Array.from({ length: Number(commentCount) }, (_, i) => BigInt(i + 1));
|
|
4634
|
-
const
|
|
4850
|
+
const commentTuples = ids.length ? await client.multicall({
|
|
4635
4851
|
allowFailure: false,
|
|
4636
4852
|
contracts: ids.map((id) => ({
|
|
4637
4853
|
abi: forumAbi,
|
|
@@ -4640,15 +4856,21 @@ forum.command("thread", {
|
|
|
4640
4856
|
args: [id]
|
|
4641
4857
|
}))
|
|
4642
4858
|
}) : [];
|
|
4859
|
+
const comments = commentTuples.map(decodeComment);
|
|
4643
4860
|
return c.ok({
|
|
4644
|
-
thread,
|
|
4645
|
-
comments: comments.filter((x) =>
|
|
4861
|
+
thread: jsonSafe(thread),
|
|
4862
|
+
comments: comments.filter((x) => x.threadId === c.args.id).map((comment) => jsonSafe(comment))
|
|
4646
4863
|
});
|
|
4647
4864
|
}
|
|
4648
4865
|
});
|
|
4649
4866
|
forum.command("comments", {
|
|
4650
|
-
|
|
4867
|
+
description: "List comments for a thread id.",
|
|
4868
|
+
args: z2.object({
|
|
4869
|
+
threadId: z2.coerce.number().int().positive().describe("Thread id to filter comments by")
|
|
4870
|
+
}),
|
|
4651
4871
|
env: env2,
|
|
4872
|
+
output: z2.array(z2.record(z2.string(), z2.unknown())),
|
|
4873
|
+
examples: [{ args: { threadId: 1 }, description: "List comments for thread #1" }],
|
|
4652
4874
|
async run(c) {
|
|
4653
4875
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4654
4876
|
const count = await client.readContract({
|
|
@@ -4657,7 +4879,7 @@ forum.command("comments", {
|
|
|
4657
4879
|
functionName: "commentCount"
|
|
4658
4880
|
});
|
|
4659
4881
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
4660
|
-
const
|
|
4882
|
+
const commentTuples = ids.length ? await client.multicall({
|
|
4661
4883
|
allowFailure: false,
|
|
4662
4884
|
contracts: ids.map((id) => ({
|
|
4663
4885
|
abi: forumAbi,
|
|
@@ -4666,25 +4888,36 @@ forum.command("comments", {
|
|
|
4666
4888
|
args: [id]
|
|
4667
4889
|
}))
|
|
4668
4890
|
}) : [];
|
|
4669
|
-
|
|
4891
|
+
const comments = commentTuples.map(decodeComment);
|
|
4892
|
+
return c.ok(
|
|
4893
|
+
comments.filter((x) => x.threadId === c.args.threadId).map((comment) => jsonSafe(comment))
|
|
4894
|
+
);
|
|
4670
4895
|
}
|
|
4671
4896
|
});
|
|
4672
4897
|
forum.command("comment", {
|
|
4673
|
-
|
|
4898
|
+
description: "Get one comment by comment id.",
|
|
4899
|
+
args: z2.object({
|
|
4900
|
+
id: z2.coerce.number().int().positive().describe("Comment id (1-indexed)")
|
|
4901
|
+
}),
|
|
4674
4902
|
env: env2,
|
|
4903
|
+
output: z2.record(z2.string(), z2.unknown()),
|
|
4904
|
+
examples: [{ args: { id: 1 }, description: "Fetch comment #1" }],
|
|
4675
4905
|
async run(c) {
|
|
4676
4906
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4677
|
-
const
|
|
4907
|
+
const commentTuple = await client.readContract({
|
|
4678
4908
|
abi: forumAbi,
|
|
4679
4909
|
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
4680
4910
|
functionName: "comments",
|
|
4681
4911
|
args: [BigInt(c.args.id)]
|
|
4682
4912
|
});
|
|
4683
|
-
return c.ok(
|
|
4913
|
+
return c.ok(jsonSafe(decodeComment(commentTuple)));
|
|
4684
4914
|
}
|
|
4685
4915
|
});
|
|
4686
4916
|
forum.command("petitions", {
|
|
4917
|
+
description: "List petitions submitted in the forum contract.",
|
|
4687
4918
|
env: env2,
|
|
4919
|
+
output: z2.array(z2.record(z2.string(), z2.unknown())),
|
|
4920
|
+
examples: [{ description: "List all petitions" }],
|
|
4688
4921
|
async run(c) {
|
|
4689
4922
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4690
4923
|
const count = await client.readContract({
|
|
@@ -4693,7 +4926,7 @@ forum.command("petitions", {
|
|
|
4693
4926
|
functionName: "petitionCount"
|
|
4694
4927
|
});
|
|
4695
4928
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
4696
|
-
const
|
|
4929
|
+
const petitionTuples = ids.length ? await client.multicall({
|
|
4697
4930
|
allowFailure: false,
|
|
4698
4931
|
contracts: ids.map((id) => ({
|
|
4699
4932
|
abi: forumAbi,
|
|
@@ -4702,32 +4935,58 @@ forum.command("petitions", {
|
|
|
4702
4935
|
args: [id]
|
|
4703
4936
|
}))
|
|
4704
4937
|
}) : [];
|
|
4705
|
-
|
|
4938
|
+
const petitions = petitionTuples.map(decodePetition);
|
|
4939
|
+
return c.ok(petitions.map((petition) => jsonSafe(petition)));
|
|
4706
4940
|
}
|
|
4707
4941
|
});
|
|
4708
4942
|
forum.command("petition", {
|
|
4709
|
-
|
|
4943
|
+
description: "Get one petition plus whether proposer already signed it.",
|
|
4944
|
+
args: z2.object({
|
|
4945
|
+
id: z2.coerce.number().int().positive().describe("Petition id (1-indexed)")
|
|
4946
|
+
}),
|
|
4710
4947
|
env: env2,
|
|
4948
|
+
output: z2.object({ proposerSigned: z2.boolean() }).passthrough(),
|
|
4949
|
+
examples: [{ args: { id: 1 }, description: "Fetch petition #1" }],
|
|
4711
4950
|
async run(c) {
|
|
4712
4951
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4713
|
-
const petition =
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4952
|
+
const petition = decodePetition(
|
|
4953
|
+
await client.readContract({
|
|
4954
|
+
abi: forumAbi,
|
|
4955
|
+
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
4956
|
+
functionName: "petitions",
|
|
4957
|
+
args: [BigInt(c.args.id)]
|
|
4958
|
+
})
|
|
4959
|
+
);
|
|
4719
4960
|
const proposerSigned = await client.readContract({
|
|
4720
4961
|
abi: forumAbi,
|
|
4721
4962
|
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
4722
4963
|
functionName: "hasSignedPetition",
|
|
4723
4964
|
args: [BigInt(c.args.id), petition.proposer]
|
|
4724
4965
|
});
|
|
4725
|
-
return c.ok({ ...petition, proposerSigned });
|
|
4966
|
+
return c.ok({ ...jsonSafe(petition), proposerSigned });
|
|
4726
4967
|
}
|
|
4727
4968
|
});
|
|
4728
4969
|
forum.command("has-signed", {
|
|
4729
|
-
|
|
4970
|
+
description: "Check whether an address signed a petition.",
|
|
4971
|
+
args: z2.object({
|
|
4972
|
+
petitionId: z2.coerce.number().int().positive().describe("Petition id (1-indexed)"),
|
|
4973
|
+
address: z2.string().describe("Signer address to check")
|
|
4974
|
+
}),
|
|
4730
4975
|
env: env2,
|
|
4976
|
+
output: z2.object({
|
|
4977
|
+
petitionId: z2.number(),
|
|
4978
|
+
address: z2.string(),
|
|
4979
|
+
hasSigned: z2.boolean()
|
|
4980
|
+
}),
|
|
4981
|
+
examples: [
|
|
4982
|
+
{
|
|
4983
|
+
args: {
|
|
4984
|
+
petitionId: 1,
|
|
4985
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
|
|
4986
|
+
},
|
|
4987
|
+
description: "Check if an address signed petition #1"
|
|
4988
|
+
}
|
|
4989
|
+
],
|
|
4731
4990
|
async run(c) {
|
|
4732
4991
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4733
4992
|
const hasSigned = await client.readContract({
|
|
@@ -4740,7 +4999,15 @@ forum.command("has-signed", {
|
|
|
4740
4999
|
}
|
|
4741
5000
|
});
|
|
4742
5001
|
forum.command("stats", {
|
|
5002
|
+
description: "Read top-level forum counters and petition threshold.",
|
|
4743
5003
|
env: env2,
|
|
5004
|
+
output: z2.object({
|
|
5005
|
+
threadCount: z2.number(),
|
|
5006
|
+
commentCount: z2.number(),
|
|
5007
|
+
petitionCount: z2.number(),
|
|
5008
|
+
petitionThresholdBps: z2.number()
|
|
5009
|
+
}),
|
|
5010
|
+
examples: [{ description: "Get forum counts and petition threshold" }],
|
|
4744
5011
|
async run(c) {
|
|
4745
5012
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4746
5013
|
const [threadCount, commentCount, petitionCount, petitionThresholdBps] = await Promise.all([
|
|
@@ -4776,12 +5043,105 @@ forum.command("stats", {
|
|
|
4776
5043
|
|
|
4777
5044
|
// src/commands/governance.ts
|
|
4778
5045
|
import { Cli as Cli3, z as z3 } from "incur";
|
|
4779
|
-
var env3 = z3.object({
|
|
5046
|
+
var env3 = z3.object({
|
|
5047
|
+
ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
|
|
5048
|
+
});
|
|
5049
|
+
function decodeProposal(value) {
|
|
5050
|
+
const [
|
|
5051
|
+
kind,
|
|
5052
|
+
configRiskTier,
|
|
5053
|
+
origin,
|
|
5054
|
+
status,
|
|
5055
|
+
proposer,
|
|
5056
|
+
threadId,
|
|
5057
|
+
petitionId,
|
|
5058
|
+
createdAt,
|
|
5059
|
+
deliberationEndsAt,
|
|
5060
|
+
voteStartAt,
|
|
5061
|
+
voteEndAt,
|
|
5062
|
+
timelockEndsAt,
|
|
5063
|
+
activeSeatsSnapshot,
|
|
5064
|
+
forVotes,
|
|
5065
|
+
againstVotes,
|
|
5066
|
+
abstainVotes,
|
|
5067
|
+
amount,
|
|
5068
|
+
snapshotAssetBalance,
|
|
5069
|
+
transferIntent,
|
|
5070
|
+
intentDeadline,
|
|
5071
|
+
intentMaxRiskTier,
|
|
5072
|
+
title,
|
|
5073
|
+
description
|
|
5074
|
+
] = value;
|
|
5075
|
+
return {
|
|
5076
|
+
kind,
|
|
5077
|
+
configRiskTier,
|
|
5078
|
+
origin,
|
|
5079
|
+
status,
|
|
5080
|
+
proposer: toChecksum(proposer),
|
|
5081
|
+
threadId,
|
|
5082
|
+
petitionId,
|
|
5083
|
+
createdAt,
|
|
5084
|
+
deliberationEndsAt,
|
|
5085
|
+
voteStartAt,
|
|
5086
|
+
voteEndAt,
|
|
5087
|
+
timelockEndsAt,
|
|
5088
|
+
activeSeatsSnapshot,
|
|
5089
|
+
forVotes,
|
|
5090
|
+
againstVotes,
|
|
5091
|
+
abstainVotes,
|
|
5092
|
+
amount,
|
|
5093
|
+
snapshotAssetBalance,
|
|
5094
|
+
transferIntent,
|
|
5095
|
+
intentDeadline,
|
|
5096
|
+
intentMaxRiskTier,
|
|
5097
|
+
title,
|
|
5098
|
+
description
|
|
5099
|
+
};
|
|
5100
|
+
}
|
|
5101
|
+
function serializeProposal(proposal) {
|
|
5102
|
+
return {
|
|
5103
|
+
kind: asNum(proposal.kind),
|
|
5104
|
+
configRiskTier: asNum(proposal.configRiskTier),
|
|
5105
|
+
origin: asNum(proposal.origin),
|
|
5106
|
+
status: asNum(proposal.status),
|
|
5107
|
+
proposer: proposal.proposer,
|
|
5108
|
+
threadId: asNum(proposal.threadId),
|
|
5109
|
+
petitionId: asNum(proposal.petitionId),
|
|
5110
|
+
createdAt: asNum(proposal.createdAt),
|
|
5111
|
+
deliberationEndsAt: asNum(proposal.deliberationEndsAt),
|
|
5112
|
+
voteStartAt: asNum(proposal.voteStartAt),
|
|
5113
|
+
voteEndAt: asNum(proposal.voteEndAt),
|
|
5114
|
+
timelockEndsAt: asNum(proposal.timelockEndsAt),
|
|
5115
|
+
activeSeatsSnapshot: asNum(proposal.activeSeatsSnapshot),
|
|
5116
|
+
forVotes: proposal.forVotes.toString(),
|
|
5117
|
+
againstVotes: proposal.againstVotes.toString(),
|
|
5118
|
+
abstainVotes: proposal.abstainVotes.toString(),
|
|
5119
|
+
amount: proposal.amount.toString(),
|
|
5120
|
+
snapshotAssetBalance: proposal.snapshotAssetBalance.toString(),
|
|
5121
|
+
transferIntent: proposal.transferIntent,
|
|
5122
|
+
intentDeadline: asNum(proposal.intentDeadline),
|
|
5123
|
+
intentMaxRiskTier: asNum(proposal.intentMaxRiskTier),
|
|
5124
|
+
title: proposal.title,
|
|
5125
|
+
description: proposal.description
|
|
5126
|
+
};
|
|
5127
|
+
}
|
|
4780
5128
|
var governance = Cli3.create("governance", {
|
|
4781
|
-
description: "
|
|
5129
|
+
description: "Inspect Assembly governance proposals, votes, and parameters."
|
|
4782
5130
|
});
|
|
4783
5131
|
governance.command("proposals", {
|
|
5132
|
+
description: "List governance proposals with status and vote end time.",
|
|
4784
5133
|
env: env3,
|
|
5134
|
+
output: z3.array(
|
|
5135
|
+
z3.object({
|
|
5136
|
+
id: z3.number(),
|
|
5137
|
+
kind: z3.number(),
|
|
5138
|
+
status: z3.number(),
|
|
5139
|
+
title: z3.string().nullable().optional(),
|
|
5140
|
+
voteEndAt: z3.number(),
|
|
5141
|
+
voteEndRelative: z3.string()
|
|
5142
|
+
})
|
|
5143
|
+
),
|
|
5144
|
+
examples: [{ description: "List all proposals" }],
|
|
4785
5145
|
async run(c) {
|
|
4786
5146
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4787
5147
|
const count = await client.readContract({
|
|
@@ -4790,7 +5150,7 @@ governance.command("proposals", {
|
|
|
4790
5150
|
functionName: "proposalCount"
|
|
4791
5151
|
});
|
|
4792
5152
|
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
4793
|
-
const
|
|
5153
|
+
const proposalTuples = ids.length ? await client.multicall({
|
|
4794
5154
|
allowFailure: false,
|
|
4795
5155
|
contracts: ids.map((id) => ({
|
|
4796
5156
|
abi: governanceAbi,
|
|
@@ -4799,12 +5159,13 @@ governance.command("proposals", {
|
|
|
4799
5159
|
args: [id]
|
|
4800
5160
|
}))
|
|
4801
5161
|
}) : [];
|
|
5162
|
+
const proposals = proposalTuples.map(decodeProposal);
|
|
4802
5163
|
return c.ok(
|
|
4803
5164
|
proposals.map((p, i) => ({
|
|
4804
5165
|
id: i + 1,
|
|
4805
5166
|
kind: asNum(p.kind),
|
|
4806
5167
|
status: asNum(p.status),
|
|
4807
|
-
title: p.title,
|
|
5168
|
+
title: p.title ?? null,
|
|
4808
5169
|
voteEndAt: asNum(p.voteEndAt),
|
|
4809
5170
|
voteEndRelative: relTime(p.voteEndAt)
|
|
4810
5171
|
})),
|
|
@@ -4821,22 +5182,47 @@ governance.command("proposals", {
|
|
|
4821
5182
|
}
|
|
4822
5183
|
});
|
|
4823
5184
|
governance.command("proposal", {
|
|
4824
|
-
|
|
5185
|
+
description: "Get full raw proposal details by proposal id.",
|
|
5186
|
+
args: z3.object({
|
|
5187
|
+
id: z3.coerce.number().int().positive().describe("Proposal id (1-indexed)")
|
|
5188
|
+
}),
|
|
4825
5189
|
env: env3,
|
|
5190
|
+
output: z3.record(z3.string(), z3.unknown()),
|
|
5191
|
+
examples: [{ args: { id: 1 }, description: "Fetch proposal #1" }],
|
|
4826
5192
|
async run(c) {
|
|
4827
5193
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4828
|
-
const proposal =
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
5194
|
+
const proposal = decodeProposal(
|
|
5195
|
+
await client.readContract({
|
|
5196
|
+
abi: governanceAbi,
|
|
5197
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
5198
|
+
functionName: "proposals",
|
|
5199
|
+
args: [BigInt(c.args.id)]
|
|
5200
|
+
})
|
|
5201
|
+
);
|
|
5202
|
+
return c.ok(serializeProposal(proposal));
|
|
4835
5203
|
}
|
|
4836
5204
|
});
|
|
4837
5205
|
governance.command("has-voted", {
|
|
4838
|
-
|
|
5206
|
+
description: "Check if an address has voted on a proposal.",
|
|
5207
|
+
args: z3.object({
|
|
5208
|
+
proposalId: z3.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
|
|
5209
|
+
address: z3.string().describe("Voter address")
|
|
5210
|
+
}),
|
|
4839
5211
|
env: env3,
|
|
5212
|
+
output: z3.object({
|
|
5213
|
+
proposalId: z3.number(),
|
|
5214
|
+
address: z3.string(),
|
|
5215
|
+
hasVoted: z3.boolean()
|
|
5216
|
+
}),
|
|
5217
|
+
examples: [
|
|
5218
|
+
{
|
|
5219
|
+
args: {
|
|
5220
|
+
proposalId: 1,
|
|
5221
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
|
|
5222
|
+
},
|
|
5223
|
+
description: "Check whether an address already voted"
|
|
5224
|
+
}
|
|
5225
|
+
],
|
|
4840
5226
|
async run(c) {
|
|
4841
5227
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4842
5228
|
const hasVoted = await client.readContract({
|
|
@@ -4845,11 +5231,31 @@ governance.command("has-voted", {
|
|
|
4845
5231
|
functionName: "hasVoted",
|
|
4846
5232
|
args: [BigInt(c.args.proposalId), c.args.address]
|
|
4847
5233
|
});
|
|
4848
|
-
return c.ok({
|
|
5234
|
+
return c.ok({
|
|
5235
|
+
proposalId: c.args.proposalId,
|
|
5236
|
+
address: toChecksum(c.args.address),
|
|
5237
|
+
hasVoted
|
|
5238
|
+
});
|
|
4849
5239
|
}
|
|
4850
5240
|
});
|
|
4851
5241
|
governance.command("params", {
|
|
5242
|
+
description: "Read governance threshold and timing parameters.",
|
|
4852
5243
|
env: env3,
|
|
5244
|
+
output: z3.object({
|
|
5245
|
+
deliberationPeriod: z3.number(),
|
|
5246
|
+
votePeriod: z3.number(),
|
|
5247
|
+
quorumBps: z3.number(),
|
|
5248
|
+
constitutionalDeliberationPeriod: z3.number(),
|
|
5249
|
+
constitutionalVotePeriod: z3.number(),
|
|
5250
|
+
constitutionalPassBps: z3.number(),
|
|
5251
|
+
majorPassBps: z3.number(),
|
|
5252
|
+
parameterPassBps: z3.number(),
|
|
5253
|
+
significantPassBps: z3.number(),
|
|
5254
|
+
significantThresholdBps: z3.number(),
|
|
5255
|
+
routineThresholdBps: z3.number(),
|
|
5256
|
+
timelockPeriod: z3.number()
|
|
5257
|
+
}),
|
|
5258
|
+
examples: [{ description: "Inspect governance timing and pass thresholds" }],
|
|
4853
5259
|
async run(c) {
|
|
4854
5260
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4855
5261
|
const getters = [
|
|
@@ -4874,33 +5280,171 @@ governance.command("params", {
|
|
|
4874
5280
|
functionName: name
|
|
4875
5281
|
}))
|
|
4876
5282
|
});
|
|
4877
|
-
return c.ok(
|
|
5283
|
+
return c.ok({
|
|
5284
|
+
deliberationPeriod: asNum(values[0]),
|
|
5285
|
+
votePeriod: asNum(values[1]),
|
|
5286
|
+
quorumBps: asNum(values[2]),
|
|
5287
|
+
constitutionalDeliberationPeriod: asNum(values[3]),
|
|
5288
|
+
constitutionalVotePeriod: asNum(values[4]),
|
|
5289
|
+
constitutionalPassBps: asNum(values[5]),
|
|
5290
|
+
majorPassBps: asNum(values[6]),
|
|
5291
|
+
parameterPassBps: asNum(values[7]),
|
|
5292
|
+
significantPassBps: asNum(values[8]),
|
|
5293
|
+
significantThresholdBps: asNum(values[9]),
|
|
5294
|
+
routineThresholdBps: asNum(values[10]),
|
|
5295
|
+
timelockPeriod: asNum(values[11])
|
|
5296
|
+
});
|
|
4878
5297
|
}
|
|
4879
5298
|
});
|
|
4880
5299
|
|
|
4881
5300
|
// src/commands/members.ts
|
|
4882
5301
|
import { Cli as Cli4, z as z4 } from "incur";
|
|
5302
|
+
var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
|
|
5303
|
+
var REGISTERED_EVENT_SCAN_STEP = 100000n;
|
|
4883
5304
|
var env4 = z4.object({
|
|
4884
|
-
ABSTRACT_RPC_URL: z4.string().optional(),
|
|
4885
|
-
ASSEMBLY_INDEXER_URL: z4.string().optional()
|
|
5305
|
+
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override"),
|
|
5306
|
+
ASSEMBLY_INDEXER_URL: z4.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
|
|
4886
5307
|
});
|
|
5308
|
+
var memberSnapshotSchema = z4.array(z4.string());
|
|
5309
|
+
var AssemblyApiValidationError = class extends Error {
|
|
5310
|
+
constructor(details) {
|
|
5311
|
+
super("Assembly API response validation failed");
|
|
5312
|
+
this.details = details;
|
|
5313
|
+
this.name = "AssemblyApiValidationError";
|
|
5314
|
+
}
|
|
5315
|
+
};
|
|
5316
|
+
var AssemblyIndexerUnavailableError = class extends Error {
|
|
5317
|
+
constructor(details) {
|
|
5318
|
+
super("Assembly indexer unavailable");
|
|
5319
|
+
this.details = details;
|
|
5320
|
+
this.name = "AssemblyIndexerUnavailableError";
|
|
5321
|
+
}
|
|
5322
|
+
};
|
|
4887
5323
|
async function memberSnapshot(url) {
|
|
4888
|
-
|
|
4889
|
-
|
|
5324
|
+
let res;
|
|
5325
|
+
try {
|
|
5326
|
+
res = await fetch(url);
|
|
5327
|
+
} catch (error) {
|
|
5328
|
+
throw new AssemblyIndexerUnavailableError({
|
|
5329
|
+
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
5330
|
+
url,
|
|
5331
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
5332
|
+
});
|
|
5333
|
+
}
|
|
5334
|
+
if (!res.ok) {
|
|
5335
|
+
throw new AssemblyIndexerUnavailableError({
|
|
5336
|
+
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
5337
|
+
url,
|
|
5338
|
+
status: res.status,
|
|
5339
|
+
statusText: res.statusText
|
|
5340
|
+
});
|
|
5341
|
+
}
|
|
4890
5342
|
const json = await res.json();
|
|
4891
|
-
|
|
4892
|
-
|
|
5343
|
+
const parsed = memberSnapshotSchema.safeParse(json);
|
|
5344
|
+
if (parsed.success) {
|
|
5345
|
+
return parsed.data;
|
|
5346
|
+
}
|
|
5347
|
+
throw new AssemblyApiValidationError({
|
|
5348
|
+
code: "INVALID_ASSEMBLY_API_RESPONSE",
|
|
5349
|
+
url,
|
|
5350
|
+
issues: parsed.error.issues,
|
|
5351
|
+
response: json
|
|
5352
|
+
});
|
|
5353
|
+
}
|
|
5354
|
+
async function membersFromRegisteredEvents(client) {
|
|
5355
|
+
const latestBlock = await client.getBlockNumber();
|
|
5356
|
+
const addresses = /* @__PURE__ */ new Set();
|
|
5357
|
+
for (let fromBlock = 0n; fromBlock <= latestBlock; fromBlock += REGISTERED_EVENT_SCAN_STEP) {
|
|
5358
|
+
const toBlock = fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n > latestBlock ? latestBlock : fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n;
|
|
5359
|
+
const events = await client.getContractEvents({
|
|
5360
|
+
abi: registryAbi,
|
|
5361
|
+
address: ABSTRACT_MAINNET_ADDRESSES.registry,
|
|
5362
|
+
eventName: "Registered",
|
|
5363
|
+
fromBlock,
|
|
5364
|
+
toBlock,
|
|
5365
|
+
strict: true
|
|
5366
|
+
});
|
|
5367
|
+
for (const event of events) {
|
|
5368
|
+
const member = event.args.member;
|
|
5369
|
+
if (typeof member === "string") {
|
|
5370
|
+
addresses.add(member);
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
return [...addresses];
|
|
5375
|
+
}
|
|
5376
|
+
function indexerIssue(details) {
|
|
5377
|
+
if (typeof details.status === "number") {
|
|
5378
|
+
return `${details.status}${details.statusText ? ` ${details.statusText}` : ""}`;
|
|
5379
|
+
}
|
|
5380
|
+
if (details.reason) return details.reason;
|
|
5381
|
+
return "unknown error";
|
|
5382
|
+
}
|
|
5383
|
+
function emitIndexerFallbackWarning(details) {
|
|
5384
|
+
process.stderr.write(
|
|
5385
|
+
`${JSON.stringify({
|
|
5386
|
+
level: "warn",
|
|
5387
|
+
code: details.code,
|
|
5388
|
+
message: "Member snapshot indexer is unavailable. Falling back to on-chain Registered events.",
|
|
5389
|
+
url: details.url,
|
|
5390
|
+
issue: indexerIssue(details)
|
|
5391
|
+
})}
|
|
5392
|
+
`
|
|
5393
|
+
);
|
|
4893
5394
|
}
|
|
4894
5395
|
var members = Cli4.create("members", {
|
|
4895
|
-
description: "
|
|
5396
|
+
description: "Inspect Assembly membership and registry fee state."
|
|
4896
5397
|
});
|
|
4897
5398
|
members.command("list", {
|
|
4898
|
-
description: "List members from indexer snapshot
|
|
5399
|
+
description: "List members from an indexer snapshot (or Registered event fallback) plus on-chain active state.",
|
|
4899
5400
|
env: env4,
|
|
5401
|
+
output: z4.array(
|
|
5402
|
+
z4.object({
|
|
5403
|
+
address: z4.string(),
|
|
5404
|
+
active: z4.boolean(),
|
|
5405
|
+
registered: z4.boolean(),
|
|
5406
|
+
activeUntil: z4.number(),
|
|
5407
|
+
activeUntilRelative: z4.string(),
|
|
5408
|
+
lastHeartbeatAt: z4.number(),
|
|
5409
|
+
lastHeartbeatRelative: z4.string()
|
|
5410
|
+
})
|
|
5411
|
+
),
|
|
5412
|
+
examples: [
|
|
5413
|
+
{ description: "List members using default indexer snapshot" },
|
|
5414
|
+
{ description: "Override ASSEMBLY_INDEXER_URL to use a custom snapshot source" }
|
|
5415
|
+
],
|
|
4900
5416
|
async run(c) {
|
|
4901
5417
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4902
|
-
const snapshotUrl = c.env.ASSEMBLY_INDEXER_URL ??
|
|
4903
|
-
|
|
5418
|
+
const snapshotUrl = c.env.ASSEMBLY_INDEXER_URL ?? DEFAULT_MEMBER_SNAPSHOT_URL;
|
|
5419
|
+
let addresses;
|
|
5420
|
+
let fallbackReason;
|
|
5421
|
+
try {
|
|
5422
|
+
addresses = await memberSnapshot(snapshotUrl);
|
|
5423
|
+
} catch (error) {
|
|
5424
|
+
if (error instanceof AssemblyApiValidationError) {
|
|
5425
|
+
return c.error({
|
|
5426
|
+
code: error.details.code,
|
|
5427
|
+
message: `Member snapshot response failed validation. url=${error.details.url}; issues=${JSON.stringify(error.details.issues)}; response=${JSON.stringify(error.details.response)}`,
|
|
5428
|
+
retryable: false
|
|
5429
|
+
});
|
|
5430
|
+
}
|
|
5431
|
+
if (!(error instanceof AssemblyIndexerUnavailableError)) {
|
|
5432
|
+
throw error;
|
|
5433
|
+
}
|
|
5434
|
+
fallbackReason = error.details;
|
|
5435
|
+
try {
|
|
5436
|
+
addresses = await membersFromRegisteredEvents(client);
|
|
5437
|
+
} catch (fallbackError) {
|
|
5438
|
+
return c.error({
|
|
5439
|
+
code: "MEMBER_LIST_SOURCE_UNAVAILABLE",
|
|
5440
|
+
message: `Member indexer unavailable (${indexerIssue(error.details)} at ${error.details.url}) and on-chain Registered event fallback failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
|
|
5441
|
+
retryable: true
|
|
5442
|
+
});
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
if (fallbackReason) {
|
|
5446
|
+
emitIndexerFallbackWarning(fallbackReason);
|
|
5447
|
+
}
|
|
4904
5448
|
const calls = addresses.flatMap((address) => [
|
|
4905
5449
|
{
|
|
4906
5450
|
abi: registryAbi,
|
|
@@ -4931,16 +5475,32 @@ members.command("list", {
|
|
|
4931
5475
|
});
|
|
4932
5476
|
return c.ok(rows, {
|
|
4933
5477
|
cta: {
|
|
4934
|
-
description: "Inspect one member:",
|
|
5478
|
+
description: fallbackReason ? `Indexer unavailable (${indexerIssue(fallbackReason)}); using on-chain Registered event fallback. Inspect one member:` : "Inspect one member:",
|
|
4935
5479
|
commands: [{ command: "members info", args: { address: "<addr>" } }]
|
|
4936
5480
|
}
|
|
4937
5481
|
});
|
|
4938
5482
|
}
|
|
4939
5483
|
});
|
|
4940
5484
|
members.command("info", {
|
|
4941
|
-
description: "
|
|
4942
|
-
args: z4.object({
|
|
5485
|
+
description: "Get registry record and active status for a member address.",
|
|
5486
|
+
args: z4.object({
|
|
5487
|
+
address: z4.string().describe("Member wallet address")
|
|
5488
|
+
}),
|
|
4943
5489
|
env: env4,
|
|
5490
|
+
output: z4.object({
|
|
5491
|
+
address: z4.string(),
|
|
5492
|
+
active: z4.boolean(),
|
|
5493
|
+
activeUntil: z4.number(),
|
|
5494
|
+
lastHeartbeatAt: z4.number(),
|
|
5495
|
+
activeUntilRelative: z4.string(),
|
|
5496
|
+
lastHeartbeatRelative: z4.string()
|
|
5497
|
+
}),
|
|
5498
|
+
examples: [
|
|
5499
|
+
{
|
|
5500
|
+
args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
|
|
5501
|
+
description: "Inspect one member address"
|
|
5502
|
+
}
|
|
5503
|
+
],
|
|
4944
5504
|
async run(c) {
|
|
4945
5505
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4946
5506
|
const [member, active] = await Promise.all([
|
|
@@ -4960,15 +5520,21 @@ members.command("info", {
|
|
|
4960
5520
|
return c.ok({
|
|
4961
5521
|
address: toChecksum(c.args.address),
|
|
4962
5522
|
active,
|
|
4963
|
-
|
|
5523
|
+
activeUntil: Number(member.activeUntil),
|
|
5524
|
+
lastHeartbeatAt: Number(member.lastHeartbeatAt),
|
|
4964
5525
|
activeUntilRelative: relTime(member.activeUntil),
|
|
4965
5526
|
lastHeartbeatRelative: relTime(member.lastHeartbeatAt)
|
|
4966
5527
|
});
|
|
4967
5528
|
}
|
|
4968
5529
|
});
|
|
4969
5530
|
members.command("count", {
|
|
4970
|
-
description: "
|
|
5531
|
+
description: "Get active and total-known member counts from Registry.",
|
|
4971
5532
|
env: env4,
|
|
5533
|
+
output: z4.object({
|
|
5534
|
+
active: z4.number(),
|
|
5535
|
+
total: z4.number()
|
|
5536
|
+
}),
|
|
5537
|
+
examples: [{ description: "Count active and known members" }],
|
|
4972
5538
|
async run(c) {
|
|
4973
5539
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4974
5540
|
const [active, total] = await Promise.all([
|
|
@@ -4987,8 +5553,16 @@ members.command("count", {
|
|
|
4987
5553
|
}
|
|
4988
5554
|
});
|
|
4989
5555
|
members.command("fees", {
|
|
4990
|
-
description: "
|
|
5556
|
+
description: "Get registration and heartbeat fee settings.",
|
|
4991
5557
|
env: env4,
|
|
5558
|
+
output: z4.object({
|
|
5559
|
+
registrationFeeWei: z4.string(),
|
|
5560
|
+
registrationFee: z4.string(),
|
|
5561
|
+
heartbeatFeeWei: z4.string(),
|
|
5562
|
+
heartbeatFee: z4.string(),
|
|
5563
|
+
heartbeatGracePeriodSeconds: z4.number()
|
|
5564
|
+
}),
|
|
5565
|
+
examples: [{ description: "Inspect current registry fee configuration" }],
|
|
4992
5566
|
async run(c) {
|
|
4993
5567
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
4994
5568
|
const [registrationFee, heartbeatFee, heartbeatGracePeriod] = await Promise.all([
|
|
@@ -5020,10 +5594,21 @@ members.command("fees", {
|
|
|
5020
5594
|
|
|
5021
5595
|
// src/commands/treasury.ts
|
|
5022
5596
|
import { Cli as Cli5, z as z5 } from "incur";
|
|
5023
|
-
var env5 = z5.object({
|
|
5024
|
-
|
|
5597
|
+
var env5 = z5.object({
|
|
5598
|
+
ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
|
|
5599
|
+
});
|
|
5600
|
+
var treasury = Cli5.create("treasury", {
|
|
5601
|
+
description: "Inspect treasury balances, execution status, and spend controls."
|
|
5602
|
+
});
|
|
5025
5603
|
treasury.command("balance", {
|
|
5604
|
+
description: "Get current native token balance for the treasury contract.",
|
|
5026
5605
|
env: env5,
|
|
5606
|
+
output: z5.object({
|
|
5607
|
+
address: z5.string(),
|
|
5608
|
+
balanceWei: z5.string(),
|
|
5609
|
+
balance: z5.string()
|
|
5610
|
+
}),
|
|
5611
|
+
examples: [{ description: "Check treasury balance" }],
|
|
5027
5612
|
async run(c) {
|
|
5028
5613
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5029
5614
|
const balance = await client.getBalance({ address: ABSTRACT_MAINNET_ADDRESSES.treasury });
|
|
@@ -5035,8 +5620,21 @@ treasury.command("balance", {
|
|
|
5035
5620
|
}
|
|
5036
5621
|
});
|
|
5037
5622
|
treasury.command("whitelist", {
|
|
5038
|
-
|
|
5623
|
+
description: "Check whether an asset address is treasury-whitelisted.",
|
|
5624
|
+
args: z5.object({
|
|
5625
|
+
asset: z5.string().describe("Token/asset contract address")
|
|
5626
|
+
}),
|
|
5039
5627
|
env: env5,
|
|
5628
|
+
output: z5.object({
|
|
5629
|
+
asset: z5.string(),
|
|
5630
|
+
whitelisted: z5.boolean()
|
|
5631
|
+
}),
|
|
5632
|
+
examples: [
|
|
5633
|
+
{
|
|
5634
|
+
args: { asset: "0x0000000000000000000000000000000000000000" },
|
|
5635
|
+
description: "Check whitelist status for one asset"
|
|
5636
|
+
}
|
|
5637
|
+
],
|
|
5040
5638
|
async run(c) {
|
|
5041
5639
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5042
5640
|
const whitelisted = await client.readContract({
|
|
@@ -5049,7 +5647,15 @@ treasury.command("whitelist", {
|
|
|
5049
5647
|
}
|
|
5050
5648
|
});
|
|
5051
5649
|
treasury.command("major-spend-status", {
|
|
5650
|
+
description: "Read major-spend cooldown status for the treasury contract.",
|
|
5052
5651
|
env: env5,
|
|
5652
|
+
output: z5.object({
|
|
5653
|
+
majorSpendCooldownSeconds: z5.number(),
|
|
5654
|
+
lastMajorSpendAt: z5.number(),
|
|
5655
|
+
lastMajorSpendRelative: z5.string(),
|
|
5656
|
+
isMajorSpendAllowed: z5.boolean()
|
|
5657
|
+
}),
|
|
5658
|
+
examples: [{ description: "Inspect treasury major-spend guardrails" }],
|
|
5053
5659
|
async run(c) {
|
|
5054
5660
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5055
5661
|
const [cooldown, lastMajorSpendAt, allowed] = await Promise.all([
|
|
@@ -5080,8 +5686,16 @@ treasury.command("major-spend-status", {
|
|
|
5080
5686
|
}
|
|
5081
5687
|
});
|
|
5082
5688
|
treasury.command("executed", {
|
|
5083
|
-
|
|
5689
|
+
description: "Check whether a treasury action for a proposal has executed.",
|
|
5690
|
+
args: z5.object({
|
|
5691
|
+
proposalId: z5.coerce.number().int().positive().describe("Governance proposal id")
|
|
5692
|
+
}),
|
|
5084
5693
|
env: env5,
|
|
5694
|
+
output: z5.object({
|
|
5695
|
+
proposalId: z5.number(),
|
|
5696
|
+
executed: z5.boolean()
|
|
5697
|
+
}),
|
|
5698
|
+
examples: [{ args: { proposalId: 1 }, description: "Check execution status for proposal #1" }],
|
|
5085
5699
|
async run(c) {
|
|
5086
5700
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5087
5701
|
const executed = await client.readContract({
|
|
@@ -5103,10 +5717,21 @@ cli.command(council);
|
|
|
5103
5717
|
cli.command(forum);
|
|
5104
5718
|
cli.command(governance);
|
|
5105
5719
|
cli.command(treasury);
|
|
5106
|
-
var rootEnv = z6.object({
|
|
5720
|
+
var rootEnv = z6.object({
|
|
5721
|
+
ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
|
|
5722
|
+
});
|
|
5107
5723
|
cli.command("status", {
|
|
5108
|
-
description: "
|
|
5724
|
+
description: "Get a cross-contract Assembly snapshot (members, council, governance, treasury).",
|
|
5109
5725
|
env: rootEnv,
|
|
5726
|
+
output: z6.object({
|
|
5727
|
+
activeMemberCount: z6.number(),
|
|
5728
|
+
seatCount: z6.number(),
|
|
5729
|
+
proposalCount: z6.number(),
|
|
5730
|
+
currentAuctionDay: z6.number(),
|
|
5731
|
+
currentAuctionSlot: z6.number(),
|
|
5732
|
+
treasuryBalance: z6.string()
|
|
5733
|
+
}),
|
|
5734
|
+
examples: [{ description: "Fetch the current Assembly system status" }],
|
|
5110
5735
|
async run(c) {
|
|
5111
5736
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5112
5737
|
const [
|
|
@@ -5155,9 +5780,25 @@ cli.command("status", {
|
|
|
5155
5780
|
}
|
|
5156
5781
|
});
|
|
5157
5782
|
cli.command("health", {
|
|
5158
|
-
description: "
|
|
5159
|
-
args: z6.object({
|
|
5783
|
+
description: "Check cross-contract health for one address (membership, council, refunds, power).",
|
|
5784
|
+
args: z6.object({
|
|
5785
|
+
address: z6.string().describe("Member or wallet address to inspect")
|
|
5786
|
+
}),
|
|
5160
5787
|
env: rootEnv,
|
|
5788
|
+
output: z6.object({
|
|
5789
|
+
address: z6.string(),
|
|
5790
|
+
isActive: z6.boolean(),
|
|
5791
|
+
activeUntil: z6.number(),
|
|
5792
|
+
isCouncilMember: z6.boolean(),
|
|
5793
|
+
pendingReturnsWei: z6.string(),
|
|
5794
|
+
votingPower: z6.number()
|
|
5795
|
+
}),
|
|
5796
|
+
examples: [
|
|
5797
|
+
{
|
|
5798
|
+
args: { address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" },
|
|
5799
|
+
description: "Inspect one address across Assembly contracts"
|
|
5800
|
+
}
|
|
5801
|
+
],
|
|
5161
5802
|
async run(c) {
|
|
5162
5803
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5163
5804
|
const [isActive, member, isCouncilMember, pendingReturns, votingPower] = await Promise.all([
|
|
@@ -5193,7 +5834,7 @@ cli.command("health", {
|
|
|
5193
5834
|
})
|
|
5194
5835
|
]);
|
|
5195
5836
|
return c.ok({
|
|
5196
|
-
address: c.args.address,
|
|
5837
|
+
address: toChecksum(c.args.address),
|
|
5197
5838
|
isActive,
|
|
5198
5839
|
activeUntil: Number(member.activeUntil),
|
|
5199
5840
|
isCouncilMember,
|