# Anchor CPI related ## SPL token transfer CPI ### Method #1 ``` #[program] pub mod locker_manager { ... pub fn create_locker( ctx: Context<CreateLocker>, beneficiary: Pubkey, deposit_amount: u64, nonce: u8, start_ts: i64, end_ts: i64, period_count: u64, // reward_kepper: Option<RewardKeeper>, ) -> Result<()> { ... transfer(ctx.accounts.transfer_ctx(), deposit_amount)?; ... Ok(()) } } #[derive(Accounts)] pub struct CreateLocker<'info> { #[account(zero)] pub locker: Box<Account<'info, Locker>>, #[account(mut)] pub vault: Account<'info, TokenAccount>, /// CHECK: This is not dangerous because we don't read or write from this account #[account(mut)] pub depositor: AccountInfo<'info>, pub depositor_authority: Signer<'info>, // Misc. pub token_program: Program<'info, Token>, pub rent: Sysvar<'info, Rent>, pub clock: Sysvar<'info, Clock>, } impl<'info> CreateLocker<'info> { pub fn transfer_ctx(&self) -> CpiContext<'_, '_, '_, 'info, Transfer<'info>> { CpiContext::new( self.token_program.to_account_info(), Transfer { from: self.depositor.clone(), to: self.vault.to_account_info(), authority: self.depositor_authority.to_account_info() } ) } } ``` ## Method #2 ``` #[program] pub mod locker_manager { ... pub fn create_locker( ctx: Context<CreateLocker>, beneficiary: Pubkey, deposit_amount: u64, nonce: u8, start_ts: i64, end_ts: i64, period_count: u64, // reward_kepper: Option<RewardKeeper>, ) -> Result<()> { ... transfer(ctx.accounts.into(), deposit_amount)?; ... Ok(()) } } #[derive(Accounts)] pub struct CreateLocker<'info> { #[account(zero)] // TOCHECK: why not mut? pub locker: Box<Account<'info, Locker>>, #[account(mut)] pub vault: Account<'info, TokenAccount>, /// CHECK: This is not dangerous because we don't read or write from this account #[account(mut)] pub depositor: AccountInfo<'info>, pub depositor_authority: Signer<'info>, // Misc. pub token_program: Program<'info, Token>, pub rent: Sysvar<'info, Rent>, pub clock: Sysvar<'info, Clock>, } impl<'a, 'b, 'c, 'info> From<&mut CreateLocker<'info>> for CpiContext<'a, 'b, 'c, 'info, Transfer<'info>> { fn from(accounts: &mut CreateLocker<'info>) -> CpiContext<'a, 'b, 'c, 'info, Transfer<'info>> { let cpi_accounts = Transfer { from: accounts.depositor.clone(), to: accounts.vault.to_account_info(), authority: accounts.depositor_authority.to_account_info().clone(), }; let cpi_program = accounts.token_program.to_account_info().clone(); CpiContext::new(cpi_program, cpi_accounts) } } ```