2

I'm trying to use the current timestamp as seed but i can't find the right way, i even try to passing as string and getting a deserialize error.

here is the code for my program:

use anchor_lang::prelude::*;

declare_id!("5hH748CgCFrbuJ19GtdgaB9M1pV5VuUuTicTyz8Jhr3d");


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

    pub fn create_game(ctx: Context<CreateGame>, players: Vec<Pubkey>, timestamp: String, items_by_line: u8, lines: u8) -> Result<()> {
        
        Ok(())
    }
}

#[derive(Accounts)]
#[instruction(timestamp: String)]
pub struct CreateGame<'info> {
    #[account(
        init,
        payer = payer,
        space = 1000,
        seeds = [b"game".as_ref(), &payer.key().to_bytes(), timestamp.as_ref()],
        bump
    )]
    pub game: Account<'info, Game>,
    #[account(mut)]
    pub payer: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct Game {
    pub board: Vec<Bubble>,
    pub players: Vec<Pubkey>,
    pub turn: u64,
    pub updated: u64,
}

#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)]
pub struct Bubble {
    pub player: u8,
    pub amount: u8,
}

Here my test:

import * as anchor from "@project-serum/anchor";
import { Program } from "@project-serum/anchor";
import { Bubbles } from "../target/types/bubbles";
import * as web3 from "@solana/web3.js"
import { PublicKey } from "@solana/web3.js"

describe("bubbles", () => {
 // Configure the client to use the local cluster.
 anchor.setProvider(anchor.AnchorProvider.env());

 const program = anchor.workspace.Bubbles as Program<Bubbles>;
 const payer = (program.provider as anchor.AnchorProvider).wallet;
 const player1 = new PublicKey("EjPpXXDykPawauyZHsBMtxGwG7K4iFmxdvB6ockM56ZN")
 const player2 = new PublicKey("CUtKCTar8gb5VYCDWbX5yFMVrhbnod9aCNf4cfhD2qPK")
 const timestamp = `${Date.now()}`

 it("Is initialized!", async () => {
   const [groupPublicKey] = web3.PublicKey.findProgramAddressSync(
     [Buffer.from("game"), payer.publicKey.toBuffer(), Buffer.from(timestamp),],
     program.programId,
   )
   const tx = await program.methods.createGame(
     [player1, player2],
     timestamp,
     5,
     10,
   ).accounts({
     game: groupPublicKey,
     payer: payer.publicKey,
     systemProgram: web3.SystemProgram.programId,
   })
   .rpc();
   console.log("Your transaction signature", tx);
 });
});

and here the error i'm getting:

 Error: AnchorError occurred. Error Code: InstructionDidNotDeserialize. Error Number: 102. Error Message: The program could not deserialize the given instruction.
      at Function.parse (node_modules/@project-serum/anchor/src/error.ts:135:14)
      at translateError (node_modules/@project-serum/anchor/src/error.ts:276:35)
      at MethodsBuilder.rpc [as _rpcFn] (node_modules/@project-serum/anchor/src/program/namespace/rpc.ts:35:29)
      at processTicksAndRejections (node:internal/process/task_queues:95:5)

any idea how can i approach this?

2 Answers 2

1

Only thing that pops out at me is to change:

#[instruction(timestamp: String)]

to:

#[instruction(players: Vec<Pubkey>, timestamp: String)]

Because you need the 1st-nth arguments from your instruction in the instruction macro, where n is the highest indexed argument you need from your instruction arguments. So since even if you only need your 2nd argument (timestamp), you have to pull in the 1st (players) as well.

2

we had a similar challenge some times ago and we solved like the following:

use crate::{
    errors::VyperVaultsErrorCode,
    state::{EpochData, VaultConfig},
};
use anchor_lang::prelude::*;
use rust_decimal::Decimal;

#[derive(Accounts)]
#[instruction(input_data: InitializeEpochDataInputData)]
pub struct InitializeEpochDataContext<'info> {
    /// Vault Configuration
    #[account()]
    pub vault_config: Box<Account<'info, VaultConfig>>,

    /// Epoch Data parameters account initialized
    #[account(init, seeds = [vault_config.key().as_ref(), input_data.start_timestamp.to_be_bytes().as_ref(),  b"epoch_data".as_ref()], bump, payer = signer, space = EpochData::LEN)]
    pub epoch_data: Box<Account<'info, EpochData>>,

    /// Payer for the `epoch_data` account creation
    #[account(mut)]
    pub signer: Signer<'info>,

    // System program
    pub system_program: Program<'info, System>,
}

#[derive(AnchorDeserialize, AnchorSerialize, Clone, Copy, Debug)]
pub struct InitializeEpochDataInputData {
    pub start_timestamp: i64,
}

pub fn handler(
    ctx: Context<InitializeEpochDataContext>,
    input_data: InitializeEpochDataInputData,
) -> Result<()> {
  
    // ...

    Ok(())
}

Using the start_timestamp.to_be_bytes() make the trick in the PDA seed.

Following for the tests (copying from our sdk, some methods are left behind, happy to share more if needed):

static async initializeIX(client: ProgramClient, vaultConfig: VaultConfig): Promise<anchor.web3.TransactionInstruction> {
    const epochData = await EpochData.findCurrentEpochPdaAddress(client, vaultConfig);

    return await client.program.methods
      .initializeEpochData({
        startTimestamp: new anchor.BN(await this.getCurrentEpochStartTimestamp(vaultConfig)),
      })
      .accounts({
        vaultConfig: vaultConfig.publicKey,
        epochData: epochData,
        signer: client.provider.wallet.publicKey,
      })
      .instruction();
  }

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.