From be20034e576ceae074576ec1a8eb41fd617a28e4 Mon Sep 17 00:00:00 2001 From: Hardhat Chad Date: Fri, 27 Sep 2024 00:22:32 +0000 Subject: [PATCH] continue migration --- Cargo.lock | 2 +- Cargo.toml | 2 +- api/src/error.rs | 2 - api/src/event.rs | 1 - api/src/loaders.rs | 211 ++------------------------------------ api/src/sdk.rs | 7 +- api/src/state/bus.rs | 28 ----- api/src/state/config.rs | 7 -- api/src/state/mod.rs | 24 ++++- api/src/state/proof.rs | 9 -- api/src/state/treasury.rs | 9 -- program/src/claim.rs | 15 +-- program/src/close.rs | 16 ++- program/src/initialize.rs | 64 ++++++++---- program/src/mine.rs | 21 ++-- program/src/open.rs | 3 +- program/src/reset.rs | 63 +++++++----- program/src/stake.rs | 14 ++- program/src/update.rs | 13 ++- program/src/upgrade.rs | 27 +++-- 20 files changed, 175 insertions(+), 363 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8758d26..19d48f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2211,7 +2211,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "steel" -version = "0.1.5" +version = "1.0.0" dependencies = [ "bytemuck", "num_enum", diff --git a/Cargo.toml b/Cargo.toml index 134951f..7ea337d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ solana-program = "^1.18" spl-token = { version = "^4", features = ["no-entrypoint"] } spl-associated-token-account = { version = "^2.3", features = [ "no-entrypoint" ] } static_assertions = "1.1.0" -steel = { features = ["spl"], version = "0.1.0" } +steel = { features = ["spl"], version = "1.0" } thiserror = "1.0.57" diff --git a/api/src/error.rs b/api/src/error.rs index 408681d..33fdb75 100644 --- a/api/src/error.rs +++ b/api/src/error.rs @@ -1,6 +1,4 @@ -use num_enum::IntoPrimitive; use steel::*; -use thiserror::Error; #[derive(Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive)] #[repr(u32)] diff --git a/api/src/event.rs b/api/src/event.rs index b7068b3..28b266d 100644 --- a/api/src/event.rs +++ b/api/src/event.rs @@ -1,4 +1,3 @@ -use bytemuck::{Pod, Zeroable}; use steel::*; #[repr(C)] diff --git a/api/src/loaders.rs b/api/src/loaders.rs index 77fa46a..ebc7383 100644 --- a/api/src/loaders.rs +++ b/api/src/loaders.rs @@ -1,223 +1,28 @@ -use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use steel::*; use crate::{ consts::*, - state::{Bus, Config, Proof, Treasury}, + state::{Config, Treasury}, }; -/// Errors if: -/// - Owner is not Ore program. -/// - Address does not match the expected bus address. -/// - Data is empty. -/// - Data cannot deserialize into a bus account. -/// - Bus ID does not match the expected ID. -/// - Expected to be writable, but is not. -pub fn load_bus(info: &AccountInfo<'_>, id: u64, is_writable: bool) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.key.ne(&BUS_ADDRESSES[id as usize]) { - return Err(ProgramError::InvalidSeeds); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - let bus_data = info.data.borrow(); - let bus = Bus::try_from_bytes(&bus_data)?; - - if bus.id.ne(&id) { - return Err(ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Data is empty. -/// - Data cannot deserialize into a bus account. -/// - Bus ID is not in the expected range. -/// - Address is not in set of valid bus address. -/// - Expected to be writable, but is not. -pub fn load_any_bus(info: &AccountInfo<'_>, is_writable: bool) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - if info.data.borrow()[0].ne(&(Bus::discriminator() as u8)) { - return Err(solana_program::program_error::ProgramError::InvalidAccountData); - } - - if !BUS_ADDRESSES.contains(info.key) { - return Err(ProgramError::InvalidSeeds); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Address does not match the expected address. -/// - Data is empty. -/// - Data cannot deserialize into a config account. -/// - Expected to be writable, but is not. -pub fn load_config(info: &AccountInfo<'_>, is_writable: bool) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.key.ne(&CONFIG_ADDRESS) { - return Err(ProgramError::InvalidSeeds); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - if info.data.borrow()[0].ne(&(Config::discriminator() as u8)) { - return Err(solana_program::program_error::ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Data is empty. -/// - Data cannot deserialize into a proof account. -/// - Proof authority does not match the expected address. -/// - Expected to be writable, but is not. -pub fn load_proof( - info: &AccountInfo<'_>, - authority: &Pubkey, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - let proof_data = info.data.borrow(); - let proof = Proof::try_from_bytes(&proof_data)?; - - if proof.authority.ne(&authority) { - return Err(ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Data is empty. -/// - Data cannot deserialize into a proof account. -/// - Proof miner does not match the expected address. -/// - Expected to be writable, but is not. -pub fn load_proof_with_miner( - info: &AccountInfo<'_>, - miner: &Pubkey, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - let proof_data = info.data.borrow(); - let proof = Proof::try_from_bytes(&proof_data)?; - - if proof.miner.ne(&miner) { - return Err(ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Data is empty. -/// - Data cannot deserialize into a proof account. -/// - Expected to be writable, but is not. -pub fn load_any_proof(info: &AccountInfo<'_>, is_writable: bool) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - if info.data.borrow()[0].ne(&(Proof::discriminator() as u8)) { - return Err(solana_program::program_error::ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - pub trait OreAccountInfoValidation { fn is_config(&self) -> Result<&Self, ProgramError>; fn is_treasury(&self) -> Result<&Self, ProgramError>; + fn is_treasury_tokens(&self) -> Result<&Self, ProgramError>; } -impl<'a> OreAccountInfoValidation for AccountInfo<'a> { +impl OreAccountInfoValidation for AccountInfo<'_> { fn is_config(&self) -> Result<&Self, ProgramError> { self.has_address(&CONFIG_ADDRESS)? - .has_owner(&crate::ID)? - .is_type::() + .is_type::(&crate::ID) } fn is_treasury(&self) -> Result<&Self, ProgramError> { self.has_address(&TREASURY_ADDRESS)? - .has_owner(&crate::ID)? - .is_type::() - } -} - -/// Errors if: -/// - Address does not match the expected treasury tokens address. -/// - Cannot load as a token account -pub fn load_treasury_tokens(info: &AccountInfo<'_>, is_writable: bool) -> Result<(), ProgramError> { - if info.key.ne(&TREASURY_TOKENS_ADDRESS) { - return Err(ProgramError::InvalidSeeds); + .is_type::(&crate::ID) } - load_token_account(info, Some(&TREASURY_ADDRESS), &MINT_ADDRESS, is_writable) + fn is_treasury_tokens(&self) -> Result<&Self, ProgramError> { + self.has_address(&TREASURY_TOKENS_ADDRESS) + } } diff --git a/api/src/sdk.rs b/api/src/sdk.rs index 67793dc..602a4f6 100644 --- a/api/src/sdk.rs +++ b/api/src/sdk.rs @@ -1,9 +1,6 @@ use drillx::Solution; -use solana_program::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - system_program, sysvar, -}; +use solana_program::{system_program, sysvar}; +use steel::*; use crate::{ consts::*, diff --git a/api/src/state/bus.rs b/api/src/state/bus.rs index f92f715..bf32edc 100644 --- a/api/src/state/bus.rs +++ b/api/src/state/bus.rs @@ -1,7 +1,5 @@ use steel::*; -use crate::consts::BUS; - use super::OreAccount; /// Bus accounts are responsible for distributing mining rewards. There are 8 busses total @@ -23,30 +21,4 @@ pub struct Bus { pub top_balance: u64, } -/// Fetch the PDA of a bus account. -pub fn bus_pda(id: u8) -> (Pubkey, u8) { - Pubkey::find_program_address(&[BUS, &[id]], &crate::id()) -} - -impl<'a> From<&'a [u8]> for &'a Bus { - fn from(value: &'a [u8]) -> &'a Bus { - Bus::try_from_bytes(value).unwrap() - } -} - -impl<'a> From<*const u8> for &'a Bus { - fn from(value: *const u8) -> &'a Bus { - unsafe { - if Bus::discriminator().ne(&value.add(0).read()) { - panic!(""); - } - bytemuck::try_from_bytes::(std::slice::from_raw_parts( - value.add(8), - std::mem::size_of::(), - )) - .expect("") - } - } -} - account!(OreAccount, Bus); diff --git a/api/src/state/config.rs b/api/src/state/config.rs index 64bbf8c..52b21cc 100644 --- a/api/src/state/config.rs +++ b/api/src/state/config.rs @@ -1,7 +1,5 @@ use steel::*; -use crate::consts::CONFIG; - use super::OreAccount; /// Config is a singleton account which manages program global variables. @@ -21,9 +19,4 @@ pub struct Config { pub top_balance: u64, } -/// Derive the PDA of the config account. -pub fn config_pda() -> (Pubkey, u8) { - Pubkey::find_program_address(&[CONFIG], &crate::id()) -} - account!(OreAccount, Config); diff --git a/api/src/state/mod.rs b/api/src/state/mod.rs index 6803553..20baa13 100644 --- a/api/src/state/mod.rs +++ b/api/src/state/mod.rs @@ -8,7 +8,9 @@ pub use config::*; pub use proof::*; pub use treasury::*; -use num_enum::{IntoPrimitive, TryFromPrimitive}; +use steel::*; + +use crate::consts::*; #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] @@ -18,3 +20,23 @@ pub enum OreAccount { Proof = 102, Treasury = 103, } + +/// Fetch the PDA of a bus account. +pub fn bus_pda(id: u8) -> (Pubkey, u8) { + Pubkey::find_program_address(&[BUS, &[id]], &crate::id()) +} + +/// Derive the PDA of the config account. +pub fn config_pda() -> (Pubkey, u8) { + Pubkey::find_program_address(&[CONFIG], &crate::id()) +} + +/// Derive the PDA of a proof account. +pub fn proof_pda(authority: Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()) +} + +/// Derive the PDA of the treasury account. +pub fn treasury_pda() -> (Pubkey, u8) { + Pubkey::find_program_address(&[TREASURY], &crate::id()) +} diff --git a/api/src/state/proof.rs b/api/src/state/proof.rs index 33c0f4a..733e115 100644 --- a/api/src/state/proof.rs +++ b/api/src/state/proof.rs @@ -1,9 +1,5 @@ -use bytemuck::{Pod, Zeroable}; -use solana_program::pubkey::Pubkey; use steel::*; -use crate::consts::PROOF; - use super::OreAccount; /// Proof accounts track a miner's current hash, claimable rewards, and lifetime stats. @@ -39,9 +35,4 @@ pub struct Proof { pub total_rewards: u64, } -/// Derive the PDA of a proof account. -pub fn proof_pda(authority: Pubkey) -> (Pubkey, u8) { - Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()) -} - account!(OreAccount, Proof); diff --git a/api/src/state/treasury.rs b/api/src/state/treasury.rs index 289fc35..2268ae0 100644 --- a/api/src/state/treasury.rs +++ b/api/src/state/treasury.rs @@ -1,9 +1,5 @@ -use bytemuck::{Pod, Zeroable}; -use solana_program::pubkey::Pubkey; use steel::*; -use crate::consts::TREASURY; - use super::OreAccount; /// Treasury is a singleton account which is the mint authority for the ORE token and the authority of @@ -12,9 +8,4 @@ use super::OreAccount; #[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] pub struct Treasury {} -/// Derive the PDA of the treasury account. -pub fn treasury_pda() -> (Pubkey, u8) { - Pubkey::find_program_address(&[TREASURY], &crate::id()) -} - account!(OreAccount, Treasury); diff --git a/program/src/claim.rs b/program/src/claim.rs index 9f564b8..6e594fb 100644 --- a/program/src/claim.rs +++ b/program/src/claim.rs @@ -17,15 +17,18 @@ pub fn process_claim(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult return Err(ProgramError::NotEnoughAccountKeys); }; signer.is_signer()?; - load_token_account(beneficiary_info, None, &MINT_ADDRESS, true)?; - load_proof(proof_info, signer.key, true)?; + beneficiary_info + .is_writable()? + .to_token_account()? + .check(|t| t.mint.eq(&MINT_ADDRESS))?; + let proof = proof_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|p| p.authority == *signer.key)?; treasury_info.is_treasury()?; - load_treasury_tokens(treasury_tokens_info, true)?; - token_program.has_address(&spl_token::ID)?; + treasury_tokens_info.is_writable()?.is_treasury_tokens()?; + token_program.is_program(&spl_token::ID)?; // Update miner balance. - let mut proof_data = proof_info.data.borrow_mut(); - let proof = Proof::try_from_bytes_mut(&mut proof_data)?; proof.balance = proof .balance .checked_sub(amount) diff --git a/program/src/close.rs b/program/src/close.rs index 4201b5f..94e63e4 100644 --- a/program/src/close.rs +++ b/program/src/close.rs @@ -1,4 +1,4 @@ -use ore_api::{loaders::*, state::Proof}; +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, system_program, @@ -12,17 +12,13 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?; - load_proof(proof_info, signer_info.key, true)?; + proof_info + .is_writable()? + .to_account::(&ore_api::ID)? + .check(|p| p.authority == *signer_info.key)? + .check(|p| p.balance > 0)?; system_program.is_program(&system_program::ID)?; - // Validate balance is zero. - let proof_data = proof_info.data.borrow(); - let proof = Proof::try_from_bytes(&proof_data)?; - if proof.balance.gt(&0) { - return Err(ProgramError::InvalidAccountData); - } - drop(proof_data); - // Realloc data to zero. proof_info.realloc(0, true)?; diff --git a/program/src/initialize.rs b/program/src/initialize.rs index 16bd2d0..d331c14 100644 --- a/program/src/initialize.rs +++ b/program/src/initialize.rs @@ -24,26 +24,50 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramR return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?.has_address(&INITIALIZER_ADDRESS)?; - bus_0_info.is_empty_pda(&[BUS, &[0]], args.bus_0_bump, &ore_api::ID)?; - bus_1_info.is_empty_pda(&[BUS, &[1]], args.bus_1_bump, &ore_api::ID)?; - bus_2_info.is_empty_pda(&[BUS, &[2]], args.bus_2_bump, &ore_api::ID)?; - bus_3_info.is_empty_pda(&[BUS, &[3]], args.bus_3_bump, &ore_api::ID)?; - bus_4_info.is_empty_pda(&[BUS, &[4]], args.bus_4_bump, &ore_api::ID)?; - bus_5_info.is_empty_pda(&[BUS, &[5]], args.bus_5_bump, &ore_api::ID)?; - bus_6_info.is_empty_pda(&[BUS, &[6]], args.bus_6_bump, &ore_api::ID)?; - bus_7_info.is_empty_pda(&[BUS, &[7]], args.bus_7_bump, &ore_api::ID)?; - config_info.is_empty_pda(&[CONFIG], args.config_bump, &ore_api::id())?; - metadata_info.is_empty_pda( - &[ - METADATA, - mpl_token_metadata::ID.as_ref(), - MINT_ADDRESS.as_ref(), - ], - args.metadata_bump, - &mpl_token_metadata::ID, - )?; - mint_info.is_empty_pda(&[MINT, MINT_NOISE.as_slice()], args.mint_bump, &ore_api::ID)?; - treasury_info.is_empty_pda(&[TREASURY], args.treasury_bump, &ore_api::ID)?; + bus_0_info + .has_seeds(&[BUS, &[0]], args.bus_0_bump, &ore_api::ID)? + .is_empty()?; + bus_1_info + .has_seeds(&[BUS, &[1]], args.bus_1_bump, &ore_api::ID)? + .is_empty()?; + bus_2_info + .has_seeds(&[BUS, &[2]], args.bus_2_bump, &ore_api::ID)? + .is_empty()?; + bus_3_info + .has_seeds(&[BUS, &[3]], args.bus_3_bump, &ore_api::ID)? + .is_empty()?; + bus_4_info + .has_seeds(&[BUS, &[4]], args.bus_4_bump, &ore_api::ID)? + .is_empty()?; + bus_5_info + .has_seeds(&[BUS, &[5]], args.bus_5_bump, &ore_api::ID)? + .is_empty()?; + bus_6_info + .has_seeds(&[BUS, &[6]], args.bus_6_bump, &ore_api::ID)? + .is_empty()?; + bus_7_info + .has_seeds(&[BUS, &[7]], args.bus_7_bump, &ore_api::ID)? + .is_empty()?; + config_info + .has_seeds(&[CONFIG], args.config_bump, &ore_api::ID)? + .is_empty()?; + metadata_info + .has_seeds( + &[ + METADATA, + mpl_token_metadata::ID.as_ref(), + MINT_ADDRESS.as_ref(), + ], + args.metadata_bump, + &mpl_token_metadata::ID, + )? + .is_empty()?; + mint_info + .has_seeds(&[MINT, MINT_NOISE.as_slice()], args.mint_bump, &ore_api::ID)? + .is_empty()?; + treasury_info + .has_seeds(&[TREASURY], args.treasury_bump, &ore_api::ID)? + .is_empty()?; treasury_tokens_info.is_empty()?; system_program.is_program(&system_program::ID)?; token_program.is_program(&spl_token::ID)?; diff --git a/program/src/mine.rs b/program/src/mine.rs index cf5cf2d..b5af8db 100644 --- a/program/src/mine.rs +++ b/program/src/mine.rs @@ -6,7 +6,6 @@ use ore_api::{ error::OreError, event::MineEvent, instruction::Mine, - loaders::*, state::{Bus, Config, Proof}, }; use solana_program::program::set_return_data; @@ -37,9 +36,11 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult { return Err(ProgramError::NotEnoughAccountKeys); }; signer.is_signer()?; - bus_info.is_type::()?.is_writable()?; - config_info.is_config()?; - load_proof_with_miner(proof_info, signer.key, true)?; + let bus = bus_info.to_account_mut::(&ore_api::ID)?; + let config = config_info.to_account::(&ore_api::ID)?; + let proof = proof_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|p| p.authority.eq(signer.key))?; instructions_sysvar.is_sysvar(&sysvar::instructions::ID)?; slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?; @@ -50,8 +51,8 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult { authenticate(&instructions_sysvar.data.borrow(), proof_info.key)?; // Validate epoch is active. - let config_data = config_info.data.borrow(); - let config = Config::try_from_bytes(&config_data)?; + // let config_data = config_info.data.borrow(); + // let config = Config::try_from_bytes(&config_data)?; let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?; if config .last_reset_at @@ -65,8 +66,8 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult { // // Here we use drillx to validate the provided solution is a valid hash of the challenge. // If invalid, we return an error. - let mut proof_data = proof_info.data.borrow_mut(); - let proof = Proof::try_from_bytes_mut(&mut proof_data)?; + // let mut proof_data = proof_info.data.borrow_mut(); + // let proof = Proof::try_from_bytes_mut(&mut proof_data)?; let solution = Solution::new(args.digest, args.nonce); if !solution.is_valid(&proof.challenge) { return Err(OreError::HashInvalid.into()); @@ -110,8 +111,8 @@ pub fn process_mine(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult { // If user has greater than or equal to the max stake on the network, they receive 2x multiplier. // Any stake less than this will receives between 1x and 2x multipler. The multipler is only active // if the miner's last stake deposit was more than one minute ago to protect against flash loan attacks. - let mut bus_data = bus_info.data.borrow_mut(); - let bus = Bus::try_from_bytes_mut(&mut bus_data)?; + // let mut bus_data = bus_info.data.borrow_mut(); + // let bus = Bus::try_from_bytes_mut(&mut bus_data)?; if proof.balance.gt(&0) && proof.last_stake_at.saturating_add(ONE_MINUTE).lt(&t) { // Calculate staking reward. if config.top_balance.gt(&0) { diff --git a/program/src/open.rs b/program/src/open.rs index e2c99e3..a89dbea 100644 --- a/program/src/open.rs +++ b/program/src/open.rs @@ -27,7 +27,8 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult signer_info.is_signer()?; payer_info.is_signer()?; proof_info - .is_empty_pda(&[PROOF, signer_info.key.as_ref()], args.bump, &ore_api::ID)? + .has_seeds(&[PROOF, signer_info.key.as_ref()], args.bump, &ore_api::ID)? + .is_empty()? .is_writable()?; system_program.is_program(&system_program::ID)?; slot_hashes_info.is_sysvar(&sysvar::slot_hashes::ID)?; diff --git a/program/src/reset.rs b/program/src/reset.rs index ffb282c..fccb2f3 100644 --- a/program/src/reset.rs +++ b/program/src/reset.rs @@ -4,11 +4,7 @@ use ore_api::{ loaders::*, state::{Bus, Config}, }; -use solana_program::{ - account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, - program_error::ProgramError, program_pack::Pack, sysvar::Sysvar, -}; -use spl_token::state::Mint; +use solana_program::clock::Clock; use steel::*; /// Reset tops up the bus balances, updates the base reward rate, and sets up the ORE program for the next epoch. @@ -20,27 +16,42 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?; - load_bus(bus_0_info, 0, true)?; - load_bus(bus_1_info, 1, true)?; - load_bus(bus_2_info, 2, true)?; - load_bus(bus_3_info, 3, true)?; - load_bus(bus_4_info, 4, true)?; - load_bus(bus_5_info, 5, true)?; - load_bus(bus_6_info, 6, true)?; - load_bus(bus_7_info, 7, true)?; - config_info.is_config()?.is_writable()?; - load_mint(mint_info, MINT_ADDRESS, true)?; + let bus_0 = bus_0_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 0)?; + let bus_1 = bus_1_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 1)?; + let bus_2 = bus_2_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 2)?; + let bus_3 = bus_3_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 3)?; + let bus_4 = bus_4_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 4)?; + let bus_5 = bus_5_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 5)?; + let bus_6 = bus_6_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 6)?; + let bus_7 = bus_7_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|b| b.id == 7)?; + let config = config_info.to_account_mut::(&ore_api::ID)?; + let mint = mint_info + .has_address(&MINT_ADDRESS)? + .is_writable()? + .to_mint()?; treasury_info.is_treasury()?.is_writable()?; - load_treasury_tokens(treasury_tokens_info, true)?; + treasury_tokens_info.is_treasury_tokens()?.is_writable()?; token_program.is_program(&spl_token::ID)?; - let busses: [&AccountInfo; BUS_COUNT] = [ - bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, - bus_7_info, - ]; // Validate enough time has passed since the last reset. - let mut config_data = config_info.data.borrow_mut(); - let config = Config::try_from_bytes_mut(&mut config_data)?; + // let mut config_data = config_info.data.borrow_mut(); + // let config = Config::try_from_bytes_mut(&mut config_data)?; let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?; if config .last_reset_at @@ -54,14 +65,11 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul config.last_reset_at = clock.unix_timestamp; // Reset bus accounts and calculate actual rewards mined since last reset. + let busses = [bus_0, bus_1, bus_2, bus_3, bus_4, bus_5, bus_6, bus_7]; let mut total_remaining_rewards = 0u64; let mut total_theoretical_rewards = 0u64; let mut top_balance = 0u64; - for i in 0..BUS_COUNT { - // Parse bus account. - let mut bus_data = busses[i].data.borrow_mut(); - let bus = Bus::try_from_bytes_mut(&mut bus_data)?; - + for bus in busses { // Track top balance. if bus.top_balance.gt(&top_balance) { top_balance = bus.top_balance; @@ -99,7 +107,6 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul } // Max supply check. - let mint = Mint::unpack(&mint_info.data.borrow()).expect("Failed to parse mint"); if mint.supply.ge(&MAX_SUPPLY) { return Err(OreError::MaxSupply.into()); } diff --git a/program/src/stake.rs b/program/src/stake.rs index 94fef15..9a4ac41 100644 --- a/program/src/stake.rs +++ b/program/src/stake.rs @@ -17,14 +17,18 @@ pub fn process_stake(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?; - load_proof(proof_info, signer_info.key, true)?; - load_token_account(sender_info, Some(signer_info.key), &MINT_ADDRESS, true)?; - load_treasury_tokens(treasury_tokens_info, true)?; + let proof = proof_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|p| p.authority == *signer_info.key)?; + sender_info + .is_writable()? + .to_token_account()? + .check(|t| t.owner.eq(signer_info.key))? + .check(|t| t.mint.eq(&MINT_ADDRESS))?; + treasury_tokens_info.is_writable()?.is_treasury_tokens()?; token_program.is_program(&spl_token::ID)?; // Update the proof balance. - let mut proof_data = proof_info.data.borrow_mut(); - let proof = Proof::try_from_bytes_mut(&mut proof_data)?; proof.balance = proof.balance.checked_add(amount).unwrap(); // Update deposit timestamp. diff --git a/program/src/update.rs b/program/src/update.rs index 849eb1a..b101a3e 100644 --- a/program/src/update.rs +++ b/program/src/update.rs @@ -1,4 +1,4 @@ -use ore_api::{loaders::*, state::Proof}; +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, }; @@ -7,16 +7,15 @@ use steel::*; /// Update changes the miner authority on a proof account. pub fn process_update(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { // Load accounts. - let [signer, miner_info, proof_info] = accounts else { + let [signer_info, miner_info, proof_info] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - signer.is_signer()?; - // load_any(miner_info, false)?; - load_proof(proof_info, signer.key, true)?; + signer_info.is_signer()?; + let proof = proof_info + .to_account_mut::(&ore_api::ID)? + .check_mut(|p| p.authority == *signer_info.key)?; // Update the proof's miner authority. - let mut proof_data = proof_info.data.borrow_mut(); - let proof = Proof::try_from_bytes_mut(&mut proof_data)?; proof.miner = *miner_info.key; Ok(()) diff --git a/program/src/upgrade.rs b/program/src/upgrade.rs index d3b2220..f530d2b 100644 --- a/program/src/upgrade.rs +++ b/program/src/upgrade.rs @@ -19,15 +19,24 @@ pub fn process_upgrade(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResu return Err(ProgramError::NotEnoughAccountKeys); }; signer_info.is_signer()?; - load_token_account( - beneficiary_info, - Some(&signer_info.key), - &MINT_ADDRESS, - true, - )?; - load_mint(mint_info, MINT_ADDRESS, true)?; - load_mint(mint_v1_info, MINT_V1_ADDRESS, true)?; - load_token_account(sender_info, Some(signer_info.key), &MINT_V1_ADDRESS, true)?; + beneficiary_info + .is_writable()? + .to_token_account()? + .check(|t| t.owner.eq(signer_info.key))? + .check(|t| t.mint.eq(&MINT_ADDRESS))?; + mint_info + .is_writable()? + .has_address(&MINT_ADDRESS)? + .to_mint()?; + mint_v1_info + .is_writable()? + .has_address(&MINT_V1_ADDRESS)? + .to_mint()?; + sender_info + .is_writable()? + .to_token_account()? + .check(|t| t.owner.eq(signer_info.key))? + .check(|t| t.mint.eq(&MINT_V1_ADDRESS))?; token_program.is_program(&spl_token::ID)?; // Burn v1 tokens