auths_cli/commands/
witness_set.rs1use anyhow::{Context, Result};
11use auths_sdk::workflows::witness_set::{
12 build_witness_set, declare_witness_set, resolve_declaration_alias,
13};
14use clap::{Parser, Subcommand};
15
16use crate::commands::executable::ExecutableCommand;
17use crate::config::CliConfig;
18use crate::factories::storage::build_auths_context;
19use crate::ux::format::{JsonResponse, is_json_mode};
20
21#[derive(Parser, Debug, Clone)]
23#[command(
24 about = "Declare the spend-anchor witness set, anchored in your KEL",
25 after_help = "Examples:
26 auths witness-set said --member w1=<hex> --member w2=p256:<hex> --threshold 2
27 auths witness-set declare --member network=did:key:z6Mk... --threshold 1
28
29Member keys carry their curve in-band: a CESR verkey, a did:key, `<curve>:<hex>`,
30or bare hex (Ed25519 — the checkpoint-signing curve)."
31)]
32pub struct WitnessSetCommand {
33 #[command(subcommand)]
34 pub subcommand: WitnessSetSubcommand,
35}
36
37#[derive(Subcommand, Debug, Clone)]
39pub enum WitnessSetSubcommand {
40 Declare {
43 #[clap(long = "member", value_name = "NAME=KEY", required = true)]
45 members: Vec<String>,
46
47 #[clap(long, value_name = "T")]
49 threshold: u32,
50
51 #[clap(long, value_name = "ALIAS")]
54 key: Option<String>,
55 },
56
57 Said {
59 #[clap(long = "member", value_name = "NAME=KEY", required = true)]
61 members: Vec<String>,
62
63 #[clap(long, value_name = "T")]
65 threshold: u32,
66 },
67}
68
69#[derive(serde::Serialize)]
70struct DeclareResponse {
71 set_said: String,
72 ixn_said: String,
73 sequence: u128,
74}
75
76impl ExecutableCommand for WitnessSetCommand {
77 fn execute(&self, ctx: &CliConfig) -> Result<()> {
78 match &self.subcommand {
79 WitnessSetSubcommand::Said { members, threshold } => print_said(members, *threshold),
80 WitnessSetSubcommand::Declare {
81 members,
82 threshold,
83 key,
84 } => declare(ctx, members, *threshold, key.clone()),
85 }
86 }
87}
88
89fn print_said(members: &[String], threshold: u32) -> Result<()> {
91 let set = build_witness_set(members, threshold).map_err(anyhow::Error::new)?;
92 if is_json_mode() {
93 JsonResponse::success(
94 "witness-set said",
95 serde_json::json!({ "set_said": set.said }),
96 )
97 .print()?;
98 } else {
99 println!("{}", set.said);
100 }
101 Ok(())
102}
103
104fn declare(ctx: &CliConfig, members: &[String], threshold: u32, key: Option<String>) -> Result<()> {
106 let set = build_witness_set(members, threshold).map_err(anyhow::Error::new)?;
107 let repo_path = auths_sdk::storage_layout::layout::resolve_repo_path(ctx.repo_path.clone())?;
108 let sdk_ctx = build_auths_context(
109 &repo_path,
110 &ctx.env_config,
111 Some(ctx.passphrase_provider.clone()),
112 )?;
113 let alias = resolve_declaration_alias(&sdk_ctx, key).map_err(anyhow::Error::new)?;
114 let declared = declare_witness_set(&sdk_ctx, &alias, &set)
115 .with_context(|| format!("Failed to declare witness set {}", set.said))?;
116
117 if is_json_mode() {
118 JsonResponse::success(
119 "witness-set declare",
120 DeclareResponse {
121 set_said: declared.set_said,
122 ixn_said: declared.ixn_said,
123 sequence: declared.sequence,
124 },
125 )
126 .print()?;
127 } else {
128 println!("✓ Witness set declared in your KEL:");
129 println!(" set SAID {}", declared.set_said);
130 println!(
131 " anchored ixn {} (seq {})",
132 declared.ixn_said, declared.sequence
133 );
134 println!(" verifiers now hold your anchors to exactly this set");
135 }
136 Ok(())
137}