diff --git a/programs/bets/src/instructions/buy_tickets.rs b/programs/bets/src/instructions/buy_tickets.rs new file mode 100644 index 0000000..d4c717d --- /dev/null +++ b/programs/bets/src/instructions/buy_tickets.rs @@ -0,0 +1,74 @@ +use anchor_lang::prelude::*; +use anchor_spl::{associated_token::AssociatedToken, token::{transfer_checked, TransferChecked}, token_interface::{TokenAccount, TokenInterface}}; +use crate::*; + +pub fn buy_tickets(ctx: Context, _id:u64, amount: u64) -> Result<()> { + + let transfer_amount = 100000000; // 0.1 SOL in lamports + + let ix = anchor_lang::solana_program::system_instruction::transfer( + &ctx.accounts.payer.key(), + &ctx.accounts.ticket_sale_vault.key(), + transfer_amount + ); + + anchor_lang::solana_program::program::invoke( + &ix, + &[ + ctx.accounts.payer.to_account_info(), + ctx.accounts.ticket_sale_vault.to_account_info(), + ], + )?; + + //Transfer tokens from leaderboard vault to user vault + let cpi_program: AccountInfo<'_> = ctx.accounts.token_program.to_account_info(); + let cpi_accounts = TransferChecked { + from: ctx.accounts.ticket_leaderboard_list_vault.to_account_info(), + to: ctx.accounts.user_token_vault.to_account_info(), + authority: ctx.accounts.ticket_leaderboard_list.to_account_info(), + mint: ctx.accounts.token_mint.to_account_info(), + }; + let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + transfer_checked(cpi_ctx, amount, 9,)?; + + Ok(()) +} + +#[derive(Accounts)] +pub struct BuyTickets<'info>{ + #[account(mut)] + pub payer: Signer<'info>, + + + #[account(mut)] + pub ticket_sale_vault: AccountInfo<'info>, + + #[account( + mut, + seeds = [b"ticket_leaderboard_list"], + bump + )] + pub ticket_leaderboard_list: Account<'info, TicketLeaderboardList>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = ticket_leaderboard_list, + associated_token::token_program = token_program + )] + pub ticket_leaderboard_list_vault: InterfaceAccount<'info, TokenAccount>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = payer, + associated_token::token_program = token_program + )] + pub user_token_vault: InterfaceAccount<'info, TokenAccount>, + + pub token_mint: InterfaceAccount<'info, anchor_spl::token_interface::Mint>, + + pub system_program: Program<'info, System>, + pub token_program: Interface<'info, TokenInterface>, + pub associated_token_program: Program<'info, AssociatedToken>, +} \ No newline at end of file diff --git a/programs/bets/src/instructions/create_leaderboard.rs b/programs/bets/src/instructions/create_leaderboard.rs new file mode 100644 index 0000000..33d7927 --- /dev/null +++ b/programs/bets/src/instructions/create_leaderboard.rs @@ -0,0 +1,53 @@ +use anchor_lang::prelude::*; +use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}}; +use crate::*; + +pub fn create_leaderboard(ctx: Context, _id:u64) -> Result<()> { + let ticket_leaderboard_list = &mut ctx.accounts.ticket_leaderboard_list; + let ticket_leaderboard = &mut ctx.accounts.ticket_leaderboard; + + ticket_leaderboard.players = vec![]; + + ticket_leaderboard_list.leaderboards.push(ticket_leaderboard.key()); + msg!("Leaderboard created!"); + Ok(()) +} + + +#[derive(Accounts)] +#[instruction(id:u64)] +pub struct CreateLeaderboard<'info>{ + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + mut, + seeds = [b"ticket_leaderboard_list"], + bump + )] + pub ticket_leaderboard_list: Account<'info, TicketLeaderboardList>, + + #[account( + init, + payer = payer, + space = 8 + TicketLeaderboard::INIT_SPACE, + seeds = [b"ticket_leaderboard", id.to_le_bytes().as_ref()], + bump + )] + pub ticket_leaderboard: Account<'info, TicketLeaderboard>, + + #[account( + init, + payer = payer, + associated_token::mint = token_mint, + associated_token::authority = ticket_leaderboard, + associated_token::token_program = token_program + )] + pub token_vault: InterfaceAccount<'info, TokenAccount>, + + pub token_mint: InterfaceAccount<'info, anchor_spl::token_interface::Mint>, + + pub system_program: Program<'info, System>, + pub token_program: Interface<'info, TokenInterface>, + pub associated_token_program: Program<'info, AssociatedToken>, +} \ No newline at end of file diff --git a/programs/bets/src/instructions/init_leaderboard_list.rs b/programs/bets/src/instructions/init_leaderboard_list.rs new file mode 100644 index 0000000..e1be407 --- /dev/null +++ b/programs/bets/src/instructions/init_leaderboard_list.rs @@ -0,0 +1,26 @@ +use anchor_lang::prelude::*; +use crate::*; + +pub fn init_leaderboard_list(ctx: Context) -> Result<()> { + ctx.accounts.ticket_leaderboard_list.leaderboards = vec![]; + msg!("Initialized Leaderboard List!"); + Ok(()) +} + + +#[derive(Accounts)] +pub struct InitLeaderboardList<'info>{ + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + payer = payer, + space = 8 + 4 + (500 * 8), + seeds = [b"ticket_leaderboard_list"], + bump + )] + pub ticket_leaderboard_list: Account<'info, TicketLeaderboardList>, + + pub system_program: Program<'info, System>, +} \ No newline at end of file diff --git a/programs/bets/src/instructions/mod.rs b/programs/bets/src/instructions/mod.rs index 70239d0..077ac6f 100644 --- a/programs/bets/src/instructions/mod.rs +++ b/programs/bets/src/instructions/mod.rs @@ -33,3 +33,15 @@ pub use shared::*; pub mod clear_bets_list; pub use clear_bets_list::*; + +pub mod init_leaderboard_list; +pub use init_leaderboard_list::*; + +pub mod create_leaderboard; +pub use create_leaderboard::*; + +pub mod update_leaderboard; +pub use update_leaderboard::*; + +pub mod buy_tickets; +pub use buy_tickets::*; \ No newline at end of file diff --git a/programs/bets/src/instructions/update_leaderboard.rs b/programs/bets/src/instructions/update_leaderboard.rs new file mode 100644 index 0000000..d2bb5f4 --- /dev/null +++ b/programs/bets/src/instructions/update_leaderboard.rs @@ -0,0 +1,82 @@ +use anchor_lang::prelude::*; +use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}}; +use crate::*; + +pub fn update_leaderboard(ctx: Context, _id:u64, new_score:u64) -> Result<()> { + let payer = &ctx.accounts.payer; + let leaderboard_entry: &mut Account = &mut ctx.accounts.leaderboard_entry; + let leaderboard: &mut Account = &mut ctx.accounts.ticket_leaderboard; + + // Transfer 1 token from user's vault to leaderboard vault + let transfer_amount = 1u64; + + let cpi_program = ctx.accounts.token_program.to_account_info(); + let cpi_accounts = anchor_spl::token_interface::TransferChecked { + from: ctx.accounts.user_token_vault.to_account_info(), + to: ctx.accounts.token_vault.to_account_info(), + authority: payer.to_account_info(), + mint: ctx.accounts.token_mint.to_account_info(), + }; + let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); + anchor_spl::token_interface::transfer_checked(cpi_ctx, transfer_amount, ctx.accounts.token_mint.decimals)?; + + // Find existing entry for this payer + if leaderboard_entry.highscore < new_score { + leaderboard_entry.highscore = new_score; + } + + leaderboard_entry.total_tickets += transfer_amount; + + if !leaderboard.players.contains(&payer.key()) { + leaderboard.players.push(payer.key()); + } + + msg!("Successfully updated leaderboard with score: {}", new_score); + Ok(()) +} + + +#[derive(Accounts)] +#[instruction(id:u64)] +pub struct UpdateLeaderboard<'info>{ + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + mut, + seeds = [b"ticket_leaderboard", id.to_le_bytes().as_ref()], + bump + )] + pub ticket_leaderboard: Account<'info, TicketLeaderboard>, + + #[account( + init_if_needed, + payer= payer, + space = 8 + LeaderboardEntry::INIT_SPACE, + seeds = [b"leaderboard_entry", ticket_leaderboard.key().as_ref(), payer.key().as_ref()], + bump + )] + pub leaderboard_entry: Account<'info, LeaderboardEntry>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = ticket_leaderboard, + associated_token::token_program = token_program + )] + pub token_vault: InterfaceAccount<'info, TokenAccount>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = payer, + associated_token::token_program = token_program + )] + pub user_token_vault: InterfaceAccount<'info, TokenAccount>, + + pub token_mint: InterfaceAccount<'info, anchor_spl::token_interface::Mint>, + + pub system_program: Program<'info, System>, + pub token_program: Interface<'info, TokenInterface>, + pub associated_token_program: Program<'info, AssociatedToken>, +} \ No newline at end of file diff --git a/programs/bets/src/state/mod.rs b/programs/bets/src/state/mod.rs index 4a9bdbb..5fc2769 100644 --- a/programs/bets/src/state/mod.rs +++ b/programs/bets/src/state/mod.rs @@ -2,4 +2,13 @@ pub mod bets_list; pub use bets_list::*; pub mod bet_vault; -pub use bet_vault::*; \ No newline at end of file +pub use bet_vault::*; + +pub mod ticket_leaderboard; +pub use ticket_leaderboard::*; + +pub mod ticket_leaderboard_account; +pub use ticket_leaderboard_account::*; + +pub mod ticket_leaderboard_list; +pub use ticket_leaderboard_list::*; \ No newline at end of file diff --git a/programs/bets/src/state/ticket_leaderboard.rs b/programs/bets/src/state/ticket_leaderboard.rs new file mode 100644 index 0000000..5865d16 --- /dev/null +++ b/programs/bets/src/state/ticket_leaderboard.rs @@ -0,0 +1,9 @@ +use anchor_lang::*; +use crate::*; + +#[account] +#[derive(InitSpace)] +pub struct TicketLeaderboard{ + #[max_len(500)] + pub players: Vec +} \ No newline at end of file diff --git a/programs/bets/src/state/ticket_leaderboard_account.rs b/programs/bets/src/state/ticket_leaderboard_account.rs new file mode 100644 index 0000000..dce3694 --- /dev/null +++ b/programs/bets/src/state/ticket_leaderboard_account.rs @@ -0,0 +1,10 @@ +use anchor_lang::*; +use crate::*; + +#[account] +#[derive(InitSpace)] +pub struct LeaderboardEntry{ + pub owner: Pubkey, + pub highscore: u64, + pub total_tickets: u64 +} \ No newline at end of file diff --git a/programs/bets/src/state/ticket_leaderboard_list.rs b/programs/bets/src/state/ticket_leaderboard_list.rs new file mode 100644 index 0000000..cc36b8f --- /dev/null +++ b/programs/bets/src/state/ticket_leaderboard_list.rs @@ -0,0 +1,9 @@ +use anchor_lang::*; +use crate::*; + +#[account] +#[derive(InitSpace)] +pub struct TicketLeaderboardList{ + #[max_len(500)] + pub leaderboards: Vec +} \ No newline at end of file