use serde::{Deserialize, Serialize};
use steel::*;
use crate::state::refinery_pda;
use super::OilAccount;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct RigConfig {
pub mining_power: u64,
pub fuel_requirement: u64,
pub fuel_consumption_rate: u64,
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct Refinery {
pub total_network_mining_power: u64,
pub emission_per_block: u64,
pub last_emission_update_block: u64,
pub rig_supplies: [u64; 15],
pub rig_current: [u64; 15],
pub rig_configs: [RigConfig; 15],
pub admin: Pubkey,
pub refinery_rewards_factor: Numeric,
pub last_rewards_factor_block: u64,
pub init_timestamp: i64,
pub last_emission_update_timestamp: i64,
pub reserved_a: u64,
pub reserved_b: u64,
pub buffer_a: u64,
pub buffer_b: u64,
pub buffer_c: u64,
pub buffer_d: u64,
}
impl Refinery {
pub fn pda() -> (Pubkey, u8) {
refinery_pda()
}
pub fn initialize(&mut self, admin: Pubkey, clock: &Clock, initial_emission: u64) {
self.total_network_mining_power = 0;
self.emission_per_block = initial_emission; self.last_emission_update_block = clock.slot;
self.rig_supplies = [u64::MAX; 15]; self.rig_current = [0; 15];
self.admin = admin;
self.refinery_rewards_factor = Numeric::ZERO;
self.last_rewards_factor_block = clock.slot;
self.init_timestamp = clock.unix_timestamp;
self.last_emission_update_timestamp = clock.unix_timestamp;
self.reserved_a = 0;
self.reserved_b = 0;
self.buffer_a = 0;
self.buffer_b = 0;
self.buffer_c = 0;
self.buffer_d = 0;
}
pub fn update_emission_rate(&mut self, clock: &Clock, _blocks_per_day: u64) {
const SECONDS_PER_DAY: i64 = 86400;
let now = clock.unix_timestamp;
let days_elapsed = (now - self.init_timestamp).max(0) / SECONDS_PER_DAY;
if days_elapsed <= 7 {
let start_emission = 2_000_000_000u64; let peak_emission = 5_000_000_000u64;
if days_elapsed == 0 {
self.emission_per_block = start_emission;
} else if days_elapsed >= 7 {
self.emission_per_block = peak_emission;
} else {
let days_progress = (days_elapsed - 1) as u128;
let emission_range = (peak_emission - start_emission) as u128;
let interpolated = start_emission as u128
+ (emission_range * days_progress) / 6;
self.emission_per_block = interpolated as u64;
}
self.last_emission_update_block = clock.slot;
self.last_emission_update_timestamp = now;
return;
}
if days_elapsed <= 14 {
self.emission_per_block = 5_000_000_000u64; self.last_emission_update_block = clock.slot;
self.last_emission_update_timestamp = now;
return;
}
let seconds_since_update = (now - self.last_emission_update_timestamp).max(0);
if seconds_since_update >= SECONDS_PER_DAY {
let min_emission = 1_000_000_000u64; let new_emission = (self.emission_per_block as u128 * 98) / 100;
self.emission_per_block = new_emission.max(min_emission as u128) as u64;
self.last_emission_update_block = clock.slot;
self.last_emission_update_timestamp = now;
}
}
pub fn can_mint_rig(&self, rig_type: u64) -> bool {
let idx = rig_type as usize;
if idx >= 15 {
return false;
}
let max_supply = self.rig_supplies[idx];
if max_supply == u64::MAX {
true } else {
self.rig_current[idx] < max_supply
}
}
pub fn increment_rig_supply(&mut self, rig_type: u64) {
let idx = rig_type as usize;
if idx < 15 {
self.rig_current[idx] = self.rig_current[idx].saturating_add(1);
}
}
pub fn update_mining_power(&mut self, mining_power_change: i64) {
if mining_power_change > 0 {
self.total_network_mining_power = self.total_network_mining_power
.saturating_add(mining_power_change as u64);
} else {
self.total_network_mining_power = self.total_network_mining_power
.saturating_sub((-mining_power_change) as u64);
}
}
pub fn advance_rewards_factor(&mut self, clock: &Clock) {
let blocks = clock.slot.saturating_sub(self.last_rewards_factor_block);
if self.total_network_mining_power > 0 && blocks > 0 {
let total_emission = self.emission_per_block.saturating_mul(blocks);
self.refinery_rewards_factor +=
Numeric::from_fraction(total_emission, self.total_network_mining_power);
}
self.last_rewards_factor_block = clock.slot;
}
}
account!(OilAccount, Refinery);