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!