Skip to content

Commit

Permalink
feat: use anchor InterfaceAccounts instead of manual checks
Browse files Browse the repository at this point in the history
  • Loading branch information
ananas-block committed Dec 2, 2024
1 parent b4e0eb6 commit a1bb6f1
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 316 deletions.
57 changes: 12 additions & 45 deletions programs/compressed-token/src/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use crate::{
get_input_compressed_accounts_with_merkle_context_and_check_signer, DelegatedTransfer,
InputTokenDataWithContext,
},
spl_compression::spl_token_pool_derivation,
BurnInstruction, ErrorCode,
};

Expand Down Expand Up @@ -64,52 +63,20 @@ pub fn burn_spl_from_pool_pda<'info>(
ctx: &Context<'_, '_, '_, 'info, BurnInstruction<'info>>,
inputs: &CompressedTokenInstructionDataBurn,
) -> Result<()> {
if *ctx.accounts.mint.owner != *ctx.accounts.token_program.key {
return err!(crate::ErrorCode::InvalidTokenMintOwner);
}
spl_token_pool_derivation(
ctx.accounts.mint.key,
&crate::ID,
&ctx.accounts.token_pool_pda.key(),
)?;

let pre_token_balance = TokenAccount::try_deserialize(
&mut &ctx.accounts.token_pool_pda.to_account_info().data.borrow()[..],
)?
.amount;

let pre_token_balance = ctx.accounts.token_pool_pda.amount;
let cpi_accounts = anchor_spl::token_interface::Burn {
mint: ctx.accounts.mint.to_account_info(),
from: ctx.accounts.token_pool_pda.to_account_info(),
authority: ctx.accounts.cpi_authority_pda.to_account_info(),
};
let signer_seeds = get_cpi_signer_seeds();
let signer_seeds_ref = &[&signer_seeds[..]];

match *ctx.accounts.token_program.key {
spl_token::ID => {
let cpi_accounts = anchor_spl::token::Burn {
mint: ctx.accounts.mint.to_account_info(),
from: ctx.accounts.token_pool_pda.to_account_info(),
authority: ctx.accounts.cpi_authority_pda.to_account_info(),
};
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
cpi_accounts,
signer_seeds_ref,
);
anchor_spl::token::burn(cpi_ctx, inputs.burn_amount)
}
anchor_spl::token_2022::ID => {
let cpi_accounts = anchor_spl::token_2022::Burn {
mint: ctx.accounts.mint.to_account_info(),
from: ctx.accounts.token_pool_pda.to_account_info(),
authority: ctx.accounts.cpi_authority_pda.to_account_info(),
};
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
cpi_accounts,
signer_seeds_ref,
);
anchor_spl::token_2022::burn(cpi_ctx, inputs.burn_amount)
}
_ => err!(crate::ErrorCode::InvalidTokenProgram),
}?;
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
cpi_accounts,
signer_seeds_ref,
);
anchor_spl::token_interface::burn(cpi_ctx, inputs.burn_amount)?;

let post_token_balance = TokenAccount::try_deserialize(
&mut &ctx.accounts.token_pool_pda.to_account_info().data.borrow()[..],
Expand Down
23 changes: 0 additions & 23 deletions programs/compressed-token/src/freeze.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use anchor_lang::prelude::*;
use anchor_spl::token::Mint;
use light_hasher::DataHasher;
use light_hasher::Poseidon;
use light_system_program::{
Expand Down Expand Up @@ -47,7 +46,6 @@ pub fn process_freeze_or_thaw<
) -> Result<()> {
let inputs: CompressedTokenInstructionDataFreeze =
CompressedTokenInstructionDataFreeze::deserialize(&mut inputs.as_slice())?;
check_mint_and_freeze_authority(&ctx.accounts.mint, ctx.accounts.authority.key)?;
let (compressed_input_accounts, output_compressed_accounts) =
create_input_and_output_accounts_freeze_or_thaw::<FROZEN_INPUTS, FROZEN_OUTPUTS>(
&inputs,
Expand All @@ -67,27 +65,6 @@ pub fn process_freeze_or_thaw<
)
}

/// Checks:
/// 1. Mint account is owner token22 or spl token program.
/// 2. Mint account is correct account.
/// 3. Freeze authority is authority.
pub fn check_mint_and_freeze_authority(mint: &AccountInfo<'_>, authority: &Pubkey) -> Result<()> {
let freeze_authority = match *mint.owner {
anchor_spl::token_2022::ID | spl_token::ID => {
let mint = Mint::try_deserialize(&mut &mint.try_borrow_data()?[..])?;
Ok(mint
.freeze_authority
.ok_or(crate::ErrorCode::MintHasNoFreezeAuthority)?)
}
_ => err!(crate::ErrorCode::InvalidTokenProgram),
}?;
if freeze_authority != *authority {
err!(crate::ErrorCode::InvalidFreezeAuthority)
} else {
Ok(())
}
}

pub fn create_input_and_output_accounts_freeze_or_thaw<
const FROZEN_INPUTS: bool,
const FROZEN_OUTPUTS: bool,
Expand Down
12 changes: 6 additions & 6 deletions programs/compressed-token/src/instructions/burn.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use account_compression::{program::AccountCompression, utils::constants::CPI_AUTHORITY_PDA_SEED};
use anchor_lang::prelude::*;
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
use light_system_program::{
program::LightSystemProgram,
sdk::accounts::{InvokeAccounts, SignerAccounts},
};

use crate::program::LightCompressedToken;
use crate::{program::LightCompressedToken, POOL_SEED};

#[derive(Accounts)]
pub struct BurnInstruction<'info> {
Expand All @@ -22,12 +23,11 @@ pub struct BurnInstruction<'info> {
pub cpi_authority_pda: UncheckedAccount<'info>,
/// CHECK: is used to burn tokens.
#[account(mut)]
pub mint: AccountInfo<'info>,
pub mint: InterfaceAccount<'info, Mint>,
/// CHECK: (seed constraint) is derived from mint account.
#[account(mut)]
pub token_pool_pda: AccountInfo<'info>,
/// CHECK: in burn_spl_from_pool_pda.
pub token_program: AccountInfo<'info>,
#[account(mut, seeds = [POOL_SEED, mint.key().as_ref()], bump)]
pub token_pool_pda: InterfaceAccount<'info, TokenAccount>,
pub token_program: Interface<'info, TokenInterface>,
pub light_system_program: Program<'info, LightSystemProgram>,
/// CHECK: (account compression program).
pub registered_program_pda: AccountInfo<'info>,
Expand Down
41 changes: 5 additions & 36 deletions programs/compressed-token/src/instructions/create_token_pool.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use account_compression::utils::constants::CPI_AUTHORITY_PDA_SEED;
use anchor_lang::prelude::*;
use anchor_spl::{
token::{Mint, Token, TokenAccount},
token_2022::Token2022,
token_interface::{Mint as Mint22, TokenAccount as Token22Account},
};
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
use spl_token_2022::{
extension::{BaseStateWithExtensions, ExtensionType, PodStateWithExtensions},
pod::PodMint,
};

pub const POOL_SEED: &[u8] = b"pool";

/// Creates a spl token pool account which is owned by the token authority pda.
/// Creates a spl or token 2022 token pool account which is owned by the token authority pda.
#[derive(Accounts)]
pub struct CreateTokenPoolInstruction<'info> {
/// UNCHECKED: only pays fees.
Expand All @@ -28,39 +24,12 @@ pub struct CreateTokenPoolInstruction<'info> {
token::mint = mint,
token::authority = cpi_authority_pda,
)]
pub token_pool_pda: Account<'info, TokenAccount>,
pub system_program: Program<'info, System>,
/// CHECK: is mint account.
#[account(mut)]
pub mint: Account<'info, Mint>,
pub token_program: Program<'info, Token>,
/// CHECK: (seeds anchor constraint).
#[account(seeds = [CPI_AUTHORITY_PDA_SEED], bump)]
pub cpi_authority_pda: AccountInfo<'info>,
}

/// Creates a token22 token pool account which is owned by the token authority pda.
#[derive(Accounts)]
pub struct CreateTokenPoolInstruction2022<'info> {
/// UNCHECKED: only pays fees.
#[account(mut)]
pub fee_payer: Signer<'info>,
#[account(
init,
seeds = [
POOL_SEED, &mint.key().to_bytes(),
],
bump,
payer = fee_payer,
token::mint = mint,
token::authority = cpi_authority_pda,
)]
pub token_pool_pda: InterfaceAccount<'info, Token22Account>,
pub token_pool_pda: InterfaceAccount<'info, TokenAccount>,
pub system_program: Program<'info, System>,
/// CHECK: is mint account.
#[account(mut)]
pub mint: InterfaceAccount<'info, Mint22>,
pub token_program: Program<'info, Token2022>,
pub mint: InterfaceAccount<'info, Mint>,
pub token_program: Interface<'info, TokenInterface>,
/// CHECK: (seeds anchor constraint).
#[account(seeds = [CPI_AUTHORITY_PDA_SEED], bump)]
pub cpi_authority_pda: AccountInfo<'info>,
Expand Down
9 changes: 4 additions & 5 deletions programs/compressed-token/src/instructions/freeze.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use account_compression::{program::AccountCompression, utils::constants::CPI_AUTHORITY_PDA_SEED};
use anchor_lang::prelude::*;
use anchor_spl::token_interface::Mint;
use light_system_program::{
program::LightSystemProgram,
sdk::accounts::{InvokeAccounts, SignerAccounts},
Expand All @@ -12,8 +13,8 @@ pub struct FreezeInstruction<'info> {
/// UNCHECKED: only pays fees.
#[account(mut)]
pub fee_payer: Signer<'info>,
/// CHECK: is freeze authority, in instruction with
/// check_mint_and_freeze_authority().
#[account(constraint= authority.key() == mint.freeze_authority.ok_or(crate::ErrorCode::MintHasNoFreezeAuthority)?
@ crate::ErrorCode::InvalidFreezeAuthority)]
pub authority: Signer<'info>,
/// CHECK: (seed constraint).
#[account(seeds = [CPI_AUTHORITY_PDA_SEED], bump,)]
Expand All @@ -31,9 +32,7 @@ pub struct FreezeInstruction<'info> {
/// that this program is the signer of the cpi.
pub self_program: Program<'info, LightCompressedToken>,
pub system_program: Program<'info, System>,
/// CHECK: owner and account type in instruction with
/// check_mint_and_freeze_authority().
pub mint: AccountInfo<'info>,
pub mint: InterfaceAccount<'info, Mint>,
}

impl<'info> InvokeAccounts<'info> for FreezeInstruction<'info> {
Expand Down
8 changes: 4 additions & 4 deletions programs/compressed-token/src/instructions/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use account_compression::{program::AccountCompression, utils::constants::CPI_AUTHORITY_PDA_SEED};
use anchor_lang::prelude::*;
use anchor_spl::token_interface::{TokenAccount, TokenInterface};
use light_system_program::{
self,
program::LightSystemProgram,
Expand Down Expand Up @@ -32,12 +33,11 @@ pub struct TransferInstruction<'info> {
/// CHECK:(system program) used to derive cpi_authority_pda and check that
/// this program is the signer of the cpi.
pub self_program: Program<'info, LightCompressedToken>,
/// CHECK: derivation checked in compress or decompress function.
#[account(mut)]
pub token_pool_pda: Option<AccountInfo<'info>>,
pub token_pool_pda: Option<InterfaceAccount<'info, TokenAccount>>,
#[account(mut, constraint= if token_pool_pda.is_some() {Ok(token_pool_pda.as_ref().unwrap().key() != compress_or_decompress_token_account.key())}else {err!(crate::ErrorCode::TokenPoolPdaUndefined)}? @crate::ErrorCode::IsTokenPoolPda)]
pub compress_or_decompress_token_account: Option<AccountInfo<'info>>,
pub token_program: Option<AccountInfo<'info>>,
pub compress_or_decompress_token_account: Option<InterfaceAccount<'info, TokenAccount>>,
pub token_program: Option<Interface<'info, TokenInterface>>,
pub system_program: Program<'info, System>,
}

Expand Down
13 changes: 2 additions & 11 deletions programs/compressed-token/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,11 @@ pub mod light_compressed_token {
/// transferrred to the token pool, and their compressed equivalent is
/// minted into a Merkle tree.
pub fn create_token_pool<'info>(
_ctx: Context<'_, '_, '_, 'info, CreateTokenPoolInstruction<'info>>,
) -> Result<()> {
Ok(())
}

pub fn create_token_pool_2022<'info>(
ctx: Context<'_, '_, '_, 'info, CreateTokenPoolInstruction2022<'info>>,
ctx: Context<'_, '_, '_, 'info, CreateTokenPoolInstruction<'info>>,
) -> Result<()> {
create_token_pool::assert_mint_extensions(
&ctx.accounts.mint.to_account_info().try_borrow_data()?,
)?;
Ok(())
)
}

/// Mints tokens from an spl token mint to a list of compressed accounts.
Expand Down Expand Up @@ -211,7 +204,5 @@ pub enum ErrorCode {
NoInputsProvided,
InvalidMintAccount,
MintHasNoFreezeAuthority,
InvalidTokenProgram,
InvalidTokenMintOwner,
MintWithInvalidExtension,
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::{
ErrorCode,
};
use anchor_lang::prelude::*;
use anchor_lang::solana_program::program_pack::Pack;
use light_system_program::sdk::CompressedCpiContext;

pub fn process_compress_spl_token_account<'info>(
Expand All @@ -17,18 +16,7 @@ pub fn process_compress_spl_token_account<'info>(
) -> Result<()> {
let compression_token_account =
if let Some(token_account) = ctx.accounts.compress_or_decompress_token_account.as_ref() {
if *token_account.owner
!= ctx
.accounts
.token_program
.as_ref()
.ok_or(ErrorCode::InvalidTokenProgram)?
.key()
{
msg!("Token account is not owned by the token program.");
return err!(ErrorCode::InvalidTokenProgram);
}
spl_token::state::Account::unpack(&token_account.data.borrow())?
token_account
} else {
return err!(ErrorCode::CompressedPdaUndefinedForCompress);
};
Expand Down
Loading

0 comments on commit a1bb6f1

Please sign in to comment.