diff --git a/api/src/instruction.rs b/api/src/instruction.rs index 3582371..399b02b 100644 --- a/api/src/instruction.rs +++ b/api/src/instruction.rs @@ -18,9 +18,11 @@ pub enum OreInstruction { Wrap = 10, SetAdmin = 11, SetFeeCollector = 12, + MigrateMiner = 13, + MigrateSquares = 14, // Seeker - ClaimSeeker = 14, + ClaimSeeker = 15, } #[repr(C)] @@ -121,6 +123,14 @@ pub struct Bury { #[derive(Clone, Copy, Debug, Pod, Zeroable)] pub struct ClaimSeeker {} +#[repr(C)] +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +pub struct MigrateMiner {} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Pod, Zeroable)] +pub struct MigrateSquares {} + instruction!(OreInstruction, Automate); instruction!(OreInstruction, Boost); instruction!(OreInstruction, ClaimSOL); @@ -134,3 +144,5 @@ instruction!(OreInstruction, Reset); instruction!(OreInstruction, SetAdmin); instruction!(OreInstruction, SetFeeCollector); instruction!(OreInstruction, ClaimSeeker); +instruction!(OreInstruction, MigrateMiner); +instruction!(OreInstruction, MigrateSquares); diff --git a/api/src/state/miner.rs b/api/src/state/miner.rs index c1a0a0a..534f6b9 100644 --- a/api/src/state/miner.rs +++ b/api/src/state/miner.rs @@ -1,6 +1,6 @@ use steel::*; -use crate::state::miner_pda; +use crate::state::{miner_pda, OreAccountOLD}; use super::OreAccount; @@ -36,6 +36,35 @@ pub struct Miner { pub lifetime_rewards_ore: u64, } +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +pub struct MinerOLD { + /// The authority of this miner account. + pub authority: Pubkey, + + /// The miner's prospects in the current round. + pub deployed: [u64; 25], + + /// The executor with permmission to deploy capital with this account. + #[deprecated(note = "Use automation executor instead")] + pub executor: Pubkey, + + /// The amount of SOL this miner can claim. + pub rewards_sol: u64, + + /// The amount of ORE this miner can claim. + pub rewards_ore: u64, + + /// The ID of the round this miner last played in. + pub round_id: u64, + + /// The total amount of SOL this miner has mined across all blocks. + pub lifetime_rewards_sol: u64, + + /// The total amount of ORE this miner has mined across all blocks. + pub lifetime_rewards_ore: u64, +} + impl Miner { pub fn pda(&self) -> (Pubkey, u8) { miner_pda(self.authority) @@ -43,3 +72,4 @@ impl Miner { } account!(OreAccount, Miner); +account!(OreAccountOLD, MinerOLD); diff --git a/api/src/state/mod.rs b/api/src/state/mod.rs index 63cc36b..1fb961a 100644 --- a/api/src/state/mod.rs +++ b/api/src/state/mod.rs @@ -29,6 +29,14 @@ pub enum OreAccount { Square = 106, } +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +pub enum OreAccountOLD { + MinerOLD = 103, + TreasuryOLD = 104, + SquareOLD = 106, +} + pub fn automation_pda(authority: Pubkey) -> (Pubkey, u8) { Pubkey::find_program_address(&[AUTOMATION, &authority.to_bytes()], &crate::ID) } diff --git a/api/src/state/square.rs b/api/src/state/square.rs index 79bd81a..7f8a7d4 100644 --- a/api/src/state/square.rs +++ b/api/src/state/square.rs @@ -1,6 +1,6 @@ use steel::*; -use crate::state::square_pda; +use crate::state::{square_pda, OreAccountOLD}; use super::OreAccount; @@ -17,6 +17,19 @@ pub struct 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; 25], + + /// The deployments of all players. + pub deployed: [[u64; 16]; 25], + + /// The miners in each square. + pub miners: [[Pubkey; 16]; 25], +} + impl Square { pub fn pda() -> (Pubkey, u8) { square_pda() @@ -24,3 +37,4 @@ impl Square { } account!(OreAccount, Square); +account!(OreAccountOLD, SquareOLD); diff --git a/api/src/state/treasury.rs b/api/src/state/treasury.rs index 4989d26..58cb1cc 100644 --- a/api/src/state/treasury.rs +++ b/api/src/state/treasury.rs @@ -1,5 +1,7 @@ use steel::*; +use crate::state::OreAccountOLD; + use super::OreAccount; /// Treasury is a singleton account which is the mint authority for the ORE token and the authority of @@ -9,6 +11,17 @@ use super::OreAccount; pub struct Treasury { // The amount of SOL collected for buy-bury operations. pub balance: u64, + + /// The amount of ORE in the motherlode. + pub motherlode: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +pub struct TreasuryOLD { + // The amount of SOL collected for buy-bury operations. + pub balance: u64, } account!(OreAccount, Treasury); +account!(OreAccountOLD, TreasuryOLD); diff --git a/program/src/claim_sol.rs b/program/src/claim_sol.rs index d8cced4..8345348 100644 --- a/program/src/claim_sol.rs +++ b/program/src/claim_sol.rs @@ -19,12 +19,16 @@ pub fn process_claim_sol(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramRe system_program.is_program(&system_program::ID)?; // Normalize amount. - let amount = miner.rewards_sol.min(amount); + let total_claimable = miner.rewards_sol + miner.refund_sol; + let amount = total_claimable.min(amount); sol_log(&format!("Claiming {} SOL", lamports_to_sol(amount)).as_str()); - // Update miner. - miner.rewards_sol -= amount; + // Update miner. Deduct from refund first, then from rewards. + let from_refund = amount.min(miner.refund_sol); + miner.refund_sol -= from_refund; + let from_rewards = amount - from_refund; + miner.rewards_sol -= from_rewards; // Transfer reward to recipient. miner_info.send(amount, signer_info); diff --git a/program/src/lib.rs b/program/src/lib.rs index cc5e641..6fab9ad 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -7,6 +7,8 @@ mod claim_sol; mod deploy; mod initialize; mod log; +mod migrate_miner; +mod migrate_squares; mod reset; mod set_admin; mod set_fee_collector; @@ -22,6 +24,8 @@ use claim_sol::*; use deploy::*; use initialize::*; use log::*; +use migrate_miner::*; +use migrate_squares::*; use reset::*; use set_admin::*; use set_fee_collector::*; @@ -53,6 +57,8 @@ pub fn process_instruction( OreInstruction::Wrap => process_wrap(accounts, data)?, OreInstruction::SetAdmin => process_set_admin(accounts, data)?, OreInstruction::SetFeeCollector => process_set_fee_collector(accounts, data)?, + OreInstruction::MigrateMiner => process_migrate_miner(accounts, data)?, + OreInstruction::MigrateSquares => process_migrate_squares(accounts, data)?, // Seeker OreInstruction::ClaimSeeker => process_claim_seeker(accounts, data)?, diff --git a/program/src/migrate_miner.rs b/program/src/migrate_miner.rs new file mode 100644 index 0000000..c942ecf --- /dev/null +++ b/program/src/migrate_miner.rs @@ -0,0 +1,55 @@ +use ore_api::prelude::*; +use solana_program::rent::Rent; +use steel::*; + +/// Sets the admin. +pub fn process_migrate_miner(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { + // Load accounts. + let [signer_info, config_info, miner_info, system_program] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + signer_info.is_signer()?; + let miner_old = miner_info + .as_account_mut::(&ore_api::ID)? + .assert_mut(|m| m.authority == *signer_info.key)?; + config_info + .as_account_mut::(&ore_api::ID)? + .assert_mut_err( + |c| c.admin == *signer_info.key, + OreError::NotAuthorized.into(), + )?; + system_program.is_program(&system_program::ID)?; + + // Record old values. + let authority = miner_old.authority; + let deployed = miner_old.deployed; + let executor = miner_old.executor; + let rewards_sol = miner_old.rewards_sol; + let rewards_ore = miner_old.rewards_ore; + let round_id = miner_old.round_id; + let lifetime_rewards_sol = miner_old.lifetime_rewards_sol; + let lifetime_rewards_ore = miner_old.lifetime_rewards_ore; + + // Realloc miner + let new_size = 8 + std::mem::size_of::(); + let old_size = 8 + std::mem::size_of::(); + let new_rent = Rent::get()?.minimum_balance(new_size); + let old_rent = Rent::get()?.minimum_balance(old_size); + let additional_rent = new_rent - old_rent; + miner_info.realloc(new_size, false)?; + miner_info.collect(additional_rent, &signer_info)?; + + // Update miner. + let miner = miner_info.as_account_mut::(&ore_api::ID)?; + miner.authority = authority; + miner.deployed = deployed; + miner.executor = executor; + miner.refund_sol = 0; + miner.rewards_sol = rewards_sol; + miner.rewards_ore = rewards_ore; + miner.round_id = round_id; + miner.lifetime_rewards_sol = lifetime_rewards_sol; + miner.lifetime_rewards_ore = lifetime_rewards_ore; + + Ok(()) +} diff --git a/program/src/migrate_squares.rs b/program/src/migrate_squares.rs new file mode 100644 index 0000000..da75fe7 --- /dev/null +++ b/program/src/migrate_squares.rs @@ -0,0 +1,59 @@ +use ore_api::prelude::*; +use solana_program::rent::Rent; +use steel::*; + +/// Sets the admin. +pub fn process_migrate_squares(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { + // Load accounts. + let [signer_info, config_info, squares_info, treasury_info, system_program] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + signer_info.is_signer()?; + let squares_old = squares_info.as_account_mut::(&ore_api::ID)?; + let treasury_old = treasury_info.as_account_mut::(&ore_api::ID)?; + config_info + .as_account_mut::(&ore_api::ID)? + .assert_mut_err( + |c| c.admin == *signer_info.key, + OreError::NotAuthorized.into(), + )?; + system_program.is_program(&system_program::ID)?; + + // Record old values. + let count = squares_old.count; + let miners = squares_old.miners; + + // Record old values. + let balance = treasury_old.balance; + + // Realloc squares + let new_size = 8 + std::mem::size_of::(); + let old_size = 8 + std::mem::size_of::(); + let new_rent = Rent::get()?.minimum_balance(new_size); + let old_rent = Rent::get()?.minimum_balance(old_size); + let additional_rent = new_rent - old_rent; + squares_info.realloc(new_size, false)?; + squares_info.collect(additional_rent, &signer_info)?; + + // Realloc treasury + let new_size = 8 + std::mem::size_of::(); + let old_size = 8 + std::mem::size_of::(); + let new_rent = Rent::get()?.minimum_balance(new_size); + let old_rent = Rent::get()?.minimum_balance(old_size); + let additional_rent = new_rent - old_rent; + treasury_info.realloc(new_size, false)?; + treasury_info.collect(additional_rent, &signer_info)?; + + // Update squares. + let squares = squares_info.as_account_mut::(&ore_api::ID)?; + squares.count = count; + squares.miners = miners; + squares.deployed = [[0; 16]; 25]; + + // Update treasury. + let treasury = treasury_info.as_account_mut::(&ore_api::ID)?; + treasury.balance = balance; + treasury.motherlode = 0; + + Ok(()) +}