Skip to main content
added 1208 characters in body
Source Link

Here is a simple example using the CpiContext::new_with_signer to transfer some tokens from a token vault owned by this program. Inside the seeds I put in the values needed to create the PDA of the vault as described in the Withdraw vault_account seeds.

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        seeds = [b"vault", to.mint.as_ref()],
        bump,
    )]
    pub vault_account: Account<'info, TokenAccount>,
    #[account(
        mut,
        seeds = [b"vault-access", to.mint.as_ref(), authority.key().as_ref()],
        bump, 
        constraint = vault_access.authority == authority.key()
    )]
    pub vault_access: Account<'info, VaultAccess>,
    #[account(mut, constraint = to.owner == authority.key())]
    pub to: Account<'info, TokenAccount>,
    pub authority: Signer<'info>,
    pub token_program: Program<'info, Token>,
}
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, bump: u8) -> Result<()> {
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_accounts = Transfer {
            from: ctx.accounts.vault_account.to_account_info(),
            to: ctx.accounts.to.to_account_info(),
            authority: ctx.accounts.vault_account.to_account_info(),
        };

        if amount > ctx.accounts.vault_access.amount {
            return Err(ErrorCode::InsufficientFundsInVault.into())
        }

        ctx.accounts.vault_access.amount -= amount;

        token::transfer(
            CpiContext::new_with_signer(
                cpi_program, 
                cpi_accounts,
                &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), 
            amount)?;
        Ok(())
    }

Note - with the latest version of anchor you don't need to pass the bump in as a parameter if you don't want to. There are new ways to deal with the bump that can make things a bit easier.

    let cpi_program = ctx.accounts.token_program.to_account_info();
    let cpi_accounts = Transfer {
        from: ctx.accounts.vault_account.to_account_info(),
        to: ctx.accounts.to.to_account_info(),
        authority: ctx.accounts.vault_account.to_account_info(),
    };

    if amount > ctx.accounts.vault_access.amount {
        return Err(ErrorCode::InsufficientFundsInVault.into())
    }

    ctx.accounts.vault_access.amount -= amount;

    token::transfer(
        CpiContext::new_with_signer(
            cpi_program, 
            cpi_accounts,
            &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), 
        amount)?;

Here is a simple example using the CpiContext::new_with_signer to transfer some tokens from a token vault owned by this program. Inside the seeds I put in the values needed to create the PDA of the vault as described in the Withdraw vault_account seeds.

#[derive(Accounts)]
pub struct Withdraw<'info> {
    #[account(
        mut,
        seeds = [b"vault", to.mint.as_ref()],
        bump,
    )]
    pub vault_account: Account<'info, TokenAccount>,
    #[account(
        mut,
        seeds = [b"vault-access", to.mint.as_ref(), authority.key().as_ref()],
        bump, 
        constraint = vault_access.authority == authority.key()
    )]
    pub vault_access: Account<'info, VaultAccess>,
    #[account(mut, constraint = to.owner == authority.key())]
    pub to: Account<'info, TokenAccount>,
    pub authority: Signer<'info>,
    pub token_program: Program<'info, Token>,
}
pub fn withdraw(ctx: Context<Withdraw>, amount: u64, bump: u8) -> Result<()> {
        let cpi_program = ctx.accounts.token_program.to_account_info();
        let cpi_accounts = Transfer {
            from: ctx.accounts.vault_account.to_account_info(),
            to: ctx.accounts.to.to_account_info(),
            authority: ctx.accounts.vault_account.to_account_info(),
        };

        if amount > ctx.accounts.vault_access.amount {
            return Err(ErrorCode::InsufficientFundsInVault.into())
        }

        ctx.accounts.vault_access.amount -= amount;

        token::transfer(
            CpiContext::new_with_signer(
                cpi_program, 
                cpi_accounts,
                &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), 
            amount)?;
        Ok(())
    }

Note - with the latest version of anchor you don't need to pass the bump in as a parameter if you don't want to. There are new ways to deal with the bump that can make things a bit easier.

Source Link

    let cpi_program = ctx.accounts.token_program.to_account_info();
    let cpi_accounts = Transfer {
        from: ctx.accounts.vault_account.to_account_info(),
        to: ctx.accounts.to.to_account_info(),
        authority: ctx.accounts.vault_account.to_account_info(),
    };

    if amount > ctx.accounts.vault_access.amount {
        return Err(ErrorCode::InsufficientFundsInVault.into())
    }

    ctx.accounts.vault_access.amount -= amount;

    token::transfer(
        CpiContext::new_with_signer(
            cpi_program, 
            cpi_accounts,
            &[&[b"vault", ctx.accounts.to.mint.as_ref(), &[bump]]]), 
        amount)?;