2021-02-03 01:59:21 -08:00
|
|
|
use borsh::{BorshDeserialize, BorshSerialize};
|
|
|
|
|
|
|
|
use solana_program::{
|
2021-02-04 00:22:45 -08:00
|
|
|
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
|
2021-02-03 17:50:04 -08:00
|
|
|
program_pack::IsInitialized, sysvar::rent::Rent,
|
2021-02-03 01:59:21 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
pub trait BorshState: BorshDeserialize + BorshSerialize {
|
2021-02-03 17:50:04 -08:00
|
|
|
fn load(account: &AccountInfo) -> Result<Self, ProgramError> {
|
|
|
|
let data = (*account.data).borrow();
|
|
|
|
Self::try_from_slice(&data).map_err(|_| ProgramError::InvalidAccountData)
|
|
|
|
}
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
fn save(&self, account: &AccountInfo) -> ProgramResult {
|
|
|
|
let data = self
|
|
|
|
.try_to_vec()
|
|
|
|
.map_err(|_| ProgramError::InvalidAccountData)?;
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
// FIXME: looks like there is association precedence issue that prevents
|
|
|
|
// RefMut from being automatically dereferenced.
|
|
|
|
//
|
|
|
|
// let dst = &mut account.data.borrow_mut();
|
|
|
|
//
|
|
|
|
// Why does it work in an SPL token program though?
|
|
|
|
//
|
|
|
|
// Account::pack(source_account, &mut source_account_info.data.borrow_mut())?;
|
|
|
|
let mut dst = (*account.data).borrow_mut();
|
|
|
|
if dst.len() != data.len() {
|
|
|
|
return Err(ProgramError::InvalidAccountData);
|
|
|
|
}
|
|
|
|
dst.copy_from_slice(&data);
|
|
|
|
|
|
|
|
Ok(())
|
2021-02-03 01:59:21 -08:00
|
|
|
}
|
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
fn save_exempt(&self, account: &AccountInfo, rent: &Rent) -> ProgramResult {
|
|
|
|
let data = self
|
|
|
|
.try_to_vec()
|
|
|
|
.map_err(|_| ProgramError::InvalidAccountData)?;
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
if !rent.is_exempt(account.lamports(), data.len()) {
|
|
|
|
// FIXME: return a custom error
|
|
|
|
return Err(ProgramError::InvalidAccountData);
|
|
|
|
}
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
let mut dst = (*account.data).borrow_mut();
|
|
|
|
if dst.len() != data.len() {
|
|
|
|
// FIXME: return a custom error
|
|
|
|
return Err(ProgramError::InvalidAccountData);
|
|
|
|
}
|
|
|
|
dst.copy_from_slice(&data);
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
Ok(())
|
2021-02-03 01:59:21 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait InitBorshState: BorshState + IsInitialized {
|
2021-02-03 17:50:04 -08:00
|
|
|
// type Self = IsInitialized
|
|
|
|
fn load_initialized(account: &AccountInfo) -> Result<Self, ProgramError> {
|
|
|
|
let object = Self::load(account)?;
|
|
|
|
if !object.is_initialized() {
|
|
|
|
return Err(ProgramError::UninitializedAccount);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(object)
|
2021-02-03 01:59:21 -08:00
|
|
|
}
|
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
fn init_uninitialized(account: &AccountInfo) -> Result<Self, ProgramError> {
|
|
|
|
let object = Self::load(account)?;
|
|
|
|
if object.is_initialized() {
|
|
|
|
return Err(ProgramError::AccountAlreadyInitialized);
|
|
|
|
}
|
2021-02-03 01:59:21 -08:00
|
|
|
|
2021-02-03 17:50:04 -08:00
|
|
|
Ok(object)
|
2021-02-03 01:59:21 -08:00
|
|
|
}
|
2021-02-03 17:50:04 -08:00
|
|
|
}
|