mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-14 15:10:13 +00:00
mystery block reward, sniper fee
This commit is contained in:
56
program/src/claim.rs
Normal file
56
program/src/claim.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Claims a block reward.
|
||||
pub fn process_claim(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Claim::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts.
|
||||
let [signer_info, miner_info, miner_rewards_info, recipient_info, mint_info, system_program, token_program, associated_token_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let miner = miner_info
|
||||
.as_account::<Miner>(&ore_api::ID)?
|
||||
.assert(|m| m.authority == *signer_info.key)?;
|
||||
let miner_rewards =
|
||||
miner_rewards_info.as_associated_token_account(&miner_info.key, &mint_info.key)?;
|
||||
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
associated_token_program.is_program(&spl_associated_token_account::ID)?;
|
||||
|
||||
// Load recipient.
|
||||
if recipient_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
signer_info,
|
||||
recipient_info,
|
||||
mint_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
} else {
|
||||
recipient_info.as_associated_token_account(signer_info.key, mint_info.key)?;
|
||||
}
|
||||
|
||||
// Load amount.
|
||||
let amount = miner_rewards.amount().min(amount);
|
||||
|
||||
// Transfer reward to recipient.
|
||||
transfer_signed(
|
||||
miner_info,
|
||||
miner_rewards_info,
|
||||
mint_info,
|
||||
token_program,
|
||||
amount,
|
||||
&[MINER, miner.authority.as_ref()],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -5,7 +5,7 @@ use steel::*;
|
||||
pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, miner_info, mint_info, opener_info, recipient_info, treasury_info, system_program, token_program, ore_program] =
|
||||
let [signer_info, block_info, miner_info, miner_rewards_info, mint_info, opener_info, recipient_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program, ore_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -17,10 +17,29 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
|
||||
opener_info.is_writable()?.has_address(&block.opener)?;
|
||||
treasury_info.as_account::<Treasury>(&ore_api::ID)?;
|
||||
treasury_tokens_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(treasury_info.key, mint_info.key)?;
|
||||
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)?;
|
||||
|
||||
// Load miner rewards.
|
||||
if miner_rewards_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
miner_info,
|
||||
miner_rewards_info,
|
||||
mint_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
} else {
|
||||
miner_rewards_info.as_associated_token_account(&miner_info.key, &mint_info.key)?;
|
||||
}
|
||||
|
||||
// Payout block reward.
|
||||
if block.best_hash_miner != Pubkey::default() {
|
||||
// Load recipient.
|
||||
@@ -29,21 +48,16 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
.as_account_mut::<Miner>(&ore_api::ID)?
|
||||
.assert_mut(|m| m.authority == block.best_hash_miner)?;
|
||||
|
||||
// Limit payout to supply cap.
|
||||
let ore_mint = mint_info.as_mint()?;
|
||||
let max_reward = MAX_SUPPLY.saturating_sub(ore_mint.supply());
|
||||
let reward_amount = block.reward.min(max_reward);
|
||||
|
||||
// Update stats.
|
||||
miner.total_rewards += reward_amount;
|
||||
miner.total_rewards += block.reward;
|
||||
|
||||
// Mint reward to recipient.
|
||||
mint_to_signed(
|
||||
mint_info,
|
||||
recipient_info,
|
||||
// Transfer reward to miner.
|
||||
transfer_signed(
|
||||
treasury_info,
|
||||
treasury_tokens_info,
|
||||
miner_rewards_info,
|
||||
token_program,
|
||||
reward_amount,
|
||||
block.reward,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use steel::*;
|
||||
/// Initializes the program.
|
||||
pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let [signer_info, config_info, market_info, mint_info, treasury_info, vault_info, system_program, token_program] =
|
||||
let [signer_info, config_info, market_info, mint_info, treasury_info, treasury_tokens_info, vault_info, system_program, token_program, associated_token_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -24,12 +24,14 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
.is_writable()?
|
||||
.is_empty()?
|
||||
.has_seeds(&[TREASURY], &ore_api::ID)?;
|
||||
treasury_tokens_info.is_writable()?.is_empty()?;
|
||||
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)?;
|
||||
associated_token_program.is_program(&spl_associated_token_account::ID)?;
|
||||
|
||||
// Create config account.
|
||||
create_program_account::<Config>(
|
||||
@@ -41,9 +43,9 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
)?;
|
||||
let config = config_info.as_account_mut::<Config>(&ore_api::ID)?;
|
||||
config.admin = *signer_info.key;
|
||||
config.block_duration = 1500;
|
||||
config.block_duration = INITIAL_BLOCK_DURATION;
|
||||
config.fee_collector = *signer_info.key;
|
||||
config.fee_rate = 0;
|
||||
config.fee_rate = FEE_LAMPORTS;
|
||||
|
||||
// Initialize market.
|
||||
let initial_id: u64 = 0;
|
||||
@@ -66,7 +68,7 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
balance_virtual: 0,
|
||||
};
|
||||
market.fee = FeeParams {
|
||||
rate: FEE_RATE_BPS,
|
||||
rate: 0,
|
||||
uncollected: 0,
|
||||
cumulative: 0,
|
||||
};
|
||||
@@ -87,6 +89,21 @@ pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> Program
|
||||
&[TREASURY],
|
||||
)?;
|
||||
|
||||
// Load treasury tokens.
|
||||
if treasury_tokens_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
treasury_info,
|
||||
treasury_tokens_info,
|
||||
mint_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
} else {
|
||||
treasury_tokens_info.as_associated_token_account(treasury_info.key, mint_info.key)?;
|
||||
}
|
||||
|
||||
// Initialize vault token account.
|
||||
if vault_info.data_is_empty() {
|
||||
let vault_pda = vault_pda();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod claim;
|
||||
mod close;
|
||||
mod initialize;
|
||||
mod log;
|
||||
@@ -9,6 +10,7 @@ mod set_fee_collector;
|
||||
mod set_fee_rate;
|
||||
mod swap;
|
||||
|
||||
use claim::*;
|
||||
use close::*;
|
||||
use initialize::*;
|
||||
use log::*;
|
||||
@@ -32,6 +34,7 @@ pub fn process_instruction(
|
||||
|
||||
match ix {
|
||||
// User
|
||||
OreInstruction::Claim => process_claim(accounts, data)?,
|
||||
OreInstruction::Open => process_open(accounts, data)?,
|
||||
OreInstruction::Close => process_close(accounts, data)?,
|
||||
OreInstruction::Log => process_log(accounts, data)?,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_nostd_keccak::hash;
|
||||
use steel::*;
|
||||
|
||||
/// Opens a new block.
|
||||
@@ -34,7 +33,7 @@ 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 = calculate_reward(block.id);
|
||||
block.reward = 0;
|
||||
block.best_hash = [0; 32];
|
||||
block.best_hash_miner = Pubkey::default();
|
||||
block.start_slot = u64::MAX; // Set by reset
|
||||
@@ -61,34 +60,3 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_reward(block_id: u64) -> u64 {
|
||||
// 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 n = (byte_value / 25) + 1;
|
||||
|
||||
// Ensure the value doesn't exceed 10
|
||||
let n = n.min(10);
|
||||
|
||||
n as u64 * ONE_ORE
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lode_rewards() {
|
||||
for i in 0u64..1000 {
|
||||
let lode_reward = ONE_ORE * calculate_reward(i) as u64;
|
||||
let target_block_reward = ONE_ORE * 10;
|
||||
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;
|
||||
println!("{}: {} {}", i, lode_reward, difficulty_reward);
|
||||
}
|
||||
// assert!(false);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::slot_hashes::SlotHashes;
|
||||
use steel::*;
|
||||
@@ -6,7 +8,7 @@ use steel::*;
|
||||
pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_prev_info, block_next_info, config_info, fee_collector_info, market_info, mint_info, vault_info, system_program, token_program, ore_program, slot_hashes_sysvar] =
|
||||
let [signer_info, block_prev_info, block_next_info, config_info, fee_collector_info, market_info, mint_info, treasury_info, treasury_tokens_info, vault_info, system_program, token_program, ore_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -21,6 +23,10 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
.as_account_mut::<Market>(&ore_api::ID)?
|
||||
.assert_mut(|m| m.block_id == block_next.id - 1)?;
|
||||
mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
|
||||
treasury_info.as_account::<Treasury>(&ore_api::ID)?;
|
||||
treasury_tokens_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(treasury_info.key, mint_info.key)?;
|
||||
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)?;
|
||||
@@ -34,28 +40,33 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
.assert_mut(|b| b.id == market.block_id)?
|
||||
.assert_mut(|b| b.end_slot <= clock.slot)?;
|
||||
|
||||
// Set the slot hash of the previous block.
|
||||
let slot_hashes =
|
||||
bincode::deserialize::<SlotHashes>(slot_hashes_sysvar.data.borrow().as_ref()).unwrap();
|
||||
let Some(slot_hash) = slot_hashes.get(&block_prev.end_slot) else {
|
||||
// If mine is not called within ~2.5 minutes of the block starting,
|
||||
// then the slot hash will be unavailable and secure hashes cannot be generated.
|
||||
return Ok(());
|
||||
};
|
||||
block_prev.slot_hash = slot_hash.to_bytes();
|
||||
}
|
||||
// Get the slot hash, given the end slot of the previous block.
|
||||
if let Ok(slot_hash) = get_slot_hash(block_prev.end_slot, slot_hashes_sysvar) {
|
||||
// Set the block slot hash.
|
||||
block_prev.slot_hash = slot_hash;
|
||||
|
||||
// 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;
|
||||
// Calculate the block reward.
|
||||
let block_reward = calculate_block_reward(&block_prev.slot_hash);
|
||||
|
||||
// Limit the block reward to supply cap.
|
||||
let ore_mint = mint_info.as_mint()?;
|
||||
let max_reward = MAX_SUPPLY.saturating_sub(ore_mint.supply());
|
||||
let block_reward = block_reward.min(max_reward);
|
||||
|
||||
// Set the block reward.
|
||||
block_prev.reward = block_reward;
|
||||
|
||||
// Mint the block reward to the treasury.
|
||||
// This will get transferred to the miner account for claiming when the block is closed.
|
||||
mint_to_signed(
|
||||
mint_info,
|
||||
treasury_tokens_info,
|
||||
treasury_info,
|
||||
token_program,
|
||||
block_reward,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Burn vault liquidity.
|
||||
@@ -79,7 +90,7 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
market.snapshot.base_balance = 0;
|
||||
market.snapshot.quote_balance = 0;
|
||||
market.snapshot.slot = 0;
|
||||
market.fee.rate = config.fee_rate;
|
||||
market.fee.rate = 0;
|
||||
market.fee.uncollected = 0;
|
||||
market.fee.cumulative = 0;
|
||||
|
||||
@@ -89,3 +100,56 @@ pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_slot_hash(
|
||||
slot: u64,
|
||||
slot_hashes_sysvar: &AccountInfo<'_>,
|
||||
) -> Result<[u8; 32], ProgramError> {
|
||||
let slot_hashes =
|
||||
bincode::deserialize::<SlotHashes>(slot_hashes_sysvar.data.borrow().as_ref()).unwrap();
|
||||
let Some(slot_hash) = slot_hashes.get(&slot) else {
|
||||
// If reset is not called within ~2.5 minutes of the block ending,
|
||||
// then the slot hash will be unavailable and secure hashes cannot be generated.
|
||||
return Err(ProgramError::InvalidAccountData);
|
||||
};
|
||||
let slot_hash = slot_hash.to_bytes();
|
||||
Ok(slot_hash)
|
||||
}
|
||||
|
||||
fn calculate_block_reward(slot_hash: &[u8]) -> u64 {
|
||||
let block_distribution = HashMap::from([
|
||||
(1u64, 737869762948382064), // 4%
|
||||
(2u64, 1641760222560150093), // 4.9%
|
||||
(3u64, 2564097426245627674), // 5%
|
||||
(4u64, 3486434629931105255), // 5%
|
||||
(5u64, 4408771833616582835), // 5%
|
||||
(6u64, 5331109037302060416), // 5%
|
||||
(7u64, 6253446240987537997), // 5%
|
||||
(8u64, 7175783444673015578), // 5%
|
||||
(9u64, 8098120648358493158), // 5%
|
||||
(10u64, 9020457852043970739), // 5%
|
||||
(11u64, 9942795055729448320), // 5%
|
||||
(12u64, 10865132259414925901), // 5%
|
||||
(13u64, 11787469463100403481), // 5%
|
||||
(14u64, 12709806666785881062), // 5%
|
||||
(15u64, 13632143870471358643), // 5%
|
||||
(16u64, 14554481074156836224), // 5%
|
||||
(17u64, 15476818277842313804), // 5%
|
||||
(18u64, 16399155481527791385), // 5%
|
||||
(19u64, 17321492685213268966), // 5%
|
||||
(20u64, 18243829888898746547), // 5%
|
||||
(100u64, 18428297329635842063), // 1%
|
||||
(1000u64, u64::MAX), // 0.1%
|
||||
]);
|
||||
let r1 = u64::from_le_bytes(slot_hash[0..8].try_into().unwrap());
|
||||
let r2 = u64::from_le_bytes(slot_hash[8..16].try_into().unwrap());
|
||||
let r3 = u64::from_le_bytes(slot_hash[16..24].try_into().unwrap());
|
||||
let r4 = u64::from_le_bytes(slot_hash[24..32].try_into().unwrap());
|
||||
let r = r1 ^ r2 ^ r3 ^ r4;
|
||||
for (k, v) in block_distribution.iter() {
|
||||
if r <= *v {
|
||||
return *k;
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
@@ -17,12 +17,6 @@ pub fn process_set_fee_rate(accounts: &[AccountInfo<'_>], data: &[u8]) -> Progra
|
||||
.assert_mut(|c| c.admin == *signer_info.key)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// Limit fee rate.
|
||||
assert!(
|
||||
new_fee_rate <= FEE_RATE_BPS,
|
||||
"Fee rate must be less than or equal to 100 bps"
|
||||
);
|
||||
|
||||
// Set fee rate.
|
||||
config.fee_rate = new_fee_rate;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, market_info, miner_info, mint_info, tokens_info, vault_info, system_program, token_program, associated_token_program, ore_program] =
|
||||
let [signer_info, block_info, config_info, fee_collector_info, market_info, miner_info, mint_info, tokens_info, vault_info, system_program, token_program, associated_token_program, ore_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -21,6 +21,10 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
.as_account_mut::<Block>(&ore_api::ID)?
|
||||
.assert_mut(|b| b.start_slot <= clock.slot)?
|
||||
.assert_mut(|b| b.end_slot > clock.slot)?;
|
||||
let config = config_info.as_account_mut::<Config>(&ore_api::ID)?;
|
||||
fee_collector_info
|
||||
.is_writable()?
|
||||
.has_address(&config.fee_collector)?;
|
||||
let market = market_info
|
||||
.as_account_mut::<Market>(&ore_api::ID)?
|
||||
.assert_mut(|m| m.block_id == block.id)?
|
||||
@@ -41,6 +45,11 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
associated_token_program.is_program(&spl_associated_token_account::ID)?;
|
||||
ore_program.is_program(&ore_api::ID)?;
|
||||
|
||||
// Pay swap fee.
|
||||
if config.fee_rate > 0 {
|
||||
signer_info.send(config.fee_rate, fee_collector_info);
|
||||
}
|
||||
|
||||
// Load token acccounts.
|
||||
if tokens_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
@@ -58,7 +67,11 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
.as_associated_token_account(signer_info.key, mint_info.key)?;
|
||||
}
|
||||
|
||||
// Update market state.
|
||||
// Set the sniper fee based on time since the market began.
|
||||
let fee_rate = calculate_sniper_fee(&clock, block);
|
||||
market.fee.rate = fee_rate;
|
||||
|
||||
// Execute the swap
|
||||
let mut swap_event = market.swap(amount, direction, precision, clock)?;
|
||||
swap_event.authority = *signer_info.key;
|
||||
swap_event.block_id = block.id;
|
||||
@@ -109,3 +122,53 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_sniper_fee(clock: &Clock, block: &Block) -> u64 {
|
||||
let elapsed_slots = clock.slot.saturating_sub(block.start_slot);
|
||||
|
||||
if elapsed_slots >= 100 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Linear decay from 5000 bps (50%) to 0 bps over 100 slots
|
||||
// Using formula: y = mx + b
|
||||
// Where:
|
||||
// - x is elapsed_slots (0 to 100)
|
||||
// - y is fee_bps (5000 to 0)
|
||||
// - m = -50 (slope)
|
||||
// - b = 5000 (y-intercept)
|
||||
|
||||
let remaining_fee = 5000 - (elapsed_slots * 50);
|
||||
remaining_fee
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sniper_fees() {
|
||||
let mut clock = Clock {
|
||||
slot: 0,
|
||||
epoch_start_timestamp: 0,
|
||||
epoch: 0,
|
||||
leader_schedule_epoch: 0,
|
||||
unix_timestamp: 0,
|
||||
};
|
||||
|
||||
let block = Block {
|
||||
id: 0,
|
||||
opener: Pubkey::default(),
|
||||
reward: 0,
|
||||
best_hash: [0; 32],
|
||||
best_hash_miner: Pubkey::default(),
|
||||
start_slot: 0,
|
||||
end_slot: u64::MAX,
|
||||
slot_hash: [0; 32],
|
||||
total_hashpower: 0,
|
||||
};
|
||||
|
||||
for i in 0..200 {
|
||||
clock.slot = i;
|
||||
let fee = calculate_sniper_fee(&clock, &block);
|
||||
println!("Slot {}: {} bps fee", i, fee);
|
||||
}
|
||||
|
||||
// assert!(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user