oil_api/state/
refinery.rs1use serde::{Deserialize, Serialize};
2use steel::*;
3
4use crate::state::refinery_pda;
5
6use super::OilAccount;
7
8#[repr(C)]
10#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
11pub struct RigConfig {
12 pub mining_power: u64,
14
15 pub fuel_requirement: u64,
17
18 pub fuel_consumption_rate: u64,
20}
21
22#[repr(C)]
24#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
25pub struct Refinery {
26 pub total_network_mining_power: u64,
28
29 pub emission_per_block: u64,
31
32 pub last_emission_update_block: u64,
34
35 pub rig_supplies: [u64; 15],
37
38 pub rig_current: [u64; 15],
40
41 pub rig_configs: [RigConfig; 15],
43
44 pub admin: Pubkey,
46
47 pub refinery_rewards_factor: Numeric,
49
50 pub last_rewards_factor_block: u64,
52
53 pub init_timestamp: i64,
55 pub last_emission_update_timestamp: i64,
57
58 pub reserved_a: u64,
60 pub reserved_b: u64,
62 pub buffer_a: u64,
64 pub buffer_b: u64,
66 pub buffer_c: u64,
68 pub buffer_d: u64,
70}
71
72impl Refinery {
73 pub fn pda() -> (Pubkey, u8) {
74 refinery_pda()
75 }
76
77 pub fn initialize(&mut self, admin: Pubkey, clock: &Clock, initial_emission: u64) {
78 self.total_network_mining_power = 0;
79 self.emission_per_block = initial_emission; self.last_emission_update_block = clock.slot;
81 self.rig_supplies = [u64::MAX; 15]; self.rig_current = [0; 15];
83 self.admin = admin;
85 self.refinery_rewards_factor = Numeric::ZERO;
86 self.last_rewards_factor_block = clock.slot;
87 self.init_timestamp = clock.unix_timestamp;
88 self.last_emission_update_timestamp = clock.unix_timestamp;
89 self.reserved_a = 0;
90 self.reserved_b = 0;
91 self.buffer_a = 0;
92 self.buffer_b = 0;
93 self.buffer_c = 0;
94 self.buffer_d = 0;
95 }
96
97 pub fn update_emission_rate(&mut self, clock: &Clock, _blocks_per_day: u64) {
100 const SECONDS_PER_DAY: i64 = 86400;
101 let now = clock.unix_timestamp;
102 let days_elapsed = (now - self.init_timestamp).max(0) / SECONDS_PER_DAY;
103
104 if days_elapsed <= 7 {
106 let start_emission = 7_100_000_000u64; let peak_emission = 17_900_000_000u64; if days_elapsed == 0 {
110 self.emission_per_block = start_emission;
111 } else if days_elapsed >= 7 {
112 self.emission_per_block = peak_emission;
113 } else {
114 let days_progress = (days_elapsed - 1) as u128;
115 let emission_range = (peak_emission - start_emission) as u128;
116 let interpolated = start_emission as u128
117 + (emission_range * days_progress) / 6;
118 self.emission_per_block = interpolated as u64;
119 }
120 self.last_emission_update_block = clock.slot;
121 self.last_emission_update_timestamp = now;
122 return;
123 }
124
125 if days_elapsed <= 14 {
127 self.emission_per_block = 17_900_000_000u64; self.last_emission_update_block = clock.slot;
129 self.last_emission_update_timestamp = now;
130 return;
131 }
132
133 let seconds_since_update = (now - self.last_emission_update_timestamp).max(0);
135 if seconds_since_update >= SECONDS_PER_DAY {
136 let min_emission = 3_600_000_000u64; let new_emission = (self.emission_per_block as u128 * 98) / 100;
138 self.emission_per_block = new_emission.max(min_emission as u128) as u64;
139 self.last_emission_update_block = clock.slot;
140 self.last_emission_update_timestamp = now;
141 }
142 }
143
144 pub fn can_mint_rig(&self, rig_type: u64) -> bool {
146 let idx = rig_type as usize;
147 if idx >= 15 {
148 return false;
149 }
150
151 let max_supply = self.rig_supplies[idx];
152 if max_supply == u64::MAX {
153 true } else {
155 self.rig_current[idx] < max_supply
156 }
157 }
158
159 pub fn increment_rig_supply(&mut self, rig_type: u64) {
161 let idx = rig_type as usize;
162 if idx < 15 {
163 self.rig_current[idx] = self.rig_current[idx].saturating_add(1);
164 }
165 }
166
167 pub fn update_mining_power(&mut self, mining_power_change: i64) {
169 if mining_power_change > 0 {
170 self.total_network_mining_power = self.total_network_mining_power
171 .saturating_add(mining_power_change as u64);
172 } else {
173 self.total_network_mining_power = self.total_network_mining_power
174 .saturating_sub((-mining_power_change) as u64);
175 }
176 }
177
178 pub fn advance_rewards_factor(&mut self, clock: &Clock) {
181 let blocks = clock.slot.saturating_sub(self.last_rewards_factor_block);
182 if self.total_network_mining_power > 0 && blocks > 0 {
183 let total_emission = self.emission_per_block.saturating_mul(blocks);
184 self.refinery_rewards_factor +=
185 Numeric::from_fraction(total_emission, self.total_network_mining_power);
186 }
187 self.last_rewards_factor_block = clock.slot;
188 }
189}
190
191account!(OilAccount, Refinery);