use anchor_lang::prelude::*; use anchor_spl::token; use anchor_spl::token::Token; use anchor_spl::token::TokenAccount; use crate::error::*; use crate::state::*; #[derive(Accounts)] pub struct TokenWithdraw<'info> { #[account( constraint = group.load()?.is_ix_enabled(IxGate::TokenWithdraw) @ MangoError::IxIsDisabled, )] pub group: AccountLoader<'info, Group>, #[account( mut, has_one = group, has_one = owner, constraint = account.load()?.is_operational() @ MangoError::AccountIsFrozen )] pub account: AccountLoader<'info, MangoAccountFixed>, pub owner: Signer<'info>, #[account( mut, has_one = group, has_one = vault, has_one = oracle, // the mints of bank/vault/token_account are implicitly the same because // spl::token::transfer succeeds between token_account and vault )] pub bank: AccountLoader<'info, Bank>, #[account(mut)] pub vault: Account<'info, TokenAccount>, /// CHECK: The oracle can be one of several different account types pub oracle: UncheckedAccount<'info>, #[account(mut)] pub token_account: Box>, pub token_program: Program<'info, Token>, } impl<'info> TokenWithdraw<'info> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, token::Transfer<'info>> { let program = self.token_program.to_account_info(); let accounts = token::Transfer { from: self.vault.to_account_info(), to: self.token_account.to_account_info(), authority: self.group.to_account_info(), }; CpiContext::new(program, accounts) } }