mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-13 23:16:52 +00:00
update comments
This commit is contained in:
@@ -16,6 +16,7 @@ use crate::{
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
|
||||
#[rustfmt::skip]
|
||||
pub enum OreInstruction {
|
||||
// User
|
||||
Claim = 0,
|
||||
Close = 1,
|
||||
Mine = 2,
|
||||
@@ -25,6 +26,7 @@ pub enum OreInstruction {
|
||||
Update = 6,
|
||||
Upgrade = 7,
|
||||
|
||||
// Admin
|
||||
Initialize = 100,
|
||||
}
|
||||
|
||||
@@ -96,6 +98,15 @@ impl_instruction_from_bytes!(ClaimArgs);
|
||||
impl_instruction_from_bytes!(StakeArgs);
|
||||
impl_instruction_from_bytes!(UpgradeArgs);
|
||||
|
||||
/// Builds an auth instruction.
|
||||
pub fn auth(proof: Pubkey) -> Instruction {
|
||||
Instruction {
|
||||
program_id: NOOP_PROGRAM_ID,
|
||||
accounts: vec![],
|
||||
data: proof.to_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
@@ -139,15 +150,6 @@ pub fn close(signer: Pubkey) -> Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an auth instruction.
|
||||
pub fn auth(proof: Pubkey) -> Instruction {
|
||||
Instruction {
|
||||
program_id: NOOP_PROGRAM_ID,
|
||||
accounts: vec![],
|
||||
data: proof.to_bytes().to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a mine instruction.
|
||||
pub fn mine(
|
||||
signer: Pubkey,
|
||||
|
||||
@@ -4,8 +4,8 @@ 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.
|
||||
/// Bus accounts are responsible for distributing mining rewards. There are 8 busses total
|
||||
/// to minimize write-lock contention and allow Solana to process mine instructions in parallel.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
|
||||
pub struct Bus {
|
||||
@@ -16,7 +16,7 @@ pub struct Bus {
|
||||
pub rewards: u64,
|
||||
|
||||
/// The rewards this bus would have paid out in the current epoch if there no limit.
|
||||
/// Used to calculate the updated reward rate.
|
||||
/// This is used to calculate the updated reward rate.
|
||||
pub theoretical_rewards: u64,
|
||||
|
||||
/// The largest known stake balance seen by the bus this epoch.
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::utils::{impl_account_from_bytes, impl_to_bytes, Discriminator};
|
||||
|
||||
use super::AccountDiscriminator;
|
||||
|
||||
/// Config is a singleton account which manages admin configurable variables.
|
||||
/// Config is a singleton account which manages program global variables.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
|
||||
pub struct Config {
|
||||
|
||||
@@ -4,8 +4,8 @@ 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.
|
||||
/// Treasury is a singleton account which is the mint authority for the ORE token and the authority of
|
||||
/// the program's global token account.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
|
||||
pub struct Treasury {}
|
||||
|
||||
@@ -6,13 +6,13 @@ use solana_program::{
|
||||
|
||||
use crate::utils::AccountDeserialize;
|
||||
|
||||
/// Claim distributes ORE from the treasury to a miner.
|
||||
/// Claim distributes claimable ORE from the treasury to a miner.
|
||||
pub fn process_claim<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8]) -> ProgramResult {
|
||||
// Parse args
|
||||
// Parse args.
|
||||
let args = ClaimArgs::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, beneficiary_info, proof_info, treasury_info, treasury_tokens_info, token_program] =
|
||||
accounts
|
||||
else {
|
||||
@@ -25,7 +25,7 @@ pub fn process_claim<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
load_treasury_tokens(treasury_tokens_info, true)?;
|
||||
load_program(token_program, spl_token::id())?;
|
||||
|
||||
// Update miner balance
|
||||
// Update miner balance.
|
||||
let mut proof_data = proof_info.data.borrow_mut();
|
||||
let proof = Proof::try_from_bytes_mut(&mut proof_data)?;
|
||||
proof.balance = proof
|
||||
@@ -33,7 +33,7 @@ pub fn process_claim<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
.checked_sub(amount)
|
||||
.ok_or(OreError::ClaimTooLarge)?;
|
||||
|
||||
// Distribute tokens from treasury to beneficiary
|
||||
// Transfer tokens from treasury to beneficiary.
|
||||
transfer_signed(
|
||||
treasury_info,
|
||||
treasury_tokens_info,
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::utils::AccountDeserialize;
|
||||
|
||||
/// Close closes a proof account and returns the rent to the owner.
|
||||
pub fn process_close<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, proof_info, system_program] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
@@ -16,7 +16,7 @@ pub fn process_close<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]
|
||||
load_proof(proof_info, signer.key, true)?;
|
||||
load_program(system_program, system_program::id())?;
|
||||
|
||||
// Validate balance is zero
|
||||
// Validate balance is zero.
|
||||
let proof_data = proof_info.data.borrow();
|
||||
let proof = Proof::try_from_bytes(&proof_data)?;
|
||||
if proof.balance.gt(&0) {
|
||||
@@ -24,10 +24,10 @@ pub fn process_close<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]
|
||||
}
|
||||
drop(proof_data);
|
||||
|
||||
// Realloc data to zero
|
||||
// Realloc data to zero.
|
||||
proof_info.realloc(0, true)?;
|
||||
|
||||
// Send lamports to signer
|
||||
// Send remaining lamports to signer.
|
||||
**signer.lamports.borrow_mut() += proof_info.lamports();
|
||||
**proof_info.lamports.borrow_mut() = 0;
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ pub fn process_initialize<'a, 'info>(
|
||||
accounts: &'a [AccountInfo<'info>],
|
||||
data: &[u8],
|
||||
) -> ProgramResult {
|
||||
// Parse args
|
||||
// Parse args.
|
||||
let args = InitializeArgs::try_from_bytes(data)?;
|
||||
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, config_info, metadata_info, mint_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program, metadata_program, rent_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
@@ -71,12 +71,12 @@ pub fn process_initialize<'a, 'info>(
|
||||
load_program(metadata_program, mpl_token_metadata::ID)?;
|
||||
load_sysvar(rent_sysvar, sysvar::rent::id())?;
|
||||
|
||||
// Check signer
|
||||
// Check signer.
|
||||
if signer.key.ne(&INITIALIZER_ADDRESS) {
|
||||
return Err(ProgramError::MissingRequiredSignature);
|
||||
}
|
||||
|
||||
// Initialize bus accounts
|
||||
// Initialize bus accounts.
|
||||
let bus_infos = [
|
||||
bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info,
|
||||
bus_7_info,
|
||||
@@ -107,7 +107,7 @@ pub fn process_initialize<'a, 'info>(
|
||||
bus.rewards = 0;
|
||||
}
|
||||
|
||||
// Initialize config
|
||||
// Initialize config.
|
||||
create_pda(
|
||||
config_info,
|
||||
&ore_api::id(),
|
||||
@@ -124,7 +124,7 @@ pub fn process_initialize<'a, 'info>(
|
||||
config.min_difficulty = INITIAL_MIN_DIFFICULTY as u64;
|
||||
config.top_balance = 0;
|
||||
|
||||
// Initialize treasury
|
||||
// Initialize treasury.
|
||||
create_pda(
|
||||
treasury_info,
|
||||
&ore_api::id(),
|
||||
@@ -137,7 +137,7 @@ pub fn process_initialize<'a, 'info>(
|
||||
treasury_data[0] = Treasury::discriminator() as u8;
|
||||
drop(treasury_data);
|
||||
|
||||
// Initialize mint
|
||||
// Initialize mint.
|
||||
create_pda(
|
||||
mint_info,
|
||||
&spl_token::id(),
|
||||
@@ -163,7 +163,7 @@ pub fn process_initialize<'a, 'info>(
|
||||
&[&[MINT, MINT_NOISE.as_slice(), &[args.mint_bump]]],
|
||||
)?;
|
||||
|
||||
// Initialize mint metadata
|
||||
// Initialize mint metadata.
|
||||
mpl_token_metadata::instructions::CreateMetadataAccountV3Cpi {
|
||||
__program: metadata_program,
|
||||
metadata: metadata_info,
|
||||
@@ -189,7 +189,7 @@ pub fn process_initialize<'a, 'info>(
|
||||
}
|
||||
.invoke_signed(&[&[TREASURY, &[args.treasury_bump]]])?;
|
||||
|
||||
// Initialize treasury token account
|
||||
// Initialize treasury token account.
|
||||
create_ata(
|
||||
signer,
|
||||
treasury_info,
|
||||
|
||||
@@ -28,10 +28,10 @@ use crate::utils::AccountDeserialize;
|
||||
|
||||
/// Mine validates hashes and increments a miner's collectable balance.
|
||||
pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8]) -> ProgramResult {
|
||||
// Parse args
|
||||
// Parse args.
|
||||
let args = MineArgs::try_from_bytes(data)?;
|
||||
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, bus_info, config_info, proof_info, instructions_sysvar, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
@@ -44,7 +44,7 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
load_sysvar(instructions_sysvar, sysvar::instructions::id())?;
|
||||
load_sysvar(slot_hashes_sysvar, sysvar::slot_hashes::id())?;
|
||||
|
||||
// Authenticate the proof account
|
||||
// Authenticate the proof account.
|
||||
authenticate(&instructions_sysvar.data.borrow(), proof_info.key)?;
|
||||
|
||||
// Validate epoch is active.
|
||||
@@ -75,14 +75,17 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
return Err(OreError::Spam.into());
|
||||
}
|
||||
|
||||
// Validate hash satisfies the minimnum difficulty.
|
||||
// Validate the hash satisfies the minimum difficulty.
|
||||
let hash = solution.to_hash();
|
||||
let difficulty = hash.difficulty();
|
||||
if difficulty.lt(&(config.min_difficulty as u32)) {
|
||||
return Err(OreError::HashTooEasy.into());
|
||||
}
|
||||
|
||||
// Normalize difficulty and calculate reward rate
|
||||
// Normalize difficulty and calculate reward rate.
|
||||
//
|
||||
// The reward double for every bit of difficulty (leading zero) on the hash. We use the normalized
|
||||
// difficulty so the minimum accepted difficulty pays out at the base reward rate.
|
||||
let normalized_difficulty = difficulty
|
||||
.checked_sub(config.min_difficulty as u32)
|
||||
.unwrap();
|
||||
@@ -92,9 +95,10 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
.unwrap();
|
||||
|
||||
// Apply staking multiplier.
|
||||
//
|
||||
// If user has greater than or equal to the max stake on the network, they receive 2x multiplier.
|
||||
// Any stake less than this will receives between 1x and 2x multipler. The multipler is only active
|
||||
// if the miner's last stake deposit was more than one minute ago.
|
||||
// if the miner's last stake deposit was more than one minute ago to protect against flash loan attacks.
|
||||
let mut bus_data = bus_info.data.borrow_mut();
|
||||
let bus = Bus::try_from_bytes_mut(&mut bus_data)?;
|
||||
if proof.balance.gt(&0) && proof.last_stake_at.saturating_add(ONE_MINUTE).lt(&t) {
|
||||
@@ -115,6 +119,13 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
}
|
||||
|
||||
// Apply liveness penalty.
|
||||
//
|
||||
// The liveness penalty exists to ensure there is no "invisible" hashpower on the network. It
|
||||
// should not be possible to spend ~1 hour on a given challenge and submit a hash with a large
|
||||
// difficulty value to earn an outsized reward.
|
||||
//
|
||||
// This penalty works by halving the reward amount for every minute late the solution has been submitted.
|
||||
// This ultimately drives the reward to zero given enough time (10-20 minutes).
|
||||
let t_liveness = t_target.saturating_add(TOLERANCE);
|
||||
if t.gt(&t_liveness) {
|
||||
reward = reward.saturating_sub(
|
||||
@@ -126,15 +137,19 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
);
|
||||
}
|
||||
|
||||
// Limit payout amount to whatever is left in the bus
|
||||
// Limit payout amount to whatever is left in the bus.
|
||||
//
|
||||
// Busses are limited 1 ORE per epoch. This is the maximum amount a miner can earn for any one hash.
|
||||
// We still track the theoretical rewards that would have been paid out ignoring the bus limit, so the
|
||||
// base reward rate will be updated to account for the real hashpower on the network.
|
||||
let reward_actual = reward.min(bus.rewards);
|
||||
|
||||
// Update balances
|
||||
// Update balances.
|
||||
bus.theoretical_rewards = bus.theoretical_rewards.checked_add(reward).unwrap();
|
||||
bus.rewards = bus.rewards.checked_sub(reward_actual).unwrap();
|
||||
proof.balance = proof.balance.checked_add(reward_actual).unwrap();
|
||||
|
||||
// Hash recent slot hash into the next challenge to prevent pre-mining attacks
|
||||
// Hash recent slot hash into the next challenge to prevent pre-mining attacks.
|
||||
proof.last_hash = hash.h;
|
||||
proof.challenge = hashv(&[
|
||||
hash.h.as_slice(),
|
||||
@@ -142,14 +157,14 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
])
|
||||
.0;
|
||||
|
||||
// Update time trackers
|
||||
// Update time trackers.
|
||||
proof.last_hash_at = t.max(t_target);
|
||||
|
||||
// Update lifetime stats
|
||||
// Update lifetime stats.
|
||||
proof.total_hashes = proof.total_hashes.saturating_add(1);
|
||||
proof.total_rewards = proof.total_rewards.saturating_add(reward);
|
||||
|
||||
// Log the mined rewards
|
||||
// Log the mined rewards.
|
||||
set_return_data(
|
||||
MineEvent {
|
||||
difficulty: difficulty as u64,
|
||||
@@ -166,12 +181,12 @@ pub fn process_mine<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
///
|
||||
/// This process is necessary to prevent sybil attacks. If a user can pack multiple hashes into a single
|
||||
/// transaction, then there is a financial incentive to mine across multiple keypairs and submit as many hashes
|
||||
/// as possible in each transaction to minimize fee / hash.
|
||||
/// as possible in the same transaction to minimize fee / hash.
|
||||
///
|
||||
/// We prevent this by forcing every transaction to declare the proof account being mined with upfont.
|
||||
/// The authentication process includes passing the 32 byte pubkey address as instruction data to the
|
||||
/// CU-optimized noop program. We parse this address through transaction introspection and use it to
|
||||
/// ensure only one proof account can be used for `mine` instructions for a given transaction.
|
||||
/// This is prevented by forcing every transaction to declare upfront the proof account that will be used for mining.
|
||||
/// The authentication process includes passing the 32 byte pubkey address as instruction data to a CU-optimized noop
|
||||
/// program. We parse this address through transaction introspection and use it to ensure the same proof account is
|
||||
/// used for every `mine` instruction in a given transaction.
|
||||
fn authenticate(data: &[u8], proof_address: &Pubkey) -> ProgramResult {
|
||||
if let Ok(Some(auth_address)) = parse_auth_address(data) {
|
||||
if proof_address.ne(&auth_address) {
|
||||
|
||||
@@ -15,15 +15,11 @@ use solana_program::{
|
||||
use crate::utils::{create_pda, AccountDeserialize, Discriminator};
|
||||
|
||||
/// Open creates a new proof account to track a miner's state.
|
||||
///
|
||||
/// Safety requirements:
|
||||
/// - Register is a permissionless instruction and can be invoked by any singer.
|
||||
/// - Can only succeed if the user does not already have a proof account.
|
||||
pub fn process_open<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8]) -> ProgramResult {
|
||||
// Parse args
|
||||
// Parse args.
|
||||
let args = OpenArgs::try_from_bytes(data)?;
|
||||
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, miner_info, payer_info, proof_info, system_program, slot_hashes_info] = accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -40,7 +36,7 @@ pub fn process_open<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
load_program(system_program, system_program::id())?;
|
||||
load_sysvar(slot_hashes_info, sysvar::slot_hashes::id())?;
|
||||
|
||||
// Initialize proof
|
||||
// Initialize proof.
|
||||
create_pda(
|
||||
proof_info,
|
||||
&ore_api::id(),
|
||||
|
||||
@@ -12,9 +12,9 @@ use spl_token::state::Mint;
|
||||
|
||||
use crate::utils::AccountDeserialize;
|
||||
|
||||
/// Reset tops up the busses, updates the base reward rate, and generally sets up the ORE program for the next epoch.
|
||||
/// Reset tops up the busses, updates the base reward rate, and sets up the ORE program for the next epoch.
|
||||
pub fn process_reset<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, config_info, mint_info, treasury_info, treasury_tokens_info, token_program] =
|
||||
accounts
|
||||
else {
|
||||
@@ -39,7 +39,7 @@ pub fn process_reset<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]
|
||||
bus_7_info,
|
||||
];
|
||||
|
||||
// Validate enough time has passed since last reset
|
||||
// Validate enough time has passed since last reset.
|
||||
let mut config_data = config_info.data.borrow_mut();
|
||||
let config = Config::try_from_bytes_mut(&mut config_data)?;
|
||||
let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?;
|
||||
@@ -51,10 +51,10 @@ pub fn process_reset<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Update reset timestamp
|
||||
// Update reset timestamp.
|
||||
config.last_reset_at = clock.unix_timestamp;
|
||||
|
||||
// Reset bus accounts and calculate actual rewards mined since last reset
|
||||
// Reset bus accounts and calculate actual rewards mined since last reset.
|
||||
let mut total_remaining_rewards = 0u64;
|
||||
let mut total_theoretical_rewards = 0u64;
|
||||
let mut top_balance = 0u64;
|
||||
@@ -73,32 +73,32 @@ pub fn process_reset<'a, 'info>(accounts: &'a [AccountInfo<'info>], _data: &[u8]
|
||||
}
|
||||
let total_epoch_rewards = MAX_EPOCH_REWARDS.saturating_sub(total_remaining_rewards);
|
||||
|
||||
// Update the top balance
|
||||
// Update the top balance.
|
||||
config.top_balance = top_balance;
|
||||
|
||||
// Update base reward rate for next epoch
|
||||
// Update base reward rate for next epoch.
|
||||
config.base_reward_rate =
|
||||
calculate_new_reward_rate(config.base_reward_rate, total_theoretical_rewards);
|
||||
|
||||
// If base_reward_rate is too low, then increment difficulty by 1 and double base reward rate
|
||||
// If base_reward_rate is too low, then increment difficulty by 1 and double base reward rate.
|
||||
if config.base_reward_rate.le(&BASE_REWARD_RATE_MIN_THRESHOLD) {
|
||||
config.min_difficulty = config.min_difficulty.checked_add(1).unwrap();
|
||||
config.base_reward_rate = config.base_reward_rate.checked_mul(2).unwrap();
|
||||
}
|
||||
|
||||
// If base reward rate is too high, then decrement difficulty by 1 and halve base reward rate
|
||||
// If base reward rate is too high, then decrement difficulty by 1 and halve base reward rate.
|
||||
if config.base_reward_rate.ge(&BASE_REWARD_RATE_MAX_THRESHOLD) && config.min_difficulty.gt(&1) {
|
||||
config.min_difficulty = config.min_difficulty.checked_sub(1).unwrap();
|
||||
config.base_reward_rate = config.base_reward_rate.checked_div(2).unwrap();
|
||||
}
|
||||
|
||||
// Max supply check
|
||||
// Max supply check.
|
||||
let mint = Mint::unpack(&mint_info.data.borrow()).expect("Failed to parse mint");
|
||||
if mint.supply.ge(&MAX_SUPPLY) {
|
||||
return Err(OreError::MaxSupply.into());
|
||||
}
|
||||
|
||||
// Fund treasury token account
|
||||
// Fund treasury token account.
|
||||
let amount = MAX_SUPPLY
|
||||
.saturating_sub(mint.supply)
|
||||
.min(total_epoch_rewards);
|
||||
|
||||
@@ -9,11 +9,11 @@ use crate::utils::AccountDeserialize;
|
||||
|
||||
/// Stake deposits ORE into a proof account to earn multiplier.
|
||||
pub fn process_stake<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8]) -> ProgramResult {
|
||||
// Parse args
|
||||
// Parse args.
|
||||
let args = StakeArgs::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, proof_info, sender_info, treasury_tokens_info, token_program] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
@@ -23,16 +23,16 @@ pub fn process_stake<'a, 'info>(accounts: &'a [AccountInfo<'info>], data: &[u8])
|
||||
load_treasury_tokens(treasury_tokens_info, true)?;
|
||||
load_program(token_program, spl_token::id())?;
|
||||
|
||||
// Update proof balance
|
||||
// Update the proof balance.
|
||||
let mut proof_data = proof_info.data.borrow_mut();
|
||||
let proof = Proof::try_from_bytes_mut(&mut proof_data)?;
|
||||
proof.balance = proof.balance.checked_add(amount).unwrap();
|
||||
|
||||
// Update deposit timestamp
|
||||
// Update deposit timestamp.
|
||||
let clock = Clock::get().or(Err(ProgramError::InvalidAccountData))?;
|
||||
proof.last_stake_at = clock.unix_timestamp;
|
||||
|
||||
// Distribute tokens from signer to treasury
|
||||
// Transfer tokens from signer to treasury.
|
||||
transfer(
|
||||
signer,
|
||||
sender_info,
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn process_update<'a, 'info>(
|
||||
accounts: &'a [AccountInfo<'info>],
|
||||
_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
// Load accounts
|
||||
// Load accounts.
|
||||
let [signer, miner_info, proof_info] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
@@ -18,7 +18,7 @@ pub fn process_update<'a, 'info>(
|
||||
load_system_account(miner_info, false)?;
|
||||
load_proof(proof_info, signer.key, true)?;
|
||||
|
||||
// Update the proof
|
||||
// Update the proof's miner authority.
|
||||
let mut proof_data = proof_info.data.borrow_mut();
|
||||
let proof = Proof::try_from_bytes_mut(&mut proof_data)?;
|
||||
proof.miner = *miner_info.key;
|
||||
|
||||
@@ -56,9 +56,9 @@ pub fn process_upgrade<'a, 'info>(
|
||||
if mint.supply.saturating_add(amount_to_mint).gt(&MAX_SUPPLY) {
|
||||
return Err(OreError::MaxSupply.into());
|
||||
}
|
||||
drop(mint_data);
|
||||
|
||||
// Mint to the beneficiary account
|
||||
drop(mint_data);
|
||||
mint_to_signed(
|
||||
mint_info,
|
||||
beneficiary_info,
|
||||
|
||||
@@ -6,7 +6,7 @@ use solana_program::{
|
||||
pubkey::Pubkey, rent::Rent, sysvar::Sysvar,
|
||||
};
|
||||
|
||||
/// Creates a new pda
|
||||
/// Creates a new pda.
|
||||
#[inline(always)]
|
||||
pub fn create_pda<'a, 'info>(
|
||||
target_account: &'a AccountInfo<'info>,
|
||||
@@ -75,7 +75,7 @@ pub fn create_pda<'a, 'info>(
|
||||
}
|
||||
|
||||
pub trait Discriminator {
|
||||
fn discriminator() -> u8; //AccountDiscriminator;
|
||||
fn discriminator() -> u8;
|
||||
}
|
||||
|
||||
pub trait AccountDeserialize {
|
||||
|
||||
Reference in New Issue
Block a user