leaderboard update

This commit is contained in:
Sewmina Dilshan 2025-07-29 08:16:00 +05:30
parent db24f57690
commit 5681511a0d
11 changed files with 151 additions and 45 deletions

View File

@ -26,3 +26,11 @@ pub enum BettingError {
#[msg("Invalid ticket sale vault address")] #[msg("Invalid ticket sale vault address")]
InvalidTicketSaleVault, InvalidTicketSaleVault,
} }
#[error_code]
pub enum LeaderboardError {
#[msg("Invalid id")]
InvalidId,
#[msg("Not active")]
NotActive,
}

View File

@ -4,7 +4,7 @@ use crate::{error::BettingError, *};
use crate::constants::TICKET_SALE_VAULT_ADDRESS; use crate::constants::TICKET_SALE_VAULT_ADDRESS;
use std::str::FromStr; use std::str::FromStr;
pub fn buy_tickets(ctx: Context<BuyTickets>, _id:u64, amount: u64) -> Result<()> { pub fn buy(ctx: Context<BuyTickets>, amount: u64) -> Result<()> {
let transfer_amount = 100000000; // 0.1 SOL in lamports let transfer_amount = 100000000; // 0.1 SOL in lamports

View File

@ -2,11 +2,14 @@ use anchor_lang::prelude::*;
use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}}; use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}};
use crate::*; use crate::*;
pub fn create_leaderboard(ctx: Context<CreateLeaderboard>, _id:u64) -> Result<()> { pub fn create(ctx: Context<CreateLeaderboard>, id:u64, game_id:String) -> Result<()> {
let ticket_leaderboard_list = &mut ctx.accounts.ticket_leaderboard_list; let ticket_leaderboard_list = &mut ctx.accounts.ticket_leaderboard_list;
let ticket_leaderboard = &mut ctx.accounts.ticket_leaderboard; let ticket_leaderboard = &mut ctx.accounts.ticket_leaderboard;
ticket_leaderboard.id = id;
ticket_leaderboard.players = vec![]; ticket_leaderboard.players = vec![];
ticket_leaderboard.game_id = game_id;
ticket_leaderboard.is_over = false;
ticket_leaderboard_list.leaderboards.push(ticket_leaderboard.key()); ticket_leaderboard_list.leaderboards.push(ticket_leaderboard.key());
msg!("Leaderboard created!"); msg!("Leaderboard created!");

View File

@ -0,0 +1,73 @@
use anchor_lang::prelude::*;
use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}};
use crate::*;
pub fn enter(ctx: Context<EnterLeaderboard>, id:u64) -> Result<()> {
let payer = &ctx.accounts.payer;
let receipt = &mut ctx.accounts.receipt_account;
// 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)?;
receipt.active = true;
receipt.id= id;
msg!("Successfully entered leaderboard");
Ok(())
}
#[derive(Accounts)]
#[instruction(id:u64)]
pub struct EnterLeaderboard<'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 + TicketReceiptVault::INIT_SPACE,
seeds = [b"receipt", payer.key().as_ref()],
bump
)]
pub receipt_account: Account<'info, TicketReceiptVault>,
#[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>,
}

View File

@ -1,7 +1,7 @@
use anchor_lang::prelude::*; use anchor_lang::prelude::*;
use crate::*; use crate::*;
pub fn init_leaderboard_list(ctx: Context<InitLeaderboardList>) -> Result<()> { pub fn init(ctx: Context<InitLeaderboardList>) -> Result<()> {
ctx.accounts.ticket_leaderboard_list.leaderboards = vec![]; ctx.accounts.ticket_leaderboard_list.leaderboards = vec![];
msg!("Initialized Leaderboard List!"); msg!("Initialized Leaderboard List!");
Ok(()) Ok(())

View File

@ -45,3 +45,6 @@ pub use update_leaderboard::*;
pub mod buy_tickets; pub mod buy_tickets;
pub use buy_tickets::*; pub use buy_tickets::*;
pub mod enter_leaderboard;
pub use enter_leaderboard::*;

View File

@ -1,34 +1,29 @@
use anchor_lang::prelude::*; use anchor_lang::prelude::*;
use anchor_spl::{associated_token::AssociatedToken, token_interface::{TokenAccount, TokenInterface}}; use crate::{error::LeaderboardError, *};
use crate::*;
pub fn update_leaderboard(ctx: Context<UpdateLeaderboard>, _id:u64, new_score:u64) -> Result<()> { pub fn update(ctx: Context<UpdateLeaderboard>, id:u64, player:Pubkey, new_score:u64) -> Result<()> {
let payer = &ctx.accounts.payer;
let leaderboard_entry: &mut Account<LeaderboardEntry> = &mut ctx.accounts.leaderboard_entry; let leaderboard_entry: &mut Account<LeaderboardEntry> = &mut ctx.accounts.leaderboard_entry;
let leaderboard: &mut Account<TicketLeaderboard> = &mut ctx.accounts.ticket_leaderboard; let leaderboard: &mut Account<TicketLeaderboard> = &mut ctx.accounts.ticket_leaderboard;
// Transfer 1 token from user's vault to leaderboard vault let receipt = &mut ctx.accounts.receipt_account;
let transfer_amount = 1u64;
let cpi_program = ctx.accounts.token_program.to_account_info(); if receipt.id != id {
let cpi_accounts = anchor_spl::token_interface::TransferChecked { return Err(LeaderboardError::InvalidId.into());
from: ctx.accounts.user_token_vault.to_account_info(), }
to: ctx.accounts.token_vault.to_account_info(),
authority: payer.to_account_info(), if !receipt.active {
mint: ctx.accounts.token_mint.to_account_info(), return Err(LeaderboardError::NotActive.into());
}; }
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 // Find existing entry for this payer
if leaderboard_entry.highscore < new_score { if leaderboard_entry.highscore < new_score {
leaderboard_entry.highscore = new_score; leaderboard_entry.highscore = new_score;
} }
leaderboard_entry.total_tickets += transfer_amount; leaderboard_entry.total_tickets += 1;
if !leaderboard.players.contains(&payer.key()) { if !leaderboard.players.contains(&player) {
leaderboard.players.push(payer.key()); leaderboard.players.push(player);
} }
msg!("Successfully updated leaderboard with score: {}", new_score); msg!("Successfully updated leaderboard with score: {}", new_score);
@ -37,7 +32,7 @@ pub fn update_leaderboard(ctx: Context<UpdateLeaderboard>, _id:u64, new_score:u6
#[derive(Accounts)] #[derive(Accounts)]
#[instruction(id:u64)] #[instruction(id:u64, player:Pubkey, new_score:u64)]
pub struct UpdateLeaderboard<'info>{ pub struct UpdateLeaderboard<'info>{
#[account(mut)] #[account(mut)]
pub payer: Signer<'info>, pub payer: Signer<'info>,
@ -60,23 +55,11 @@ pub struct UpdateLeaderboard<'info>{
#[account( #[account(
mut, mut,
associated_token::mint = token_mint, seeds = [b"receipt", player.as_ref()],
associated_token::authority = ticket_leaderboard, bump
associated_token::token_program = token_program
)] )]
pub token_vault: InterfaceAccount<'info, TokenAccount>, pub receipt_account: Account<'info, TicketReceiptVault>,
#[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 system_program: Program<'info, System>,
pub token_program: Interface<'info, TokenInterface>,
pub associated_token_program: Program<'info, AssociatedToken>,
} }

View File

@ -58,4 +58,26 @@ pub mod bets {
pub fn clear_bets_list(ctx: Context<ClearBetsList>) -> Result<()> { pub fn clear_bets_list(ctx: Context<ClearBetsList>) -> Result<()> {
clear_bets_list::clear(ctx) clear_bets_list::clear(ctx)
} }
pub fn init_leaderboard_list(ctx:Context<InitLeaderboardList>) -> Result<()>{
init_leaderboard_list::init(ctx)
}
pub fn create_leaderboard(ctx:Context<CreateLeaderboard>, id:u64, game_id:String)->Result<()>{
create_leaderboard::create(ctx, id, game_id)
}
pub fn update_leaderboard(ctx:Context<UpdateLeaderboard>, id:u64, player:Pubkey, new_score:u64)->Result<()>{
update_leaderboard::update(ctx, id, player, new_score)
}
pub fn buy_tickets(ctx:Context<BuyTickets>, amount:u64)->Result<()>{
buy_tickets::buy(ctx,amount)
}
pub fn enter_leaderboard(ctx:Context<EnterLeaderboard>, id:u64)->Result<()>{
enter_leaderboard::enter(ctx, id)
}
} }

View File

@ -12,3 +12,6 @@ pub use ticket_leaderboard_account::*;
pub mod ticket_leaderboard_list; pub mod ticket_leaderboard_list;
pub use ticket_leaderboard_list::*; pub use ticket_leaderboard_list::*;
pub mod ticket_receipt_vault;
pub use ticket_receipt_vault::*;

View File

@ -4,8 +4,10 @@ use crate::*;
#[account] #[account]
#[derive(InitSpace)] #[derive(InitSpace)]
pub struct TicketLeaderboard{ pub struct TicketLeaderboard{
pub id: u64,
#[max_len(16)]
pub game_id: String,
#[max_len(500)] #[max_len(500)]
pub players: Vec<Pubkey> pub players: Vec<Pubkey>,
pub is_over: bool,
} }

View File

@ -0,0 +1,9 @@
use anchor_lang::*;
use crate::*;
#[account]
#[derive(InitSpace)]
pub struct TicketReceiptVault{
pub id: u64,
pub active: bool
}