diff --git a/Cargo.lock b/Cargo.lock index 412b136..8d229be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -670,15 +670,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" -[[package]] -name = "bs58" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" -dependencies = [ - "tinyvec", -] - [[package]] name = "bs64" version = "0.1.2" @@ -2591,27 +2582,40 @@ dependencies = [ ] [[package]] -name = "ore-program" +name = "ore-api" version = "2.0.0" dependencies = [ "array-const-fn-init", - "bs58 0.5.0", - "bs64", "bytemuck", "const-crypto", "drillx", "mpl-token-metadata", "num_enum 0.7.2", - "rand 0.8.5", "shank", "solana-program", + "spl-associated-token-account", + "spl-token", + "static_assertions", + "thiserror", + "utils", +] + +[[package]] +name = "ore-program" +version = "2.0.0" +dependencies = [ + "bs64", + "drillx", + "mpl-token-metadata", + "ore-api", + "rand 0.8.5", + "solana-program", "solana-program-test", "solana-sdk", "spl-associated-token-account", "spl-token", - "static_assertions", - "thiserror", "tokio", + "utils", ] [[package]] @@ -3662,7 +3666,7 @@ dependencies = [ "Inflector", "base64 0.21.7", "bincode", - "bs58 0.4.0", + "bs58", "bv", "lazy_static", "serde", @@ -3972,7 +3976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35a0b24cc4d0ebd5fd45d6bd47bed3790f8a75ade67af8ff24a3d719a8bc93bc" dependencies = [ "block-buffer 0.10.4", - "bs58 0.4.0", + "bs58", "bv", "either", "generic-array", @@ -4125,7 +4129,7 @@ dependencies = [ "borsh 0.10.3", "borsh 0.9.3", "borsh 1.5.0", - "bs58 0.4.0", + "bs58", "bv", "bytemuck", "cc", @@ -4311,7 +4315,7 @@ dependencies = [ "async-trait", "base64 0.21.7", "bincode", - "bs58 0.4.0", + "bs58", "indicatif", "log", "reqwest", @@ -4335,7 +4339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31feddef24d3e0aab189571adea7f109639ef6179fcd3cd34ffc8c73d3409f1" dependencies = [ "base64 0.21.7", - "bs58 0.4.0", + "bs58", "jsonrpc-core", "reqwest", "semver", @@ -4451,7 +4455,7 @@ dependencies = [ "bincode", "bitflags 2.5.0", "borsh 1.5.0", - "bs58 0.4.0", + "bs58", "bytemuck", "byteorder", "chrono", @@ -4501,7 +4505,7 @@ version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cb099b2f9c0a65a6f23ced791325141cd68c27b04d11c04fef838a00f613861" dependencies = [ - "bs58 0.4.0", + "bs58", "proc-macro2", "quote", "rustversion", @@ -4641,7 +4645,7 @@ dependencies = [ "base64 0.21.7", "bincode", "borsh 0.10.3", - "bs58 0.4.0", + "bs58", "lazy_static", "log", "serde", @@ -5710,6 +5714,14 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utils" +version = "2.0.0" +dependencies = [ + "bytemuck", + "solana-program", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index fa1ecd3..9e3dcb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,26 +1,19 @@ -[package] -name = "ore-program" +[workspace] +resolver = "2" +members = ["core/*", "utils"] + +[workspace.package] version = "2.0.0" -description = "Ore is a digital currency you can mine from anywhere, at home or on your phone." edition = "2021" license = "Apache-2.0" homepage = "https://ore.supply" documentation = "https://ore.supply" -repository = "https://github.com/hardhatchad/ore" +repository = "https://github.com/regolith-labs/ore" readme = "./README.md" keywords = ["solana", "crypto", "mining"] -[lib] -crate-type = ["cdylib", "lib"] -name = "ore" - -[features] -no-entrypoint = [] -default = [] - -[dependencies] +[workspace.dependencies] array-const-fn-init = "0.1.1" -bs58 = "0.5.0" bytemuck = "1.14.3" const-crypto = "0.1.0" drillx = { git = "https://github.com/regolith-labs/drillx", branch = "master", features = ["solana"] } @@ -32,10 +25,4 @@ spl-token = { version = "^4", features = ["no-entrypoint"] } spl-associated-token-account = { version = "^2.2", features = [ "no-entrypoint" ] } static_assertions = "1.1.0" thiserror = "1.0.57" - -[dev-dependencies] -bs64 = "0.1.2" -rand = "0.8.5" -solana-program-test = "^1.18" -solana-sdk = "^1.18" -tokio = { version = "1.35", features = ["full"] } +utils = { path = "utils" } diff --git a/core/api/Cargo.toml b/core/api/Cargo.toml new file mode 100644 index 0000000..224c77f --- /dev/null +++ b/core/api/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "ore-api" +description = "API for interacting with the ORE program" +version.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +documentation.workspace = true +repository.workspace = true +keywords.workspace = true + +[dependencies] +array-const-fn-init.workspace = true +bytemuck.workspace = true +const-crypto.workspace = true +drillx.workspace = true +mpl-token-metadata.workspace = true +num_enum.workspace = true +shank.workspace = true +solana-program.workspace = true +spl-token.workspace = true +spl-associated-token-account.workspace = true +static_assertions.workspace = true +thiserror.workspace = true +utils.workspace = true \ No newline at end of file diff --git a/src/consts.rs b/core/api/src/consts.rs similarity index 100% rename from src/consts.rs rename to core/api/src/consts.rs diff --git a/src/error.rs b/core/api/src/error.rs similarity index 100% rename from src/error.rs rename to core/api/src/error.rs diff --git a/core/api/src/event.rs b/core/api/src/event.rs new file mode 100644 index 0000000..675e9e9 --- /dev/null +++ b/core/api/src/event.rs @@ -0,0 +1,13 @@ +use bytemuck::{Pod, Zeroable}; + +use crate::utils::impl_to_bytes; + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] +pub struct MineEvent { + pub difficulty: u64, + pub reward: u64, + pub timing: i64, +} + +impl_to_bytes!(MineEvent); diff --git a/src/instruction.rs b/core/api/src/instruction.rs similarity index 98% rename from src/instruction.rs rename to core/api/src/instruction.rs index fdf9d2a..5d00d43 100644 --- a/src/instruction.rs +++ b/core/api/src/instruction.rs @@ -9,8 +9,8 @@ use solana_program::{ }; use crate::{ - impl_instruction_from_bytes, impl_to_bytes, BUS, BUS_ADDRESSES, CONFIG, CONFIG_ADDRESS, - METADATA, MINT, MINT_ADDRESS, MINT_NOISE, MINT_V1_ADDRESS, PROOF, TREASURY, TREASURY_ADDRESS, + consts::*, + utils::{impl_instruction_from_bytes, impl_to_bytes}, }; #[repr(u8)] @@ -185,8 +185,9 @@ impl_instruction_from_bytes!(ClaimArgs); impl_instruction_from_bytes!(StakeArgs); impl_instruction_from_bytes!(UpgradeArgs); -/// Builds a reset instruction. -pub fn reset(signer: Pubkey) -> Instruction { +/// Builds a claim instruction. +pub fn claim(signer: Pubkey, beneficiary: Pubkey, amount: u64) -> Instruction { + let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0; let treasury_tokens = spl_associated_token_account::get_associated_token_address( &TREASURY_ADDRESS, &MINT_ADDRESS, @@ -195,39 +196,20 @@ pub fn reset(signer: Pubkey) -> Instruction { program_id: crate::id(), accounts: vec![ AccountMeta::new(signer, true), - AccountMeta::new(BUS_ADDRESSES[0], false), - AccountMeta::new(BUS_ADDRESSES[1], false), - AccountMeta::new(BUS_ADDRESSES[2], false), - AccountMeta::new(BUS_ADDRESSES[3], false), - AccountMeta::new(BUS_ADDRESSES[4], false), - AccountMeta::new(BUS_ADDRESSES[5], false), - AccountMeta::new(BUS_ADDRESSES[6], false), - AccountMeta::new(BUS_ADDRESSES[7], false), - AccountMeta::new(CONFIG_ADDRESS, false), + AccountMeta::new(beneficiary, false), AccountMeta::new(MINT_ADDRESS, false), - AccountMeta::new(TREASURY_ADDRESS, false), + AccountMeta::new(proof, false), + AccountMeta::new_readonly(TREASURY_ADDRESS, false), AccountMeta::new(treasury_tokens, false), AccountMeta::new_readonly(spl_token::id(), false), ], - data: OreInstruction::Reset.to_vec(), - } -} - -/// Builds an open instruction. -pub fn open(signer: Pubkey, miner: Pubkey) -> Instruction { - let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()); - Instruction { - program_id: crate::id(), - accounts: vec![ - AccountMeta::new(signer, true), - AccountMeta::new_readonly(miner, false), - AccountMeta::new(proof_pda.0, false), - AccountMeta::new_readonly(solana_program::system_program::id(), false), - AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), - ], data: [ - OreInstruction::Open.to_vec(), - OpenArgs { bump: proof_pda.1 }.to_bytes().to_vec(), + OreInstruction::Claim.to_vec(), + ClaimArgs { + amount: amount.to_le_bytes(), + } + .to_bytes() + .to_vec(), ] .concat(), } @@ -273,9 +255,28 @@ pub fn mine(signer: Pubkey, bus: Pubkey, solution: Solution) -> Instruction { } } -/// Builds a claim instruction. -pub fn claim(signer: Pubkey, beneficiary: Pubkey, amount: u64) -> Instruction { - let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0; +/// Builds an open instruction. +pub fn open(signer: Pubkey, miner: Pubkey) -> Instruction { + let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()); + Instruction { + program_id: crate::id(), + accounts: vec![ + AccountMeta::new(signer, true), + AccountMeta::new_readonly(miner, false), + AccountMeta::new(proof_pda.0, false), + AccountMeta::new_readonly(solana_program::system_program::id(), false), + AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), + ], + data: [ + OreInstruction::Open.to_vec(), + OpenArgs { bump: proof_pda.1 }.to_bytes().to_vec(), + ] + .concat(), + } +} + +/// Builds a reset instruction. +pub fn reset(signer: Pubkey) -> Instruction { let treasury_tokens = spl_associated_token_account::get_associated_token_address( &TREASURY_ADDRESS, &MINT_ADDRESS, @@ -284,22 +285,21 @@ pub fn claim(signer: Pubkey, beneficiary: Pubkey, amount: u64) -> Instruction { program_id: crate::id(), accounts: vec![ AccountMeta::new(signer, true), - AccountMeta::new(beneficiary, false), + AccountMeta::new(BUS_ADDRESSES[0], false), + AccountMeta::new(BUS_ADDRESSES[1], false), + AccountMeta::new(BUS_ADDRESSES[2], false), + AccountMeta::new(BUS_ADDRESSES[3], false), + AccountMeta::new(BUS_ADDRESSES[4], false), + AccountMeta::new(BUS_ADDRESSES[5], false), + AccountMeta::new(BUS_ADDRESSES[6], false), + AccountMeta::new(BUS_ADDRESSES[7], false), + AccountMeta::new(CONFIG_ADDRESS, false), AccountMeta::new(MINT_ADDRESS, false), - AccountMeta::new(proof, false), - AccountMeta::new_readonly(TREASURY_ADDRESS, false), + AccountMeta::new(TREASURY_ADDRESS, false), AccountMeta::new(treasury_tokens, false), AccountMeta::new_readonly(spl_token::id(), false), ], - data: [ - OreInstruction::Claim.to_vec(), - ClaimArgs { - amount: amount.to_le_bytes(), - } - .to_bytes() - .to_vec(), - ] - .concat(), + data: OreInstruction::Reset.to_vec(), } } diff --git a/core/api/src/lib.rs b/core/api/src/lib.rs new file mode 100644 index 0000000..409cafb --- /dev/null +++ b/core/api/src/lib.rs @@ -0,0 +1,11 @@ +pub mod consts; +pub mod error; +pub mod event; +pub mod instruction; +pub mod state; + +pub(crate) use utils; + +use solana_program::declare_id; + +declare_id!("mineRHF5r6S7HyD9SppBfVMXMavDkJsxwGesEvxZr2A"); diff --git a/src/state/bus.rs b/core/api/src/state/bus.rs similarity index 79% rename from src/state/bus.rs rename to core/api/src/state/bus.rs index 7275119..2eaa557 100644 --- a/src/state/bus.rs +++ b/core/api/src/state/bus.rs @@ -1,10 +1,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Bus accounts are responsible for distributing mining rewards. /// There are 8 busses total to minimize write-lock contention and allow for parallel mine operations. @@ -23,8 +22,8 @@ pub struct Bus { } impl Discriminator for Bus { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Bus + fn discriminator() -> u8 { + AccountDiscriminator::Bus.into() } } diff --git a/src/state/config.rs b/core/api/src/state/config.rs similarity index 80% rename from src/state/config.rs rename to core/api/src/state/config.rs index 2c8214f..d08e00d 100644 --- a/src/state/config.rs +++ b/core/api/src/state/config.rs @@ -2,10 +2,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; use solana_program::pubkey::Pubkey; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Config is a singleton account which manages admin configurable variables. #[repr(C)] @@ -28,8 +27,8 @@ pub struct Config { } impl Discriminator for Config { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Config + fn discriminator() -> u8 { + AccountDiscriminator::Config.into() } } diff --git a/core/api/src/state/mod.rs b/core/api/src/state/mod.rs new file mode 100644 index 0000000..e228cac --- /dev/null +++ b/core/api/src/state/mod.rs @@ -0,0 +1,20 @@ +mod bus; +mod config; +mod proof; +mod treasury; + +pub use bus::*; +pub use config::*; +pub use proof::*; +pub use treasury::*; + +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] +pub enum AccountDiscriminator { + Bus = 100, + Config = 101, + Proof = 102, + Treasury = 103, +} diff --git a/src/state/proof.rs b/core/api/src/state/proof.rs similarity index 86% rename from src/state/proof.rs rename to core/api/src/state/proof.rs index 1d1aa76..83e9dd5 100644 --- a/src/state/proof.rs +++ b/core/api/src/state/proof.rs @@ -2,10 +2,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; use solana_program::pubkey::Pubkey; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Proof accounts track a miner's current hash, claimable rewards, and lifetime stats. /// Every miner is allowed one proof account which is required by the program to mine or claim rewards. @@ -41,8 +40,8 @@ pub struct Proof { } impl Discriminator for Proof { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Proof + fn discriminator() -> u8 { + AccountDiscriminator::Proof.into() } } diff --git a/src/state/treasury.rs b/core/api/src/state/treasury.rs similarity index 69% rename from src/state/treasury.rs rename to core/api/src/state/treasury.rs index e699ae2..5b78b6c 100644 --- a/src/state/treasury.rs +++ b/core/api/src/state/treasury.rs @@ -1,10 +1,9 @@ use bytemuck::{Pod, Zeroable}; use shank::ShankAccount; -use crate::{ - impl_account_from_bytes, impl_to_bytes, - utils::{AccountDiscriminator, Discriminator}, -}; +use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator}; + +use super::AccountDiscriminator; /// Treasury is a singleton account which manages all program wide variables. /// It is the mint authority for the Ore token and also the authority of the program-owned token account. @@ -13,8 +12,8 @@ use crate::{ pub struct Treasury {} impl Discriminator for Treasury { - fn discriminator() -> AccountDiscriminator { - AccountDiscriminator::Treasury + fn discriminator() -> u8 { + AccountDiscriminator::Treasury.into() } } diff --git a/core/program/Cargo.toml b/core/program/Cargo.toml new file mode 100644 index 0000000..cb97a8e --- /dev/null +++ b/core/program/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "ore-program" +description = "ORE is a fair-launch, proof-of-work, digital currency everyone can mine" +version.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +documentation.workspace = true +repository.workspace = true +readme.workspace = true +keywords.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] +name = "ore" + +[features] +no-entrypoint = [] +default = [] + +[dependencies] +drillx.workspace = true +mpl-token-metadata.workspace = true +ore-api = { path = "../api" } +solana-program.workspace = true +spl-token.workspace = true +spl-associated-token-account.workspace = true +utils.workspace = true + +[dev-dependencies] +bs64 = "0.1.2" +rand = "0.8.5" +solana-program-test = "^1.18" +solana-sdk = "^1.18" +tokio = { version = "1.35", features = ["full"] } diff --git a/src/lib.rs b/core/program/src/lib.rs similarity index 78% rename from src/lib.rs rename to core/program/src/lib.rs index 51ede90..010e69c 100644 --- a/src/lib.rs +++ b/core/program/src/lib.rs @@ -1,20 +1,14 @@ -pub mod consts; -pub mod error; -pub mod instruction; -pub mod loaders; +mod loaders; mod processor; -pub mod state; -pub mod utils; -pub use consts::*; -use instruction::*; +use ore_api::instruction::*; use processor::*; use solana_program::{ - self, account_info::AccountInfo, declare_id, entrypoint::ProgramResult, - program_error::ProgramError, pubkey::Pubkey, + self, account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, }; -declare_id!("oreFHcE6FvJTrsfaYca4mVeZn7J7T6oZS9FAvW9eg4q"); +pub(crate) use utils; #[cfg(not(feature = "no-entrypoint"))] solana_program::entrypoint!(process_instruction); @@ -24,7 +18,7 @@ pub fn process_instruction( accounts: &[AccountInfo], data: &[u8], ) -> ProgramResult { - if program_id.ne(&crate::id()) { + if program_id.ne(&ore_api::id()) { return Err(ProgramError::IncorrectProgramId); } diff --git a/core/program/src/loaders.rs b/core/program/src/loaders.rs new file mode 100644 index 0000000..1daaa96 --- /dev/null +++ b/core/program/src/loaders.rs @@ -0,0 +1,425 @@ +use ore_api::{ + consts::*, + state::{Bus, Config, Proof, Treasury}, +}; +use solana_program::{ + account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, + system_program, sysvar, +}; +use spl_token::state::Mint; + +use crate::utils::{AccountDeserialize, Discriminator}; + +/// Errors if: +/// - Account is not a signer. +pub fn load_signer<'a, 'info>(info: &'a AccountInfo<'info>) -> Result<(), ProgramError> { + if !info.is_signer { + return Err(ProgramError::MissingRequiredSignature); + } + + Ok(()) +} + +/// 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<'a, 'info>( + info: &'a AccountInfo<'info>, + id: u64, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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<'a, 'info>( + info: &'a AccountInfo<'info>, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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<'a, 'info>( + info: &'a AccountInfo<'info>, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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<'a, 'info>( + info: &'a AccountInfo<'info>, + authority: &Pubkey, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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<'a, 'info>( + info: &'a AccountInfo<'info>, + miner: &Pubkey, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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<'a, 'info>( + info: &'a AccountInfo<'info>, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::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(()) +} + +/// Errors if: +/// - Owner is not Ore program. +/// - Address does not match the expected address. +/// - Data is empty. +/// - Data cannot deserialize into a treasury account. +/// - Expected to be writable, but is not. +pub fn load_treasury<'a, 'info>( + info: &'a AccountInfo<'info>, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&ore_api::id()) { + return Err(ProgramError::InvalidAccountOwner); + } + + if info.key.ne(&TREASURY_ADDRESS) { + return Err(ProgramError::InvalidSeeds); + } + + if info.data_is_empty() { + return Err(ProgramError::UninitializedAccount); + } + + if info.data.borrow()[0].ne(&(Treasury::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 SPL token program. +/// - Address does not match the expected mint address. +/// - Data is empty. +/// - Data cannot deserialize into a mint account. +/// - Expected to be writable, but is not. +pub fn load_mint<'a, 'info>( + info: &'a AccountInfo<'info>, + address: Pubkey, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&spl_token::id()) { + return Err(ProgramError::InvalidAccountOwner); + } + + if info.key.ne(&address) { + return Err(ProgramError::InvalidSeeds); + } + + if info.data_is_empty() { + return Err(ProgramError::UninitializedAccount); + } + + if Mint::unpack_unchecked(&info.data.borrow()).is_err() { + return Err(ProgramError::InvalidAccountData); + } + + if is_writable && !info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + Ok(()) +} + +/// Errors if: +/// - Owner is not SPL token program. +/// - Data is empty. +/// - Data cannot deserialize into a token account. +/// - Token account owner does not match the expected owner address. +/// - Token account mint does not match the expected mint address. +/// - Expected to be writable, but is not. +pub fn load_token_account<'a, 'info>( + info: &'a AccountInfo<'info>, + owner: Option<&Pubkey>, + mint: &Pubkey, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&spl_token::id()) { + return Err(ProgramError::InvalidAccountOwner); + } + + if info.data_is_empty() { + return Err(ProgramError::UninitializedAccount); + } + + let account_data = info.data.borrow(); + let account = spl_token::state::Account::unpack_unchecked(&account_data) + .or(Err(ProgramError::InvalidAccountData))?; + + if account.mint.ne(&mint) { + return Err(ProgramError::InvalidAccountData); + } + + if let Some(owner) = owner { + if account.owner.ne(owner) { + return Err(ProgramError::InvalidAccountData); + } + } + + if is_writable && !info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + Ok(()) +} + +/// Errors if: +/// - Address does not match PDA derived from provided seeds. +/// - Cannot load as an uninitialized account. +pub fn load_uninitialized_pda<'a, 'info>( + info: &'a AccountInfo<'info>, + seeds: &[&[u8]], + bump: u8, + program_id: &Pubkey, +) -> Result<(), ProgramError> { + let pda = Pubkey::find_program_address(seeds, program_id); + + if info.key.ne(&pda.0) { + return Err(ProgramError::InvalidSeeds); + } + + if bump.ne(&pda.1) { + return Err(ProgramError::InvalidSeeds); + } + + load_system_account(info, true) +} + +/// Errors if: +/// - Owner is not the system program. +/// - Data is not empty. +/// - Account is not writable. +pub fn load_system_account<'a, 'info>( + info: &'a AccountInfo<'info>, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.owner.ne(&system_program::id()) { + return Err(ProgramError::InvalidAccountOwner); + } + + if !info.data_is_empty() { + return Err(ProgramError::AccountAlreadyInitialized); + } + + if is_writable && !info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + Ok(()) +} + +/// Errors if: +/// - Owner is not the sysvar address. +/// - Account cannot load with the expected address. +pub fn load_sysvar<'a, 'info>( + info: &'a AccountInfo<'info>, + key: Pubkey, +) -> Result<(), ProgramError> { + if info.owner.ne(&sysvar::id()) { + return Err(ProgramError::InvalidAccountOwner); + } + + load_account(info, key, false) +} + +/// Errors if: +/// - Address does not match the expected value. +/// - Expected to be writable, but is not. +pub fn load_account<'a, 'info>( + info: &'a AccountInfo<'info>, + key: Pubkey, + is_writable: bool, +) -> Result<(), ProgramError> { + if info.key.ne(&key) { + return Err(ProgramError::InvalidAccountData); + } + + if is_writable && !info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + Ok(()) +} + +/// Errors if: +/// - Address does not match the expected value. +/// - Account is not executable. +pub fn load_program<'a, 'info>( + info: &'a AccountInfo<'info>, + key: Pubkey, +) -> Result<(), ProgramError> { + if info.key.ne(&key) { + return Err(ProgramError::IncorrectProgramId); + } + + if !info.executable { + return Err(ProgramError::InvalidAccountData); + } + + Ok(()) +} diff --git a/src/processor/claim.rs b/core/program/src/processor/claim.rs similarity index 93% rename from src/processor/claim.rs rename to core/program/src/processor/claim.rs index f41cf0d..554f824 100644 --- a/src/processor/claim.rs +++ b/core/program/src/processor/claim.rs @@ -1,12 +1,10 @@ +use ore_api::{consts::*, error::OreError, instruction::ClaimArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::{ - error::OreError, instruction::ClaimArgs, loaders::*, state::Proof, utils::AccountDeserialize, - MINT_ADDRESS, TREASURY, TREASURY_BUMP, -}; +use crate::{loaders::*, utils::AccountDeserialize}; /// Claim distributes Ore from the treasury to a miner. Its responsibilies include: /// 1. Decrement the miner's claimable balance. diff --git a/src/processor/close.rs b/core/program/src/processor/close.rs similarity index 94% rename from src/processor/close.rs rename to core/program/src/processor/close.rs index 0356341..107f1c0 100644 --- a/src/processor/close.rs +++ b/core/program/src/processor/close.rs @@ -1,9 +1,10 @@ +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, system_program, }; -use crate::{loaders::*, state::Proof, utils::AccountDeserialize}; +use crate::{loaders::*, utils::AccountDeserialize}; /// Close closes a proof account and returns the rent to the owner. Its responsibilities include: /// 1. Realloc proof account size to 0. diff --git a/src/processor/crown.rs b/core/program/src/processor/crown.rs similarity index 79% rename from src/processor/crown.rs rename to core/program/src/processor/crown.rs index 674f114..aeb1827 100644 --- a/src/processor/crown.rs +++ b/core/program/src/processor/crown.rs @@ -1,15 +1,12 @@ +use ore_api::state::{Config, Proof}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::{ - loaders::*, - state::{Config, Proof}, - utils::AccountDeserialize, -}; +use crate::{loaders::*, utils::AccountDeserialize}; -/// Crown marks an account as the top staker if their balance is greater than the last known top staker. +/// Crown flags an account as the top staker if their balance is greater than the last known top staker. pub fn process_crown<'a, 'info>( _program_id: &Pubkey, accounts: &'a [AccountInfo<'info>], @@ -31,19 +28,17 @@ pub fn process_crown<'a, 'info>( let proof_new_data = proof_new_info.data.borrow(); let proof_new = Proof::try_from_bytes(&proof_new_data)?; - // If top staker is not the default null address, then compare balances + // If top staker is the defualt null balance, skip this. if config.top_staker.ne(&Pubkey::new_from_array([0; 32])) { // Load current top staker load_any_proof(proof_info, false)?; - let proof_data = proof_info.data.borrow(); - let proof = Proof::try_from_bytes(&proof_data)?; - - // Require the provided proof account is the current top staker - if config.top_staker.ne(&proof_info.key) { + if proof_info.key.ne(&config.top_staker) { return Ok(()); } // Compare balances + let proof_data = proof_info.data.borrow(); + let proof = Proof::try_from_bytes(&proof_data)?; if proof_new.balance.lt(&proof.balance) { return Ok(()); } diff --git a/src/processor/initialize.rs b/core/program/src/processor/initialize.rs similarity index 91% rename from src/processor/initialize.rs rename to core/program/src/processor/initialize.rs index fa614eb..d4200f9 100644 --- a/src/processor/initialize.rs +++ b/core/program/src/processor/initialize.rs @@ -1,5 +1,10 @@ use std::mem::size_of; +use ore_api::{ + consts::*, + instruction::*, + state::{Bus, Config, Treasury}, +}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, @@ -11,14 +16,8 @@ use solana_program::{ use spl_token::state::Mint; use crate::{ - instruction::*, loaders::*, - state::{Bus, Config, Treasury}, - utils::create_pda, - utils::AccountDeserialize, - utils::Discriminator, - BUS, BUS_COUNT, CONFIG, INITIAL_ADMIN, INITIAL_BASE_REWARD_RATE, METADATA, METADATA_NAME, - METADATA_SYMBOL, METADATA_URI, MINT, MINT_ADDRESS, MINT_NOISE, TOKEN_DECIMALS, TREASURY, + utils::{create_pda, AccountDeserialize, Discriminator}, }; /// Initialize sets up the Ore program. Its responsibilities include: @@ -54,15 +53,15 @@ pub fn process_initialize<'a, 'info>( return Err(ProgramError::NotEnoughAccountKeys); }; load_signer(signer)?; - load_uninitialized_pda(bus_0_info, &[BUS, &[0]], args.bus_0_bump, &crate::id())?; - load_uninitialized_pda(bus_1_info, &[BUS, &[1]], args.bus_1_bump, &crate::id())?; - load_uninitialized_pda(bus_2_info, &[BUS, &[2]], args.bus_2_bump, &crate::id())?; - load_uninitialized_pda(bus_3_info, &[BUS, &[3]], args.bus_3_bump, &crate::id())?; - load_uninitialized_pda(bus_4_info, &[BUS, &[4]], args.bus_4_bump, &crate::id())?; - load_uninitialized_pda(bus_5_info, &[BUS, &[5]], args.bus_5_bump, &crate::id())?; - load_uninitialized_pda(bus_6_info, &[BUS, &[6]], args.bus_6_bump, &crate::id())?; - load_uninitialized_pda(bus_7_info, &[BUS, &[7]], args.bus_7_bump, &crate::id())?; - load_uninitialized_pda(config_info, &[CONFIG], args.config_bump, &crate::id())?; + load_uninitialized_pda(bus_0_info, &[BUS, &[0]], args.bus_0_bump, &ore_api::id())?; + load_uninitialized_pda(bus_1_info, &[BUS, &[1]], args.bus_1_bump, &ore_api::id())?; + load_uninitialized_pda(bus_2_info, &[BUS, &[2]], args.bus_2_bump, &ore_api::id())?; + load_uninitialized_pda(bus_3_info, &[BUS, &[3]], args.bus_3_bump, &ore_api::id())?; + load_uninitialized_pda(bus_4_info, &[BUS, &[4]], args.bus_4_bump, &ore_api::id())?; + load_uninitialized_pda(bus_5_info, &[BUS, &[5]], args.bus_5_bump, &ore_api::id())?; + load_uninitialized_pda(bus_6_info, &[BUS, &[6]], args.bus_6_bump, &ore_api::id())?; + load_uninitialized_pda(bus_7_info, &[BUS, &[7]], args.bus_7_bump, &ore_api::id())?; + load_uninitialized_pda(config_info, &[CONFIG], args.config_bump, &ore_api::id())?; load_uninitialized_pda( metadata_info, &[ @@ -77,9 +76,14 @@ pub fn process_initialize<'a, 'info>( mint_info, &[MINT, MINT_NOISE.as_slice()], args.mint_bump, - &crate::id(), + &ore_api::id(), + )?; + load_uninitialized_pda( + treasury_info, + &[TREASURY], + args.treasury_bump, + &ore_api::id(), )?; - load_uninitialized_pda(treasury_info, &[TREASURY], args.treasury_bump, &crate::id())?; load_system_account(treasury_tokens_info, true)?; load_program(system_program, system_program::id())?; load_program(token_program, spl_token::id())?; @@ -110,7 +114,7 @@ pub fn process_initialize<'a, 'info>( for i in 0..BUS_COUNT { create_pda( bus_infos[i], - &crate::id(), + &ore_api::id(), 8 + size_of::(), &[BUS, &[i as u8], &[bus_bumps[i]]], system_program, @@ -126,7 +130,7 @@ pub fn process_initialize<'a, 'info>( // Initialize config create_pda( config_info, - &crate::id(), + &ore_api::id(), 8 + size_of::(), &[CONFIG, &[args.config_bump]], system_program, @@ -144,7 +148,7 @@ pub fn process_initialize<'a, 'info>( // Initialize treasury create_pda( treasury_info, - &crate::id(), + &ore_api::id(), 8 + size_of::(), &[TREASURY, &[args.treasury_bump]], system_program, diff --git a/src/processor/mine.rs b/core/program/src/processor/mine.rs similarity index 95% rename from src/processor/mine.rs rename to core/program/src/processor/mine.rs index e66b8aa..d362ed0 100644 --- a/src/processor/mine.rs +++ b/core/program/src/processor/mine.rs @@ -1,6 +1,13 @@ use std::mem::size_of; use drillx::Solution; +use ore_api::{ + consts::*, + error::OreError, + event::MineEvent, + instruction::{MineArgs, OreInstruction}, + state::{Bus, Config, Proof}, +}; use solana_program::program::set_return_data; #[allow(deprecated)] use solana_program::{ @@ -18,14 +25,7 @@ use solana_program::{ sysvar::{self, instructions::load_current_index, Sysvar}, }; -use crate::{ - error::OreError, - instruction::{MineArgs, OreInstruction}, - loaders::*, - state::{Bus, Config, Proof}, - utils::{AccountDeserialize, MineEvent}, - EPOCH_DURATION, MIN_DIFFICULTY, ONE_MINUTE, TOLERANCE, -}; +use crate::{loaders::*, utils::AccountDeserialize}; /// Mine is the primary workhorse instruction of the Ore program. Its responsibilities include: /// 1. Calculate the hash from the provided nonce. @@ -162,11 +162,14 @@ pub fn process_mine<'a, 'info>( proof.total_rewards = proof.total_rewards.saturating_add(reward); // Log the mined rewards - set_return_data(bytemuck::bytes_of(&MineEvent { - difficulty: difficulty as u64, - reward: reward_actual, - timing: t.saturating_sub(t_liveness), - })); + set_return_data( + MineEvent { + difficulty: difficulty as u64, + reward: reward_actual, + timing: t.saturating_sub(t_liveness), + } + .to_bytes(), + ); Ok(()) } @@ -193,7 +196,7 @@ fn validate_transaction(msg: &[u8]) -> Result { c += num_accounts * 33; // Only allow instructions to call ore and the compute budget program. match read_pubkey(&mut c, msg)? { - crate::ID => { + ore_api::ID => { c += 2; if let Ok(ix) = OreInstruction::try_from(read_u8(&mut c, msg)?) { if let OreInstruction::Mine = ix { diff --git a/src/processor/mod.rs b/core/program/src/processor/mod.rs similarity index 100% rename from src/processor/mod.rs rename to core/program/src/processor/mod.rs diff --git a/src/processor/open.rs b/core/program/src/processor/open.rs similarity index 93% rename from src/processor/open.rs rename to core/program/src/processor/open.rs index 3f03f61..66e603a 100644 --- a/src/processor/open.rs +++ b/core/program/src/processor/open.rs @@ -1,5 +1,6 @@ use std::mem::size_of; +use ore_api::{consts::*, instruction::OpenArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, blake3::hashv, @@ -13,12 +14,8 @@ use solana_program::{ }; use crate::{ - instruction::OpenArgs, loaders::*, - state::Proof, - utils::AccountDeserialize, - utils::{create_pda, Discriminator}, - PROOF, + utils::{create_pda, AccountDeserialize, Discriminator}, }; /// Register generates a new hash chain for a prospective miner. Its responsibilities include: @@ -48,7 +45,7 @@ pub fn process_open<'a, 'info>( proof_info, &[PROOF, signer.key.as_ref()], args.bump, - &crate::id(), + &ore_api::id(), )?; load_program(system_program, system_program::id())?; load_sysvar(slot_hashes_info, sysvar::slot_hashes::id())?; @@ -56,7 +53,7 @@ pub fn process_open<'a, 'info>( // Initialize proof create_pda( proof_info, - &crate::id(), + &ore_api::id(), 8 + size_of::(), &[PROOF, signer.key.as_ref(), &[args.bump]], system_program, diff --git a/src/processor/reset.rs b/core/program/src/processor/reset.rs similarity index 96% rename from src/processor/reset.rs rename to core/program/src/processor/reset.rs index 3f2b924..dd656a3 100644 --- a/src/processor/reset.rs +++ b/core/program/src/processor/reset.rs @@ -1,3 +1,8 @@ +use ore_api::{ + consts::*, + error::OreError, + state::{Bus, Config}, +}; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, sysvar::Sysvar, @@ -5,15 +10,11 @@ use solana_program::{ use spl_token::state::Mint; use crate::{ - error::OreError, loaders::{ load_bus, load_config, load_mint, load_program, load_signer, load_token_account, load_treasury, }, - state::{Bus, Config}, utils::AccountDeserialize, - BUS_COUNT, BUS_EPOCH_REWARDS, EPOCH_DURATION, MAX_EPOCH_REWARDS, MAX_SUPPLY, MINT_ADDRESS, - SMOOTHING_FACTOR, TARGET_EPOCH_REWARDS, TREASURY, TREASURY_BUMP, }; /// Reset sets up the Ore program for the next epoch. Its responsibilities include: @@ -167,9 +168,9 @@ pub(crate) fn calculate_new_reward_rate(current_rate: u64, epoch_rewards: u64) - mod tests { use rand::{distributions::Uniform, Rng}; - use crate::{ - calculate_new_reward_rate, BUS_EPOCH_REWARDS, MAX_EPOCH_REWARDS, SMOOTHING_FACTOR, - TARGET_EPOCH_REWARDS, + use crate::calculate_new_reward_rate; + use ore_api::consts::{ + BUS_EPOCH_REWARDS, MAX_EPOCH_REWARDS, SMOOTHING_FACTOR, TARGET_EPOCH_REWARDS, }; const FUZZ_SIZE: u64 = 10_000; diff --git a/src/processor/stake.rs b/core/program/src/processor/stake.rs similarity index 94% rename from src/processor/stake.rs rename to core/program/src/processor/stake.rs index 79be3dd..d72ddb3 100644 --- a/src/processor/stake.rs +++ b/core/program/src/processor/stake.rs @@ -1,12 +1,10 @@ +use ore_api::{consts::*, instruction::StakeArgs, state::Proof}; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, }; -use crate::{ - instruction::StakeArgs, loaders::*, state::Proof, utils::AccountDeserialize, MINT_ADDRESS, - TREASURY_ADDRESS, -}; +use crate::{loaders::*, utils::AccountDeserialize}; /// Stake deposits Ore into a miner's proof account to earn multiplier. Its responsibilies include: /// 1. Transfer tokens from the miner to the treasury account. diff --git a/src/processor/update.rs b/core/program/src/processor/update.rs similarity index 90% rename from src/processor/update.rs rename to core/program/src/processor/update.rs index 246c6d8..35f384c 100644 --- a/src/processor/update.rs +++ b/core/program/src/processor/update.rs @@ -1,9 +1,10 @@ +use ore_api::state::Proof; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, }; -use crate::{loaders::*, state::Proof, utils::AccountDeserialize}; +use crate::{loaders::*, utils::AccountDeserialize}; /// Update changes the miner authority on a proof account. pub fn process_update<'a, 'info>( diff --git a/src/processor/upgrade.rs b/core/program/src/processor/upgrade.rs similarity index 95% rename from src/processor/upgrade.rs rename to core/program/src/processor/upgrade.rs index acfe18d..0f5a044 100644 --- a/src/processor/upgrade.rs +++ b/core/program/src/processor/upgrade.rs @@ -1,13 +1,11 @@ +use ore_api::{consts::*, error::OreError, instruction::StakeArgs}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, }; use spl_token::state::Mint; -use crate::{ - error::OreError, instruction::StakeArgs, loaders::*, MAX_SUPPLY, MINT_ADDRESS, MINT_V1_ADDRESS, - TREASURY, TREASURY_BUMP, -}; +use crate::loaders::*; /// Upgrade allows a user to migrate a v1 token to a v2 token one-for-one. Its responsibilies include: /// 1. Burns the v1 tokens. diff --git a/idl/ore.json b/idl/ore.json deleted file mode 100644 index 2157a96..0000000 --- a/idl/ore.json +++ /dev/null @@ -1,618 +0,0 @@ -{ - "version": "0.0.1", - "name": "ore", - "instructions": [ - { - "name": "Reset", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "signer", - "isMut": false, - "isSigner": true, - "docs": [ - "Signer" - ] - }, - { - "name": "bus0", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 0" - ] - }, - { - "name": "bus1", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 1" - ] - }, - { - "name": "bus2", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 2" - ] - }, - { - "name": "bus3", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 3" - ] - }, - { - "name": "bus4", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 4" - ] - }, - { - "name": "bus5", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 5" - ] - }, - { - "name": "bus6", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 6" - ] - }, - { - "name": "bus7", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 7" - ] - }, - { - "name": "mint", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore token mint account" - ] - }, - { - "name": "treasury", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - }, - { - "name": "treasuryTokens", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore treasury token account" - ] - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "SPL token program" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 0 - } - }, - { - "name": "Register", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "signer", - "isMut": false, - "isSigner": true, - "docs": [ - "Signer" - ] - }, - { - "name": "proof", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore miner proof account" - ] - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Solana system program" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 1 - } - }, - { - "name": "Mine", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "signer", - "isMut": false, - "isSigner": true, - "docs": [ - "Signer" - ] - }, - { - "name": "bus", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account" - ] - }, - { - "name": "proof", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore miner proof account" - ] - }, - { - "name": "treasury", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - }, - { - "name": "slotHashes", - "isMut": false, - "isSigner": false, - "docs": [ - "Solana slot hashes sysvar" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 2 - } - }, - { - "name": "Claim", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "signer", - "isMut": false, - "isSigner": true, - "docs": [ - "Signer" - ] - }, - { - "name": "beneficiary", - "isMut": true, - "isSigner": false, - "docs": [ - "Beneficiary token account" - ] - }, - { - "name": "mint", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore token mint account" - ] - }, - { - "name": "proof", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore miner proof account" - ] - }, - { - "name": "treasury", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - }, - { - "name": "treasuryTokens", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore treasury token account" - ] - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "SPL token program" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 3 - } - }, - { - "name": "Initialize", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "admin", - "isMut": false, - "isSigner": true, - "docs": [ - "Admin signer" - ] - }, - { - "name": "bus0", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 0" - ] - }, - { - "name": "bus1", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 1" - ] - }, - { - "name": "bus2", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 2" - ] - }, - { - "name": "bus3", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 3" - ] - }, - { - "name": "bus4", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 4" - ] - }, - { - "name": "bus5", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 5" - ] - }, - { - "name": "bus6", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 6" - ] - }, - { - "name": "bus7", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore bus account 7" - ] - }, - { - "name": "mint", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore token mint account" - ] - }, - { - "name": "treasury", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - }, - { - "name": "treasuryTokens", - "isMut": true, - "isSigner": false, - "docs": [ - "Ore treasury token account" - ] - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Solana system program" - ] - }, - { - "name": "tokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "SPL token program" - ] - }, - { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "SPL associated token program" - ] - }, - { - "name": "rent", - "isMut": false, - "isSigner": false, - "docs": [ - "Solana rent sysvar" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 100 - } - }, - { - "name": "UpdateAdmin", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "treasury", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 102 - } - }, - { - "name": "UpdateDifficulty", - "accounts": [ - { - "name": "oreProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore program" - ] - }, - { - "name": "treasury", - "isMut": false, - "isSigner": false, - "docs": [ - "Ore treasury account" - ] - } - ], - "args": [], - "discriminant": { - "type": "u8", - "value": 103 - } - } - ], - "accounts": [ - { - "name": "Bus", - "type": { - "kind": "struct", - "fields": [ - { - "name": "id", - "type": "u64" - }, - { - "name": "rewards", - "type": "u64" - } - ] - } - }, - { - "name": "Proof", - "type": { - "kind": "struct", - "fields": [ - { - "name": "authority", - "type": "publicKey" - }, - { - "name": "claimableRewards", - "type": "u64" - }, - { - "name": "hash", - "type": { - "defined": "Hash" - } - }, - { - "name": "totalHashes", - "type": "u64" - }, - { - "name": "totalRewards", - "type": "u64" - } - ] - } - }, - { - "name": "Treasury", - "type": { - "kind": "struct", - "fields": [ - { - "name": "admin", - "type": "publicKey" - }, - { - "name": "bump", - "type": "u64" - }, - { - "name": "difficulty", - "type": { - "defined": "Hash" - } - }, - { - "name": "epochStartAt", - "type": "i64" - }, - { - "name": "rewardRate", - "type": "u64" - }, - { - "name": "totalClaimedRewards", - "type": "u64" - } - ] - } - } - ], - "errors": [ - { - "code": 0, - "name": "EpochActive", - "msg": "The epoch is still active and cannot be reset" - }, - { - "code": 1, - "name": "EpochExpired", - "msg": "The epoch has expired and needs reset" - }, - { - "code": 2, - "name": "InvalidHash", - "msg": "The provided hash was invalid" - }, - { - "code": 3, - "name": "InsufficientHashDifficulty", - "msg": "The provided hash does not satisfy the difficulty requirement" - }, - { - "code": 4, - "name": "InsufficientBusRewards", - "msg": "The bus has insufficient rewards to mine at this time" - }, - { - "code": 5, - "name": "InvalidClaimAmount", - "msg": "The claim amount cannot be larger than the claimable rewards" - } - ], - "metadata": { - "origin": "shank", - "address": "ore2mSzJwAZhxLyCLbNEnFvYq9U8jvCMvUBrVvbmqDF" - } -} \ No newline at end of file diff --git a/src/loaders.rs b/src/loaders.rs deleted file mode 100644 index dd53166..0000000 --- a/src/loaders.rs +++ /dev/null @@ -1,1366 +0,0 @@ -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, - system_program, sysvar, -}; -use spl_token::state::Mint; - -use crate::{ - state::{Bus, Config, Proof, Treasury}, - utils::{AccountDeserialize, Discriminator}, - BUS_ADDRESSES, CONFIG_ADDRESS, TREASURY_ADDRESS, -}; - -/// Errors if: -/// - Account is not a signer. -pub fn load_signer<'a, 'info>(info: &'a AccountInfo<'info>) -> Result<(), ProgramError> { - if !info.is_signer { - return Err(ProgramError::MissingRequiredSignature); - } - - Ok(()) -} - -/// 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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<'a, 'info>( - info: &'a AccountInfo<'info>, - 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(()) -} - -/// Errors if: -/// - Owner is not Ore program. -/// - Address does not match the expected address. -/// - Data is empty. -/// - Data cannot deserialize into a treasury account. -/// - Expected to be writable, but is not. -pub fn load_treasury<'a, 'info>( - info: &'a AccountInfo<'info>, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&crate::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.key.ne(&TREASURY_ADDRESS) { - return Err(ProgramError::InvalidSeeds); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - if info.data.borrow()[0].ne(&(Treasury::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 SPL token program. -/// - Address does not match the expected mint address. -/// - Data is empty. -/// - Data cannot deserialize into a mint account. -/// - Expected to be writable, but is not. -pub fn load_mint<'a, 'info>( - info: &'a AccountInfo<'info>, - address: Pubkey, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&spl_token::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.key.ne(&address) { - return Err(ProgramError::InvalidSeeds); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - if Mint::unpack_unchecked(&info.data.borrow()).is_err() { - return Err(ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not SPL token program. -/// - Data is empty. -/// - Data cannot deserialize into a token account. -/// - Token account owner does not match the expected owner address. -/// - Token account mint does not match the expected mint address. -/// - Expected to be writable, but is not. -pub fn load_token_account<'a, 'info>( - info: &'a AccountInfo<'info>, - owner: Option<&Pubkey>, - mint: &Pubkey, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&spl_token::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if info.data_is_empty() { - return Err(ProgramError::UninitializedAccount); - } - - let account_data = info.data.borrow(); - let account = spl_token::state::Account::unpack_unchecked(&account_data) - .or(Err(ProgramError::InvalidAccountData))?; - - if account.mint.ne(&mint) { - return Err(ProgramError::InvalidAccountData); - } - - if let Some(owner) = owner { - if account.owner.ne(owner) { - return Err(ProgramError::InvalidAccountData); - } - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Address does not match PDA derived from provided seeds. -/// - Cannot load as an uninitialized account. -pub fn load_uninitialized_pda<'a, 'info>( - info: &'a AccountInfo<'info>, - seeds: &[&[u8]], - bump: u8, - program_id: &Pubkey, -) -> Result<(), ProgramError> { - let pda = Pubkey::find_program_address(seeds, program_id); - - if info.key.ne(&pda.0) { - return Err(ProgramError::InvalidSeeds); - } - - if bump.ne(&pda.1) { - return Err(ProgramError::InvalidSeeds); - } - - load_system_account(info, true) -} - -/// Errors if: -/// - Owner is not the system program. -/// - Data is not empty. -/// - Account is not writable. -pub fn load_system_account<'a, 'info>( - info: &'a AccountInfo<'info>, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.owner.ne(&system_program::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - if !info.data_is_empty() { - return Err(ProgramError::AccountAlreadyInitialized); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Owner is not the sysvar address. -/// - Account cannot load with the expected address. -pub fn load_sysvar<'a, 'info>( - info: &'a AccountInfo<'info>, - key: Pubkey, -) -> Result<(), ProgramError> { - if info.owner.ne(&sysvar::id()) { - return Err(ProgramError::InvalidAccountOwner); - } - - load_account(info, key, false) -} - -/// Errors if: -/// - Address does not match the expected value. -/// - Expected to be writable, but is not. -pub fn load_account<'a, 'info>( - info: &'a AccountInfo<'info>, - key: Pubkey, - is_writable: bool, -) -> Result<(), ProgramError> { - if info.key.ne(&key) { - return Err(ProgramError::InvalidAccountData); - } - - if is_writable && !info.is_writable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -/// Errors if: -/// - Address does not match the expected value. -/// - Account is not executable. -pub fn load_program<'a, 'info>( - info: &'a AccountInfo<'info>, - key: Pubkey, -) -> Result<(), ProgramError> { - if info.key.ne(&key) { - return Err(ProgramError::IncorrectProgramId); - } - - if !info.executable { - return Err(ProgramError::InvalidAccountData); - } - - Ok(()) -} - -// #[cfg(test)] -// mod tests { -// use solana_program::{ -// account_info::AccountInfo, keccak::Hash as KeccakHash, program_option::COption, -// program_pack::Pack, pubkey::Pubkey, system_program, -// }; -// use spl_token::state::{AccountState, Mint}; - -// use crate::{ -// loaders::{ -// load_account, load_any_bus, load_bus, load_mint, load_proof, load_signer, load_sysvar, -// load_token_account, load_treasury, load_uninitialized_account, load_uninitialized_pda, -// }, -// state::{Bus, Proof, Treasury}, -// utils::Discriminator, -// BUS, BUS_ADDRESSES, BUS_COUNT, MINT_ADDRESS, PROOF, TOKEN_DECIMALS, TREASURY, -// TREASURY_ADDRESS, -// }; - -// use super::load_program; - -// #[test] -// pub fn test_signer_not_signer() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_signer(&info).is_err()); -// } - -// #[test] -// pub fn test_load_bus_bad_account_owner() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_bus_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_bus_empty_data() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_bus_bad_data() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Treasury::discriminator() as u64).to_le_bytes(), // Bus discriminator -// Bus { id: 0, rewards: 0 }.to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_bus_bad_id() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), // Bus discriminator -// Bus { id: 1, rewards: 0 }.to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_bus_not_writeable() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { id: 0, rewards: 0 }.to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_bus(&info, 0, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_bad_account_owner() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_empty_data() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_bad_data() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Treasury::discriminator() as u64).to_le_bytes(), // Treasury discriminator -// Bus { id: 0, rewards: 0 }.to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_bad_id() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { -// id: (BUS_COUNT + 1) as u64, -// rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_mismatch_id() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { -// id: 1 as u64, -// rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_any_bus_not_writeable() { -// let key = BUS_ADDRESSES[0]; -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { id: 0, rewards: 0 }.to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_any_bus(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_proof_bad_account_owner() { -// let authority = Pubkey::new_unique(); -// let pda = Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_proof(&info, &authority, true).is_err()); -// } - -// #[test] -// pub fn test_load_proof_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_proof(&info, &Pubkey::new_unique(), true).is_err()); -// } - -// #[test] -// pub fn test_load_proof_empty_data() { -// let authority = Pubkey::new_unique(); -// let pda = Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_proof(&info, &authority, true).is_err()); -// } - -// #[test] -// pub fn test_load_proof_bad_data() { -// let authority = Pubkey::new_unique(); -// let pda = Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), // Bus discriminator -// Proof { -// authority, -// balance: 0, -// hash: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// total_hashes: 0, -// total_rewards: 0, -// multiplier: 1, -// last_hash_at: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_proof(&info, &authority, true).is_err()); -// } - -// #[test] -// pub fn test_load_proof_not_writeable() { -// let authority = Pubkey::new_unique(); -// let pda = Pubkey::find_program_address(&[PROOF, authority.as_ref()], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Proof::discriminator() as u64).to_le_bytes(), -// Proof { -// authority, -// claimable_rewards: 0, -// hash: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// total_hashes: 0, -// total_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_proof(&info, &authority, true).is_err()); -// } - -// #[test] -// pub fn test_load_treasury_bad_account_owner() { -// let pda = Pubkey::find_program_address(&[TREASURY], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_treasury(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_treasury_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_treasury(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_treasury_empty_data() { -// let key = TREASURY_ADDRESS; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = crate::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_treasury(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_treasury_bad_data() { -// let pda = Pubkey::find_program_address(&[TREASURY], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Bus::discriminator() as u64).to_le_bytes(), // Bus discriminator -// Treasury { -// bump: pda.1 as u64, -// // admin: Pubkey::new_unique(), -// // difficulty: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// last_reset_at: 0, -// reward_rate: 100, -// total_claimed_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_treasury(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_treasury_not_writeable() { -// let pda = Pubkey::find_program_address(&[TREASURY], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = [ -// &(Treasury::discriminator() as u64).to_le_bytes(), -// Treasury { -// bump: pda.1 as u64, -// // admin: Pubkey::new_unique(), -// // difficulty: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// last_reset_at: 0, -// reward_rate: 100, -// total_claimed_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(); -// let owner = crate::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_treasury(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_mint_bad_account_owner() { -// let key = MINT_ADDRESS; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_token_account(&info, None, &MINT_ADDRESS, true).is_err()); -// } - -// #[test] -// pub fn test_load_mint_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_mint(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_mint_empty_data() { -// let key = MINT_ADDRESS; -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_mint(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_mint_bad_data() { -// let key = MINT_ADDRESS; -// let mut lamports = 1_000_000_000; -// let mut data = [1]; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_mint(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_mint_not_writeable() { -// let mut data: [u8; Mint::LEN] = [0; Mint::LEN]; -// Mint { -// mint_authority: COption::Some(TREASURY_ADDRESS), -// supply: 0, -// decimals: TOKEN_DECIMALS, -// is_initialized: true, -// freeze_authority: COption::None, -// } -// .pack_into_slice(&mut data); -// let key = MINT_ADDRESS; -// let mut lamports = 1_000_000_000; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_mint(&info, true).is_err()); -// } - -// #[test] -// pub fn test_load_token_account_bad_account_owner() { -// let mut data: [u8; spl_token::state::Account::LEN] = [0; spl_token::state::Account::LEN]; -// spl_token::state::Account { -// mint: MINT_ADDRESS, -// owner: TREASURY_ADDRESS, -// amount: 2_000_000_000, -// delegate: COption::None, -// state: AccountState::Initialized, -// is_native: COption::None, -// delegated_amount: 0, -// close_authority: COption::None, -// } -// .pack_into_slice(&mut data); -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_token_account(&info, None, &MINT_ADDRESS, true).is_err()); -// } - -// #[test] -// pub fn test_load_token_account_empty_data() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_token_account(&info, None, &MINT_ADDRESS, true).is_err()); -// } - -// #[test] -// pub fn test_load_token_account_bad_data() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = [1]; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_token_account(&info, None, &MINT_ADDRESS, true).is_err()); -// } - -// #[test] -// pub fn test_load_token_account_bad_owner_mint() { -// let mut data: [u8; spl_token::state::Account::LEN] = [0; spl_token::state::Account::LEN]; -// spl_token::state::Account { -// mint: MINT_ADDRESS, -// owner: TREASURY_ADDRESS, -// amount: 2_000_000_000, -// delegate: COption::None, -// state: AccountState::Initialized, -// is_native: COption::None, -// delegated_amount: 0, -// close_authority: COption::None, -// } -// .pack_into_slice(&mut data); -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_token_account(&info, Some(&key), &MINT_ADDRESS, false).is_err()); -// assert!(load_token_account(&info, None, &Pubkey::new_unique(), false).is_err()); -// assert!(load_token_account(&info, None, &MINT_ADDRESS, true).is_err()); -// } - -// #[test] -// pub fn test_load_uninitialized_pda_bad_key_bump() { -// let pda = Pubkey::find_program_address(&[TREASURY], &crate::id()); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &pda.0, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_uninitialized_pda(&info, &[BUS], pda.1, &crate::id()).is_err()); -// assert!(load_uninitialized_pda(&info, &[TREASURY], 0, &crate::id()).is_err()); -// } - -// #[test] -// pub fn test_load_uninitialized_account_bad_owner() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = spl_token::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_uninitialized_account(&info).is_err()); -// } - -// #[test] -// pub fn test_load_uninitialized_account_data_not_empty() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = [0]; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// true, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_uninitialized_account(&info).is_err()); -// } - -// #[test] -// pub fn test_load_uninitialized_account_not_writeable() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_uninitialized_account(&info).is_err()); -// } - -// #[test] -// pub fn test_load_sysvar_bad_owner() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_sysvar(&info, key).is_err()); -// } - -// #[test] -// pub fn test_load_account_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_account(&info, Pubkey::new_unique(), false).is_err()); -// } - -// #[test] -// pub fn test_load_account_not_writeable() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_account(&info, key, true).is_err()); -// } - -// #[test] -// pub fn test_load_program_bad_key() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// true, -// 0, -// ); -// assert!(load_program(&info, Pubkey::new_unique()).is_err()); -// } - -// #[test] -// pub fn test_load_program_not_executable() { -// let key = Pubkey::new_unique(); -// let mut lamports = 1_000_000_000; -// let mut data = []; -// let owner = system_program::id(); -// let info = AccountInfo::new( -// &key, -// false, -// false, -// &mut lamports, -// &mut data, -// &owner, -// false, -// 0, -// ); -// assert!(load_program(&info, key).is_err()); -// } -// } diff --git a/src/state/mod.rs b/src/state/mod.rs deleted file mode 100644 index 7a3b009..0000000 --- a/src/state/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod bus; -mod config; -mod proof; -mod treasury; - -pub use bus::*; -pub use config::*; -pub use proof::*; -pub use treasury::*; diff --git a/stake/api/Cargo.toml b/stake/api/Cargo.toml new file mode 100644 index 0000000..e69de29 diff --git a/stake/api/src/lib.rs b/stake/api/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/stake/program/Cargo.toml b/stake/program/Cargo.toml new file mode 100644 index 0000000..e69de29 diff --git a/stake/program/src/lib.rs b/stake/program/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/buffers/metadata_program.bpf b/tests/buffers/metadata_program.bpf deleted file mode 100644 index 3ebd1b6..0000000 Binary files a/tests/buffers/metadata_program.bpf and /dev/null differ diff --git a/tests/test_initialize.rs b/tests/test_initialize.rs deleted file mode 100644 index 9e6a840..0000000 --- a/tests/test_initialize.rs +++ /dev/null @@ -1,170 +0,0 @@ -// use mpl_token_metadata::{ -// accounts::Metadata, -// types::{Key, TokenStandard}, -// }; -// use ore::{ -// state::{Bus, Treasury}, -// utils::AccountDeserialize, -// BUS_ADDRESSES, BUS_COUNT, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, METADATA_ADDRESS, -// METADATA_NAME, METADATA_SYMBOL, METADATA_URI, MINT_ADDRESS, TREASURY, -// }; -// use solana_program::{ -// hash::Hash, program_option::COption, program_pack::Pack, pubkey::Pubkey, rent::Rent, -// }; -// use solana_program_test::{processor, read_file, BanksClient, ProgramTest}; -// use solana_sdk::{ -// account::Account, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; -// use spl_token::state::{AccountState, Mint}; - -// #[tokio::test] -// async fn test_initialize() { -// // Setup -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Pdas -// let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); -// let treasury_tokens_address = -// spl_associated_token_account::get_associated_token_address(&treasury_pda.0, &MINT_ADDRESS); - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Test bus state -// for i in 0..BUS_COUNT { -// let bus_account = banks.get_account(BUS_ADDRESSES[i]).await.unwrap().unwrap(); -// assert_eq!(bus_account.owner, ore::id()); -// let bus = Bus::try_from_bytes(&bus_account.data).unwrap(); -// assert_eq!(bus.id as u8, i as u8); -// assert_eq!(bus.rewards, 0); -// } - -// // Test treasury state -// let treasury_account = banks.get_account(treasury_pda.0).await.unwrap().unwrap(); -// assert_eq!(treasury_account.owner, ore::id()); -// let treasury = Treasury::try_from_bytes(&treasury_account.data).unwrap(); -// assert_eq!(treasury.bump as u8, treasury_pda.1); -// // assert_eq!(treasury.admin, payer.pubkey()); -// // assert_eq!(treasury.difficulty, INITIAL_DIFFICULTY.into()); -// assert_eq!(treasury.last_reset_at as u8, 0); -// assert_eq!(treasury.reward_rate, INITIAL_REWARD_RATE); -// assert_eq!(treasury.total_claimed_rewards as u8, 0); - -// // Test mint state -// let mint_account = banks.get_account(MINT_ADDRESS).await.unwrap().unwrap(); -// assert_eq!(mint_account.owner, spl_token::id()); -// let mint = Mint::unpack(&mint_account.data).unwrap(); -// assert_eq!(mint.mint_authority, COption::Some(treasury_pda.0)); -// assert_eq!(mint.supply, 0); -// assert_eq!(mint.decimals, ore::TOKEN_DECIMALS); -// assert_eq!(mint.is_initialized, true); -// assert_eq!(mint.freeze_authority, COption::None); - -// // Test metadata state -// let metadata_account = banks.get_account(METADATA_ADDRESS).await.unwrap().unwrap(); -// assert_eq!(metadata_account.owner, mpl_token_metadata::ID); -// let metadata = Metadata::from_bytes(&metadata_account.data).unwrap(); -// assert_eq!(metadata.key, Key::MetadataV1); -// assert_eq!(metadata.update_authority, payer.pubkey()); -// assert_eq!(metadata.mint, MINT_ADDRESS); -// assert_eq!(metadata.name.trim_end_matches('\0'), METADATA_NAME); -// assert_eq!(metadata.symbol.trim_end_matches('\0'), METADATA_SYMBOL); -// assert_eq!(metadata.uri.trim_end_matches('\0'), METADATA_URI); -// assert_eq!(metadata.seller_fee_basis_points, 0); -// assert_eq!(metadata.creators, None); -// assert_eq!(metadata.primary_sale_happened, false); -// assert_eq!(metadata.is_mutable, true); -// assert_eq!(metadata.token_standard, Some(TokenStandard::Fungible)); -// assert_eq!(metadata.collection, None); -// assert_eq!(metadata.uses, None); -// assert_eq!(metadata.collection_details, None); -// assert_eq!(metadata.programmable_config, None); - -// // Test treasury token state -// let treasury_tokens_account = banks -// .get_account(treasury_tokens_address) -// .await -// .unwrap() -// .unwrap(); -// assert_eq!(treasury_tokens_account.owner, spl_token::id()); -// let treasury_tokens = spl_token::state::Account::unpack(&treasury_tokens_account.data).unwrap(); -// assert_eq!(treasury_tokens.mint, MINT_ADDRESS); -// assert_eq!(treasury_tokens.owner, treasury_pda.0); -// assert_eq!(treasury_tokens.amount, 0); -// assert_eq!(treasury_tokens.delegate, COption::None); -// assert_eq!(treasury_tokens.state, AccountState::Initialized); -// assert_eq!(treasury_tokens.is_native, COption::None); -// assert_eq!(treasury_tokens.delegated_amount, 0); -// assert_eq!(treasury_tokens.close_authority, COption::None); -// } - -// #[tokio::test] -// async fn test_initialize_not_enough_accounts() { -// // Setup -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let mut ix = ore::instruction::initialize(payer.pubkey()); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_initialize_bad_key() { -// // Setup -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Bad addresses -// let bad_pda = Pubkey::find_program_address(&[b"t"], &ore::id()); -// for i in 1..12 { -// let mut ix = ore::instruction::initialize(payer.pubkey()); -// ix.accounts[i].pubkey = bad_pda.0; -// let tx = -// Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } -// } - -// #[tokio::test] -// async fn test_initialize_bad_programs() { -// // Setup -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Bad addresses -// for i in 13..18 { -// let mut ix = ore::instruction::initialize(payer.pubkey()); -// ix.accounts[i].pubkey = Pubkey::new_unique(); -// let tx = -// Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } -// } - -// async fn setup_program_test_env() -> (BanksClient, Keypair, Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Setup metadata program -// let data = read_file(&"tests/buffers/metadata_program.bpf"); -// program_test.add_account( -// mpl_token_metadata::ID, -// Account { -// lamports: Rent::default().minimum_balance(data.len()).max(1), -// data, -// owner: solana_sdk::bpf_loader::id(), -// executable: true, -// rent_epoch: 0, -// }, -// ); - -// program_test.start().await -// } diff --git a/tests/test_mine.rs b/tests/test_mine.rs deleted file mode 100644 index ae10349..0000000 --- a/tests/test_mine.rs +++ /dev/null @@ -1,746 +0,0 @@ -// use std::{mem::size_of, str::FromStr}; - -// use ore::{ -// instruction::{MineArgs, OreInstruction}, -// state::{Bus, Proof, Treasury}, -// utils::{AccountDeserialize, Discriminator}, -// BUS_ADDRESSES, BUS_COUNT, EPOCH_DURATION, INITIAL_REWARD_RATE, MINT_ADDRESS, PROOF, START_AT, -// TOKEN_DECIMALS, TREASURY, TREASURY_ADDRESS, -// }; -// use rand::{distributions::Uniform, Rng}; -// use solana_program::{ -// clock::Clock, -// epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, -// hash::Hash, -// instruction::{AccountMeta, Instruction}, -// keccak::{hashv, Hash as KeccakHash}, -// native_token::LAMPORTS_PER_SOL, -// program_option::COption, -// program_pack::Pack, -// pubkey::Pubkey, -// slot_hashes::SlotHash, -// system_program, sysvar, -// }; -// use solana_program_test::{processor, BanksClient, ProgramTest}; -// use solana_sdk::{ -// account::Account, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; -// use spl_associated_token_account::{ -// get_associated_token_address, instruction::create_associated_token_account, -// }; -// use spl_token::state::{AccountState, Mint}; - -// #[tokio::test] -// async fn test_mine() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert proof state -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// assert_eq!(proof_account.owner, ore::id()); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// assert_eq!(proof.authority, payer.pubkey()); -// assert_eq!(proof.claimable_rewards, 0); -// assert_eq!(proof.total_hashes, 0); -// assert_eq!(proof.total_rewards, 0); - -// // Find next hash -// let (next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); - -// // Submit mine tx -// let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert proof state -// let slot_hashes_account = banks -// .get_account(sysvar::slot_hashes::id()) -// .await -// .unwrap() -// .unwrap(); -// let slot_hash_bytes = &slot_hashes_account.data[0..size_of::()]; -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// assert_eq!(proof_account.owner, ore::id()); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// assert_eq!(proof.authority, payer.pubkey()); -// assert_eq!(proof.claimable_rewards, INITIAL_REWARD_RATE); -// assert_eq!( -// proof.hash, -// hashv(&[&next_hash.as_ref(), slot_hash_bytes,]).into() -// ); -// assert_eq!(proof.total_hashes, 1); -// assert_eq!(proof.total_rewards, INITIAL_REWARD_RATE); - -// // Submit claim tx -// let amount = proof.claimable_rewards; -// let beneficiary_address = get_associated_token_address(&payer.pubkey(), &ore::MINT_ADDRESS); -// let token_ix = create_associated_token_account( -// &payer.pubkey(), -// &payer.pubkey(), -// &ore::MINT_ADDRESS, -// &spl_token::id(), -// ); -// let ix = ore::instruction::claim(payer.pubkey(), beneficiary_address, amount); -// let tx = Transaction::new_signed_with_payer( -// &[token_ix, ix], -// Some(&payer.pubkey()), -// &[&payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert proof state -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof_ = Proof::try_from_bytes(&proof_account.data).unwrap(); -// assert_eq!(proof_.authority, proof.authority); -// assert_eq!(proof_.claimable_rewards, 0); -// assert_eq!(proof_.hash, proof.hash); -// assert_eq!(proof_.total_hashes, proof.total_hashes); -// assert_eq!(proof_.total_rewards, proof.total_rewards); - -// // Assert beneficiary state -// let beneficiary_account = banks -// .get_account(beneficiary_address) -// .await -// .unwrap() -// .unwrap(); -// assert_eq!(beneficiary_account.owner, spl_token::id()); -// let beneficiary = spl_token::state::Account::unpack(&beneficiary_account.data).unwrap(); -// assert_eq!(beneficiary.mint, ore::MINT_ADDRESS); -// assert_eq!(beneficiary.owner, payer.pubkey()); -// assert_eq!(beneficiary.amount, amount); -// assert_eq!(beneficiary.delegate, COption::None); -// assert_eq!(beneficiary.state, AccountState::Initialized); -// assert_eq!(beneficiary.is_native, COption::None); -// assert_eq!(beneficiary.delegated_amount, 0); -// assert_eq!(beneficiary.close_authority, COption::None); -// } - -// #[tokio::test] -// async fn test_mine_alt_proof() { -// // Setup -// let (mut banks, payer, payer_alt, blockhash) = -// setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit register alt tx -// let proof_alt_pda = -// Pubkey::find_program_address(&[PROOF, payer_alt.pubkey().as_ref()], &ore::id()); -// let ix_alt = ore::instruction::register(payer_alt.pubkey()); -// let tx = Transaction::new_signed_with_payer( -// &[ix_alt], -// Some(&payer_alt.pubkey()), -// &[&payer_alt], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit mine tx with invalid proof -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(payer.pubkey(), true), -// AccountMeta::new(BUS_ADDRESSES[0], false), -// AccountMeta::new(proof_alt_pda.0, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), -// ], -// data: [ -// OreInstruction::Mine.to_vec(), -// MineArgs { -// nonce: nonce.to_le_bytes(), -// } -// .to_bytes() -// .to_vec(), -// ] -// .concat(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_correct_hash_alt_proof() { -// // Setup -// let (mut banks, payer, payer_alt, blockhash) = -// setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register alt tx -// let proof_alt_pda = -// Pubkey::find_program_address(&[PROOF, payer_alt.pubkey().as_ref()], &ore::id()); -// let ix_alt = ore::instruction::register(payer_alt.pubkey()); -// let tx = Transaction::new_signed_with_payer( -// &[ix_alt], -// Some(&payer_alt.pubkey()), -// &[&payer_alt], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit with correct hash for invalid proof -// let proof_alt_account = banks.get_account(proof_alt_pda.0).await.unwrap().unwrap(); -// let proof_alt = Proof::try_from_bytes(&proof_alt_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof_alt.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer_alt.pubkey(), -// ); -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(payer.pubkey(), true), -// AccountMeta::new(BUS_ADDRESSES[0], false), -// AccountMeta::new(proof_alt_pda.0, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), -// ], -// data: [ -// OreInstruction::Mine.to_vec(), -// MineArgs { -// nonce: nonce.to_le_bytes(), -// } -// .to_bytes() -// .to_vec(), -// ] -// .concat(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_bus_rewards_insufficient() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(false, ClockState::Normal).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Find next hash -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); - -// // Submit mine tx -// let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_claim_too_large() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit claim tx -// let beneficiary = get_associated_token_address(&payer.pubkey(), &ore::MINT_ADDRESS); -// let token_ix = create_associated_token_account( -// &payer.pubkey(), -// &payer.pubkey(), -// &ore::MINT_ADDRESS, -// &spl_token::id(), -// ); -// let ix = ore::instruction::claim(payer.pubkey(), beneficiary, 1); -// let tx = Transaction::new_signed_with_payer( -// &[token_ix, ix], -// Some(&payer.pubkey()), -// &[&payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_claim_other_proof() { -// // Setup -// let (mut banks, payer, alt_payer, blockhash) = -// setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit claim tx -// let beneficiary = get_associated_token_address(&alt_payer.pubkey(), &ore::MINT_ADDRESS); -// let token_ix = create_associated_token_account( -// &alt_payer.pubkey(), -// &alt_payer.pubkey(), -// &ore::MINT_ADDRESS, -// &spl_token::id(), -// ); -// let mut ix = ore::instruction::claim(payer.pubkey(), beneficiary, 0); -// ix.accounts[0].pubkey = alt_payer.pubkey(); -// let tx = Transaction::new_signed_with_payer( -// &[token_ix, ix], -// Some(&alt_payer.pubkey()), -// &[&alt_payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_not_enough_accounts() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Find next hash -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); - -// // Submit mine tx -// let mut ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_too_early() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::TooEarly).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Find next hash -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); - -// // Submit mine tx -// let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_needs_reset() { -// // Setup -// let (mut banks, payer, _, blockhash) = -// setup_program_test_env(true, ClockState::NeedsReset).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Find next hash -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); - -// // Submit mine tx -// let ix = ore::instruction::mine(payer.pubkey(), BUS_ADDRESSES[0], nonce); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_claim_not_enough_accounts() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit claim tx -// let beneficiary = get_associated_token_address(&payer.pubkey(), &ore::MINT_ADDRESS); -// let token_ix = create_associated_token_account( -// &payer.pubkey(), -// &payer.pubkey(), -// &ore::MINT_ADDRESS, -// &spl_token::id(), -// ); -// let mut ix = ore::instruction::claim(payer.pubkey(), beneficiary, 0); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer( -// &[token_ix, ix], -// Some(&payer.pubkey()), -// &[&payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_mine_fail_bad_data() { -// // Setup -// const FUZZ: usize = 10; -// let (mut banks, payer, _, blockhash) = setup_program_test_env(true, ClockState::Normal).await; - -// // Submit register tx -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let ix = ore::instruction::register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Get proof -// let proof_account = banks.get_account(proof_pda.0).await.unwrap().unwrap(); -// let proof = Proof::try_from_bytes(&proof_account.data).unwrap(); - -// // Shared variables for tests. -// let mut rng = rand::thread_rng(); -// let (_next_hash, nonce) = find_next_hash( -// proof.hash.into(), -// KeccakHash::new_from_array([u8::MAX; 32]), -// payer.pubkey(), -// ); -// let signer = payer.pubkey(); -// let proof_address = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &ore::id()).0; - -// // Fuzz randomized instruction data -// for _ in 0..FUZZ { -// let length_range = Uniform::from(5..=256); -// let length = rng.sample(length_range); -// let random_bytes: Vec = (0..length).map(|_| rng.gen()).collect(); -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(signer, true), -// AccountMeta::new(BUS_ADDRESSES[0], false), -// AccountMeta::new(proof_address, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new_readonly(sysvar::slot_hashes::id(), false), -// ], -// data: [OreInstruction::Mine.to_vec(), random_bytes].concat(), -// }; -// let tx = -// Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// // Fuzz test random bus addresses -// for _ in 0..FUZZ { -// assert_mine_tx_err( -// &mut banks, -// &payer, -// blockhash, -// payer.pubkey(), -// Pubkey::new_unique(), -// proof_address, -// TREASURY_ADDRESS, -// sysvar::slot_hashes::id(), -// nonce, -// ) -// .await; -// } - -// // Fuzz test random proof addresses -// for _ in 0..FUZZ { -// assert_mine_tx_err( -// &mut banks, -// &payer, -// blockhash, -// payer.pubkey(), -// BUS_ADDRESSES[0], -// Pubkey::new_unique(), -// TREASURY_ADDRESS, -// sysvar::slot_hashes::id(), -// nonce, -// ) -// .await; -// } - -// // Mix up the proof and treasury addresses -// assert_mine_tx_err( -// &mut banks, -// &payer, -// blockhash, -// payer.pubkey(), -// BUS_ADDRESSES[0], -// TREASURY_ADDRESS, -// proof_address, -// sysvar::slot_hashes::id(), -// nonce, -// ) -// .await; - -// // Pass an invalid sysvar -// assert_mine_tx_err( -// &mut banks, -// &payer, -// blockhash, -// payer.pubkey(), -// BUS_ADDRESSES[0], -// proof_address, -// TREASURY_ADDRESS, -// sysvar::clock::id(), -// nonce, -// ) -// .await; -// } - -// async fn assert_mine_tx_err( -// banks: &mut BanksClient, -// payer: &Keypair, -// blockhash: Hash, -// signer: Pubkey, -// bus: Pubkey, -// proof: Pubkey, -// treasury: Pubkey, -// slot_hash: Pubkey, -// nonce: u64, -// ) { -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(signer, true), -// AccountMeta::new(bus, false), -// AccountMeta::new(proof, false), -// AccountMeta::new(treasury, false), -// AccountMeta::new_readonly(slot_hash, false), -// ], -// data: [ -// OreInstruction::Mine.to_vec(), -// MineArgs { -// nonce: nonce.to_le_bytes(), -// } -// .to_bytes() -// .to_vec(), -// ] -// .concat(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// fn find_next_hash(hash: KeccakHash, difficulty: KeccakHash, signer: Pubkey) -> (KeccakHash, u64) { -// let mut next_hash: KeccakHash; -// let mut nonce = 0u64; -// loop { -// next_hash = hashv(&[ -// nonce.to_le_bytes().as_slice(), -// hash.to_bytes().as_slice(), -// signer.to_bytes().as_slice(), -// ]); -// if next_hash.le(&difficulty) { -// break; -// } else { -// println!("Invalid hash: {} Nonce: {:?}", next_hash.to_string(), nonce); -// } -// nonce += 1; -// } -// (next_hash, nonce) -// } - -// enum ClockState { -// Normal, -// TooEarly, -// NeedsReset, -// } - -// async fn setup_program_test_env( -// funded_busses: bool, -// clock_state: ClockState, -// ) -> (BanksClient, Keypair, Keypair, solana_program::hash::Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Busses -// for i in 0..BUS_COUNT { -// program_test.add_account_with_base64_data( -// BUS_ADDRESSES[i], -// 1057920, -// ore::id(), -// bs64::encode( -// &[ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { -// id: i as u64, -// rewards: if funded_busses { 250_000_000 } else { 0 }, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); -// } - -// // Treasury -// let admin_address = Pubkey::from_str("AeNqnoLwFanMd3ig9WoMxQZVwQHtCtqKMMBsT1sTrvz6").unwrap(); -// let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); -// program_test.add_account_with_base64_data( -// treasury_pda.0, -// 1614720, -// ore::id(), -// bs64::encode( -// &[ -// &(Treasury::discriminator() as u64).to_le_bytes(), -// Treasury { -// bump: treasury_pda.1 as u64, -// admin: admin_address, -// difficulty: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// last_reset_at: START_AT, -// reward_rate: INITIAL_REWARD_RATE, -// total_claimed_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); - -// // Mint -// let mut mint_src: [u8; Mint::LEN] = [0; Mint::LEN]; -// Mint { -// mint_authority: COption::Some(TREASURY_ADDRESS), -// supply: 2_000_000_000, -// decimals: TOKEN_DECIMALS, -// is_initialized: true, -// freeze_authority: COption::None, -// } -// .pack_into_slice(&mut mint_src); -// program_test.add_account_with_base64_data( -// MINT_ADDRESS, -// 1461600, -// spl_token::id(), -// bs64::encode(&mint_src).as_str(), -// ); - -// // Treasury tokens -// let tokens_address = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); -// let mut tokens_src: [u8; spl_token::state::Account::LEN] = [0; spl_token::state::Account::LEN]; -// spl_token::state::Account { -// mint: MINT_ADDRESS, -// owner: TREASURY_ADDRESS, -// amount: 2_000_000_000, -// delegate: COption::None, -// state: AccountState::Initialized, -// is_native: COption::None, -// delegated_amount: 0, -// close_authority: COption::None, -// } -// .pack_into_slice(&mut tokens_src); -// program_test.add_account_with_base64_data( -// tokens_address, -// 2039280, -// spl_token::id(), -// bs64::encode(&tokens_src).as_str(), -// ); - -// // Set sysvar -// let ts = match clock_state { -// ClockState::Normal => START_AT + 1, -// ClockState::TooEarly => START_AT - 1, -// ClockState::NeedsReset => START_AT + EPOCH_DURATION, -// }; -// program_test.add_sysvar_account( -// sysvar::clock::id(), -// &Clock { -// slot: 0, -// epoch_start_timestamp: 0, -// epoch: 0, -// leader_schedule_epoch: DEFAULT_SLOTS_PER_EPOCH, -// unix_timestamp: ts, -// }, -// ); - -// // Setup alt payer -// let payer_alt = Keypair::new(); -// program_test.add_account( -// payer_alt.pubkey(), -// Account { -// lamports: LAMPORTS_PER_SOL, -// data: vec![], -// owner: system_program::id(), -// executable: false, -// rent_epoch: 0, -// }, -// ); - -// let (banks, payer, blockhash) = program_test.start().await; -// (banks, payer, payer_alt, blockhash) -// } diff --git a/tests/test_register.rs b/tests/test_register.rs deleted file mode 100644 index 084b2fe..0000000 --- a/tests/test_register.rs +++ /dev/null @@ -1,188 +0,0 @@ -// use std::str::FromStr; - -// use ore::{ -// instruction::{register, OreInstruction, RegisterArgs}, -// state::{Bus, Treasury}, -// utils::Discriminator, -// BUS_ADDRESSES, BUS_COUNT, INITIAL_REWARD_RATE, MINT_ADDRESS, PROOF, TOKEN_DECIMALS, TREASURY, -// TREASURY_ADDRESS, -// }; -// use solana_program::{ -// clock::Clock, -// epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, -// instruction::{AccountMeta, Instruction}, -// keccak::Hash as KeccakHash, -// program_option::COption, -// program_pack::Pack, -// pubkey::Pubkey, -// rent::Rent, -// sysvar, -// }; -// use solana_program_test::{processor, BanksClient, ProgramTest}; -// use solana_sdk::{ -// signature::{Keypair, Signer}, -// system_transaction::transfer, -// transaction::Transaction, -// }; -// use spl_token::state::{AccountState, Mint}; - -// #[tokio::test] -// async fn test_register_account_with_lamports() { -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Send lamports to the proof pda -// let proof_pda = Pubkey::find_program_address(&[PROOF, payer.pubkey().as_ref()], &ore::id()); -// let lamports = Rent::default().minimum_balance(0); -// let tx = transfer(&payer, &proof_pda.0, lamports, blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert register succeeds -// let ix = register(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); -// } - -// #[tokio::test] -// async fn test_register_not_enough_accounts() { -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Assert register fails -// let mut ix = register(payer.pubkey()); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_register_fail_other() { -// let (mut banks, payer, blockhash) = setup_program_test_env().await; - -// // Try register for another keypair -// let other = Keypair::new(); -// let proof_pda = Pubkey::find_program_address(&[PROOF, other.pubkey().as_ref()], &ore::id()); -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(payer.pubkey(), true), -// AccountMeta::new(proof_pda.0, false), -// AccountMeta::new_readonly(solana_program::system_program::id(), false), -// ], -// data: [ -// OreInstruction::Register.to_vec(), -// RegisterArgs { bump: proof_pda.1 }.to_bytes().to_vec(), -// ] -// .concat(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// async fn setup_program_test_env() -> (BanksClient, Keypair, solana_program::hash::Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Busses -// for i in 0..BUS_COUNT { -// program_test.add_account_with_base64_data( -// BUS_ADDRESSES[i], -// 1057920, -// ore::id(), -// bs64::encode( -// &[ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { -// id: i as u64, -// rewards: 250_000_000, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); -// } - -// // Treasury -// let admin_address = Pubkey::from_str("AeNqnoLwFanMd3ig9WoMxQZVwQHtCtqKMMBsT1sTrvz6").unwrap(); -// let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); -// program_test.add_account_with_base64_data( -// treasury_pda.0, -// 1614720, -// ore::id(), -// bs64::encode( -// &[ -// &(Treasury::discriminator() as u64).to_le_bytes(), -// Treasury { -// bump: treasury_pda.1 as u64, -// admin: admin_address, -// difficulty: KeccakHash::new_from_array([u8::MAX; 32]).into(), -// last_reset_at: 100, -// reward_rate: INITIAL_REWARD_RATE, -// total_claimed_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); - -// // Mint -// let mut mint_src: [u8; Mint::LEN] = [0; Mint::LEN]; -// Mint { -// mint_authority: COption::Some(TREASURY_ADDRESS), -// supply: 2_000_000_000, -// decimals: TOKEN_DECIMALS, -// is_initialized: true, -// freeze_authority: COption::None, -// } -// .pack_into_slice(&mut mint_src); -// program_test.add_account_with_base64_data( -// MINT_ADDRESS, -// 1461600, -// spl_token::id(), -// bs64::encode(&mint_src).as_str(), -// ); - -// // Treasury tokens -// let tokens_address = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); -// let mut tokens_src: [u8; spl_token::state::Account::LEN] = [0; spl_token::state::Account::LEN]; -// spl_token::state::Account { -// mint: MINT_ADDRESS, -// owner: TREASURY_ADDRESS, -// amount: 2_000_000_000, -// delegate: COption::None, -// state: AccountState::Initialized, -// is_native: COption::None, -// delegated_amount: 0, -// close_authority: COption::None, -// } -// .pack_into_slice(&mut tokens_src); -// program_test.add_account_with_base64_data( -// tokens_address, -// 2039280, -// spl_token::id(), -// bs64::encode(&tokens_src).as_str(), -// ); - -// // Set sysvar -// program_test.add_sysvar_account( -// sysvar::clock::id(), -// &Clock { -// slot: 0, -// epoch_start_timestamp: 0, -// epoch: 0, -// leader_schedule_epoch: DEFAULT_SLOTS_PER_EPOCH, -// unix_timestamp: 0, -// }, -// ); - -// program_test.start().await -// } diff --git a/tests/test_reset.rs b/tests/test_reset.rs deleted file mode 100644 index 3f0a774..0000000 --- a/tests/test_reset.rs +++ /dev/null @@ -1,440 +0,0 @@ -// use std::str::FromStr; - -// use ore::{ -// instruction::OreInstruction, -// state::{Bus, Treasury}, -// utils::{AccountDeserialize, Discriminator}, -// BUS, BUS_ADDRESSES, BUS_COUNT, BUS_EPOCH_REWARDS, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, -// MAX_EPOCH_REWARDS, MINT_ADDRESS, START_AT, TOKEN_DECIMALS, TREASURY, TREASURY_ADDRESS, -// }; -// use rand::seq::SliceRandom; -// use solana_program::{ -// clock::Clock, -// epoch_schedule::DEFAULT_SLOTS_PER_EPOCH, -// hash::Hash, -// instruction::{AccountMeta, Instruction}, -// native_token::LAMPORTS_PER_SOL, -// program_option::COption, -// program_pack::Pack, -// pubkey::Pubkey, -// system_program, sysvar, -// }; -// use solana_program_test::{processor, BanksClient, ProgramTest}; -// use solana_sdk::{ -// account::Account, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; -// use spl_token::state::{AccountState, Mint}; - -// #[tokio::test] -// async fn test_reset() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Pdas -// let bus_pdas = vec![ -// Pubkey::find_program_address(&[BUS, &[0]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[1]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[2]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[3]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[4]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[5]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[6]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[7]], &ore::id()), -// ]; -// // let mint_pda = Pubkey::find_program_address(&[MINT], &ore::id()); -// let treasury_tokens_address = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); - -// // Submit tx -// let ix = ore::instruction::reset(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Test bus state -// for i in 0..BUS_COUNT { -// let bus_account = banks.get_account(bus_pdas[i].0).await.unwrap().unwrap(); -// assert_eq!(bus_account.owner, ore::id()); -// let bus = Bus::try_from_bytes(&bus_account.data).unwrap(); -// assert_eq!(bus.id as u8, i as u8); -// assert_eq!(bus.rewards, BUS_EPOCH_REWARDS); -// } - -// // Test treasury state -// let treasury_account = banks.get_account(TREASURY_ADDRESS).await.unwrap().unwrap(); -// assert_eq!(treasury_account.owner, ore::id()); -// let treasury = Treasury::try_from_bytes(&treasury_account.data).unwrap(); -// assert_eq!( -// treasury.admin, -// Pubkey::from_str("AeNqnoLwFanMd3ig9WoMxQZVwQHtCtqKMMBsT1sTrvz6").unwrap() -// ); -// assert_eq!(treasury.difficulty, INITIAL_DIFFICULTY.into()); -// assert_eq!(treasury.last_reset_at, START_AT + 1); -// assert_eq!(treasury.reward_rate, INITIAL_REWARD_RATE.saturating_div(2)); -// assert_eq!(treasury.total_claimed_rewards as u8, 0); - -// // Test mint state -// let mint_account = banks.get_account(MINT_ADDRESS).await.unwrap().unwrap(); -// assert_eq!(mint_account.owner, spl_token::id()); -// let mint = Mint::unpack(&mint_account.data).unwrap(); -// assert_eq!(mint.mint_authority, COption::Some(TREASURY_ADDRESS)); -// assert_eq!(mint.supply, MAX_EPOCH_REWARDS); -// assert_eq!(mint.decimals, ore::TOKEN_DECIMALS); -// assert_eq!(mint.is_initialized, true); -// assert_eq!(mint.freeze_authority, COption::None); - -// // Test treasury token state -// let treasury_tokens_account = banks -// .get_account(treasury_tokens_address) -// .await -// .unwrap() -// .unwrap(); -// assert_eq!(treasury_tokens_account.owner, spl_token::id()); -// let treasury_tokens = spl_token::state::Account::unpack(&treasury_tokens_account.data).unwrap(); -// assert_eq!(treasury_tokens.mint, MINT_ADDRESS); -// assert_eq!(treasury_tokens.owner, TREASURY_ADDRESS); -// assert_eq!(treasury_tokens.amount, MAX_EPOCH_REWARDS); -// assert_eq!(treasury_tokens.delegate, COption::None); -// assert_eq!(treasury_tokens.state, AccountState::Initialized); -// assert_eq!(treasury_tokens.is_native, COption::None); -// assert_eq!(treasury_tokens.delegated_amount, 0); -// assert_eq!(treasury_tokens.close_authority, COption::None); -// } - -// #[tokio::test] -// async fn test_reset_bad_key() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Bad addresses -// let bad_pda = Pubkey::find_program_address(&[b"t"], &ore::id()); -// for i in 1..13 { -// let mut ix = ore::instruction::reset(payer.pubkey()); -// ix.accounts[i].pubkey = bad_pda.0; -// let tx = -// Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } -// } - -// #[tokio::test] -// async fn test_reset_busses_out_of_order_fail() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Pdas -// let signer = payer.pubkey(); -// let bus_pdas = vec![ -// Pubkey::find_program_address(&[BUS, &[5]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[0]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[6]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[2]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[3]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[7]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[1]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[4]], &ore::id()), -// ]; -// let treasury_tokens = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); - -// // Submit tx -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(signer, true), -// AccountMeta::new(bus_pdas[0].0, false), -// AccountMeta::new(bus_pdas[1].0, false), -// AccountMeta::new(bus_pdas[2].0, false), -// AccountMeta::new(bus_pdas[3].0, false), -// AccountMeta::new(bus_pdas[4].0, false), -// AccountMeta::new(bus_pdas[5].0, false), -// AccountMeta::new(bus_pdas[6].0, false), -// AccountMeta::new(bus_pdas[7].0, false), -// AccountMeta::new(MINT_ADDRESS, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new(treasury_tokens, false), -// AccountMeta::new_readonly(spl_token::id(), false), -// ], -// data: OreInstruction::Reset.to_vec(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_reset_race() { -// // Setup -// let (mut banks, payer, payer_alt, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Reset one passes -// let ix = ore::instruction::reset(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Reset two fails -// let ix = ore::instruction::reset(payer_alt.pubkey()); -// let tx = Transaction::new_signed_with_payer( -// &[ix], -// Some(&payer_alt.pubkey()), -// &[&payer_alt], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_reset_too_early() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::TooEarly).await; - -// // Reset one passes -// let ix = ore::instruction::reset(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_reset_not_enough_keys() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Reset with missing account -// let mut ix = ore::instruction::reset(payer.pubkey()); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_reset_busses_duplicate_fail() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Pdas -// let signer = payer.pubkey(); -// let bus_pda = Pubkey::find_program_address(&[BUS, &[0]], &ore::id()); -// let treasury_tokens = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); - -// // Submit tx -// let ix = Instruction { -// program_id: ore::id(), -// accounts: vec![ -// AccountMeta::new(signer, true), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(bus_pda.0, false), -// AccountMeta::new(MINT_ADDRESS, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new(treasury_tokens, false), -// AccountMeta::new_readonly(spl_token::id(), false), -// ], -// data: OreInstruction::Reset.to_vec(), -// }; -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_reset_shuffle_error() { -// // Setup -// const FUZZ: u64 = 100; -// let (mut banks, payer, _, blockhash) = setup_program_test_env(ClockState::Normal).await; - -// // Pdas -// let signer = payer.pubkey(); -// let bus_pdas = vec![ -// Pubkey::find_program_address(&[BUS, &[5]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[0]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[6]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[2]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[3]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[7]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[1]], &ore::id()), -// Pubkey::find_program_address(&[BUS, &[4]], &ore::id()), -// ]; -// let treasury_tokens = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); - -// // Fuzz test shuffled accounts. -// // Note some shuffles may still be valid if signer and non-bus accounts are all in correct positions. -// let mut rng = rand::thread_rng(); -// for _ in 0..FUZZ { -// let mut accounts = vec![ -// AccountMeta::new(signer, true), -// AccountMeta::new(bus_pdas[0].0, false), -// AccountMeta::new(bus_pdas[1].0, false), -// AccountMeta::new(bus_pdas[2].0, false), -// AccountMeta::new(bus_pdas[3].0, false), -// AccountMeta::new(bus_pdas[4].0, false), -// AccountMeta::new(bus_pdas[5].0, false), -// AccountMeta::new(bus_pdas[6].0, false), -// AccountMeta::new(bus_pdas[7].0, false), -// AccountMeta::new(MINT_ADDRESS, false), -// AccountMeta::new(TREASURY_ADDRESS, false), -// AccountMeta::new(treasury_tokens, false), -// AccountMeta::new_readonly(spl_token::id(), false), -// ]; -// accounts.shuffle(&mut rng); -// let ix = Instruction { -// program_id: ore::id(), -// accounts, -// data: OreInstruction::Reset.to_vec(), -// }; -// let tx = -// Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } -// } - -// enum ClockState { -// Normal, -// TooEarly, -// } - -// async fn setup_program_test_env(clock_state: ClockState) -> (BanksClient, Keypair, Keypair, Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Busses -// for i in 0..BUS_COUNT { -// program_test.add_account_with_base64_data( -// BUS_ADDRESSES[i], -// 1057920, -// ore::id(), -// bs64::encode( -// &[ -// &(Bus::discriminator() as u64).to_le_bytes(), -// Bus { -// id: i as u64, -// rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); -// } - -// // Treasury -// let admin_address = Pubkey::from_str("AeNqnoLwFanMd3ig9WoMxQZVwQHtCtqKMMBsT1sTrvz6").unwrap(); -// let treasury_pda = Pubkey::find_program_address(&[TREASURY], &ore::id()); -// program_test.add_account_with_base64_data( -// treasury_pda.0, -// 1614720, -// ore::id(), -// bs64::encode( -// &[ -// &(Treasury::discriminator() as u64).to_le_bytes(), -// Treasury { -// bump: treasury_pda.1 as u64, -// admin: admin_address, -// difficulty: INITIAL_DIFFICULTY.into(), -// last_reset_at: 0, -// reward_rate: INITIAL_REWARD_RATE, -// total_claimed_rewards: 0, -// } -// .to_bytes(), -// ] -// .concat(), -// ) -// .as_str(), -// ); - -// // Mint -// let mut mint_src: [u8; Mint::LEN] = [0; Mint::LEN]; -// Mint { -// mint_authority: COption::Some(TREASURY_ADDRESS), -// supply: 0, -// decimals: TOKEN_DECIMALS, -// is_initialized: true, -// freeze_authority: COption::None, -// } -// .pack_into_slice(&mut mint_src); -// program_test.add_account_with_base64_data( -// MINT_ADDRESS, -// 1461600, -// spl_token::id(), -// bs64::encode(&mint_src).as_str(), -// ); - -// // Treasury tokens -// let tokens_address = spl_associated_token_account::get_associated_token_address( -// &TREASURY_ADDRESS, -// &MINT_ADDRESS, -// ); -// let mut tokens_src: [u8; spl_token::state::Account::LEN] = [0; spl_token::state::Account::LEN]; -// spl_token::state::Account { -// mint: MINT_ADDRESS, -// owner: TREASURY_ADDRESS, -// amount: 0, -// delegate: COption::None, -// state: AccountState::Initialized, -// is_native: COption::None, -// delegated_amount: 0, -// close_authority: COption::None, -// } -// .pack_into_slice(&mut tokens_src); -// program_test.add_account_with_base64_data( -// tokens_address, -// 2039280, -// spl_token::id(), -// bs64::encode(&tokens_src).as_str(), -// ); - -// // Set sysvar -// let ts = match clock_state { -// ClockState::Normal => START_AT + 1, -// ClockState::TooEarly => START_AT - 1, -// }; -// program_test.add_sysvar_account( -// sysvar::clock::id(), -// &Clock { -// slot: 0, -// epoch_start_timestamp: 0, -// epoch: 0, -// leader_schedule_epoch: DEFAULT_SLOTS_PER_EPOCH, -// unix_timestamp: ts, -// }, -// ); - -// // Setup alt payer -// let payer_alt = Keypair::new(); -// program_test.add_account( -// payer_alt.pubkey(), -// Account { -// lamports: LAMPORTS_PER_SOL, -// data: vec![], -// owner: system_program::id(), -// executable: false, -// rent_epoch: 0, -// }, -// ); - -// let (banks, payer, blockhash) = program_test.start().await; -// (banks, payer, payer_alt, blockhash) -// } diff --git a/tests/test_update_admin.rs b/tests/test_update_admin.rs deleted file mode 100644 index cd00ccd..0000000 --- a/tests/test_update_admin.rs +++ /dev/null @@ -1,128 +0,0 @@ -// use ore::{state::Treasury, utils::AccountDeserialize, TREASURY_ADDRESS}; -// use solana_program::{ -// hash::Hash, native_token::LAMPORTS_PER_SOL, pubkey::Pubkey, rent::Rent, system_program, -// }; -// use solana_program_test::{processor, read_file, BanksClient, ProgramTest}; -// use solana_sdk::{ -// account::Account, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; - -// #[tokio::test] -// async fn test_update_admin() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Get treasury account -// let treasury_account = banks.get_account(TREASURY_ADDRESS).await.unwrap().unwrap(); -// let treasury = Treasury::try_from_bytes(&treasury_account.data).unwrap(); - -// // Submit update admin ix -// let new_admin = Pubkey::new_unique(); -// let ix = ore::instruction::update_admin(payer.pubkey(), new_admin); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert treasury state -// let treasury_account = banks.get_account(TREASURY_ADDRESS).await.unwrap().unwrap(); -// let treasury_ = Treasury::try_from_bytes(&treasury_account.data).unwrap(); -// assert_eq!(treasury_.bump, treasury.bump); -// assert_eq!(treasury_.admin, new_admin); -// assert_eq!(treasury_.difficulty, treasury.difficulty); -// assert_eq!(treasury_.last_reset_at, treasury.last_reset_at); -// assert_eq!(treasury_.reward_rate, treasury.reward_rate); -// assert_eq!( -// treasury_.total_claimed_rewards, -// treasury.total_claimed_rewards -// ); - -// // Submit another update admin ix -// let ix = ore::instruction::update_admin(payer.pubkey(), payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_update_admin_bad_signer() { -// // Setup -// let (mut banks, payer, alt_payer, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit ix -// let ix = ore::instruction::update_admin(alt_payer.pubkey(), Pubkey::new_unique()); -// let tx = Transaction::new_signed_with_payer( -// &[ix], -// Some(&alt_payer.pubkey()), -// &[&alt_payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_update_admin_not_enough_accounts() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit ix without enough accounts -// let mut ix = ore::instruction::update_admin(payer.pubkey(), Pubkey::new_unique()); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// async fn setup_program_test_env() -> (BanksClient, Keypair, Keypair, Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Setup metadata program -// let data = read_file(&"tests/buffers/metadata_program.bpf"); -// program_test.add_account( -// mpl_token_metadata::ID, -// Account { -// lamports: Rent::default().minimum_balance(data.len()).max(1), -// data, -// owner: solana_sdk::bpf_loader::id(), -// executable: true, -// rent_epoch: 0, -// }, -// ); - -// // Setup alt payer -// let payer_alt = Keypair::new(); -// program_test.add_account( -// payer_alt.pubkey(), -// Account { -// lamports: LAMPORTS_PER_SOL, -// data: vec![], -// owner: system_program::id(), -// executable: false, -// rent_epoch: 0, -// }, -// ); - -// let (banks, payer, blockhash) = program_test.start().await; -// (banks, payer, payer_alt, blockhash) -// } diff --git a/tests/test_update_difficulty.rs b/tests/test_update_difficulty.rs deleted file mode 100644 index 4666a8a..0000000 --- a/tests/test_update_difficulty.rs +++ /dev/null @@ -1,125 +0,0 @@ -// use ore::{state::Treasury, utils::AccountDeserialize, TREASURY_ADDRESS}; -// use solana_program::{ -// hash::Hash, keccak::Hash as KeccakHash, native_token::LAMPORTS_PER_SOL, rent::Rent, -// system_program, -// }; -// use solana_program_test::{processor, read_file, BanksClient, ProgramTest}; -// use solana_sdk::{ -// account::Account, -// signature::{Keypair, Signer}, -// transaction::Transaction, -// }; - -// #[tokio::test] -// async fn test_update_difficulty() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Get treasury account -// let treasury_account = banks.get_account(TREASURY_ADDRESS).await.unwrap().unwrap(); -// let treasury = Treasury::try_from_bytes(&treasury_account.data).unwrap(); - -// // Submit update difficulty ix -// let new_difficulty = KeccakHash::new_unique(); -// let ix = ore::instruction::update_difficulty(payer.pubkey(), new_difficulty.into()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Assert treasury state -// let treasury_account = banks.get_account(TREASURY_ADDRESS).await.unwrap().unwrap(); -// let treasury_ = Treasury::try_from_bytes(&treasury_account.data).unwrap(); -// assert_eq!(treasury_.bump, treasury.bump); -// assert_eq!(treasury_.admin, treasury.admin); -// assert_eq!(treasury_.difficulty, new_difficulty.into()); -// assert_eq!(treasury_.last_reset_at, treasury.last_reset_at); -// assert_eq!(treasury_.reward_rate, treasury.reward_rate); -// assert_eq!( -// treasury_.total_claimed_rewards, -// treasury.total_claimed_rewards -// ); -// } - -// #[tokio::test] -// async fn test_update_difficulty_bad_signer() { -// // Setup -// let (mut banks, payer, alt_payer, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit update difficulty ix -// let new_difficulty = KeccakHash::new_unique(); -// let ix = ore::instruction::update_difficulty(alt_payer.pubkey(), new_difficulty.into()); -// let tx = Transaction::new_signed_with_payer( -// &[ix], -// Some(&alt_payer.pubkey()), -// &[&alt_payer], -// blockhash, -// ); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// #[tokio::test] -// async fn test_update_difficulty_not_enough_accounts() { -// // Setup -// let (mut banks, payer, _, blockhash) = setup_program_test_env().await; - -// // Submit tx -// let ix = ore::instruction::initialize(payer.pubkey()); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_ok()); - -// // Submit ix without enough accounts -// let new_difficulty = KeccakHash::new_unique(); -// let mut ix = ore::instruction::update_difficulty(payer.pubkey(), new_difficulty.into()); -// ix.accounts.remove(1); -// let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash); -// let res = banks.process_transaction(tx).await; -// assert!(res.is_err()); -// } - -// async fn setup_program_test_env() -> (BanksClient, Keypair, Keypair, Hash) { -// let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction)); -// program_test.prefer_bpf(true); - -// // Setup metadata program -// let data = read_file(&"tests/buffers/metadata_program.bpf"); -// program_test.add_account( -// mpl_token_metadata::ID, -// Account { -// lamports: Rent::default().minimum_balance(data.len()).max(1), -// data, -// owner: solana_sdk::bpf_loader::id(), -// executable: true, -// rent_epoch: 0, -// }, -// ); - -// // Setup alt payer -// let payer_alt = Keypair::new(); -// program_test.add_account( -// payer_alt.pubkey(), -// Account { -// lamports: LAMPORTS_PER_SOL, -// data: vec![], -// owner: system_program::id(), -// executable: false, -// rent_epoch: 0, -// }, -// ); - -// let (banks, payer, blockhash) = program_test.start().await; -// (banks, payer, payer_alt, blockhash) -// } diff --git a/utils/Cargo.toml b/utils/Cargo.toml new file mode 100644 index 0000000..cc44d0f --- /dev/null +++ b/utils/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "utils" +description = "Utils for building ORE programs" +version.workspace = true +edition.workspace = true +license.workspace = true +homepage.workspace = true +documentation.workspace = true +repository.workspace = true +keywords.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] +name = "utils" + +[dependencies] +bytemuck.workspace = true +solana-program.workspace = true diff --git a/src/utils.rs b/utils/src/lib.rs similarity index 86% rename from src/utils.rs rename to utils/src/lib.rs index cdb9779..1694c98 100644 --- a/src/utils.rs +++ b/utils/src/lib.rs @@ -1,5 +1,3 @@ -use bytemuck::{Pod, Zeroable}; -use num_enum::{IntoPrimitive, TryFromPrimitive}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, @@ -7,7 +5,7 @@ use solana_program::{ /// Creates a new pda #[inline(always)] -pub(crate) fn create_pda<'a, 'info>( +pub fn create_pda<'a, 'info>( target_account: &'a AccountInfo<'info>, owner: &Pubkey, space: usize, @@ -73,25 +71,8 @@ pub(crate) fn create_pda<'a, 'info>( Ok(()) } -#[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] -pub struct MineEvent { - pub difficulty: u64, - pub reward: u64, - pub timing: i64, -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] -pub enum AccountDiscriminator { - Bus = 100, - Config = 101, - Proof = 102, - Treasury = 103, -} - pub trait Discriminator { - fn discriminator() -> AccountDiscriminator; + fn discriminator() -> u8; //AccountDiscriminator; } pub trait AccountDeserialize { @@ -117,7 +98,7 @@ macro_rules! impl_account_from_bytes { fn try_from_bytes( data: &[u8], ) -> Result<&Self, solana_program::program_error::ProgramError> { - if (Self::discriminator() as u8).ne(&data[0]) { + if Self::discriminator().ne(&data[0]) { return Err(solana_program::program_error::ProgramError::InvalidAccountData); } bytemuck::try_from_bytes::(&data[8..]).or(Err( @@ -127,7 +108,7 @@ macro_rules! impl_account_from_bytes { fn try_from_bytes_mut( data: &mut [u8], ) -> Result<&mut Self, solana_program::program_error::ProgramError> { - if (Self::discriminator() as u8).ne(&data[0]) { + if Self::discriminator().ne(&data[0]) { return Err(solana_program::program_error::ProgramError::InvalidAccountData); } bytemuck::try_from_bytes_mut::(&mut data[8..]).or(Err(