1

I'm converting my custom SPL token anchor program from using mint token as a newly generated anchor keypair, to using a PDA instead.

It seems that SPL can take either a keypair or PDA for the mint token account. However, I'm running into issues with my SPL setup.

Error:

Error in 'Create token!':  AnchorError: AnchorError caused by account: mint_token. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected.
Program log: Left:
Program log: 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA
Program log: Right:
Program log: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
    at Function.parse (/Users/gavinmai/personal/portfolio/hermes/node_modules/@coral-xyz/anchor/src/error.ts:167:14)
    at translateError (/Users/gavinmai/personal/portfolio/hermes/node_modules/@coral-xyz/anchor/src/error.ts:276:35)
    at MethodsBuilder.rpc [as _rpcFn] (/Users/gavinmai/personal/portfolio/hermes/node_modules/@coral-xyz/anchor/src/program/namespace/rpc.ts:35:29)
    at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  errorLogs: [
    'Program log: AnchorError caused by account: mint_token. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected.',
    'Program log: Left:',
    'Program log: 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA',
    'Program log: Right:',
    'Program log: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
  ],
  logs: [
    'Program 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA invoke [1]',
    'Program log: Instruction: CreateToken',
    'Program 11111111111111111111111111111111 invoke [2]',
    'Program 11111111111111111111111111111111 success',
    'Program log: AnchorError caused by account: mint_token. Error Code: AccountOwnedByWrongProgram. Error Number: 3007. Error Message: The given account is owned by a different program than expected.',
    'Program log: Left:',
    'Program log: 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA',
    'Program log: Right:',
    'Program log: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
    'Program 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA consumed 12806 of 200000 compute units',
    'Program 5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA failed: custom program error: 0xbbf'
  ],
  error: {
    errorCode: { code: 'AccountOwnedByWrongProgram', number: 3007 },
    errorMessage: 'The given account is owned by a different program than expected',
    comparedValues: [
      [PublicKey [PublicKey(5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA)]],
      [PublicKey [PublicKey(TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)]]
    ],
    origin: 'mint_token'
  },
  _programErrorStack: ProgramErrorStack {
    stack: [
      [PublicKey [PublicKey(5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA)]]
    ]
  }
}

Clearly, this is because my PDA is owned by my local program, and NOT by the constant token program id TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA

I've attached my anchor code and test case in the hopes that someone more experienced can help me out.

Anchor Lib.rs

use anchor_lang::prelude::*;
use anchor_spl::{token::{Token, TokenAccount, Mint}, associated_token::AssociatedToken};
use mpl_token_metadata::types::DataV2;

// Declare the program ID for the test token
declare_id!("5qoJ4bwuvYbzKDbEhjfZbvsF8A8C6QrMT1LDomq2PMpA");

// The main program module for the test token
#[program]
pub mod test_token {
    // Import the system program and various token-related functions from the anchor_spl library
    use anchor_lang::system_program;
    use anchor_spl::{token::{initialize_mint, InitializeMint, mint_to, MintTo, transfer, Transfer, burn, Burn, freeze_account, FreezeAccount, close_account, CloseAccount, thaw_account, ThawAccount, set_authority, SetAuthority}, associated_token, metadata::{create_metadata_accounts_v3, create_master_edition_v3}};
    
    // Import the parent module
    use super::*;

    // Function to create a new test token
    // Takes in a context of CreateToken, the number of decimals for the token, and the initial amount of the token
    pub fn create_token(ctx: Context<CreateToken>, decimals:u8, amount:u64) -> Result<()> {
        // Create a new account for the mint token
        system_program::create_account(
            CpiContext::new(
                // The system program account
                ctx.accounts.system_program.to_account_info(), 
                // The CreateAccount instruction, specifying the signer and the mint token account
                system_program::CreateAccount { from: ctx.accounts.signer.to_account_info(), to: ctx.accounts.mint_token.to_account_info() }
            ), 
            // The amount of lamports to fund the account with
            10_000_000, 
            // The size of the account data
            82, 
            // The program ID of the account
            ctx.accounts.token_program.key
        )?;

        // Initialize the mint for the token
        initialize_mint(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(),
                // The InitializeMint instruction, specifying the mint token account and the rent account
                InitializeMint{mint:ctx.accounts.mint_token.to_account_info(),rent:ctx.accounts.rent.to_account_info()}
            ), 
            // The number of decimals for the token
            decimals, 
            // The mint authority for the token
            ctx.accounts.signer.key, 
            // The freeze authority for the token
            Some(ctx.accounts.signer.key)
        )?;

        // Create an associated token account for the token
        associated_token::create(
            CpiContext::new(
                // The associated token program account
                ctx.accounts.associate_token_program.to_account_info(), 
                // The Create instruction, specifying the payer, the associated token account, the authority, the mint token account, the system program account, and the token program account
                associated_token::Create { 
                    payer: ctx.accounts.signer.to_account_info(), 
                    associated_token: ctx.accounts.token_account.to_account_info(), 
                    authority: ctx.accounts.signer.to_account_info(), 
                    mint: ctx.accounts.mint_token.to_account_info(), 
                    system_program: ctx.accounts.system_program.to_account_info(), 
                    token_program: ctx.accounts.token_program.to_account_info() 
                }
            )
        )?;

        // Mint the initial amount of the token to the associated token account
        mint_to(
            CpiContext::new(
                // The token account
                ctx.accounts.token_account.to_account_info(), 
                // The MintTo instruction, specifying the authority, the mint token account, and the token account
                MintTo{authority:ctx.accounts.signer.to_account_info(),mint:ctx.accounts.mint_token.to_account_info(),to:ctx.accounts.token_account.to_account_info()}
            ), 
            // The amount of the token to mint
            amount
        )?;

        // Return success
        Ok(())
    }

    // Function to transfer test tokens from one account to another
    // Takes in a context of TransferToken and the amount of the token to transfer
    pub fn transfer_token(ctx: Context<TransferToken>, amount:u64)->Result<()>{

        // Log the start of the transfer
        msg!("Started {:} tokens transfer from account {:} to {:}",amount,ctx.accounts.from_account.key(),ctx.accounts.to_account.key());

        // Transfer the specified amount of the token from the from_account to the to_account
        transfer(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The Transfer instruction, specifying the authority, the from_account, and the to_account
                Transfer{authority:ctx.accounts.signer.to_account_info(),from:ctx.accounts.from_account.to_account_info(),to:ctx.accounts.to_account.to_account_info()}
            ), 
            // The amount of the token to transfer
            amount
        )?;

        // Return success
        Ok(())
    }

    // Function to set the authority of a test token
    // Takes in a context of SetAuthorityToken and the value of the authority to set
    pub fn set_authority_token(ctx: Context<SetAuthorityToken>, authority_value:u8)->Result<()>{
        // Declare variables for the account or mint and the authority type
        let account_or_mint;
        let authority_type;
        // Match the authority_value to set the authority type and the account or mint
        match authority_value {
            // If the authority_value is 0, set the authority type to MintTokens and the account or mint to the mint token account
            0=> {
                authority_type = anchor_spl::token::spl_token::instruction::AuthorityType::MintTokens;
                account_or_mint=ctx.accounts.mint_token.to_account_info();
            },
            // If the authority_value is 1, set the authority type to FreezeAccount and the account or mint to the mint token account
            1=> {
                authority_type = anchor_spl::token::spl_token::instruction::AuthorityType::FreezeAccount;
                account_or_mint=ctx.accounts.mint_token.to_account_info();
            },
            // If the authority_value is 2, set the authority type to AccountOwner and the account or mint to the token account
            2 => {
                authority_type = anchor_spl::token::spl_token::instruction::AuthorityType::AccountOwner;
                account_or_mint = ctx.accounts.token_account.to_account_info();
            },
            // If the authority_value is anything else, set the authority type to CloseAccount and the account or mint to the token account
            _ => {
                authority_type = anchor_spl::token::spl_token::instruction::AuthorityType::CloseAccount;
                account_or_mint = ctx.accounts.token_account.to_account_info();
            }
        }
        // Set the authority of the account or mint
        set_authority(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The SetAuthority instruction, specifying the account or mint and the current authority
                SetAuthority{
                    account_or_mint:account_or_mint,
                    current_authority:ctx.accounts.signer.to_account_info()
                }
            ), 
            // The authority type to set
            authority_type.clone(), 
            // The new authority
            Some(ctx.accounts.new_signer.key())
        )?;

        // Return success
        Ok(())
    }

    // Function to burn a specified amount of a test token
    // Takes in a context of BurnToken and the amount of the token to burn
    pub fn burn_token(ctx: Context<BurnToken>, amount:u64)->Result<()>{
        // Burn the specified amount of the token from the token account
        burn(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The Burn instruction, specifying the authority, the from_account, and the mint token account
                Burn{
                    authority:ctx.accounts.signer.to_account_info(),
                    from:ctx.accounts.token_account.to_account_info(),
                    mint:ctx.accounts.mint_token.to_account_info()
                }
            ), 
            // The amount of the token to burn
            amount
        )?;
        // Return success
        Ok(())
    }

    // Function to freeze a test token
    // Takes in a context of FreezeToken
    pub fn freeze_token(ctx: Context<FreezeToken>)->Result<()>{
        
        // Freeze the token account
        freeze_account(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The FreezeAccount instruction, specifying the account, the mint token account, and the authority
                FreezeAccount{
                    account:ctx.accounts.token_account.to_account_info(),
                    mint:ctx.accounts.mint_token.to_account_info(),
                    authority:ctx.accounts.signer.to_account_info(),
                }
            )
        )?;


        // Return success
        Ok(())
    }

    // Function to unfreeze a test token
    // Takes in a context of FreezeToken
    pub fn un_freeze_token(ctx: Context<FreezeToken>)->Result<()>{
        
        // Unfreeze the token account
        thaw_account(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The ThawAccount instruction, specifying the account, the mint token account, and the authority
                ThawAccount{
                    account:ctx.accounts.token_account.to_account_info(),
                    mint:ctx.accounts.mint_token.to_account_info(),
                    authority:ctx.accounts.signer.to_account_info(),
                }
            )
        )?;


        // Return success
        Ok(())
    }

    // Function to close a test token
    // Takes in a context of CloseToken
    pub fn close_token(ctx: Context<CloseToken>)->Result<()>{
        
        // Close the token account
        close_account(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(), 
                // The CloseAccount instruction, specifying the account, the destination, and the authority
                CloseAccount{
                    account:ctx.accounts.token_account.to_account_info(),
                    destination:ctx.accounts.signer.to_account_info(),
                    authority:ctx.accounts.signer.to_account_info(),
                }
            )
        )?;


        // Return success
        Ok(())
    }

    // Function to set the metadata of a test token
    // Takes in a context of CreateMetadata and the metadata data
    pub fn set_token_metadata(ctx: Context<CreateMetadata>, data:MetadataData)->Result<()>{
        // Find the program address for the metadata
        let (metadata_address, _b1) = Pubkey::find_program_address(&[
            b"metadata", 
            &ctx.accounts.metadata_program.key.to_bytes(),
            &ctx.accounts.mint_token.key().to_bytes()
            ], 
            ctx.accounts.metadata_program.key
        );

        // The metadata account
        let metadata_account = &ctx.accounts.metadata_account;
        // The master account
        let master_account = &ctx.accounts.master_account;

        // Check if the metadata address matches the metadata account key
        if metadata_address != *metadata_account.key{
            // If not, return an error
            return err!(ProgramErrors::PdaNotMatched)
        }
        
        // Find the program address for the master edition
        let (master_address, _b2) = Pubkey::find_program_address(&[
            b"metadata", 
            &ctx.accounts.metadata_program.key.to_bytes(),
            &ctx.accounts.mint_token.key().to_bytes(),
            b"edition"
            ], 
            ctx.accounts.metadata_program.key
        );

        // Check if the master address matches the master account key
        if master_address != *master_account.key{
            // If not, return an error
            return err!(ProgramErrors::PdaNotMatched)
        }

        // Create the metadata accounts for the token
        create_metadata_accounts_v3(
            CpiContext::new(
                // The metadata program account
                ctx.accounts.metadata_program.to_account_info(), 
                // The CreateMetadataAccountsV3 instruction, specifying the metadata account, the mint token account, the mint authority, the update authority, the payer, the system program account, and the rent account
                anchor_spl::metadata::CreateMetadataAccountsV3{
                    metadata:metadata_account.to_account_info(),
                    mint:ctx.accounts.mint_token.to_account_info(),
                    mint_authority:ctx.accounts.signer.to_account_info(),
                    update_authority:ctx.accounts.signer.to_account_info(),
                    payer:ctx.accounts.signer.to_account_info(),
                    system_program:ctx.accounts.system_program.to_account_info(),
                    rent:ctx.accounts.rent.to_account_info(),
                }
            ), 
            // The metadata data
            DataV2 { 
                name: data.name, 
                symbol: data.symbol, 
                uri: data.uri, 
                seller_fee_basis_points: data.seller_fee_basis_points,
                creators: None, 
                collection: None, 
                uses: None 
            },
            // Whether to update the metadata
            true, 
            // Whether to update the authority
            true, 
            // The new authority
            None
        )?;


        // Create the master edition for the token
        create_master_edition_v3(
            CpiContext::new(
                // The metadata program account
                ctx.accounts.metadata_program.to_account_info(), 
                // The CreateMasterEditionV3 instruction, specifying the metadata account, the mint token account, the mint authority, the update authority, the payer, the system program account, the rent account, the edition account, and the token program account
                anchor_spl::metadata::CreateMasterEditionV3 {
                    metadata:metadata_account.to_account_info(),
                    mint:ctx.accounts.mint_token.to_account_info(),
                    mint_authority:ctx.accounts.signer.to_account_info(),
                    update_authority:ctx.accounts.signer.to_account_info(),
                    payer:ctx.accounts.signer.to_account_info(),
                    system_program:ctx.accounts.system_program.to_account_info(),
                    rent:ctx.accounts.rent.to_account_info(),
                    edition:ctx.accounts.edition_account.to_account_info(),
                    token_program:ctx.accounts.token_program.to_account_info()
                }
            ), 
            // The supply of the token
            Some(data.supply)
        )?;

        // Return success
        Ok(())
    }
}

// Struct for the metadata data
#[derive(Debug,AnchorDeserialize,AnchorSerialize)]
pub struct MetadataData{
    // The name of the token
    pub name: String,
    // The symbol of the token
    pub symbol: String,
    // The URI of the token
    pub uri: String,
    // The seller fee basis points of the token
    pub seller_fee_basis_points: u16,
    // The supply of the token
    pub supply: u64
}

// Accounts for the CreateMetadata instruction
#[derive(Accounts)]
pub struct CreateMetadata<'info> {
    // The mint token account
    #[account(mut)]
    pub mint_token:Account<'info,Mint>,
    // The signer account
    #[account(mut)]
    pub signer:Signer<'info>,
    // The metadata account
    #[account(mut)]
    /// CHECK: check for safety in future
    pub metadata_account:AccountInfo<'info>,
    // The master account
    #[account(mut)]
    /// CHECK: check for safety in future
    pub master_account:AccountInfo<'info>,
    // The edition account
    #[account(mut)]
    /// CHECK: check for safety in future
    pub edition_account:AccountInfo<'info>,
    // The system program account
    pub system_program:Program<'info,System>,
    // The token program account
    pub token_program:Program<'info,Token>,
    // The associated token program account
    pub associate_token_program:Program<'info,AssociatedToken>,
    // The metadata program account
    #[account(mut)]
    /// CHECK: check for safety in future
    pub metadata_program:AccountInfo<'info>,
    // The rent account
    pub rent:Sysvar<'info,Rent>
}

// Accounts for the CreateToken instruction
#[derive(Accounts)]
pub struct CreateToken<'info> {
    // The mint token account
    #[account(init_if_needed, payer = signer, seeds = [b"mint-token", signer.key().as_ref()], bump, space=82)]
    pub mint_token:Account<'info,Mint>,
    // The signer account
    #[account(mut)]
    pub signer:Signer<'info>,
    // The token account
    #[account(mut)]
    /// CHECK: check for safety in future
    pub token_account:AccountInfo<'info>,
    // The system program account
    pub system_program:Program<'info,System>,
    // The token program account
    pub token_program:Program<'info,Token>,
    // The associated token program account
    pub associate_token_program:Program<'info,AssociatedToken>,
    // The rent account
    pub rent:Sysvar<'info,Rent>
}

// Accounts for the TransferToken instruction
#[derive(Accounts)]
pub struct TransferToken<'info>{    
    // The mint token account
    #[account(mut, seeds = [b"mint-token", signer.key().as_ref()], bump, mint::decimals = 9, mint::authority = mint_token)]
    pub mint_token:Account<'info,Mint>,
    #[account(mut)]
    pub from_account:Account<'info,TokenAccount>,
    #[account(mut)]
    pub to_account:Account<'info,TokenAccount>,
    #[account(mut)]
    pub signer:Signer<'info>,
    pub system_program:Program<'info,System>,
    pub token_program:Program<'info,Token>,
    pub associate_token_program:Program<'info,AssociatedToken>,
}

#[derive(Accounts)]
pub struct SetAuthorityToken<'info> {
    #[account(mut, seeds = [b"mint-token", signer.key().as_ref()], bump)]
    pub mint_token:Account<'info,Mint>,
    #[account(mut)]
    pub signer:Signer<'info>,
    #[account(mut)]
    pub new_signer:Signer<'info>,
    #[account(mut)]
    pub token_account:Account<'info,TokenAccount>,
    pub token_program:Program<'info,Token>,
}

#[derive(Accounts)]
pub struct BurnToken<'info> {
    #[account(mut, seeds = [b"mint-token", signer.key().as_ref()], bump)]
    pub mint_token:Account<'info,Mint>,
    #[account(mut)]
    pub signer:Signer<'info>,
    #[account(mut)]
    pub token_account:Account<'info,TokenAccount>,
    pub token_program:Program<'info,Token>,
}

#[derive(Accounts)]
pub struct FreezeToken<'info> {
    #[account(mut, seeds = [b"mint-token", signer.key().as_ref()], bump)]
    pub mint_token:Account<'info,Mint>,
    #[account(mut)]
    pub signer:Signer<'info>,
    #[account(mut)]
    pub token_account:Account<'info,TokenAccount>,
    pub token_program:Program<'info,Token>,
}

#[derive(Accounts)]
pub struct CloseToken<'info> {
    #[account(mut, seeds = [b"mint-token", signer.key().as_ref()], bump)]
    pub mint_token:Account<'info,Mint>,
    #[account(mut)]
    pub signer:Signer<'info>,
    #[account(mut)]
    pub token_account:Account<'info,TokenAccount>,
    pub token_program:Program<'info,Token>,
}

#[error_code]
pub enum ProgramErrors {
    #[msg("PDA account not matched")]
    PdaNotMatched
}

test.ts

describe("Token Operations", () => {
  const provider = anchor.AnchorProvider.env();
  anchor.setProvider(provider);

  const testTokenProgram = anchor.workspace.TestToken as Program<TestToken>;

  let mintTokenPDA, mintTokenPDABump, associatedTokenProgramKey, providerTokenAccountKey, tokenAccountKey
  beforeEach(async () => {
    try {
      [mintTokenPDA, mintTokenPDABump] = await anchor.web3.PublicKey.findProgramAddress(
        [Buffer.from(anchor.utils.bytes.utf8.encode("mint-token")), provider.wallet.publicKey.toBuffer()],
        testTokenProgram.programId
      );

      associatedTokenProgramKey = new anchor.web3.PublicKey(
        "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
      );
    
      providerTokenAccountKey = anchor.utils.token.associatedAddress({
        mint: mintTokenPDA,
        owner: provider.wallet.publicKey,
      });
    
      tokenAccountKey = anchor.web3.PublicKey.findProgramAddressSync(
        [
          provider.wallet.publicKey.toBuffer(),
          TOKEN_PROGRAM_ID.toBuffer(),
          mintTokenPDA.toBuffer(),
        ],
        associatedTokenProgramKey
      )[0];
    } catch (error) {
      console.error("Error calculating PDA: ", error);
    }
  });

  const DECIMALS = 9;

  function convertTokensToBN(tokens: number) {
    return new anchor.BN(tokens * Math.pow(10, DECIMALS));
  }

  async function fetchUserTokenBalance(
    connection: anchor.web3.Connection,
    mintKey: anchor.web3.PublicKey,
    userKey: anchor.web3.PublicKey
  ): Promise<number> {
    try {
      const userTokenAccountKey = await getAssociatedTokenAddress(
        mintKey,
        userKey
      );

      const accountInfo = await getAccount(connection, userTokenAccountKey);

      const balance = Number(accountInfo.amount) / Math.pow(10, DECIMALS);

      return balance;
    } catch (error) {
      console.error(
        `Failed to fetch user token balance: ${error}, mintKey=${mintKey}, userKey=${userKey}`
      );
      throw error;
    }
  }

  it("Create token!", async () => {
    console.log("Mint token key: ", mintTokenPDA.toBase58());
    console.log(
      "Provider token account key via anchor: ",
      providerTokenAccountKey.toBase58()
    );
    console.log("Token account key via PDA: ", tokenAccountKey.toBase58());

    expect(providerTokenAccountKey.toBase58()).to.equal(
      tokenAccountKey.toBase58(),
      "Token accounts must be same using different methods"
    );

    try {
      const transactionSignature = await testTokenProgram.methods
        .createToken(DECIMALS, convertTokensToBN(100))
        .accounts({
          mintToken: mintTokenPDA,
          tokenAccount: providerTokenAccountKey,
          associateTokenProgram: associatedTokenProgramKey,
        })
        .signers([])
        .rpc();
      console.log("Transaction signature", transactionSignature);
      const balance = await fetchUserTokenBalance(
        provider.connection,
        mintTokenPDA,
        provider.wallet.publicKey
      );
      expect(balance).to.equal(
        100,
        `Balance for TestToken (TEST) does not match expected balance.`
      );
    } catch (error) {
      console.log("Error in 'Create token!': ", error);
    }
  });
...

2 Answers 2

3

It sounds like you're trying to create a mint account using PDA from your program as the address.

Try just using anchor constaints to create the mint account.

#[derive(Accounts)]
pub struct CreateToken<'info> {
    #[account(
        init,
        seeds = [b"mint-token", signer.key().as_ref()], 
        bump,
        payer = signer,
        mint::decimals = 9,
        mint::authority = signer.key(),
        mint::freeze_authority = signer.key(),
    )]
    pub mint_token:Account<'info,Mint>,
    ...
}

You can then remove these CPIs from your create_token instruction logic. The constaints make these for you under the hood.

        // Create a new account for the mint token
        system_program::create_account(
            CpiContext::new(
                // The system program account
                ctx.accounts.system_program.to_account_info(), 
                // The CreateAccount instruction, specifying the signer and the mint token account
                system_program::CreateAccount { from: ctx.accounts.signer.to_account_info(), to: ctx.accounts.mint_token.to_account_info() }
            ), 
            // The amount of lamports to fund the account with
            10_000_000, 
            // The size of the account data
            82, 
            // The program ID of the account
            ctx.accounts.token_program.key
        )?;

        // Initialize the mint for the token
        initialize_mint(
            CpiContext::new(
                // The token program account
                ctx.accounts.token_program.to_account_info(),
                // The InitializeMint instruction, specifying the mint token account and the rent account
                InitializeMint{mint:ctx.accounts.mint_token.to_account_info(),rent:ctx.accounts.rent.to_account_info()}
            ), 
            // The number of decimals for the token
            decimals, 
            // The mint authority for the token
            ctx.accounts.signer.key, 
            // The freeze authority for the token
            Some(ctx.accounts.signer.key)
        )?;

Here is a reference example.

3
  • will try this out soon! thank you for the reference example. do you have any tips on how to understand anchor constraints? I have rust analyzer installed in vs code but don't know if there's good documentation on what args I can pass in for the constraints.
    – AceGravity
    Commented Jan 3 at 17:19
  • here are some examples to reference. here are some explanations for the constraints
    – john
    Commented Jan 3 at 18:14
  • thank you! one last question: do you think I need the other fn calls for burn token, freeze token? Or because I'm inheriting the SPL token standard, I can just call those fns via the program directly? Sorry if a dumb question, still a beginner. I see a lot of people also using CLI / JS or TS to call certain SPL functions too...
    – AceGravity
    Commented Jan 9 at 14:08
1

Using constraints to create the associated token account should solve your problem:

ex:

#[account(
    init,
    payer = initializer,
    associated_token::mint = mint,
    associated_token::authority = initializer
)]
initializer_ata: Account<'info, TokenAccount>,

Or if u want to use token_interface

#[account(
    init,
    payer = initializer,
    associated_token::authority = initializer,
    associated_token::mint = mint,
)]
initializer_ata:: InterfaceAccount<'info, TokenAccount>,

i would also advise to use constraints to set the decimals, authority etc... ex:

 #[account(
    init,
    payer = initializer,
    seeds = [b"mint", config.key().as_ref()],
    bump,
    mint::authority = auth,
    mint::decimals = 0
)]
mint: Account<'info, Mint>,

and use saved bumps.

ex:

#[account(
    mut,
    seeds=[b"mint", config.key().as_ref()],
    bump = config.mint_bump
)]
mint: Account<'info, Mint>,
1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Jan 3 at 2:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.