@spectratools/assembly-cli 0.12.0 → 0.14.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 +1404 -788
- package/dist/index.js +1404 -788
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7,9 +7,9 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
import {
|
|
8
8
|
initTelemetry,
|
|
9
9
|
shutdownTelemetry,
|
|
10
|
-
withCommandSpan
|
|
10
|
+
withCommandSpan as withCommandSpan2
|
|
11
11
|
} from "@spectratools/cli-shared/telemetry";
|
|
12
|
-
import { Cli as
|
|
12
|
+
import { Cli as Cli7, z as z10 } from "incur";
|
|
13
13
|
|
|
14
14
|
// src/commands/_common.ts
|
|
15
15
|
import { checksumAddress, weiToEth } from "@spectratools/cli-shared";
|
|
@@ -4358,8 +4358,8 @@ var writeOptions = z.object({
|
|
|
4358
4358
|
"max-fee": z.string().optional().describe("Max fee per gas override in wei (EIP-1559)"),
|
|
4359
4359
|
nonce: z.number().optional().describe("Nonce override")
|
|
4360
4360
|
});
|
|
4361
|
-
function resolveAccount(
|
|
4362
|
-
const signer = createPrivateKeySigner(
|
|
4361
|
+
function resolveAccount(env7) {
|
|
4362
|
+
const signer = createPrivateKeySigner(env7.PRIVATE_KEY);
|
|
4363
4363
|
return signer.account;
|
|
4364
4364
|
}
|
|
4365
4365
|
function formatTxResult(result) {
|
|
@@ -4381,10 +4381,10 @@ function formatTxResult(result) {
|
|
|
4381
4381
|
};
|
|
4382
4382
|
}
|
|
4383
4383
|
async function assemblyWriteTx(opts) {
|
|
4384
|
-
const { env:
|
|
4385
|
-
const account = resolveAccount(
|
|
4386
|
-
const publicClient = createAssemblyPublicClient(
|
|
4387
|
-
const walletClient = createAssemblyWalletClient(account,
|
|
4384
|
+
const { env: env7, options, address, abi, functionName, args, value } = opts;
|
|
4385
|
+
const account = resolveAccount(env7);
|
|
4386
|
+
const publicClient = createAssemblyPublicClient(env7.ABSTRACT_RPC_URL);
|
|
4387
|
+
const walletClient = createAssemblyWalletClient(account, env7.ABSTRACT_RPC_URL);
|
|
4388
4388
|
const result = await executeTx({
|
|
4389
4389
|
publicClient,
|
|
4390
4390
|
walletClient,
|
|
@@ -4459,9 +4459,9 @@ council.command("seats", {
|
|
|
4459
4459
|
args: [id]
|
|
4460
4460
|
}))
|
|
4461
4461
|
}) : [];
|
|
4462
|
-
const
|
|
4462
|
+
const seats2 = seatTuples.map(decodeSeat);
|
|
4463
4463
|
return c.ok(
|
|
4464
|
-
|
|
4464
|
+
seats2.map((seat, idx) => ({
|
|
4465
4465
|
id: idx,
|
|
4466
4466
|
owner: toChecksum(seat.owner),
|
|
4467
4467
|
startAt: timeValue(seat.startAt, c.format),
|
|
@@ -4546,10 +4546,10 @@ council.command("members", {
|
|
|
4546
4546
|
args: [id]
|
|
4547
4547
|
}))
|
|
4548
4548
|
}) : [];
|
|
4549
|
-
const
|
|
4549
|
+
const seats2 = seatTuples.map(decodeSeat);
|
|
4550
4550
|
const activeOwners = [
|
|
4551
4551
|
...new Set(
|
|
4552
|
-
|
|
4552
|
+
seats2.filter((x) => !x.forfeited && asNum(x.endAt) > Math.floor(Date.now() / 1e3)).map((x) => x.owner)
|
|
4553
4553
|
)
|
|
4554
4554
|
];
|
|
4555
4555
|
const powers = activeOwners.length ? await client.multicall({
|
|
@@ -5246,9 +5246,9 @@ council.command("withdraw-refund", {
|
|
|
5246
5246
|
}
|
|
5247
5247
|
});
|
|
5248
5248
|
|
|
5249
|
-
// src/commands/
|
|
5250
|
-
import {
|
|
5251
|
-
import {
|
|
5249
|
+
// src/commands/digest.ts
|
|
5250
|
+
import { withCommandSpan } from "@spectratools/cli-shared/telemetry";
|
|
5251
|
+
import { z as z4 } from "incur";
|
|
5252
5252
|
|
|
5253
5253
|
// src/services/forum.ts
|
|
5254
5254
|
function decodeThread(value) {
|
|
@@ -5376,51 +5376,912 @@ async function fetchForumStats(client) {
|
|
|
5376
5376
|
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
5377
5377
|
functionName: "petitionCount"
|
|
5378
5378
|
}),
|
|
5379
|
-
client.readContract({
|
|
5380
|
-
abi: forumAbi,
|
|
5381
|
-
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
5382
|
-
functionName: "petitionThresholdBps"
|
|
5383
|
-
})
|
|
5384
|
-
]);
|
|
5385
|
-
return {
|
|
5386
|
-
threadCount: asNum(threadCount),
|
|
5387
|
-
commentCount: asNum(commentCount),
|
|
5388
|
-
petitionCount: asNum(petitionCount),
|
|
5389
|
-
petitionThresholdBps: asNum(petitionThresholdBps)
|
|
5390
|
-
};
|
|
5379
|
+
client.readContract({
|
|
5380
|
+
abi: forumAbi,
|
|
5381
|
+
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
5382
|
+
functionName: "petitionThresholdBps"
|
|
5383
|
+
})
|
|
5384
|
+
]);
|
|
5385
|
+
return {
|
|
5386
|
+
threadCount: asNum(threadCount),
|
|
5387
|
+
commentCount: asNum(commentCount),
|
|
5388
|
+
petitionCount: asNum(petitionCount),
|
|
5389
|
+
petitionThresholdBps: asNum(petitionThresholdBps)
|
|
5390
|
+
};
|
|
5391
|
+
}
|
|
5392
|
+
async function fetchHasSignedBatch(client, address, petitionIds) {
|
|
5393
|
+
if (petitionIds.length === 0) return /* @__PURE__ */ new Map();
|
|
5394
|
+
const results = await client.multicall({
|
|
5395
|
+
allowFailure: false,
|
|
5396
|
+
contracts: petitionIds.map((id) => ({
|
|
5397
|
+
abi: forumAbi,
|
|
5398
|
+
address: ABSTRACT_MAINNET_ADDRESSES.forum,
|
|
5399
|
+
functionName: "hasSignedPetition",
|
|
5400
|
+
args: [BigInt(id), address]
|
|
5401
|
+
}))
|
|
5402
|
+
});
|
|
5403
|
+
const map = /* @__PURE__ */ new Map();
|
|
5404
|
+
for (let i = 0; i < petitionIds.length; i++) {
|
|
5405
|
+
map.set(petitionIds[i], results[i]);
|
|
5406
|
+
}
|
|
5407
|
+
return map;
|
|
5408
|
+
}
|
|
5409
|
+
|
|
5410
|
+
// src/services/governance.ts
|
|
5411
|
+
var proposalStatusLabels = {
|
|
5412
|
+
0: "pending",
|
|
5413
|
+
1: "active",
|
|
5414
|
+
2: "passed",
|
|
5415
|
+
3: "executed",
|
|
5416
|
+
4: "defeated",
|
|
5417
|
+
5: "cancelled"
|
|
5418
|
+
};
|
|
5419
|
+
function proposalStatus(status) {
|
|
5420
|
+
const statusCode = asNum(status);
|
|
5421
|
+
return {
|
|
5422
|
+
status: proposalStatusLabels[statusCode] ?? `unknown-${statusCode}`,
|
|
5423
|
+
statusCode
|
|
5424
|
+
};
|
|
5425
|
+
}
|
|
5426
|
+
function decodeProposal(value) {
|
|
5427
|
+
const [
|
|
5428
|
+
kind,
|
|
5429
|
+
configRiskTier,
|
|
5430
|
+
origin,
|
|
5431
|
+
status,
|
|
5432
|
+
proposer,
|
|
5433
|
+
threadId,
|
|
5434
|
+
petitionId,
|
|
5435
|
+
createdAt,
|
|
5436
|
+
deliberationEndsAt,
|
|
5437
|
+
voteStartAt,
|
|
5438
|
+
voteEndAt,
|
|
5439
|
+
timelockEndsAt,
|
|
5440
|
+
activeSeatsSnapshot,
|
|
5441
|
+
forVotes,
|
|
5442
|
+
againstVotes,
|
|
5443
|
+
abstainVotes,
|
|
5444
|
+
amount,
|
|
5445
|
+
snapshotAssetBalance,
|
|
5446
|
+
transferIntent,
|
|
5447
|
+
intentDeadline,
|
|
5448
|
+
intentMaxRiskTier,
|
|
5449
|
+
title,
|
|
5450
|
+
description
|
|
5451
|
+
] = value;
|
|
5452
|
+
return {
|
|
5453
|
+
kind,
|
|
5454
|
+
configRiskTier,
|
|
5455
|
+
origin,
|
|
5456
|
+
status,
|
|
5457
|
+
proposer: toChecksum(proposer),
|
|
5458
|
+
threadId,
|
|
5459
|
+
petitionId,
|
|
5460
|
+
createdAt,
|
|
5461
|
+
deliberationEndsAt,
|
|
5462
|
+
voteStartAt,
|
|
5463
|
+
voteEndAt,
|
|
5464
|
+
timelockEndsAt,
|
|
5465
|
+
activeSeatsSnapshot,
|
|
5466
|
+
forVotes,
|
|
5467
|
+
againstVotes,
|
|
5468
|
+
abstainVotes,
|
|
5469
|
+
amount,
|
|
5470
|
+
snapshotAssetBalance,
|
|
5471
|
+
transferIntent,
|
|
5472
|
+
intentDeadline,
|
|
5473
|
+
intentMaxRiskTier,
|
|
5474
|
+
title,
|
|
5475
|
+
description
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
function serializeProposal(proposal) {
|
|
5479
|
+
const status = proposalStatus(proposal.status);
|
|
5480
|
+
return {
|
|
5481
|
+
kind: asNum(proposal.kind),
|
|
5482
|
+
configRiskTier: asNum(proposal.configRiskTier),
|
|
5483
|
+
origin: asNum(proposal.origin),
|
|
5484
|
+
status: status.status,
|
|
5485
|
+
statusCode: status.statusCode,
|
|
5486
|
+
proposer: proposal.proposer,
|
|
5487
|
+
threadId: asNum(proposal.threadId),
|
|
5488
|
+
petitionId: asNum(proposal.petitionId),
|
|
5489
|
+
createdAt: asNum(proposal.createdAt),
|
|
5490
|
+
deliberationEndsAt: asNum(proposal.deliberationEndsAt),
|
|
5491
|
+
voteStartAt: asNum(proposal.voteStartAt),
|
|
5492
|
+
voteEndAt: asNum(proposal.voteEndAt),
|
|
5493
|
+
timelockEndsAt: asNum(proposal.timelockEndsAt),
|
|
5494
|
+
activeSeatsSnapshot: asNum(proposal.activeSeatsSnapshot),
|
|
5495
|
+
forVotes: proposal.forVotes.toString(),
|
|
5496
|
+
againstVotes: proposal.againstVotes.toString(),
|
|
5497
|
+
abstainVotes: proposal.abstainVotes.toString(),
|
|
5498
|
+
amount: proposal.amount.toString(),
|
|
5499
|
+
snapshotAssetBalance: proposal.snapshotAssetBalance.toString(),
|
|
5500
|
+
transferIntent: proposal.transferIntent,
|
|
5501
|
+
intentDeadline: asNum(proposal.intentDeadline),
|
|
5502
|
+
intentMaxRiskTier: asNum(proposal.intentMaxRiskTier),
|
|
5503
|
+
title: proposal.title,
|
|
5504
|
+
description: proposal.description
|
|
5505
|
+
};
|
|
5506
|
+
}
|
|
5507
|
+
async function fetchProposalCount(client) {
|
|
5508
|
+
return await client.readContract({
|
|
5509
|
+
abi: governanceAbi,
|
|
5510
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
5511
|
+
functionName: "proposalCount"
|
|
5512
|
+
});
|
|
5513
|
+
}
|
|
5514
|
+
async function fetchProposalById(client, id) {
|
|
5515
|
+
return decodeProposal(
|
|
5516
|
+
await client.readContract({
|
|
5517
|
+
abi: governanceAbi,
|
|
5518
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
5519
|
+
functionName: "proposals",
|
|
5520
|
+
args: [BigInt(id)]
|
|
5521
|
+
})
|
|
5522
|
+
);
|
|
5523
|
+
}
|
|
5524
|
+
async function fetchAllProposals(client) {
|
|
5525
|
+
const count = await fetchProposalCount(client);
|
|
5526
|
+
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
5527
|
+
if (ids.length === 0) return [];
|
|
5528
|
+
const proposalTuples = await client.multicall({
|
|
5529
|
+
allowFailure: false,
|
|
5530
|
+
contracts: ids.map((id) => ({
|
|
5531
|
+
abi: governanceAbi,
|
|
5532
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
5533
|
+
functionName: "proposals",
|
|
5534
|
+
args: [id]
|
|
5535
|
+
}))
|
|
5536
|
+
});
|
|
5537
|
+
return proposalTuples.map(decodeProposal);
|
|
5538
|
+
}
|
|
5539
|
+
async function fetchHasVotedBatch(client, address, proposalIds) {
|
|
5540
|
+
if (proposalIds.length === 0) return /* @__PURE__ */ new Map();
|
|
5541
|
+
const results = await client.multicall({
|
|
5542
|
+
allowFailure: false,
|
|
5543
|
+
contracts: proposalIds.map((id) => ({
|
|
5544
|
+
abi: governanceAbi,
|
|
5545
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
5546
|
+
functionName: "hasVoted",
|
|
5547
|
+
args: [BigInt(id), address]
|
|
5548
|
+
}))
|
|
5549
|
+
});
|
|
5550
|
+
const map = /* @__PURE__ */ new Map();
|
|
5551
|
+
for (let i = 0; i < proposalIds.length; i++) {
|
|
5552
|
+
map.set(proposalIds[i], results[i]);
|
|
5553
|
+
}
|
|
5554
|
+
return map;
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
// src/services/members.ts
|
|
5558
|
+
import { z as z3 } from "incur";
|
|
5559
|
+
var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
|
|
5560
|
+
var REGISTERED_EVENT_SCAN_STEP = 100000n;
|
|
5561
|
+
var REGISTERED_EVENT_SCAN_TIMEOUT_MS = 2e4;
|
|
5562
|
+
var memberSnapshotEntrySchema = z3.union([
|
|
5563
|
+
z3.string(),
|
|
5564
|
+
z3.object({
|
|
5565
|
+
address: z3.string(),
|
|
5566
|
+
ens: z3.string().optional(),
|
|
5567
|
+
name: z3.string().optional()
|
|
5568
|
+
})
|
|
5569
|
+
]);
|
|
5570
|
+
var memberSnapshotSchema = z3.array(memberSnapshotEntrySchema);
|
|
5571
|
+
var AssemblyApiValidationError = class extends Error {
|
|
5572
|
+
constructor(details) {
|
|
5573
|
+
super("Assembly API response validation failed");
|
|
5574
|
+
this.details = details;
|
|
5575
|
+
this.name = "AssemblyApiValidationError";
|
|
5576
|
+
}
|
|
5577
|
+
};
|
|
5578
|
+
var AssemblyIndexerUnavailableError = class extends Error {
|
|
5579
|
+
constructor(details) {
|
|
5580
|
+
super("Assembly indexer unavailable");
|
|
5581
|
+
this.details = details;
|
|
5582
|
+
this.name = "AssemblyIndexerUnavailableError";
|
|
5583
|
+
}
|
|
5584
|
+
};
|
|
5585
|
+
function memberSnapshotEntryToIdentity(entry) {
|
|
5586
|
+
if (typeof entry === "string") return { address: entry };
|
|
5587
|
+
const identity = { address: entry.address };
|
|
5588
|
+
if (entry.ens !== void 0) identity.ens = entry.ens;
|
|
5589
|
+
if (entry.name !== void 0) identity.name = entry.name;
|
|
5590
|
+
return identity;
|
|
5591
|
+
}
|
|
5592
|
+
function mergeMemberIdentities(entries) {
|
|
5593
|
+
const byAddress = /* @__PURE__ */ new Map();
|
|
5594
|
+
for (const entry of entries) {
|
|
5595
|
+
const key = entry.address.toLowerCase();
|
|
5596
|
+
const existing = byAddress.get(key);
|
|
5597
|
+
if (!existing) {
|
|
5598
|
+
byAddress.set(key, entry);
|
|
5599
|
+
continue;
|
|
5600
|
+
}
|
|
5601
|
+
const merged = { address: existing.address };
|
|
5602
|
+
const ens = existing.ens ?? entry.ens;
|
|
5603
|
+
const name = existing.name ?? entry.name;
|
|
5604
|
+
if (ens !== void 0) merged.ens = ens;
|
|
5605
|
+
if (name !== void 0) merged.name = name;
|
|
5606
|
+
byAddress.set(key, merged);
|
|
5607
|
+
}
|
|
5608
|
+
return [...byAddress.values()];
|
|
5609
|
+
}
|
|
5610
|
+
async function memberSnapshot(url) {
|
|
5611
|
+
let res;
|
|
5612
|
+
try {
|
|
5613
|
+
res = await fetch(url);
|
|
5614
|
+
} catch (error) {
|
|
5615
|
+
throw new AssemblyIndexerUnavailableError({
|
|
5616
|
+
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
5617
|
+
url,
|
|
5618
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
5619
|
+
});
|
|
5620
|
+
}
|
|
5621
|
+
if (!res.ok) {
|
|
5622
|
+
throw new AssemblyIndexerUnavailableError({
|
|
5623
|
+
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
5624
|
+
url,
|
|
5625
|
+
status: res.status,
|
|
5626
|
+
statusText: res.statusText
|
|
5627
|
+
});
|
|
5628
|
+
}
|
|
5629
|
+
const json = await res.json();
|
|
5630
|
+
const parsed = memberSnapshotSchema.safeParse(json);
|
|
5631
|
+
if (parsed.success) {
|
|
5632
|
+
return mergeMemberIdentities(parsed.data.map(memberSnapshotEntryToIdentity));
|
|
5633
|
+
}
|
|
5634
|
+
throw new AssemblyApiValidationError({
|
|
5635
|
+
code: "INVALID_ASSEMBLY_API_RESPONSE",
|
|
5636
|
+
url,
|
|
5637
|
+
issues: parsed.error.issues,
|
|
5638
|
+
response: json
|
|
5639
|
+
});
|
|
5640
|
+
}
|
|
5641
|
+
async function withTimeout(promise, timeoutMs, timeoutMessage) {
|
|
5642
|
+
let timer;
|
|
5643
|
+
try {
|
|
5644
|
+
return await Promise.race([
|
|
5645
|
+
promise,
|
|
5646
|
+
new Promise((_, reject) => {
|
|
5647
|
+
timer = setTimeout(() => {
|
|
5648
|
+
reject(new Error(timeoutMessage));
|
|
5649
|
+
}, timeoutMs);
|
|
5650
|
+
})
|
|
5651
|
+
]);
|
|
5652
|
+
} finally {
|
|
5653
|
+
if (timer) clearTimeout(timer);
|
|
5654
|
+
}
|
|
5655
|
+
}
|
|
5656
|
+
async function membersFromRegisteredEvents(client) {
|
|
5657
|
+
const latestBlock = await client.getBlockNumber();
|
|
5658
|
+
const addresses = /* @__PURE__ */ new Set();
|
|
5659
|
+
for (let fromBlock = ABSTRACT_MAINNET_DEPLOYMENT_BLOCKS.registry; fromBlock <= latestBlock; fromBlock += REGISTERED_EVENT_SCAN_STEP) {
|
|
5660
|
+
const toBlock = fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n > latestBlock ? latestBlock : fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n;
|
|
5661
|
+
const events = await client.getContractEvents({
|
|
5662
|
+
abi: registryAbi,
|
|
5663
|
+
address: ABSTRACT_MAINNET_ADDRESSES.registry,
|
|
5664
|
+
eventName: "Registered",
|
|
5665
|
+
fromBlock,
|
|
5666
|
+
toBlock,
|
|
5667
|
+
strict: true
|
|
5668
|
+
});
|
|
5669
|
+
for (const event of events) {
|
|
5670
|
+
const member = event.args.member;
|
|
5671
|
+
if (typeof member === "string") {
|
|
5672
|
+
addresses.add(member);
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
return [...addresses].map((address) => ({ address }));
|
|
5677
|
+
}
|
|
5678
|
+
async function fetchMemberList(client, snapshotUrl) {
|
|
5679
|
+
const url = snapshotUrl ?? DEFAULT_MEMBER_SNAPSHOT_URL;
|
|
5680
|
+
try {
|
|
5681
|
+
return { members: await memberSnapshot(url) };
|
|
5682
|
+
} catch (error) {
|
|
5683
|
+
if (error instanceof AssemblyApiValidationError) {
|
|
5684
|
+
throw error;
|
|
5685
|
+
}
|
|
5686
|
+
if (!(error instanceof AssemblyIndexerUnavailableError)) {
|
|
5687
|
+
throw error;
|
|
5688
|
+
}
|
|
5689
|
+
const fallbackMembers = await withTimeout(
|
|
5690
|
+
membersFromRegisteredEvents(client),
|
|
5691
|
+
REGISTERED_EVENT_SCAN_TIMEOUT_MS,
|
|
5692
|
+
`Registered event fallback scan timed out after ${REGISTERED_EVENT_SCAN_TIMEOUT_MS}ms`
|
|
5693
|
+
);
|
|
5694
|
+
return {
|
|
5695
|
+
members: mergeMemberIdentities(fallbackMembers),
|
|
5696
|
+
fallbackReason: error.details
|
|
5697
|
+
};
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
async function fetchMemberOnchainState(client, addresses) {
|
|
5701
|
+
if (addresses.length === 0) return [];
|
|
5702
|
+
const calls = addresses.flatMap((address) => [
|
|
5703
|
+
{
|
|
5704
|
+
abi: registryAbi,
|
|
5705
|
+
address: ABSTRACT_MAINNET_ADDRESSES.registry,
|
|
5706
|
+
functionName: "isActive",
|
|
5707
|
+
args: [address]
|
|
5708
|
+
},
|
|
5709
|
+
{
|
|
5710
|
+
abi: registryAbi,
|
|
5711
|
+
address: ABSTRACT_MAINNET_ADDRESSES.registry,
|
|
5712
|
+
functionName: "members",
|
|
5713
|
+
args: [address]
|
|
5714
|
+
}
|
|
5715
|
+
]);
|
|
5716
|
+
const values = await client.multicall({ allowFailure: false, contracts: calls });
|
|
5717
|
+
return addresses.map((address, i) => {
|
|
5718
|
+
const active = values[i * 2];
|
|
5719
|
+
const info = values[i * 2 + 1];
|
|
5720
|
+
return {
|
|
5721
|
+
address: toChecksum(address),
|
|
5722
|
+
active,
|
|
5723
|
+
registered: info.registered,
|
|
5724
|
+
activeUntil: info.activeUntil,
|
|
5725
|
+
lastHeartbeatAt: info.lastHeartbeatAt
|
|
5726
|
+
};
|
|
5727
|
+
});
|
|
5728
|
+
}
|
|
5729
|
+
|
|
5730
|
+
// src/commands/digest.ts
|
|
5731
|
+
var digestEnv = z4.object({
|
|
5732
|
+
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override"),
|
|
5733
|
+
ASSEMBLY_INDEXER_URL: z4.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
|
|
5734
|
+
});
|
|
5735
|
+
var memberItemSchema = z4.object({
|
|
5736
|
+
address: z4.string(),
|
|
5737
|
+
active: z4.boolean(),
|
|
5738
|
+
registered: z4.boolean(),
|
|
5739
|
+
activeUntil: z4.string(),
|
|
5740
|
+
lastHeartbeatAt: z4.string()
|
|
5741
|
+
});
|
|
5742
|
+
var proposalDigestSchema = z4.object({
|
|
5743
|
+
id: z4.number(),
|
|
5744
|
+
kind: z4.number(),
|
|
5745
|
+
configRiskTier: z4.number(),
|
|
5746
|
+
origin: z4.number(),
|
|
5747
|
+
status: z4.string(),
|
|
5748
|
+
statusCode: z4.number(),
|
|
5749
|
+
proposer: z4.string(),
|
|
5750
|
+
threadId: z4.number(),
|
|
5751
|
+
petitionId: z4.number(),
|
|
5752
|
+
createdAt: z4.number(),
|
|
5753
|
+
deliberationEndsAt: z4.number(),
|
|
5754
|
+
voteStartAt: z4.number(),
|
|
5755
|
+
voteEndAt: z4.number(),
|
|
5756
|
+
timelockEndsAt: z4.number(),
|
|
5757
|
+
activeSeatsSnapshot: z4.number(),
|
|
5758
|
+
forVotes: z4.string(),
|
|
5759
|
+
againstVotes: z4.string(),
|
|
5760
|
+
abstainVotes: z4.string(),
|
|
5761
|
+
amount: z4.string(),
|
|
5762
|
+
snapshotAssetBalance: z4.string(),
|
|
5763
|
+
transferIntent: z4.boolean(),
|
|
5764
|
+
intentDeadline: z4.number(),
|
|
5765
|
+
intentMaxRiskTier: z4.number(),
|
|
5766
|
+
title: z4.string(),
|
|
5767
|
+
description: z4.string(),
|
|
5768
|
+
hasVoted: z4.boolean().optional()
|
|
5769
|
+
});
|
|
5770
|
+
var threadDigestSchema = z4.object({
|
|
5771
|
+
id: z4.number(),
|
|
5772
|
+
kind: z4.number(),
|
|
5773
|
+
author: z4.string(),
|
|
5774
|
+
createdAt: z4.number(),
|
|
5775
|
+
category: z4.string(),
|
|
5776
|
+
title: z4.string(),
|
|
5777
|
+
proposalId: z4.number(),
|
|
5778
|
+
petitionId: z4.number()
|
|
5779
|
+
});
|
|
5780
|
+
var commentDigestSchema = z4.object({
|
|
5781
|
+
id: z4.number(),
|
|
5782
|
+
threadId: z4.number(),
|
|
5783
|
+
parentId: z4.number(),
|
|
5784
|
+
author: z4.string(),
|
|
5785
|
+
createdAt: z4.number(),
|
|
5786
|
+
body: z4.string()
|
|
5787
|
+
});
|
|
5788
|
+
var petitionDigestSchema = z4.object({
|
|
5789
|
+
id: z4.number(),
|
|
5790
|
+
proposer: z4.string(),
|
|
5791
|
+
createdAt: z4.number(),
|
|
5792
|
+
category: z4.string(),
|
|
5793
|
+
title: z4.string(),
|
|
5794
|
+
body: z4.string(),
|
|
5795
|
+
signatures: z4.number(),
|
|
5796
|
+
promoted: z4.boolean(),
|
|
5797
|
+
threadId: z4.number(),
|
|
5798
|
+
hasSigned: z4.boolean().optional()
|
|
5799
|
+
});
|
|
5800
|
+
var proposalSummarySchema = z4.object({
|
|
5801
|
+
id: z4.number(),
|
|
5802
|
+
title: z4.string(),
|
|
5803
|
+
status: z4.string(),
|
|
5804
|
+
statusCode: z4.number(),
|
|
5805
|
+
createdAt: z4.number(),
|
|
5806
|
+
hasVoted: z4.boolean().optional()
|
|
5807
|
+
});
|
|
5808
|
+
var threadSummarySchema = z4.object({
|
|
5809
|
+
id: z4.number(),
|
|
5810
|
+
title: z4.string(),
|
|
5811
|
+
category: z4.string(),
|
|
5812
|
+
createdAt: z4.number()
|
|
5813
|
+
});
|
|
5814
|
+
var commentSummarySchema = z4.object({
|
|
5815
|
+
id: z4.number(),
|
|
5816
|
+
threadId: z4.number(),
|
|
5817
|
+
author: z4.string(),
|
|
5818
|
+
createdAt: z4.number()
|
|
5819
|
+
});
|
|
5820
|
+
var petitionSummarySchema = z4.object({
|
|
5821
|
+
id: z4.number(),
|
|
5822
|
+
title: z4.string(),
|
|
5823
|
+
category: z4.string(),
|
|
5824
|
+
signatures: z4.number(),
|
|
5825
|
+
promoted: z4.boolean(),
|
|
5826
|
+
createdAt: z4.number(),
|
|
5827
|
+
hasSigned: z4.boolean().optional()
|
|
5828
|
+
});
|
|
5829
|
+
var filtersMetaSchema = z4.object({
|
|
5830
|
+
since: z4.string().optional(),
|
|
5831
|
+
until: z4.string().optional(),
|
|
5832
|
+
omitComments: z4.boolean().optional(),
|
|
5833
|
+
omitMembers: z4.boolean().optional(),
|
|
5834
|
+
omitPetitions: z4.boolean().optional(),
|
|
5835
|
+
proposalsLimit: z4.number().optional(),
|
|
5836
|
+
threadsLimit: z4.number().optional(),
|
|
5837
|
+
commentsLimit: z4.number().optional(),
|
|
5838
|
+
petitionsLimit: z4.number().optional(),
|
|
5839
|
+
summaryOnly: z4.boolean().optional(),
|
|
5840
|
+
proposalStatus: z4.string().optional()
|
|
5841
|
+
});
|
|
5842
|
+
var digestOutputSchema = z4.object({
|
|
5843
|
+
meta: z4.object({
|
|
5844
|
+
chainId: z4.number(),
|
|
5845
|
+
fetchedAt: z4.string(),
|
|
5846
|
+
address: z4.string().optional(),
|
|
5847
|
+
filters: filtersMetaSchema.optional()
|
|
5848
|
+
}),
|
|
5849
|
+
proposals: z4.array(z4.union([proposalDigestSchema, proposalSummarySchema])),
|
|
5850
|
+
threads: z4.array(z4.union([threadDigestSchema, threadSummarySchema])),
|
|
5851
|
+
comments: z4.array(z4.union([commentDigestSchema, commentSummarySchema])).optional(),
|
|
5852
|
+
petitions: z4.array(z4.union([petitionDigestSchema, petitionSummarySchema])).optional(),
|
|
5853
|
+
members: z4.object({
|
|
5854
|
+
count: z4.number(),
|
|
5855
|
+
items: z4.array(memberItemSchema)
|
|
5856
|
+
}).optional(),
|
|
5857
|
+
errors: z4.array(z4.string())
|
|
5858
|
+
});
|
|
5859
|
+
function parseDuration(value) {
|
|
5860
|
+
const match = value.match(/^(\d+(?:\.\d+)?)\s*(m|h|d)$/i);
|
|
5861
|
+
if (!match) return null;
|
|
5862
|
+
const amount = Number.parseFloat(match[1]);
|
|
5863
|
+
const unit = match[2].toLowerCase();
|
|
5864
|
+
switch (unit) {
|
|
5865
|
+
case "m":
|
|
5866
|
+
return amount * 60 * 1e3;
|
|
5867
|
+
case "h":
|
|
5868
|
+
return amount * 3600 * 1e3;
|
|
5869
|
+
case "d":
|
|
5870
|
+
return amount * 86400 * 1e3;
|
|
5871
|
+
default:
|
|
5872
|
+
return null;
|
|
5873
|
+
}
|
|
5874
|
+
}
|
|
5875
|
+
var validProposalStatuses = new Set(Object.values(proposalStatusLabels));
|
|
5876
|
+
function registerDigestCommand(cli2) {
|
|
5877
|
+
cli2.command("digest", {
|
|
5878
|
+
description: "Aggregate proposals, threads, comments, petitions, and members into a single governance snapshot.",
|
|
5879
|
+
options: z4.object({
|
|
5880
|
+
address: z4.string().optional().describe("Wallet address to enrich proposals (hasVoted) and petitions (hasSigned)"),
|
|
5881
|
+
since: z4.string().optional().describe("Only items created/updated after this ISO-8601 timestamp"),
|
|
5882
|
+
last: z4.string().optional().describe("Duration shorthand (e.g. 24h, 7d, 30m) \u2014 converted to --since"),
|
|
5883
|
+
until: z4.string().optional().describe("Only items created/updated before this ISO-8601 timestamp"),
|
|
5884
|
+
"omit-comments": z4.boolean().optional().describe("Exclude comments from output"),
|
|
5885
|
+
"omit-members": z4.boolean().optional().describe("Exclude members from output"),
|
|
5886
|
+
"omit-petitions": z4.boolean().optional().describe("Exclude petitions from output"),
|
|
5887
|
+
"proposals-limit": z4.number().optional().describe("Return only the most recent N proposals"),
|
|
5888
|
+
"threads-limit": z4.number().optional().describe("Return only the most recent N threads"),
|
|
5889
|
+
"comments-limit": z4.number().optional().describe("Return only the most recent N comments"),
|
|
5890
|
+
"petitions-limit": z4.number().optional().describe("Return only the most recent N petitions"),
|
|
5891
|
+
"summary-only": z4.boolean().optional().describe("Return only counts/metadata per section (no full bodies)"),
|
|
5892
|
+
"proposal-status": z4.string().optional().describe("Filter proposals by status (pending/active/passed/executed/defeated/cancelled)")
|
|
5893
|
+
}),
|
|
5894
|
+
env: digestEnv,
|
|
5895
|
+
output: digestOutputSchema,
|
|
5896
|
+
examples: [
|
|
5897
|
+
{ description: "Fetch a full governance digest" },
|
|
5898
|
+
{
|
|
5899
|
+
options: { address: "0x230Ccc765765d729fFb1897D538f773b92005Aa2" },
|
|
5900
|
+
description: "Fetch digest with wallet-relative enrichment"
|
|
5901
|
+
},
|
|
5902
|
+
{
|
|
5903
|
+
options: { last: "24h" },
|
|
5904
|
+
description: "Fetch digest for the last 24 hours"
|
|
5905
|
+
},
|
|
5906
|
+
{
|
|
5907
|
+
options: { "summary-only": true },
|
|
5908
|
+
description: "Fetch digest with only summary metadata"
|
|
5909
|
+
},
|
|
5910
|
+
{
|
|
5911
|
+
options: { "proposal-status": "active", "omit-comments": true },
|
|
5912
|
+
description: "Fetch only active proposals, omitting comments"
|
|
5913
|
+
}
|
|
5914
|
+
],
|
|
5915
|
+
async run(c) {
|
|
5916
|
+
return withCommandSpan("assembly digest", { address: c.options.address }, async () => {
|
|
5917
|
+
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
5918
|
+
const errors = [];
|
|
5919
|
+
const address = c.options.address ? toChecksum(c.options.address) : void 0;
|
|
5920
|
+
let sinceTs;
|
|
5921
|
+
let untilTs;
|
|
5922
|
+
if (c.options.last && c.options.since) {
|
|
5923
|
+
return c.error({
|
|
5924
|
+
code: "INVALID_OPTIONS",
|
|
5925
|
+
message: "Cannot specify both --since and --last",
|
|
5926
|
+
retryable: false
|
|
5927
|
+
});
|
|
5928
|
+
}
|
|
5929
|
+
if (c.options.last) {
|
|
5930
|
+
const durationMs = parseDuration(c.options.last);
|
|
5931
|
+
if (durationMs === null) {
|
|
5932
|
+
return c.error({
|
|
5933
|
+
code: "INVALID_DURATION",
|
|
5934
|
+
message: `Invalid duration format: "${c.options.last}". Use e.g. 24h, 7d, 30m`,
|
|
5935
|
+
retryable: false
|
|
5936
|
+
});
|
|
5937
|
+
}
|
|
5938
|
+
sinceTs = Math.floor((Date.now() - durationMs) / 1e3);
|
|
5939
|
+
} else if (c.options.since) {
|
|
5940
|
+
const parsed = Date.parse(c.options.since);
|
|
5941
|
+
if (Number.isNaN(parsed)) {
|
|
5942
|
+
return c.error({
|
|
5943
|
+
code: "INVALID_TIMESTAMP",
|
|
5944
|
+
message: `Invalid --since timestamp: "${c.options.since}"`,
|
|
5945
|
+
retryable: false
|
|
5946
|
+
});
|
|
5947
|
+
}
|
|
5948
|
+
sinceTs = Math.floor(parsed / 1e3);
|
|
5949
|
+
}
|
|
5950
|
+
if (c.options.until) {
|
|
5951
|
+
const parsed = Date.parse(c.options.until);
|
|
5952
|
+
if (Number.isNaN(parsed)) {
|
|
5953
|
+
return c.error({
|
|
5954
|
+
code: "INVALID_TIMESTAMP",
|
|
5955
|
+
message: `Invalid --until timestamp: "${c.options.until}"`,
|
|
5956
|
+
retryable: false
|
|
5957
|
+
});
|
|
5958
|
+
}
|
|
5959
|
+
untilTs = Math.floor(parsed / 1e3);
|
|
5960
|
+
}
|
|
5961
|
+
const proposalStatusFilter = c.options["proposal-status"];
|
|
5962
|
+
if (proposalStatusFilter && !validProposalStatuses.has(proposalStatusFilter)) {
|
|
5963
|
+
return c.error({
|
|
5964
|
+
code: "INVALID_STATUS",
|
|
5965
|
+
message: `Invalid --proposal-status: "${proposalStatusFilter}". Valid: ${[...validProposalStatuses].join(", ")}`,
|
|
5966
|
+
retryable: false
|
|
5967
|
+
});
|
|
5968
|
+
}
|
|
5969
|
+
const omitComments = c.options["omit-comments"] ?? false;
|
|
5970
|
+
const omitMembers = c.options["omit-members"] ?? false;
|
|
5971
|
+
const omitPetitions = c.options["omit-petitions"] ?? false;
|
|
5972
|
+
const summaryOnly = c.options["summary-only"] ?? false;
|
|
5973
|
+
const proposalsLimit = c.options["proposals-limit"];
|
|
5974
|
+
const threadsLimit = c.options["threads-limit"];
|
|
5975
|
+
const commentsLimit = c.options["comments-limit"];
|
|
5976
|
+
const petitionsLimit = c.options["petitions-limit"];
|
|
5977
|
+
const [proposalsResult, threadsResult, commentsResult, petitionsResult, membersResult] = await Promise.allSettled([
|
|
5978
|
+
fetchAllProposals(client),
|
|
5979
|
+
fetchAllThreads(client),
|
|
5980
|
+
omitComments ? Promise.resolve([]) : fetchAllComments(client),
|
|
5981
|
+
omitPetitions ? Promise.resolve([]) : fetchAllPetitions(client),
|
|
5982
|
+
omitMembers ? Promise.resolve({ members: [], fallbackReason: void 0 }) : fetchMemberList(client, c.env.ASSEMBLY_INDEXER_URL)
|
|
5983
|
+
]);
|
|
5984
|
+
let proposals = [];
|
|
5985
|
+
if (proposalsResult.status === "fulfilled") {
|
|
5986
|
+
proposals = proposalsResult.value;
|
|
5987
|
+
} else {
|
|
5988
|
+
errors.push(`proposals: ${proposalsResult.reason}`);
|
|
5989
|
+
}
|
|
5990
|
+
let threads = [];
|
|
5991
|
+
if (threadsResult.status === "fulfilled") {
|
|
5992
|
+
threads = threadsResult.value;
|
|
5993
|
+
} else {
|
|
5994
|
+
errors.push(`threads: ${threadsResult.reason}`);
|
|
5995
|
+
}
|
|
5996
|
+
let comments = [];
|
|
5997
|
+
if (!omitComments) {
|
|
5998
|
+
if (commentsResult.status === "fulfilled") {
|
|
5999
|
+
comments = commentsResult.value;
|
|
6000
|
+
} else {
|
|
6001
|
+
errors.push(`comments: ${commentsResult.reason}`);
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
6004
|
+
let petitions = [];
|
|
6005
|
+
if (!omitPetitions) {
|
|
6006
|
+
if (petitionsResult.status === "fulfilled") {
|
|
6007
|
+
petitions = petitionsResult.value;
|
|
6008
|
+
} else {
|
|
6009
|
+
errors.push(`petitions: ${petitionsResult.reason}`);
|
|
6010
|
+
}
|
|
6011
|
+
}
|
|
6012
|
+
let memberIdentities = [];
|
|
6013
|
+
if (!omitMembers) {
|
|
6014
|
+
if (membersResult.status === "fulfilled") {
|
|
6015
|
+
const loaded = membersResult.value;
|
|
6016
|
+
memberIdentities = loaded.members;
|
|
6017
|
+
if (loaded.fallbackReason) {
|
|
6018
|
+
process.stderr.write(
|
|
6019
|
+
`${JSON.stringify({
|
|
6020
|
+
level: "warn",
|
|
6021
|
+
code: loaded.fallbackReason.code,
|
|
6022
|
+
message: "Member snapshot indexer is unavailable. Falling back to on-chain Registered events.",
|
|
6023
|
+
url: loaded.fallbackReason.url
|
|
6024
|
+
})}
|
|
6025
|
+
`
|
|
6026
|
+
);
|
|
6027
|
+
}
|
|
6028
|
+
} else {
|
|
6029
|
+
const err = membersResult.reason;
|
|
6030
|
+
if (err instanceof AssemblyApiValidationError) {
|
|
6031
|
+
errors.push(`members: ${err.details.code}`);
|
|
6032
|
+
} else {
|
|
6033
|
+
errors.push(`members: ${err}`);
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
if (sinceTs !== void 0) {
|
|
6038
|
+
proposals = proposals.filter((p) => Number(p.createdAt) >= sinceTs);
|
|
6039
|
+
threads = threads.filter((t) => t.createdAt >= sinceTs);
|
|
6040
|
+
comments = comments.filter((cm) => cm.createdAt >= sinceTs);
|
|
6041
|
+
petitions = petitions.filter((p) => p.createdAt >= sinceTs);
|
|
6042
|
+
}
|
|
6043
|
+
if (untilTs !== void 0) {
|
|
6044
|
+
proposals = proposals.filter((p) => Number(p.createdAt) <= untilTs);
|
|
6045
|
+
threads = threads.filter((t) => t.createdAt <= untilTs);
|
|
6046
|
+
comments = comments.filter((cm) => cm.createdAt <= untilTs);
|
|
6047
|
+
petitions = petitions.filter((p) => p.createdAt <= untilTs);
|
|
6048
|
+
}
|
|
6049
|
+
if (proposalStatusFilter) {
|
|
6050
|
+
const statusLabelToCode = /* @__PURE__ */ new Map();
|
|
6051
|
+
for (const [code, label] of Object.entries(proposalStatusLabels)) {
|
|
6052
|
+
statusLabelToCode.set(label, Number(code));
|
|
6053
|
+
}
|
|
6054
|
+
const targetCode = statusLabelToCode.get(proposalStatusFilter);
|
|
6055
|
+
if (targetCode !== void 0) {
|
|
6056
|
+
proposals = proposals.filter((p) => Number(p.status) === targetCode);
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
proposals.sort((a, b) => Number(b.createdAt) - Number(a.createdAt));
|
|
6060
|
+
threads.sort((a, b) => b.createdAt - a.createdAt);
|
|
6061
|
+
comments.sort((a, b) => b.createdAt - a.createdAt);
|
|
6062
|
+
petitions.sort((a, b) => b.createdAt - a.createdAt);
|
|
6063
|
+
if (proposalsLimit !== void 0) {
|
|
6064
|
+
proposals = proposals.slice(0, proposalsLimit);
|
|
6065
|
+
}
|
|
6066
|
+
if (threadsLimit !== void 0) {
|
|
6067
|
+
threads = threads.slice(0, threadsLimit);
|
|
6068
|
+
}
|
|
6069
|
+
if (commentsLimit !== void 0) {
|
|
6070
|
+
comments = comments.slice(0, commentsLimit);
|
|
6071
|
+
}
|
|
6072
|
+
if (petitionsLimit !== void 0) {
|
|
6073
|
+
petitions = petitions.slice(0, petitionsLimit);
|
|
6074
|
+
}
|
|
6075
|
+
let memberItems = [];
|
|
6076
|
+
if (!omitMembers && memberIdentities.length > 0) {
|
|
6077
|
+
try {
|
|
6078
|
+
const onchainStates = await fetchMemberOnchainState(
|
|
6079
|
+
client,
|
|
6080
|
+
memberIdentities.map((m) => m.address)
|
|
6081
|
+
);
|
|
6082
|
+
memberItems = onchainStates.map((s) => ({
|
|
6083
|
+
address: s.address,
|
|
6084
|
+
active: s.active,
|
|
6085
|
+
registered: s.registered,
|
|
6086
|
+
activeUntil: isoTime(s.activeUntil),
|
|
6087
|
+
lastHeartbeatAt: isoTime(s.lastHeartbeatAt)
|
|
6088
|
+
}));
|
|
6089
|
+
} catch (err) {
|
|
6090
|
+
errors.push(`members onchain state: ${err}`);
|
|
6091
|
+
}
|
|
6092
|
+
}
|
|
6093
|
+
let hasVotedMap = /* @__PURE__ */ new Map();
|
|
6094
|
+
let hasSignedMap = /* @__PURE__ */ new Map();
|
|
6095
|
+
if (address) {
|
|
6096
|
+
const proposalIds = proposals.map((_, i) => i + 1);
|
|
6097
|
+
const petitionIds = petitions.map((p) => p.id);
|
|
6098
|
+
const [votedResult, signedResult] = await Promise.allSettled([
|
|
6099
|
+
fetchHasVotedBatch(client, address, proposalIds),
|
|
6100
|
+
omitPetitions ? Promise.resolve(/* @__PURE__ */ new Map()) : fetchHasSignedBatch(client, address, petitionIds)
|
|
6101
|
+
]);
|
|
6102
|
+
if (votedResult.status === "fulfilled") {
|
|
6103
|
+
hasVotedMap = votedResult.value;
|
|
6104
|
+
} else {
|
|
6105
|
+
errors.push(`hasVoted enrichment: ${votedResult.reason}`);
|
|
6106
|
+
}
|
|
6107
|
+
if (signedResult.status === "fulfilled") {
|
|
6108
|
+
hasSignedMap = signedResult.value;
|
|
6109
|
+
} else {
|
|
6110
|
+
errors.push(`hasSigned enrichment: ${signedResult.reason}`);
|
|
6111
|
+
}
|
|
6112
|
+
}
|
|
6113
|
+
let serializedProposals;
|
|
6114
|
+
if (summaryOnly) {
|
|
6115
|
+
serializedProposals = proposals.map((p, i) => {
|
|
6116
|
+
const { status, statusCode } = serializeProposal(p);
|
|
6117
|
+
const entry = {
|
|
6118
|
+
id: i + 1,
|
|
6119
|
+
title: p.title,
|
|
6120
|
+
status,
|
|
6121
|
+
statusCode,
|
|
6122
|
+
createdAt: Number(p.createdAt)
|
|
6123
|
+
};
|
|
6124
|
+
if (address) {
|
|
6125
|
+
entry.hasVoted = hasVotedMap.get(i + 1) ?? false;
|
|
6126
|
+
}
|
|
6127
|
+
return entry;
|
|
6128
|
+
});
|
|
6129
|
+
} else {
|
|
6130
|
+
serializedProposals = proposals.map((p, i) => {
|
|
6131
|
+
const serialized = serializeProposal(p);
|
|
6132
|
+
const entry = {
|
|
6133
|
+
id: i + 1,
|
|
6134
|
+
...serialized
|
|
6135
|
+
};
|
|
6136
|
+
if (address) {
|
|
6137
|
+
entry.hasVoted = hasVotedMap.get(i + 1) ?? false;
|
|
6138
|
+
}
|
|
6139
|
+
return entry;
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
6142
|
+
let serializedThreads;
|
|
6143
|
+
if (summaryOnly) {
|
|
6144
|
+
serializedThreads = threads.map((t) => ({
|
|
6145
|
+
id: t.id,
|
|
6146
|
+
title: t.title,
|
|
6147
|
+
category: t.category,
|
|
6148
|
+
createdAt: t.createdAt
|
|
6149
|
+
}));
|
|
6150
|
+
} else {
|
|
6151
|
+
serializedThreads = threads.map((t) => ({
|
|
6152
|
+
id: t.id,
|
|
6153
|
+
kind: t.kind,
|
|
6154
|
+
author: t.author,
|
|
6155
|
+
createdAt: t.createdAt,
|
|
6156
|
+
category: t.category,
|
|
6157
|
+
title: t.title,
|
|
6158
|
+
proposalId: t.proposalId,
|
|
6159
|
+
petitionId: t.petitionId
|
|
6160
|
+
}));
|
|
6161
|
+
}
|
|
6162
|
+
let serializedComments;
|
|
6163
|
+
if (!omitComments) {
|
|
6164
|
+
if (summaryOnly) {
|
|
6165
|
+
serializedComments = comments.map((cm) => ({
|
|
6166
|
+
id: cm.id,
|
|
6167
|
+
threadId: cm.threadId,
|
|
6168
|
+
author: cm.author,
|
|
6169
|
+
createdAt: cm.createdAt
|
|
6170
|
+
}));
|
|
6171
|
+
} else {
|
|
6172
|
+
serializedComments = comments.map((cm) => ({
|
|
6173
|
+
id: cm.id,
|
|
6174
|
+
threadId: cm.threadId,
|
|
6175
|
+
parentId: cm.parentId,
|
|
6176
|
+
author: cm.author,
|
|
6177
|
+
createdAt: cm.createdAt,
|
|
6178
|
+
body: cm.body
|
|
6179
|
+
}));
|
|
6180
|
+
}
|
|
6181
|
+
}
|
|
6182
|
+
let serializedPetitions;
|
|
6183
|
+
if (!omitPetitions) {
|
|
6184
|
+
if (summaryOnly) {
|
|
6185
|
+
serializedPetitions = petitions.map((p) => {
|
|
6186
|
+
const entry = {
|
|
6187
|
+
id: p.id,
|
|
6188
|
+
title: p.title,
|
|
6189
|
+
category: p.category,
|
|
6190
|
+
signatures: p.signatures,
|
|
6191
|
+
promoted: p.promoted,
|
|
6192
|
+
createdAt: p.createdAt
|
|
6193
|
+
};
|
|
6194
|
+
if (address) {
|
|
6195
|
+
entry.hasSigned = hasSignedMap.get(p.id) ?? false;
|
|
6196
|
+
}
|
|
6197
|
+
return entry;
|
|
6198
|
+
});
|
|
6199
|
+
} else {
|
|
6200
|
+
serializedPetitions = petitions.map((p) => {
|
|
6201
|
+
const entry = {
|
|
6202
|
+
id: p.id,
|
|
6203
|
+
proposer: p.proposer,
|
|
6204
|
+
createdAt: p.createdAt,
|
|
6205
|
+
category: p.category,
|
|
6206
|
+
title: p.title,
|
|
6207
|
+
body: p.body,
|
|
6208
|
+
signatures: p.signatures,
|
|
6209
|
+
promoted: p.promoted,
|
|
6210
|
+
threadId: p.threadId
|
|
6211
|
+
};
|
|
6212
|
+
if (address) {
|
|
6213
|
+
entry.hasSigned = hasSignedMap.get(p.id) ?? false;
|
|
6214
|
+
}
|
|
6215
|
+
return entry;
|
|
6216
|
+
});
|
|
6217
|
+
}
|
|
6218
|
+
}
|
|
6219
|
+
const filtersMeta = {};
|
|
6220
|
+
if (sinceTs !== void 0) filtersMeta.since = isoTime(sinceTs);
|
|
6221
|
+
if (untilTs !== void 0) filtersMeta.until = isoTime(untilTs);
|
|
6222
|
+
if (omitComments) filtersMeta.omitComments = true;
|
|
6223
|
+
if (omitMembers) filtersMeta.omitMembers = true;
|
|
6224
|
+
if (omitPetitions) filtersMeta.omitPetitions = true;
|
|
6225
|
+
if (proposalsLimit !== void 0) filtersMeta.proposalsLimit = proposalsLimit;
|
|
6226
|
+
if (threadsLimit !== void 0) filtersMeta.threadsLimit = threadsLimit;
|
|
6227
|
+
if (commentsLimit !== void 0) filtersMeta.commentsLimit = commentsLimit;
|
|
6228
|
+
if (petitionsLimit !== void 0) filtersMeta.petitionsLimit = petitionsLimit;
|
|
6229
|
+
if (summaryOnly) filtersMeta.summaryOnly = true;
|
|
6230
|
+
if (proposalStatusFilter) filtersMeta.proposalStatus = proposalStatusFilter;
|
|
6231
|
+
const hasFilters = Object.keys(filtersMeta).length > 0;
|
|
6232
|
+
const output = {
|
|
6233
|
+
meta: {
|
|
6234
|
+
chainId: 2741,
|
|
6235
|
+
fetchedAt: (/* @__PURE__ */ new Date()).toISOString().replace(".000Z", "Z"),
|
|
6236
|
+
...address ? { address } : {},
|
|
6237
|
+
...hasFilters ? { filters: filtersMeta } : {}
|
|
6238
|
+
},
|
|
6239
|
+
proposals: serializedProposals,
|
|
6240
|
+
threads: serializedThreads,
|
|
6241
|
+
...omitComments ? {} : { comments: serializedComments },
|
|
6242
|
+
...omitPetitions ? {} : { petitions: serializedPetitions },
|
|
6243
|
+
...omitMembers ? {} : { members: { count: memberItems.length, items: memberItems } },
|
|
6244
|
+
errors
|
|
6245
|
+
};
|
|
6246
|
+
return c.ok(output);
|
|
6247
|
+
});
|
|
6248
|
+
}
|
|
6249
|
+
});
|
|
5391
6250
|
}
|
|
5392
6251
|
|
|
5393
6252
|
// src/commands/forum.ts
|
|
5394
|
-
|
|
5395
|
-
|
|
6253
|
+
import { TxError } from "@spectratools/tx-shared";
|
|
6254
|
+
import { Cli as Cli2, z as z5 } from "incur";
|
|
6255
|
+
var env2 = z5.object({
|
|
6256
|
+
ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
|
|
5396
6257
|
});
|
|
5397
6258
|
var commentEnv = env2.extend({
|
|
5398
|
-
PRIVATE_KEY:
|
|
6259
|
+
PRIVATE_KEY: z5.string().optional().describe("Private key (required only when posting a comment via --body)")
|
|
5399
6260
|
});
|
|
5400
|
-
var timestampOutput2 =
|
|
5401
|
-
var txResultOutput2 =
|
|
5402
|
-
|
|
5403
|
-
status:
|
|
5404
|
-
hash:
|
|
5405
|
-
blockNumber:
|
|
5406
|
-
gasUsed:
|
|
5407
|
-
from:
|
|
5408
|
-
to:
|
|
5409
|
-
effectiveGasPrice:
|
|
6261
|
+
var timestampOutput2 = z5.union([z5.number(), z5.string()]);
|
|
6262
|
+
var txResultOutput2 = z5.union([
|
|
6263
|
+
z5.object({
|
|
6264
|
+
status: z5.literal("success"),
|
|
6265
|
+
hash: z5.string(),
|
|
6266
|
+
blockNumber: z5.number(),
|
|
6267
|
+
gasUsed: z5.string(),
|
|
6268
|
+
from: z5.string(),
|
|
6269
|
+
to: z5.string().nullable(),
|
|
6270
|
+
effectiveGasPrice: z5.string().optional()
|
|
5410
6271
|
}),
|
|
5411
|
-
|
|
5412
|
-
status:
|
|
5413
|
-
hash:
|
|
5414
|
-
blockNumber:
|
|
5415
|
-
gasUsed:
|
|
5416
|
-
from:
|
|
5417
|
-
to:
|
|
5418
|
-
effectiveGasPrice:
|
|
6272
|
+
z5.object({
|
|
6273
|
+
status: z5.literal("reverted"),
|
|
6274
|
+
hash: z5.string(),
|
|
6275
|
+
blockNumber: z5.number(),
|
|
6276
|
+
gasUsed: z5.string(),
|
|
6277
|
+
from: z5.string(),
|
|
6278
|
+
to: z5.string().nullable(),
|
|
6279
|
+
effectiveGasPrice: z5.string().optional()
|
|
5419
6280
|
}),
|
|
5420
|
-
|
|
5421
|
-
status:
|
|
5422
|
-
estimatedGas:
|
|
5423
|
-
simulationResult:
|
|
6281
|
+
z5.object({
|
|
6282
|
+
status: z5.literal("dry-run"),
|
|
6283
|
+
estimatedGas: z5.string(),
|
|
6284
|
+
simulationResult: z5.unknown()
|
|
5424
6285
|
})
|
|
5425
6286
|
]);
|
|
5426
6287
|
var forum = Cli2.create("forum", {
|
|
@@ -5429,19 +6290,19 @@ var forum = Cli2.create("forum", {
|
|
|
5429
6290
|
forum.command("threads", {
|
|
5430
6291
|
description: "List forum threads with author and creation metadata.",
|
|
5431
6292
|
env: env2,
|
|
5432
|
-
output:
|
|
5433
|
-
threads:
|
|
5434
|
-
|
|
5435
|
-
id:
|
|
5436
|
-
kind:
|
|
5437
|
-
author:
|
|
6293
|
+
output: z5.object({
|
|
6294
|
+
threads: z5.array(
|
|
6295
|
+
z5.object({
|
|
6296
|
+
id: z5.number(),
|
|
6297
|
+
kind: z5.number(),
|
|
6298
|
+
author: z5.string(),
|
|
5438
6299
|
createdAt: timestampOutput2,
|
|
5439
|
-
createdAtRelative:
|
|
5440
|
-
category:
|
|
5441
|
-
title:
|
|
6300
|
+
createdAtRelative: z5.string(),
|
|
6301
|
+
category: z5.string().nullable().optional(),
|
|
6302
|
+
title: z5.string().nullable().optional()
|
|
5442
6303
|
})
|
|
5443
6304
|
),
|
|
5444
|
-
count:
|
|
6305
|
+
count: z5.number()
|
|
5445
6306
|
}),
|
|
5446
6307
|
examples: [{ description: "List all forum threads" }],
|
|
5447
6308
|
async run(c) {
|
|
@@ -5475,13 +6336,13 @@ forum.command("threads", {
|
|
|
5475
6336
|
});
|
|
5476
6337
|
forum.command("thread", {
|
|
5477
6338
|
description: "Get one thread and all comments associated with it.",
|
|
5478
|
-
args:
|
|
5479
|
-
id:
|
|
6339
|
+
args: z5.object({
|
|
6340
|
+
id: z5.coerce.number().int().positive().describe("Thread id (1-indexed)")
|
|
5480
6341
|
}),
|
|
5481
6342
|
env: env2,
|
|
5482
|
-
output:
|
|
5483
|
-
thread:
|
|
5484
|
-
comments:
|
|
6343
|
+
output: z5.object({
|
|
6344
|
+
thread: z5.record(z5.string(), z5.unknown()),
|
|
6345
|
+
comments: z5.array(z5.record(z5.string(), z5.unknown()))
|
|
5485
6346
|
}),
|
|
5486
6347
|
examples: [{ args: { id: 1 }, description: "Fetch thread #1 and its comments" }],
|
|
5487
6348
|
async run(c) {
|
|
@@ -5514,11 +6375,11 @@ forum.command("thread", {
|
|
|
5514
6375
|
});
|
|
5515
6376
|
forum.command("comments", {
|
|
5516
6377
|
description: "List comments for a thread id.",
|
|
5517
|
-
args:
|
|
5518
|
-
threadId:
|
|
6378
|
+
args: z5.object({
|
|
6379
|
+
threadId: z5.coerce.number().int().positive().describe("Thread id to filter comments by")
|
|
5519
6380
|
}),
|
|
5520
6381
|
env: env2,
|
|
5521
|
-
output:
|
|
6382
|
+
output: z5.array(z5.record(z5.string(), z5.unknown())),
|
|
5522
6383
|
examples: [{ args: { threadId: 1 }, description: "List comments for thread #1" }],
|
|
5523
6384
|
async run(c) {
|
|
5524
6385
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -5530,15 +6391,15 @@ forum.command("comments", {
|
|
|
5530
6391
|
});
|
|
5531
6392
|
forum.command("comment", {
|
|
5532
6393
|
description: "Get one comment by id, or post to a thread when --body is provided.",
|
|
5533
|
-
args:
|
|
5534
|
-
id:
|
|
6394
|
+
args: z5.object({
|
|
6395
|
+
id: z5.coerce.number().int().positive().describe("Comment id (read) or thread id (write)")
|
|
5535
6396
|
}),
|
|
5536
6397
|
options: writeOptions.extend({
|
|
5537
|
-
body:
|
|
5538
|
-
"parent-id":
|
|
6398
|
+
body: z5.string().min(1).optional().describe("Comment body (write mode)"),
|
|
6399
|
+
"parent-id": z5.coerce.number().int().nonnegative().default(0).describe("Optional parent comment id for threaded replies (write mode)")
|
|
5539
6400
|
}),
|
|
5540
6401
|
env: commentEnv,
|
|
5541
|
-
output:
|
|
6402
|
+
output: z5.record(z5.string(), z5.unknown()),
|
|
5542
6403
|
examples: [
|
|
5543
6404
|
{ args: { id: 1 }, description: "Fetch comment #1" },
|
|
5544
6405
|
{
|
|
@@ -5653,16 +6514,16 @@ forum.command("post", {
|
|
|
5653
6514
|
description: "Create a new discussion thread in the forum.",
|
|
5654
6515
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
5655
6516
|
options: writeOptions.extend({
|
|
5656
|
-
category:
|
|
5657
|
-
title:
|
|
5658
|
-
body:
|
|
6517
|
+
category: z5.string().min(1).describe("Thread category label (e.g., general, governance)"),
|
|
6518
|
+
title: z5.string().min(1).describe("Thread title"),
|
|
6519
|
+
body: z5.string().min(1).describe("Thread body")
|
|
5659
6520
|
}),
|
|
5660
6521
|
env: writeEnv,
|
|
5661
|
-
output:
|
|
5662
|
-
author:
|
|
5663
|
-
category:
|
|
5664
|
-
title:
|
|
5665
|
-
expectedThreadId:
|
|
6522
|
+
output: z5.object({
|
|
6523
|
+
author: z5.string(),
|
|
6524
|
+
category: z5.string(),
|
|
6525
|
+
title: z5.string(),
|
|
6526
|
+
expectedThreadId: z5.number(),
|
|
5666
6527
|
tx: txResultOutput2
|
|
5667
6528
|
}),
|
|
5668
6529
|
examples: [
|
|
@@ -5730,19 +6591,19 @@ forum.command("post", {
|
|
|
5730
6591
|
forum.command("post-comment", {
|
|
5731
6592
|
description: "Post a comment to a forum thread.",
|
|
5732
6593
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
5733
|
-
args:
|
|
5734
|
-
threadId:
|
|
6594
|
+
args: z5.object({
|
|
6595
|
+
threadId: z5.coerce.number().int().positive().describe("Thread id to comment on")
|
|
5735
6596
|
}),
|
|
5736
6597
|
options: writeOptions.extend({
|
|
5737
|
-
body:
|
|
5738
|
-
"parent-id":
|
|
6598
|
+
body: z5.string().min(1).describe("Comment body"),
|
|
6599
|
+
"parent-id": z5.coerce.number().int().nonnegative().default(0).describe("Optional parent comment id for threaded replies")
|
|
5739
6600
|
}),
|
|
5740
6601
|
env: writeEnv,
|
|
5741
|
-
output:
|
|
5742
|
-
author:
|
|
5743
|
-
threadId:
|
|
5744
|
-
parentId:
|
|
5745
|
-
expectedCommentId:
|
|
6602
|
+
output: z5.object({
|
|
6603
|
+
author: z5.string(),
|
|
6604
|
+
threadId: z5.number(),
|
|
6605
|
+
parentId: z5.number(),
|
|
6606
|
+
expectedCommentId: z5.number(),
|
|
5746
6607
|
tx: txResultOutput2
|
|
5747
6608
|
}),
|
|
5748
6609
|
examples: [
|
|
@@ -5829,20 +6690,20 @@ forum.command("create-petition", {
|
|
|
5829
6690
|
description: "Create a new petition for community-initiated proposals.",
|
|
5830
6691
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
5831
6692
|
options: writeOptions.extend({
|
|
5832
|
-
title:
|
|
5833
|
-
description:
|
|
5834
|
-
kind:
|
|
5835
|
-
category:
|
|
6693
|
+
title: z5.string().min(1).describe("Petition title"),
|
|
6694
|
+
description: z5.string().min(1).describe("Petition description"),
|
|
6695
|
+
kind: z5.coerce.number().int().nonnegative().max(255).describe("Proposal kind enum value"),
|
|
6696
|
+
category: z5.string().default("governance").describe("Forum category label for the petition")
|
|
5836
6697
|
}),
|
|
5837
6698
|
env: writeEnv,
|
|
5838
|
-
output:
|
|
5839
|
-
proposer:
|
|
5840
|
-
category:
|
|
5841
|
-
kind:
|
|
5842
|
-
title:
|
|
5843
|
-
description:
|
|
5844
|
-
expectedPetitionId:
|
|
5845
|
-
expectedThreadId:
|
|
6699
|
+
output: z5.object({
|
|
6700
|
+
proposer: z5.string(),
|
|
6701
|
+
category: z5.string(),
|
|
6702
|
+
kind: z5.number(),
|
|
6703
|
+
title: z5.string(),
|
|
6704
|
+
description: z5.string(),
|
|
6705
|
+
expectedPetitionId: z5.number(),
|
|
6706
|
+
expectedThreadId: z5.number(),
|
|
5846
6707
|
tx: txResultOutput2
|
|
5847
6708
|
}),
|
|
5848
6709
|
examples: [
|
|
@@ -5945,15 +6806,15 @@ forum.command("create-petition", {
|
|
|
5945
6806
|
forum.command("sign-petition", {
|
|
5946
6807
|
description: "Sign an existing petition as an active member.",
|
|
5947
6808
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
5948
|
-
args:
|
|
5949
|
-
petitionId:
|
|
6809
|
+
args: z5.object({
|
|
6810
|
+
petitionId: z5.coerce.number().int().positive().describe("Petition id (1-indexed)")
|
|
5950
6811
|
}),
|
|
5951
6812
|
options: writeOptions,
|
|
5952
6813
|
env: writeEnv,
|
|
5953
|
-
output:
|
|
5954
|
-
signer:
|
|
5955
|
-
petitionId:
|
|
5956
|
-
expectedSignatures:
|
|
6814
|
+
output: z5.object({
|
|
6815
|
+
signer: z5.string(),
|
|
6816
|
+
petitionId: z5.number(),
|
|
6817
|
+
expectedSignatures: z5.number(),
|
|
5957
6818
|
tx: txResultOutput2
|
|
5958
6819
|
}),
|
|
5959
6820
|
examples: [{ args: { petitionId: 1 }, description: "Sign petition #1" }],
|
|
@@ -6040,7 +6901,7 @@ forum.command("sign-petition", {
|
|
|
6040
6901
|
forum.command("petitions", {
|
|
6041
6902
|
description: "List petitions submitted in the forum contract.",
|
|
6042
6903
|
env: env2,
|
|
6043
|
-
output:
|
|
6904
|
+
output: z5.array(z5.record(z5.string(), z5.unknown())),
|
|
6044
6905
|
examples: [{ description: "List all petitions" }],
|
|
6045
6906
|
async run(c) {
|
|
6046
6907
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -6050,11 +6911,11 @@ forum.command("petitions", {
|
|
|
6050
6911
|
});
|
|
6051
6912
|
forum.command("petition", {
|
|
6052
6913
|
description: "Get one petition plus whether proposer already signed it.",
|
|
6053
|
-
args:
|
|
6054
|
-
id:
|
|
6914
|
+
args: z5.object({
|
|
6915
|
+
id: z5.coerce.number().int().positive().describe("Petition id (1-indexed)")
|
|
6055
6916
|
}),
|
|
6056
6917
|
env: env2,
|
|
6057
|
-
output:
|
|
6918
|
+
output: z5.object({ proposerSigned: z5.boolean() }).passthrough(),
|
|
6058
6919
|
examples: [{ args: { id: 1 }, description: "Fetch petition #1" }],
|
|
6059
6920
|
async run(c) {
|
|
6060
6921
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
@@ -6089,15 +6950,15 @@ forum.command("petition", {
|
|
|
6089
6950
|
});
|
|
6090
6951
|
forum.command("has-signed", {
|
|
6091
6952
|
description: "Check whether an address signed a petition.",
|
|
6092
|
-
args:
|
|
6093
|
-
petitionId:
|
|
6094
|
-
address:
|
|
6953
|
+
args: z5.object({
|
|
6954
|
+
petitionId: z5.coerce.number().int().positive().describe("Petition id (1-indexed)"),
|
|
6955
|
+
address: z5.string().describe("Signer address to check")
|
|
6095
6956
|
}),
|
|
6096
6957
|
env: env2,
|
|
6097
|
-
output:
|
|
6098
|
-
petitionId:
|
|
6099
|
-
address:
|
|
6100
|
-
hasSigned:
|
|
6958
|
+
output: z5.object({
|
|
6959
|
+
petitionId: z5.number(),
|
|
6960
|
+
address: z5.string(),
|
|
6961
|
+
hasSigned: z5.boolean()
|
|
6101
6962
|
}),
|
|
6102
6963
|
examples: [
|
|
6103
6964
|
{
|
|
@@ -6122,11 +6983,11 @@ forum.command("has-signed", {
|
|
|
6122
6983
|
forum.command("stats", {
|
|
6123
6984
|
description: "Read top-level forum counters and petition threshold.",
|
|
6124
6985
|
env: env2,
|
|
6125
|
-
output:
|
|
6126
|
-
threadCount:
|
|
6127
|
-
commentCount:
|
|
6128
|
-
petitionCount:
|
|
6129
|
-
petitionThresholdBps:
|
|
6986
|
+
output: z5.object({
|
|
6987
|
+
threadCount: z5.number(),
|
|
6988
|
+
commentCount: z5.number(),
|
|
6989
|
+
petitionCount: z5.number(),
|
|
6990
|
+
petitionThresholdBps: z5.number()
|
|
6130
6991
|
}),
|
|
6131
6992
|
examples: [{ description: "Get forum counts and petition threshold" }],
|
|
6132
6993
|
async run(c) {
|
|
@@ -6137,176 +6998,44 @@ forum.command("stats", {
|
|
|
6137
6998
|
|
|
6138
6999
|
// src/commands/governance.ts
|
|
6139
7000
|
import { TxError as TxError2 } from "@spectratools/tx-shared";
|
|
6140
|
-
import { Cli as Cli3, z as
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
var proposalStatusLabels = {
|
|
6144
|
-
0: "pending",
|
|
6145
|
-
1: "active",
|
|
6146
|
-
2: "passed",
|
|
6147
|
-
3: "executed",
|
|
6148
|
-
4: "defeated",
|
|
6149
|
-
5: "cancelled"
|
|
6150
|
-
};
|
|
6151
|
-
function proposalStatus(status) {
|
|
6152
|
-
const statusCode = asNum(status);
|
|
6153
|
-
return {
|
|
6154
|
-
status: proposalStatusLabels[statusCode] ?? `unknown-${statusCode}`,
|
|
6155
|
-
statusCode
|
|
6156
|
-
};
|
|
6157
|
-
}
|
|
6158
|
-
function decodeProposal(value) {
|
|
6159
|
-
const [
|
|
6160
|
-
kind,
|
|
6161
|
-
configRiskTier,
|
|
6162
|
-
origin,
|
|
6163
|
-
status,
|
|
6164
|
-
proposer,
|
|
6165
|
-
threadId,
|
|
6166
|
-
petitionId,
|
|
6167
|
-
createdAt,
|
|
6168
|
-
deliberationEndsAt,
|
|
6169
|
-
voteStartAt,
|
|
6170
|
-
voteEndAt,
|
|
6171
|
-
timelockEndsAt,
|
|
6172
|
-
activeSeatsSnapshot,
|
|
6173
|
-
forVotes,
|
|
6174
|
-
againstVotes,
|
|
6175
|
-
abstainVotes,
|
|
6176
|
-
amount,
|
|
6177
|
-
snapshotAssetBalance,
|
|
6178
|
-
transferIntent,
|
|
6179
|
-
intentDeadline,
|
|
6180
|
-
intentMaxRiskTier,
|
|
6181
|
-
title,
|
|
6182
|
-
description
|
|
6183
|
-
] = value;
|
|
6184
|
-
return {
|
|
6185
|
-
kind,
|
|
6186
|
-
configRiskTier,
|
|
6187
|
-
origin,
|
|
6188
|
-
status,
|
|
6189
|
-
proposer: toChecksum(proposer),
|
|
6190
|
-
threadId,
|
|
6191
|
-
petitionId,
|
|
6192
|
-
createdAt,
|
|
6193
|
-
deliberationEndsAt,
|
|
6194
|
-
voteStartAt,
|
|
6195
|
-
voteEndAt,
|
|
6196
|
-
timelockEndsAt,
|
|
6197
|
-
activeSeatsSnapshot,
|
|
6198
|
-
forVotes,
|
|
6199
|
-
againstVotes,
|
|
6200
|
-
abstainVotes,
|
|
6201
|
-
amount,
|
|
6202
|
-
snapshotAssetBalance,
|
|
6203
|
-
transferIntent,
|
|
6204
|
-
intentDeadline,
|
|
6205
|
-
intentMaxRiskTier,
|
|
6206
|
-
title,
|
|
6207
|
-
description
|
|
6208
|
-
};
|
|
6209
|
-
}
|
|
6210
|
-
function serializeProposal(proposal) {
|
|
6211
|
-
const status = proposalStatus(proposal.status);
|
|
6212
|
-
return {
|
|
6213
|
-
kind: asNum(proposal.kind),
|
|
6214
|
-
configRiskTier: asNum(proposal.configRiskTier),
|
|
6215
|
-
origin: asNum(proposal.origin),
|
|
6216
|
-
status: status.status,
|
|
6217
|
-
statusCode: status.statusCode,
|
|
6218
|
-
proposer: proposal.proposer,
|
|
6219
|
-
threadId: asNum(proposal.threadId),
|
|
6220
|
-
petitionId: asNum(proposal.petitionId),
|
|
6221
|
-
createdAt: asNum(proposal.createdAt),
|
|
6222
|
-
deliberationEndsAt: asNum(proposal.deliberationEndsAt),
|
|
6223
|
-
voteStartAt: asNum(proposal.voteStartAt),
|
|
6224
|
-
voteEndAt: asNum(proposal.voteEndAt),
|
|
6225
|
-
timelockEndsAt: asNum(proposal.timelockEndsAt),
|
|
6226
|
-
activeSeatsSnapshot: asNum(proposal.activeSeatsSnapshot),
|
|
6227
|
-
forVotes: proposal.forVotes.toString(),
|
|
6228
|
-
againstVotes: proposal.againstVotes.toString(),
|
|
6229
|
-
abstainVotes: proposal.abstainVotes.toString(),
|
|
6230
|
-
amount: proposal.amount.toString(),
|
|
6231
|
-
snapshotAssetBalance: proposal.snapshotAssetBalance.toString(),
|
|
6232
|
-
transferIntent: proposal.transferIntent,
|
|
6233
|
-
intentDeadline: asNum(proposal.intentDeadline),
|
|
6234
|
-
intentMaxRiskTier: asNum(proposal.intentMaxRiskTier),
|
|
6235
|
-
title: proposal.title,
|
|
6236
|
-
description: proposal.description
|
|
6237
|
-
};
|
|
6238
|
-
}
|
|
6239
|
-
async function fetchProposalCount(client) {
|
|
6240
|
-
return await client.readContract({
|
|
6241
|
-
abi: governanceAbi,
|
|
6242
|
-
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
6243
|
-
functionName: "proposalCount"
|
|
6244
|
-
});
|
|
6245
|
-
}
|
|
6246
|
-
async function fetchProposalById(client, id) {
|
|
6247
|
-
return decodeProposal(
|
|
6248
|
-
await client.readContract({
|
|
6249
|
-
abi: governanceAbi,
|
|
6250
|
-
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
6251
|
-
functionName: "proposals",
|
|
6252
|
-
args: [BigInt(id)]
|
|
6253
|
-
})
|
|
6254
|
-
);
|
|
6255
|
-
}
|
|
6256
|
-
async function fetchAllProposals(client) {
|
|
6257
|
-
const count = await fetchProposalCount(client);
|
|
6258
|
-
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
|
|
6259
|
-
if (ids.length === 0) return [];
|
|
6260
|
-
const proposalTuples = await client.multicall({
|
|
6261
|
-
allowFailure: false,
|
|
6262
|
-
contracts: ids.map((id) => ({
|
|
6263
|
-
abi: governanceAbi,
|
|
6264
|
-
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
6265
|
-
functionName: "proposals",
|
|
6266
|
-
args: [id]
|
|
6267
|
-
}))
|
|
6268
|
-
});
|
|
6269
|
-
return proposalTuples.map(decodeProposal);
|
|
6270
|
-
}
|
|
6271
|
-
|
|
6272
|
-
// src/commands/governance.ts
|
|
6273
|
-
var env3 = z4.object({
|
|
6274
|
-
ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
|
|
7001
|
+
import { Cli as Cli3, z as z6 } from "incur";
|
|
7002
|
+
var env3 = z6.object({
|
|
7003
|
+
ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
|
|
6275
7004
|
});
|
|
6276
|
-
var timestampOutput3 =
|
|
7005
|
+
var timestampOutput3 = z6.union([z6.number(), z6.string()]);
|
|
6277
7006
|
var PROPOSAL_STATUS_PENDING = 0;
|
|
6278
|
-
var PROPOSAL_STATUS_ACTIVE = 1;
|
|
6279
|
-
var PROPOSAL_STATUS_PASSED = 2;
|
|
6280
|
-
var supportChoiceToValue = {
|
|
6281
|
-
against: 0,
|
|
6282
|
-
for: 1,
|
|
6283
|
-
abstain: 2
|
|
6284
|
-
};
|
|
6285
|
-
var proposalOutputSchema =
|
|
6286
|
-
kind:
|
|
6287
|
-
configRiskTier:
|
|
6288
|
-
origin:
|
|
6289
|
-
status:
|
|
6290
|
-
statusCode:
|
|
6291
|
-
proposer:
|
|
6292
|
-
threadId:
|
|
6293
|
-
petitionId:
|
|
6294
|
-
createdAt:
|
|
6295
|
-
deliberationEndsAt:
|
|
6296
|
-
voteStartAt:
|
|
6297
|
-
voteEndAt:
|
|
6298
|
-
timelockEndsAt:
|
|
6299
|
-
activeSeatsSnapshot:
|
|
6300
|
-
forVotes:
|
|
6301
|
-
againstVotes:
|
|
6302
|
-
abstainVotes:
|
|
6303
|
-
amount:
|
|
6304
|
-
snapshotAssetBalance:
|
|
6305
|
-
transferIntent:
|
|
6306
|
-
intentDeadline:
|
|
6307
|
-
intentMaxRiskTier:
|
|
6308
|
-
title:
|
|
6309
|
-
description:
|
|
7007
|
+
var PROPOSAL_STATUS_ACTIVE = 1;
|
|
7008
|
+
var PROPOSAL_STATUS_PASSED = 2;
|
|
7009
|
+
var supportChoiceToValue = {
|
|
7010
|
+
against: 0,
|
|
7011
|
+
for: 1,
|
|
7012
|
+
abstain: 2
|
|
7013
|
+
};
|
|
7014
|
+
var proposalOutputSchema = z6.object({
|
|
7015
|
+
kind: z6.number(),
|
|
7016
|
+
configRiskTier: z6.number(),
|
|
7017
|
+
origin: z6.number(),
|
|
7018
|
+
status: z6.string(),
|
|
7019
|
+
statusCode: z6.number(),
|
|
7020
|
+
proposer: z6.string(),
|
|
7021
|
+
threadId: z6.number(),
|
|
7022
|
+
petitionId: z6.number(),
|
|
7023
|
+
createdAt: z6.number(),
|
|
7024
|
+
deliberationEndsAt: z6.number(),
|
|
7025
|
+
voteStartAt: z6.number(),
|
|
7026
|
+
voteEndAt: z6.number(),
|
|
7027
|
+
timelockEndsAt: z6.number(),
|
|
7028
|
+
activeSeatsSnapshot: z6.number(),
|
|
7029
|
+
forVotes: z6.string(),
|
|
7030
|
+
againstVotes: z6.string(),
|
|
7031
|
+
abstainVotes: z6.string(),
|
|
7032
|
+
amount: z6.string(),
|
|
7033
|
+
snapshotAssetBalance: z6.string(),
|
|
7034
|
+
transferIntent: z6.boolean(),
|
|
7035
|
+
intentDeadline: z6.number(),
|
|
7036
|
+
intentMaxRiskTier: z6.number(),
|
|
7037
|
+
title: z6.string(),
|
|
7038
|
+
description: z6.string()
|
|
6310
7039
|
});
|
|
6311
7040
|
var governance = Cli3.create("governance", {
|
|
6312
7041
|
description: "Inspect Assembly governance proposals, votes, and parameters."
|
|
@@ -6314,19 +7043,19 @@ var governance = Cli3.create("governance", {
|
|
|
6314
7043
|
governance.command("proposals", {
|
|
6315
7044
|
description: "List governance proposals with status and vote end time.",
|
|
6316
7045
|
env: env3,
|
|
6317
|
-
output:
|
|
6318
|
-
proposals:
|
|
6319
|
-
|
|
6320
|
-
id:
|
|
6321
|
-
kind:
|
|
6322
|
-
status:
|
|
6323
|
-
statusCode:
|
|
6324
|
-
title:
|
|
7046
|
+
output: z6.object({
|
|
7047
|
+
proposals: z6.array(
|
|
7048
|
+
z6.object({
|
|
7049
|
+
id: z6.number(),
|
|
7050
|
+
kind: z6.number(),
|
|
7051
|
+
status: z6.string(),
|
|
7052
|
+
statusCode: z6.number(),
|
|
7053
|
+
title: z6.string().nullable().optional(),
|
|
6325
7054
|
voteEndAt: timestampOutput3,
|
|
6326
|
-
voteEndRelative:
|
|
7055
|
+
voteEndRelative: z6.string()
|
|
6327
7056
|
})
|
|
6328
7057
|
),
|
|
6329
|
-
count:
|
|
7058
|
+
count: z6.number()
|
|
6330
7059
|
}),
|
|
6331
7060
|
examples: [{ description: "List all proposals" }],
|
|
6332
7061
|
async run(c) {
|
|
@@ -6362,8 +7091,8 @@ governance.command("proposals", {
|
|
|
6362
7091
|
});
|
|
6363
7092
|
governance.command("proposal", {
|
|
6364
7093
|
description: "Get full raw proposal details by proposal id.",
|
|
6365
|
-
args:
|
|
6366
|
-
id:
|
|
7094
|
+
args: z6.object({
|
|
7095
|
+
id: z6.coerce.number().int().positive().describe("Proposal id (1-indexed)")
|
|
6367
7096
|
}),
|
|
6368
7097
|
env: env3,
|
|
6369
7098
|
output: proposalOutputSchema,
|
|
@@ -6384,15 +7113,15 @@ governance.command("proposal", {
|
|
|
6384
7113
|
});
|
|
6385
7114
|
governance.command("has-voted", {
|
|
6386
7115
|
description: "Check if an address has voted on a proposal.",
|
|
6387
|
-
args:
|
|
6388
|
-
proposalId:
|
|
6389
|
-
address:
|
|
7116
|
+
args: z6.object({
|
|
7117
|
+
proposalId: z6.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
|
|
7118
|
+
address: z6.string().describe("Voter address")
|
|
6390
7119
|
}),
|
|
6391
7120
|
env: env3,
|
|
6392
|
-
output:
|
|
6393
|
-
proposalId:
|
|
6394
|
-
address:
|
|
6395
|
-
hasVoted:
|
|
7121
|
+
output: z6.object({
|
|
7122
|
+
proposalId: z6.number(),
|
|
7123
|
+
address: z6.string(),
|
|
7124
|
+
hasVoted: z6.boolean()
|
|
6396
7125
|
}),
|
|
6397
7126
|
examples: [
|
|
6398
7127
|
{
|
|
@@ -6421,19 +7150,19 @@ governance.command("has-voted", {
|
|
|
6421
7150
|
governance.command("params", {
|
|
6422
7151
|
description: "Read governance threshold and timing parameters.",
|
|
6423
7152
|
env: env3,
|
|
6424
|
-
output:
|
|
6425
|
-
deliberationPeriod:
|
|
6426
|
-
votePeriod:
|
|
6427
|
-
quorumBps:
|
|
6428
|
-
constitutionalDeliberationPeriod:
|
|
6429
|
-
constitutionalVotePeriod:
|
|
6430
|
-
constitutionalPassBps:
|
|
6431
|
-
majorPassBps:
|
|
6432
|
-
parameterPassBps:
|
|
6433
|
-
significantPassBps:
|
|
6434
|
-
significantThresholdBps:
|
|
6435
|
-
routineThresholdBps:
|
|
6436
|
-
timelockPeriod:
|
|
7153
|
+
output: z6.object({
|
|
7154
|
+
deliberationPeriod: z6.number(),
|
|
7155
|
+
votePeriod: z6.number(),
|
|
7156
|
+
quorumBps: z6.number(),
|
|
7157
|
+
constitutionalDeliberationPeriod: z6.number(),
|
|
7158
|
+
constitutionalVotePeriod: z6.number(),
|
|
7159
|
+
constitutionalPassBps: z6.number(),
|
|
7160
|
+
majorPassBps: z6.number(),
|
|
7161
|
+
parameterPassBps: z6.number(),
|
|
7162
|
+
significantPassBps: z6.number(),
|
|
7163
|
+
significantThresholdBps: z6.number(),
|
|
7164
|
+
routineThresholdBps: z6.number(),
|
|
7165
|
+
timelockPeriod: z6.number()
|
|
6437
7166
|
}),
|
|
6438
7167
|
examples: [{ description: "Inspect governance timing and pass thresholds" }],
|
|
6439
7168
|
async run(c) {
|
|
@@ -6476,36 +7205,36 @@ governance.command("params", {
|
|
|
6476
7205
|
});
|
|
6477
7206
|
}
|
|
6478
7207
|
});
|
|
6479
|
-
var txResultOutput3 =
|
|
6480
|
-
|
|
6481
|
-
status:
|
|
6482
|
-
hash:
|
|
6483
|
-
blockNumber:
|
|
6484
|
-
gasUsed:
|
|
6485
|
-
from:
|
|
6486
|
-
to:
|
|
6487
|
-
effectiveGasPrice:
|
|
7208
|
+
var txResultOutput3 = z6.union([
|
|
7209
|
+
z6.object({
|
|
7210
|
+
status: z6.enum(["success", "reverted"]),
|
|
7211
|
+
hash: z6.string(),
|
|
7212
|
+
blockNumber: z6.number(),
|
|
7213
|
+
gasUsed: z6.string(),
|
|
7214
|
+
from: z6.string(),
|
|
7215
|
+
to: z6.string().nullable(),
|
|
7216
|
+
effectiveGasPrice: z6.string().optional()
|
|
6488
7217
|
}),
|
|
6489
|
-
|
|
6490
|
-
status:
|
|
6491
|
-
estimatedGas:
|
|
6492
|
-
simulationResult:
|
|
7218
|
+
z6.object({
|
|
7219
|
+
status: z6.literal("dry-run"),
|
|
7220
|
+
estimatedGas: z6.string(),
|
|
7221
|
+
simulationResult: z6.unknown()
|
|
6493
7222
|
})
|
|
6494
7223
|
]);
|
|
6495
7224
|
governance.command("vote", {
|
|
6496
7225
|
description: "Cast a governance vote on a proposal.",
|
|
6497
7226
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
6498
|
-
args:
|
|
6499
|
-
proposalId:
|
|
6500
|
-
support:
|
|
7227
|
+
args: z6.object({
|
|
7228
|
+
proposalId: z6.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
|
|
7229
|
+
support: z6.enum(["for", "against", "abstain"]).describe("Vote support: for, against, or abstain")
|
|
6501
7230
|
}),
|
|
6502
7231
|
options: writeOptions,
|
|
6503
7232
|
env: writeEnv,
|
|
6504
|
-
output:
|
|
6505
|
-
proposalId:
|
|
6506
|
-
proposalTitle:
|
|
6507
|
-
support:
|
|
6508
|
-
supportValue:
|
|
7233
|
+
output: z6.object({
|
|
7234
|
+
proposalId: z6.number(),
|
|
7235
|
+
proposalTitle: z6.string(),
|
|
7236
|
+
support: z6.enum(["for", "against", "abstain"]),
|
|
7237
|
+
supportValue: z6.number(),
|
|
6509
7238
|
tx: txResultOutput3
|
|
6510
7239
|
}),
|
|
6511
7240
|
examples: [
|
|
@@ -6585,22 +7314,22 @@ governance.command("propose", {
|
|
|
6585
7314
|
description: "Create a new council-originated governance proposal.",
|
|
6586
7315
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
6587
7316
|
options: writeOptions.extend({
|
|
6588
|
-
title:
|
|
6589
|
-
description:
|
|
6590
|
-
kind:
|
|
6591
|
-
category:
|
|
6592
|
-
"risk-tier":
|
|
6593
|
-
amount:
|
|
6594
|
-
recipient:
|
|
7317
|
+
title: z6.string().min(1).describe("Proposal title"),
|
|
7318
|
+
description: z6.string().min(1).describe("Proposal description"),
|
|
7319
|
+
kind: z6.coerce.number().int().nonnegative().max(255).describe("Proposal kind enum value"),
|
|
7320
|
+
category: z6.string().default("governance").describe("Forum category label for the proposal"),
|
|
7321
|
+
"risk-tier": z6.coerce.number().int().nonnegative().max(255).optional().describe("Optional max allowed intent risk tier (default: 0)"),
|
|
7322
|
+
amount: z6.string().optional().describe("Optional treasury amount hint (currently unsupported for intent encoding)"),
|
|
7323
|
+
recipient: z6.string().optional().describe("Optional treasury recipient hint (currently unsupported for intent encoding)")
|
|
6595
7324
|
}),
|
|
6596
7325
|
env: writeEnv,
|
|
6597
|
-
output:
|
|
6598
|
-
proposer:
|
|
6599
|
-
category:
|
|
6600
|
-
kind:
|
|
6601
|
-
title:
|
|
6602
|
-
description:
|
|
6603
|
-
expectedProposalId:
|
|
7326
|
+
output: z6.object({
|
|
7327
|
+
proposer: z6.string(),
|
|
7328
|
+
category: z6.string(),
|
|
7329
|
+
kind: z6.number(),
|
|
7330
|
+
title: z6.string(),
|
|
7331
|
+
description: z6.string(),
|
|
7332
|
+
expectedProposalId: z6.number(),
|
|
6604
7333
|
tx: txResultOutput3
|
|
6605
7334
|
}),
|
|
6606
7335
|
examples: [
|
|
@@ -6689,15 +7418,15 @@ governance.command("propose", {
|
|
|
6689
7418
|
governance.command("queue", {
|
|
6690
7419
|
description: "Finalize voting and queue an eligible proposal into timelock.",
|
|
6691
7420
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
6692
|
-
args:
|
|
6693
|
-
proposalId:
|
|
7421
|
+
args: z6.object({
|
|
7422
|
+
proposalId: z6.coerce.number().int().positive().describe("Proposal id (1-indexed)")
|
|
6694
7423
|
}),
|
|
6695
7424
|
options: writeOptions,
|
|
6696
7425
|
env: writeEnv,
|
|
6697
|
-
output:
|
|
6698
|
-
proposalId:
|
|
6699
|
-
proposalTitle:
|
|
6700
|
-
statusBefore:
|
|
7426
|
+
output: z6.object({
|
|
7427
|
+
proposalId: z6.number(),
|
|
7428
|
+
proposalTitle: z6.string(),
|
|
7429
|
+
statusBefore: z6.string(),
|
|
6701
7430
|
tx: txResultOutput3
|
|
6702
7431
|
}),
|
|
6703
7432
|
examples: [
|
|
@@ -6732,308 +7461,133 @@ governance.command("queue", {
|
|
|
6732
7461
|
retryable: false
|
|
6733
7462
|
});
|
|
6734
7463
|
}
|
|
6735
|
-
if (status.statusCode !== PROPOSAL_STATUS_ACTIVE) {
|
|
6736
|
-
return c.error({
|
|
6737
|
-
code: "PROPOSAL_NOT_QUEUEABLE",
|
|
6738
|
-
message: `Proposal ${c.args.proposalId} is ${status.status} and cannot be queued.`,
|
|
6739
|
-
retryable: false
|
|
6740
|
-
});
|
|
6741
|
-
}
|
|
6742
|
-
const latestBlock = await client.getBlock({ blockTag: "latest" });
|
|
6743
|
-
if (latestBlock.timestamp < proposal.voteEndAt) {
|
|
6744
|
-
return c.error({
|
|
6745
|
-
code: "VOTING_STILL_ACTIVE",
|
|
6746
|
-
message: `Proposal ${c.args.proposalId} voting window is still open (ends ${relTime(proposal.voteEndAt)}).`,
|
|
6747
|
-
retryable: false
|
|
6748
|
-
});
|
|
6749
|
-
}
|
|
6750
|
-
try {
|
|
6751
|
-
const txResult = await assemblyWriteTx({
|
|
6752
|
-
env: c.env,
|
|
6753
|
-
options: c.options,
|
|
6754
|
-
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
6755
|
-
abi: governanceAbi,
|
|
6756
|
-
functionName: "finalizeVote",
|
|
6757
|
-
args: [BigInt(c.args.proposalId)]
|
|
6758
|
-
});
|
|
6759
|
-
return c.ok({
|
|
6760
|
-
proposalId: c.args.proposalId,
|
|
6761
|
-
proposalTitle: proposal.title,
|
|
6762
|
-
statusBefore: status.status,
|
|
6763
|
-
tx: txResult
|
|
6764
|
-
});
|
|
6765
|
-
} catch (error) {
|
|
6766
|
-
if (error instanceof TxError2) {
|
|
6767
|
-
return c.error({
|
|
6768
|
-
code: error.code,
|
|
6769
|
-
message: error.message,
|
|
6770
|
-
retryable: error.code === "NONCE_CONFLICT"
|
|
6771
|
-
});
|
|
6772
|
-
}
|
|
6773
|
-
throw error;
|
|
6774
|
-
}
|
|
6775
|
-
}
|
|
6776
|
-
});
|
|
6777
|
-
governance.command("execute", {
|
|
6778
|
-
description: "Execute a queued governance proposal after timelock expiry.",
|
|
6779
|
-
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
6780
|
-
args: z4.object({
|
|
6781
|
-
proposalId: z4.coerce.number().int().positive().describe("Proposal id (1-indexed)")
|
|
6782
|
-
}),
|
|
6783
|
-
options: writeOptions,
|
|
6784
|
-
env: writeEnv,
|
|
6785
|
-
output: z4.object({
|
|
6786
|
-
proposalId: z4.number(),
|
|
6787
|
-
proposalTitle: z4.string(),
|
|
6788
|
-
timelockEndsAt: timestampOutput3,
|
|
6789
|
-
tx: txResultOutput3
|
|
6790
|
-
}),
|
|
6791
|
-
examples: [
|
|
6792
|
-
{
|
|
6793
|
-
args: { proposalId: 1 },
|
|
6794
|
-
description: "Execute proposal #1 after timelock has expired"
|
|
6795
|
-
}
|
|
6796
|
-
],
|
|
6797
|
-
async run(c) {
|
|
6798
|
-
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
6799
|
-
const proposalCount = await fetchProposalCount(client);
|
|
6800
|
-
if (c.args.proposalId > Number(proposalCount)) {
|
|
6801
|
-
return c.error({
|
|
6802
|
-
code: "OUT_OF_RANGE",
|
|
6803
|
-
message: `Proposal id ${c.args.proposalId} does not exist (proposalCount: ${proposalCount})`,
|
|
6804
|
-
retryable: false
|
|
6805
|
-
});
|
|
6806
|
-
}
|
|
6807
|
-
const proposal = await fetchProposalById(client, c.args.proposalId);
|
|
6808
|
-
const status = proposalStatus(proposal.status);
|
|
6809
|
-
if (status.statusCode !== PROPOSAL_STATUS_PASSED) {
|
|
6810
|
-
return c.error({
|
|
6811
|
-
code: "PROPOSAL_NOT_EXECUTABLE",
|
|
6812
|
-
message: `Proposal ${c.args.proposalId} is ${status.status} and cannot be executed.`,
|
|
6813
|
-
retryable: false
|
|
6814
|
-
});
|
|
6815
|
-
}
|
|
6816
|
-
const latestBlock = await client.getBlock({ blockTag: "latest" });
|
|
6817
|
-
if (latestBlock.timestamp < proposal.timelockEndsAt) {
|
|
6818
|
-
return c.error({
|
|
6819
|
-
code: "TIMELOCK_ACTIVE",
|
|
6820
|
-
message: `Proposal ${c.args.proposalId} timelock has not expired yet (ends ${relTime(proposal.timelockEndsAt)}).`,
|
|
6821
|
-
retryable: false
|
|
6822
|
-
});
|
|
6823
|
-
}
|
|
6824
|
-
try {
|
|
6825
|
-
const txResult = await assemblyWriteTx({
|
|
6826
|
-
env: c.env,
|
|
6827
|
-
options: c.options,
|
|
6828
|
-
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
6829
|
-
abi: governanceAbi,
|
|
6830
|
-
functionName: "executeProposal",
|
|
6831
|
-
args: [BigInt(c.args.proposalId)]
|
|
6832
|
-
});
|
|
6833
|
-
return c.ok({
|
|
6834
|
-
proposalId: c.args.proposalId,
|
|
6835
|
-
proposalTitle: proposal.title,
|
|
6836
|
-
timelockEndsAt: timeValue(proposal.timelockEndsAt, c.format),
|
|
6837
|
-
tx: txResult
|
|
6838
|
-
});
|
|
6839
|
-
} catch (error) {
|
|
6840
|
-
if (error instanceof TxError2) {
|
|
6841
|
-
return c.error({
|
|
6842
|
-
code: error.code,
|
|
6843
|
-
message: error.message,
|
|
6844
|
-
retryable: error.code === "NONCE_CONFLICT"
|
|
6845
|
-
});
|
|
6846
|
-
}
|
|
6847
|
-
throw error;
|
|
6848
|
-
}
|
|
6849
|
-
}
|
|
6850
|
-
});
|
|
6851
|
-
|
|
6852
|
-
// src/commands/members.ts
|
|
6853
|
-
import { TxError as TxError3 } from "@spectratools/tx-shared";
|
|
6854
|
-
import { Cli as Cli4, z as z6 } from "incur";
|
|
6855
|
-
|
|
6856
|
-
// src/services/members.ts
|
|
6857
|
-
import { z as z5 } from "incur";
|
|
6858
|
-
var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
|
|
6859
|
-
var REGISTERED_EVENT_SCAN_STEP = 100000n;
|
|
6860
|
-
var REGISTERED_EVENT_SCAN_TIMEOUT_MS = 2e4;
|
|
6861
|
-
var memberSnapshotEntrySchema = z5.union([
|
|
6862
|
-
z5.string(),
|
|
6863
|
-
z5.object({
|
|
6864
|
-
address: z5.string(),
|
|
6865
|
-
ens: z5.string().optional(),
|
|
6866
|
-
name: z5.string().optional()
|
|
6867
|
-
})
|
|
6868
|
-
]);
|
|
6869
|
-
var memberSnapshotSchema = z5.array(memberSnapshotEntrySchema);
|
|
6870
|
-
var AssemblyApiValidationError = class extends Error {
|
|
6871
|
-
constructor(details) {
|
|
6872
|
-
super("Assembly API response validation failed");
|
|
6873
|
-
this.details = details;
|
|
6874
|
-
this.name = "AssemblyApiValidationError";
|
|
6875
|
-
}
|
|
6876
|
-
};
|
|
6877
|
-
var AssemblyIndexerUnavailableError = class extends Error {
|
|
6878
|
-
constructor(details) {
|
|
6879
|
-
super("Assembly indexer unavailable");
|
|
6880
|
-
this.details = details;
|
|
6881
|
-
this.name = "AssemblyIndexerUnavailableError";
|
|
6882
|
-
}
|
|
6883
|
-
};
|
|
6884
|
-
function memberSnapshotEntryToIdentity(entry) {
|
|
6885
|
-
if (typeof entry === "string") return { address: entry };
|
|
6886
|
-
const identity = { address: entry.address };
|
|
6887
|
-
if (entry.ens !== void 0) identity.ens = entry.ens;
|
|
6888
|
-
if (entry.name !== void 0) identity.name = entry.name;
|
|
6889
|
-
return identity;
|
|
6890
|
-
}
|
|
6891
|
-
function mergeMemberIdentities(entries) {
|
|
6892
|
-
const byAddress = /* @__PURE__ */ new Map();
|
|
6893
|
-
for (const entry of entries) {
|
|
6894
|
-
const key = entry.address.toLowerCase();
|
|
6895
|
-
const existing = byAddress.get(key);
|
|
6896
|
-
if (!existing) {
|
|
6897
|
-
byAddress.set(key, entry);
|
|
6898
|
-
continue;
|
|
6899
|
-
}
|
|
6900
|
-
const merged = { address: existing.address };
|
|
6901
|
-
const ens = existing.ens ?? entry.ens;
|
|
6902
|
-
const name = existing.name ?? entry.name;
|
|
6903
|
-
if (ens !== void 0) merged.ens = ens;
|
|
6904
|
-
if (name !== void 0) merged.name = name;
|
|
6905
|
-
byAddress.set(key, merged);
|
|
6906
|
-
}
|
|
6907
|
-
return [...byAddress.values()];
|
|
6908
|
-
}
|
|
6909
|
-
async function memberSnapshot(url) {
|
|
6910
|
-
let res;
|
|
6911
|
-
try {
|
|
6912
|
-
res = await fetch(url);
|
|
6913
|
-
} catch (error) {
|
|
6914
|
-
throw new AssemblyIndexerUnavailableError({
|
|
6915
|
-
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
6916
|
-
url,
|
|
6917
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
6918
|
-
});
|
|
6919
|
-
}
|
|
6920
|
-
if (!res.ok) {
|
|
6921
|
-
throw new AssemblyIndexerUnavailableError({
|
|
6922
|
-
code: "ASSEMBLY_INDEXER_UNAVAILABLE",
|
|
6923
|
-
url,
|
|
6924
|
-
status: res.status,
|
|
6925
|
-
statusText: res.statusText
|
|
6926
|
-
});
|
|
6927
|
-
}
|
|
6928
|
-
const json = await res.json();
|
|
6929
|
-
const parsed = memberSnapshotSchema.safeParse(json);
|
|
6930
|
-
if (parsed.success) {
|
|
6931
|
-
return mergeMemberIdentities(parsed.data.map(memberSnapshotEntryToIdentity));
|
|
6932
|
-
}
|
|
6933
|
-
throw new AssemblyApiValidationError({
|
|
6934
|
-
code: "INVALID_ASSEMBLY_API_RESPONSE",
|
|
6935
|
-
url,
|
|
6936
|
-
issues: parsed.error.issues,
|
|
6937
|
-
response: json
|
|
6938
|
-
});
|
|
6939
|
-
}
|
|
6940
|
-
async function withTimeout(promise, timeoutMs, timeoutMessage) {
|
|
6941
|
-
let timer;
|
|
6942
|
-
try {
|
|
6943
|
-
return await Promise.race([
|
|
6944
|
-
promise,
|
|
6945
|
-
new Promise((_, reject) => {
|
|
6946
|
-
timer = setTimeout(() => {
|
|
6947
|
-
reject(new Error(timeoutMessage));
|
|
6948
|
-
}, timeoutMs);
|
|
6949
|
-
})
|
|
6950
|
-
]);
|
|
6951
|
-
} finally {
|
|
6952
|
-
if (timer) clearTimeout(timer);
|
|
6953
|
-
}
|
|
6954
|
-
}
|
|
6955
|
-
async function membersFromRegisteredEvents(client) {
|
|
6956
|
-
const latestBlock = await client.getBlockNumber();
|
|
6957
|
-
const addresses = /* @__PURE__ */ new Set();
|
|
6958
|
-
for (let fromBlock = ABSTRACT_MAINNET_DEPLOYMENT_BLOCKS.registry; fromBlock <= latestBlock; fromBlock += REGISTERED_EVENT_SCAN_STEP) {
|
|
6959
|
-
const toBlock = fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n > latestBlock ? latestBlock : fromBlock + REGISTERED_EVENT_SCAN_STEP - 1n;
|
|
6960
|
-
const events = await client.getContractEvents({
|
|
6961
|
-
abi: registryAbi,
|
|
6962
|
-
address: ABSTRACT_MAINNET_ADDRESSES.registry,
|
|
6963
|
-
eventName: "Registered",
|
|
6964
|
-
fromBlock,
|
|
6965
|
-
toBlock,
|
|
6966
|
-
strict: true
|
|
6967
|
-
});
|
|
6968
|
-
for (const event of events) {
|
|
6969
|
-
const member = event.args.member;
|
|
6970
|
-
if (typeof member === "string") {
|
|
6971
|
-
addresses.add(member);
|
|
6972
|
-
}
|
|
7464
|
+
if (status.statusCode !== PROPOSAL_STATUS_ACTIVE) {
|
|
7465
|
+
return c.error({
|
|
7466
|
+
code: "PROPOSAL_NOT_QUEUEABLE",
|
|
7467
|
+
message: `Proposal ${c.args.proposalId} is ${status.status} and cannot be queued.`,
|
|
7468
|
+
retryable: false
|
|
7469
|
+
});
|
|
6973
7470
|
}
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
} catch (error) {
|
|
6982
|
-
if (error instanceof AssemblyApiValidationError) {
|
|
6983
|
-
throw error;
|
|
7471
|
+
const latestBlock = await client.getBlock({ blockTag: "latest" });
|
|
7472
|
+
if (latestBlock.timestamp < proposal.voteEndAt) {
|
|
7473
|
+
return c.error({
|
|
7474
|
+
code: "VOTING_STILL_ACTIVE",
|
|
7475
|
+
message: `Proposal ${c.args.proposalId} voting window is still open (ends ${relTime(proposal.voteEndAt)}).`,
|
|
7476
|
+
retryable: false
|
|
7477
|
+
});
|
|
6984
7478
|
}
|
|
6985
|
-
|
|
7479
|
+
try {
|
|
7480
|
+
const txResult = await assemblyWriteTx({
|
|
7481
|
+
env: c.env,
|
|
7482
|
+
options: c.options,
|
|
7483
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
7484
|
+
abi: governanceAbi,
|
|
7485
|
+
functionName: "finalizeVote",
|
|
7486
|
+
args: [BigInt(c.args.proposalId)]
|
|
7487
|
+
});
|
|
7488
|
+
return c.ok({
|
|
7489
|
+
proposalId: c.args.proposalId,
|
|
7490
|
+
proposalTitle: proposal.title,
|
|
7491
|
+
statusBefore: status.status,
|
|
7492
|
+
tx: txResult
|
|
7493
|
+
});
|
|
7494
|
+
} catch (error) {
|
|
7495
|
+
if (error instanceof TxError2) {
|
|
7496
|
+
return c.error({
|
|
7497
|
+
code: error.code,
|
|
7498
|
+
message: error.message,
|
|
7499
|
+
retryable: error.code === "NONCE_CONFLICT"
|
|
7500
|
+
});
|
|
7501
|
+
}
|
|
6986
7502
|
throw error;
|
|
6987
7503
|
}
|
|
6988
|
-
const fallbackMembers = await withTimeout(
|
|
6989
|
-
membersFromRegisteredEvents(client),
|
|
6990
|
-
REGISTERED_EVENT_SCAN_TIMEOUT_MS,
|
|
6991
|
-
`Registered event fallback scan timed out after ${REGISTERED_EVENT_SCAN_TIMEOUT_MS}ms`
|
|
6992
|
-
);
|
|
6993
|
-
return {
|
|
6994
|
-
members: mergeMemberIdentities(fallbackMembers),
|
|
6995
|
-
fallbackReason: error.details
|
|
6996
|
-
};
|
|
6997
7504
|
}
|
|
6998
|
-
}
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7505
|
+
});
|
|
7506
|
+
governance.command("execute", {
|
|
7507
|
+
description: "Execute a queued governance proposal after timelock expiry.",
|
|
7508
|
+
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
7509
|
+
args: z6.object({
|
|
7510
|
+
proposalId: z6.coerce.number().int().positive().describe("Proposal id (1-indexed)")
|
|
7511
|
+
}),
|
|
7512
|
+
options: writeOptions,
|
|
7513
|
+
env: writeEnv,
|
|
7514
|
+
output: z6.object({
|
|
7515
|
+
proposalId: z6.number(),
|
|
7516
|
+
proposalTitle: z6.string(),
|
|
7517
|
+
timelockEndsAt: timestampOutput3,
|
|
7518
|
+
tx: txResultOutput3
|
|
7519
|
+
}),
|
|
7520
|
+
examples: [
|
|
7008
7521
|
{
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
functionName: "members",
|
|
7012
|
-
args: [address]
|
|
7522
|
+
args: { proposalId: 1 },
|
|
7523
|
+
description: "Execute proposal #1 after timelock has expired"
|
|
7013
7524
|
}
|
|
7014
|
-
]
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
const
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7525
|
+
],
|
|
7526
|
+
async run(c) {
|
|
7527
|
+
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
7528
|
+
const proposalCount = await fetchProposalCount(client);
|
|
7529
|
+
if (c.args.proposalId > Number(proposalCount)) {
|
|
7530
|
+
return c.error({
|
|
7531
|
+
code: "OUT_OF_RANGE",
|
|
7532
|
+
message: `Proposal id ${c.args.proposalId} does not exist (proposalCount: ${proposalCount})`,
|
|
7533
|
+
retryable: false
|
|
7534
|
+
});
|
|
7535
|
+
}
|
|
7536
|
+
const proposal = await fetchProposalById(client, c.args.proposalId);
|
|
7537
|
+
const status = proposalStatus(proposal.status);
|
|
7538
|
+
if (status.statusCode !== PROPOSAL_STATUS_PASSED) {
|
|
7539
|
+
return c.error({
|
|
7540
|
+
code: "PROPOSAL_NOT_EXECUTABLE",
|
|
7541
|
+
message: `Proposal ${c.args.proposalId} is ${status.status} and cannot be executed.`,
|
|
7542
|
+
retryable: false
|
|
7543
|
+
});
|
|
7544
|
+
}
|
|
7545
|
+
const latestBlock = await client.getBlock({ blockTag: "latest" });
|
|
7546
|
+
if (latestBlock.timestamp < proposal.timelockEndsAt) {
|
|
7547
|
+
return c.error({
|
|
7548
|
+
code: "TIMELOCK_ACTIVE",
|
|
7549
|
+
message: `Proposal ${c.args.proposalId} timelock has not expired yet (ends ${relTime(proposal.timelockEndsAt)}).`,
|
|
7550
|
+
retryable: false
|
|
7551
|
+
});
|
|
7552
|
+
}
|
|
7553
|
+
try {
|
|
7554
|
+
const txResult = await assemblyWriteTx({
|
|
7555
|
+
env: c.env,
|
|
7556
|
+
options: c.options,
|
|
7557
|
+
address: ABSTRACT_MAINNET_ADDRESSES.governance,
|
|
7558
|
+
abi: governanceAbi,
|
|
7559
|
+
functionName: "executeProposal",
|
|
7560
|
+
args: [BigInt(c.args.proposalId)]
|
|
7561
|
+
});
|
|
7562
|
+
return c.ok({
|
|
7563
|
+
proposalId: c.args.proposalId,
|
|
7564
|
+
proposalTitle: proposal.title,
|
|
7565
|
+
timelockEndsAt: timeValue(proposal.timelockEndsAt, c.format),
|
|
7566
|
+
tx: txResult
|
|
7567
|
+
});
|
|
7568
|
+
} catch (error) {
|
|
7569
|
+
if (error instanceof TxError2) {
|
|
7570
|
+
return c.error({
|
|
7571
|
+
code: error.code,
|
|
7572
|
+
message: error.message,
|
|
7573
|
+
retryable: error.code === "NONCE_CONFLICT"
|
|
7574
|
+
});
|
|
7575
|
+
}
|
|
7576
|
+
throw error;
|
|
7577
|
+
}
|
|
7578
|
+
}
|
|
7579
|
+
});
|
|
7028
7580
|
|
|
7029
7581
|
// src/commands/members.ts
|
|
7582
|
+
import { TxError as TxError3 } from "@spectratools/tx-shared";
|
|
7583
|
+
import { Cli as Cli4, z as z7 } from "incur";
|
|
7030
7584
|
var DEFAULT_MEMBER_SNAPSHOT_URL2 = "https://www.theaiassembly.org/api/indexer/members";
|
|
7031
7585
|
var MAX_MEMBER_LOOKUP_SUGGESTIONS = 5;
|
|
7032
|
-
var env4 =
|
|
7033
|
-
ABSTRACT_RPC_URL:
|
|
7034
|
-
ASSEMBLY_INDEXER_URL:
|
|
7586
|
+
var env4 = z7.object({
|
|
7587
|
+
ABSTRACT_RPC_URL: z7.string().optional().describe("Abstract RPC URL override"),
|
|
7588
|
+
ASSEMBLY_INDEXER_URL: z7.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
|
|
7035
7589
|
});
|
|
7036
|
-
var timestampOutput4 =
|
|
7590
|
+
var timestampOutput4 = z7.union([z7.number(), z7.string()]);
|
|
7037
7591
|
function matchableAddressInput(query) {
|
|
7038
7592
|
return query.startsWith("0x") && query.length === 42;
|
|
7039
7593
|
}
|
|
@@ -7079,19 +7633,19 @@ var members = Cli4.create("members", {
|
|
|
7079
7633
|
members.command("list", {
|
|
7080
7634
|
description: "List members from an indexer snapshot (or Registered event fallback) plus on-chain active state.",
|
|
7081
7635
|
env: env4,
|
|
7082
|
-
output:
|
|
7083
|
-
members:
|
|
7084
|
-
|
|
7085
|
-
address:
|
|
7086
|
-
active:
|
|
7087
|
-
registered:
|
|
7636
|
+
output: z7.object({
|
|
7637
|
+
members: z7.array(
|
|
7638
|
+
z7.object({
|
|
7639
|
+
address: z7.string(),
|
|
7640
|
+
active: z7.boolean(),
|
|
7641
|
+
registered: z7.boolean(),
|
|
7088
7642
|
activeUntil: timestampOutput4,
|
|
7089
|
-
activeUntilRelative:
|
|
7643
|
+
activeUntilRelative: z7.string(),
|
|
7090
7644
|
lastHeartbeatAt: timestampOutput4,
|
|
7091
|
-
lastHeartbeatRelative:
|
|
7645
|
+
lastHeartbeatRelative: z7.string()
|
|
7092
7646
|
})
|
|
7093
7647
|
),
|
|
7094
|
-
count:
|
|
7648
|
+
count: z7.number()
|
|
7095
7649
|
}),
|
|
7096
7650
|
examples: [
|
|
7097
7651
|
{ description: "List members using default indexer snapshot" },
|
|
@@ -7145,17 +7699,17 @@ members.command("list", {
|
|
|
7145
7699
|
});
|
|
7146
7700
|
members.command("info", {
|
|
7147
7701
|
description: "Get member registry record and active status by full address, partial address, ENS, or name.",
|
|
7148
|
-
args:
|
|
7149
|
-
address:
|
|
7702
|
+
args: z7.object({
|
|
7703
|
+
address: z7.string().describe("Member lookup query (full/partial address, ENS, or name metadata)")
|
|
7150
7704
|
}),
|
|
7151
7705
|
env: env4,
|
|
7152
|
-
output:
|
|
7153
|
-
address:
|
|
7154
|
-
active:
|
|
7706
|
+
output: z7.object({
|
|
7707
|
+
address: z7.string(),
|
|
7708
|
+
active: z7.boolean(),
|
|
7155
7709
|
activeUntil: timestampOutput4,
|
|
7156
7710
|
lastHeartbeatAt: timestampOutput4,
|
|
7157
|
-
activeUntilRelative:
|
|
7158
|
-
lastHeartbeatRelative:
|
|
7711
|
+
activeUntilRelative: z7.string(),
|
|
7712
|
+
lastHeartbeatRelative: z7.string()
|
|
7159
7713
|
}),
|
|
7160
7714
|
examples: [
|
|
7161
7715
|
{
|
|
@@ -7240,9 +7794,9 @@ members.command("info", {
|
|
|
7240
7794
|
members.command("count", {
|
|
7241
7795
|
description: "Get active and total-known member counts from Registry.",
|
|
7242
7796
|
env: env4,
|
|
7243
|
-
output:
|
|
7244
|
-
active:
|
|
7245
|
-
total:
|
|
7797
|
+
output: z7.object({
|
|
7798
|
+
active: z7.number(),
|
|
7799
|
+
total: z7.number()
|
|
7246
7800
|
}),
|
|
7247
7801
|
examples: [{ description: "Count active and known members" }],
|
|
7248
7802
|
async run(c) {
|
|
@@ -7265,12 +7819,12 @@ members.command("count", {
|
|
|
7265
7819
|
members.command("fees", {
|
|
7266
7820
|
description: "Get registration and heartbeat fee settings.",
|
|
7267
7821
|
env: env4,
|
|
7268
|
-
output:
|
|
7269
|
-
registrationFeeWei:
|
|
7270
|
-
registrationFee:
|
|
7271
|
-
heartbeatFeeWei:
|
|
7272
|
-
heartbeatFee:
|
|
7273
|
-
heartbeatGracePeriodSeconds:
|
|
7822
|
+
output: z7.object({
|
|
7823
|
+
registrationFeeWei: z7.string(),
|
|
7824
|
+
registrationFee: z7.string(),
|
|
7825
|
+
heartbeatFeeWei: z7.string(),
|
|
7826
|
+
heartbeatFee: z7.string(),
|
|
7827
|
+
heartbeatGracePeriodSeconds: z7.number()
|
|
7274
7828
|
}),
|
|
7275
7829
|
examples: [{ description: "Inspect current registry fee configuration" }],
|
|
7276
7830
|
async run(c) {
|
|
@@ -7301,24 +7855,24 @@ members.command("fees", {
|
|
|
7301
7855
|
});
|
|
7302
7856
|
}
|
|
7303
7857
|
});
|
|
7304
|
-
var txOutputSchema =
|
|
7305
|
-
|
|
7306
|
-
status:
|
|
7307
|
-
hash:
|
|
7308
|
-
blockNumber:
|
|
7309
|
-
gasUsed:
|
|
7310
|
-
from:
|
|
7311
|
-
to:
|
|
7312
|
-
effectiveGasPrice:
|
|
7313
|
-
fee:
|
|
7314
|
-
feeEth:
|
|
7858
|
+
var txOutputSchema = z7.union([
|
|
7859
|
+
z7.object({
|
|
7860
|
+
status: z7.enum(["success", "reverted"]),
|
|
7861
|
+
hash: z7.string(),
|
|
7862
|
+
blockNumber: z7.number(),
|
|
7863
|
+
gasUsed: z7.string(),
|
|
7864
|
+
from: z7.string(),
|
|
7865
|
+
to: z7.string().nullable(),
|
|
7866
|
+
effectiveGasPrice: z7.string().optional(),
|
|
7867
|
+
fee: z7.string(),
|
|
7868
|
+
feeEth: z7.string()
|
|
7315
7869
|
}),
|
|
7316
|
-
|
|
7317
|
-
status:
|
|
7318
|
-
estimatedGas:
|
|
7319
|
-
simulationResult:
|
|
7320
|
-
fee:
|
|
7321
|
-
feeEth:
|
|
7870
|
+
z7.object({
|
|
7871
|
+
status: z7.literal("dry-run"),
|
|
7872
|
+
estimatedGas: z7.string(),
|
|
7873
|
+
simulationResult: z7.unknown(),
|
|
7874
|
+
fee: z7.string(),
|
|
7875
|
+
feeEth: z7.string()
|
|
7322
7876
|
})
|
|
7323
7877
|
]);
|
|
7324
7878
|
members.command("register", {
|
|
@@ -7475,49 +8029,109 @@ members.command("renew", {
|
|
|
7475
8029
|
}
|
|
7476
8030
|
});
|
|
7477
8031
|
|
|
8032
|
+
// src/commands/seats.ts
|
|
8033
|
+
import { Cli as Cli5, z as z8 } from "incur";
|
|
8034
|
+
var env5 = z8.object({
|
|
8035
|
+
ABSTRACT_RPC_URL: z8.string().optional().describe("Abstract RPC URL override")
|
|
8036
|
+
});
|
|
8037
|
+
var timestampOutput5 = z8.union([z8.number(), z8.string()]);
|
|
8038
|
+
function decodeSeat2(value) {
|
|
8039
|
+
const [owner, startAt, endAt, forfeited] = value;
|
|
8040
|
+
return { owner, startAt, endAt, forfeited };
|
|
8041
|
+
}
|
|
8042
|
+
var seats = Cli5.create("seats", {
|
|
8043
|
+
description: "Council seat aliases (compatibility shim for council seats)."
|
|
8044
|
+
});
|
|
8045
|
+
seats.command("list", {
|
|
8046
|
+
description: "List all council seats and their occupancy windows (alias for council seats).",
|
|
8047
|
+
env: env5,
|
|
8048
|
+
output: z8.array(
|
|
8049
|
+
z8.object({
|
|
8050
|
+
id: z8.number(),
|
|
8051
|
+
owner: z8.string(),
|
|
8052
|
+
startAt: timestampOutput5,
|
|
8053
|
+
startAtRelative: z8.string(),
|
|
8054
|
+
endAt: timestampOutput5,
|
|
8055
|
+
endAtRelative: z8.string(),
|
|
8056
|
+
forfeited: z8.boolean()
|
|
8057
|
+
})
|
|
8058
|
+
),
|
|
8059
|
+
examples: [{ description: "List all council seats" }],
|
|
8060
|
+
async run(c) {
|
|
8061
|
+
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
8062
|
+
const count = await client.readContract({
|
|
8063
|
+
abi: councilSeatsAbi,
|
|
8064
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
8065
|
+
functionName: "seatCount"
|
|
8066
|
+
});
|
|
8067
|
+
const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i));
|
|
8068
|
+
const seatTuples = ids.length ? await client.multicall({
|
|
8069
|
+
allowFailure: false,
|
|
8070
|
+
contracts: ids.map((id) => ({
|
|
8071
|
+
abi: councilSeatsAbi,
|
|
8072
|
+
address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
|
|
8073
|
+
functionName: "seats",
|
|
8074
|
+
args: [id]
|
|
8075
|
+
}))
|
|
8076
|
+
}) : [];
|
|
8077
|
+
const seatList = seatTuples.map(decodeSeat2);
|
|
8078
|
+
return c.ok(
|
|
8079
|
+
seatList.map((seat, idx) => ({
|
|
8080
|
+
id: idx,
|
|
8081
|
+
owner: toChecksum(seat.owner),
|
|
8082
|
+
startAt: timeValue(seat.startAt, c.format),
|
|
8083
|
+
startAtRelative: relTime(seat.startAt),
|
|
8084
|
+
endAt: timeValue(seat.endAt, c.format),
|
|
8085
|
+
endAtRelative: relTime(seat.endAt),
|
|
8086
|
+
forfeited: seat.forfeited
|
|
8087
|
+
}))
|
|
8088
|
+
);
|
|
8089
|
+
}
|
|
8090
|
+
});
|
|
8091
|
+
|
|
7478
8092
|
// src/commands/treasury.ts
|
|
7479
8093
|
import { TxError as TxError4 } from "@spectratools/tx-shared";
|
|
7480
|
-
import { Cli as
|
|
8094
|
+
import { Cli as Cli6, z as z9 } from "incur";
|
|
7481
8095
|
import { encodeAbiParameters, parseUnits, zeroAddress } from "viem";
|
|
7482
|
-
var
|
|
7483
|
-
ABSTRACT_RPC_URL:
|
|
8096
|
+
var env6 = z9.object({
|
|
8097
|
+
ABSTRACT_RPC_URL: z9.string().optional().describe("Abstract RPC URL override")
|
|
7484
8098
|
});
|
|
7485
|
-
var
|
|
7486
|
-
var txResultOutput4 =
|
|
7487
|
-
|
|
7488
|
-
status:
|
|
7489
|
-
hash:
|
|
7490
|
-
blockNumber:
|
|
7491
|
-
gasUsed:
|
|
7492
|
-
from:
|
|
7493
|
-
to:
|
|
7494
|
-
effectiveGasPrice:
|
|
8099
|
+
var timestampOutput6 = z9.union([z9.number(), z9.string()]);
|
|
8100
|
+
var txResultOutput4 = z9.union([
|
|
8101
|
+
z9.object({
|
|
8102
|
+
status: z9.literal("success"),
|
|
8103
|
+
hash: z9.string(),
|
|
8104
|
+
blockNumber: z9.number(),
|
|
8105
|
+
gasUsed: z9.string(),
|
|
8106
|
+
from: z9.string(),
|
|
8107
|
+
to: z9.string().nullable(),
|
|
8108
|
+
effectiveGasPrice: z9.string().optional()
|
|
7495
8109
|
}),
|
|
7496
|
-
|
|
7497
|
-
status:
|
|
7498
|
-
hash:
|
|
7499
|
-
blockNumber:
|
|
7500
|
-
gasUsed:
|
|
7501
|
-
from:
|
|
7502
|
-
to:
|
|
7503
|
-
effectiveGasPrice:
|
|
8110
|
+
z9.object({
|
|
8111
|
+
status: z9.literal("reverted"),
|
|
8112
|
+
hash: z9.string(),
|
|
8113
|
+
blockNumber: z9.number(),
|
|
8114
|
+
gasUsed: z9.string(),
|
|
8115
|
+
from: z9.string(),
|
|
8116
|
+
to: z9.string().nullable(),
|
|
8117
|
+
effectiveGasPrice: z9.string().optional()
|
|
7504
8118
|
}),
|
|
7505
|
-
|
|
7506
|
-
status:
|
|
7507
|
-
estimatedGas:
|
|
7508
|
-
simulationResult:
|
|
8119
|
+
z9.object({
|
|
8120
|
+
status: z9.literal("dry-run"),
|
|
8121
|
+
estimatedGas: z9.string(),
|
|
8122
|
+
simulationResult: z9.unknown()
|
|
7509
8123
|
})
|
|
7510
8124
|
]);
|
|
7511
|
-
var treasury =
|
|
8125
|
+
var treasury = Cli6.create("treasury", {
|
|
7512
8126
|
description: "Inspect treasury balances, execution status, and spend controls."
|
|
7513
8127
|
});
|
|
7514
8128
|
treasury.command("balance", {
|
|
7515
8129
|
description: "Get current native token balance for the treasury contract.",
|
|
7516
|
-
env:
|
|
7517
|
-
output:
|
|
7518
|
-
address:
|
|
7519
|
-
balanceWei:
|
|
7520
|
-
balance:
|
|
8130
|
+
env: env6,
|
|
8131
|
+
output: z9.object({
|
|
8132
|
+
address: z9.string(),
|
|
8133
|
+
balanceWei: z9.string(),
|
|
8134
|
+
balance: z9.string()
|
|
7521
8135
|
}),
|
|
7522
8136
|
examples: [{ description: "Check treasury balance" }],
|
|
7523
8137
|
async run(c) {
|
|
@@ -7532,13 +8146,13 @@ treasury.command("balance", {
|
|
|
7532
8146
|
});
|
|
7533
8147
|
treasury.command("whitelist", {
|
|
7534
8148
|
description: "Check whether an asset address is treasury-whitelisted.",
|
|
7535
|
-
args:
|
|
7536
|
-
asset:
|
|
8149
|
+
args: z9.object({
|
|
8150
|
+
asset: z9.string().describe("Token/asset contract address")
|
|
7537
8151
|
}),
|
|
7538
|
-
env:
|
|
7539
|
-
output:
|
|
7540
|
-
asset:
|
|
7541
|
-
whitelisted:
|
|
8152
|
+
env: env6,
|
|
8153
|
+
output: z9.object({
|
|
8154
|
+
asset: z9.string(),
|
|
8155
|
+
whitelisted: z9.boolean()
|
|
7542
8156
|
}),
|
|
7543
8157
|
examples: [
|
|
7544
8158
|
{
|
|
@@ -7559,12 +8173,12 @@ treasury.command("whitelist", {
|
|
|
7559
8173
|
});
|
|
7560
8174
|
treasury.command("major-spend-status", {
|
|
7561
8175
|
description: "Read major-spend cooldown status for the treasury contract.",
|
|
7562
|
-
env:
|
|
7563
|
-
output:
|
|
7564
|
-
majorSpendCooldownSeconds:
|
|
7565
|
-
lastMajorSpendAt:
|
|
7566
|
-
lastMajorSpendRelative:
|
|
7567
|
-
isMajorSpendAllowed:
|
|
8176
|
+
env: env6,
|
|
8177
|
+
output: z9.object({
|
|
8178
|
+
majorSpendCooldownSeconds: z9.number(),
|
|
8179
|
+
lastMajorSpendAt: timestampOutput6,
|
|
8180
|
+
lastMajorSpendRelative: z9.string(),
|
|
8181
|
+
isMajorSpendAllowed: z9.boolean()
|
|
7568
8182
|
}),
|
|
7569
8183
|
examples: [{ description: "Inspect treasury major-spend guardrails" }],
|
|
7570
8184
|
async run(c) {
|
|
@@ -7598,13 +8212,13 @@ treasury.command("major-spend-status", {
|
|
|
7598
8212
|
});
|
|
7599
8213
|
treasury.command("executed", {
|
|
7600
8214
|
description: "Check whether a treasury action for a proposal has executed.",
|
|
7601
|
-
args:
|
|
7602
|
-
proposalId:
|
|
8215
|
+
args: z9.object({
|
|
8216
|
+
proposalId: z9.coerce.number().int().positive().describe("Governance proposal id")
|
|
7603
8217
|
}),
|
|
7604
|
-
env:
|
|
7605
|
-
output:
|
|
7606
|
-
proposalId:
|
|
7607
|
-
executed:
|
|
8218
|
+
env: env6,
|
|
8219
|
+
output: z9.object({
|
|
8220
|
+
proposalId: z9.number(),
|
|
8221
|
+
executed: z9.boolean()
|
|
7608
8222
|
}),
|
|
7609
8223
|
examples: [{ args: { proposalId: 1 }, description: "Check execution status for proposal #1" }],
|
|
7610
8224
|
async run(c) {
|
|
@@ -7634,25 +8248,25 @@ treasury.command("propose-spend", {
|
|
|
7634
8248
|
description: "Create a council proposal that spends treasury funds via TreasuryTransferIntentModule.",
|
|
7635
8249
|
hint: "Requires PRIVATE_KEY environment variable for signing.",
|
|
7636
8250
|
options: writeOptions.extend({
|
|
7637
|
-
token:
|
|
7638
|
-
recipient:
|
|
7639
|
-
amount:
|
|
7640
|
-
decimals:
|
|
7641
|
-
title:
|
|
7642
|
-
description:
|
|
7643
|
-
category:
|
|
7644
|
-
"risk-tier":
|
|
8251
|
+
token: z9.string().describe("Token address to spend (use 0x0000000000000000000000000000000000000000 for ETH)"),
|
|
8252
|
+
recipient: z9.string().describe("Recipient address"),
|
|
8253
|
+
amount: z9.string().describe("Token amount as decimal string (human units)"),
|
|
8254
|
+
decimals: z9.coerce.number().int().min(0).max(36).default(18).describe("Token decimals used to parse --amount (default: 18)"),
|
|
8255
|
+
title: z9.string().min(1).describe("Proposal title"),
|
|
8256
|
+
description: z9.string().min(1).describe("Proposal description"),
|
|
8257
|
+
category: z9.string().default("treasury").describe("Forum category label for this proposal"),
|
|
8258
|
+
"risk-tier": z9.coerce.number().int().min(0).max(3).default(3).describe("Max allowed risk tier in intent constraints (0-3, default: 3)")
|
|
7645
8259
|
}),
|
|
7646
8260
|
env: writeEnv,
|
|
7647
|
-
output:
|
|
7648
|
-
proposer:
|
|
7649
|
-
category:
|
|
7650
|
-
token:
|
|
7651
|
-
recipient:
|
|
7652
|
-
amount:
|
|
7653
|
-
amountWei:
|
|
7654
|
-
expectedProposalId:
|
|
7655
|
-
expectedThreadId:
|
|
8261
|
+
output: z9.object({
|
|
8262
|
+
proposer: z9.string(),
|
|
8263
|
+
category: z9.string(),
|
|
8264
|
+
token: z9.string(),
|
|
8265
|
+
recipient: z9.string(),
|
|
8266
|
+
amount: z9.string(),
|
|
8267
|
+
amountWei: z9.string(),
|
|
8268
|
+
expectedProposalId: z9.number(),
|
|
8269
|
+
expectedThreadId: z9.number(),
|
|
7656
8270
|
tx: txResultOutput4
|
|
7657
8271
|
}),
|
|
7658
8272
|
examples: [
|
|
@@ -7947,33 +8561,35 @@ function applyFriendlyErrorHandling(cli2) {
|
|
|
7947
8561
|
// src/cli.ts
|
|
7948
8562
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7949
8563
|
var pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
|
|
7950
|
-
var cli =
|
|
8564
|
+
var cli = Cli7.create("assembly", {
|
|
7951
8565
|
version: pkg.version,
|
|
7952
8566
|
description: "Assembly governance CLI for Abstract chain."
|
|
7953
8567
|
});
|
|
7954
8568
|
cli.command(members);
|
|
7955
8569
|
cli.command(council);
|
|
8570
|
+
cli.command(seats);
|
|
7956
8571
|
cli.command(forum);
|
|
7957
8572
|
cli.command(governance);
|
|
7958
8573
|
cli.command(treasury);
|
|
7959
|
-
|
|
7960
|
-
|
|
8574
|
+
registerDigestCommand(cli);
|
|
8575
|
+
var rootEnv = z10.object({
|
|
8576
|
+
ABSTRACT_RPC_URL: z10.string().optional().describe("Abstract RPC URL override")
|
|
7961
8577
|
});
|
|
7962
|
-
var
|
|
8578
|
+
var timestampOutput7 = z10.union([z10.number(), z10.string()]);
|
|
7963
8579
|
cli.command("status", {
|
|
7964
8580
|
description: "Get a cross-contract Assembly snapshot (members, council, governance, treasury).",
|
|
7965
8581
|
env: rootEnv,
|
|
7966
|
-
output:
|
|
7967
|
-
activeMemberCount:
|
|
7968
|
-
seatCount:
|
|
7969
|
-
proposalCount:
|
|
7970
|
-
currentAuctionDay:
|
|
7971
|
-
currentAuctionSlot:
|
|
7972
|
-
treasuryBalance:
|
|
8582
|
+
output: z10.object({
|
|
8583
|
+
activeMemberCount: z10.number(),
|
|
8584
|
+
seatCount: z10.number(),
|
|
8585
|
+
proposalCount: z10.number(),
|
|
8586
|
+
currentAuctionDay: z10.number(),
|
|
8587
|
+
currentAuctionSlot: z10.number(),
|
|
8588
|
+
treasuryBalance: z10.string()
|
|
7973
8589
|
}),
|
|
7974
8590
|
examples: [{ description: "Fetch the current Assembly system status" }],
|
|
7975
8591
|
async run(c) {
|
|
7976
|
-
return
|
|
8592
|
+
return withCommandSpan2("assembly status", {}, async () => {
|
|
7977
8593
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
7978
8594
|
const [
|
|
7979
8595
|
activeMemberCount,
|
|
@@ -8023,18 +8639,18 @@ cli.command("status", {
|
|
|
8023
8639
|
});
|
|
8024
8640
|
cli.command("health", {
|
|
8025
8641
|
description: "Check cross-contract health for one address (membership, council, refunds, power).",
|
|
8026
|
-
args:
|
|
8027
|
-
address:
|
|
8642
|
+
args: z10.object({
|
|
8643
|
+
address: z10.string().describe("Member or wallet address to inspect")
|
|
8028
8644
|
}),
|
|
8029
8645
|
env: rootEnv,
|
|
8030
|
-
output:
|
|
8031
|
-
address:
|
|
8032
|
-
isActive:
|
|
8033
|
-
activeUntil:
|
|
8034
|
-
activeUntilRelative:
|
|
8035
|
-
isCouncilMember:
|
|
8036
|
-
pendingReturnsWei:
|
|
8037
|
-
votingPower:
|
|
8646
|
+
output: z10.object({
|
|
8647
|
+
address: z10.string(),
|
|
8648
|
+
isActive: z10.boolean(),
|
|
8649
|
+
activeUntil: timestampOutput7,
|
|
8650
|
+
activeUntilRelative: z10.string(),
|
|
8651
|
+
isCouncilMember: z10.boolean(),
|
|
8652
|
+
pendingReturnsWei: z10.string(),
|
|
8653
|
+
votingPower: z10.number()
|
|
8038
8654
|
}),
|
|
8039
8655
|
examples: [
|
|
8040
8656
|
{
|
|
@@ -8043,7 +8659,7 @@ cli.command("health", {
|
|
|
8043
8659
|
}
|
|
8044
8660
|
],
|
|
8045
8661
|
async run(c) {
|
|
8046
|
-
return
|
|
8662
|
+
return withCommandSpan2("assembly health", { address: c.args.address }, async () => {
|
|
8047
8663
|
const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
|
|
8048
8664
|
const [isActive, member, isCouncilMember, pendingReturns, votingPower] = await Promise.all([
|
|
8049
8665
|
client.readContract({
|