2

Folks, I'm starting with Solana and it's been rough to learn. Despite the poor error messages and the learning curve of Rust, I'm making my way through it.

I'm trying to develop a new token that will be a fungible asset (0 decimals, supply greater than 1 for the same token).

In another transaction, I already created a mint account and initialized it. Now I'm trying to mint that to another wallet. Basically, this is mint accounts context (for simplicity reasons I've excluded the metadata accounts):

pub struct MintAsset<'info> {
    #[account(mut)]
    pub mint: Account<'info, token::Mint>,
    #[account(mut)]
    pub mint_authority: Signer<'info>,
    /// CHECK: We're about to create this with Anchor
    #[account(mut)]
    pub minter_token: UncheckedAccount<'info>,
    #[account(mut)]
    pub payer: Signer<'info>,
    pub rent: Sysvar<'info, Rent>,
    pub system_program: Program<'info, System>,
    pub token_program: Program<'info, token::Token>,
    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
}

Then, I proceed to run this transaction for minting my tokens

pub fn mint_asset(ctx: Context<MintAsset>, data: MintArgs) -> Result<()> {   
        associated_token::create(
            CpiContext::new(
                ctx.accounts.associated_token_program.to_account_info(),
                associated_token::Create {
                    payer: ctx.accounts.mint_authority.to_account_info(),
                    associated_token: ctx.accounts.minter_token.to_account_info(),
                    authority: ctx.accounts.mint_authority.to_account_info(),
                    mint: ctx.accounts.mint.to_account_info(),
                    system_program: ctx.accounts.system_program.to_account_info(),
                    token_program: ctx.accounts.token_program.to_account_info(),
                    rent: ctx.accounts.rent.to_account_info(),
                },
            ),
        )?;

        token::mint_to(
            CpiContext::new(
                ctx.accounts.token_program.to_account_info(),
                token::MintTo {
                    mint: ctx.accounts.mint.to_account_info(),
                    to: ctx.accounts.minter_token.to_account_info(),
                    authority: ctx.accounts.mint_authority.to_account_info(),
                },
            ),
            data.amount,
        )?;

        Ok(())
    }

By using the following test:

async function mintToken(
    program: anchor.Program<Pdas>,
    wallet: anchor.Wallet,
    mintKeypair: anchor.web3.Keypair,
    minterWallet: anchor.Wallet,
    amount: number
  ) {
    try {
      
      const buyerTokenAddress = await anchor.utils.token.associatedAddress({
        mint: mintKeypair.publicKey,
        owner: wallet.publicKey,
      });
  
      const accounts = {
        mint: mintKeypair.publicKey,
        mintAuthority: wallet.publicKey,
        minterToken: buyerTokenAddress,
        payer: wallet.publicKey,
      };
  
      const signers = [];
  
      const args = {
        amount: new BN(amount),
      };
  
      const signature = await program.methods
        .mintAsset(args)
        .accounts(accounts)
        .signers(signers)
        .rpc();
    } catch (error) {
      console.log("MINT ERROR:", inspect({ error }, { depth: null }));
    }
  }

Now, that test throws an error if for the buyerTokenAddress I use the minterWallet as owner (Transaction simulation failed: Error processing Instruction 0: An account required by the instruction is missing). I understand that for owning a token, one must have an associated token account, which, as stated by the documentation, is an

account for a given wallet address is simply a program-derived account consisting of the wallet address itself and the token mint

https://spl.solana.com/associated-token-account

Why's that? I mean, doesn't anyone can mint this token? I understand that only the mintAuthority can mint the tokens, but it makes sense to have it as a signer (as accounts struct expect), but (and here's another question) if I put an empty array of signers, the code still runs (again, why is that? I thought I had to provide an signer account at least for mint_authority).

Should I create a new mint account and initialize it? Wouldn't that be a new token, instead?

What is obvious in Solana token development that I'm missing here? Thanks in advance

1 Answer 1

1

So there are a few questions here

  • Account missing error: This error is caused by missing an account from anchor's list of accounts. The error is most likey caused by anchor not being able to figure out one of the addresses you didn't include. I'd suggest always using accountsStrict instead of accounts to not hit this issue.
  • Why do you need an associated token account: Technically you don't need an associated token account, just a token account. An associated token account is a special token account that is derivable based on the wallet address and mint. That still begs the question of why you need a token account. This is because tokens on solana (not just solana really) are just numbers being passed around and we need somewhere to store those numbers. We also need to pass it in to be minted because solana requires that all accounts we read from or wirte to are passed as transaction arguments.
  • Why does this work with no signers: The reason it works is because there is actually a signer, the fee payer.Anchor hides this from you but if your fee payer is also the mint authority then the signature is valid for both.
  • New mint: A new mint is a new token. If you want the same token use the same mint.

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.