mirror of
https://github.com/d0zingcat/ore.git
synced 2026-06-10 07:36:48 +00:00
cleanup
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::rent::Rent;
|
||||
use solana_program::{log::sol_log, rent::Rent};
|
||||
use steel::*;
|
||||
|
||||
/// Checkpoints a miner's rewards.
|
||||
pub fn process_checkpoint(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, automation_info, board_info, miner_info, round_info, treasury_info, system_program] =
|
||||
accounts
|
||||
let [signer_info, board_info, miner_info, round_info, treasury_info, system_program] = accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
@@ -40,37 +39,25 @@ pub fn process_checkpoint(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Calculate bot fee permissions.
|
||||
// Get the RNG.
|
||||
let Some(r) = round.rng() else {
|
||||
// If the round has no RNG, no one wins.
|
||||
miner.checkpoint_id = miner.round_id;
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Calculate bot fee.
|
||||
let mut bot_fee = 0;
|
||||
if clock.slot >= round.expires_at - ONE_DAY_SLOTS {
|
||||
// The round expires in less than 24h.
|
||||
// Anyone is allowed to checkpoint this account and may collect the bot fee.
|
||||
// Anyone may checkpoint this account and collect the bot fee.
|
||||
bot_fee = miner.checkpoint_fee;
|
||||
miner.checkpoint_fee = 0;
|
||||
} else {
|
||||
// There is still time remaining before the round expires.
|
||||
// Bots may not yet checkpoint this account.
|
||||
automation_info.has_seeds(&[AUTOMATION, &miner.authority.to_bytes()], &ore_api::ID)?;
|
||||
if !automation_info.data_is_empty() {
|
||||
let automation = automation_info
|
||||
.as_account::<Automation>(&ore_api::ID)?
|
||||
.assert(|a| a.authority == miner.authority)?;
|
||||
assert!(
|
||||
*signer_info.key == miner.authority || *signer_info.key == automation.executor,
|
||||
"Only the miner or automation executor can checkpoint this account"
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
*signer_info.key == miner.authority,
|
||||
"Only the miner can checkpoint this account"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate miner rewards.
|
||||
let mut rewards_sol = 0;
|
||||
let mut rewards_ore = 0;
|
||||
let r = round.rng();
|
||||
let winning_square = round.winning_square(r) as usize;
|
||||
if miner.deployed[winning_square] > 0 {
|
||||
// Sanity check.
|
||||
@@ -101,6 +88,8 @@ pub fn process_checkpoint(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
}
|
||||
}
|
||||
|
||||
sol_log("I");
|
||||
|
||||
// Checkpoint miner.
|
||||
miner.checkpoint_id = round.id;
|
||||
miner.rewards_ore += rewards_ore;
|
||||
@@ -116,8 +105,9 @@ pub fn process_checkpoint(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
miner_info.send(bot_fee, &signer_info);
|
||||
}
|
||||
|
||||
// TODO Round debts. Track total checkpointed and/or num miner's checkpointed.
|
||||
|
||||
// Assert round has sufficient funds for rent + debts.
|
||||
// TODO Debts
|
||||
let account_size = 8 + std::mem::size_of::<Round>();
|
||||
let required_rent = Rent::get()?.minimum_balance(account_size);
|
||||
assert!(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::rent::Rent;
|
||||
use steel::*;
|
||||
|
||||
/// Closes a round accound, and returns the rent to the rent payer.
|
||||
pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, board_info, rent_payer_info, round_info, system_program] = accounts else {
|
||||
let [signer_info, board_info, rent_payer_info, round_info, treasury_info, system_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
@@ -16,8 +19,18 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
.assert_mut(|r| r.id < board.round_id)?
|
||||
.assert_mut(|r| r.expires_at < clock.slot)? // Ensure round has expired.
|
||||
.assert_mut(|r| r.rent_payer == *rent_payer_info.key)?; // Ensure the rent payer is the correct one.
|
||||
let treasury = treasury_info.as_account_mut::<Treasury>(&ore_api::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// Vault all unclaimed rewards.
|
||||
let size = 8 + std::mem::size_of::<Round>();
|
||||
let min_rent = Rent::get()?.minimum_balance(size);
|
||||
let unclaimed_sol = round_info.lamports() - min_rent;
|
||||
if unclaimed_sol > 0 {
|
||||
round_info.send(unclaimed_sol, treasury_info);
|
||||
treasury.balance += unclaimed_sol;
|
||||
}
|
||||
|
||||
// Close the account.
|
||||
round_info.close(rent_payer_info)?;
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ use ore_api::prelude::*;
|
||||
use solana_program::{keccak::hashv, log::sol_log, native_token::lamports_to_sol};
|
||||
use steel::*;
|
||||
|
||||
use crate::AUTHORIZED_ACCOUNTS;
|
||||
|
||||
/// Deploys capital to prospect on a square.
|
||||
pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
@@ -18,16 +20,25 @@ pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResul
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
authority_info.is_writable()?;
|
||||
automation_info.is_writable()?;
|
||||
automation_info
|
||||
.is_writable()?
|
||||
.has_seeds(&[AUTOMATION, &authority_info.key.to_bytes()], &ore_api::ID)?;
|
||||
let board = board_info
|
||||
.as_account_mut::<Board>(&ore_api::ID)?
|
||||
.assert_mut(|b| clock.slot >= b.start_slot && clock.slot < b.end_slot)?;
|
||||
let round = round_info
|
||||
.as_account_mut::<Round>(&ore_api::ID)?
|
||||
.assert_mut(|r| r.id == board.round_id)?;
|
||||
miner_info.is_writable()?;
|
||||
miner_info
|
||||
.is_writable()?
|
||||
.has_seeds(&[MINER, &authority_info.key.to_bytes()], &ore_api::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// Check whitelist
|
||||
if !AUTHORIZED_ACCOUNTS.contains(&signer_info.key) {
|
||||
return Err(trace("Not authorized", OreError::NotAuthorized.into()));
|
||||
}
|
||||
|
||||
// Check if signer is the automation executor.
|
||||
let automation = if !automation_info.data_is_empty() {
|
||||
let automation = automation_info
|
||||
@@ -68,17 +79,6 @@ pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResul
|
||||
}
|
||||
}
|
||||
|
||||
// Log
|
||||
sol_log(
|
||||
&format!(
|
||||
"Round {}. Deploying {} SOL to {} squares",
|
||||
round.id,
|
||||
lamports_to_sol(amount),
|
||||
squares.iter().filter(|&&s| s).count(),
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
// Open miner account.
|
||||
let miner = if miner_info.data_is_empty() {
|
||||
create_program_account::<Miner>(
|
||||
@@ -127,6 +127,7 @@ pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResul
|
||||
|
||||
// Calculate all deployments.
|
||||
let mut total_amount = 0;
|
||||
let mut total_squares = 0;
|
||||
for (square_id, &should_deploy) in squares.iter().enumerate() {
|
||||
// Skip if square index is out of bounds.
|
||||
if square_id > 24 {
|
||||
@@ -154,8 +155,9 @@ pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResul
|
||||
round.total_deployed += amount;
|
||||
round.count[square_id] += 1;
|
||||
|
||||
// Update total amount
|
||||
// Update totals.
|
||||
total_amount += amount;
|
||||
total_squares += 1;
|
||||
|
||||
// Exit early if automation does not have enough balance for another square.
|
||||
if let Some(automation) = &automation {
|
||||
@@ -185,6 +187,17 @@ pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResul
|
||||
round_info.collect(total_amount, &signer_info)?;
|
||||
}
|
||||
|
||||
// Log
|
||||
sol_log(
|
||||
&format!(
|
||||
"Round #{}: deploying {} SOL to {} squares",
|
||||
round.id,
|
||||
lamports_to_sol(amount),
|
||||
total_squares,
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,6 @@ mod claim_yield;
|
||||
mod close;
|
||||
mod deploy;
|
||||
mod deposit;
|
||||
mod migrate_board;
|
||||
mod migrate_miner;
|
||||
// mod initialize;
|
||||
mod log;
|
||||
mod reset;
|
||||
mod set_admin;
|
||||
@@ -31,9 +28,6 @@ use claim_yield::*;
|
||||
use close::*;
|
||||
use deploy::*;
|
||||
use deposit::*;
|
||||
use migrate_board::*;
|
||||
use migrate_miner::*;
|
||||
// use initialize::*;
|
||||
use log::*;
|
||||
use reset::*;
|
||||
use set_admin::*;
|
||||
@@ -62,7 +56,6 @@ pub fn process_instruction(
|
||||
OreInstruction::Deploy => process_deploy(accounts, data)?,
|
||||
OreInstruction::Log => process_log(accounts, data)?,
|
||||
OreInstruction::Close => process_close(accounts, data)?,
|
||||
// OreInstruction::Initialize => process_initialize(accounts, data)?,
|
||||
OreInstruction::Reset => process_reset(accounts, data)?,
|
||||
|
||||
// Staker
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::slot_hashes::SlotHashes;
|
||||
use steel::*;
|
||||
|
||||
/// Pays out the winners and block reward.
|
||||
pub fn process_migrate_board(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, board_info, system_program] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let board = board_info.as_account_mut::<Board>(&ore_api::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// TODO Migrate miner account.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::slot_hashes::SlotHashes;
|
||||
use steel::*;
|
||||
|
||||
/// Pays out the winners and block reward.
|
||||
pub fn process_migrate_miner(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, miner_info, system_program] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let miner = miner_info.as_account_mut::<Miner>(&ore_api::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// TODO Migrate miner account.
|
||||
// TODO Move refund_sol into rewards_sol.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -34,15 +34,43 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
ore_program.is_program(&ore_api::ID)?;
|
||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||
|
||||
// Open next round account.
|
||||
create_program_account::<Round>(
|
||||
round_next_info,
|
||||
ore_program,
|
||||
signer_info,
|
||||
&ore_api::ID,
|
||||
&[ROUND, &(board.round_id + 1).to_le_bytes()],
|
||||
)?;
|
||||
let round_next = round_next_info.as_account_mut::<Round>(&ore_api::ID)?;
|
||||
round_next.id = board.round_id + 1;
|
||||
round_next.deployed = [0; 25];
|
||||
round_next.slot_hash = [0; 32];
|
||||
round_next.count = [0; 25];
|
||||
round_next.expires_at = clock.slot + 150 + ONE_WEEK_SLOTS;
|
||||
round_next.rent_payer = *signer_info.key;
|
||||
round_next.motherlode = 0;
|
||||
round_next.top_miner = Pubkey::default();
|
||||
round_next.top_miner_reward = 0;
|
||||
round_next.total_deployed = 0;
|
||||
round_next.total_vaulted = 0;
|
||||
round_next.total_winnings = 0;
|
||||
|
||||
// Sample slot hash.
|
||||
let mut r = 0;
|
||||
let (winning_square, square_deployed) =
|
||||
if let Ok(slot_hash) = get_slot_hash(board.end_slot, slot_hashes_sysvar) {
|
||||
round.slot_hash = slot_hash;
|
||||
r = round.rng();
|
||||
let winning_square = round.winning_square(r);
|
||||
let square_deployed = round.deployed[winning_square];
|
||||
(winning_square, square_deployed)
|
||||
if let Some(rng) = round.rng() {
|
||||
r = rng;
|
||||
let winning_square = round.winning_square(r);
|
||||
let square_deployed = round.deployed[winning_square];
|
||||
(winning_square, square_deployed)
|
||||
} else {
|
||||
// Cannot get slot hash. No one wins.
|
||||
round.slot_hash = [u8::MAX; 32];
|
||||
(u64::MAX as usize, 0)
|
||||
}
|
||||
} else {
|
||||
// Cannot get slot hash. No one wins.
|
||||
round.slot_hash = [u8::MAX; 32];
|
||||
@@ -54,8 +82,8 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
|
||||
// No one won. Vault all deployed.
|
||||
if square_deployed == 0 {
|
||||
// Update board.
|
||||
round.total_vaulted = round.total_deployed;
|
||||
// Vault all deployed.
|
||||
round.total_vaulted = round.total_deployed - total_admin_fee;
|
||||
treasury.balance += round.total_deployed - total_admin_fee;
|
||||
|
||||
// Emit event.
|
||||
@@ -78,9 +106,14 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
.to_bytes(),
|
||||
)?;
|
||||
|
||||
// Update board
|
||||
board.round_id += 1;
|
||||
board.start_slot = clock.slot + 1;
|
||||
board.end_slot = board.start_slot + 150;
|
||||
|
||||
// Do SOL transfers.
|
||||
board_info.send(total_admin_fee, &fee_collector_info);
|
||||
board_info.send(round.total_deployed - total_admin_fee, &treasury_info);
|
||||
round_info.send(total_admin_fee, &fee_collector_info);
|
||||
round_info.send(round.total_deployed - total_admin_fee, &treasury_info);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -153,15 +186,16 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
}
|
||||
|
||||
// Validate top miner.
|
||||
// TODO Safety checks here.
|
||||
let top_miner_sample = round.top_miner_sample(r, winning_square);
|
||||
let top_miner = top_miner_info
|
||||
.as_account::<Miner>(&ore_api::ID)?
|
||||
.assert(|m| m.round_id == round.id)?
|
||||
.assert(|m| {
|
||||
m.cumulative[winning_square] >= top_miner_sample
|
||||
&& top_miner_sample < m.cumulative[winning_square] + m.deployed[winning_square]
|
||||
})?;
|
||||
// TODO Safety checks here (if no one won).
|
||||
// let mut top_miner_address = Pubkey::default();
|
||||
// let top_miner_sample = round.top_miner_sample(r, winning_square);
|
||||
// let top_miner = top_miner_info
|
||||
// .as_account::<Miner>(&ore_api::ID)?
|
||||
// .assert(|m| m.round_id == round.id)?
|
||||
// .assert(|m| {
|
||||
// m.cumulative[winning_square] >= top_miner_sample
|
||||
// && top_miner_sample < m.cumulative[winning_square] + m.deployed[winning_square]
|
||||
// })?;
|
||||
|
||||
// Emit event.
|
||||
program_log(
|
||||
@@ -172,7 +206,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
start_slot: board.start_slot,
|
||||
end_slot: board.end_slot,
|
||||
winning_square: winning_square as u64,
|
||||
top_miner: top_miner.authority,
|
||||
top_miner: Pubkey::default(), // top_miner.authority,
|
||||
num_winners: round.count[winning_square],
|
||||
total_deployed: round.total_deployed,
|
||||
total_vaulted: round.total_vaulted,
|
||||
@@ -188,28 +222,6 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
board.start_slot = clock.slot + 1;
|
||||
board.end_slot = board.start_slot + 150;
|
||||
|
||||
// Open next round account.
|
||||
create_program_account::<Round>(
|
||||
round_next_info,
|
||||
ore_program,
|
||||
signer_info,
|
||||
&ore_api::ID,
|
||||
&[ROUND, &board.round_id.to_le_bytes()],
|
||||
)?;
|
||||
let round_next = round_next_info.as_account_mut::<Round>(&ore_api::ID)?;
|
||||
round_next.id = board.round_id;
|
||||
round_next.deployed = [0; 25];
|
||||
round_next.slot_hash = [0; 32];
|
||||
round_next.count = [0; 25];
|
||||
round_next.expires_at = board.end_slot + ONE_WEEK_SLOTS;
|
||||
round_next.rent_payer = *signer_info.key;
|
||||
round_next.motherlode = 0;
|
||||
round_next.top_miner = Pubkey::default();
|
||||
round_next.top_miner_reward = round.top_miner_reward;
|
||||
round_next.total_deployed = 0;
|
||||
round_next.total_vaulted = 0;
|
||||
round_next.total_winnings = 0;
|
||||
|
||||
// Do SOL transfers.
|
||||
round_info.send(total_admin_fee, &fee_collector_info);
|
||||
round_info.send(vault_amount, &treasury_info);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use solana_program::pubkey;
|
||||
use steel::*;
|
||||
|
||||
pub const AUTHORIZED_ACCOUNTS: [Pubkey; 4] = [
|
||||
pub const AUTHORIZED_ACCOUNTS: [Pubkey; 1] = [
|
||||
pubkey!("pqspJ298ryBjazPAr95J9sULCVpZe3HbZTWkbC1zrkS"),
|
||||
pubkey!("By5JFFueXCqeqLk5MzR8ZSwFxASz3SKWX2TVfT1LTFbX"),
|
||||
pubkey!("5Nb2ibzu4bWrwis2vNVD4mJprt6KTchzW6wgbVWM2PkY"),
|
||||
pubkey!("6tUUXB6LuTE1Pzpe6sP4mZL9CNA5XQYGWYbn1oqPpKeH"),
|
||||
// pubkey!("By5JFFueXCqeqLk5MzR8ZSwFxASz3SKWX2TVfT1LTFbX"),
|
||||
// pubkey!("5Nb2ibzu4bWrwis2vNVD4mJprt6KTchzW6wgbVWM2PkY"),
|
||||
// pubkey!("6tUUXB6LuTE1Pzpe6sP4mZL9CNA5XQYGWYbn1oqPpKeH"),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user