use hopper_runtime::{ProgramError, AccountView, Address};
use crate::check::{
check_account, check_executable, check_signer, check_system_program, check_writable,
};
pub struct AccountList<'a> {
accounts: &'a [AccountView],
pos: usize,
}
impl<'a> AccountList<'a> {
#[inline(always)]
pub fn new(accounts: &'a [AccountView]) -> Self {
Self { accounts, pos: 0 }
}
#[inline(always)]
pub fn remaining(&self) -> usize {
self.accounts.len().saturating_sub(self.pos)
}
#[inline(always)]
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<&'a AccountView, ProgramError> {
if self.pos >= self.accounts.len() {
return Err(ProgramError::NotEnoughAccountKeys);
}
let acc = &self.accounts[self.pos];
self.pos += 1;
Ok(acc)
}
#[inline(always)]
pub fn next_signer(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_signer(acc)?;
Ok(acc)
}
#[inline(always)]
pub fn next_writable(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_writable(acc)?;
Ok(acc)
}
#[inline(always)]
pub fn next_writable_signer(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_signer(acc)?;
check_writable(acc)?;
Ok(acc)
}
#[inline(always)]
pub fn next_system_program(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_system_program(acc)?;
Ok(acc)
}
#[inline(always)]
pub fn next_with_address(
&mut self,
expected: &Address,
) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
if acc.address() != expected {
return Err(ProgramError::IncorrectProgramId);
}
Ok(acc)
}
#[inline(always)]
pub fn next_account(
&mut self,
program_id: &Address,
discriminator: u8,
min_len: usize,
) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_account(acc, program_id, discriminator, min_len)?;
Ok(acc)
}
#[inline(always)]
pub fn next_writable_account(
&mut self,
program_id: &Address,
discriminator: u8,
min_len: usize,
) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_writable(acc)?;
check_account(acc, program_id, discriminator, min_len)?;
Ok(acc)
}
#[inline(always)]
pub fn next_executable(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_executable(acc)?;
Ok(acc)
}
#[inline(always)]
pub fn next_signer_writable_account(
&mut self,
program_id: &Address,
discriminator: u8,
min_len: usize,
) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
check_signer(acc)?;
check_writable(acc)?;
check_account(acc, program_id, discriminator, min_len)?;
Ok(acc)
}
#[cfg(feature = "programs")]
#[inline(always)]
pub fn next_clock(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
if *acc.address() != crate::programs::SYSVAR_CLOCK {
return Err(ProgramError::InvalidArgument);
}
Ok(acc)
}
#[cfg(feature = "programs")]
#[inline(always)]
pub fn next_sysvar_instructions(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
if *acc.address() != crate::programs::SYSVAR_INSTRUCTIONS {
return Err(ProgramError::InvalidArgument);
}
Ok(acc)
}
#[cfg(feature = "programs")]
#[inline(always)]
pub fn next_rent(&mut self) -> Result<&'a AccountView, ProgramError> {
let acc = self.next()?;
if *acc.address() != crate::programs::SYSVAR_RENT {
return Err(ProgramError::InvalidArgument);
}
Ok(acc)
}
}