use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey};
pub struct BurnVault {}
impl BurnVault {
pub fn seeds(base: &Pubkey) -> Vec<Vec<u8>> {
vec![b"burn_vault".as_ref().to_vec(), base.to_bytes().to_vec()]
}
pub fn find_program_address(program_id: &Pubkey, base: &Pubkey) -> (Pubkey, u8, Vec<Vec<u8>>) {
let seeds = Self::seeds(base);
let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect();
let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id);
(pda, bump, seeds)
}
pub fn load(
program_id: &Pubkey,
base: &Pubkey,
account: &AccountInfo,
expect_writable: bool,
) -> Result<(), ProgramError> {
if account.owner.ne(&solana_program::system_program::ID) {
msg!("Burn Vault account has an invalid owner");
return Err(ProgramError::InvalidAccountOwner);
}
if expect_writable && !account.is_writable {
msg!("Burn Vault account is not writable");
return Err(ProgramError::InvalidAccountData);
}
if account
.key
.ne(&Self::find_program_address(program_id, base).0)
{
msg!("Burn Vault account is not at the correct PDA");
return Err(ProgramError::InvalidAccountData);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use solana_program::{account_info::AccountInfo, rent::Rent, system_program};
use super::*;
#[test]
fn test_seeds_generation() {
let base = Pubkey::new_unique();
let seeds = BurnVault::seeds(&base);
assert_eq!(seeds.len(), 2);
assert_eq!(seeds[0], b"burn_vault".as_ref());
assert_eq!(seeds[1], base.to_bytes().to_vec());
}
#[test]
fn test_find_program_address() {
let program_id = Pubkey::new_unique();
let base = Pubkey::new_unique();
let (pda, bump, seeds) = BurnVault::find_program_address(&program_id, &base);
assert_eq!(seeds, BurnVault::seeds(&base));
let seeds_with_bump = seeds.iter().map(|s| s.as_slice()).collect::<Vec<_>>();
let (expected_pda, expected_bump) =
Pubkey::find_program_address(&seeds_with_bump, &program_id);
assert_eq!(pda, expected_pda);
assert_eq!(bump, expected_bump);
}
#[test]
fn test_load_valid_account() {
let program_id = Pubkey::new_unique();
let base = Pubkey::new_unique();
let (pda, _bump, _) = BurnVault::find_program_address(&program_id, &base);
let mut lamports = 1000000;
let mut data = vec![];
let account = AccountInfo::new(
&pda,
false,
true,
&mut lamports,
&mut data,
&system_program::ID,
false,
Rent::default().minimum_balance(0),
);
let result = BurnVault::load(&program_id, &base, &account, false);
assert!(result.is_ok());
let result = BurnVault::load(&program_id, &base, &account, true);
assert!(result.is_ok());
}
#[test]
fn test_load_invalid_owner() {
let program_id = Pubkey::new_unique();
let base = Pubkey::new_unique();
let (pda, _bump, _) = BurnVault::find_program_address(&program_id, &base);
let mut lamports = 1000000;
let mut data = vec![];
let invalid_owner = Pubkey::new_unique();
let account = AccountInfo::new(
&pda,
false,
true,
&mut lamports,
&mut data,
&invalid_owner,
false,
Rent::default().minimum_balance(0),
);
let result = BurnVault::load(&program_id, &base, &account, false);
assert_eq!(result.unwrap_err(), ProgramError::InvalidAccountOwner);
}
#[test]
fn test_load_invalid_pda() {
let program_id = Pubkey::new_unique();
let base = Pubkey::new_unique();
let invalid_pda = Pubkey::new_unique();
let mut lamports = 1000000;
let mut data = vec![];
let account = AccountInfo::new(
&invalid_pda,
false,
true,
&mut lamports,
&mut data,
&system_program::ID,
false,
Rent::default().minimum_balance(0),
);
let result = BurnVault::load(&program_id, &base, &account, false);
assert_eq!(result.unwrap_err(), ProgramError::InvalidAccountData);
}
#[test]
fn test_load_not_writable() {
let program_id = Pubkey::new_unique();
let base = Pubkey::new_unique();
let (pda, _bump, _) = BurnVault::find_program_address(&program_id, &base);
let mut lamports = 1000000;
let mut data = vec![];
let account = AccountInfo::new(
&pda,
false,
false, &mut lamports,
&mut data,
&system_program::ID,
false,
Rent::default().minimum_balance(0),
);
let result = BurnVault::load(&program_id, &base, &account, true);
assert_eq!(result.unwrap_err(), ProgramError::InvalidAccountData);
}
}