Skip to content

Commit

Permalink
Merge pull request #3196 from dusk-network/wallet-stake-owner
Browse files Browse the repository at this point in the history
  • Loading branch information
herr-seppia authored Dec 18, 2024
2 parents 341b58e + 38e3441 commit a580bfd
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 36 deletions.
12 changes: 12 additions & 0 deletions contracts/stake/tests/partial_stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fn stake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
stake_1,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -79,6 +80,7 @@ fn stake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
stake_2,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -112,6 +114,7 @@ fn stake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
stake_3,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -146,6 +149,7 @@ fn stake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
stake_4,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -179,6 +183,7 @@ fn unstake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
STAKE_VALUE,
GAS_LIMIT,
GAS_PRICE,
Expand All @@ -200,6 +205,7 @@ fn unstake() -> Result<(), PiecrustError> {
rng,
&moonlight_sk,
&stake_sk,
&stake_sk,
unstake_1,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -229,6 +235,7 @@ fn unstake() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
unstake_1,
GAS_LIMIT,
GAS_PRICE,
Expand All @@ -254,6 +261,7 @@ fn unstake() -> Result<(), PiecrustError> {
rng,
&moonlight_sk,
&stake_sk,
&stake_sk,
unstake_2,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -291,6 +299,7 @@ fn unstake() -> Result<(), PiecrustError> {
rng,
&moonlight_sk,
&stake_sk,
&stake_sk,
unstake_3,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -333,6 +342,7 @@ fn withdraw_reward() -> Result<(), PiecrustError> {
let tx = moonlight_stake(
&moonlight_sk,
&stake_sk,
&stake_sk,
STAKE_VALUE,
GAS_LIMIT,
GAS_PRICE,
Expand All @@ -357,6 +367,7 @@ fn withdraw_reward() -> Result<(), PiecrustError> {
rng,
&moonlight_sk,
&stake_sk,
&stake_sk,
reward_withdawal_1,
GAS_LIMIT,
GAS_PRICE,
Expand Down Expand Up @@ -391,6 +402,7 @@ fn withdraw_reward() -> Result<(), PiecrustError> {
rng,
&moonlight_sk,
&stake_sk,
&stake_sk,
reward_withdawal_2,
GAS_LIMIT,
GAS_PRICE,
Expand Down
6 changes: 3 additions & 3 deletions contracts/stake/tests/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn stake_withdraw_unstake() {
// Stake

// Fashion a Stake struct
let stake = Stake::new(&stake_sk, INITIAL_STAKE, CHAIN_ID);
let stake = Stake::new(&stake_sk, &stake_sk, INITIAL_STAKE, CHAIN_ID);
let stake_bytes = rkyv::to_bytes::<_, 1024>(&stake)
.expect("Should serialize Stake correctly")
.to_vec();
Expand Down Expand Up @@ -153,7 +153,7 @@ fn stake_withdraw_unstake() {
input_notes[1].gen_nullifier(&phoenix_sender_sk),
]),
);
let withdraw = StakeWithdraw::new(&stake_sk, withdraw);
let withdraw = StakeWithdraw::new(&stake_sk, &stake_sk, withdraw);

let withdraw_bytes = rkyv::to_bytes::<_, 2048>(&withdraw)
.expect("Serializing Withdraw should succeed")
Expand Down Expand Up @@ -248,7 +248,7 @@ fn stake_withdraw_unstake() {
]),
);

let unstake = StakeWithdraw::new(&stake_sk, withdraw);
let unstake = StakeWithdraw::new(&stake_sk, &stake_sk, withdraw);

let unstake_bytes = rkyv::to_bytes::<_, 2048>(&unstake)
.expect("Serializing Unstake should succeed")
Expand Down
44 changes: 32 additions & 12 deletions execution-core/src/stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,18 @@ impl Stake {
const MESSAGE_SIZE: usize =
1 + BlsPublicKey::SIZE + BlsPublicKey::SIZE + u64::SIZE;

/// Create a new stake.
/// Create a new stake specifying the owner.
#[must_use]
pub fn new(sk: &BlsSecretKey, value: u64, chain_id: u8) -> Self {
let key = BlsPublicKey::from(sk);
pub fn new(
account_sk: &BlsSecretKey,
owner_sk: &BlsSecretKey,
value: u64,
chain_id: u8,
) -> Self {
let account = BlsPublicKey::from(account_sk);
let owner = BlsPublicKey::from(owner_sk);

let keys = StakeKeys::single_key(key);
let keys = StakeKeys::new(account, owner);

let mut stake = Stake {
chain_id,
Expand All @@ -68,14 +74,14 @@ impl Stake {
let msg = stake.signature_message();

stake.signature = DoubleSignature {
account: sk.sign(&msg),
owner: sk.sign(&msg),
account: account_sk.sign(&msg),
owner: owner_sk.sign(&msg),
};

stake
}

/// Create a new stake.
/// Create a new stake from a contract.
#[must_use]
pub fn new_from_contract(
sk: &BlsSecretKey,
Expand Down Expand Up @@ -249,10 +255,15 @@ pub struct Withdraw {
}

impl Withdraw {
/// Create a new withdraw call.
/// Create a new withdraw call specifying the owner.
#[must_use]
pub fn new(sk: &BlsSecretKey, withdraw: TransferWithdraw) -> Self {
let account = BlsPublicKey::from(sk);
pub fn new(
account_sk: &BlsSecretKey,
owner_sk: &BlsSecretKey,
withdraw: TransferWithdraw,
) -> Self {
let account = BlsPublicKey::from(account_sk);

let mut stake_withdraw = Withdraw {
account,
withdraw,
Expand All @@ -262,13 +273,22 @@ impl Withdraw {
let msg = stake_withdraw.signature_message();

stake_withdraw.signature = DoubleSignature {
account: sk.sign(&msg),
owner: sk.sign(&msg),
account: account_sk.sign(&msg),
owner: owner_sk.sign(&msg),
};

stake_withdraw
}

/// Create a new withdraw call using the same account as the owner.
#[must_use]
pub fn with_single_key(
sk: &BlsSecretKey,
withdraw: TransferWithdraw,
) -> Self {
Self::new(sk, sk, withdraw)
}

/// The public key to withdraw from.
#[must_use]
pub fn account(&self) -> &BlsPublicKey {
Expand Down
15 changes: 13 additions & 2 deletions rusk-wallet/src/bin/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ pub(crate) enum Command {
#[arg(long)]
address: Option<Address>,

/// Owner of the stake [default: same Public address of the stake]
#[arg(long)]
owner: Option<Address>,

/// Amount of DUSK to stake
#[arg(short, long)]
amt: Dusk,
Expand Down Expand Up @@ -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
}
}?;

Expand Down
3 changes: 3 additions & 0 deletions rusk-wallet/src/bin/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,18 @@ fn confirm(cmd: &Command, wallet: &Wallet<WalletFile>) -> anyhow::Result<bool> {
}
Command::Stake {
address,
owner,
amt,
gas_limit,
gas_price,
} => {
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 {
Expand Down
23 changes: 22 additions & 1 deletion rusk-wallet/src/bin/interactive/command_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
13 changes: 13 additions & 0 deletions rusk-wallet/src/bin/io/prompt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,19 @@ pub(crate) fn request_transaction_model() -> anyhow::Result<TransactionModel> {
)
}

/// Request transaction model to use
pub(crate) fn request_address(
current_idx: u8,
choices: Vec<Address>,
) -> anyhow::Result<Address> {
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<PathBuf> {
let validator = |path_str: &str| {
Expand Down
28 changes: 28 additions & 0 deletions rusk-wallet/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Option<StakeFundOwner>, Error> {
let status = self.status;
status("Fetching stake owner...");

// the target type of the deserialization has to match the return type
// of the contract-query
let stake_keys: Option<StakeKeys> = rkyv::from_bytes(
&self
.client
.contract_query::<_, _, 1024>(
STAKE_CONTRACT,
"get_stake_keys",
pk,
)
.await?,
)
.map_err(|_| Error::Rkyv)?;

let stake_owner = stake_keys.map(|keys| keys.owner);

Ok(stake_owner)
}

pub(crate) fn store(&self) -> &LocalStore {
&self.store
}
Expand Down
Loading

0 comments on commit a580bfd

Please sign in to comment.