This commit is contained in:
Hardhat Chad
2025-07-16 16:51:23 -07:00
parent 084757cc8d
commit 39ff6f51cd
9 changed files with 213 additions and 457 deletions

View File

@@ -68,10 +68,10 @@ pub const DENOMINATOR_BPS: u64 = 10_000;
pub const SLOT_WINDOW: u64 = 4;
/// Amount of hash tokens to mint to market.
pub const HASH_TOKEN_SUPPLY: u64 = 1_000_000;
pub const HASHPOWER_LIQUIDITY: u64 = 1_000_000;
/// The virtual liquidity to seed the markets with (in ORE).
pub const VIRTUAL_LIQUIDITY: u64 = ONE_ORE * 5;
/// The ORE liquidity to seed the markets with.
pub const ORE_LIQUIDITY: u64 = ONE_ORE * 5;
/// The minimum difficulty required for payout.
pub const NUGGET_DIFFICULTY: u64 = 10;

View File

@@ -8,11 +8,14 @@ pub enum OreInstruction {
Mine = 2,
Swap = 3,
Initialize = 4,
Open = 5,
Close = 6,
Reset = 7,
// Admin
SetAdmin = 9,
SetFeeCollector = 10,
SetFeeRate = 11,
SetAdmin = 8,
SetFeeCollector = 9,
SetFeeRate = 10,
}
#[repr(C)]
@@ -25,6 +28,10 @@ pub struct Open {
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct Close {}
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct Reset {}
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct Commit {
@@ -47,7 +54,7 @@ pub struct Log {
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct Mine {
pub amount: [u8; 8],
pub nonce: [u8; 8],
}
#[repr(C)]
@@ -82,10 +89,13 @@ pub struct SetFeeRate {
pub fee_rate: [u8; 8],
}
instruction!(OreInstruction, Open);
instruction!(OreInstruction, Close);
instruction!(OreInstruction, Reset);
instruction!(OreInstruction, Initialize);
instruction!(OreInstruction, Log);
instruction!(OreInstruction, Mine);
instruction!(OreInstruction, Swap);
instruction!(OreInstruction, Initialize);
instruction!(OreInstruction, SetAdmin);
instruction!(OreInstruction, SetFeeCollector);
instruction!(OreInstruction, SetFeeRate);

View File

@@ -33,7 +33,7 @@ pub fn program_log(
)
}
pub fn mine(signer: Pubkey, authority: Pubkey, id: u64, amount: u64) -> Instruction {
pub fn mine(signer: Pubkey, authority: Pubkey, id: u64, nonce: u64) -> Instruction {
let block_adddress = block_pda(id).0;
let market_address = market_pda().0;
let miner_address = miner_pda(authority).0;
@@ -55,7 +55,7 @@ pub fn mine(signer: Pubkey, authority: Pubkey, id: u64, amount: u64) -> Instruct
AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
],
data: Mine {
amount: amount.to_le_bytes(),
nonce: nonce.to_le_bytes(),
}
.to_bytes(),
}

View File

@@ -5,76 +5,41 @@ use steel::*;
pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
let clock = Clock::get()?;
let [signer_info, block_info, config_info, collateral_info, commitment_info, fee_collector_info, market_info, miner_info, mint_base_info, mint_quote_info, opener_info, recipient_info, treasury_info, vault_base_info, vault_quote_info, system_program, token_program, ore_program] =
let [signer_info, block_info, miner_info, mint_info, opener_info, recipient_info, treasury_info, system_program, token_program, ore_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?;
let block = block_info
.as_account_mut::<Block>(&ore_api::ID)?
.assert_mut(|b| clock.slot >= b.start_slot + 1500)?;
let config = config_info.as_account::<Config>(&ore_api::ID)?;
collateral_info
.is_writable()?
.has_address(&collateral_pda(block.id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_quote_info.key)?
.assert(|t| t.owner() == *block_info.key)?;
commitment_info
.is_writable()?
.has_address(&commitment_pda(block.id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_base_info.key)?
.assert(|t| t.owner() == *block_info.key)?;
fee_collector_info
.is_writable()?
.as_associated_token_account(&config.fee_collector, &mint_quote_info.key)?;
let market = market_info
.as_account_mut::<Market>(&ore_api::ID)?
.assert_mut(|m| m.id == block.id)?;
mint_base_info.has_address(&market.base.mint)?.as_mint()?;
mint_quote_info.has_address(&market.quote.mint)?.as_mint()?;
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
// TODO Ensure block is closed.
// .assert_mut(|b| clock.slot >= b.start_slot + 1500)?;
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
opener_info.is_writable()?.has_address(&block.opener)?;
treasury_info
.is_writable()?
.has_address(&TREASURY_ADDRESS)?;
vault_base_info
.is_writable()?
.has_address(&vault_base_pda(block.id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_base_info.key)?
.assert(|t| t.owner() == *market_info.key)?;
vault_quote_info
.is_writable()?
.has_address(&vault_quote_pda(block.id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_quote_info.key)?
.assert(|t| t.owner() == *market_info.key)?;
treasury_info.as_account::<Treasury>(&ore_api::ID)?;
system_program.is_program(&system_program::ID)?;
token_program.is_program(&spl_token::ID)?;
ore_program.is_program(&ore_api::ID)?;
// Payout block reward.
if block.reward.lode_reward > 0 && block.reward.lode_authority != Pubkey::default() {
if block.reward > 0 && block.best_hash_miner != Pubkey::default() {
// Load recipient.
recipient_info.as_associated_token_account(&block.reward.lode_authority, &MINT_ADDRESS)?;
recipient_info.as_associated_token_account(&block.best_hash_miner, &mint_info.key)?;
let miner = miner_info
.as_account_mut::<Miner>(&ore_api::ID)?
.assert_mut(|m| m.authority == block.reward.lode_authority)?;
.assert_mut(|m| m.authority == block.best_hash_miner)?;
// Limit payout to supply cap.
let ore_mint = mint_quote_info.as_mint()?;
let ore_mint = mint_info.as_mint()?;
let max_reward = MAX_SUPPLY.saturating_sub(ore_mint.supply());
let reward_amount = block.reward.lode_reward.min(max_reward);
let reward_amount = block.reward.min(max_reward);
// Update stats.
block.total_rewards += reward_amount;
miner.total_rewards += reward_amount;
// Mint reward to recipient.
mint_to_signed(
mint_quote_info,
mint_info,
recipient_info,
treasury_info,
token_program,
@@ -83,108 +48,33 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
)?;
// Emit event.
RewardEvent {
disc: OreEvent::Reward as u64,
amount: reward_amount,
authority: block.reward.lode_authority,
block_id: block.id,
rewards_type: RewardsType::Lode as u64,
ts: clock.unix_timestamp,
}
.log();
// RewardEvent {
// disc: OreEvent::Reward as u64,
// amount: reward_amount,
// authority: block.reward.lode_authority,
// block_id: block.id,
// rewards_type: RewardsType::Lode as u64,
// ts: clock.unix_timestamp,
// }
// .log();
}
// Payout fee.
if market.fee.uncollected > 0 {
transfer_signed(
market_info,
vault_quote_info,
fee_collector_info,
token_program,
market.fee.uncollected,
&[MARKET, &market.id.to_le_bytes()],
)?;
market.fee.uncollected = 0;
}
// Burn base liquidity.
let vault_base = vault_base_info.as_token_account()?;
let base_burned = vault_base.amount();
burn_signed(
vault_base_info,
mint_base_info,
market_info,
token_program,
base_burned,
&[MARKET, &market.id.to_le_bytes()],
)?;
// Burn quote liquidity.
let vault_quote = vault_quote_info.as_token_account()?;
let quote_burned = vault_quote.amount();
burn_signed(
vault_quote_info,
mint_quote_info,
market_info,
token_program,
quote_burned,
&[MARKET, &market.id.to_le_bytes()],
)?;
// Burn any remaining commitment.
let commitment = commitment_info.as_token_account()?;
let commitment_burned = commitment.amount();
burn_signed(
commitment_info,
mint_base_info,
block_info,
token_program,
commitment_burned,
&[BLOCK, &block.id.to_le_bytes()],
)?;
// Emit event.
program_log(
block.id,
&[block_info.clone(), ore_program.clone()],
&CloseEvent {
authority: *signer_info.key,
id: block.id,
burned_base: base_burned,
burned_quote: quote_burned,
ts: clock.unix_timestamp,
}
.to_bytes(),
)?;
// Close token accounts.
close_token_account_signed(
vault_base_info,
opener_info,
market_info,
token_program,
&[MARKET, &market.id.to_le_bytes()],
)?;
close_token_account_signed(
vault_quote_info,
opener_info,
market_info,
token_program,
&[MARKET, &market.id.to_le_bytes()],
)?;
close_token_account_signed(
commitment_info,
opener_info,
block_info,
token_program,
&[BLOCK, &block.id.to_le_bytes()],
)?;
// program_log(
// block.id,
// &[block_info.clone(), ore_program.clone()],
// &CloseEvent {
// authority: *signer_info.key,
// id: block.id,
// burned_base: base_burned,
// burned_quote: quote_burned,
// ts: clock.unix_timestamp,
// }
// .to_bytes(),
// )?;
// Close block.
block_info.close(opener_info)?;
// Close market.
market_info.close(opener_info)?;
Ok(())
}

View File

@@ -1,4 +1,5 @@
use ore_api::prelude::*;
use solana_program::program_pack::Pack;
use steel::*;
/// Sets the admin.
@@ -7,7 +8,9 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
// let args = Initialize::try_from_bytes(data)?;
// Load accounts.
let [signer_info, config_info, market_info, treasury_info, system_program] = accounts else {
let [signer_info, config_info, market_info, mint_info, treasury_info, vault_info, system_program, token_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?.has_address(&ADMIN_ADDRESS)?;
@@ -19,11 +22,17 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
.is_writable()?
.is_empty()?
.has_seeds(&[MARKET], &ore_api::ID)?;
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
treasury_info
.is_writable()?
.is_empty()?
.has_seeds(&[TREASURY], &ore_api::ID)?;
vault_info
.is_writable()?
.is_empty()?
.has_address(&vault_pda().0)?;
system_program.is_program(&system_program::ID)?;
token_program.is_program(&spl_token::ID)?;
// Create config account.
create_program_account::<Config>(
@@ -80,5 +89,43 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
&[TREASURY],
)?;
// Initialize vault token account.
if vault_info.data_is_empty() {
let vault_pda = vault_pda();
allocate_account_with_bump(
vault_info,
system_program,
signer_info,
spl_token::state::Account::LEN,
&spl_token::ID,
&[
market_info.key.as_ref(),
token_program.key.as_ref(),
mint_info.key.as_ref(),
],
vault_pda.1,
)?;
solana_program::program::invoke(
&spl_token_2022::instruction::initialize_account3(
&spl_token::ID,
&vault_pda.0,
&mint_info.key,
&market_info.key,
)?,
&[
vault_info.clone(),
mint_info.clone(),
market_info.clone(),
token_program.clone(),
],
)?;
} else {
vault_info
.has_address(&vault_pda().0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_info.key)?
.assert(|t| t.owner() == *market_info.key)?;
}
Ok(())
}

View File

@@ -1,14 +1,20 @@
mod close;
mod initialize;
mod log;
mod mine;
mod open;
mod reset;
mod set_admin;
mod set_fee_collector;
mod set_fee_rate;
mod swap;
use close::*;
use initialize::*;
use log::*;
use mine::*;
use open::*;
use reset::*;
use set_admin::*;
use set_fee_collector::*;
use set_fee_rate::*;
@@ -26,9 +32,12 @@ pub fn process_instruction(
match ix {
// User
OreInstruction::Open => process_open(accounts, data)?,
OreInstruction::Close => process_close(accounts, data)?,
OreInstruction::Log => process_log(accounts, data)?,
OreInstruction::Mine => process_mine(accounts, data)?,
OreInstruction::Swap => process_swap(accounts, data)?,
OreInstruction::Reset => process_reset(accounts, data)?,
OreInstruction::Initialize => process_initialize(accounts, data)?,
// Admin

View File

@@ -7,11 +7,11 @@ use steel::*;
pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
// Parse data.
let args = Mine::try_from_bytes(data)?;
let amount = u64::from_le_bytes(args.amount);
let nonce = u64::from_le_bytes(args.nonce);
// Load accounts.
let clock = Clock::get()?;
let [signer_info, authority_info, block_info, market_info, miner_info, mint_info, recipient_info, treasury_info, system_program, token_program, ore_program, slot_hashes_sysvar] =
let [signer_info, authority_info, block_info, miner_info, mint_info, recipient_info, treasury_info, system_program, token_program, ore_program, slot_hashes_sysvar] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
@@ -21,9 +21,9 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
// .assert_mut(|b| clock.slot >= b.start_slot)?
// .assert_mut(|b| clock.slot < b.start_slot + 1500)?;
let market = market_info
.as_account::<Market>(&ore_api::ID)?
.assert(|m| m.block_id == block.id)?;
// let market = market_info
// .as_account::<Market>(&ore_api::ID)?
// .assert(|m| m.block_id == block.id)?;
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
let miner = miner_info
.as_account_mut::<Miner>(&ore_api::ID)?

View File

@@ -1,7 +1,5 @@
use ore_api::{prelude::*, sdk::program_log};
use ore_api::prelude::*;
use solana_nostd_keccak::hash;
use solana_program::program_pack::Pack;
use spl_token_2022::instruction::AuthorityType;
use steel::*;
/// Opens a new block.
@@ -12,9 +10,7 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
// Load accounts.
let clock = Clock::get()?;
let [signer_info, block_info, config_info, collateral_info, commitment_info, market_info, mint_base_info, mint_quote_info, sender_info, treasury_info, vault_base_info, vault_quote_info, system_program, token_program, associated_token_program, ore_program, rent_sysvar] =
accounts
else {
let [signer_info, block_info, system_program, ore_program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?;
@@ -22,25 +18,10 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
.is_empty()?
.is_writable()?
.has_seeds(&[BLOCK, &id.to_le_bytes()], &ore_api::ID)?;
let config = config_info.as_account::<Config>(&ore_api::ID)?;
market_info
.is_empty()?
.is_writable()?
.has_seeds(&[MARKET, &id.to_le_bytes()], &ore_api::ID)?;
mint_base_info
.is_empty()?
.is_writable()?
.has_seeds(&[MINT, &id.to_le_bytes()], &ore_api::ID)?;
mint_quote_info.has_address(&MINT_ADDRESS)?.as_mint()?;
sender_info
.is_writable()?
.as_associated_token_account(&signer_info.key, &mint_quote_info.key)?;
treasury_info.has_address(&TREASURY_ADDRESS)?;
system_program.is_program(&system_program::ID)?;
token_program.is_program(&spl_token::ID)?;
associated_token_program.is_program(&spl_associated_token_account::ID)?;
ore_program.is_program(&ore_api::ID)?;
rent_sysvar.is_sysvar(&sysvar::rent::ID)?;
// TODO
// Error out if start slot is within the current period.
let start_slot = id * 1500;
@@ -50,11 +31,8 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
if start_slot < current_period_end {
return Err(ProgramError::InvalidArgument);
}
if id > current_block + config.block_limit {
return Err(ProgramError::InvalidArgument);
}
// Initialize config.
// Initialize block.
create_program_account::<Block>(
block_info,
system_program,
@@ -65,279 +43,36 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
block.id = id;
block.opener = *signer_info.key;
block.reward = RewardConfig {
lode_hash: [0; 32],
lode_authority: Pubkey::default(),
lode_reward: 0,
nugget_reward: 0,
nugget_threshold: NUGGET_DIFFICULTY,
};
block.slot_hash = [0; 32];
block.start_slot = start_slot;
block.total_committed = 0;
block.total_deployed = 0;
block.total_rewards = 0;
// Select reward strategy.
let noise_seed = block.id.to_le_bytes();
let noise = hash(&noise_seed);
let lode_reward = ONE_ORE * generate_lode(noise) as u64;
let target_block_reward = ONE_ORE * 10;
let expected_hashes_per_block = HASH_TOKEN_SUPPLY / 2;
let expected_qualifying_hashes = expected_hashes_per_block / 2u64.pow(NUGGET_DIFFICULTY as u32);
let difficulty_reward = (target_block_reward - lode_reward) / expected_qualifying_hashes;
block.reward.lode_reward = lode_reward;
block.reward.nugget_reward = difficulty_reward;
// Initialize market.
create_program_account::<Market>(
market_info,
system_program,
signer_info,
&ore_api::ID,
&[MARKET, &id.to_le_bytes()],
)?;
let market = market_info.as_account_mut::<Market>(&ore_api::ID)?;
market.base = TokenParams {
mint: *mint_base_info.key,
balance: HASH_TOKEN_SUPPLY,
balance_virtual: 0,
};
market.quote = TokenParams {
mint: *mint_quote_info.key,
balance: 0,
balance_virtual: VIRTUAL_LIQUIDITY,
};
market.fee = FeeParams {
rate: FEE_RATE_BPS,
uncollected: 0,
cumulative: 0,
};
market.snapshot = Snapshot {
enabled: 1,
base_balance: 0,
quote_balance: 0,
slot: 0,
};
market.id = id;
// Initialize hash token mint.
let mint_bump = mint_pda(block.id).1;
allocate_account_with_bump(
mint_base_info,
system_program,
signer_info,
spl_token::state::Mint::LEN,
&spl_token::ID,
&[MINT, &id.to_le_bytes()],
mint_bump,
)?;
initialize_mint_signed_with_bump(
mint_base_info,
block_info,
None,
token_program,
rent_sysvar,
0,
&[MINT, &id.to_le_bytes()],
mint_bump,
)?;
// TODO Initialize hash token metadata.
// Initialize collateral and commitment token accounts.
if collateral_info.data_is_empty() {
let collateral_pda = collateral_pda(id);
allocate_account_with_bump(
collateral_info,
system_program,
signer_info,
spl_token::state::Account::LEN,
&spl_token::ID,
&[
block_info.key.as_ref(),
token_program.key.as_ref(),
mint_quote_info.key.as_ref(),
],
collateral_pda.1,
)?;
solana_program::program::invoke(
&spl_token_2022::instruction::initialize_account3(
&spl_token::ID,
&collateral_pda.0,
&mint_quote_info.key,
&block_info.key,
)?,
&[
collateral_info.clone(),
mint_quote_info.clone(),
block_info.clone(),
token_program.clone(),
],
)?;
} else {
collateral_info
.has_address(&collateral_pda(id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_quote_info.key)?
.assert(|t| t.owner() == *block_info.key)?;
}
if commitment_info.data_is_empty() {
let commitment_pda = commitment_pda(id);
allocate_account_with_bump(
commitment_info,
system_program,
signer_info,
spl_token::state::Account::LEN,
&spl_token::ID,
&[
block_info.key.as_ref(),
token_program.key.as_ref(),
mint_base_info.key.as_ref(),
],
commitment_pda.1,
)?;
solana_program::program::invoke(
&spl_token_2022::instruction::initialize_account3(
&spl_token::ID,
&commitment_pda.0,
&mint_base_info.key,
&block_info.key,
)?,
&[
commitment_info.clone(),
mint_base_info.clone(),
block_info.clone(),
token_program.clone(),
],
)?;
} else {
commitment_info
.has_address(&commitment_pda(id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_base_info.key)?
.assert(|t| t.owner() == *block_info.key)?;
}
// Initialize base vault token account.
if vault_base_info.data_is_empty() {
let vault_base_pda = vault_base_pda(id);
allocate_account_with_bump(
vault_base_info,
system_program,
signer_info,
spl_token::state::Account::LEN,
&spl_token::ID,
&[
market_info.key.as_ref(),
token_program.key.as_ref(),
mint_base_info.key.as_ref(),
],
vault_base_pda.1,
)?;
solana_program::program::invoke(
&spl_token_2022::instruction::initialize_account3(
&spl_token::ID,
&vault_base_pda.0,
&mint_base_info.key,
&market_info.key,
)?,
&[
vault_base_info.clone(),
mint_base_info.clone(),
market_info.clone(),
token_program.clone(),
],
)?;
} else {
vault_base_info
.has_address(&vault_base_pda(id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_base_info.key)?
.assert(|t| t.owner() == *market_info.key)?;
}
// Initialize quote vault token account.
if vault_quote_info.data_is_empty() {
let vault_quote_pda = vault_quote_pda(id);
allocate_account_with_bump(
vault_quote_info,
system_program,
signer_info,
spl_token::state::Account::LEN,
&spl_token::ID,
&[
market_info.key.as_ref(),
token_program.key.as_ref(),
mint_quote_info.key.as_ref(),
],
vault_quote_pda.1,
)?;
solana_program::program::invoke(
&spl_token_2022::instruction::initialize_account3(
&spl_token::ID,
&vault_quote_pda.0,
&mint_quote_info.key,
&market_info.key,
)?,
&[
vault_quote_info.clone(),
mint_quote_info.clone(),
market_info.clone(),
token_program.clone(),
],
)?;
} else {
vault_quote_info
.has_address(&vault_quote_pda(id).0)?
.as_token_account()?
.assert(|t| t.mint() == *mint_quote_info.key)?
.assert(|t| t.owner() == *market_info.key)?;
}
// Mint hash tokens to market.
mint_to_signed(
mint_base_info,
vault_base_info,
block_info,
token_program,
HASH_TOKEN_SUPPLY,
&[BLOCK, &id.to_le_bytes()],
)?;
// Burn mint authority.
set_authority_signed(
mint_base_info,
block_info,
None,
AuthorityType::MintTokens,
token_program,
&[BLOCK, &id.to_le_bytes()],
)?;
block.reward = ONE_ORE * generate_lode(block.id) as u64;
block.total_hashpower = 0;
// Emit event.
program_log(
id,
&[block_info.clone(), ore_program.clone()],
&OpenEvent {
disc: OreEvent::Open as u64,
id,
start_slot,
signer: *signer_info.key,
reward_config: block.reward,
liquidity_base: market.base.liquidity() as u64,
liquidity_quote: market.quote.liquidity() as u64,
ts: clock.unix_timestamp,
}
.to_bytes(),
)?;
// program_log(
// id,
// &[block_info.clone(), ore_program.clone()],
// &OpenEvent {
// disc: OreEvent::Open as u64,
// id,
// start_slot,
// signer: *signer_info.key,
// reward_config: block.reward,
// // liquidity_base: market.base.liquidity() as u64,
// // liquidity_quote: market.quote.liquidity() as u64,
// ts: clock.unix_timestamp,
// }
// .to_bytes(),
// )?;
Ok(())
}
fn generate_lode(hash: [u8; 32]) -> u8 {
// Extract the first byte (0 to 255)
let byte_value = hash[0];
fn generate_lode(block_id: u64) -> u8 {
// Generate noise.
let noise_seed = block_id.to_le_bytes();
let noise = hash(&noise_seed);
// Extract the first byte (0 to 255).
let byte_value = noise[0];
// Map to 1-10 using integer division
let reward = (byte_value / 25) + 1;
@@ -353,11 +88,9 @@ fn generate_lode(hash: [u8; 32]) -> u8 {
#[test]
fn test_lode_rewards() {
for i in 0u64..1000 {
let noise_seed = i.to_le_bytes();
let noise = hash(&noise_seed);
let lode_reward = ONE_ORE * generate_lode(noise) as u64;
let lode_reward = ONE_ORE * generate_lode(i) as u64;
let target_block_reward = ONE_ORE * 10;
let expected_hashes_per_block = HASH_TOKEN_SUPPLY / 2;
let expected_hashes_per_block = HASHPOWER_LIQUIDITY / 2;
let expected_qualifying_hashes =
expected_hashes_per_block / 2u64.pow(NUGGET_DIFFICULTY as u32);
let difficulty_reward = (target_block_reward - lode_reward) / expected_qualifying_hashes;

67
program/src/reset.rs Normal file
View File

@@ -0,0 +1,67 @@
use ore_api::prelude::*;
use steel::*;
/// Resets a block.
pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
// let clock = Clock::get()?;
let [signer_info, block_info, config_info, fee_collector_info, market_info, mint_info, vault_info, system_program, token_program, ore_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?;
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
let config = config_info.as_account::<Config>(&ore_api::ID)?;
fee_collector_info
.is_writable()?
.as_associated_token_account(&config.fee_collector, &mint_info.key)?;
let market = market_info
.as_account_mut::<Market>(&ore_api::ID)?
.assert_mut(|m| m.block_id == block.id - 1)?;
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
let vault = vault_info.as_associated_token_account(&mint_info.key, &mint_info.key)?;
system_program.is_program(&system_program::ID)?;
token_program.is_program(&spl_token::ID)?;
ore_program.is_program(&ore_api::ID)?;
// Payout fee.
if market.fee.uncollected > 0 {
transfer_signed(
market_info,
vault_info,
fee_collector_info,
token_program,
market.fee.uncollected,
&[MARKET],
)?;
market.fee.uncollected = 0;
}
// Burn vault liquidity.
let burn_amount = vault.amount();
burn_signed(
vault_info,
mint_info,
market_info,
token_program,
burn_amount,
&[MARKET],
)?;
// Reset market account.
market.block_id = block.id;
market.base.balance = HASHPOWER_LIQUIDITY;
market.base.balance_virtual = 0;
market.quote.balance = 0;
market.quote.balance_virtual = ORE_LIQUIDITY;
market.snapshot.enabled = 1;
market.snapshot.base_balance = 0;
market.snapshot.quote_balance = 0;
market.snapshot.slot = 0;
market.fee.rate = config.fee_rate;
market.fee.uncollected = 0;
market.fee.cumulative = 0;
Ok(())
}