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. 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 a 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