From 3a9fa10f438061ab717c818b5cbbcdb1008d3568 Mon Sep 17 00:00:00 2001 From: Sewmina Dilshan Date: Wed, 30 Jul 2025 22:24:45 +0530 Subject: [PATCH] reward dist --- programs/bets/src/error.rs | 6 + programs/bets/src/instructions/buy_tickets.rs | 17 +-- programs/bets/src/instructions/mod.rs | 5 +- .../src/instructions/reward_leaderboard.rs | 109 ++++++++++++++++++ programs/bets/src/lib.rs | 4 + 5 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 programs/bets/src/instructions/reward_leaderboard.rs diff --git a/programs/bets/src/error.rs b/programs/bets/src/error.rs index 4cab67c..14146a2 100644 --- a/programs/bets/src/error.rs +++ b/programs/bets/src/error.rs @@ -33,4 +33,10 @@ pub enum LeaderboardError { InvalidId, #[msg("Not active")] NotActive, +} + +#[error_code] +pub enum ArithmeticError { + #[msg("Arithmetic error")] + ArithmeticError, } \ No newline at end of file diff --git a/programs/bets/src/instructions/buy_tickets.rs b/programs/bets/src/instructions/buy_tickets.rs index eeef2c8..e36fdee 100644 --- a/programs/bets/src/instructions/buy_tickets.rs +++ b/programs/bets/src/instructions/buy_tickets.rs @@ -1,8 +1,7 @@ use anchor_lang::prelude::*; use anchor_spl::{associated_token::AssociatedToken, token::{transfer_checked, TransferChecked}, token_interface::{TokenAccount, TokenInterface}}; -use crate::{error::BettingError, *}; -use crate::constants::TICKET_SALE_VAULT_ADDRESS; -use std::str::FromStr; +use crate::*; + pub fn buy(ctx: Context, amount: u64) -> Result<()> { @@ -10,7 +9,7 @@ pub fn buy(ctx: Context, amount: u64) -> Result<()> { let ix = anchor_lang::solana_program::system_instruction::transfer( &ctx.accounts.payer.key(), - &ctx.accounts.ticket_sale_vault.key(), + &ctx.accounts.ticket_leaderboard_list.key(), transfer_amount ); @@ -18,7 +17,7 @@ pub fn buy(ctx: Context, amount: u64) -> Result<()> { &ix, &[ ctx.accounts.payer.to_account_info(), - ctx.accounts.ticket_sale_vault.to_account_info(), + ctx.accounts.ticket_leaderboard_list.to_account_info(), ], )?; @@ -49,14 +48,6 @@ pub struct BuyTickets<'info>{ #[account(mut)] pub payer: Signer<'info>, - - /// CHECK: The vault that receives SOL payments for tickets - #[account( - mut, - address = Pubkey::from_str(TICKET_SALE_VAULT_ADDRESS).unwrap() @ BettingError::InvalidTicketSaleVault - )] - pub ticket_sale_vault: AccountInfo<'info>, - #[account( mut, seeds = [TICKET_LEADERBOARD_LIST_SEED], diff --git a/programs/bets/src/instructions/mod.rs b/programs/bets/src/instructions/mod.rs index 891268d..ac438ff 100644 --- a/programs/bets/src/instructions/mod.rs +++ b/programs/bets/src/instructions/mod.rs @@ -50,4 +50,7 @@ pub mod enter_leaderboard; pub use enter_leaderboard::*; pub mod remove_leaderboard; -pub use remove_leaderboard::*; \ No newline at end of file +pub use remove_leaderboard::*; + +pub mod reward_leaderboard; +pub use reward_leaderboard::*; \ No newline at end of file diff --git a/programs/bets/src/instructions/reward_leaderboard.rs b/programs/bets/src/instructions/reward_leaderboard.rs new file mode 100644 index 0000000..e476ce1 --- /dev/null +++ b/programs/bets/src/instructions/reward_leaderboard.rs @@ -0,0 +1,109 @@ +use anchor_lang::prelude::*; +use anchor_spl::{associated_token::AssociatedToken, token::{transfer_checked, TransferChecked}, token_interface::{TokenAccount, TokenInterface}}; +use crate::{error::ArithmeticError, *}; + +pub fn reward(ctx:Context, id:u64)->Result<()>{ + + let leaderboard = &mut ctx.accounts.ticket_leaderboard; + + let ticket_leaderboard_vault = &ctx.accounts.ticket_leaderboard_vault; + let ticket_leaderboard_list_vault = &ctx.accounts.ticket_leaderboard_list_vault; + let winner = &ctx.accounts.winner; + + // Get the token balance in the ticket_leaderboard vault + let token_balance = ticket_leaderboard_vault.amount; + + // Calculate SOL reward: each token is worth 0.1 SOL (100,000,000 lamports) + let sol_reward = match token_balance.checked_mul(100_000_000) { + Some(reward) => reward, + None => return Err(Error::from(ArithmeticError::ArithmeticError)), + }; + + // Transfer SOL from ticket_leaderboard_list to winner + let ix = anchor_lang::solana_program::system_instruction::transfer( + &ctx.accounts.ticket_leaderboard_list.key(), + &winner.key(), + sol_reward + ); + + anchor_lang::solana_program::program::invoke( + &ix, + &[ + ctx.accounts.ticket_leaderboard_list.to_account_info(), + winner.to_account_info(), + ], + )?; + + // Transfer all tokens from ticket_leaderboard vault to ticket_leaderboard_list vault + let cpi_program = ctx.accounts.token_program.to_account_info(); + let cpi_accounts = TransferChecked { + from: ticket_leaderboard_vault.to_account_info(), + to: ticket_leaderboard_list_vault.to_account_info(), + authority: leaderboard.to_account_info(), + mint: ctx.accounts.token_mint.to_account_info(), + }; + + let seeds = &[ + TICKET_LEADERBOARD_SEED, + &id.to_le_bytes()[..], + &[ctx.bumps.ticket_leaderboard][..] + ]; + let signer_seeds = &[&seeds[..]]; + + let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds); + transfer_checked(cpi_ctx, token_balance, ctx.accounts.token_mint.decimals)?; + + leaderboard.is_over = true; + + msg!("Successfully rewarded winner with {} SOL and transferred {} tokens to leaderboard list", + sol_reward as f64 / 1_000_000_000.0, token_balance); + + Ok(()) +} + +#[derive(Accounts)] +#[instruction(id:u64)] +pub struct RewardLeaderboard<'info>{ + #[account(mut)] + pub payer: Signer<'info>, + + /// CHECK: The winner account + #[account(mut)] + pub winner: AccountInfo<'info>, + + #[account( + mut, + seeds = [TICKET_LEADERBOARD_LIST_SEED], + bump + )] + pub ticket_leaderboard_list: Account<'info, TicketLeaderboardList>, + + #[account( + mut, + seeds = [TICKET_LEADERBOARD_SEED, id.to_le_bytes().as_ref()], + bump + )] + pub ticket_leaderboard: Account<'info, TicketLeaderboard>, + + #[account( + mut, + associated_token::mint = token_mint, + associated_token::authority = ticket_leaderboard, + associated_token::token_program = token_program + )] + pub ticket_leaderboard_vault: InterfaceAccount<'info, TokenAccount>, + + #[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>, + + 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/lib.rs b/programs/bets/src/lib.rs index f444bdf..e79a5d2 100644 --- a/programs/bets/src/lib.rs +++ b/programs/bets/src/lib.rs @@ -83,5 +83,9 @@ pub mod bets { remove_leaderboard::remove(ctx, id) } + pub fn reward_leaderboard(ctx:Context, id:u64)->Result<()>{ + reward_leaderboard::reward(ctx, id) + } + }