mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-14 07:26:51 +00:00
scaffold
This commit is contained in:
@@ -1,87 +0,0 @@
|
||||
use meteora_pools_sdk::instructions::{SwapCpi, SwapCpiAccounts, SwapInstructionArgs};
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Swap commits into ORE and bury the ORE.
|
||||
pub fn process_bury(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Bury::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let (required_accounts, meteora_accounts) = accounts.split_at(6);
|
||||
let [signer_info, block_info, block_commits_info, block_ore_info, mint_info, ore_mint_info] =
|
||||
required_accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?; // .has_address(&ADMIN_ADDRESS)?;
|
||||
block_info.as_account::<Block>(&ore_api::ID)?;
|
||||
let block_commits = block_commits_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(block_info.key, mint_info.key)?;
|
||||
block_ore_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(block_info.key, &MINT_ADDRESS)?;
|
||||
mint_info.as_mint()?;
|
||||
ore_mint_info.has_address(&MINT_ADDRESS)?.as_mint()?;
|
||||
|
||||
// Load meteora accounts.
|
||||
let [pool_info, a_vault_info, b_vault_info, a_token_vault_info, b_token_vault_info, a_vault_lp_mint_info, b_vault_lp_mint_info, a_vault_lp_info, b_vault_lp_info, protocol_token_fee_info, vault_program_info, token_program_info, meteora_pools_program] =
|
||||
meteora_accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
meteora_pools_program.is_program(&meteora_pools_sdk::programs::AMM_ID)?;
|
||||
|
||||
// Execute swap.
|
||||
let swap = SwapCpi::new(
|
||||
&meteora_pools_program,
|
||||
SwapCpiAccounts {
|
||||
pool: pool_info,
|
||||
user_source_token: block_commits_info,
|
||||
user_destination_token: block_ore_info,
|
||||
a_vault: a_vault_info,
|
||||
b_vault: b_vault_info,
|
||||
a_token_vault: a_token_vault_info,
|
||||
b_token_vault: b_token_vault_info,
|
||||
a_vault_lp_mint: a_vault_lp_mint_info,
|
||||
b_vault_lp_mint: b_vault_lp_mint_info,
|
||||
a_vault_lp: a_vault_lp_info,
|
||||
b_vault_lp: b_vault_lp_info,
|
||||
protocol_token_fee: protocol_token_fee_info,
|
||||
user: block_info,
|
||||
vault_program: vault_program_info,
|
||||
token_program: token_program_info,
|
||||
},
|
||||
SwapInstructionArgs {
|
||||
in_amount: block_commits.amount().min(amount),
|
||||
minimum_out_amount: 0, // TODO: Calculate minimum out amount with slippage
|
||||
},
|
||||
);
|
||||
let block_bump = block_pda().1;
|
||||
swap.invoke_signed(&[&[BLOCK, &[block_bump]]])?;
|
||||
|
||||
// Burn (bury) the purchased ORE.
|
||||
let block_ore = block_ore_info.as_associated_token_account(block_info.key, &MINT_ADDRESS)?;
|
||||
let burn_amount = block_ore.amount();
|
||||
burn_signed_with_bump(
|
||||
block_ore_info,
|
||||
ore_mint_info,
|
||||
block_info,
|
||||
token_program_info,
|
||||
burn_amount,
|
||||
&[BLOCK],
|
||||
block_bump,
|
||||
)?;
|
||||
|
||||
// Emit an event.
|
||||
BuryEvent {
|
||||
amount: burn_amount,
|
||||
ts: clock.unix_timestamp as u64,
|
||||
}
|
||||
.log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
0
program/src/buy.rs
Normal file
0
program/src/buy.rs
Normal file
@@ -1,54 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Claim distributes claimable ORE from the treasury to a miner.
|
||||
pub fn process_claim(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse args.
|
||||
let args = Claim::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, beneficiary_info, proof_info, treasury_info, treasury_tokens_info, token_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
beneficiary_info
|
||||
.is_writable()?
|
||||
.as_token_account()?
|
||||
.assert(|t| t.mint() == MINT_ADDRESS)?;
|
||||
let proof = proof_info
|
||||
.as_account_mut::<Proof>(&ore_api::ID)?
|
||||
.assert_mut_err(
|
||||
|p| p.authority == *signer_info.key,
|
||||
ProgramError::MissingRequiredSignature,
|
||||
)?;
|
||||
treasury_info.has_address(&TREASURY_ADDRESS)?;
|
||||
treasury_tokens_info
|
||||
.is_writable()?
|
||||
.has_address(&TREASURY_TOKENS_ADDRESS)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
|
||||
// Update miner balance.
|
||||
proof.balance = proof
|
||||
.balance
|
||||
.checked_sub(amount)
|
||||
.ok_or(ProgramError::InsufficientFunds)?;
|
||||
|
||||
// Update last claim timestamp.
|
||||
proof.last_claim_at = clock.unix_timestamp;
|
||||
|
||||
// Transfer tokens from treasury to beneficiary.
|
||||
transfer_signed(
|
||||
treasury_info,
|
||||
treasury_tokens_info,
|
||||
beneficiary_info,
|
||||
token_program,
|
||||
amount,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Close a commit account.
|
||||
pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let [signer_info, block_info, commit_info, system_program] = accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info.as_account::<Block>(&ore_api::ID)?;
|
||||
commit_info
|
||||
.as_account_mut::<Commit>(&ore_api::ID)?
|
||||
.assert_mut(|c| c.authority == *signer_info.key)?
|
||||
.assert_mut(|c| c.round < block.current_round)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
|
||||
// Close the commit account
|
||||
commit_info.close(&signer_info)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::keccak::hashv;
|
||||
use steel::*;
|
||||
|
||||
/// Deploy capital to mine the current block.
|
||||
pub fn process_deploy(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Deploy::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
let seed = args.seed;
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, block_commits_info, commit_info, sender_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info
|
||||
.as_account_mut::<Block>(&ore_api::ID)?
|
||||
.assert_mut(|b| b.ends_at > clock.slot)?
|
||||
.assert_mut(|b| b.paid == 0)?;
|
||||
block_commits_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(block_info.key, &block.mint)?;
|
||||
commit_info.is_writable()?.is_empty()?.has_seeds(
|
||||
&[COMMIT, &block.current_round.to_le_bytes(), &seed],
|
||||
&ore_api::ID,
|
||||
)?;
|
||||
sender_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(signer_info.key, &block.mint)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||
|
||||
// Create commit account.
|
||||
create_program_account::<Commit>(
|
||||
&commit_info,
|
||||
&system_program,
|
||||
&signer_info,
|
||||
&ore_api::ID,
|
||||
&[COMMIT, &block.current_round.to_le_bytes(), &seed],
|
||||
)?;
|
||||
let commit = commit_info.as_account_mut::<Commit>(&ore_api::ID)?;
|
||||
commit.amount = amount;
|
||||
commit.authority = *signer_info.key;
|
||||
commit.cumulative_sum = block.cumulative_sum;
|
||||
commit.round = block.current_round;
|
||||
commit.seed = seed;
|
||||
commit.timestamp = clock.unix_timestamp as u64;
|
||||
|
||||
// Update block stats.
|
||||
block.cumulative_sum += amount;
|
||||
block.total_commits += 1;
|
||||
|
||||
// Hash client seed into block noise for provably fair randomness.
|
||||
block.noise = hashv(&[&block.noise, &seed]).to_bytes();
|
||||
|
||||
// Transfer commits.
|
||||
transfer(
|
||||
&signer_info,
|
||||
&sender_info,
|
||||
&block_commits_info,
|
||||
&token_program,
|
||||
amount,
|
||||
)?;
|
||||
|
||||
// Emit an event.
|
||||
DeployEvent {
|
||||
authority: *signer_info.key,
|
||||
amount,
|
||||
ts: clock.unix_timestamp as u64,
|
||||
}
|
||||
.log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
0
program/src/deposit.rs
Normal file
0
program/src/deposit.rs
Normal file
0
program/src/free.rs
Normal file
0
program/src/free.rs
Normal file
@@ -1,65 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Initialize the program.
|
||||
pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let [signer_info, block_info, block_commits_info, block_ore_info, ore_mint_info, sol_mint_info, system_program, token_program, associated_token_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?; // .has_address(&ADMIN_ADDRESS)?;
|
||||
block_info
|
||||
.is_empty()?
|
||||
.is_writable()?
|
||||
.has_seeds(&[BLOCK], &ore_api::ID)?;
|
||||
block_commits_info.is_empty()?.is_writable()?;
|
||||
block_ore_info.is_empty()?.is_writable()?;
|
||||
ore_mint_info.has_address(&MINT_ADDRESS)?;
|
||||
sol_mint_info.has_address(&spl_token::native_mint::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
associated_token_program.is_program(&spl_associated_token_account::ID)?;
|
||||
|
||||
// Initialize config.
|
||||
create_program_account::<Block>(
|
||||
block_info,
|
||||
system_program,
|
||||
signer_info,
|
||||
&ore_api::ID,
|
||||
&[BLOCK],
|
||||
)?;
|
||||
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
|
||||
block.cumulative_sum = 0;
|
||||
block.current_round = 0;
|
||||
block.ends_at = 0;
|
||||
block.mint = spl_token::native_mint::ID;
|
||||
block.noise = [0; 32];
|
||||
block.paid = 0;
|
||||
block.reward = 0;
|
||||
block.started_at = 0;
|
||||
block.total_commits = 0;
|
||||
|
||||
// Initialize block token accounts.
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
block_info,
|
||||
block_commits_info,
|
||||
sol_mint_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
block_info,
|
||||
block_ore_info,
|
||||
ore_mint_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,18 +1,20 @@
|
||||
mod bury;
|
||||
mod claim;
|
||||
mod buy;
|
||||
mod close;
|
||||
mod deploy;
|
||||
mod initialize;
|
||||
mod payout;
|
||||
mod reset;
|
||||
mod deposit;
|
||||
mod free;
|
||||
mod mine;
|
||||
mod open;
|
||||
mod sell;
|
||||
mod withdraw;
|
||||
|
||||
use bury::*;
|
||||
use claim::*;
|
||||
use buy::*;
|
||||
use close::*;
|
||||
use deploy::*;
|
||||
use initialize::*;
|
||||
use payout::*;
|
||||
use reset::*;
|
||||
use deposit::*;
|
||||
use free::*;
|
||||
use mine::*;
|
||||
use open::*;
|
||||
use sell::*;
|
||||
use withdraw::*;
|
||||
|
||||
use ore_api::instruction::*;
|
||||
use steel::*;
|
||||
@@ -25,16 +27,10 @@ pub fn process_instruction(
|
||||
let (ix, data) = parse_instruction(&ore_api::ID, program_id, data)?;
|
||||
|
||||
match ix {
|
||||
// User
|
||||
OreInstruction::Claim => process_claim(accounts, data)?,
|
||||
OreInstruction::Close => process_close(accounts, data)?,
|
||||
OreInstruction::Deploy => process_deploy(accounts, data)?,
|
||||
OreInstruction::Payout => process_payout(accounts, data)?,
|
||||
OreInstruction::Reset => process_reset(accounts, data)?,
|
||||
OreInstruction::Open => process_open(accounts, data)?,
|
||||
OreInstruction::Mine => process_mine(accounts, data)?,
|
||||
|
||||
// Admin
|
||||
OreInstruction::Bury => process_bury(accounts, data)?,
|
||||
OreInstruction::Initialize => process_initialize(accounts, data)?,
|
||||
_ => panic!("Not implemented"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
49
program/src/mine.rs
Normal file
49
program/src/mine.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::keccak;
|
||||
use steel::*;
|
||||
|
||||
/// Opens a new block for hashpower trading.
|
||||
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);
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, miner_info, system_program, token_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)?
|
||||
.assert_mut(|b| clock.slot < b.start_slot + 1500)?;
|
||||
let miner = miner_info
|
||||
.as_account_mut::<Miner>(&ore_api::ID)?
|
||||
.assert_mut(|m| m.authority == *signer_info.key)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
|
||||
// TODO Open miner account if it doesn't exist.
|
||||
// TODO Burn hash tokens
|
||||
|
||||
// Reset miner hash if mining new block.
|
||||
if miner.block_id != block.id {
|
||||
miner.block_id = block.id;
|
||||
miner.hash =
|
||||
keccak::hashv(&[block.slot_hash.as_ref(), miner.authority.as_ref()]).to_bytes();
|
||||
}
|
||||
|
||||
for _ in 0..amount {
|
||||
miner.hash = keccak::hashv(&[miner.hash.as_ref()]).to_bytes();
|
||||
if miner.hash < block.best_hash {
|
||||
block.best_hash = miner.hash;
|
||||
block.best_miner = miner.authority;
|
||||
}
|
||||
}
|
||||
|
||||
// Update miner stats.
|
||||
miner.total_hashes += amount;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
67
program/src/open.rs
Normal file
67
program/src/open.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Opens a new block for hashpower trading.
|
||||
pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Open::try_from_bytes(data)?;
|
||||
let id = u64::from_le_bytes(args.id);
|
||||
|
||||
// Load accounts.
|
||||
let [signer_info, block_info, system_program, token_program, associated_token_program] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
block_info
|
||||
.is_empty()?
|
||||
.is_writable()?
|
||||
.has_seeds(&[BLOCK, &id.to_le_bytes()], &ore_api::ID)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
associated_token_program.is_program(&spl_associated_token_account::ID)?;
|
||||
|
||||
// Initialize config.
|
||||
create_program_account::<Block>(
|
||||
block_info,
|
||||
system_program,
|
||||
signer_info,
|
||||
&ore_api::ID,
|
||||
&[BLOCK, &id.to_le_bytes()],
|
||||
)?;
|
||||
let block = block_info.as_account_mut::<Block>(&ore_api::ID)?;
|
||||
block.best_hash = [0; 32];
|
||||
block.best_miner = Pubkey::default();
|
||||
block.id = id;
|
||||
block.reward = ONE_ORE * 10;
|
||||
block.slot_hash = [0; 32];
|
||||
block.start_slot = 1500 * id;
|
||||
|
||||
// TODO Init market
|
||||
// TODO Init hash token mint
|
||||
// TODO Init token accounts for market
|
||||
// TODO Init mint hash tokens to market
|
||||
|
||||
// // Initialize block token accounts.
|
||||
// create_associated_token_account(
|
||||
// signer_info,
|
||||
// block_info,
|
||||
// block_commits_info,
|
||||
// sol_mint_info,
|
||||
// system_program,
|
||||
// token_program,
|
||||
// associated_token_program,
|
||||
// )?;
|
||||
// create_associated_token_account(
|
||||
// signer_info,
|
||||
// block_info,
|
||||
// block_ore_info,
|
||||
// ore_mint_info,
|
||||
// system_program,
|
||||
// token_program,
|
||||
// associated_token_program,
|
||||
// )?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use solana_program::keccak::hashv;
|
||||
use steel::*;
|
||||
use sysvar::slot_hashes::SlotHashes;
|
||||
|
||||
/// Payout block reward to the winning commit.
|
||||
pub fn process_payout(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, commit_info, mint_info, recipient_info, treasury_info, treasury_tokens_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info
|
||||
.as_account_mut::<Block>(&ore_api::ID)?
|
||||
.assert_mut(|b| b.ends_at <= clock.slot)?
|
||||
.assert_mut(|b| b.paid == 0)?;
|
||||
mint_info
|
||||
.is_writable()?
|
||||
.has_address(&MINT_ADDRESS)?
|
||||
.as_mint()?;
|
||||
treasury_info.has_address(&TREASURY_ADDRESS)?;
|
||||
treasury_tokens_info
|
||||
.has_address(&TREASURY_TOKENS_ADDRESS)?
|
||||
.is_writable()?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||
|
||||
// Mark the block as paid out.
|
||||
block.paid = 1;
|
||||
|
||||
// Skip if no block reward.
|
||||
if block.reward == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Skip payout if no commits were placed.
|
||||
if block.cumulative_sum == 0 {
|
||||
burn_signed(
|
||||
&treasury_tokens_info,
|
||||
&mint_info,
|
||||
&treasury_info,
|
||||
&token_program,
|
||||
block.reward,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Select the hash from the slot when the block ended for provably fair randomness.
|
||||
let slot_hashes =
|
||||
bincode::deserialize::<SlotHashes>(slot_hashes_sysvar.data.borrow().as_ref()).unwrap();
|
||||
let Some(slot_hash) = slot_hashes.get(&block.ends_at) else {
|
||||
// If payout is not called within 2.5 minutes of the block ending,
|
||||
// then the slot hash will be unavailable and the winning commit cannot be determined.
|
||||
burn_signed(
|
||||
&treasury_tokens_info,
|
||||
&mint_info,
|
||||
&treasury_info,
|
||||
&token_program,
|
||||
block.reward,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
return Ok(());
|
||||
};
|
||||
block.noise = hashv(&[&block.noise, slot_hash.as_ref()]).to_bytes();
|
||||
|
||||
// Calculate the random number.
|
||||
let x = u64::from_le_bytes(block.noise[0..8].try_into().unwrap());
|
||||
let y = u64::from_le_bytes(block.noise[8..16].try_into().unwrap());
|
||||
let z = u64::from_le_bytes(block.noise[16..24].try_into().unwrap());
|
||||
let w = u64::from_le_bytes(block.noise[24..32].try_into().unwrap());
|
||||
let roll = (x ^ y ^ z ^ w) % block.cumulative_sum;
|
||||
|
||||
// Validate the commit account.
|
||||
let commit = commit_info
|
||||
.as_account_mut::<Commit>(&ore_api::ID)?
|
||||
.assert_mut(|c| roll >= c.cumulative_sum)?
|
||||
.assert_mut(|c| roll < c.cumulative_sum + c.amount)?;
|
||||
recipient_info.as_associated_token_account(&commit.authority, &MINT_ADDRESS)?;
|
||||
|
||||
// Transfer the winnings to the recipient.
|
||||
transfer_signed(
|
||||
&treasury_info,
|
||||
&treasury_tokens_info,
|
||||
&recipient_info,
|
||||
&token_program,
|
||||
block.reward,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
|
||||
// Emit an event.
|
||||
PayoutEvent {
|
||||
authority: commit.authority,
|
||||
amount: block.reward,
|
||||
ts: clock.unix_timestamp as u64,
|
||||
}
|
||||
.log();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
use ore_api::prelude::*;
|
||||
use ore_boost_api::{consts::DENOMINATOR_BPS, prelude::Config as BoostConfig};
|
||||
use steel::*;
|
||||
|
||||
/// Start the next block.
|
||||
pub fn process_reset(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let (required_accounts, boost_accounts) = accounts.split_at(6);
|
||||
let [signer_info, block_info, mint_info, treasury_info, treasury_tokens_info, token_program] =
|
||||
required_accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info
|
||||
.as_account_mut::<Block>(&ore_api::ID)?
|
||||
.assert_mut(|b| b.ends_at <= clock.slot)?
|
||||
.assert_mut(|b| b.paid != 0)?;
|
||||
let mint = mint_info
|
||||
.has_address(&MINT_ADDRESS)?
|
||||
.is_writable()?
|
||||
.as_mint()?;
|
||||
treasury_info.has_address(&TREASURY_ADDRESS)?;
|
||||
treasury_tokens_info.has_address(&TREASURY_TOKENS_ADDRESS)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
|
||||
// Load boost accounts.
|
||||
let [boost_config_info, boost_proof_info] = boost_accounts else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
let boost_config = boost_config_info.as_account::<BoostConfig>(&ore_boost_api::ID)?;
|
||||
let boost_proof = boost_proof_info
|
||||
.as_account_mut::<Proof>(&ore_api::ID)?
|
||||
.assert_mut(|p| p.authority == *boost_config_info.key)?;
|
||||
|
||||
// Payout to boosts.
|
||||
let net_emissions = get_target_emissions_rate(mint.supply());
|
||||
let boost_reward =
|
||||
(net_emissions as u128 * boost_config.take_rate as u128 / DENOMINATOR_BPS as u128) as u64;
|
||||
boost_proof.balance += boost_reward;
|
||||
boost_proof.total_rewards += boost_reward;
|
||||
|
||||
// Reset the block.
|
||||
block.cumulative_sum = 0;
|
||||
block.current_round += 1;
|
||||
block.ends_at = clock.slot + 150; // 60 seconds
|
||||
block.noise = [0; 32];
|
||||
block.paid = 0;
|
||||
block.reward = net_emissions - boost_reward;
|
||||
block.started_at = clock.slot;
|
||||
block.total_commits = 0;
|
||||
|
||||
// Fund the treasury.
|
||||
mint_to_signed(
|
||||
mint_info,
|
||||
treasury_tokens_info,
|
||||
treasury_info,
|
||||
token_program,
|
||||
net_emissions,
|
||||
&[TREASURY],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function calculates the target emissions rate (ORE / min) based on the current supply.
|
||||
/// It is designed to reduce emissions by 10% approximately every 12 months with a hardcap at 5 million ORE.
|
||||
pub(crate) fn get_target_emissions_rate(current_supply: u64) -> u64 {
|
||||
match current_supply {
|
||||
n if n < ONE_ORE * 525_600 => 100_000_000_000, // Year ~1
|
||||
n if n < ONE_ORE * 998_640 => 90_000_000_000, // Year ~2
|
||||
n if n < ONE_ORE * 1_424_376 => 81_000_000_000, // Year ~3
|
||||
n if n < ONE_ORE * 1_807_538 => 72_900_000_000, // Year ~4
|
||||
n if n < ONE_ORE * 2_152_384 => 65_610_000_000, // Year ~5
|
||||
n if n < ONE_ORE * 2_462_746 => 59_049_000_000, // Year ~6
|
||||
n if n < ONE_ORE * 2_742_071 => 53_144_100_000, // Year ~7
|
||||
n if n < ONE_ORE * 2_993_464 => 47_829_690_000, // Year ~8
|
||||
n if n < ONE_ORE * 3_219_717 => 43_046_721_000, // Year ~9
|
||||
n if n < ONE_ORE * 3_423_346 => 38_742_048_900, // Year ~10
|
||||
n if n < ONE_ORE * 3_606_611 => 34_867_844_010, // Year ~11
|
||||
n if n < ONE_ORE * 3_771_550 => 31_381_059_609, // Year ~12
|
||||
n if n < ONE_ORE * 3_919_995 => 28_242_953_648, // Year ~13
|
||||
n if n < ONE_ORE * 4_053_595 => 25_418_658_283, // Year ~14
|
||||
n if n < ONE_ORE * 4_173_836 => 22_876_792_454, // Year ~15
|
||||
n if n < ONE_ORE * 4_282_052 => 20_589_113_208, // Year ~16
|
||||
n if n < ONE_ORE * 4_379_447 => 18_530_201_887, // Year ~17
|
||||
n if n < ONE_ORE * 4_467_102 => 16_677_181_698, // Year ~18
|
||||
n if n < ONE_ORE * 4_545_992 => 15_009_463_528, // Year ~19
|
||||
n if n < ONE_ORE * 4_616_993 => 13_508_517_175, // Year ~20
|
||||
n if n < ONE_ORE * 4_680_893 => 12_157_665_457, // Year ~21
|
||||
n if n < ONE_ORE * 4_738_404 => 10_941_898_911, // Year ~22
|
||||
n if n < ONE_ORE * 4_790_164 => 9_847_709_019, // Year ~23
|
||||
n if n < ONE_ORE * 4_836_747 => 8_862_938_117, // Year ~24
|
||||
n if n < ONE_ORE * 4_878_672 => 7_976_644_305, // Year ~25
|
||||
n if n < ONE_ORE * 4_916_405 => 7_178_979_874, // Year ~26
|
||||
n if n < ONE_ORE * 4_950_365 => 6_461_081_886, // Year ~27
|
||||
n if n < ONE_ORE * 4_980_928 => 5_814_973_607, // Year ~28
|
||||
n if n < ONE_ORE * 5_000_000 => 5_233_476_327, // Year ~29
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
0
program/src/sell.rs
Normal file
0
program/src/sell.rs
Normal file
0
program/src/withdraw.rs
Normal file
0
program/src/withdraw.rs
Normal file
Reference in New Issue
Block a user