diff --git a/rusk-wallet/src/bin/command.rs b/rusk-wallet/src/bin/command.rs
index 3e0233326..75fbce712 100644
--- a/rusk-wallet/src/bin/command.rs
+++ b/rusk-wallet/src/bin/command.rs
@@ -159,6 +159,10 @@ pub(crate) enum Command {
#[arg(long)]
address: Option
,
+ /// Owner of the stake [default: same Public address of the stake]
+ #[arg(long)]
+ owner: Option,
+
/// Amount of DUSK to stake
#[arg(short, long)]
amt: Dusk,
@@ -393,21 +397,28 @@ impl Command {
}
Command::Stake {
address,
+ owner,
amt,
gas_limit,
gas_price,
} => {
let address = address.unwrap_or(wallet.default_address());
let addr_idx = wallet.find_index(&address)?;
+ let owner_idx =
+ owner.map(|owner| wallet.find_index(&owner)).transpose()?;
let gas = Gas::new(gas_limit).with_price(gas_price);
let tx = match address {
Address::Shielded(_) => {
wallet.sync().await?;
- wallet.phoenix_stake(addr_idx, amt, gas).await
+ wallet
+ .phoenix_stake(addr_idx, owner_idx, amt, gas)
+ .await
}
Address::Public(_) => {
- wallet.moonlight_stake(addr_idx, amt, gas).await
+ wallet
+ .moonlight_stake(addr_idx, owner_idx, amt, gas)
+ .await
}
}?;
diff --git a/rusk-wallet/src/bin/interactive.rs b/rusk-wallet/src/bin/interactive.rs
index 129594d64..d3330d5c1 100644
--- a/rusk-wallet/src/bin/interactive.rs
+++ b/rusk-wallet/src/bin/interactive.rs
@@ -373,6 +373,7 @@ fn confirm(cmd: &Command, wallet: &Wallet) -> anyhow::Result {
}
Command::Stake {
address,
+ owner,
amt,
gas_limit,
gas_price,
@@ -380,8 +381,10 @@ fn confirm(cmd: &Command, wallet: &Wallet) -> anyhow::Result {
let sender = address.as_ref().ok_or(Error::BadAddress)?;
let max_fee = gas_limit * gas_price;
let stake_to = wallet.public_address(wallet.find_index(sender)?)?;
+ let owner = owner.as_ref().unwrap_or(&stake_to);
println!(" > Pay with {}", sender.preview());
println!(" > Stake to {}", stake_to.preview());
+ println!(" > Stake owner {}", owner.preview());
println!(" > Amount to stake = {} DUSK", amt);
println!(" > Max fee = {} DUSK", Dusk::from(max_fee));
if let Address::Public(_) = sender {
diff --git a/rusk-wallet/src/bin/interactive/command_menu.rs b/rusk-wallet/src/bin/interactive/command_menu.rs
index f995787c7..3003027e4 100644
--- a/rusk-wallet/src/bin/interactive/command_menu.rs
+++ b/rusk-wallet/src/bin/interactive/command_menu.rs
@@ -14,7 +14,7 @@ use rusk_wallet::gas::{
DEFAULT_PRICE, GAS_PER_DEPLOY_BYTE, MIN_PRICE_DEPLOYMENT,
};
use rusk_wallet::{
- Address, Wallet, MAX_CONTRACT_INIT_ARG_SIZE, MAX_FUNCTION_NAME_SIZE,
+ Address, Error, Wallet, MAX_CONTRACT_INIT_ARG_SIZE, MAX_FUNCTION_NAME_SIZE,
};
use super::ProfileOp;
@@ -162,8 +162,29 @@ pub(crate) async fn online(
let mempool_gas_prices = wallet.get_mempool_gas_prices().await?;
+ let stake_idx = wallet
+ .find_index(&addr)
+ .expect("index to exists in interactive mode");
+ let stake_pk = wallet
+ .public_key(stake_idx)
+ .expect("public key to exists in interactive mode");
+
+ let owner = match wallet.find_stake_owner_account(stake_pk).await {
+ Ok(account) => account,
+ Err(Error::NotStaked) => {
+ let choices = wallet
+ .profiles()
+ .iter()
+ .map(|p| Address::Public(p.public_addr))
+ .collect();
+ prompt::request_address(stake_idx, choices)?
+ }
+ e => e?,
+ };
+
ProfileOp::Run(Box::new(Command::Stake {
address: Some(addr),
+ owner: Some(owner),
amt: prompt::request_stake_token_amt(balance)?,
gas_limit: prompt::request_gas_limit(gas::DEFAULT_LIMIT_CALL)?,
gas_price: prompt::request_gas_price(
diff --git a/rusk-wallet/src/bin/io/prompt.rs b/rusk-wallet/src/bin/io/prompt.rs
index ecae173c9..7498d2c19 100644
--- a/rusk-wallet/src/bin/io/prompt.rs
+++ b/rusk-wallet/src/bin/io/prompt.rs
@@ -354,6 +354,19 @@ pub(crate) fn request_transaction_model() -> anyhow::Result {
)
}
+/// Request transaction model to use
+pub(crate) fn request_address(
+ current_idx: u8,
+ choices: Vec,
+) -> anyhow::Result {
+ Ok(Select::new(
+ "Please select the moonlight address to use as stake owner",
+ choices,
+ )
+ .with_starting_cursor(current_idx as usize)
+ .prompt()?)
+}
+
/// Request contract WASM file location
pub(crate) fn request_contract_code() -> anyhow::Result {
let validator = |path_str: &str| {
diff --git a/rusk-wallet/src/clients.rs b/rusk-wallet/src/clients.rs
index 2836efa92..368074d86 100644
--- a/rusk-wallet/src/clients.rs
+++ b/rusk-wallet/src/clients.rs
@@ -11,6 +11,7 @@ use std::sync::{Arc, Mutex};
use dusk_bytes::Serializable;
use execution_core::signatures::bls::PublicKey as BlsPublicKey;
+use execution_core::stake::{StakeFundOwner, StakeKeys};
use execution_core::transfer::moonlight::AccountData;
use execution_core::transfer::phoenix::{Note, NoteLeaf, Prove};
use execution_core::transfer::Transaction;
@@ -322,6 +323,33 @@ impl State {
Ok(stake_data)
}
+ /// Get the stake owner of a given stake account.
+ pub(crate) async fn fetch_stake_owner(
+ &self,
+ pk: &BlsPublicKey,
+ ) -> Result