diff --git a/Cargo.lock b/Cargo.lock index 92cdcee..8df0be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1286,7 +1286,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "ore-api" -version = "2.1.5" +version = "2.1.6" dependencies = [ "array-const-fn-init", "bytemuck", @@ -1304,7 +1304,7 @@ dependencies = [ [[package]] name = "ore-program" -version = "2.1.5" +version = "2.1.6" dependencies = [ "drillx", "mpl-token-metadata", @@ -1318,7 +1318,7 @@ dependencies = [ [[package]] name = "ore-utils" -version = "2.1.5" +version = "2.1.6" dependencies = [ "bytemuck", "solana-program", diff --git a/Cargo.toml b/Cargo.toml index 3fff5cb..5c2034a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "2" members = ["api", "program", "utils"] [workspace.package] -version = "2.1.5" +version = "2.1.6" edition = "2021" license = "Apache-2.0" homepage = "https://ore.supply" diff --git a/api/src/loaders.rs b/api/src/loaders.rs index c7f4cd0..881ca5d 100644 --- a/api/src/loaders.rs +++ b/api/src/loaders.rs @@ -1,4 +1,4 @@ -use ore_utils::{loaders::*, AccountDeserialize, Discriminator}; +use ore_utils::*; use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use crate::{ diff --git a/api/src/state/bus.rs b/api/src/state/bus.rs index a48c276..359b066 100644 --- a/api/src/state/bus.rs +++ b/api/src/state/bus.rs @@ -1,5 +1,5 @@ use bytemuck::{Pod, Zeroable}; -use ore_utils::{account, Discriminator}; +use ore_utils::*; use super::AccountDiscriminator; diff --git a/program/src/claim.rs b/program/src/claim.rs index dde7e25..fa16658 100644 --- a/program/src/claim.rs +++ b/program/src/claim.rs @@ -1,11 +1,9 @@ use ore_api::{consts::*, error::OreError, instruction::ClaimArgs, loaders::*, state::Proof}; -use ore_utils::spl::transfer_signed; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, }; -use ore_utils::{loaders::*, AccountDeserialize}; - /// Claim distributes claimable ORE from the treasury to a miner. pub fn process_claim(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { // Parse args. diff --git a/program/src/close.rs b/program/src/close.rs index bd572c9..c12150c 100644 --- a/program/src/close.rs +++ b/program/src/close.rs @@ -1,11 +1,10 @@ use ore_api::{loaders::*, state::Proof}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, system_program, }; -use ore_utils::{loaders::*, AccountDeserialize}; - /// Close closes a proof account and returns the rent to the owner. pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { // Load accounts. diff --git a/program/src/initialize.rs b/program/src/initialize.rs index bc116fb..46bd4a5 100644 --- a/program/src/initialize.rs +++ b/program/src/initialize.rs @@ -5,7 +5,7 @@ use ore_api::{ instruction::*, state::{Bus, Config, Treasury}, }; -use ore_utils::{create_pda, loaders::*, spl::create_ata, AccountDeserialize, Discriminator}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, diff --git a/program/src/mine.rs b/program/src/mine.rs index b088e51..3d1180a 100644 --- a/program/src/mine.rs +++ b/program/src/mine.rs @@ -9,6 +9,7 @@ use ore_api::{ loaders::*, state::{Bus, Config, Proof}, }; +use ore_utils::*; use solana_program::program::set_return_data; #[allow(deprecated)] use solana_program::{ @@ -24,8 +25,6 @@ use solana_program::{ sysvar::{self, Sysvar}, }; -use ore_utils::{loaders::*, AccountDeserialize}; - /// Mine validates hashes and increments a miner's collectable balance. pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { // Parse args. diff --git a/program/src/open.rs b/program/src/open.rs index 248012e..e42ecd2 100644 --- a/program/src/open.rs +++ b/program/src/open.rs @@ -1,6 +1,7 @@ use std::mem::size_of; use ore_api::{consts::*, instruction::OpenArgs, state::Proof}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, clock::Clock, @@ -12,8 +13,6 @@ use solana_program::{ sysvar::{self, Sysvar}, }; -use ore_utils::{create_pda, loaders::*, AccountDeserialize, Discriminator}; - /// Open creates a new proof account to track a miner's state. pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { // Parse args. diff --git a/program/src/reset.rs b/program/src/reset.rs index 60451f9..eda9489 100644 --- a/program/src/reset.rs +++ b/program/src/reset.rs @@ -4,14 +4,13 @@ use ore_api::{ loaders::*, state::{Bus, Config}, }; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, sysvar::Sysvar, }; use spl_token::state::Mint; -use ore_utils::{loaders::*, AccountDeserialize}; - /// Reset tops up the bus balances, updates the base reward rate, and sets up the ORE program for the next epoch. pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult { // Load accounts. diff --git a/program/src/stake.rs b/program/src/stake.rs index 12ac357..e82912a 100644 --- a/program/src/stake.rs +++ b/program/src/stake.rs @@ -1,5 +1,5 @@ use ore_api::{consts::*, instruction::StakeArgs, loaders::*, state::Proof}; -use ore_utils::{loaders::*, spl::transfer, AccountDeserialize}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, sysvar::Sysvar, diff --git a/program/src/update.rs b/program/src/update.rs index cc7fca4..c5a21e7 100644 --- a/program/src/update.rs +++ b/program/src/update.rs @@ -1,5 +1,5 @@ use ore_api::{loaders::*, state::Proof}; -use ore_utils::{loaders::*, AccountDeserialize}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, }; diff --git a/program/src/upgrade.rs b/program/src/upgrade.rs index c28eace..a2bf8f5 100644 --- a/program/src/upgrade.rs +++ b/program/src/upgrade.rs @@ -1,5 +1,5 @@ use ore_api::{consts::*, error::OreError, instruction::StakeArgs}; -use ore_utils::{loaders::*, spl::mint_to_signed}; +use ore_utils::*; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, diff --git a/utils/src/spl.rs b/utils/src/cpi.rs similarity index 60% rename from utils/src/spl.rs rename to utils/src/cpi.rs index bb60d52..bce2c8e 100644 --- a/utils/src/spl.rs +++ b/utils/src/cpi.rs @@ -1,5 +1,77 @@ -use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey, rent::Rent, + sysvar::Sysvar, +}; +/// Creates a new pda. +#[inline(always)] +pub fn create_pda<'a, 'info>( + target_account: &'a AccountInfo<'info>, + owner: &Pubkey, + space: usize, + pda_seeds: &[&[u8]], + system_program: &'a AccountInfo<'info>, + payer: &'a AccountInfo<'info>, +) -> ProgramResult { + let rent = Rent::get()?; + if target_account.lamports().eq(&0) { + // If balance is zero, create account + solana_program::program::invoke_signed( + &solana_program::system_instruction::create_account( + payer.key, + target_account.key, + rent.minimum_balance(space), + space as u64, + owner, + ), + &[ + payer.clone(), + target_account.clone(), + system_program.clone(), + ], + &[pda_seeds], + )?; + } else { + // Otherwise, if balance is nonzero: + + // 1) transfer sufficient lamports for rent exemption + let rent_exempt_balance = rent + .minimum_balance(space) + .saturating_sub(target_account.lamports()); + if rent_exempt_balance.gt(&0) { + solana_program::program::invoke( + &solana_program::system_instruction::transfer( + payer.key, + target_account.key, + rent_exempt_balance, + ), + &[ + payer.clone(), + target_account.clone(), + system_program.clone(), + ], + )?; + } + + // 2) allocate space for the account + solana_program::program::invoke_signed( + &solana_program::system_instruction::allocate(target_account.key, space as u64), + &[target_account.clone(), system_program.clone()], + &[pda_seeds], + )?; + + // 3) assign our program as the owner + solana_program::program::invoke_signed( + &solana_program::system_instruction::assign(target_account.key, owner), + &[target_account.clone(), system_program.clone()], + &[pda_seeds], + )?; + } + + Ok(()) +} + +#[cfg(feature = "spl")] #[inline(always)] pub fn create_ata<'info>( funder_info: &AccountInfo<'info>, @@ -29,6 +101,7 @@ pub fn create_ata<'info>( ) } +#[cfg(feature = "spl")] #[inline(always)] pub fn transfer<'info>( authority_info: &AccountInfo<'info>, @@ -55,6 +128,7 @@ pub fn transfer<'info>( ) } +#[cfg(feature = "spl")] #[inline(always)] pub fn transfer_signed<'info>( authority_info: &AccountInfo<'info>, @@ -83,6 +157,7 @@ pub fn transfer_signed<'info>( ) } +#[cfg(feature = "spl")] #[inline(always)] pub fn mint_to_signed<'info>( mint_info: &AccountInfo<'info>, @@ -111,6 +186,7 @@ pub fn mint_to_signed<'info>( ) } +#[cfg(feature = "spl")] #[inline(always)] pub fn burn<'info>( token_account_info: &AccountInfo<'info>, diff --git a/utils/src/lib.rs b/utils/src/lib.rs index e2dd012..d4c963a 100644 --- a/utils/src/lib.rs +++ b/utils/src/lib.rs @@ -1,155 +1,8 @@ -pub mod loaders; -#[cfg(feature = "spl")] -pub mod spl; +mod cpi; +mod loaders; +pub mod macros; +mod traits; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, rent::Rent, sysvar::Sysvar, -}; - -/// Creates a new pda. -#[inline(always)] -pub fn create_pda<'a, 'info>( - target_account: &'a AccountInfo<'info>, - owner: &Pubkey, - space: usize, - pda_seeds: &[&[u8]], - system_program: &'a AccountInfo<'info>, - payer: &'a AccountInfo<'info>, -) -> ProgramResult { - let rent = Rent::get()?; - if target_account.lamports().eq(&0) { - // If balance is zero, create account - solana_program::program::invoke_signed( - &solana_program::system_instruction::create_account( - payer.key, - target_account.key, - rent.minimum_balance(space), - space as u64, - owner, - ), - &[ - payer.clone(), - target_account.clone(), - system_program.clone(), - ], - &[pda_seeds], - )?; - } else { - // Otherwise, if balance is nonzero: - - // 1) transfer sufficient lamports for rent exemption - let rent_exempt_balance = rent - .minimum_balance(space) - .saturating_sub(target_account.lamports()); - if rent_exempt_balance.gt(&0) { - solana_program::program::invoke( - &solana_program::system_instruction::transfer( - payer.key, - target_account.key, - rent_exempt_balance, - ), - &[ - payer.clone(), - target_account.clone(), - system_program.clone(), - ], - )?; - } - - // 2) allocate space for the account - solana_program::program::invoke_signed( - &solana_program::system_instruction::allocate(target_account.key, space as u64), - &[target_account.clone(), system_program.clone()], - &[pda_seeds], - )?; - - // 3) assign our program as the owner - solana_program::program::invoke_signed( - &solana_program::system_instruction::assign(target_account.key, owner), - &[target_account.clone(), system_program.clone()], - &[pda_seeds], - )?; - } - - Ok(()) -} - -pub trait Discriminator { - fn discriminator() -> u8; -} - -pub trait AccountDeserialize { - fn try_from_bytes(data: &[u8]) -> Result<&Self, ProgramError>; - fn try_from_bytes_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError>; -} - -#[macro_export] -macro_rules! impl_to_bytes { - ($struct_name:ident) => { - impl $struct_name { - pub fn to_bytes(&self) -> &[u8] { - bytemuck::bytes_of(self) - } - } - }; -} - -#[macro_export] -macro_rules! impl_account_from_bytes { - ($struct_name:ident) => { - impl $crate::AccountDeserialize for $struct_name { - fn try_from_bytes( - data: &[u8], - ) -> Result<&Self, solana_program::program_error::ProgramError> { - if Self::discriminator().ne(&data[0]) { - return Err(solana_program::program_error::ProgramError::InvalidAccountData); - } - bytemuck::try_from_bytes::(&data[8..]).or(Err( - solana_program::program_error::ProgramError::InvalidAccountData, - )) - } - fn try_from_bytes_mut( - data: &mut [u8], - ) -> Result<&mut Self, solana_program::program_error::ProgramError> { - if Self::discriminator().ne(&data[0]) { - return Err(solana_program::program_error::ProgramError::InvalidAccountData); - } - bytemuck::try_from_bytes_mut::(&mut data[8..]).or(Err( - solana_program::program_error::ProgramError::InvalidAccountData, - )) - } - } - }; -} - -#[macro_export] -macro_rules! impl_instruction_from_bytes { - ($struct_name:ident) => { - impl $struct_name { - pub fn try_from_bytes( - data: &[u8], - ) -> Result<&Self, solana_program::program_error::ProgramError> { - bytemuck::try_from_bytes::(data).or(Err( - solana_program::program_error::ProgramError::InvalidInstructionData, - )) - } - } - }; -} - -#[macro_export] -macro_rules! account { - ($struct_name:ident) => { - $crate::impl_to_bytes!($struct_name); - $crate::impl_account_from_bytes!($struct_name); - }; -} - -#[macro_export] -macro_rules! instruction { - ($struct_name:ident) => { - $crate::impl_to_bytes!($struct_name); - $crate::impl_instruction_from_bytes!($struct_name); - }; -} +pub use cpi::*; +pub use loaders::*; +pub use traits::*; diff --git a/utils/src/macros.rs b/utils/src/macros.rs new file mode 100644 index 0000000..917260f --- /dev/null +++ b/utils/src/macros.rs @@ -0,0 +1,69 @@ +#[macro_export] +macro_rules! impl_to_bytes { + ($struct_name:ident) => { + impl $struct_name { + pub fn to_bytes(&self) -> &[u8] { + bytemuck::bytes_of(self) + } + } + }; +} + +#[macro_export] +macro_rules! impl_account_from_bytes { + ($struct_name:ident) => { + impl $crate::AccountDeserialize for $struct_name { + fn try_from_bytes( + data: &[u8], + ) -> Result<&Self, solana_program::program_error::ProgramError> { + if Self::discriminator().ne(&data[0]) { + return Err(solana_program::program_error::ProgramError::InvalidAccountData); + } + bytemuck::try_from_bytes::(&data[8..]).or(Err( + solana_program::program_error::ProgramError::InvalidAccountData, + )) + } + fn try_from_bytes_mut( + data: &mut [u8], + ) -> Result<&mut Self, solana_program::program_error::ProgramError> { + if Self::discriminator().ne(&data[0]) { + return Err(solana_program::program_error::ProgramError::InvalidAccountData); + } + bytemuck::try_from_bytes_mut::(&mut data[8..]).or(Err( + solana_program::program_error::ProgramError::InvalidAccountData, + )) + } + } + }; +} + +#[macro_export] +macro_rules! impl_instruction_from_bytes { + ($struct_name:ident) => { + impl $struct_name { + pub fn try_from_bytes( + data: &[u8], + ) -> Result<&Self, solana_program::program_error::ProgramError> { + bytemuck::try_from_bytes::(data).or(Err( + solana_program::program_error::ProgramError::InvalidInstructionData, + )) + } + } + }; +} + +#[macro_export] +macro_rules! account { + ($struct_name:ident) => { + $crate::impl_to_bytes!($struct_name); + $crate::impl_account_from_bytes!($struct_name); + }; +} + +#[macro_export] +macro_rules! instruction { + ($struct_name:ident) => { + $crate::impl_to_bytes!($struct_name); + $crate::impl_instruction_from_bytes!($struct_name); + }; +} diff --git a/utils/src/traits.rs b/utils/src/traits.rs new file mode 100644 index 0000000..32d1696 --- /dev/null +++ b/utils/src/traits.rs @@ -0,0 +1,10 @@ +use solana_program::program_error::ProgramError; + +pub trait Discriminator { + fn discriminator() -> u8; +} + +pub trait AccountDeserialize { + fn try_from_bytes(data: &[u8]) -> Result<&Self, ProgramError>; + fn try_from_bytes_mut(data: &mut [u8]) -> Result<&mut Self, ProgramError>; +}