This commit is contained in:
Hardhat Chad
2025-09-18 14:42:18 -07:00
parent 04940529f8
commit fbcdae6296
9 changed files with 63 additions and 132 deletions

View File

@@ -8,7 +8,6 @@ pub enum OreInstruction {
ClaimSOL = 1, ClaimSOL = 1,
ClaimORE = 2, ClaimORE = 2,
Initialize = 3, Initialize = 3,
InitializeSquares = 4,
Prospect = 5, Prospect = 5,
Redeem = 6, Redeem = 6,
Reset = 7, Reset = 7,
@@ -116,6 +115,10 @@ pub struct SetSniperFeeDuration {
#[derive(Clone, Copy, Debug, Pod, Zeroable)] #[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct ClaimSeeker {} pub struct ClaimSeeker {}
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct MigrateSquares {}
instruction!(OreInstruction, Boost); instruction!(OreInstruction, Boost);
instruction!(OreInstruction, ClaimSOL); instruction!(OreInstruction, ClaimSOL);
instruction!(OreInstruction, ClaimORE); instruction!(OreInstruction, ClaimORE);
@@ -123,7 +126,6 @@ instruction!(OreInstruction, Redeem);
instruction!(OreInstruction, Reset); instruction!(OreInstruction, Reset);
instruction!(OreInstruction, Prospect); instruction!(OreInstruction, Prospect);
instruction!(OreInstruction, Initialize); instruction!(OreInstruction, Initialize);
instruction!(OreInstruction, InitializeSquares);
instruction!(OreInstruction, SetAdmin); instruction!(OreInstruction, SetAdmin);
instruction!(OreInstruction, SetFeeCollector); instruction!(OreInstruction, SetFeeCollector);
instruction!(OreInstruction, ClaimSeeker); instruction!(OreInstruction, ClaimSeeker);

View File

@@ -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 { pub fn claim_sol(signer: Pubkey, amount: u64) -> Instruction {
let miner_address = miner_pda(signer).0; let miner_address = miner_pda(signer).0;
Instruction { 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 board_address = board_pda().0;
let config_address = config_pda().0; let config_address = config_pda().0;
let miner_address = miner_pda(signer).0; let miner_address = miner_pda(signer).0;
let square_address = square_pda(square_id).0; let square_address = square_pda(0).0;
Instruction { Instruction {
program_id: crate::ID, program_id: crate::ID,
accounts: vec![ accounts: vec![

View File

@@ -26,6 +26,12 @@ pub enum OreAccount {
Square = 106, Square = 106,
} }
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
pub enum OreAccountOLD {
SquareOLD = 106,
}
pub fn board_pda() -> (Pubkey, u8) { pub fn board_pda() -> (Pubkey, u8) {
Pubkey::find_program_address(&[BOARD], &crate::ID) Pubkey::find_program_address(&[BOARD], &crate::ID)
} }

View File

@@ -1,12 +1,22 @@
use steel::*; use steel::*;
use crate::state::square_pda; use crate::state::{square_pda, OreAccountOLD};
use super::OreAccount; use super::OreAccount;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct Square { 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. /// The count of miners on this square.
pub count: u64, pub count: u64,
@@ -20,10 +30,11 @@ pub struct Square {
pub miners: [Pubkey; 16], pub miners: [Pubkey; 16],
} }
impl Square { // impl Square {
pub fn pda(&self) -> (Pubkey, u8) { // pub fn pda() -> (Pubkey, u8) {
square_pda(self.id) // square_pda()
} // }
} // }
account!(OreAccount, Square); account!(OreAccount, Square);
account!(OreAccountOLD, SquareOLD);

View File

@@ -51,9 +51,6 @@ async fn main() {
"initialize" => { "initialize" => {
initialize(&rpc, &payer).await.unwrap(); initialize(&rpc, &payer).await.unwrap();
} }
"initialize_squares" => {
initialize_squares(&rpc, &payer).await.unwrap();
}
"redeem" => { "redeem" => {
redeem(&rpc, &payer).await.unwrap(); redeem(&rpc, &payer).await.unwrap();
} }
@@ -124,15 +121,6 @@ async fn initialize(
Ok(()) 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( async fn claim_sol(
rpc: &RpcClient, rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair, payer: &solana_sdk::signer::keypair::Keypair,
@@ -171,10 +159,10 @@ async fn reset(
let mut miners = vec![]; let mut miners = vec![];
if let Some(slot_hash) = slot_hashes.get(&board.end_slot) { if let Some(slot_hash) = slot_hashes.get(&board.end_slot) {
let id = get_winning_square(&slot_hash.to_bytes()); 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!("Winning square: {}", id);
println!("Miners: {:?}", square.miners); 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); let reset_ix = ore_api::sdk::reset(payer.pubkey(), miners);
submit_transaction(rpc, payer, &[reset_ix]).await?; 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> { async fn log_square(rpc: &RpcClient) -> Result<(), anyhow::Error> {
let id = std::env::var("ID").expect("Missing ID env var"); let id = std::env::var("ID").expect("Missing ID env var");
let id = u64::from_str(&id).expect("Invalid ID"); let id = usize::from_str(&id).expect("Invalid ID");
let square = get_square(rpc, id).await?; let square = get_square(rpc).await?;
println!("Square"); println!("Square");
println!(" id: {}", square.id); println!(" count: {:?}", square.count[id]);
println!(" count: {}", square.count); println!(" miners: {:?}", square.miners[id]);
println!(" round_id: {}", square.round_id);
println!(" miners: {:?}", square.miners);
Ok(()) Ok(())
} }
@@ -320,6 +306,7 @@ fn print_board(board: Board, clock: &Clock) {
println!(" Start slot: {}", board.start_slot); println!(" Start slot: {}", board.start_slot);
println!(" End slot: {}", board.end_slot); println!(" End slot: {}", board.end_slot);
println!(" Prospects: {:?}", board.prospects); println!(" Prospects: {:?}", board.prospects);
println!(" Top miner: {:?}", board.top_miner);
println!(" Total prospects: {}", board.total_prospects); println!(" Total prospects: {}", board.total_prospects);
println!(" Total vaulted: {}", board.total_vaulted); println!(" Total vaulted: {}", board.total_vaulted);
println!(" Total winnings: {}", board.total_winnings); println!(" Total winnings: {}", board.total_winnings);
@@ -347,8 +334,8 @@ async fn get_slot_hashes(rpc: &RpcClient) -> Result<SlotHashes, anyhow::Error> {
Ok(slot_hashes) Ok(slot_hashes)
} }
async fn get_square(rpc: &RpcClient, id: u64) -> Result<Square, anyhow::Error> { async fn get_square(rpc: &RpcClient) -> Result<Square, anyhow::Error> {
let square_pda = ore_api::state::square_pda(id); let square_pda = ore_api::state::square_pda(0);
let account = rpc.get_account(&square_pda.0).await?; let account = rpc.get_account(&square_pda.0).await?;
let square = Square::try_from_bytes(&account.data)?; let square = Square::try_from_bytes(&account.data)?;
Ok(*square) Ok(*square)

View File

@@ -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>(
square_info,
system_program,
signer_info,
&ore_api::ID,
&[SQUARE, &(i as u64).to_le_bytes()],
)?;
let square = square_info.as_account_mut::<Square>(&ore_api::ID)?;
square.id = i as u64;
square.round_id = 0;
square.miners = [Pubkey::default(); 16];
} else {
square_info
.as_account_mut::<Square>(&ore_api::ID)?
.assert_mut(|s| s.id == i as u64)?;
}
}
Ok(())
}

View File

@@ -3,7 +3,6 @@ mod claim_ore;
mod claim_seeker; mod claim_seeker;
mod claim_sol; mod claim_sol;
mod initialize; mod initialize;
mod initialize_squares;
mod prospect; mod prospect;
mod redeem; mod redeem;
mod reset; mod reset;
@@ -16,7 +15,6 @@ use claim_ore::*;
use claim_seeker::*; use claim_seeker::*;
use claim_sol::*; use claim_sol::*;
use initialize::*; use initialize::*;
use initialize_squares::*;
use prospect::*; use prospect::*;
use redeem::*; use redeem::*;
use reset::*; use reset::*;
@@ -39,9 +37,7 @@ pub fn process_instruction(
OreInstruction::ClaimSOL => process_claim_sol(accounts, data)?, OreInstruction::ClaimSOL => process_claim_sol(accounts, data)?,
OreInstruction::ClaimORE => process_claim_ore(accounts, data)?, OreInstruction::ClaimORE => process_claim_ore(accounts, data)?,
OreInstruction::Initialize => process_initialize(accounts, data)?, OreInstruction::Initialize => process_initialize(accounts, data)?,
OreInstruction::InitializeSquares => process_initialize_squares(accounts, data)?,
OreInstruction::Prospect => process_prospect(accounts, data)?, OreInstruction::Prospect => process_prospect(accounts, data)?,
OreInstruction::Redeem => panic!("not allowed"),
OreInstruction::Reset => process_reset(accounts, data)?, OreInstruction::Reset => process_reset(accounts, data)?,
// Admin // Admin
@@ -50,6 +46,8 @@ pub fn process_instruction(
// Seeker // Seeker
OreInstruction::ClaimSeeker => process_claim_seeker(accounts, data)?, OreInstruction::ClaimSeeker => process_claim_seeker(accounts, data)?,
_ => return Err(ProgramError::InvalidInstructionData),
} }
Ok(()) Ok(())

View File

@@ -8,7 +8,7 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes
// Parse data. // Parse data.
let args = Prospect::try_from_bytes(data)?; let args = Prospect::try_from_bytes(data)?;
let amount = u64::from_le_bytes(args.amount); 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. // Load accounts.
let clock = Clock::get()?; let clock = Clock::get()?;
@@ -29,12 +29,10 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes
.has_address(&config.fee_collector)? .has_address(&config.fee_collector)?
.is_writable()?; .is_writable()?;
miner_info.is_writable()?; miner_info.is_writable()?;
let square = square_info let square = square_info.as_account_mut::<Square>(&ore_api::ID)?;
.as_account_mut::<Square>(&ore_api::ID)?
.assert_mut(|s| s.id == square_id)?;
system_program.is_program(&system_program::ID)?; system_program.is_program(&system_program::ID)?;
// Chekc whitelist // Check whitelist
if !AUTHORIZED_ACCOUNTS.contains(&signer_info.key) { if !AUTHORIZED_ACCOUNTS.contains(&signer_info.key) {
return Err(ProgramError::InvalidAccountData); return Err(ProgramError::InvalidAccountData);
} }
@@ -65,6 +63,7 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes
// Reset board. // Reset board.
if board.slot_hash != [0; 32] { if board.slot_hash != [0; 32] {
// Reset board
board.prospects = [0; 25]; board.prospects = [0; 25];
board.id += 1; board.id += 1;
board.slot_hash = [0; 32]; board.slot_hash = [0; 32];
@@ -74,6 +73,10 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes
board.total_prospects = 0; board.total_prospects = 0;
board.total_vaulted = 0; board.total_vaulted = 0;
board.total_winnings = 0; board.total_winnings = 0;
// Reset squares
square.count = [0; 25];
square.miners = [[Pubkey::default(); 16]; 25];
} }
// Reset miner // Reset miner
@@ -82,29 +85,22 @@ pub fn process_prospect(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRes
miner.round_id = board.id; 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. // Normalize amount.
let fee = amount / 100; let fee = amount / 100;
let amount = amount - fee; let amount = amount - fee;
// Update miner // Update miner
let is_first_move = miner.prospects[square_id as usize] == 0; let is_first_move = miner.prospects[square_id] == 0;
miner.prospects[square_id as usize] += amount; miner.prospects[square_id] += amount;
// Update square // Update square
if is_first_move { if is_first_move {
square.miners[square.count as usize] = *signer_info.key; square.miners[square_id][square.count[square_id]] = *signer_info.key;
square.count += 1; square.count[square_id] += 1;
} }
// Update board // Update board
board.prospects[square_id as usize] += amount; board.prospects[square_id] += amount;
board.total_prospects += amount; board.total_prospects += amount;
// Transfer prospects. // Transfer prospects.

View File

@@ -7,7 +7,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
// Load accounts. // Load accounts.
let clock = Clock::get()?; let clock = Clock::get()?;
let (required_accounts, miner_accounts) = accounts.split_at(8); 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 required_accounts
else { else {
return Err(ProgramError::NotEnoughAccountKeys); 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| b.slot_hash == [0; 32])?
.assert_mut(|b| clock.slot >= b.end_slot)?; .assert_mut(|b| clock.slot >= b.end_slot)?;
let mint = mint_info.has_address(&MINT_ADDRESS)?.as_mint()?; let mint = mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
let square = square_info.as_account_mut::<Square>(&ore_api::ID)?;
let treasury = treasury_info.as_account_mut::<Treasury>(&ore_api::ID)?; let treasury = treasury_info.as_account_mut::<Treasury>(&ore_api::ID)?;
treasury_tokens_info.as_associated_token_account(&treasury_info.key, &mint_info.key)?; treasury_tokens_info.as_associated_token_account(&treasury_info.key, &mint_info.key)?;
system_program.is_program(&system_program::ID)?; 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) { if let Ok(slot_hash) = get_slot_hash(board.end_slot, slot_hashes_sysvar) {
board.slot_hash = slot_hash; board.slot_hash = slot_hash;
let winning_square = get_winning_square(&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) (winning_square, square_prospects)
} else { } else {
// Cannot get slot hash. No one wins. // Cannot get slot hash. No one wins.
@@ -68,13 +69,18 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
let miner = miner_info let miner = miner_info
.as_account_mut::<Miner>(&ore_api::ID)? .as_account_mut::<Miner>(&ore_api::ID)?
.assert_mut(|m| m.round_id == board.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. let rewards = miner_prospects + (winnings * miner_prospects / square_prospects); // Winners get their own prospect back plus their share of the winnings.
checksum += miner_prospects; checksum += miner_prospects;
miner.rewards_sol += rewards; miner.rewards_sol += rewards;
miner.lifetime_rewards_sol += rewards; miner.lifetime_rewards_sol += rewards;
rewards_sol[i] = 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. // Find the top winner.
if miner_prospects > top_miner_prospects { if miner_prospects > top_miner_prospects {
top_miner_prospects = miner_prospects; top_miner_prospects = miner_prospects;
@@ -134,7 +140,7 @@ pub fn get_slot_hash(
Ok(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 // Use slot hash to generate a random u64
let r1 = u64::from_le_bytes(slot_hash[0..8].try_into().unwrap()); 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()); 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; let r = r1 ^ r2 ^ r3 ^ r4;
// Returns a value in the range [0, 24] inclusive // Returns a value in the range [0, 24] inclusive
r % 25 (r % 25) as usize
} }