diff --git a/client/src/bin/space-cli.rs b/client/src/bin/space-cli.rs index 62b75b3..46cd279 100644 --- a/client/src/bin/space-cli.rs +++ b/client/src/bin/space-cli.rs @@ -28,7 +28,7 @@ use spaces_client::{ }, wallets::{AddressKind, WalletResponse}, }; -use spaces_client::rpc::{AuthorizeParams, CommitParams, CreateNumParams, DelegateParams, SetFallbackParams}; +use spaces_client::rpc::{CommitParams, CreateNumParams, DelegateParams, OperateParams, SetFallbackParams}; use spaces_client::store::Sha256; use spaces_protocol::bitcoin::{Amount, FeeRate, OutPoint, Txid}; use spaces_protocol::slabel::SLabel; @@ -188,8 +188,8 @@ enum Commands { fee_rate: Option, }, /// Initialize a space or numeric for operation of off-chain subspaces - #[command(name = "delegate")] - Delegate { + #[command(name = "operate")] + Operate { /// Space name, numeric, or num id subject: Subject, /// Fee rate to use in sat/vB @@ -216,9 +216,9 @@ enum Commands { #[arg(long, short)] fee_rate: Option, }, - /// Authorize someone else to operate a space or numeric - #[command(name = "authorize")] - Authorize { + /// Delegate operation of a space or numeric to someone else + #[command(name = "delegate")] + Delegate { /// Space name, numeric, or num id #[arg(display_order = 0)] subject: Subject, @@ -964,9 +964,9 @@ async fn handle_commands(cli: &SpaceCli, command: Commands) -> Result<(), Client .map_err(|e| ClientError::Custom(e.to_string()))?; println!("{}", serde_json::to_string(&numout).expect("result")); } - Commands::Delegate { subject, fee_rate } => { + Commands::Operate { subject, fee_rate } => { cli.send_request( - Some(RpcWalletRequest::Delegate(DelegateParams { + Some(RpcWalletRequest::Operate(OperateParams { subject, })), None, @@ -974,7 +974,7 @@ async fn handle_commands(cli: &SpaceCli, command: Commands) -> Result<(), Client false, ) .await?; - println!("Delegation should be complete once tx is confirmed"); + println!("Operate setup should be complete once tx is confirmed"); } Commands::Commit { subject, root, fee_rate } => { cli.send_request( @@ -1001,9 +1001,9 @@ async fn handle_commands(cli: &SpaceCli, command: Commands) -> Result<(), Client .await?; println!("Rollback transaction sent"); } - Commands::Authorize { subject, to, fee_rate } => { + Commands::Delegate { subject, to, fee_rate } => { cli.send_request( - Some(RpcWalletRequest::Authorize(AuthorizeParams { + Some(RpcWalletRequest::Delegate(DelegateParams { subject, to, })), diff --git a/client/src/rpc.rs b/client/src/rpc.rs index 7be7665..2d2c4bb 100644 --- a/client/src/rpc.rs +++ b/client/src/rpc.rs @@ -471,12 +471,12 @@ pub enum RpcWalletRequest { Transfer(TransferSpacesParams), #[serde(rename = "createnum")] CreateNum(CreateNumParams), - #[serde(rename = "delegate")] - Delegate(DelegateParams), + #[serde(rename = "operate")] + Operate(OperateParams), #[serde(rename = "commit")] Commit(CommitParams), - #[serde(rename = "authorize")] - Authorize(AuthorizeParams), + #[serde(rename = "delegate")] + Delegate(DelegateParams), #[serde(rename = "setfallback")] SetFallback(SetFallbackParams), #[serde(rename = "send")] @@ -502,12 +502,12 @@ pub struct CreateNumParams { } #[derive(Clone, Serialize, Deserialize)] -pub struct DelegateParams { +pub struct OperateParams { pub subject: Subject, } #[derive(Clone, Serialize, Deserialize)] -pub struct AuthorizeParams { +pub struct DelegateParams { pub subject: Subject, pub to: String, } @@ -865,7 +865,12 @@ impl RpcServerImpl { let addr = listener.local_addr()?; info!("Listening at {addr}"); - let handle = listener.start(self.clone().into_rpc()); + let mut module = self.clone().into_rpc(); + let methods: Vec = module.method_names().map(|s| s.to_string()).collect(); + module.register_method("rpc.discover", move |_, _| { + serde_json::json!({ "methods": methods }) + }).expect("register rpc.discover"); + let handle = listener.start(module); let mut signal = signal.subscribe(); set.spawn(async move { diff --git a/client/src/wallets.rs b/client/src/wallets.rs index 2485a62..89dd038 100644 --- a/client/src/wallets.rs +++ b/client/src/wallets.rs @@ -400,7 +400,7 @@ fn commit_params_to_req( let num_info = chain .get_num_info(&spk_id)? - .ok_or_else(|| anyhow!("commit: num '{}' not found - use delegate first", spk_id))?; + .ok_or_else(|| anyhow!("commit: num '{}' not found - use operate first", spk_id))?; if !wallet.is_mine(num_info.numout.script_pubkey.clone()) { return Err(anyhow!("commit: you don't control '{}'", spk_id)); @@ -699,7 +699,7 @@ impl RpcWallet { Ok(()) } - /// Check if wallet can operate on a subject by verifying it controls the delegated num + /// Check if wallet can operate on a subject by verifying it controls the operator num fn can_operate( wallet: &SpacesWallet, chain: &mut Chain, @@ -1567,7 +1567,7 @@ impl RpcWallet { let reqs = commit_params_to_req(chain, wallet, params)?; builder = builder.add_commitment(reqs) } - RpcWalletRequest::Delegate(params) => { + RpcWalletRequest::Operate(params) => { let unique_num_spk = advance_address_to_unique_num_spk(chain, wallet)?; match ¶ms.subject { @@ -1575,14 +1575,14 @@ impl RpcWallet { let numeric: SNumeric = label.clone().try_into().unwrap(); let key = NumericKey::from_numeric::(&numeric); let id = chain.get_num_id(&key)?.ok_or_else(|| { - anyhow!("delegate: numeric '{}' not found", label) + anyhow!("operate: numeric '{}' not found", label) })?; let num = match chain.get_num_info(&id)? { - None => return Err(anyhow!("delegate: num '{}' not found", id)), + None => return Err(anyhow!("operate: num '{}' not found", id)), Some(full) if !wallet.is_mine(full.numout.script_pubkey.clone()) => { - return Err(anyhow!("delegate: you don't own '{}'", label)) + return Err(anyhow!("operate: you don't own '{}'", label)) } Some(full) if wallet @@ -1590,7 +1590,7 @@ impl RpcWallet { .is_none() => { return Err(anyhow!( - "delegate '{}': wallet already has a pending tx", + "operate '{}': wallet already has a pending tx", label )) } @@ -1603,11 +1603,11 @@ impl RpcWallet { } Subject::NumId(id) => { let num = match chain.get_num_info(id)? { - None => return Err(anyhow!("delegate: num '{}' not found", id)), + None => return Err(anyhow!("operate: num '{}' not found", id)), Some(full) if !wallet.is_mine(full.numout.script_pubkey.clone()) => { - return Err(anyhow!("delegate: you don't own '{}'", id)) + return Err(anyhow!("operate: you don't own '{}'", id)) } Some(full) if wallet @@ -1615,7 +1615,7 @@ impl RpcWallet { .is_none() => { return Err(anyhow!( - "delegate '{}': wallet already has a pending tx", + "operate '{}': wallet already has a pending tx", id )) } @@ -1631,18 +1631,18 @@ impl RpcWallet { let full = match chain.get_space_info(&spacehash)? { None => { - return Err(anyhow!("delegate: space '{}' not found", label)) + return Err(anyhow!("operate: space '{}' not found", label)) } Some(full) if full.spaceout.space.is_none() || !full.spaceout.space.as_ref().unwrap().is_owned() || !wallet.is_mine(full.spaceout.script_pubkey.clone()) => { - return Err(anyhow!("delegate: you don't own '{}'", label)) + return Err(anyhow!("operate: you don't own '{}'", label)) } Some(full) if wallet.get_utxo(full.outpoint()).is_none() => { return Err(anyhow!( - "delegate '{}': wallet already has a pending tx", + "operate '{}': wallet already has a pending tx", label )) } @@ -1661,13 +1661,13 @@ impl RpcWallet { } } } - RpcWalletRequest::Authorize(params) => { + RpcWalletRequest::Delegate(params) => { let delegate_utxo = find_delegate_utxo(chain, ¶ms.subject)?; if !wallet.is_mine(delegate_utxo.numout.script_pubkey.clone()) { - return Err(anyhow!("authorize: you don't own '{}'", params.subject)); + return Err(anyhow!("delegate: you don't own '{}'", params.subject)); } let Some(r) = Self::resolve(network, chain, ¶ms.to, true)? else { - return Err(anyhow!("authorize: recipient '{}' not found", params.to)); + return Err(anyhow!("delegate: recipient '{}' not found", params.to)); }; builder = builder.add_num_transfer(NumTransfer { num: delegate_utxo, @@ -2137,7 +2137,7 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result(&numeric); let id = chain.get_num_id(&key)?.ok_or_else(|| { - anyhow!("authorize: numeric '{}' not found", label) + anyhow!("delegate: numeric '{}' not found", label) })?; Some(id) } @@ -2146,50 +2146,50 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result(num_utxo.numout.script_pubkey); if target == num_id { - return Err(anyhow!("authorize: num has no separate delegation - call delegate first")) + return Err(anyhow!("delegate: num has no separate operator - call operate first")) } let dk = DelegatorKey::from_id::(target); let Some(delegator) = chain.get_delegator(&dk)? else { - return Err(anyhow!("authorize: num {} is not delegated - call delegate first", subject)); + return Err(anyhow!("delegate: num {} is not operated - call operate first", subject)); }; if !delegator.is_numeric() { - return Err(anyhow!("authorize: num {} is delegated to {} - call delegate to switch", + return Err(anyhow!("delegate: num {} is delegated to {} - call operate to switch", subject, delegator)); } let numeric : SNumeric = delegator.clone().try_into().expect("valid numeric"); if numeric != num_utxo.numout.num.name { - return Err(anyhow!("authorize: num {} is delegated to {} - call delegate to switch", + return Err(anyhow!("delegate: num {} is delegated to {} - call operate to switch", subject, delegator)); } target } else { let Subject::Label(label) = subject else { - return Err(anyhow!("authorize: expected a space, got {}", subject)) + return Err(anyhow!("delegate: expected a space, got {}", subject)) }; let space_utxo = chain .get_space_info(&SpaceKey::from(Sha256::hash(label.as_ref())))? - .ok_or_else(|| anyhow!("authorize: space '{}' not found", label))?; + .ok_or_else(|| anyhow!("delegate: space '{}' not found", label))?; let Some(space) = space_utxo.spaceout.space else { - return Err(anyhow!("authorize: space {} not found", subject)); + return Err(anyhow!("delegate: space {} not found", subject)); }; let target = NumId::from_spk::(space_utxo.spaceout.script_pubkey); let dk = DelegatorKey::from_id::(target); let Some(delegator) = chain.get_delegator(&dk)? else { - return Err(anyhow!("authorize: space {} is not delegated - call delegate first", subject)); + return Err(anyhow!("delegate: space {} is not operated - call operate first", subject)); }; if delegator != space.name { - return Err(anyhow!("authorize: num {} is delegated to {} - call delegate to switch", + return Err(anyhow!("delegate: num {} is delegated to {} - call operate to switch", target, delegator) ); } @@ -2198,7 +2198,7 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result anyhow::Result<()> { let delegate = wallet_do( rig, ALICE, - vec![RpcWalletRequest::Delegate(DelegateParams { + vec![RpcWalletRequest::Operate(OperateParams { subject: space_name.clone().into(), })], false, @@ -327,7 +327,7 @@ async fn it_should_handle_multiple_commitments(rig: &TestRig) -> anyhow::Result< let delegate = wallet_do( rig, ALICE, - vec![RpcWalletRequest::Delegate(DelegateParams { + vec![RpcWalletRequest::Operate(OperateParams { subject: space_name.clone().into(), })], false, @@ -451,7 +451,7 @@ async fn it_should_override_pending_commitments(rig: &TestRig) -> anyhow::Result let delegate = wallet_do( rig, ALICE, - vec![RpcWalletRequest::Delegate(DelegateParams { + vec![RpcWalletRequest::Operate(OperateParams { subject: space_name.clone().into(), })], false, @@ -1161,7 +1161,7 @@ async fn it_should_transfer_ptr_with_n_to_n_rule(rig: &TestRig) -> anyhow::Resul // Delegate to create PTR wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { subject: space_name.clone().into() }) + RpcWalletRequest::Operate(OperateParams { subject: space_name.clone().into() }) ], false).await?; mine_and_sync(rig, 1).await?; @@ -1223,7 +1223,7 @@ async fn it_should_delegate_and_commit_numeric(rig: &TestRig) -> anyhow::Result< // Delegate the numeric let delegate_res = wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { + RpcWalletRequest::Operate(OperateParams { subject: Subject::Label(numeric_label.clone()), }) ], false).await?; @@ -1309,7 +1309,7 @@ async fn it_should_authorize_numeric_to_another_wallet(rig: &TestRig) -> anyhow: // Delegate it let delegate_res = wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { + RpcWalletRequest::Operate(OperateParams { subject: Subject::Label(numeric_label.clone()), }) ], false).await?; @@ -1395,7 +1395,7 @@ async fn it_should_authorize_numeric_to_another_wallet(rig: &TestRig) -> anyhow: // Test 5: Alice re-delegates to revoke Bob's authorization println!("\nTest 5: Alice re-delegates to revoke Bob's authorization"); let redelegate_res = wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { + RpcWalletRequest::Operate(OperateParams { subject: Subject::Label(numeric_label.clone()), }) ], false).await?; @@ -1493,14 +1493,14 @@ async fn it_should_create_multiple_nums_same_tx(rig: &TestRig) -> anyhow::Result // Test 3: Delegate both and verify independent delegations println!("\nTest 3: Delegate both nums independently"); wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { + RpcWalletRequest::Operate(OperateParams { subject: Subject::Label(name_a.to_slabel()), }) ], false).await?; mine_and_sync(rig, 1).await?; wallet_do(rig, ALICE, vec![ - RpcWalletRequest::Delegate(DelegateParams { + RpcWalletRequest::Operate(OperateParams { subject: Subject::Label(name_b.to_slabel()), }) ], false).await?;