From fbcdae629626ac8cf0470ebfd32034736282033b Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Thu, 18 Sep 2025 14:42:18 -0700 Subject: [PATCH] square --- api/src/instruction.rs | 6 +++-- api/src/sdk.rs | 40 +------------------------------ api/src/state/mod.rs | 6 +++++ api/src/state/square.rs | 23 +++++++++++++----- cli/src/main.rs | 31 +++++++----------------- program/src/initialize_squares.rs | 37 ---------------------------- program/src/lib.rs | 6 ++--- program/src/prospect.rs | 30 ++++++++++------------- program/src/reset.rs | 16 +++++++++---- 9 files changed, 63 insertions(+), 132 deletions(-) delete mode 100644 program/src/initialize_squares.rs diff --git a/api/src/instruction.rs b/api/src/instruction.rs index c322b78..123cde2 100644 --- a/api/src/instruction.rs +++ b/api/src/instruction.rs @@ -8,7 +8,6 @@ pub enum OreInstruction { ClaimSOL = 1, ClaimORE = 2, Initialize = 3, - InitializeSquares = 4, Prospect = 5, Redeem = 6, Reset = 7, @@ -116,6 +115,10 @@ pub struct SetSniperFeeDuration { #[derive(Clone, Copy, Debug, Pod, Zeroable)] pub struct ClaimSeeker {} +#[repr(C)] +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +pub struct MigrateSquares {} + instruction!(OreInstruction, Boost); instruction!(OreInstruction, ClaimSOL); instruction!(OreInstruction, ClaimORE); @@ -123,7 +126,6 @@ instruction!(OreInstruction, Redeem); instruction!(OreInstruction, Reset); instruction!(OreInstruction, Prospect); instruction!(OreInstruction, Initialize); -instruction!(OreInstruction, InitializeSquares); instruction!(OreInstruction, SetAdmin); instruction!(OreInstruction, SetFeeCollector); instruction!(OreInstruction, ClaimSeeker); diff --git a/api/src/sdk.rs b/api/src/sdk.rs index ef363bb..b0c354c 100644 --- a/api/src/sdk.rs +++ b/api/src/sdk.rs @@ -54,44 +54,6 @@ pub fn initialize(signer: Pubkey) -> Instruction { } } -// let [signer_info, square_info, system_program] = accounts else { - -pub fn initialize_squares(signer: Pubkey) -> Instruction { - Instruction { - program_id: crate::ID, - accounts: vec![ - AccountMeta::new(signer, true), - AccountMeta::new_readonly(system_program::ID, false), - AccountMeta::new(square_pda(0).0, false), - AccountMeta::new(square_pda(1).0, false), - AccountMeta::new(square_pda(2).0, false), - AccountMeta::new(square_pda(3).0, false), - AccountMeta::new(square_pda(4).0, false), - AccountMeta::new(square_pda(5).0, false), - AccountMeta::new(square_pda(6).0, false), - AccountMeta::new(square_pda(7).0, false), - AccountMeta::new(square_pda(8).0, false), - AccountMeta::new(square_pda(9).0, false), - AccountMeta::new(square_pda(10).0, false), - AccountMeta::new(square_pda(11).0, false), - AccountMeta::new(square_pda(12).0, false), - AccountMeta::new(square_pda(13).0, false), - AccountMeta::new(square_pda(14).0, false), - AccountMeta::new(square_pda(15).0, false), - AccountMeta::new(square_pda(16).0, false), - AccountMeta::new(square_pda(17).0, false), - AccountMeta::new(square_pda(18).0, false), - AccountMeta::new(square_pda(19).0, false), - AccountMeta::new(square_pda(20).0, false), - AccountMeta::new(square_pda(21).0, false), - AccountMeta::new(square_pda(22).0, false), - AccountMeta::new(square_pda(23).0, false), - AccountMeta::new(square_pda(24).0, false), - ], - data: InitializeSquares {}.to_bytes(), - } -} - pub fn claim_sol(signer: Pubkey, amount: u64) -> Instruction { let miner_address = miner_pda(signer).0; Instruction { @@ -191,7 +153,7 @@ pub fn prospect(signer: Pubkey, fee_collector: Pubkey, amount: u64, square_id: u let board_address = board_pda().0; let config_address = config_pda().0; let miner_address = miner_pda(signer).0; - let square_address = square_pda(square_id).0; + let square_address = square_pda(0).0; Instruction { program_id: crate::ID, accounts: vec![ diff --git a/api/src/state/mod.rs b/api/src/state/mod.rs index 2029915..6e49ed3 100644 --- a/api/src/state/mod.rs +++ b/api/src/state/mod.rs @@ -26,6 +26,12 @@ pub enum OreAccount { Square = 106, } +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +pub enum OreAccountOLD { + SquareOLD = 106, +} + pub fn board_pda() -> (Pubkey, u8) { Pubkey::find_program_address(&[BOARD], &crate::ID) } diff --git a/api/src/state/square.rs b/api/src/state/square.rs index 95d37e6..824c82c 100644 --- a/api/src/state/square.rs +++ b/api/src/state/square.rs @@ -1,12 +1,22 @@ use steel::*; -use crate::state::square_pda; +use crate::state::{square_pda, OreAccountOLD}; use super::OreAccount; #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] pub struct Square { + /// The count of miners on this square. + pub count: [usize; 25], + + /// The miners in each square. + pub miners: [[Pubkey; 16]; 25], +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +pub struct SquareOLD { /// The count of miners on this square. pub count: u64, @@ -20,10 +30,11 @@ pub struct Square { pub miners: [Pubkey; 16], } -impl Square { - pub fn pda(&self) -> (Pubkey, u8) { - square_pda(self.id) - } -} +// impl Square { +// pub fn pda() -> (Pubkey, u8) { +// square_pda() +// } +// } account!(OreAccount, Square); +account!(OreAccountOLD, SquareOLD); diff --git a/cli/src/main.rs b/cli/src/main.rs index 38fe0ef..a5a1c44 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -51,9 +51,6 @@ async fn main() { "initialize" => { initialize(&rpc, &payer).await.unwrap(); } - "initialize_squares" => { - initialize_squares(&rpc, &payer).await.unwrap(); - } "redeem" => { redeem(&rpc, &payer).await.unwrap(); } @@ -124,15 +121,6 @@ async fn initialize( Ok(()) } -async fn initialize_squares( - rpc: &RpcClient, - payer: &solana_sdk::signer::keypair::Keypair, -) -> Result<(), anyhow::Error> { - let ix = ore_api::sdk::initialize_squares(payer.pubkey()); - submit_transaction(rpc, payer, &[ix]).await?; - Ok(()) -} - async fn claim_sol( rpc: &RpcClient, payer: &solana_sdk::signer::keypair::Keypair, @@ -171,10 +159,10 @@ async fn reset( let mut miners = vec![]; if let Some(slot_hash) = slot_hashes.get(&board.end_slot) { let id = get_winning_square(&slot_hash.to_bytes()); - let square = get_square(rpc, id).await?; + let square = get_square(rpc).await?; println!("Winning square: {}", id); println!("Miners: {:?}", square.miners); - miners = square.miners.to_vec(); + miners = square.miners[id as usize].to_vec(); }; let reset_ix = ore_api::sdk::reset(payer.pubkey(), miners); submit_transaction(rpc, payer, &[reset_ix]).await?; @@ -253,13 +241,11 @@ async fn log_treasury(rpc: &RpcClient) -> Result<(), anyhow::Error> { async fn log_square(rpc: &RpcClient) -> Result<(), anyhow::Error> { let id = std::env::var("ID").expect("Missing ID env var"); - let id = u64::from_str(&id).expect("Invalid ID"); - let square = get_square(rpc, id).await?; + let id = usize::from_str(&id).expect("Invalid ID"); + let square = get_square(rpc).await?; println!("Square"); - println!(" id: {}", square.id); - println!(" count: {}", square.count); - println!(" round_id: {}", square.round_id); - println!(" miners: {:?}", square.miners); + println!(" count: {:?}", square.count[id]); + println!(" miners: {:?}", square.miners[id]); Ok(()) } @@ -320,6 +306,7 @@ fn print_board(board: Board, clock: &Clock) { println!(" Start slot: {}", board.start_slot); println!(" End slot: {}", board.end_slot); println!(" Prospects: {:?}", board.prospects); + println!(" Top miner: {:?}", board.top_miner); println!(" Total prospects: {}", board.total_prospects); println!(" Total vaulted: {}", board.total_vaulted); println!(" Total winnings: {}", board.total_winnings); @@ -347,8 +334,8 @@ async fn get_slot_hashes(rpc: &RpcClient) -> Result { Ok(slot_hashes) } -async fn get_square(rpc: &RpcClient, id: u64) -> Result { - let square_pda = ore_api::state::square_pda(id); +async fn get_square(rpc: &RpcClient) -> Result { + let square_pda = ore_api::state::square_pda(0); let account = rpc.get_account(&square_pda.0).await?; let square = Square::try_from_bytes(&account.data)?; Ok(*square) diff --git a/program/src/initialize_squares.rs b/program/src/initialize_squares.rs deleted file mode 100644 index 68c79cb..0000000 --- a/program/src/initialize_squares.rs +++ /dev/null @@ -1,37 +0,0 @@ -use ore_api::prelude::*; -use steel::*; - -/// Initializes the program. -pub fn process_initialize_squares(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { - // Load accounts. - let (required_accounts, square_accounts) = accounts.split_at(2); - let [signer_info, system_program] = required_accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - signer_info.is_signer()?.has_address(&ADMIN_ADDRESS)?; - system_program.is_program(&system_program::ID)?; - - // Create config account. - for i in 0..25 { - let square_info = &square_accounts[i]; - if square_info.data_is_empty() { - create_program_account::( - square_info, - system_program, - signer_info, - &ore_api::ID, - &[SQUARE, &(i as u64).to_le_bytes()], - )?; - let square = square_info.as_account_mut::(&ore_api::ID)?; - square.id = i as u64; - square.round_id = 0; - square.miners = [Pubkey::default(); 16]; - } else { - square_info - .as_account_mut::(&ore_api::ID)? - .assert_mut(|s| s.id == i as u64)?; - } - } - - Ok(()) -} diff --git a/program/src/lib.rs b/program/src/lib.rs index 943c2e4..eedc5ee 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -3,7 +3,6 @@ mod claim_ore; mod claim_seeker; mod claim_sol; mod initialize; -mod initialize_squares; mod prospect; mod redeem; mod reset; @@ -16,7 +15,6 @@ use claim_ore::*; use claim_seeker::*; use claim_sol::*; use initialize::*; -use initialize_squares::*; use prospect::*; use redeem::*; use reset::*; @@ -39,9 +37,7 @@ pub fn process_instruction( OreInstruction::ClaimSOL => process_claim_sol(accounts, data)?, OreInstruction::ClaimORE => process_claim_ore(accounts, data)?, OreInstruction::Initialize => process_initialize(accounts, data)?, - OreInstruction::InitializeSquares => process_initialize_squares(accounts, data)?, OreInstruction::Prospect => process_prospect(accounts, data)?, - OreInstruction::Redeem => panic!("not allowed"), OreInstruction::Reset => process_reset(accounts, data)?, // Admin @@ -50,6 +46,8 @@ pub fn process_instruction( // Seeker OreInstruction::ClaimSeeker => process_claim_seeker(accounts, data)?, + + _ => return Err(ProgramError::InvalidInstructionData), } Ok(()) diff --git a/program/src/prospect.rs b/program/src/prospect.rs index a210597..9102616 100644 --- a/program/src/prospect.rs +++ b/program/src/prospect.rs @@ -8,7 +8,7 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes // Parse data. let args = Prospect::try_from_bytes(data)?; let amount = u64::from_le_bytes(args.amount); - let square_id = u64::from_le_bytes(args.square_id); + let square_id = usize::from_le_bytes(args.square_id); // Load accounts. let clock = Clock::get()?; @@ -29,12 +29,10 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes .has_address(&config.fee_collector)? .is_writable()?; miner_info.is_writable()?; - let square = square_info - .as_account_mut::(&ore_api::ID)? - .assert_mut(|s| s.id == square_id)?; + let square = square_info.as_account_mut::(&ore_api::ID)?; system_program.is_program(&system_program::ID)?; - // Chekc whitelist + // Check whitelist if !AUTHORIZED_ACCOUNTS.contains(&signer_info.key) { return Err(ProgramError::InvalidAccountData); } @@ -65,6 +63,7 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes // Reset board. if board.slot_hash != [0; 32] { + // Reset board board.prospects = [0; 25]; board.id += 1; board.slot_hash = [0; 32]; @@ -74,6 +73,10 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes board.total_prospects = 0; board.total_vaulted = 0; board.total_winnings = 0; + + // Reset squares + square.count = [0; 25]; + square.miners = [[Pubkey::default(); 16]; 25]; } // Reset miner @@ -82,29 +85,22 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes miner.round_id = board.id; } - // Reset square - if square.round_id != board.id { - square.count = 0; - square.miners = [Pubkey::default(); 16]; - square.round_id = board.id; - } - // Normalize amount. let fee = amount / 100; let amount = amount - fee; // Update miner - let is_first_move = miner.prospects[square_id as usize] == 0; - miner.prospects[square_id as usize] += amount; + let is_first_move = miner.prospects[square_id] == 0; + miner.prospects[square_id] += amount; // Update square if is_first_move { - square.miners[square.count as usize] = *signer_info.key; - square.count += 1; + square.miners[square_id][square.count[square_id]] = *signer_info.key; + square.count[square_id] += 1; } // Update board - board.prospects[square_id as usize] += amount; + board.prospects[square_id] += amount; board.total_prospects += amount; // Transfer prospects. diff --git a/program/src/reset.rs b/program/src/reset.rs index a7b9fd1..4ad050f 100644 --- a/program/src/reset.rs +++ b/program/src/reset.rs @@ -7,7 +7,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul // Load accounts. let clock = Clock::get()?; let (required_accounts, miner_accounts) = accounts.split_at(8); - let [signer_info, board_info, mint_info, treasury_info, treasury_tokens_info, system_program, token_program, slot_hashes_sysvar] = + let [signer_info, board_info, mint_info, square_info, treasury_info, treasury_tokens_info, system_program, token_program, slot_hashes_sysvar] = required_accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -18,6 +18,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul .assert_mut(|b| b.slot_hash == [0; 32])? .assert_mut(|b| clock.slot >= b.end_slot)?; let mint = mint_info.has_address(&MINT_ADDRESS)?.as_mint()?; + let square = square_info.as_account_mut::(&ore_api::ID)?; let treasury = treasury_info.as_account_mut::(&ore_api::ID)?; treasury_tokens_info.as_associated_token_account(&treasury_info.key, &mint_info.key)?; system_program.is_program(&system_program::ID)?; @@ -29,7 +30,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul if let Ok(slot_hash) = get_slot_hash(board.end_slot, slot_hashes_sysvar) { board.slot_hash = slot_hash; let winning_square = get_winning_square(&slot_hash); - let square_prospects = board.prospects[winning_square as usize]; + let square_prospects = board.prospects[winning_square]; (winning_square, square_prospects) } else { // Cannot get slot hash. No one wins. @@ -68,13 +69,18 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul let miner = miner_info .as_account_mut::(&ore_api::ID)? .assert_mut(|m| m.round_id == board.id)?; - let miner_prospects = miner.prospects[winning_square as usize]; + let miner_prospects = miner.prospects[winning_square]; let rewards = miner_prospects + (winnings * miner_prospects / square_prospects); // Winners get their own prospect back plus their share of the winnings. checksum += miner_prospects; miner.rewards_sol += rewards; miner.lifetime_rewards_sol += rewards; rewards_sol[i] = rewards; + // Check if miner was provided in correct order. + if miner.authority != square.miners[winning_square][i] { + return Err(ProgramError::InvalidAccountData); + } + // Find the top winner. if miner_prospects > top_miner_prospects { top_miner_prospects = miner_prospects; @@ -134,7 +140,7 @@ pub fn get_slot_hash( Ok(slot_hash) } -fn get_winning_square(slot_hash: &[u8]) -> u64 { +fn get_winning_square(slot_hash: &[u8]) -> usize { // Use slot hash to generate a random u64 let r1 = u64::from_le_bytes(slot_hash[0..8].try_into().unwrap()); let r2 = u64::from_le_bytes(slot_hash[8..16].try_into().unwrap()); @@ -143,5 +149,5 @@ fn get_winning_square(slot_hash: &[u8]) -> u64 { let r = r1 ^ r2 ^ r3 ^ r4; // Returns a value in the range [0, 24] inclusive - r % 25 + (r % 25) as usize }