use alloc::vec::Vec;
use dusk_bytes::Serializable;
use dusk_core::abi::ContractId;
use dusk_core::signatures::bls::{
PublicKey as BlsPublicKey, SecretKey as BlsSecretKey,
};
use dusk_core::stake::{STAKE_CONTRACT, Stake, Withdraw as StakeWithdraw};
use dusk_core::transfer::data::{
ContractCall, ContractDeploy, TransactionData,
};
use dusk_core::transfer::moonlight::Transaction as MoonlightTransaction;
use dusk_core::transfer::phoenix::{
Note, NoteOpening, Prove, PublicKey as PhoenixPublicKey,
SecretKey as PhoenixSecretKey, Transaction as PhoenixTransaction,
};
use dusk_core::transfer::withdraw::{
Withdraw, WithdrawReceiver, WithdrawReplayToken,
};
use dusk_core::transfer::{TRANSFER_CONTRACT, Transaction};
use dusk_core::{BlsScalar, Error, JubJubScalar};
use ff::Field;
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
#[allow(clippy::too_many_arguments)]
pub fn phoenix<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
sender_sk: &PhoenixSecretKey,
refund_pk: &PhoenixPublicKey,
receiver_pk: &PhoenixPublicKey,
inputs: Vec<(Note, NoteOpening)>,
root: BlsScalar,
transfer_value: u64,
is_transfer: bool,
deposit: u64,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
data: Option<impl Into<TransactionData>>,
prover: &P,
) -> Result<Transaction, Error> {
let mut obfuscate_transfer_note = is_transfer;
if transfer_value == 0 {
obfuscate_transfer_note = false;
}
Ok(PhoenixTransaction::new::<R, P>(
rng,
sender_sk,
refund_pk,
receiver_pk,
inputs,
root,
transfer_value,
obfuscate_transfer_note,
deposit,
gas_limit,
gas_price,
chain_id,
data,
prover,
)?
.into())
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight(
sender_sk: &BlsSecretKey,
receiver_pk: Option<BlsPublicKey>,
transfer_value: u64,
deposit: u64,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
chain_id: u8,
data: Option<impl Into<TransactionData>>,
) -> Result<Transaction, Error> {
Ok(MoonlightTransaction::new(
sender_sk,
receiver_pk,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
data,
)?
.into())
}
#[allow(clippy::too_many_arguments)]
pub fn phoenix_stake<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
inputs: Vec<(Note, NoteOpening)>,
root: BlsScalar,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
stake_value: u64,
prover: &P,
) -> Result<Transaction, Error> {
let phoenix_receiver_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let phoenix_refund_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let transfer_value = 0;
let is_transfer = false;
let deposit = stake_value;
let stake = Stake::new(stake_sk, stake_owner_sk, stake_value, chain_id);
let contract_call =
ContractCall::new(STAKE_CONTRACT, "stake").with_args(&stake)?;
phoenix::<R, P>(
rng,
phoenix_sender_sk,
&phoenix_refund_pk,
&phoenix_receiver_pk,
inputs,
root,
transfer_value,
is_transfer,
deposit,
gas_limit,
gas_price,
chain_id,
Some(contract_call),
prover,
)
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight_stake(
moonlight_sender_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
stake_value: u64,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
chain_id: u8,
) -> Result<Transaction, Error> {
let transfer_value = 0;
let deposit = stake_value;
let stake = Stake::new(stake_sk, stake_owner_sk, stake_value, chain_id);
let contract_call =
ContractCall::new(STAKE_CONTRACT, "stake").with_args(&stake)?;
moonlight(
moonlight_sender_sk,
None,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
Some(contract_call),
)
}
#[allow(clippy::too_many_arguments)]
pub fn phoenix_stake_reward<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
inputs: Vec<(Note, NoteOpening, BlsScalar)>,
root: BlsScalar,
reward_amount: u64,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
prover: &P,
) -> Result<Transaction, Error> {
let phoenix_receiver_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let phoenix_refund_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let transfer_value = 0;
let is_transfer = false;
let deposit = 0;
let mut nullifiers = Vec::with_capacity(inputs.len());
let inputs = inputs
.into_iter()
.map(|(note, opening, nullifier)| {
nullifiers.push(nullifier);
(note, opening)
})
.collect();
let gas_payment_token = WithdrawReplayToken::Phoenix(nullifiers);
let contract_call = stake_reward_to_phoenix(
rng,
phoenix_sender_sk,
stake_sk,
stake_owner_sk,
gas_payment_token,
reward_amount,
)?;
phoenix::<R, P>(
rng,
phoenix_sender_sk,
&phoenix_refund_pk,
&phoenix_receiver_pk,
inputs,
root,
transfer_value,
is_transfer,
deposit,
gas_limit,
gas_price,
chain_id,
Some(contract_call),
prover,
)
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight_stake_reward<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_sender_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
reward_amount: u64,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
chain_id: u8,
) -> Result<Transaction, Error> {
let transfer_value = 0;
let deposit = 0;
let gas_payment_token = WithdrawReplayToken::Moonlight(moonlight_nonce);
let contract_call = stake_reward_to_moonlight(
rng,
moonlight_sender_sk,
stake_sk,
stake_owner_sk,
gas_payment_token,
reward_amount,
)?;
moonlight(
moonlight_sender_sk,
None,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
Some(contract_call),
)
}
#[allow(clippy::too_many_arguments)]
pub fn phoenix_unstake<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
inputs: Vec<(Note, NoteOpening, BlsScalar)>,
root: BlsScalar,
unstake_value: u64,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
prover: &P,
) -> Result<Transaction, Error> {
let phoenix_receiver_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let phoenix_refund_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let transfer_value = 0;
let is_transfer = false;
let deposit = 0;
let mut nullifiers = Vec::with_capacity(inputs.len());
let inputs = inputs
.into_iter()
.map(|(note, opening, nullifier)| {
nullifiers.push(nullifier);
(note, opening)
})
.collect();
let gas_payment_token = WithdrawReplayToken::Phoenix(nullifiers);
let contract_call = unstake_to_phoenix(
rng,
phoenix_sender_sk,
stake_sk,
stake_owner_sk,
gas_payment_token,
unstake_value,
)?;
phoenix::<R, P>(
rng,
phoenix_sender_sk,
&phoenix_refund_pk,
&phoenix_receiver_pk,
inputs,
root,
transfer_value,
is_transfer,
deposit,
gas_limit,
gas_price,
chain_id,
Some(contract_call),
prover,
)
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight_unstake<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_sender_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
unstake_value: u64,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
chain_id: u8,
) -> Result<Transaction, Error> {
let transfer_value = 0;
let deposit = 0;
let gas_payment_token = WithdrawReplayToken::Moonlight(moonlight_nonce);
let contract_call = unstake_to_moonlight(
rng,
moonlight_sender_sk,
stake_sk,
stake_owner_sk,
gas_payment_token,
unstake_value,
)?;
moonlight(
moonlight_sender_sk,
None,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
Some(contract_call),
)
}
#[allow(clippy::too_many_arguments)]
pub fn phoenix_to_moonlight<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
moonlight_receiver_sk: &BlsSecretKey,
inputs: Vec<(Note, NoteOpening, BlsScalar)>,
root: BlsScalar,
convert_value: u64,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
prover: &P,
) -> Result<Transaction, Error> {
let phoenix_receiver_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let phoenix_refund_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let transfer_value = 0;
let is_transfer = false;
let deposit = convert_value;
let mut nullifiers = Vec::with_capacity(inputs.len());
let inputs = inputs
.into_iter()
.map(|(note, opening, nullifier)| {
nullifiers.push(nullifier);
(note, opening)
})
.collect();
let gas_payment_token = WithdrawReplayToken::Phoenix(nullifiers);
let contract_call = convert_to_moonlight(
rng,
moonlight_receiver_sk,
gas_payment_token,
convert_value,
)?;
phoenix::<R, P>(
rng,
phoenix_sender_sk,
&phoenix_refund_pk,
&phoenix_receiver_pk,
inputs,
root,
transfer_value,
is_transfer,
deposit,
gas_limit,
gas_price,
chain_id,
Some(contract_call),
prover,
)
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight_to_phoenix<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_sender_sk: &BlsSecretKey,
phoenix_receiver_sk: &PhoenixSecretKey,
convert_value: u64,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
chain_id: u8,
) -> Result<Transaction, Error> {
let deposit = convert_value;
let transfer_value = 0;
let gas_payment_token = WithdrawReplayToken::Moonlight(moonlight_nonce);
let contract_call = convert_to_phoenix(
rng,
phoenix_receiver_sk,
gas_payment_token,
convert_value,
)?;
moonlight(
moonlight_sender_sk,
None,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
Some(contract_call),
)
}
#[allow(clippy::too_many_arguments)]
pub fn phoenix_deployment<R: RngCore + CryptoRng, P: Prove>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
inputs: Vec<(Note, NoteOpening, BlsScalar)>,
root: BlsScalar,
bytecode: impl Into<Vec<u8>>,
owner: &BlsPublicKey,
init_args: Vec<u8>,
nonce: u64,
gas_limit: u64,
gas_price: u64,
chain_id: u8,
prover: &P,
) -> Result<Transaction, Error> {
let phoenix_receiver_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let phoenix_refund_pk = PhoenixPublicKey::from(phoenix_sender_sk);
let transfer_value = 0;
let is_transfer = false;
let deposit = 0;
let mut nullifiers = Vec::with_capacity(inputs.len());
let inputs = inputs
.into_iter()
.map(|(note, opening, nullifier)| {
nullifiers.push(nullifier);
(note, opening)
})
.collect();
let deploy = ContractDeploy::new(
bytecode,
owner.to_bytes().to_vec(),
Some(init_args),
nonce,
);
phoenix(
rng,
phoenix_sender_sk,
&phoenix_refund_pk,
&phoenix_receiver_pk,
inputs,
root,
transfer_value,
is_transfer,
deposit,
gas_limit,
gas_price,
chain_id,
Some(deploy),
prover,
)
}
#[allow(clippy::too_many_arguments)]
pub fn moonlight_deployment(
moonlight_sender_sk: &BlsSecretKey,
bytecode: impl Into<Vec<u8>>,
owner: &BlsPublicKey,
init_args: Vec<u8>,
gas_limit: u64,
gas_price: u64,
moonlight_nonce: u64,
deploy_nonce: u64,
chain_id: u8,
) -> Result<Transaction, Error> {
let transfer_value = 0;
let deposit = 0;
let deploy = ContractDeploy::new(
bytecode,
owner.to_bytes().to_vec(),
Some(init_args),
deploy_nonce,
);
moonlight(
moonlight_sender_sk,
None,
transfer_value,
deposit,
gas_limit,
gas_price,
moonlight_nonce,
chain_id,
Some(deploy),
)
}
fn stake_reward_to_phoenix<R: RngCore + CryptoRng>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
gas_payment_token: WithdrawReplayToken,
reward_amount: u64,
) -> Result<ContractCall, Error> {
let withdraw = withdraw_to_phoenix(
rng,
phoenix_sender_sk,
STAKE_CONTRACT,
gas_payment_token,
reward_amount,
);
let reward_withdraw =
StakeWithdraw::new(stake_sk, stake_owner_sk, withdraw);
ContractCall::new(STAKE_CONTRACT, "withdraw").with_args(&reward_withdraw)
}
pub(crate) fn stake_reward_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_receiver_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
gas_payment_token: WithdrawReplayToken,
reward_amount: u64,
) -> Result<ContractCall, Error> {
let withdraw = withdraw_to_moonlight(
rng,
moonlight_receiver_sk,
STAKE_CONTRACT,
gas_payment_token,
reward_amount,
);
let reward_withdraw =
StakeWithdraw::new(stake_sk, stake_owner_sk, withdraw);
ContractCall::new(STAKE_CONTRACT, "withdraw").with_args(&reward_withdraw)
}
fn unstake_to_phoenix<R: RngCore + CryptoRng>(
rng: &mut R,
phoenix_sender_sk: &PhoenixSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
gas_payment_token: WithdrawReplayToken,
unstake_value: u64,
) -> Result<ContractCall, Error> {
let withdraw = withdraw_to_phoenix(
rng,
phoenix_sender_sk,
STAKE_CONTRACT,
gas_payment_token,
unstake_value,
);
let unstake = StakeWithdraw::new(stake_sk, stake_owner_sk, withdraw);
ContractCall::new(STAKE_CONTRACT, "unstake").with_args(&unstake)
}
pub(crate) fn unstake_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_receiver_sk: &BlsSecretKey,
stake_sk: &BlsSecretKey,
stake_owner_sk: &BlsSecretKey,
gas_payment_token: WithdrawReplayToken,
unstake_value: u64,
) -> Result<ContractCall, Error> {
let withdraw = withdraw_to_moonlight(
rng,
moonlight_receiver_sk,
STAKE_CONTRACT,
gas_payment_token,
unstake_value,
);
let unstake = StakeWithdraw::new(stake_sk, stake_owner_sk, withdraw);
ContractCall::new(STAKE_CONTRACT, "unstake").with_args(&unstake)
}
fn convert_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
moonlight_receiver_sk: &BlsSecretKey,
gas_payment_token: WithdrawReplayToken,
convert_value: u64,
) -> Result<ContractCall, Error> {
let fn_args = withdraw_to_moonlight(
rng,
moonlight_receiver_sk,
TRANSFER_CONTRACT,
gas_payment_token,
convert_value,
);
ContractCall::new(TRANSFER_CONTRACT, "convert").with_args(&fn_args)
}
fn convert_to_phoenix<R: RngCore + CryptoRng>(
rng: &mut R,
phoenix_receiver_sk: &PhoenixSecretKey,
gas_payment_token: WithdrawReplayToken,
convert_value: u64,
) -> Result<ContractCall, Error> {
let fn_args = withdraw_to_phoenix(
rng,
phoenix_receiver_sk,
TRANSFER_CONTRACT,
gas_payment_token,
convert_value,
);
ContractCall::new(TRANSFER_CONTRACT, "convert").with_args(&fn_args)
}
fn withdraw_to_phoenix<R: RngCore + CryptoRng>(
rng: &mut R,
receiver_sk: &PhoenixSecretKey,
contract: impl Into<ContractId>,
gas_payment_token: WithdrawReplayToken,
value: u64,
) -> Withdraw {
let withdraw_address = PhoenixPublicKey::from(receiver_sk)
.gen_stealth_address(&JubJubScalar::random(&mut *rng));
let mut withdraw_note_sk = receiver_sk.gen_note_sk(&withdraw_address);
let withdraw = Withdraw::new(
rng,
&withdraw_note_sk,
contract.into(),
value,
WithdrawReceiver::Phoenix(withdraw_address),
gas_payment_token,
);
withdraw_note_sk.zeroize();
withdraw
}
fn withdraw_to_moonlight<R: RngCore + CryptoRng>(
rng: &mut R,
receiver_sk: &BlsSecretKey,
contract: impl Into<ContractId>,
gas_payment_token: WithdrawReplayToken,
value: u64,
) -> Withdraw {
Withdraw::new(
rng,
receiver_sk,
contract.into(),
value,
WithdrawReceiver::Moonlight(BlsPublicKey::from(receiver_sk)),
gas_payment_token,
)
}