@spectratools/assembly-cli 0.5.1 → 0.7.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.
Files changed (2) hide show
  1. package/dist/cli.js +783 -244
  2. package/package.json +3 -2
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { readFileSync, realpathSync } from "fs";
5
5
  import { dirname, resolve } from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { Cli as Cli6, z as z6 } from "incur";
7
+ import { Cli as Cli6, z as z7 } from "incur";
8
8
 
9
9
  // src/commands/_common.ts
10
10
  import { checksumAddress, weiToEth } from "@spectratools/cli-shared";
@@ -59,7 +59,8 @@ function jsonSafe(value) {
59
59
  }
60
60
 
61
61
  // src/commands/council.ts
62
- import { Cli, z } from "incur";
62
+ import { Cli, z as z2 } from "incur";
63
+ import { parseEther } from "viem";
63
64
 
64
65
  // src/contracts/CouncilSeats.abi.json
65
66
  var CouncilSeats_abi_default = [
@@ -4302,7 +4303,12 @@ var ABSTRACT_MAINNET_DEPLOYMENT_BLOCKS = {
4302
4303
  };
4303
4304
 
4304
4305
  // src/contracts/client.ts
4305
- import { http, createPublicClient, defineChain } from "viem";
4306
+ import {
4307
+ http,
4308
+ createPublicClient,
4309
+ createWalletClient,
4310
+ defineChain
4311
+ } from "viem";
4306
4312
  var abstractMainnet = defineChain({
4307
4313
  id: 2741,
4308
4314
  name: "Abstract Mainnet",
@@ -4323,12 +4329,79 @@ function createAssemblyPublicClient(rpcUrl) {
4323
4329
  transport: http(rpcUrl ?? process.env.ABSTRACT_RPC_URL ?? "https://api.mainnet.abs.xyz")
4324
4330
  });
4325
4331
  }
4332
+ function createAssemblyWalletClient(account, rpcUrl) {
4333
+ return createWalletClient({
4334
+ account,
4335
+ chain: abstractMainnet,
4336
+ transport: http(rpcUrl ?? process.env.ABSTRACT_RPC_URL ?? "https://api.mainnet.abs.xyz")
4337
+ });
4338
+ }
4326
4339
 
4327
- // src/commands/council.ts
4328
- var env = z.object({
4340
+ // src/commands/_write-utils.ts
4341
+ import {
4342
+ createPrivateKeySigner,
4343
+ executeTx
4344
+ } from "@spectratools/tx-shared";
4345
+ import { z } from "incur";
4346
+ var writeEnv = z.object({
4347
+ PRIVATE_KEY: z.string().describe("Private key (0x-prefixed 32-byte hex) for signing transactions"),
4329
4348
  ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override")
4330
4349
  });
4331
- var timestampOutput = z.union([z.number(), z.string()]);
4350
+ var writeOptions = z.object({
4351
+ "dry-run": z.boolean().default(false).describe("Simulate the transaction without broadcasting"),
4352
+ "gas-limit": z.string().optional().describe("Gas limit override (in gas units)"),
4353
+ "max-fee": z.string().optional().describe("Max fee per gas override in wei (EIP-1559)"),
4354
+ nonce: z.number().optional().describe("Nonce override")
4355
+ });
4356
+ function resolveAccount(env6) {
4357
+ const signer = createPrivateKeySigner(env6.PRIVATE_KEY);
4358
+ return signer.account;
4359
+ }
4360
+ function formatTxResult(result) {
4361
+ if (result.status === "dry-run") {
4362
+ return {
4363
+ status: "dry-run",
4364
+ estimatedGas: result.estimatedGas.toString(),
4365
+ simulationResult: jsonSafe(result.simulationResult)
4366
+ };
4367
+ }
4368
+ return {
4369
+ status: result.status,
4370
+ hash: result.hash,
4371
+ blockNumber: Number(result.blockNumber),
4372
+ gasUsed: result.gasUsed.toString(),
4373
+ from: result.from,
4374
+ to: result.to,
4375
+ ...result.effectiveGasPrice !== void 0 ? { effectiveGasPrice: result.effectiveGasPrice.toString() } : {}
4376
+ };
4377
+ }
4378
+ async function assemblyWriteTx(opts) {
4379
+ const { env: env6, options, address, abi, functionName, args, value } = opts;
4380
+ const account = resolveAccount(env6);
4381
+ const publicClient = createAssemblyPublicClient(env6.ABSTRACT_RPC_URL);
4382
+ const walletClient = createAssemblyWalletClient(account, env6.ABSTRACT_RPC_URL);
4383
+ const result = await executeTx({
4384
+ publicClient,
4385
+ walletClient,
4386
+ account,
4387
+ address,
4388
+ abi,
4389
+ functionName,
4390
+ ...args !== void 0 ? { args } : {},
4391
+ ...value !== void 0 ? { value } : {},
4392
+ dryRun: options["dry-run"],
4393
+ ...options["gas-limit"] ? { gasLimit: BigInt(options["gas-limit"]) } : {},
4394
+ ...options["max-fee"] ? { maxFeePerGas: BigInt(options["max-fee"]) } : {},
4395
+ ...options.nonce !== void 0 ? { nonce: options.nonce } : {}
4396
+ });
4397
+ return formatTxResult(result);
4398
+ }
4399
+
4400
+ // src/commands/council.ts
4401
+ var env = z2.object({
4402
+ ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
4403
+ });
4404
+ var timestampOutput = z2.union([z2.number(), z2.string()]);
4332
4405
  function decodeSeat(value) {
4333
4406
  const [owner, startAt, endAt, forfeited] = value;
4334
4407
  return { owner, startAt, endAt, forfeited };
@@ -4348,15 +4421,15 @@ var council = Cli.create("council", {
4348
4421
  council.command("seats", {
4349
4422
  description: "List all council seats and their occupancy windows.",
4350
4423
  env,
4351
- output: z.array(
4352
- z.object({
4353
- id: z.number(),
4354
- owner: z.string(),
4424
+ output: z2.array(
4425
+ z2.object({
4426
+ id: z2.number(),
4427
+ owner: z2.string(),
4355
4428
  startAt: timestampOutput,
4356
- startAtRelative: z.string(),
4429
+ startAtRelative: z2.string(),
4357
4430
  endAt: timestampOutput,
4358
- endAtRelative: z.string(),
4359
- forfeited: z.boolean()
4431
+ endAtRelative: z2.string(),
4432
+ forfeited: z2.boolean()
4360
4433
  })
4361
4434
  ),
4362
4435
  examples: [{ description: "List all council seats" }],
@@ -4393,17 +4466,17 @@ council.command("seats", {
4393
4466
  });
4394
4467
  council.command("seat", {
4395
4468
  description: "Get detailed seat information for a specific seat id.",
4396
- args: z.object({
4397
- id: z.coerce.number().int().nonnegative().describe("Seat id (0-indexed)")
4469
+ args: z2.object({
4470
+ id: z2.coerce.number().int().nonnegative().describe("Seat id (0-indexed)")
4398
4471
  }),
4399
4472
  env,
4400
- output: z.object({
4401
- id: z.number(),
4402
- owner: z.string(),
4473
+ output: z2.object({
4474
+ id: z2.number(),
4475
+ owner: z2.string(),
4403
4476
  startAt: timestampOutput,
4404
4477
  endAt: timestampOutput,
4405
- forfeited: z.boolean(),
4406
- endAtRelative: z.string()
4478
+ forfeited: z2.boolean(),
4479
+ endAtRelative: z2.string()
4407
4480
  }),
4408
4481
  examples: [{ args: { id: 0 }, description: "Inspect seat #0" }],
4409
4482
  async run(c) {
@@ -4440,10 +4513,10 @@ council.command("seat", {
4440
4513
  council.command("members", {
4441
4514
  description: "List currently active council members and voting power.",
4442
4515
  env,
4443
- output: z.array(
4444
- z.object({
4445
- address: z.string(),
4446
- votingPower: z.number()
4516
+ output: z2.array(
4517
+ z2.object({
4518
+ address: z2.string(),
4519
+ votingPower: z2.number()
4447
4520
  })
4448
4521
  ),
4449
4522
  examples: [{ description: "List active council members" }],
@@ -4489,13 +4562,13 @@ council.command("members", {
4489
4562
  });
4490
4563
  council.command("is-member", {
4491
4564
  description: "Check whether an address is currently a council member.",
4492
- args: z.object({
4493
- address: z.string().describe("Address to check")
4565
+ args: z2.object({
4566
+ address: z2.string().describe("Address to check")
4494
4567
  }),
4495
4568
  env,
4496
- output: z.object({
4497
- address: z.string(),
4498
- isMember: z.boolean()
4569
+ output: z2.object({
4570
+ address: z2.string(),
4571
+ isMember: z2.boolean()
4499
4572
  }),
4500
4573
  examples: [
4501
4574
  {
@@ -4516,13 +4589,13 @@ council.command("is-member", {
4516
4589
  });
4517
4590
  council.command("voting-power", {
4518
4591
  description: "Get the current voting power for an address.",
4519
- args: z.object({
4520
- address: z.string().describe("Address to inspect")
4592
+ args: z2.object({
4593
+ address: z2.string().describe("Address to inspect")
4521
4594
  }),
4522
4595
  env,
4523
- output: z.object({
4524
- address: z.string(),
4525
- votingPower: z.number()
4596
+ output: z2.object({
4597
+ address: z2.string(),
4598
+ votingPower: z2.number()
4526
4599
  }),
4527
4600
  examples: [
4528
4601
  {
@@ -4544,19 +4617,19 @@ council.command("voting-power", {
4544
4617
  council.command("auctions", {
4545
4618
  description: "List recent and current council auction slots and leading bids.",
4546
4619
  env,
4547
- output: z.object({
4548
- currentDay: z.number(),
4549
- currentSlot: z.number(),
4550
- auctions: z.array(
4551
- z.object({
4552
- day: z.number(),
4553
- slot: z.number(),
4554
- highestBidder: z.string(),
4555
- highestBid: z.string(),
4556
- settled: z.boolean(),
4620
+ output: z2.object({
4621
+ currentDay: z2.number(),
4622
+ currentSlot: z2.number(),
4623
+ auctions: z2.array(
4624
+ z2.object({
4625
+ day: z2.number(),
4626
+ slot: z2.number(),
4627
+ highestBidder: z2.string(),
4628
+ highestBid: z2.string(),
4629
+ settled: z2.boolean(),
4557
4630
  windowEnd: timestampOutput,
4558
- windowEndRelative: z.string(),
4559
- status: z.enum(["bidding", "closed", "settled"])
4631
+ windowEndRelative: z2.string(),
4632
+ status: z2.enum(["bidding", "closed", "settled"])
4560
4633
  })
4561
4634
  )
4562
4635
  }),
@@ -4644,20 +4717,20 @@ council.command("auctions", {
4644
4717
  });
4645
4718
  council.command("auction", {
4646
4719
  description: "Get one auction slot by day + slot.",
4647
- args: z.object({
4648
- day: z.coerce.number().int().nonnegative().describe("Auction day index"),
4649
- slot: z.coerce.number().int().nonnegative().describe("Slot index within day")
4720
+ args: z2.object({
4721
+ day: z2.coerce.number().int().nonnegative().describe("Auction day index"),
4722
+ slot: z2.coerce.number().int().nonnegative().describe("Slot index within day")
4650
4723
  }),
4651
4724
  env,
4652
- output: z.object({
4653
- day: z.number(),
4654
- slot: z.number(),
4655
- highestBidder: z.string(),
4656
- highestBid: z.string(),
4657
- settled: z.boolean(),
4725
+ output: z2.object({
4726
+ day: z2.number(),
4727
+ slot: z2.number(),
4728
+ highestBidder: z2.string(),
4729
+ highestBid: z2.string(),
4730
+ settled: z2.boolean(),
4658
4731
  windowEnd: timestampOutput,
4659
- windowEndRelative: z.string(),
4660
- status: z.enum(["bidding", "closed", "settled"])
4732
+ windowEndRelative: z2.string(),
4733
+ status: z2.enum(["bidding", "closed", "settled"])
4661
4734
  }),
4662
4735
  examples: [{ args: { day: 0, slot: 0 }, description: "Inspect day 0, slot 0 auction" }],
4663
4736
  async run(c) {
@@ -4710,14 +4783,14 @@ council.command("auction", {
4710
4783
  });
4711
4784
  council.command("pending-refund", {
4712
4785
  description: "Get pending refundable bid amount for an address.",
4713
- args: z.object({
4714
- address: z.string().describe("Bidder address")
4786
+ args: z2.object({
4787
+ address: z2.string().describe("Bidder address")
4715
4788
  }),
4716
4789
  env,
4717
- output: z.object({
4718
- address: z.string(),
4719
- pendingRefund: z.string(),
4720
- pendingRefundWei: z.string()
4790
+ output: z2.object({
4791
+ address: z2.string(),
4792
+ pendingRefund: z2.string(),
4793
+ pendingRefundWei: z2.string()
4721
4794
  }),
4722
4795
  examples: [
4723
4796
  {
@@ -4743,13 +4816,13 @@ council.command("pending-refund", {
4743
4816
  council.command("params", {
4744
4817
  description: "Read council seat term and auction scheduling parameters.",
4745
4818
  env,
4746
- output: z.object({
4747
- SEAT_TERM: z.number(),
4748
- AUCTION_SLOT_DURATION: z.number(),
4749
- AUCTION_SLOTS_PER_DAY: z.number(),
4750
- auctionEpochStart: z.number(),
4751
- auctionWindowStart: z.number(),
4752
- auctionWindowEnd: z.number()
4819
+ output: z2.object({
4820
+ SEAT_TERM: z2.number(),
4821
+ AUCTION_SLOT_DURATION: z2.number(),
4822
+ AUCTION_SLOTS_PER_DAY: z2.number(),
4823
+ auctionEpochStart: z2.number(),
4824
+ auctionWindowStart: z2.number(),
4825
+ auctionWindowEnd: z2.number()
4753
4826
  }),
4754
4827
  examples: [{ description: "Inspect council seat + auction timing constants" }],
4755
4828
  async run(c) {
@@ -4800,13 +4873,305 @@ council.command("params", {
4800
4873
  });
4801
4874
  }
4802
4875
  });
4876
+ var txResultOutput = z2.union([
4877
+ z2.object({
4878
+ status: z2.enum(["success", "reverted"]),
4879
+ hash: z2.string(),
4880
+ blockNumber: z2.number(),
4881
+ gasUsed: z2.string(),
4882
+ from: z2.string(),
4883
+ to: z2.string().nullable(),
4884
+ effectiveGasPrice: z2.string().optional()
4885
+ }),
4886
+ z2.object({
4887
+ status: z2.literal("dry-run"),
4888
+ estimatedGas: z2.string(),
4889
+ simulationResult: z2.unknown()
4890
+ })
4891
+ ]);
4892
+ council.command("bid", {
4893
+ description: "Place a bid on a council seat auction (payable).",
4894
+ hint: "Requires PRIVATE_KEY environment variable for signing.",
4895
+ args: z2.object({
4896
+ day: z2.coerce.number().int().nonnegative().describe("Auction day index"),
4897
+ slot: z2.coerce.number().int().nonnegative().describe("Slot index within day")
4898
+ }),
4899
+ options: writeOptions.extend({
4900
+ amount: z2.string().describe('ETH amount to bid (e.g. "0.1")')
4901
+ }),
4902
+ env: writeEnv,
4903
+ output: z2.object({
4904
+ day: z2.number(),
4905
+ slot: z2.number(),
4906
+ bidAmount: z2.string(),
4907
+ tx: txResultOutput
4908
+ }),
4909
+ examples: [
4910
+ {
4911
+ args: { day: 0, slot: 0 },
4912
+ options: { amount: "0.1" },
4913
+ description: "Bid 0.1 ETH on day 0, slot 0"
4914
+ }
4915
+ ],
4916
+ async run(c) {
4917
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
4918
+ let amountWei;
4919
+ try {
4920
+ amountWei = parseEther(c.options.amount);
4921
+ } catch {
4922
+ return c.error({
4923
+ code: "INVALID_AMOUNT",
4924
+ message: `Invalid ETH amount: "${c.options.amount}". Provide a decimal number (e.g. "0.1").`,
4925
+ retryable: false
4926
+ });
4927
+ }
4928
+ if (amountWei <= 0n) {
4929
+ return c.error({
4930
+ code: "INVALID_AMOUNT",
4931
+ message: "Bid amount must be greater than zero.",
4932
+ retryable: false
4933
+ });
4934
+ }
4935
+ const slotsPerDay = await client.readContract({
4936
+ abi: councilSeatsAbi,
4937
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
4938
+ functionName: "AUCTION_SLOTS_PER_DAY"
4939
+ });
4940
+ if (c.args.slot >= Number(slotsPerDay)) {
4941
+ return c.error({
4942
+ code: "OUT_OF_RANGE",
4943
+ message: `Slot ${c.args.slot} does not exist (max: ${Number(slotsPerDay) - 1})`,
4944
+ retryable: false
4945
+ });
4946
+ }
4947
+ const [auctionTuple, windowEnd, latestBlock] = await Promise.all([
4948
+ client.readContract({
4949
+ abi: councilSeatsAbi,
4950
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
4951
+ functionName: "auctions",
4952
+ args: [BigInt(c.args.day), c.args.slot]
4953
+ }),
4954
+ client.readContract({
4955
+ abi: councilSeatsAbi,
4956
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
4957
+ functionName: "auctionWindowEnd",
4958
+ args: [BigInt(c.args.day), c.args.slot]
4959
+ }),
4960
+ client.getBlock({ blockTag: "latest" })
4961
+ ]);
4962
+ const auction = decodeAuction(auctionTuple);
4963
+ const windowEndTimestamp = windowEnd;
4964
+ const currentTimestamp = latestBlock.timestamp;
4965
+ const status = deriveAuctionStatus({
4966
+ settled: auction.settled,
4967
+ windowEnd: windowEndTimestamp,
4968
+ currentTimestamp
4969
+ });
4970
+ if (status === "settled") {
4971
+ return c.error({
4972
+ code: "AUCTION_SETTLED",
4973
+ message: `Auction (day=${c.args.day}, slot=${c.args.slot}) is already settled. Winner: ${toChecksum(auction.highestBidder)}.`,
4974
+ retryable: false
4975
+ });
4976
+ }
4977
+ if (status === "closed") {
4978
+ return c.error({
4979
+ code: "AUCTION_CLOSED",
4980
+ message: `Auction (day=${c.args.day}, slot=${c.args.slot}) bidding window has ended. Use "council settle" instead.`,
4981
+ retryable: false
4982
+ });
4983
+ }
4984
+ if (auction.highestBid >= amountWei) {
4985
+ return c.error({
4986
+ code: "BID_TOO_LOW",
4987
+ message: `Bid of ${c.options.amount} ETH is not higher than current highest bid of ${eth(auction.highestBid)}. Increase your bid amount.`,
4988
+ retryable: false
4989
+ });
4990
+ }
4991
+ const txResult = await assemblyWriteTx({
4992
+ env: c.env,
4993
+ options: c.options,
4994
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
4995
+ abi: councilSeatsAbi,
4996
+ functionName: "bid",
4997
+ args: [BigInt(c.args.day), c.args.slot],
4998
+ value: amountWei
4999
+ });
5000
+ return c.ok(
5001
+ {
5002
+ day: c.args.day,
5003
+ slot: c.args.slot,
5004
+ bidAmount: `${c.options.amount} ETH`,
5005
+ tx: txResult
5006
+ },
5007
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
5008
+ cta: {
5009
+ description: "Next steps:",
5010
+ commands: [
5011
+ {
5012
+ command: "council auction",
5013
+ args: { day: String(c.args.day), slot: String(c.args.slot) },
5014
+ description: "Check auction status"
5015
+ }
5016
+ ]
5017
+ }
5018
+ }
5019
+ );
5020
+ }
5021
+ });
5022
+ council.command("settle", {
5023
+ description: "Settle a completed council seat auction.",
5024
+ hint: "Requires PRIVATE_KEY environment variable for signing.",
5025
+ args: z2.object({
5026
+ day: z2.coerce.number().int().nonnegative().describe("Auction day index"),
5027
+ slot: z2.coerce.number().int().nonnegative().describe("Slot index within day")
5028
+ }),
5029
+ options: writeOptions,
5030
+ env: writeEnv,
5031
+ output: z2.object({
5032
+ day: z2.number(),
5033
+ slot: z2.number(),
5034
+ highestBidder: z2.string(),
5035
+ highestBid: z2.string(),
5036
+ tx: txResultOutput
5037
+ }),
5038
+ examples: [
5039
+ {
5040
+ args: { day: 0, slot: 0 },
5041
+ description: "Settle the auction for day 0, slot 0"
5042
+ }
5043
+ ],
5044
+ async run(c) {
5045
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
5046
+ const slotsPerDay = await client.readContract({
5047
+ abi: councilSeatsAbi,
5048
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5049
+ functionName: "AUCTION_SLOTS_PER_DAY"
5050
+ });
5051
+ if (c.args.slot >= Number(slotsPerDay)) {
5052
+ return c.error({
5053
+ code: "OUT_OF_RANGE",
5054
+ message: `Slot ${c.args.slot} does not exist (max: ${Number(slotsPerDay) - 1})`,
5055
+ retryable: false
5056
+ });
5057
+ }
5058
+ const [auctionTuple, windowEnd, latestBlock] = await Promise.all([
5059
+ client.readContract({
5060
+ abi: councilSeatsAbi,
5061
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5062
+ functionName: "auctions",
5063
+ args: [BigInt(c.args.day), c.args.slot]
5064
+ }),
5065
+ client.readContract({
5066
+ abi: councilSeatsAbi,
5067
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5068
+ functionName: "auctionWindowEnd",
5069
+ args: [BigInt(c.args.day), c.args.slot]
5070
+ }),
5071
+ client.getBlock({ blockTag: "latest" })
5072
+ ]);
5073
+ const auction = decodeAuction(auctionTuple);
5074
+ const windowEndTimestamp = windowEnd;
5075
+ const currentTimestamp = latestBlock.timestamp;
5076
+ const status = deriveAuctionStatus({
5077
+ settled: auction.settled,
5078
+ windowEnd: windowEndTimestamp,
5079
+ currentTimestamp
5080
+ });
5081
+ if (status === "settled") {
5082
+ return c.error({
5083
+ code: "ALREADY_SETTLED",
5084
+ message: `Auction (day=${c.args.day}, slot=${c.args.slot}) is already settled.`,
5085
+ retryable: false
5086
+ });
5087
+ }
5088
+ if (status === "bidding") {
5089
+ return c.error({
5090
+ code: "AUCTION_STILL_ACTIVE",
5091
+ message: `Auction (day=${c.args.day}, slot=${c.args.slot}) is still accepting bids. Window ends ${relTime(windowEndTimestamp)}.`,
5092
+ retryable: false
5093
+ });
5094
+ }
5095
+ const txResult = await assemblyWriteTx({
5096
+ env: c.env,
5097
+ options: c.options,
5098
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5099
+ abi: councilSeatsAbi,
5100
+ functionName: "settleAuction",
5101
+ args: [BigInt(c.args.day), c.args.slot]
5102
+ });
5103
+ return c.ok(
5104
+ {
5105
+ day: c.args.day,
5106
+ slot: c.args.slot,
5107
+ highestBidder: toChecksum(auction.highestBidder),
5108
+ highestBid: eth(auction.highestBid),
5109
+ tx: txResult
5110
+ },
5111
+ c.format === "json" || c.format === "jsonl" ? void 0 : {
5112
+ cta: {
5113
+ description: "Next steps:",
5114
+ commands: [
5115
+ {
5116
+ command: "council seats",
5117
+ description: "View updated council seats"
5118
+ }
5119
+ ]
5120
+ }
5121
+ }
5122
+ );
5123
+ }
5124
+ });
5125
+ council.command("withdraw-refund", {
5126
+ description: "Withdraw pending bid refunds for the signer address.",
5127
+ hint: "Requires PRIVATE_KEY environment variable for signing.",
5128
+ options: writeOptions,
5129
+ env: writeEnv,
5130
+ output: z2.object({
5131
+ address: z2.string(),
5132
+ refundAmount: z2.string(),
5133
+ refundAmountWei: z2.string(),
5134
+ tx: txResultOutput.optional()
5135
+ }),
5136
+ examples: [{ description: "Withdraw all pending bid refunds" }],
5137
+ async run(c) {
5138
+ const account = resolveAccount(c.env);
5139
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
5140
+ const pendingAmount = await client.readContract({
5141
+ abi: councilSeatsAbi,
5142
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5143
+ functionName: "pendingReturns",
5144
+ args: [account.address]
5145
+ });
5146
+ if (pendingAmount === 0n) {
5147
+ return c.ok({
5148
+ address: toChecksum(account.address),
5149
+ refundAmount: "0 ETH",
5150
+ refundAmountWei: "0"
5151
+ });
5152
+ }
5153
+ const txResult = await assemblyWriteTx({
5154
+ env: c.env,
5155
+ options: c.options,
5156
+ address: ABSTRACT_MAINNET_ADDRESSES.councilSeats,
5157
+ abi: councilSeatsAbi,
5158
+ functionName: "withdrawRefund"
5159
+ });
5160
+ return c.ok({
5161
+ address: toChecksum(account.address),
5162
+ refundAmount: eth(pendingAmount),
5163
+ refundAmountWei: pendingAmount.toString(),
5164
+ tx: txResult
5165
+ });
5166
+ }
5167
+ });
4803
5168
 
4804
5169
  // src/commands/forum.ts
4805
- import { Cli as Cli2, z as z2 } from "incur";
4806
- var env2 = z2.object({
4807
- ABSTRACT_RPC_URL: z2.string().optional().describe("Abstract RPC URL override")
5170
+ import { Cli as Cli2, z as z3 } from "incur";
5171
+ var env2 = z3.object({
5172
+ ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
4808
5173
  });
4809
- var timestampOutput2 = z2.union([z2.number(), z2.string()]);
5174
+ var timestampOutput2 = z3.union([z3.number(), z3.string()]);
4810
5175
  function decodeThread(value) {
4811
5176
  const [id, kind, author, createdAt, category, title, body, proposalId, petitionId] = value;
4812
5177
  return {
@@ -4864,19 +5229,19 @@ var forum = Cli2.create("forum", {
4864
5229
  forum.command("threads", {
4865
5230
  description: "List forum threads with author and creation metadata.",
4866
5231
  env: env2,
4867
- output: z2.object({
4868
- threads: z2.array(
4869
- z2.object({
4870
- id: z2.number(),
4871
- kind: z2.number(),
4872
- author: z2.string(),
5232
+ output: z3.object({
5233
+ threads: z3.array(
5234
+ z3.object({
5235
+ id: z3.number(),
5236
+ kind: z3.number(),
5237
+ author: z3.string(),
4873
5238
  createdAt: timestampOutput2,
4874
- createdAtRelative: z2.string(),
4875
- category: z2.string().nullable().optional(),
4876
- title: z2.string().nullable().optional()
5239
+ createdAtRelative: z3.string(),
5240
+ category: z3.string().nullable().optional(),
5241
+ title: z3.string().nullable().optional()
4877
5242
  })
4878
5243
  ),
4879
- count: z2.number()
5244
+ count: z3.number()
4880
5245
  }),
4881
5246
  examples: [{ description: "List all forum threads" }],
4882
5247
  async run(c) {
@@ -4925,13 +5290,13 @@ forum.command("threads", {
4925
5290
  });
4926
5291
  forum.command("thread", {
4927
5292
  description: "Get one thread and all comments associated with it.",
4928
- args: z2.object({
4929
- id: z2.coerce.number().int().positive().describe("Thread id (1-indexed)")
5293
+ args: z3.object({
5294
+ id: z3.coerce.number().int().positive().describe("Thread id (1-indexed)")
4930
5295
  }),
4931
5296
  env: env2,
4932
- output: z2.object({
4933
- thread: z2.record(z2.string(), z2.unknown()),
4934
- comments: z2.array(z2.record(z2.string(), z2.unknown()))
5297
+ output: z3.object({
5298
+ thread: z3.record(z3.string(), z3.unknown()),
5299
+ comments: z3.array(z3.record(z3.string(), z3.unknown()))
4935
5300
  }),
4936
5301
  examples: [{ args: { id: 1 }, description: "Fetch thread #1 and its comments" }],
4937
5302
  async run(c) {
@@ -4981,11 +5346,11 @@ forum.command("thread", {
4981
5346
  });
4982
5347
  forum.command("comments", {
4983
5348
  description: "List comments for a thread id.",
4984
- args: z2.object({
4985
- threadId: z2.coerce.number().int().positive().describe("Thread id to filter comments by")
5349
+ args: z3.object({
5350
+ threadId: z3.coerce.number().int().positive().describe("Thread id to filter comments by")
4986
5351
  }),
4987
5352
  env: env2,
4988
- output: z2.array(z2.record(z2.string(), z2.unknown())),
5353
+ output: z3.array(z3.record(z3.string(), z3.unknown())),
4989
5354
  examples: [{ args: { threadId: 1 }, description: "List comments for thread #1" }],
4990
5355
  async run(c) {
4991
5356
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5012,11 +5377,11 @@ forum.command("comments", {
5012
5377
  });
5013
5378
  forum.command("comment", {
5014
5379
  description: "Get one comment by comment id.",
5015
- args: z2.object({
5016
- id: z2.coerce.number().int().positive().describe("Comment id (1-indexed)")
5380
+ args: z3.object({
5381
+ id: z3.coerce.number().int().positive().describe("Comment id (1-indexed)")
5017
5382
  }),
5018
5383
  env: env2,
5019
- output: z2.record(z2.string(), z2.unknown()),
5384
+ output: z3.record(z3.string(), z3.unknown()),
5020
5385
  examples: [{ args: { id: 1 }, description: "Fetch comment #1" }],
5021
5386
  async run(c) {
5022
5387
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5044,7 +5409,7 @@ forum.command("comment", {
5044
5409
  forum.command("petitions", {
5045
5410
  description: "List petitions submitted in the forum contract.",
5046
5411
  env: env2,
5047
- output: z2.array(z2.record(z2.string(), z2.unknown())),
5412
+ output: z3.array(z3.record(z3.string(), z3.unknown())),
5048
5413
  examples: [{ description: "List all petitions" }],
5049
5414
  async run(c) {
5050
5415
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5069,11 +5434,11 @@ forum.command("petitions", {
5069
5434
  });
5070
5435
  forum.command("petition", {
5071
5436
  description: "Get one petition plus whether proposer already signed it.",
5072
- args: z2.object({
5073
- id: z2.coerce.number().int().positive().describe("Petition id (1-indexed)")
5437
+ args: z3.object({
5438
+ id: z3.coerce.number().int().positive().describe("Petition id (1-indexed)")
5074
5439
  }),
5075
5440
  env: env2,
5076
- output: z2.object({ proposerSigned: z2.boolean() }).passthrough(),
5441
+ output: z3.object({ proposerSigned: z3.boolean() }).passthrough(),
5077
5442
  examples: [{ args: { id: 1 }, description: "Fetch petition #1" }],
5078
5443
  async run(c) {
5079
5444
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5108,15 +5473,15 @@ forum.command("petition", {
5108
5473
  });
5109
5474
  forum.command("has-signed", {
5110
5475
  description: "Check whether an address signed a petition.",
5111
- args: z2.object({
5112
- petitionId: z2.coerce.number().int().positive().describe("Petition id (1-indexed)"),
5113
- address: z2.string().describe("Signer address to check")
5476
+ args: z3.object({
5477
+ petitionId: z3.coerce.number().int().positive().describe("Petition id (1-indexed)"),
5478
+ address: z3.string().describe("Signer address to check")
5114
5479
  }),
5115
5480
  env: env2,
5116
- output: z2.object({
5117
- petitionId: z2.number(),
5118
- address: z2.string(),
5119
- hasSigned: z2.boolean()
5481
+ output: z3.object({
5482
+ petitionId: z3.number(),
5483
+ address: z3.string(),
5484
+ hasSigned: z3.boolean()
5120
5485
  }),
5121
5486
  examples: [
5122
5487
  {
@@ -5141,11 +5506,11 @@ forum.command("has-signed", {
5141
5506
  forum.command("stats", {
5142
5507
  description: "Read top-level forum counters and petition threshold.",
5143
5508
  env: env2,
5144
- output: z2.object({
5145
- threadCount: z2.number(),
5146
- commentCount: z2.number(),
5147
- petitionCount: z2.number(),
5148
- petitionThresholdBps: z2.number()
5509
+ output: z3.object({
5510
+ threadCount: z3.number(),
5511
+ commentCount: z3.number(),
5512
+ petitionCount: z3.number(),
5513
+ petitionThresholdBps: z3.number()
5149
5514
  }),
5150
5515
  examples: [{ description: "Get forum counts and petition threshold" }],
5151
5516
  async run(c) {
@@ -5182,11 +5547,11 @@ forum.command("stats", {
5182
5547
  });
5183
5548
 
5184
5549
  // src/commands/governance.ts
5185
- import { Cli as Cli3, z as z3 } from "incur";
5186
- var env3 = z3.object({
5187
- ABSTRACT_RPC_URL: z3.string().optional().describe("Abstract RPC URL override")
5550
+ import { Cli as Cli3, z as z4 } from "incur";
5551
+ var env3 = z4.object({
5552
+ ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override")
5188
5553
  });
5189
- var timestampOutput3 = z3.union([z3.number(), z3.string()]);
5554
+ var timestampOutput3 = z4.union([z4.number(), z4.string()]);
5190
5555
  var proposalStatusLabels = {
5191
5556
  0: "pending",
5192
5557
  1: "active",
@@ -5202,31 +5567,31 @@ function proposalStatus(status) {
5202
5567
  statusCode
5203
5568
  };
5204
5569
  }
5205
- var proposalOutputSchema = z3.object({
5206
- kind: z3.number(),
5207
- configRiskTier: z3.number(),
5208
- origin: z3.number(),
5209
- status: z3.string(),
5210
- statusCode: z3.number(),
5211
- proposer: z3.string(),
5212
- threadId: z3.number(),
5213
- petitionId: z3.number(),
5214
- createdAt: z3.number(),
5215
- deliberationEndsAt: z3.number(),
5216
- voteStartAt: z3.number(),
5217
- voteEndAt: z3.number(),
5218
- timelockEndsAt: z3.number(),
5219
- activeSeatsSnapshot: z3.number(),
5220
- forVotes: z3.string(),
5221
- againstVotes: z3.string(),
5222
- abstainVotes: z3.string(),
5223
- amount: z3.string(),
5224
- snapshotAssetBalance: z3.string(),
5225
- transferIntent: z3.boolean(),
5226
- intentDeadline: z3.number(),
5227
- intentMaxRiskTier: z3.number(),
5228
- title: z3.string(),
5229
- description: z3.string()
5570
+ var proposalOutputSchema = z4.object({
5571
+ kind: z4.number(),
5572
+ configRiskTier: z4.number(),
5573
+ origin: z4.number(),
5574
+ status: z4.string(),
5575
+ statusCode: z4.number(),
5576
+ proposer: z4.string(),
5577
+ threadId: z4.number(),
5578
+ petitionId: z4.number(),
5579
+ createdAt: z4.number(),
5580
+ deliberationEndsAt: z4.number(),
5581
+ voteStartAt: z4.number(),
5582
+ voteEndAt: z4.number(),
5583
+ timelockEndsAt: z4.number(),
5584
+ activeSeatsSnapshot: z4.number(),
5585
+ forVotes: z4.string(),
5586
+ againstVotes: z4.string(),
5587
+ abstainVotes: z4.string(),
5588
+ amount: z4.string(),
5589
+ snapshotAssetBalance: z4.string(),
5590
+ transferIntent: z4.boolean(),
5591
+ intentDeadline: z4.number(),
5592
+ intentMaxRiskTier: z4.number(),
5593
+ title: z4.string(),
5594
+ description: z4.string()
5230
5595
  });
5231
5596
  function decodeProposal(value) {
5232
5597
  const [
@@ -5315,19 +5680,19 @@ var governance = Cli3.create("governance", {
5315
5680
  governance.command("proposals", {
5316
5681
  description: "List governance proposals with status and vote end time.",
5317
5682
  env: env3,
5318
- output: z3.object({
5319
- proposals: z3.array(
5320
- z3.object({
5321
- id: z3.number(),
5322
- kind: z3.number(),
5323
- status: z3.string(),
5324
- statusCode: z3.number(),
5325
- title: z3.string().nullable().optional(),
5683
+ output: z4.object({
5684
+ proposals: z4.array(
5685
+ z4.object({
5686
+ id: z4.number(),
5687
+ kind: z4.number(),
5688
+ status: z4.string(),
5689
+ statusCode: z4.number(),
5690
+ title: z4.string().nullable().optional(),
5326
5691
  voteEndAt: timestampOutput3,
5327
- voteEndRelative: z3.string()
5692
+ voteEndRelative: z4.string()
5328
5693
  })
5329
5694
  ),
5330
- count: z3.number()
5695
+ count: z4.number()
5331
5696
  }),
5332
5697
  examples: [{ description: "List all proposals" }],
5333
5698
  async run(c) {
@@ -5375,8 +5740,8 @@ governance.command("proposals", {
5375
5740
  });
5376
5741
  governance.command("proposal", {
5377
5742
  description: "Get full raw proposal details by proposal id.",
5378
- args: z3.object({
5379
- id: z3.coerce.number().int().positive().describe("Proposal id (1-indexed)")
5743
+ args: z4.object({
5744
+ id: z4.coerce.number().int().positive().describe("Proposal id (1-indexed)")
5380
5745
  }),
5381
5746
  env: env3,
5382
5747
  output: proposalOutputSchema,
@@ -5408,15 +5773,15 @@ governance.command("proposal", {
5408
5773
  });
5409
5774
  governance.command("has-voted", {
5410
5775
  description: "Check if an address has voted on a proposal.",
5411
- args: z3.object({
5412
- proposalId: z3.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
5413
- address: z3.string().describe("Voter address")
5776
+ args: z4.object({
5777
+ proposalId: z4.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
5778
+ address: z4.string().describe("Voter address")
5414
5779
  }),
5415
5780
  env: env3,
5416
- output: z3.object({
5417
- proposalId: z3.number(),
5418
- address: z3.string(),
5419
- hasVoted: z3.boolean()
5781
+ output: z4.object({
5782
+ proposalId: z4.number(),
5783
+ address: z4.string(),
5784
+ hasVoted: z4.boolean()
5420
5785
  }),
5421
5786
  examples: [
5422
5787
  {
@@ -5445,19 +5810,19 @@ governance.command("has-voted", {
5445
5810
  governance.command("params", {
5446
5811
  description: "Read governance threshold and timing parameters.",
5447
5812
  env: env3,
5448
- output: z3.object({
5449
- deliberationPeriod: z3.number(),
5450
- votePeriod: z3.number(),
5451
- quorumBps: z3.number(),
5452
- constitutionalDeliberationPeriod: z3.number(),
5453
- constitutionalVotePeriod: z3.number(),
5454
- constitutionalPassBps: z3.number(),
5455
- majorPassBps: z3.number(),
5456
- parameterPassBps: z3.number(),
5457
- significantPassBps: z3.number(),
5458
- significantThresholdBps: z3.number(),
5459
- routineThresholdBps: z3.number(),
5460
- timelockPeriod: z3.number()
5813
+ output: z4.object({
5814
+ deliberationPeriod: z4.number(),
5815
+ votePeriod: z4.number(),
5816
+ quorumBps: z4.number(),
5817
+ constitutionalDeliberationPeriod: z4.number(),
5818
+ constitutionalVotePeriod: z4.number(),
5819
+ constitutionalPassBps: z4.number(),
5820
+ majorPassBps: z4.number(),
5821
+ parameterPassBps: z4.number(),
5822
+ significantPassBps: z4.number(),
5823
+ significantThresholdBps: z4.number(),
5824
+ routineThresholdBps: z4.number(),
5825
+ timelockPeriod: z4.number()
5461
5826
  }),
5462
5827
  examples: [{ description: "Inspect governance timing and pass thresholds" }],
5463
5828
  async run(c) {
@@ -5502,16 +5867,17 @@ governance.command("params", {
5502
5867
  });
5503
5868
 
5504
5869
  // src/commands/members.ts
5505
- import { Cli as Cli4, z as z4 } from "incur";
5870
+ import { TxError } from "@spectratools/tx-shared";
5871
+ import { Cli as Cli4, z as z5 } from "incur";
5506
5872
  var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
5507
5873
  var REGISTERED_EVENT_SCAN_STEP = 100000n;
5508
5874
  var REGISTERED_EVENT_SCAN_TIMEOUT_MS = 2e4;
5509
- var env4 = z4.object({
5510
- ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override"),
5511
- ASSEMBLY_INDEXER_URL: z4.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
5875
+ var env4 = z5.object({
5876
+ ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override"),
5877
+ ASSEMBLY_INDEXER_URL: z5.string().optional().describe("Optional members snapshot endpoint (default: theaiassembly.org indexer)")
5512
5878
  });
5513
- var timestampOutput4 = z4.union([z4.number(), z4.string()]);
5514
- var memberSnapshotSchema = z4.array(z4.string());
5879
+ var timestampOutput4 = z5.union([z5.number(), z5.string()]);
5880
+ var memberSnapshotSchema = z5.array(z5.string());
5515
5881
  var AssemblyApiValidationError = class extends Error {
5516
5882
  constructor(details) {
5517
5883
  super("Assembly API response validation failed");
@@ -5619,19 +5985,19 @@ var members = Cli4.create("members", {
5619
5985
  members.command("list", {
5620
5986
  description: "List members from an indexer snapshot (or Registered event fallback) plus on-chain active state.",
5621
5987
  env: env4,
5622
- output: z4.object({
5623
- members: z4.array(
5624
- z4.object({
5625
- address: z4.string(),
5626
- active: z4.boolean(),
5627
- registered: z4.boolean(),
5988
+ output: z5.object({
5989
+ members: z5.array(
5990
+ z5.object({
5991
+ address: z5.string(),
5992
+ active: z5.boolean(),
5993
+ registered: z5.boolean(),
5628
5994
  activeUntil: timestampOutput4,
5629
- activeUntilRelative: z4.string(),
5995
+ activeUntilRelative: z5.string(),
5630
5996
  lastHeartbeatAt: timestampOutput4,
5631
- lastHeartbeatRelative: z4.string()
5997
+ lastHeartbeatRelative: z5.string()
5632
5998
  })
5633
5999
  ),
5634
- count: z4.number()
6000
+ count: z5.number()
5635
6001
  }),
5636
6002
  examples: [
5637
6003
  { description: "List members using default indexer snapshot" },
@@ -5709,17 +6075,17 @@ members.command("list", {
5709
6075
  });
5710
6076
  members.command("info", {
5711
6077
  description: "Get registry record and active status for a member address.",
5712
- args: z4.object({
5713
- address: z4.string().describe("Member wallet address")
6078
+ args: z5.object({
6079
+ address: z5.string().describe("Member wallet address")
5714
6080
  }),
5715
6081
  env: env4,
5716
- output: z4.object({
5717
- address: z4.string(),
5718
- active: z4.boolean(),
6082
+ output: z5.object({
6083
+ address: z5.string(),
6084
+ active: z5.boolean(),
5719
6085
  activeUntil: timestampOutput4,
5720
6086
  lastHeartbeatAt: timestampOutput4,
5721
- activeUntilRelative: z4.string(),
5722
- lastHeartbeatRelative: z4.string()
6087
+ activeUntilRelative: z5.string(),
6088
+ lastHeartbeatRelative: z5.string()
5723
6089
  }),
5724
6090
  examples: [
5725
6091
  {
@@ -5756,9 +6122,9 @@ members.command("info", {
5756
6122
  members.command("count", {
5757
6123
  description: "Get active and total-known member counts from Registry.",
5758
6124
  env: env4,
5759
- output: z4.object({
5760
- active: z4.number(),
5761
- total: z4.number()
6125
+ output: z5.object({
6126
+ active: z5.number(),
6127
+ total: z5.number()
5762
6128
  }),
5763
6129
  examples: [{ description: "Count active and known members" }],
5764
6130
  async run(c) {
@@ -5781,12 +6147,12 @@ members.command("count", {
5781
6147
  members.command("fees", {
5782
6148
  description: "Get registration and heartbeat fee settings.",
5783
6149
  env: env4,
5784
- output: z4.object({
5785
- registrationFeeWei: z4.string(),
5786
- registrationFee: z4.string(),
5787
- heartbeatFeeWei: z4.string(),
5788
- heartbeatFee: z4.string(),
5789
- heartbeatGracePeriodSeconds: z4.number()
6150
+ output: z5.object({
6151
+ registrationFeeWei: z5.string(),
6152
+ registrationFee: z5.string(),
6153
+ heartbeatFeeWei: z5.string(),
6154
+ heartbeatFee: z5.string(),
6155
+ heartbeatGracePeriodSeconds: z5.number()
5790
6156
  }),
5791
6157
  examples: [{ description: "Inspect current registry fee configuration" }],
5792
6158
  async run(c) {
@@ -5817,23 +6183,196 @@ members.command("fees", {
5817
6183
  });
5818
6184
  }
5819
6185
  });
6186
+ var txOutputSchema = z5.union([
6187
+ z5.object({
6188
+ status: z5.enum(["success", "reverted"]),
6189
+ hash: z5.string(),
6190
+ blockNumber: z5.number(),
6191
+ gasUsed: z5.string(),
6192
+ from: z5.string(),
6193
+ to: z5.string().nullable(),
6194
+ effectiveGasPrice: z5.string().optional(),
6195
+ fee: z5.string(),
6196
+ feeEth: z5.string()
6197
+ }),
6198
+ z5.object({
6199
+ status: z5.literal("dry-run"),
6200
+ estimatedGas: z5.string(),
6201
+ simulationResult: z5.unknown(),
6202
+ fee: z5.string(),
6203
+ feeEth: z5.string()
6204
+ })
6205
+ ]);
6206
+ members.command("register", {
6207
+ description: "Register as a new Assembly member (pays the registration fee).",
6208
+ hint: "Requires PRIVATE_KEY environment variable for signing.",
6209
+ env: writeEnv,
6210
+ options: writeOptions,
6211
+ output: txOutputSchema,
6212
+ examples: [
6213
+ { description: "Register as a member" },
6214
+ { options: { "dry-run": true }, description: "Simulate registration without broadcasting" }
6215
+ ],
6216
+ async run(c) {
6217
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
6218
+ const fee = await client.readContract({
6219
+ abi: registryAbi,
6220
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6221
+ functionName: "registrationFee"
6222
+ });
6223
+ process.stderr.write(
6224
+ `${JSON.stringify({ level: "info", message: `Registration fee: ${eth(fee)} (${fee} wei)` })}
6225
+ `
6226
+ );
6227
+ try {
6228
+ const result = await assemblyWriteTx({
6229
+ env: c.env,
6230
+ options: c.options,
6231
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6232
+ abi: registryAbi,
6233
+ functionName: "register",
6234
+ value: fee
6235
+ });
6236
+ return c.ok(
6237
+ { ...result, fee: fee.toString(), feeEth: eth(fee) },
6238
+ result.status === "success" ? {
6239
+ cta: {
6240
+ description: "Check your membership:",
6241
+ commands: [{ command: "members info", args: { address: result.from } }]
6242
+ }
6243
+ } : void 0
6244
+ );
6245
+ } catch (error) {
6246
+ if (error instanceof TxError && error.code === "INSUFFICIENT_FUNDS") {
6247
+ return c.error({
6248
+ code: "INSUFFICIENT_FUNDS",
6249
+ message: `Insufficient funds to register. Required fee: ${eth(fee)} (${fee} wei). ${error.message}`,
6250
+ retryable: false
6251
+ });
6252
+ }
6253
+ throw error;
6254
+ }
6255
+ }
6256
+ });
6257
+ members.command("heartbeat", {
6258
+ description: "Send a heartbeat to extend active membership (pays the heartbeat fee).",
6259
+ hint: "Requires PRIVATE_KEY environment variable for signing.",
6260
+ env: writeEnv,
6261
+ options: writeOptions,
6262
+ output: txOutputSchema,
6263
+ examples: [
6264
+ { description: "Send a heartbeat" },
6265
+ { options: { "dry-run": true }, description: "Simulate heartbeat without broadcasting" }
6266
+ ],
6267
+ async run(c) {
6268
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
6269
+ const fee = await client.readContract({
6270
+ abi: registryAbi,
6271
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6272
+ functionName: "heartbeatFee"
6273
+ });
6274
+ process.stderr.write(
6275
+ `${JSON.stringify({ level: "info", message: `Heartbeat fee: ${eth(fee)} (${fee} wei)` })}
6276
+ `
6277
+ );
6278
+ try {
6279
+ const result = await assemblyWriteTx({
6280
+ env: c.env,
6281
+ options: c.options,
6282
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6283
+ abi: registryAbi,
6284
+ functionName: "heartbeat",
6285
+ value: fee
6286
+ });
6287
+ return c.ok(
6288
+ { ...result, fee: fee.toString(), feeEth: eth(fee) },
6289
+ result.status === "success" ? {
6290
+ cta: {
6291
+ description: "Check your membership:",
6292
+ commands: [{ command: "members info", args: { address: result.from } }]
6293
+ }
6294
+ } : void 0
6295
+ );
6296
+ } catch (error) {
6297
+ if (error instanceof TxError && error.code === "INSUFFICIENT_FUNDS") {
6298
+ return c.error({
6299
+ code: "INSUFFICIENT_FUNDS",
6300
+ message: `Insufficient funds for heartbeat. Required fee: ${eth(fee)} (${fee} wei). ${error.message}`,
6301
+ retryable: false
6302
+ });
6303
+ }
6304
+ throw error;
6305
+ }
6306
+ }
6307
+ });
6308
+ members.command("renew", {
6309
+ description: "Renew an expired membership (pays the registration fee).",
6310
+ hint: "Requires PRIVATE_KEY environment variable for signing. Calls register() to re-activate expired membership.",
6311
+ env: writeEnv,
6312
+ options: writeOptions,
6313
+ output: txOutputSchema,
6314
+ examples: [
6315
+ { description: "Renew expired membership" },
6316
+ { options: { "dry-run": true }, description: "Simulate renewal without broadcasting" }
6317
+ ],
6318
+ async run(c) {
6319
+ const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
6320
+ const fee = await client.readContract({
6321
+ abi: registryAbi,
6322
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6323
+ functionName: "registrationFee"
6324
+ });
6325
+ process.stderr.write(
6326
+ `${JSON.stringify({ level: "info", message: `Renewal fee: ${eth(fee)} (${fee} wei)` })}
6327
+ `
6328
+ );
6329
+ try {
6330
+ const result = await assemblyWriteTx({
6331
+ env: c.env,
6332
+ options: c.options,
6333
+ address: ABSTRACT_MAINNET_ADDRESSES.registry,
6334
+ abi: registryAbi,
6335
+ functionName: "register",
6336
+ value: fee
6337
+ });
6338
+ return c.ok(
6339
+ { ...result, fee: fee.toString(), feeEth: eth(fee) },
6340
+ result.status === "success" ? {
6341
+ cta: {
6342
+ description: "Check your membership:",
6343
+ commands: [{ command: "members info", args: { address: result.from } }]
6344
+ }
6345
+ } : void 0
6346
+ );
6347
+ } catch (error) {
6348
+ if (error instanceof TxError && error.code === "INSUFFICIENT_FUNDS") {
6349
+ return c.error({
6350
+ code: "INSUFFICIENT_FUNDS",
6351
+ message: `Insufficient funds to renew. Required fee: ${eth(fee)} (${fee} wei). ${error.message}`,
6352
+ retryable: false
6353
+ });
6354
+ }
6355
+ throw error;
6356
+ }
6357
+ }
6358
+ });
5820
6359
 
5821
6360
  // src/commands/treasury.ts
5822
- import { Cli as Cli5, z as z5 } from "incur";
5823
- var env5 = z5.object({
5824
- ABSTRACT_RPC_URL: z5.string().optional().describe("Abstract RPC URL override")
6361
+ import { Cli as Cli5, z as z6 } from "incur";
6362
+ var env5 = z6.object({
6363
+ ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
5825
6364
  });
5826
- var timestampOutput5 = z5.union([z5.number(), z5.string()]);
6365
+ var timestampOutput5 = z6.union([z6.number(), z6.string()]);
5827
6366
  var treasury = Cli5.create("treasury", {
5828
6367
  description: "Inspect treasury balances, execution status, and spend controls."
5829
6368
  });
5830
6369
  treasury.command("balance", {
5831
6370
  description: "Get current native token balance for the treasury contract.",
5832
6371
  env: env5,
5833
- output: z5.object({
5834
- address: z5.string(),
5835
- balanceWei: z5.string(),
5836
- balance: z5.string()
6372
+ output: z6.object({
6373
+ address: z6.string(),
6374
+ balanceWei: z6.string(),
6375
+ balance: z6.string()
5837
6376
  }),
5838
6377
  examples: [{ description: "Check treasury balance" }],
5839
6378
  async run(c) {
@@ -5848,13 +6387,13 @@ treasury.command("balance", {
5848
6387
  });
5849
6388
  treasury.command("whitelist", {
5850
6389
  description: "Check whether an asset address is treasury-whitelisted.",
5851
- args: z5.object({
5852
- asset: z5.string().describe("Token/asset contract address")
6390
+ args: z6.object({
6391
+ asset: z6.string().describe("Token/asset contract address")
5853
6392
  }),
5854
6393
  env: env5,
5855
- output: z5.object({
5856
- asset: z5.string(),
5857
- whitelisted: z5.boolean()
6394
+ output: z6.object({
6395
+ asset: z6.string(),
6396
+ whitelisted: z6.boolean()
5858
6397
  }),
5859
6398
  examples: [
5860
6399
  {
@@ -5876,11 +6415,11 @@ treasury.command("whitelist", {
5876
6415
  treasury.command("major-spend-status", {
5877
6416
  description: "Read major-spend cooldown status for the treasury contract.",
5878
6417
  env: env5,
5879
- output: z5.object({
5880
- majorSpendCooldownSeconds: z5.number(),
6418
+ output: z6.object({
6419
+ majorSpendCooldownSeconds: z6.number(),
5881
6420
  lastMajorSpendAt: timestampOutput5,
5882
- lastMajorSpendRelative: z5.string(),
5883
- isMajorSpendAllowed: z5.boolean()
6421
+ lastMajorSpendRelative: z6.string(),
6422
+ isMajorSpendAllowed: z6.boolean()
5884
6423
  }),
5885
6424
  examples: [{ description: "Inspect treasury major-spend guardrails" }],
5886
6425
  async run(c) {
@@ -5914,13 +6453,13 @@ treasury.command("major-spend-status", {
5914
6453
  });
5915
6454
  treasury.command("executed", {
5916
6455
  description: "Check whether a treasury action for a proposal has executed.",
5917
- args: z5.object({
5918
- proposalId: z5.coerce.number().int().positive().describe("Governance proposal id")
6456
+ args: z6.object({
6457
+ proposalId: z6.coerce.number().int().positive().describe("Governance proposal id")
5919
6458
  }),
5920
6459
  env: env5,
5921
- output: z5.object({
5922
- proposalId: z5.number(),
5923
- executed: z5.boolean()
6460
+ output: z6.object({
6461
+ proposalId: z6.number(),
6462
+ executed: z6.boolean()
5924
6463
  }),
5925
6464
  examples: [{ args: { proposalId: 1 }, description: "Check execution status for proposal #1" }],
5926
6465
  async run(c) {
@@ -6086,20 +6625,20 @@ cli.command(council);
6086
6625
  cli.command(forum);
6087
6626
  cli.command(governance);
6088
6627
  cli.command(treasury);
6089
- var rootEnv = z6.object({
6090
- ABSTRACT_RPC_URL: z6.string().optional().describe("Abstract RPC URL override")
6628
+ var rootEnv = z7.object({
6629
+ ABSTRACT_RPC_URL: z7.string().optional().describe("Abstract RPC URL override")
6091
6630
  });
6092
- var timestampOutput6 = z6.union([z6.number(), z6.string()]);
6631
+ var timestampOutput6 = z7.union([z7.number(), z7.string()]);
6093
6632
  cli.command("status", {
6094
6633
  description: "Get a cross-contract Assembly snapshot (members, council, governance, treasury).",
6095
6634
  env: rootEnv,
6096
- output: z6.object({
6097
- activeMemberCount: z6.number(),
6098
- seatCount: z6.number(),
6099
- proposalCount: z6.number(),
6100
- currentAuctionDay: z6.number(),
6101
- currentAuctionSlot: z6.number(),
6102
- treasuryBalance: z6.string()
6635
+ output: z7.object({
6636
+ activeMemberCount: z7.number(),
6637
+ seatCount: z7.number(),
6638
+ proposalCount: z7.number(),
6639
+ currentAuctionDay: z7.number(),
6640
+ currentAuctionSlot: z7.number(),
6641
+ treasuryBalance: z7.string()
6103
6642
  }),
6104
6643
  examples: [{ description: "Fetch the current Assembly system status" }],
6105
6644
  async run(c) {
@@ -6151,18 +6690,18 @@ cli.command("status", {
6151
6690
  });
6152
6691
  cli.command("health", {
6153
6692
  description: "Check cross-contract health for one address (membership, council, refunds, power).",
6154
- args: z6.object({
6155
- address: z6.string().describe("Member or wallet address to inspect")
6693
+ args: z7.object({
6694
+ address: z7.string().describe("Member or wallet address to inspect")
6156
6695
  }),
6157
6696
  env: rootEnv,
6158
- output: z6.object({
6159
- address: z6.string(),
6160
- isActive: z6.boolean(),
6697
+ output: z7.object({
6698
+ address: z7.string(),
6699
+ isActive: z7.boolean(),
6161
6700
  activeUntil: timestampOutput6,
6162
- activeUntilRelative: z6.string(),
6163
- isCouncilMember: z6.boolean(),
6164
- pendingReturnsWei: z6.string(),
6165
- votingPower: z6.number()
6701
+ activeUntilRelative: z7.string(),
6702
+ isCouncilMember: z7.boolean(),
6703
+ pendingReturnsWei: z7.string(),
6704
+ votingPower: z7.number()
6166
6705
  }),
6167
6706
  examples: [
6168
6707
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectratools/assembly-cli",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "CLI for Assembly governance on Abstract (members, council, forum, proposals, and treasury).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,9 +29,10 @@
29
29
  "assembly-cli": "./dist/cli.js"
30
30
  },
31
31
  "dependencies": {
32
- "incur": "^0.2.2",
32
+ "incur": "^0.3.0",
33
33
  "ox": "^0.14.0",
34
34
  "viem": "^2.47.0",
35
+ "@spectratools/tx-shared": "0.3.0",
35
36
  "@spectratools/cli-shared": "0.1.1"
36
37
  },
37
38
  "devDependencies": {