use anchor_lang::{prelude::*, ZeroCopy};
use crate::{
events::EventEmitter,
states::{
common::action::{Action, ActionParams, Closable},
NonceBytes, StoreWalletSigner,
},
CoreError,
};
use super::Authenticate;
pub(crate) trait Create<'info, A>: Sized + anchor_lang::Bumps {
type CreateParams: ActionParams;
fn action(&self) -> AccountInfo<'info>;
fn payer(&self) -> AccountInfo<'info>;
fn payer_seeds(&self) -> Result<Option<Vec<Vec<u8>>>> {
Ok(None)
}
fn system_program(&self) -> AccountInfo<'info>;
fn validate(&self, _params: &Self::CreateParams) -> Result<()>;
fn create_impl(
&mut self,
params: &Self::CreateParams,
nonce: &NonceBytes,
bumps: &Self::Bumps,
remaining_accounts: &'info [AccountInfo<'info>],
) -> Result<()>;
fn create(
ctx: &mut Context<'_, '_, 'info, 'info, Self>,
nonce: &NonceBytes,
params: &Self::CreateParams,
) -> Result<()> {
let accounts = &mut ctx.accounts;
accounts.validate(params)?;
accounts.transfer_execution_lamports(params)?;
accounts.create_impl(params, nonce, &ctx.bumps, ctx.remaining_accounts)?;
Ok(())
}
fn transfer_execution_lamports(&self, params: &Self::CreateParams) -> Result<()> {
use crate::ops::execution_fee::TransferExecutionFeeOperation;
let payer_seeds = self.payer_seeds()?;
let payer_seeds = payer_seeds
.as_ref()
.map(|seeds| seeds.iter().map(|seed| seed.as_slice()).collect::<Vec<_>>());
TransferExecutionFeeOperation::builder()
.payment(self.action())
.payer(self.payer())
.execution_lamports(params.execution_lamports())
.system_program(self.system_program())
.signer_seeds(payer_seeds.as_deref())
.build()
.execute()
}
}
type ShouldContinueWhenATAsAreMissing = bool;
pub(crate) type Success = bool;
pub(crate) trait Close<'info, A>: Authenticate<'info>
where
A: Action + ZeroCopy + Owner + Closable,
{
fn expected_keeper_role(&self) -> &str;
fn rent_receiver(&self) -> AccountInfo<'info>;
fn event_authority(&self, bumps: &Self::Bumps) -> (AccountInfo<'info>, u8);
fn store_wallet_bump(&self, bumps: &Self::Bumps) -> u8;
fn skip_completion_check_for_keeper(&self) -> Result<bool> {
Ok(false)
}
fn validate(&self) -> Result<()>;
fn process(
&self,
init_if_needed: bool,
store_wallet_signer: &StoreWalletSigner,
event_emitter: &EventEmitter<'_, 'info>,
) -> Result<Success>;
fn close(ctx: &Context<'_, '_, '_, 'info, Self>, reason: &str) -> Result<()> {
let accounts = &ctx.accounts;
accounts.validate()?;
let should_continue_when_atas_are_missing = accounts.preprocess()?;
let store_wallet_signer = StoreWalletSigner::new(
accounts.store().key(),
accounts.store_wallet_bump(&ctx.bumps),
);
let (authority, bump) = accounts.event_authority(&ctx.bumps);
let event_emitter = EventEmitter::new(&authority, bump);
if accounts.process(
should_continue_when_atas_are_missing,
&store_wallet_signer,
&event_emitter,
)? {
{
let action_address = accounts.action().key();
let action = accounts.action().load()?;
let event = action.to_closed_event(&action_address, reason)?;
event_emitter.emit_cpi(&event)?;
}
accounts.close_action_account()?;
} else {
msg!("Some ATAs are not initialized, skip the close");
}
Ok(())
}
fn action(&self) -> &AccountLoader<'info, A>;
fn preprocess(&self) -> Result<ShouldContinueWhenATAsAreMissing> {
if *self.authority().key == self.action().load()?.header().owner {
Ok(true)
} else {
self.only_role(self.expected_keeper_role())?;
{
let action = self.action().load()?;
if self.skip_completion_check_for_keeper()?
|| action.header().action_state()?.is_completed_or_cancelled()
{
Ok(false)
} else {
err!(CoreError::PermissionDenied)
}
}
}
}
fn close_action_account(&self) -> Result<()> {
self.action().close(self.rent_receiver())
}
}