1

I keep getting this 0x0 error when trying to send an nft from my wallet into a vault from a program. I'm trying to create an NFT auction (bids in sol) with escrow. This is an attempt to initialize the auction, creating a campaign account with the auction data and sending an nft from my wallet into a vault owned by the program.

I don't understand how the accounts can be already initialized as I keep passing in different seeds (name).

The rust code:

use anchor_lang::solana_program::entrypoint::ProgramResult;

use anchor_spl::token::{self, CloseAccount, Mint, SetAuthority, TokenAccount, Transfer};
use spl_token::instruction::AuthorityType;


declare_id!("8Prsyig5ShEKqnn7nK8sjdqvu2pacMHuQFU5KzFNqRnS");

#[program]
pub mod auction {
    use super::*;

    const ESCROW_PDA_SEED: &[u8] = b"escrow";

  pub fn create(
    ctx: Context<Create>,
    name: String, 
    symbol: String, 
    minimum: u64, 
    _vault_account_bump: u8,
) -> ProgramResult {

        let campaign = &mut ctx.accounts.campaign;
        
        campaign.name = name;
        campaign.symbol = symbol;
        campaign.topbid = minimum;
        campaign.admin = *ctx.accounts.initializer.key;


        let (vault_authority, _vault_authority_bump) =
        Pubkey::find_program_address(&[ESCROW_PDA_SEED], ctx.program_id);
        token::set_authority(
            ctx.accounts.into_set_authority_context(),
            AuthorityType::AccountOwner,
            Some(vault_authority),
        )?;

                token::transfer(
            ctx.accounts.into_transfer_to_pda_context(),
            1,
        )?;


        Ok(())
     }
}

#[derive(Accounts)]
#[instruction(name: String)]
pub struct Create<'info> {
    #[account(zero)]
    pub campaign: Box<Account<'info, Campaign>>,
        #[account(
        init,
        seeds = [name.as_ref()],
        bump,
        payer = initializer,
        token::mint = mint,
        token::authority = initializer,
    )]
    pub vault_account: Account<'info, TokenAccount>,
    pub mint: Account<'info, Mint>,
    /// CHECK: This is not dangerous because we don't read or write from this account
    #[account(mut, signer)]
    pub initializer: AccountInfo<'info>,
    pub initializer_deposit_token_account: Account<'info, TokenAccount>,
    pub rent: Sysvar<'info, Rent>,
    pub system_program: Program<'info, System>,
        /// CHECK: This is not dangerous because we don't read or write from this account
    pub token_program: AccountInfo<'info>,
}

#[account]
pub struct Campaign {
    pub admin:  Pubkey,
    pub name: String,
    pub symbol: String,
    pub topbid: u64,
    pub topbidder: Pubkey,

}

impl<'info> Create<'info> {
    fn into_transfer_to_pda_context(&self) -> CpiContext<'_, '_, '_, 'info, Transfer<'info>> {
        let cpi_accounts = Transfer {
            from: self
                .initializer_deposit_token_account
                .to_account_info()
                .clone(),
            to: self.vault_account.to_account_info().clone(),
            authority: self.initializer.clone(),
        };
        CpiContext::new(self.token_program.clone(), cpi_accounts)
    }

    fn into_set_authority_context(&self) -> CpiContext<'_, '_, '_, 'info, SetAuthority<'info>> {
        let cpi_accounts = SetAuthority {
            account_or_mint: self.vault_account.to_account_info().clone(),
            current_authority: self.initializer.clone(),
        };
        CpiContext::new(self.token_program.clone(), cpi_accounts)
    }
} 

The typescript test code:

import * as anchor from "@project-serum/anchor";
import { Auction } from "../target/types/auction";
import { Connection, PublicKey, clusterApiUrl } from "@solana/web3.js";

import { TOKEN_PROGRAM_ID, getMint, } from "@solana/spl-token";

import {
  Program,
  web3,
  utils,
  BN,
} from "@project-serum/anchor";

describe("Auction", () => {
  // Configure the client to use the local cluster.

  const provider = anchor.AnchorProvider.env()
  const wallet = provider.wallet as anchor.Wallet;
  anchor.setProvider(provider);
  const program = anchor.workspace.Auction as Program<Auction>;
  console.log(program.programId)
  const network = clusterApiUrl("devnet")
  const connection = new Connection(network);



  it("Adding new Auction", async () => {

    const name = "Test11111";
    const description = "TST";

    let mintpk = new PublicKey("3xhfybrMftPyJD5avJZHMpbU3PSTx8afyfL6ehMs8bLE");
    let mint = await getMint(connection, mintpk);

    let vault_account_bump = null;
    let vault_authority_pda = null;
    let vault_account_pda = null;

    const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: PublicKey = new PublicKey(
      'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',
    );

    async function findAssociatedTokenAddress(
      walletAddress: PublicKey,
      tokenMintAddress: PublicKey
    ): Promise<PublicKey> {
      return (await PublicKey.findProgramAddress(
        [
          walletAddress.toBuffer(),
          TOKEN_PROGRAM_ID.toBuffer(),
          tokenMintAddress.toBuffer(),
        ],
        SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
      ))[0];
    }

    let initializerTokenAccount = await findAssociatedTokenAddress(wallet.publicKey, mint.address);

    const [_vault_account_pda, _vault_account_bump] = await PublicKey.findProgramAddress(
      [Buffer.from(anchor.utils.bytes.utf8.encode(name))],
      program.programId
    );
    vault_account_pda = _vault_account_pda;
    vault_account_bump = _vault_account_bump;

    const [campaign] = await PublicKey.findProgramAddress(
      [
        // mintKeypair.publicKey.toBuffer(),
        // utils.bytes.utf8.encode("_"),
        utils.bytes.utf8.encode(name),
      ],
      program.programId
    );
    const provider = anchor.AnchorProvider.env()
    const { SystemProgram } = web3;

    await program.rpc.create(
      name,
      description,
      new BN(0.3 * web3.LAMPORTS_PER_SOL),
      vault_account_bump,
      {
        accounts: {
          campaign: campaign,
          vaultAccount: vault_account_pda,
          mint: mint.address,
          initializer: provider.wallet.publicKey,
          initializerDepositTokenAccount: initializerTokenAccount,
          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
          systemProgram: SystemProgram.programId,
          tokenProgram: TOKEN_PROGRAM_ID,
        },
        instructions: [
          await program.account.campaign.createInstruction(wallet.payer),
        ],
      }
    );
  });
});

The error:

  1 failing

  1) Auction
       Adding new Auction:
     Error: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x0
      at Connection.sendEncodedTransaction (node_modules/@solana/web3.js/src/connection.ts:5054:13)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)
      at Connection.sendRawTransaction (node_modules/@solana/web3.js/src/connection.ts:5013:20)
      at sendAndConfirmRawTransaction (node_modules/@project-serum/anchor/src/provider.ts:288:21)
      at AnchorProvider.sendAndConfirm (node_modules/@project-serum/anchor/src/provider.ts:148:14)
      at Object.rpc [as create] (node_modules/@project-serum/anchor/src/program/namespace/rpc.ts:29:16) 

Writing to the campaign account works, but I just can't seem to get sending the nft in working.

Have been messing with this code for multiple days now so any help would be greatly appreciated.

Thanks in advance!

2 Answers 2

2

Quoting an answer to this exact issue as shown here, with minor changes:

"0x0 means you're attempting to initialize an already initialized account. What's happening here is that because your vaultAccountPda has only a constant seed, the same address is generated for it on each run of the test.

Therefore, not only does running your test for the first time initialize vaultAccountPda, but subsequent tests also fail because they would attempt to initialize the same account(because constant seeds give you the exact same address each time)."

In summary, the first test initializes the account and subsequent tests fail with an 0x0 because they try to initialize the same address.

A way to fix this is to ensure that the address of vaultAccountPda has at least one non-constant seed such as a publickey. Including a randomly generated key(by anchor.web3.Keypair.generate()) in your pda derivation guarantees a different address on each test and avoids that problem.

1
  • Where can I get the list of these error codes (numbers) and their meaning/explanation? Where did you learn that "0x0 means you're attempting to initialize an already initialized account"? Commented Feb 11, 2023 at 20:04
1

This is a error on Rust's side. When you create a pda, you do it with static variables that will always give the same account and therefore an initialization error.

const ESCROW_PDA_SEED: &[u8] = b"escrow";
let (vault_authority, _vault_authority_bump) =
        Pubkey::find_program_address(&[ESCROW_PDA_SEED], ctx.program_id);

ESCROW_PDA_SEED is static and does not change.I recommend this:

let (vault_authority, _vault_authority_bump) =
            Pubkey::find_program_address(&[name.as_ref()], ctx.program_id);
1
  • Thank you for your reply! I changed the code to: let _name = name.clone(); campaign.name = name; campaign.symbol = symbol; campaign.topbid = minimum; campaign.admin = *ctx.accounts.initializer.key; let (vault_authority, _vault_authority_bump) = Pubkey::find_program_address(&[_name.as_ref()], ctx.program_id); But I get the same error... Anything else you think of? Much appreciated!
    – Matti
    Commented Nov 24, 2022 at 14:48

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.