use solana_address::Address;
use solana_instruction::{AccountMeta, Instruction};
use winterwallet_common::SIGNATURE_LEN;
use crate::{
AdvancePayload, Error, advance, advance_preimage, close, encode_advance,
transaction::{
DEFAULT_ADVANCE_COMPUTE_UNIT_LIMIT, estimate_legacy_transaction_size,
validate_legacy_transaction_size, with_compute_budget,
},
withdraw,
};
pub struct AdvancePlan {
wallet_pda: Address,
new_root: [u8; 32],
payload: AdvancePayload,
account_addresses: Vec<[u8; 32]>,
}
impl AdvancePlan {
pub fn new(
wallet_pda: &Address,
new_root: &[u8; 32],
inner_instructions: &[Instruction],
) -> Result<Self, Error> {
let payload = encode_advance(inner_instructions)?;
let account_addresses = payload
.accounts
.iter()
.map(|meta| *meta.pubkey.as_array())
.collect();
Ok(Self {
wallet_pda: *wallet_pda,
new_root: *new_root,
payload,
account_addresses,
})
}
pub fn wallet_pda(&self) -> &Address {
&self.wallet_pda
}
pub fn withdraw(
wallet_pda: &Address,
receiver: &Address,
lamports: u64,
new_root: &[u8; 32],
) -> Result<Self, Error> {
Self::new(
wallet_pda,
new_root,
&[withdraw(wallet_pda, receiver, lamports)],
)
}
pub fn close(
wallet_pda: &Address,
receiver: &Address,
new_root: &[u8; 32],
) -> Result<Self, Error> {
Self::new(wallet_pda, new_root, &[close(wallet_pda, receiver)])
}
pub fn payload(&self) -> &[u8] {
&self.payload.data
}
pub fn passthrough_accounts(&self) -> &[AccountMeta] {
&self.payload.accounts
}
pub fn account_addresses(&self) -> &[[u8; 32]] {
&self.account_addresses
}
pub fn new_root(&self) -> &[u8; 32] {
&self.new_root
}
pub fn preimage<'a>(
&'a self,
wallet_id: &'a [u8; 32],
current_root: &'a [u8; 32],
) -> Vec<&'a [u8]> {
advance_preimage(
wallet_id,
current_root,
&self.new_root,
&self.account_addresses,
&self.payload.data,
)
}
pub fn instruction(&self, signature_bytes: &[u8; SIGNATURE_LEN]) -> Instruction {
advance(
&self.wallet_pda,
&self.payload.accounts,
signature_bytes,
&self.new_root,
&self.payload.data,
)
}
pub fn estimate_transaction_size(
&self,
payer: &Address,
signature_bytes: &[u8; SIGNATURE_LEN],
) -> Result<usize, Error> {
let ix = self.instruction(signature_bytes);
let ixs = with_compute_budget(&[ix], DEFAULT_ADVANCE_COMPUTE_UNIT_LIMIT, 0);
estimate_legacy_transaction_size(payer, &ixs)
}
pub fn validate_transaction_size(
&self,
payer: &Address,
signature_bytes: &[u8; SIGNATURE_LEN],
) -> Result<usize, Error> {
let ix = self.instruction(signature_bytes);
let ixs = with_compute_budget(&[ix], DEFAULT_ADVANCE_COMPUTE_UNIT_LIMIT, 0);
validate_legacy_transaction_size(payer, &ixs)
}
}