Skip to main content

ore_api/state/
miner.rs

1use serde::{Deserialize, Serialize};
2use steel::*;
3
4use crate::state::{miner_pda, OreAccountV4, Treasury, TreasuryV1, TreasuryV4};
5
6use super::OreAccountV1;
7
8#[repr(C)]
9#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
10pub struct MinerV1 {
11    /// The authority of this miner account.
12    pub authority: Pubkey,
13
14    /// The miner's prospects in the current round.
15    pub deployed: [u64; 25],
16
17    /// The cumulative amount of SOL deployed on each square prior to this miner's move.
18    pub cumulative: [u64; 25],
19
20    /// SOL witheld in reserve to pay for checkpointing.
21    pub checkpoint_fee: u64,
22
23    /// The last round that this miner checkpointed.
24    pub checkpoint_id: u64,
25
26    /// The last time this miner claimed ORE rewards.
27    pub last_claim_ore_at: i64,
28
29    /// The last time this miner claimed SOL rewards.
30    pub last_claim_sol_at: i64,
31
32    /// The rewards factor last time rewards were updated on this miner account.
33    pub rewards_factor: Numeric,
34
35    /// The amount of SOL this miner can claim.
36    pub rewards_sol: u64,
37
38    /// The amount of ORE this miner can claim.
39    pub rewards_ore: u64,
40
41    /// The amount of ORE this miner has earned from claim fees.
42    pub refined_ore: u64,
43
44    /// The ID of the round this miner last played in.
45    pub round_id: u64,
46
47    /// The total amount of SOL this miner has mined across all blocks.
48    pub lifetime_rewards_sol: u64,
49
50    /// The total amount of ORE this miner has mined across all blocks.
51    pub lifetime_rewards_ore: u64,
52
53    /// The total amount of SOL this miner has deployed across all rounds.
54    pub lifetime_deployed: u64,
55}
56
57#[repr(C)]
58#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
59pub struct MinerV4 {
60    /// The authority of this miner account.
61    pub authority: Pubkey,
62
63    /// Whether or not to auto-return SOL winnings to the miner's wallet.
64    pub auto_return: u64,
65
66    /// The checkpoint ID.
67    pub checkpoint_id: u64,
68
69    /// SOL witheld in reserve to pay for checkpointing.
70    pub checkpoint_fee: u64,
71
72    /// The amount of SOL deployed on each square.
73    pub sol: [u64; 25],
74
75    /// The amount of SOL deployed on each square, weighted by the time remaining when deployed.
76    pub mass: [u64; 25],
77
78    /// The cumulative mass on each square prior to this miner's deployment on that square.
79    pub mass_cumulative: [u64; 25],
80
81    /// The round ID.
82    pub round_id: u64,
83
84    /// The rewards factor last time rewards were updated on this miner account.
85    pub rewards_factor: Numeric,
86
87    /// The amount of SOL this miner has had returned and may claim.
88    pub sol_returned: u64,
89
90    /// The amount of ORE this miner has earned from refining fees and may claim.
91    pub ore_refined: u64,
92
93    /// The amount of ORE this miner has mined and may claim.
94    pub ore_unrefined: u64,
95
96    /// The last time this miner claimed ORE rewards.
97    pub last_claim_ore_at: i64,
98
99    /// The last time this miner claimed SOL rewards.
100    pub last_claim_sol_at: i64,
101
102    /// The total amount of ORE this miner has mined across all blocks.
103    pub lifetime_rewards: u64,
104
105    /// The total amount of SOL this miner has deployed across all rounds.
106    pub lifetime_deployed: u64,
107
108    /// The total amount of SOL this miner has mined across all blocks.
109    pub lifetime_returned_sol: u64,
110}
111
112impl MinerV1 {
113    pub fn pda(&self) -> (Pubkey, u8) {
114        miner_pda(self.authority)
115    }
116
117    pub fn claim_ore_v1(&mut self, clock: &Clock, treasury: &mut TreasuryV1) -> u64 {
118        self.update_rewards_v1(treasury);
119        let refined_ore = self.refined_ore;
120        let rewards_ore = self.rewards_ore;
121        let mut amount = refined_ore + rewards_ore;
122        self.refined_ore = 0;
123        self.rewards_ore = 0;
124        treasury.total_unclaimed -= rewards_ore;
125        treasury.total_refined -= refined_ore;
126        self.last_claim_ore_at = clock.unix_timestamp;
127
128        // Charge a 10% fee and share with miners who haven't claimed yet.
129        if treasury.total_unclaimed > 0 {
130            let fee = rewards_ore / 10;
131            amount -= fee;
132            treasury.miner_rewards_factor += Numeric::from_fraction(fee, treasury.total_unclaimed);
133            treasury.total_refined += fee;
134            self.lifetime_rewards_ore -= fee;
135        }
136
137        amount
138    }
139
140    pub fn claim_ore_v4(&mut self, clock: &Clock, treasury: &mut TreasuryV4) -> u64 {
141        self.update_rewards_v4(treasury);
142        let refined_ore = self.refined_ore;
143        let rewards_ore = self.rewards_ore;
144        let mut amount = refined_ore + rewards_ore;
145        self.refined_ore = 0;
146        self.rewards_ore = 0;
147        treasury.total_unrefined -= rewards_ore;
148        treasury.total_refined -= refined_ore;
149        self.last_claim_ore_at = clock.unix_timestamp;
150
151        // Charge a 10% fee and share with miners who haven't claimed yet.
152        if treasury.total_unrefined > 0 {
153            let fee = rewards_ore / 10;
154            amount -= fee;
155            treasury.rewards_factor += Numeric::from_fraction(fee, treasury.total_unrefined);
156            treasury.total_refined += fee;
157            self.lifetime_rewards_ore -= fee;
158        }
159
160        amount
161    }
162
163    pub fn claim_sol(&mut self, clock: &Clock) -> u64 {
164        let amount = self.rewards_sol;
165        self.rewards_sol = 0;
166        self.last_claim_sol_at = clock.unix_timestamp;
167        amount
168    }
169
170    pub fn update_rewards_v1(&mut self, treasury: &TreasuryV1) {
171        // Accumulate rewards, weighted by stake balance.
172        if treasury.miner_rewards_factor > self.rewards_factor {
173            let accumulated_rewards = treasury.miner_rewards_factor - self.rewards_factor;
174            if accumulated_rewards < Numeric::ZERO {
175                panic!("Accumulated rewards is negative");
176            }
177            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.rewards_ore);
178            self.refined_ore += personal_rewards.to_u64();
179            self.lifetime_rewards_ore += personal_rewards.to_u64();
180        }
181
182        // Update this miner account's last seen rewards factor.
183        self.rewards_factor = treasury.miner_rewards_factor;
184    }
185
186    pub fn update_rewards_v4(&mut self, treasury: &TreasuryV4) {
187        // Accumulate rewards, weighted by stake balance.
188        if treasury.rewards_factor > self.rewards_factor {
189            let accumulated_rewards = treasury.rewards_factor - self.rewards_factor;
190            if accumulated_rewards < Numeric::ZERO {
191                panic!("Accumulated rewards is negative");
192            }
193            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.rewards_ore);
194            self.refined_ore += personal_rewards.to_u64();
195            self.lifetime_rewards_ore += personal_rewards.to_u64();
196        }
197
198        // Update this miner account's last seen rewards factor.
199        self.rewards_factor = treasury.rewards_factor;
200    }
201}
202
203impl MinerV4 {
204    pub fn pda(&self) -> (Pubkey, u8) {
205        miner_pda(self.authority)
206    }
207
208    pub fn claim_ore_v1(&mut self, clock: &Clock, treasury: &mut TreasuryV1) -> u64 {
209        self.update_rewards_v1(treasury);
210        let refined_ore = self.ore_refined;
211        let rewards_ore = self.ore_unrefined;
212        let mut amount = refined_ore + rewards_ore;
213        self.ore_refined = 0;
214        self.ore_unrefined = 0;
215        treasury.total_unclaimed -= rewards_ore;
216        treasury.total_refined -= refined_ore;
217        self.last_claim_ore_at = clock.unix_timestamp;
218
219        // Charge a 10% fee and share with miners who haven't claimed yet.
220        if treasury.total_unclaimed > 0 {
221            let fee = rewards_ore / 10;
222            amount -= fee;
223            treasury.miner_rewards_factor += Numeric::from_fraction(fee, treasury.total_unclaimed);
224            treasury.total_refined += fee;
225            self.lifetime_rewards -= fee;
226        }
227
228        amount
229    }
230
231    pub fn claim_ore_v4(&mut self, clock: &Clock, treasury: &mut TreasuryV4) -> u64 {
232        self.update_rewards_v4(treasury);
233        let refined_ore = self.ore_refined;
234        let rewards_ore = self.ore_unrefined;
235        let mut amount = refined_ore + rewards_ore;
236        self.ore_refined = 0;
237        self.ore_unrefined = 0;
238        treasury.total_unrefined -= rewards_ore;
239        treasury.total_refined -= refined_ore;
240        self.last_claim_ore_at = clock.unix_timestamp;
241
242        // Charge a 10% fee and share with miners who haven't claimed yet.
243        if treasury.total_unrefined > 0 {
244            let fee = rewards_ore / 10;
245            amount -= fee;
246            treasury.rewards_factor += Numeric::from_fraction(fee, treasury.total_unrefined);
247            treasury.total_refined += fee;
248            self.lifetime_rewards -= fee;
249        }
250
251        amount
252    }
253
254    pub fn claim_sol(&mut self, clock: &Clock) -> u64 {
255        let amount = self.sol_returned;
256        self.sol_returned = 0;
257        self.last_claim_sol_at = clock.unix_timestamp;
258        amount
259    }
260
261    pub fn update_rewards_v4(&mut self, treasury: &TreasuryV4) {
262        // Accumulate rewards, weighted by stake balance.
263        if treasury.rewards_factor > self.rewards_factor {
264            let accumulated_rewards = treasury.rewards_factor - self.rewards_factor;
265            if accumulated_rewards < Numeric::ZERO {
266                panic!("Accumulated rewards is negative");
267            }
268            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.ore_unrefined);
269            self.ore_refined += personal_rewards.to_u64();
270            self.lifetime_rewards += personal_rewards.to_u64();
271        }
272
273        // Update this miner account's last seen rewards factor.
274        self.rewards_factor = treasury.rewards_factor;
275    }
276
277    pub fn update_rewards_v1(&mut self, treasury: &TreasuryV1) {
278        // Accumulate rewards, weighted by stake balance.
279        if treasury.miner_rewards_factor > self.rewards_factor {
280            let accumulated_rewards = treasury.miner_rewards_factor - self.rewards_factor;
281            if accumulated_rewards < Numeric::ZERO {
282                panic!("Accumulated rewards is negative");
283            }
284            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.ore_unrefined);
285            self.ore_refined += personal_rewards.to_u64();
286            self.lifetime_rewards += personal_rewards.to_u64();
287        }
288
289        // Update this miner account's last seen rewards factor.
290        self.rewards_factor = treasury.miner_rewards_factor;
291    }
292}
293
294account!(OreAccountV1, MinerV1);
295account!(OreAccountV4, MinerV4);
296
297pub enum Miner {
298    MinerV1(MinerV1),
299    MinerV4(MinerV4),
300}
301
302impl Miner {
303    pub fn authority(&self) -> Pubkey {
304        match self {
305            Miner::MinerV1(miner) => miner.authority,
306            Miner::MinerV4(miner) => miner.authority,
307        }
308    }
309
310    pub fn deployed(&self) -> [u64; 25] {
311        match self {
312            Miner::MinerV1(miner) => miner.deployed,
313            Miner::MinerV4(miner) => miner.sol,
314        }
315    }
316
317    pub fn cumulative(&self) -> [u64; 25] {
318        match self {
319            Miner::MinerV1(miner) => miner.cumulative,
320            Miner::MinerV4(miner) => miner.mass_cumulative,
321        }
322    }
323
324    pub fn checkpoint_fee(&self) -> u64 {
325        match self {
326            Miner::MinerV1(miner) => miner.checkpoint_fee,
327            Miner::MinerV4(miner) => miner.checkpoint_fee,
328        }
329    }
330
331    pub fn checkpoint_id(&self) -> u64 {
332        match self {
333            Miner::MinerV1(miner) => miner.checkpoint_id,
334            Miner::MinerV4(miner) => miner.checkpoint_id,
335        }
336    }
337
338    pub fn last_claim_ore_at(&self) -> i64 {
339        match self {
340            Miner::MinerV1(miner) => miner.last_claim_ore_at,
341            Miner::MinerV4(miner) => miner.last_claim_ore_at,
342        }
343    }
344
345    pub fn last_claim_sol_at(&self) -> i64 {
346        match self {
347            Miner::MinerV1(miner) => miner.last_claim_sol_at,
348            Miner::MinerV4(miner) => miner.last_claim_sol_at,
349        }
350    }
351    pub fn rewards_factor(&self) -> Numeric {
352        match self {
353            Miner::MinerV1(miner) => miner.rewards_factor,
354            Miner::MinerV4(miner) => miner.rewards_factor,
355        }
356    }
357
358    pub fn rewards_sol(&self) -> u64 {
359        match self {
360            Miner::MinerV1(miner) => miner.rewards_sol,
361            Miner::MinerV4(miner) => miner.sol_returned,
362        }
363    }
364
365    pub fn rewards_ore(&self) -> u64 {
366        match self {
367            Miner::MinerV1(miner) => miner.rewards_ore,
368            Miner::MinerV4(miner) => miner.ore_unrefined,
369        }
370    }
371
372    pub fn refined_ore(&self) -> u64 {
373        match self {
374            Miner::MinerV1(miner) => miner.refined_ore,
375            Miner::MinerV4(miner) => miner.ore_refined,
376        }
377    }
378
379    pub fn round_id(&self) -> u64 {
380        match self {
381            Miner::MinerV1(miner) => miner.round_id,
382            Miner::MinerV4(miner) => miner.round_id,
383        }
384    }
385
386    pub fn lifetime_rewards_sol(&self) -> u64 {
387        match self {
388            Miner::MinerV1(miner) => miner.lifetime_rewards_sol,
389            Miner::MinerV4(miner) => miner.lifetime_returned_sol,
390        }
391    }
392
393    pub fn lifetime_rewards_ore(&self) -> u64 {
394        match self {
395            Miner::MinerV1(miner) => miner.lifetime_rewards_ore,
396            Miner::MinerV4(miner) => miner.lifetime_rewards,
397        }
398    }
399
400    pub fn lifetime_deployed(&self) -> u64 {
401        match self {
402            Miner::MinerV1(miner) => miner.lifetime_deployed,
403            Miner::MinerV4(miner) => miner.lifetime_deployed,
404        }
405    }
406
407    pub fn pda(&self) -> (Pubkey, u8) {
408        match self {
409            Miner::MinerV1(miner) => miner.pda(),
410            Miner::MinerV4(miner) => miner.pda(),
411        }
412    }
413
414    pub fn claim_ore(&mut self, clock: &Clock, treasury: &mut Treasury) -> u64 {
415        match self {
416            Miner::MinerV1(miner) => match treasury {
417                Treasury::TreasuryV1(treasury) => miner.claim_ore_v1(clock, treasury),
418                Treasury::TreasuryV4(treasury) => miner.claim_ore_v4(clock, treasury),
419            },
420            Miner::MinerV4(miner) => match treasury {
421                Treasury::TreasuryV1(treasury) => miner.claim_ore_v1(clock, treasury),
422                Treasury::TreasuryV4(treasury) => miner.claim_ore_v4(clock, treasury),
423            },
424        }
425    }
426
427    pub fn claim_sol(&mut self, clock: &Clock) -> u64 {
428        match self {
429            Miner::MinerV1(miner) => miner.claim_sol(clock),
430            Miner::MinerV4(miner) => miner.claim_sol(clock),
431        }
432    }
433
434    pub fn update_rewards(&mut self, treasury: &Treasury) {
435        match self {
436            Miner::MinerV1(miner) => match treasury {
437                Treasury::TreasuryV1(treasury) => miner.update_rewards_v1(treasury),
438                Treasury::TreasuryV4(treasury) => miner.update_rewards_v4(treasury),
439            },
440            Miner::MinerV4(miner) => match treasury {
441                Treasury::TreasuryV1(treasury) => miner.update_rewards_v1(treasury),
442                Treasury::TreasuryV4(treasury) => miner.update_rewards_v4(treasury),
443            },
444        }
445    }
446}