Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rusk-wallet: support different owner key for stake operations #3196

Merged
merged 7 commits into from
Dec 18, 2024
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
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
Loading