@spectratools/assembly-cli 0.6.0 → 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 +777 -243
  2. package/package.json +4 -4
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 = [
@@ -4328,12 +4329,79 @@ function createAssemblyPublicClient(rpcUrl) {
4328
4329
  transport: http(rpcUrl ?? process.env.ABSTRACT_RPC_URL ?? "https://api.mainnet.abs.xyz")
4329
4330
  });
4330
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
+ }
4331
4339
 
4332
- // src/commands/council.ts
4333
- 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"),
4334
4348
  ABSTRACT_RPC_URL: z.string().optional().describe("Abstract RPC URL override")
4335
4349
  });
4336
- 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()]);
4337
4405
  function decodeSeat(value) {
4338
4406
  const [owner, startAt, endAt, forfeited] = value;
4339
4407
  return { owner, startAt, endAt, forfeited };
@@ -4353,15 +4421,15 @@ var council = Cli.create("council", {
4353
4421
  council.command("seats", {
4354
4422
  description: "List all council seats and their occupancy windows.",
4355
4423
  env,
4356
- output: z.array(
4357
- z.object({
4358
- id: z.number(),
4359
- owner: z.string(),
4424
+ output: z2.array(
4425
+ z2.object({
4426
+ id: z2.number(),
4427
+ owner: z2.string(),
4360
4428
  startAt: timestampOutput,
4361
- startAtRelative: z.string(),
4429
+ startAtRelative: z2.string(),
4362
4430
  endAt: timestampOutput,
4363
- endAtRelative: z.string(),
4364
- forfeited: z.boolean()
4431
+ endAtRelative: z2.string(),
4432
+ forfeited: z2.boolean()
4365
4433
  })
4366
4434
  ),
4367
4435
  examples: [{ description: "List all council seats" }],
@@ -4398,17 +4466,17 @@ council.command("seats", {
4398
4466
  });
4399
4467
  council.command("seat", {
4400
4468
  description: "Get detailed seat information for a specific seat id.",
4401
- args: z.object({
4402
- 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)")
4403
4471
  }),
4404
4472
  env,
4405
- output: z.object({
4406
- id: z.number(),
4407
- owner: z.string(),
4473
+ output: z2.object({
4474
+ id: z2.number(),
4475
+ owner: z2.string(),
4408
4476
  startAt: timestampOutput,
4409
4477
  endAt: timestampOutput,
4410
- forfeited: z.boolean(),
4411
- endAtRelative: z.string()
4478
+ forfeited: z2.boolean(),
4479
+ endAtRelative: z2.string()
4412
4480
  }),
4413
4481
  examples: [{ args: { id: 0 }, description: "Inspect seat #0" }],
4414
4482
  async run(c) {
@@ -4445,10 +4513,10 @@ council.command("seat", {
4445
4513
  council.command("members", {
4446
4514
  description: "List currently active council members and voting power.",
4447
4515
  env,
4448
- output: z.array(
4449
- z.object({
4450
- address: z.string(),
4451
- votingPower: z.number()
4516
+ output: z2.array(
4517
+ z2.object({
4518
+ address: z2.string(),
4519
+ votingPower: z2.number()
4452
4520
  })
4453
4521
  ),
4454
4522
  examples: [{ description: "List active council members" }],
@@ -4494,13 +4562,13 @@ council.command("members", {
4494
4562
  });
4495
4563
  council.command("is-member", {
4496
4564
  description: "Check whether an address is currently a council member.",
4497
- args: z.object({
4498
- address: z.string().describe("Address to check")
4565
+ args: z2.object({
4566
+ address: z2.string().describe("Address to check")
4499
4567
  }),
4500
4568
  env,
4501
- output: z.object({
4502
- address: z.string(),
4503
- isMember: z.boolean()
4569
+ output: z2.object({
4570
+ address: z2.string(),
4571
+ isMember: z2.boolean()
4504
4572
  }),
4505
4573
  examples: [
4506
4574
  {
@@ -4521,13 +4589,13 @@ council.command("is-member", {
4521
4589
  });
4522
4590
  council.command("voting-power", {
4523
4591
  description: "Get the current voting power for an address.",
4524
- args: z.object({
4525
- address: z.string().describe("Address to inspect")
4592
+ args: z2.object({
4593
+ address: z2.string().describe("Address to inspect")
4526
4594
  }),
4527
4595
  env,
4528
- output: z.object({
4529
- address: z.string(),
4530
- votingPower: z.number()
4596
+ output: z2.object({
4597
+ address: z2.string(),
4598
+ votingPower: z2.number()
4531
4599
  }),
4532
4600
  examples: [
4533
4601
  {
@@ -4549,19 +4617,19 @@ council.command("voting-power", {
4549
4617
  council.command("auctions", {
4550
4618
  description: "List recent and current council auction slots and leading bids.",
4551
4619
  env,
4552
- output: z.object({
4553
- currentDay: z.number(),
4554
- currentSlot: z.number(),
4555
- auctions: z.array(
4556
- z.object({
4557
- day: z.number(),
4558
- slot: z.number(),
4559
- highestBidder: z.string(),
4560
- highestBid: z.string(),
4561
- 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(),
4562
4630
  windowEnd: timestampOutput,
4563
- windowEndRelative: z.string(),
4564
- status: z.enum(["bidding", "closed", "settled"])
4631
+ windowEndRelative: z2.string(),
4632
+ status: z2.enum(["bidding", "closed", "settled"])
4565
4633
  })
4566
4634
  )
4567
4635
  }),
@@ -4649,20 +4717,20 @@ council.command("auctions", {
4649
4717
  });
4650
4718
  council.command("auction", {
4651
4719
  description: "Get one auction slot by day + slot.",
4652
- args: z.object({
4653
- day: z.coerce.number().int().nonnegative().describe("Auction day index"),
4654
- 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")
4655
4723
  }),
4656
4724
  env,
4657
- output: z.object({
4658
- day: z.number(),
4659
- slot: z.number(),
4660
- highestBidder: z.string(),
4661
- highestBid: z.string(),
4662
- 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(),
4663
4731
  windowEnd: timestampOutput,
4664
- windowEndRelative: z.string(),
4665
- status: z.enum(["bidding", "closed", "settled"])
4732
+ windowEndRelative: z2.string(),
4733
+ status: z2.enum(["bidding", "closed", "settled"])
4666
4734
  }),
4667
4735
  examples: [{ args: { day: 0, slot: 0 }, description: "Inspect day 0, slot 0 auction" }],
4668
4736
  async run(c) {
@@ -4715,14 +4783,14 @@ council.command("auction", {
4715
4783
  });
4716
4784
  council.command("pending-refund", {
4717
4785
  description: "Get pending refundable bid amount for an address.",
4718
- args: z.object({
4719
- address: z.string().describe("Bidder address")
4786
+ args: z2.object({
4787
+ address: z2.string().describe("Bidder address")
4720
4788
  }),
4721
4789
  env,
4722
- output: z.object({
4723
- address: z.string(),
4724
- pendingRefund: z.string(),
4725
- pendingRefundWei: z.string()
4790
+ output: z2.object({
4791
+ address: z2.string(),
4792
+ pendingRefund: z2.string(),
4793
+ pendingRefundWei: z2.string()
4726
4794
  }),
4727
4795
  examples: [
4728
4796
  {
@@ -4748,13 +4816,13 @@ council.command("pending-refund", {
4748
4816
  council.command("params", {
4749
4817
  description: "Read council seat term and auction scheduling parameters.",
4750
4818
  env,
4751
- output: z.object({
4752
- SEAT_TERM: z.number(),
4753
- AUCTION_SLOT_DURATION: z.number(),
4754
- AUCTION_SLOTS_PER_DAY: z.number(),
4755
- auctionEpochStart: z.number(),
4756
- auctionWindowStart: z.number(),
4757
- 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()
4758
4826
  }),
4759
4827
  examples: [{ description: "Inspect council seat + auction timing constants" }],
4760
4828
  async run(c) {
@@ -4805,13 +4873,305 @@ council.command("params", {
4805
4873
  });
4806
4874
  }
4807
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
+ });
4808
5168
 
4809
5169
  // src/commands/forum.ts
4810
- import { Cli as Cli2, z as z2 } from "incur";
4811
- var env2 = z2.object({
4812
- 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")
4813
5173
  });
4814
- var timestampOutput2 = z2.union([z2.number(), z2.string()]);
5174
+ var timestampOutput2 = z3.union([z3.number(), z3.string()]);
4815
5175
  function decodeThread(value) {
4816
5176
  const [id, kind, author, createdAt, category, title, body, proposalId, petitionId] = value;
4817
5177
  return {
@@ -4869,19 +5229,19 @@ var forum = Cli2.create("forum", {
4869
5229
  forum.command("threads", {
4870
5230
  description: "List forum threads with author and creation metadata.",
4871
5231
  env: env2,
4872
- output: z2.object({
4873
- threads: z2.array(
4874
- z2.object({
4875
- id: z2.number(),
4876
- kind: z2.number(),
4877
- 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(),
4878
5238
  createdAt: timestampOutput2,
4879
- createdAtRelative: z2.string(),
4880
- category: z2.string().nullable().optional(),
4881
- title: z2.string().nullable().optional()
5239
+ createdAtRelative: z3.string(),
5240
+ category: z3.string().nullable().optional(),
5241
+ title: z3.string().nullable().optional()
4882
5242
  })
4883
5243
  ),
4884
- count: z2.number()
5244
+ count: z3.number()
4885
5245
  }),
4886
5246
  examples: [{ description: "List all forum threads" }],
4887
5247
  async run(c) {
@@ -4930,13 +5290,13 @@ forum.command("threads", {
4930
5290
  });
4931
5291
  forum.command("thread", {
4932
5292
  description: "Get one thread and all comments associated with it.",
4933
- args: z2.object({
4934
- 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)")
4935
5295
  }),
4936
5296
  env: env2,
4937
- output: z2.object({
4938
- thread: z2.record(z2.string(), z2.unknown()),
4939
- 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()))
4940
5300
  }),
4941
5301
  examples: [{ args: { id: 1 }, description: "Fetch thread #1 and its comments" }],
4942
5302
  async run(c) {
@@ -4986,11 +5346,11 @@ forum.command("thread", {
4986
5346
  });
4987
5347
  forum.command("comments", {
4988
5348
  description: "List comments for a thread id.",
4989
- args: z2.object({
4990
- 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")
4991
5351
  }),
4992
5352
  env: env2,
4993
- output: z2.array(z2.record(z2.string(), z2.unknown())),
5353
+ output: z3.array(z3.record(z3.string(), z3.unknown())),
4994
5354
  examples: [{ args: { threadId: 1 }, description: "List comments for thread #1" }],
4995
5355
  async run(c) {
4996
5356
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5017,11 +5377,11 @@ forum.command("comments", {
5017
5377
  });
5018
5378
  forum.command("comment", {
5019
5379
  description: "Get one comment by comment id.",
5020
- args: z2.object({
5021
- 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)")
5022
5382
  }),
5023
5383
  env: env2,
5024
- output: z2.record(z2.string(), z2.unknown()),
5384
+ output: z3.record(z3.string(), z3.unknown()),
5025
5385
  examples: [{ args: { id: 1 }, description: "Fetch comment #1" }],
5026
5386
  async run(c) {
5027
5387
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5049,7 +5409,7 @@ forum.command("comment", {
5049
5409
  forum.command("petitions", {
5050
5410
  description: "List petitions submitted in the forum contract.",
5051
5411
  env: env2,
5052
- output: z2.array(z2.record(z2.string(), z2.unknown())),
5412
+ output: z3.array(z3.record(z3.string(), z3.unknown())),
5053
5413
  examples: [{ description: "List all petitions" }],
5054
5414
  async run(c) {
5055
5415
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5074,11 +5434,11 @@ forum.command("petitions", {
5074
5434
  });
5075
5435
  forum.command("petition", {
5076
5436
  description: "Get one petition plus whether proposer already signed it.",
5077
- args: z2.object({
5078
- 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)")
5079
5439
  }),
5080
5440
  env: env2,
5081
- output: z2.object({ proposerSigned: z2.boolean() }).passthrough(),
5441
+ output: z3.object({ proposerSigned: z3.boolean() }).passthrough(),
5082
5442
  examples: [{ args: { id: 1 }, description: "Fetch petition #1" }],
5083
5443
  async run(c) {
5084
5444
  const client = createAssemblyPublicClient(c.env.ABSTRACT_RPC_URL);
@@ -5113,15 +5473,15 @@ forum.command("petition", {
5113
5473
  });
5114
5474
  forum.command("has-signed", {
5115
5475
  description: "Check whether an address signed a petition.",
5116
- args: z2.object({
5117
- petitionId: z2.coerce.number().int().positive().describe("Petition id (1-indexed)"),
5118
- 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")
5119
5479
  }),
5120
5480
  env: env2,
5121
- output: z2.object({
5122
- petitionId: z2.number(),
5123
- address: z2.string(),
5124
- hasSigned: z2.boolean()
5481
+ output: z3.object({
5482
+ petitionId: z3.number(),
5483
+ address: z3.string(),
5484
+ hasSigned: z3.boolean()
5125
5485
  }),
5126
5486
  examples: [
5127
5487
  {
@@ -5146,11 +5506,11 @@ forum.command("has-signed", {
5146
5506
  forum.command("stats", {
5147
5507
  description: "Read top-level forum counters and petition threshold.",
5148
5508
  env: env2,
5149
- output: z2.object({
5150
- threadCount: z2.number(),
5151
- commentCount: z2.number(),
5152
- petitionCount: z2.number(),
5153
- petitionThresholdBps: z2.number()
5509
+ output: z3.object({
5510
+ threadCount: z3.number(),
5511
+ commentCount: z3.number(),
5512
+ petitionCount: z3.number(),
5513
+ petitionThresholdBps: z3.number()
5154
5514
  }),
5155
5515
  examples: [{ description: "Get forum counts and petition threshold" }],
5156
5516
  async run(c) {
@@ -5187,11 +5547,11 @@ forum.command("stats", {
5187
5547
  });
5188
5548
 
5189
5549
  // src/commands/governance.ts
5190
- import { Cli as Cli3, z as z3 } from "incur";
5191
- var env3 = z3.object({
5192
- 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")
5193
5553
  });
5194
- var timestampOutput3 = z3.union([z3.number(), z3.string()]);
5554
+ var timestampOutput3 = z4.union([z4.number(), z4.string()]);
5195
5555
  var proposalStatusLabels = {
5196
5556
  0: "pending",
5197
5557
  1: "active",
@@ -5207,31 +5567,31 @@ function proposalStatus(status) {
5207
5567
  statusCode
5208
5568
  };
5209
5569
  }
5210
- var proposalOutputSchema = z3.object({
5211
- kind: z3.number(),
5212
- configRiskTier: z3.number(),
5213
- origin: z3.number(),
5214
- status: z3.string(),
5215
- statusCode: z3.number(),
5216
- proposer: z3.string(),
5217
- threadId: z3.number(),
5218
- petitionId: z3.number(),
5219
- createdAt: z3.number(),
5220
- deliberationEndsAt: z3.number(),
5221
- voteStartAt: z3.number(),
5222
- voteEndAt: z3.number(),
5223
- timelockEndsAt: z3.number(),
5224
- activeSeatsSnapshot: z3.number(),
5225
- forVotes: z3.string(),
5226
- againstVotes: z3.string(),
5227
- abstainVotes: z3.string(),
5228
- amount: z3.string(),
5229
- snapshotAssetBalance: z3.string(),
5230
- transferIntent: z3.boolean(),
5231
- intentDeadline: z3.number(),
5232
- intentMaxRiskTier: z3.number(),
5233
- title: z3.string(),
5234
- 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()
5235
5595
  });
5236
5596
  function decodeProposal(value) {
5237
5597
  const [
@@ -5320,19 +5680,19 @@ var governance = Cli3.create("governance", {
5320
5680
  governance.command("proposals", {
5321
5681
  description: "List governance proposals with status and vote end time.",
5322
5682
  env: env3,
5323
- output: z3.object({
5324
- proposals: z3.array(
5325
- z3.object({
5326
- id: z3.number(),
5327
- kind: z3.number(),
5328
- status: z3.string(),
5329
- statusCode: z3.number(),
5330
- 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(),
5331
5691
  voteEndAt: timestampOutput3,
5332
- voteEndRelative: z3.string()
5692
+ voteEndRelative: z4.string()
5333
5693
  })
5334
5694
  ),
5335
- count: z3.number()
5695
+ count: z4.number()
5336
5696
  }),
5337
5697
  examples: [{ description: "List all proposals" }],
5338
5698
  async run(c) {
@@ -5380,8 +5740,8 @@ governance.command("proposals", {
5380
5740
  });
5381
5741
  governance.command("proposal", {
5382
5742
  description: "Get full raw proposal details by proposal id.",
5383
- args: z3.object({
5384
- 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)")
5385
5745
  }),
5386
5746
  env: env3,
5387
5747
  output: proposalOutputSchema,
@@ -5413,15 +5773,15 @@ governance.command("proposal", {
5413
5773
  });
5414
5774
  governance.command("has-voted", {
5415
5775
  description: "Check if an address has voted on a proposal.",
5416
- args: z3.object({
5417
- proposalId: z3.coerce.number().int().positive().describe("Proposal id (1-indexed)"),
5418
- 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")
5419
5779
  }),
5420
5780
  env: env3,
5421
- output: z3.object({
5422
- proposalId: z3.number(),
5423
- address: z3.string(),
5424
- hasVoted: z3.boolean()
5781
+ output: z4.object({
5782
+ proposalId: z4.number(),
5783
+ address: z4.string(),
5784
+ hasVoted: z4.boolean()
5425
5785
  }),
5426
5786
  examples: [
5427
5787
  {
@@ -5450,19 +5810,19 @@ governance.command("has-voted", {
5450
5810
  governance.command("params", {
5451
5811
  description: "Read governance threshold and timing parameters.",
5452
5812
  env: env3,
5453
- output: z3.object({
5454
- deliberationPeriod: z3.number(),
5455
- votePeriod: z3.number(),
5456
- quorumBps: z3.number(),
5457
- constitutionalDeliberationPeriod: z3.number(),
5458
- constitutionalVotePeriod: z3.number(),
5459
- constitutionalPassBps: z3.number(),
5460
- majorPassBps: z3.number(),
5461
- parameterPassBps: z3.number(),
5462
- significantPassBps: z3.number(),
5463
- significantThresholdBps: z3.number(),
5464
- routineThresholdBps: z3.number(),
5465
- 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()
5466
5826
  }),
5467
5827
  examples: [{ description: "Inspect governance timing and pass thresholds" }],
5468
5828
  async run(c) {
@@ -5507,16 +5867,17 @@ governance.command("params", {
5507
5867
  });
5508
5868
 
5509
5869
  // src/commands/members.ts
5510
- 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";
5511
5872
  var DEFAULT_MEMBER_SNAPSHOT_URL = "https://www.theaiassembly.org/api/indexer/members";
5512
5873
  var REGISTERED_EVENT_SCAN_STEP = 100000n;
5513
5874
  var REGISTERED_EVENT_SCAN_TIMEOUT_MS = 2e4;
5514
- var env4 = z4.object({
5515
- ABSTRACT_RPC_URL: z4.string().optional().describe("Abstract RPC URL override"),
5516
- 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)")
5517
5878
  });
5518
- var timestampOutput4 = z4.union([z4.number(), z4.string()]);
5519
- var memberSnapshotSchema = z4.array(z4.string());
5879
+ var timestampOutput4 = z5.union([z5.number(), z5.string()]);
5880
+ var memberSnapshotSchema = z5.array(z5.string());
5520
5881
  var AssemblyApiValidationError = class extends Error {
5521
5882
  constructor(details) {
5522
5883
  super("Assembly API response validation failed");
@@ -5624,19 +5985,19 @@ var members = Cli4.create("members", {
5624
5985
  members.command("list", {
5625
5986
  description: "List members from an indexer snapshot (or Registered event fallback) plus on-chain active state.",
5626
5987
  env: env4,
5627
- output: z4.object({
5628
- members: z4.array(
5629
- z4.object({
5630
- address: z4.string(),
5631
- active: z4.boolean(),
5632
- 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(),
5633
5994
  activeUntil: timestampOutput4,
5634
- activeUntilRelative: z4.string(),
5995
+ activeUntilRelative: z5.string(),
5635
5996
  lastHeartbeatAt: timestampOutput4,
5636
- lastHeartbeatRelative: z4.string()
5997
+ lastHeartbeatRelative: z5.string()
5637
5998
  })
5638
5999
  ),
5639
- count: z4.number()
6000
+ count: z5.number()
5640
6001
  }),
5641
6002
  examples: [
5642
6003
  { description: "List members using default indexer snapshot" },
@@ -5714,17 +6075,17 @@ members.command("list", {
5714
6075
  });
5715
6076
  members.command("info", {
5716
6077
  description: "Get registry record and active status for a member address.",
5717
- args: z4.object({
5718
- address: z4.string().describe("Member wallet address")
6078
+ args: z5.object({
6079
+ address: z5.string().describe("Member wallet address")
5719
6080
  }),
5720
6081
  env: env4,
5721
- output: z4.object({
5722
- address: z4.string(),
5723
- active: z4.boolean(),
6082
+ output: z5.object({
6083
+ address: z5.string(),
6084
+ active: z5.boolean(),
5724
6085
  activeUntil: timestampOutput4,
5725
6086
  lastHeartbeatAt: timestampOutput4,
5726
- activeUntilRelative: z4.string(),
5727
- lastHeartbeatRelative: z4.string()
6087
+ activeUntilRelative: z5.string(),
6088
+ lastHeartbeatRelative: z5.string()
5728
6089
  }),
5729
6090
  examples: [
5730
6091
  {
@@ -5761,9 +6122,9 @@ members.command("info", {
5761
6122
  members.command("count", {
5762
6123
  description: "Get active and total-known member counts from Registry.",
5763
6124
  env: env4,
5764
- output: z4.object({
5765
- active: z4.number(),
5766
- total: z4.number()
6125
+ output: z5.object({
6126
+ active: z5.number(),
6127
+ total: z5.number()
5767
6128
  }),
5768
6129
  examples: [{ description: "Count active and known members" }],
5769
6130
  async run(c) {
@@ -5786,12 +6147,12 @@ members.command("count", {
5786
6147
  members.command("fees", {
5787
6148
  description: "Get registration and heartbeat fee settings.",
5788
6149
  env: env4,
5789
- output: z4.object({
5790
- registrationFeeWei: z4.string(),
5791
- registrationFee: z4.string(),
5792
- heartbeatFeeWei: z4.string(),
5793
- heartbeatFee: z4.string(),
5794
- 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()
5795
6156
  }),
5796
6157
  examples: [{ description: "Inspect current registry fee configuration" }],
5797
6158
  async run(c) {
@@ -5822,23 +6183,196 @@ members.command("fees", {
5822
6183
  });
5823
6184
  }
5824
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
+ });
5825
6359
 
5826
6360
  // src/commands/treasury.ts
5827
- import { Cli as Cli5, z as z5 } from "incur";
5828
- var env5 = z5.object({
5829
- 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")
5830
6364
  });
5831
- var timestampOutput5 = z5.union([z5.number(), z5.string()]);
6365
+ var timestampOutput5 = z6.union([z6.number(), z6.string()]);
5832
6366
  var treasury = Cli5.create("treasury", {
5833
6367
  description: "Inspect treasury balances, execution status, and spend controls."
5834
6368
  });
5835
6369
  treasury.command("balance", {
5836
6370
  description: "Get current native token balance for the treasury contract.",
5837
6371
  env: env5,
5838
- output: z5.object({
5839
- address: z5.string(),
5840
- balanceWei: z5.string(),
5841
- balance: z5.string()
6372
+ output: z6.object({
6373
+ address: z6.string(),
6374
+ balanceWei: z6.string(),
6375
+ balance: z6.string()
5842
6376
  }),
5843
6377
  examples: [{ description: "Check treasury balance" }],
5844
6378
  async run(c) {
@@ -5853,13 +6387,13 @@ treasury.command("balance", {
5853
6387
  });
5854
6388
  treasury.command("whitelist", {
5855
6389
  description: "Check whether an asset address is treasury-whitelisted.",
5856
- args: z5.object({
5857
- asset: z5.string().describe("Token/asset contract address")
6390
+ args: z6.object({
6391
+ asset: z6.string().describe("Token/asset contract address")
5858
6392
  }),
5859
6393
  env: env5,
5860
- output: z5.object({
5861
- asset: z5.string(),
5862
- whitelisted: z5.boolean()
6394
+ output: z6.object({
6395
+ asset: z6.string(),
6396
+ whitelisted: z6.boolean()
5863
6397
  }),
5864
6398
  examples: [
5865
6399
  {
@@ -5881,11 +6415,11 @@ treasury.command("whitelist", {
5881
6415
  treasury.command("major-spend-status", {
5882
6416
  description: "Read major-spend cooldown status for the treasury contract.",
5883
6417
  env: env5,
5884
- output: z5.object({
5885
- majorSpendCooldownSeconds: z5.number(),
6418
+ output: z6.object({
6419
+ majorSpendCooldownSeconds: z6.number(),
5886
6420
  lastMajorSpendAt: timestampOutput5,
5887
- lastMajorSpendRelative: z5.string(),
5888
- isMajorSpendAllowed: z5.boolean()
6421
+ lastMajorSpendRelative: z6.string(),
6422
+ isMajorSpendAllowed: z6.boolean()
5889
6423
  }),
5890
6424
  examples: [{ description: "Inspect treasury major-spend guardrails" }],
5891
6425
  async run(c) {
@@ -5919,13 +6453,13 @@ treasury.command("major-spend-status", {
5919
6453
  });
5920
6454
  treasury.command("executed", {
5921
6455
  description: "Check whether a treasury action for a proposal has executed.",
5922
- args: z5.object({
5923
- 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")
5924
6458
  }),
5925
6459
  env: env5,
5926
- output: z5.object({
5927
- proposalId: z5.number(),
5928
- executed: z5.boolean()
6460
+ output: z6.object({
6461
+ proposalId: z6.number(),
6462
+ executed: z6.boolean()
5929
6463
  }),
5930
6464
  examples: [{ args: { proposalId: 1 }, description: "Check execution status for proposal #1" }],
5931
6465
  async run(c) {
@@ -6091,20 +6625,20 @@ cli.command(council);
6091
6625
  cli.command(forum);
6092
6626
  cli.command(governance);
6093
6627
  cli.command(treasury);
6094
- var rootEnv = z6.object({
6095
- 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")
6096
6630
  });
6097
- var timestampOutput6 = z6.union([z6.number(), z6.string()]);
6631
+ var timestampOutput6 = z7.union([z7.number(), z7.string()]);
6098
6632
  cli.command("status", {
6099
6633
  description: "Get a cross-contract Assembly snapshot (members, council, governance, treasury).",
6100
6634
  env: rootEnv,
6101
- output: z6.object({
6102
- activeMemberCount: z6.number(),
6103
- seatCount: z6.number(),
6104
- proposalCount: z6.number(),
6105
- currentAuctionDay: z6.number(),
6106
- currentAuctionSlot: z6.number(),
6107
- 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()
6108
6642
  }),
6109
6643
  examples: [{ description: "Fetch the current Assembly system status" }],
6110
6644
  async run(c) {
@@ -6156,18 +6690,18 @@ cli.command("status", {
6156
6690
  });
6157
6691
  cli.command("health", {
6158
6692
  description: "Check cross-contract health for one address (membership, council, refunds, power).",
6159
- args: z6.object({
6160
- 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")
6161
6695
  }),
6162
6696
  env: rootEnv,
6163
- output: z6.object({
6164
- address: z6.string(),
6165
- isActive: z6.boolean(),
6697
+ output: z7.object({
6698
+ address: z7.string(),
6699
+ isActive: z7.boolean(),
6166
6700
  activeUntil: timestampOutput6,
6167
- activeUntilRelative: z6.string(),
6168
- isCouncilMember: z6.boolean(),
6169
- pendingReturnsWei: z6.string(),
6170
- votingPower: z6.number()
6701
+ activeUntilRelative: z7.string(),
6702
+ isCouncilMember: z7.boolean(),
6703
+ pendingReturnsWei: z7.string(),
6704
+ votingPower: z7.number()
6171
6705
  }),
6172
6706
  examples: [
6173
6707
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spectratools/assembly-cli",
3
- "version": "0.6.0",
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,11 +29,11 @@
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/cli-shared": "0.1.1",
36
- "@spectratools/tx-shared": "0.3.0"
35
+ "@spectratools/tx-shared": "0.3.0",
36
+ "@spectratools/cli-shared": "0.1.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "typescript": "5.7.3",