0

I have this function in Rust Smart Contract Solana:

 pub fn buy_ticket(ctx: Context<BuyTicket>, lottery_id: u32) -> Result<()> {
        let lottery = &mut ctx.accounts.lottery;
        let ticket = &mut ctx.accounts.ticket;
        let buyer = &mut ctx.accounts.buyer;

        if lottery.winner_id.is_some() {
            return err!(LotteryError::WinnerAlreadyExists);
        }
        invoke(
            &transfer(&buyer.key(), &lottery.key(), lottery.ticket_price),
            &[
                buyer.to_account_info(),
                lottery.to_account_info(),
                ctx.accounts.system_program.to_account_info(),
            ],
        )?;

        lottery.last_ticket_id += 1;
        ticket.id = lottery.last_ticket_id;
        ticket.lottery_id = lottery_id;
        ticket.authority = buyer.key();

        msg!("Ticket id: {}", ticket.id);
        msg!("Ticket authority: {}", ticket.authority);

        Ok(())
    }

and this:

#[instruction(lottery_id:u32)]
pub struct BuyTicket<'info> {
    #[account(
        mut,
        seeds = [LOTTERY_SEED.as_bytes(), &lottery_id.to_le_bytes()],
        bump
    )]
    pub lottery: Account<'info, Lottery>,

    #[account(
        init,
        payer = buyer,
        space = 4 + 4 + 32 + 8,
        seeds = [
            TICKET_SEED.as_bytes(),
            lottery.key().as_ref(),
            &(lottery.last_ticket_id + 1).to_le_bytes()
        ],
        bump
    )]
    pub ticket: Account<'info, Ticket>,

    #[account(mut)]
    pub buyer: Signer<'info>,

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

#[account]
pub struct Ticket {
    pub id: u32,
    pub authority: Pubkey,
    pub lottery_id: u32,
}

I builded and deployed to https://beta.solpg.io and I have one lottery active:

[{
    "publicKey": "6WwWbKYf7BzwZLWZdibeYqeixXvZdxSmc5qcDdKq44AG",
    "account": {
      "id": 1,
      "authority": "GeanNrzhjbvqSZmmVxtdE2cD4dc3mVpk2XyHhRUstrkQ",
      "ticketPrice": "1000000000",
      "lastTicketId": 2,
      "winnerId": 1,
      "claimed": false,
      "timestamp": "1707683900"
    }
}]

If I try to buyTicket from the https://beta.solpg.io calling the buyTicket function with args -> lotteryId: u32 = 1, accounts -> lottery: publicKey = 6WwWbKYf7BzwZLWZdibeYqeixXvZdxSmc5qcDdKq44AG, ticket generated from seeds: . seed(1): string = 'ticket' . seed(2): publicKey = 6WwWbKYf7BzwZLWZdibeYqeixXvZdxSmc5qcDdKq44AG . seed(3): u32 = 1 . seed(4): publicKey = Program ID (I don't put the original value) , buyer: publicKey = GeanNrzhjbvqSZmmVxtdE2cD4dc3mVpk2XyHhRUstrkQ and systemProgram: publicKey = Program ID (I don't put the original value). It works.

In Angular App I have this function and inside it I tried to create the ticket: publicKey from seed with that 4 seeds as before and after that to call the buyTicket function with the exactly same values as before:

async buyTicket(
    lotteryId: string,
    lotteryPublicKeyString: string,
    buyerPublicKeyString: string,
    last_ticket_id: string
  ) {
    const ticketSeed = Buffer.concat([
      Buffer.from(TICKET_SEED),
      new PublicKey(lotteryPublicKeyString).toBuffer(),
      Buffer.from(last_ticket_id),
      PROGRAM_ID.toBuffer(),
    ]);
    const ticketPublicKey = new PublicKey(sha256(ticketSeed)).toString();
    const lotteryPublicKey = new PublicKey(lotteryPublicKeyString);
    const buyerPublicKey = new PublicKey(buyerPublicKeyString);
    try {
      await this.program.rpc['buyTicket'](lotteryId, {
        accounts: {
          lotteryPublicKey,
          ticketPublicKey,
          buyerPublicKey,
          PROGRAM_ID,
        },
        signers: [],
      });
      console.log('Ticket bought successfully!');
    } catch (error) {
      console.error('Error buying ticket:', error);
    }
  }

When I call it I receive this error:

data.service.ts:157 Error buying ticket: Error: Invalid arguments: lottery not provided.
    at index.js:133:23
    at Array.forEach (<anonymous>)
    at validateAccounts (index.js:127:16)
    at ix (index.js:4873:13)
    at txFn (index.js:4964:20)
    at Object.<anonymous> (index.js:4937:24)
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (asyncToGenerator.js:3:1)
    at _next (asyncToGenerator.js:22:1)
    at asyncToGenerator.js:27:1

Can you help me to create this buyFunction to works as at https://beta.solpg.io? Thank you!

1 Answer 1

1

Notice your account names. Your instruction requires lottery, ticket, buyer, systemProgram. In your Angular code, you are passing these accounts, but the names are not right.

Specifically, notice this part of your code:

await this.program.rpc['buyTicket'](lotteryId, {
  accounts: {
    lotteryPublicKey,
    ticketPublicKey,
    buyerPublicKey,
    PROGRAM_ID,
  },
  signers: [],
});

The keys of the object accounts are lotteryPublicKey, ticketPublicKey, buyerPublicKey, PROGRAM_ID as you have not explicitly added keys, these values end being key names with the variable value being the respective key's value. Update it to this:

await this.program.rpc['buyTicket'](lotteryId, {
  accounts: {
    lottery: lotteryPublicKey,
    ticket: ticketPublicKey,
    buyer: buyerPublicKey,
    systemProgram: PROGRAM_ID,
  },
  signers: [],
});

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.