I am trying to follow Solana Bootcamp 2024 project 9 that I will use as boilerplate for my dapp.
When I get to test the program I run into an error and I can't find anything in the docs (or I don't understand it).
Error:
tests/tokenlottery.spec.ts:47:17 - error TS2345: Argument of type '{ tokenProgram: anchor.web3.PublicKey; }' is not assignable to parameter of type 'ResolvedAccounts<{ name: "payer"; writable: true; signer: true; } | { name: "collectionMint"; writable: true; pda: { seeds: [{ kind: "const"; value: [99, 111, 108, 108, 101, 99, 116, 105, 111, 110, 95, 109, 105, 110, 116]; }]; }; } | ... 8 more ... | { ...; }>'. Property 'tokenLottery' is missing in type '{ tokenProgram: anchor.web3.PublicKey; }' but required in type 'Pick<OmitNever<{ payer: Address | undefined; collectionMint: never; collectionAssociatedAccount: never; metadata: never; tokenMetadataProgram: never; masterEdition: never; tokenLottery: Address; assoiateTokenProgram: never; tokenProgram: Address; systemProgram: never; rent: never; }>, "tokenLottery" | "tokenProgram">'. 47 .accounts({ ~ 48 tokenProgram: TOKEN_PROGRAM_ID, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 })
I have tried to pass all the accounts that are associate with this instruction, but it doesn't seem to work. I can't find the best place to look for the solution either.
So this is my tokenlottery.specs.ts code:
import * as anchor from '@coral-xyz/anchor';import { Program } from '@coral-xyz/anchor';import { Keypair } from '@solana/web3.js';import { Tokenlottery } from '../target/types/tokenlottery';import { getAssociatedTokenAddressSync } from '@solana/spl-token';import { TOKEN_PROGRAM_ID } from '@coral-xyz/anchor/dist/cjs/utils/token';describe('tokenlottery', () => { // Configure the client to use the local cluster. const provider = anchor.AnchorProvider.env(); anchor.setProvider(provider); const wallet = provider.wallet as anchor.Wallet; anchor.setProvider(provider); const program = anchor.workspace.Tokenlottery as Program<Tokenlottery>; const connection = provider.connection; it('should init config and lottery', async () => { const slot = await connection.getSlot(); console.log('Current slot', slot); const initConfigIx = await program.methods .intializeConfig( new anchor.BN(0), new anchor.BN(slot + 10), new anchor.BN(10000) ) .instruction(); const blockhashContext = await connection.getLatestBlockhash(); const tx = new anchor.web3.Transaction({ feePayer: provider.wallet.publicKey, blockhash: blockhashContext.blockhash, lastValidBlockHeight: blockhashContext.lastValidBlockHeight, }).add(initConfigIx); const signature = await anchor.web3.sendAndConfirmTransaction( connection, tx, [wallet.payer] ); const initLotteryIx = await program.methods .initializeLottery() .accounts({ tokenProgram: TOKEN_PROGRAM_ID, // ERROR HERE }) .instruction(); const initLotteryTx = new anchor.web3.Transaction({ blockhash: blockhashContext.blockhash, lastValidBlockHeight: blockhashContext.lastValidBlockHeight, feePayer: wallet.payer.publicKey, }).add(initLotteryIx); const sig = await anchor.web3.sendAndConfirmTransaction( connection, initLotteryTx, [wallet.payer] ); console.log(signature, sig); });});
and this is my lib.rs (what matters):
pub fn initialize_lottery(context: Context<InitializeLottery>) -> Result<()> { let signer_seeds: &[&[&[u8]]] = &[&[ b"collection-mint".as_ref(),&[context.bumps.collection_mint], ]]; /* Create Mint - Minting a Single Token to our Token Account */ msg!("Creating Mint Account"); mint_to( CpiContext::new_with_signer( context.accounts.token_program.to_account_info(), MintTo { mint: context.accounts.collection_mint.to_account_info(), to: context.accounts.collection_associated_account.to_account_info(), authority: context.accounts.collection_mint.to_account_info(), }, signer_seeds,), 1 )?; /* Create Metadata Account for that token */ msg!("Creating Metadata Account"); create_metadata_accounts_v3( CpiContext::new_with_signer( context.accounts.token_metadata_program.to_account_info(), CreateMetadataAccountsV3 { metadata: context.accounts.metadata.to_account_info(), //metadata account mint: context.accounts.collection_mint.to_account_info(), //collection_mint account mint_authority: context.accounts.collection_mint.to_account_info(), //mint authority is itself payer: context.accounts.payer.to_account_info(), //payer update_authority: context.accounts.collection_mint.to_account_info(), //update authority itself system_program: context.accounts.system_program.to_account_info(), //system program rent: context.accounts.rent.to_account_info(), //rent }, &signer_seeds ), DataV2 { name: NAME.to_string(), symbol: SYMBOL.to_string(), uri: URI.to_string(), seller_fee_basis_points: 0, creators: Some(vec![Creator { address: context.accounts.collection_mint.key(), verified: false, share: 100, }]), collection: None, uses: None, }, true, // is mutable ? true, // is update authority the signer? Some(CollectionDetails::V1 { size: 0 }), // collection details (set as collection nft) )?; /* Create Master Edition */ msg!("Creating Master Edition Account"); create_master_edition_v3( CpiContext::new_with_signer( context.accounts.token_metadata_program.to_account_info(), CreateMasterEditionV3 { payer: context.accounts.payer.to_account_info(), mint: context.accounts.collection_mint.to_account_info(), edition: context.accounts.master_edition.to_account_info(), mint_authority: context.accounts.collection_mint.to_account_info(), update_authority: context.accounts.collection_mint.to_account_info(), metadata: context.accounts.metadata.to_account_info(), token_program: context.accounts.token_program.to_account_info(), system_program: context.accounts.system_program.to_account_info(), rent: context.accounts.rent.to_account_info(), },&signer_seeds ), Some(0) // Max supply (we wont be doing more than this account) )?; /* Last Step : Verify the collection */ msg!("Verifying Collection"); sign_metadata( CpiContext::new_with_signer( context.accounts.token_metadata_program.to_account_info(), SignMetadata { creator: context.accounts.collection_mint.to_account_info(), //check create_metadata_accounts_v3 metadata: context.accounts.metadata.to_account_info(), },&signer_seeds))?; Ok(()) }#[derive(Accounts)]pub struct InitializeLottery<'info> { #[account(mut)] pub payer: Signer<'info>, #[account( init, payer = payer, mint::decimals = 0, mint::authority = collection_mint, mint::freeze_authority = collection_mint, seeds = [b"collection_mint".as_ref()], bump )] pub collection_mint: InterfaceAccount<'info, Mint>, //this PDA is a mint account so we can't store the bump in the state account #[account( init, payer = payer, token::mint = collection_mint, token::authority = collection_associated_account, seeds = [b"collection_associated_account".as_ref()], bump )] pub collection_associated_account: InterfaceAccount<'info, TokenAccount>, //----- next 2 accounts not best practice -----// /* Check Metadata program code to see how to derive it */ #[account( mut, seeds =[b"metadata", token_metadata_program.key().as_ref(), collection_mint.key().as_ref() ], bump, seeds::program = token_metadata_program.key(), )] /// CHECKED: Thi is checked by the metadata program pub metadata: UncheckedAccount<'info>, #[account( mut, seeds =[ b"metadata", token_metadata_program.key().as_ref(), collection_mint.key().as_ref(), b"edition" ], bump, seeds::program = token_metadata_program.key(), )] /// CHECKED: This is checked by the metadata program #[account( mut )] pub token_lottery: Account<'info, TokenLottery>, // Programs we are going to need pub token_metadata_program: Program<'info, Metadata>, pub assoiate_token_program: Program<'info, AssociatedToken>, pub token_program: Interface<'info, TokenInterface>, pub system_program: Program<'info, System>, pub rent: Sysvar<'info, Rent>,}
If anyone could help me debug this and also explain what are we specifying so I can debug this myself in the future, I would be very thankful.
Not sure if this is helpful too:
[features]idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
[dependencies]
anchor-lang = "0.30.1"
anchor-spl = {version= "0.30.1", features= ["metadata"]}