Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions client/src/bin/space-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -188,8 +188,8 @@ enum Commands {
fee_rate: Option<u64>,
},
/// 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
Expand All @@ -216,9 +216,9 @@ enum Commands {
#[arg(long, short)]
fee_rate: Option<u64>,
},
/// 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,
Expand Down Expand Up @@ -964,17 +964,17 @@ 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,
fee_rate,
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(
Expand All @@ -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,
})),
Expand Down
19 changes: 12 additions & 7 deletions client/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -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,
}
Expand Down Expand Up @@ -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<String> = 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 {
Expand Down
56 changes: 28 additions & 28 deletions client/src/wallets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1567,30 +1567,30 @@ 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 &params.subject {
Subject::Label(label) if label.is_numeric() => {
let numeric: SNumeric = label.clone().try_into().unwrap();
let key = NumericKey::from_numeric::<Sha256>(&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
.get_utxo(OutPoint::new(full.txid, full.numout.n as u32))
.is_none() =>
{
return Err(anyhow!(
"delegate '{}': wallet already has a pending tx",
"operate '{}': wallet already has a pending tx",
label
))
}
Expand All @@ -1603,19 +1603,19 @@ 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
.get_utxo(OutPoint::new(full.txid, full.numout.n as u32))
.is_none() =>
{
return Err(anyhow!(
"delegate '{}': wallet already has a pending tx",
"operate '{}': wallet already has a pending tx",
id
))
}
Expand All @@ -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
))
}
Expand All @@ -1661,13 +1661,13 @@ impl RpcWallet {
}
}
}
RpcWalletRequest::Authorize(params) => {
RpcWalletRequest::Delegate(params) => {
let delegate_utxo = find_delegate_utxo(chain, &params.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, &params.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,
Expand Down Expand Up @@ -2137,7 +2137,7 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result<Fu
.expect("valid numeric");
let key = NumericKey::from_numeric::<Sha256>(&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)
}
Expand All @@ -2146,50 +2146,50 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result<Fu

let target = if let Some(num_id) = num_id {
let Some(num_utxo) = chain.get_num_info(&num_id)? else {
return Err(anyhow!("authorize: num {} not found", subject));
return Err(anyhow!("delegate: num {} not found", subject));
};

let target = NumId::from_spk::<Sha256>(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::<Sha256>(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::<Sha256>(space_utxo.spaceout.script_pubkey);
let dk = DelegatorKey::from_id::<Sha256>(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)
);
}
Expand All @@ -2198,7 +2198,7 @@ fn find_delegate_utxo(chain: &mut Chain, subject: &Subject) -> anyhow::Result<Fu
};

let Some(num_utxo) = chain.get_num_info(&target)? else {
return Err(anyhow!("authorize: target '{}' not found - call delegate first", target));
return Err(anyhow!("delegate: target '{}' not found - call operate first", target));
};

Ok(num_utxo)
Expand Down
20 changes: 10 additions & 10 deletions client/tests/ptr_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use spaces_client::{
},
wallets::{AddressKind, WalletResponse},
};
use spaces_client::rpc::{CommitParams, CreateNumParams, DelegateParams, SetFallbackParams, Subject, TransferSpacesParams};
use spaces_client::rpc::{CommitParams, CreateNumParams, OperateParams, SetFallbackParams, Subject, TransferSpacesParams};
use spaces_client::store::Sha256;
use spaces_protocol::{bitcoin, bitcoin::{FeeRate}};
use spaces_protocol::bitcoin::hashes::{sha256, Hash};
Expand Down Expand Up @@ -174,7 +174,7 @@ async fn it_should_commit_and_rollback(rig: &TestRig) -> anyhow::Result<()> {
let delegate = wallet_do(
rig,
ALICE,
vec![RpcWalletRequest::Delegate(DelegateParams {
vec![RpcWalletRequest::Operate(OperateParams {
subject: space_name.clone().into(),
})],
false,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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?;

Expand Down Expand Up @@ -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?;
Expand Down Expand Up @@ -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?;
Expand Down Expand Up @@ -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?;
Expand Down Expand Up @@ -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?;
Expand Down
Loading