Skip to main content

ore_api/state/
miner.rs

1use serde::{Deserialize, Serialize};
2use steel::*;
3
4use crate::state::{miner_pda, OreAccount, Treasury, DENOMINATOR_BPS};
5
6#[repr(C)]
7#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
8pub struct Miner {
9    /// The authority of this miner account.
10    pub authority: Pubkey,
11
12    /// Whether or not to auto-return SOL winnings to the miner's wallet.
13    pub auto_return: u64,
14
15    /// The checkpoint ID.
16    pub checkpoint_id: u64,
17
18    /// SOL witheld in reserve to pay for checkpointing.
19    pub checkpoint_fee: u64,
20
21    /// The amount of SOL deployed on each square.
22    /// TODO: Rename to sol.
23    pub deployed: [u64; 25],
24
25    /// The amount of SOL deployed on each square, weighted by the time remaining when deployed.
26    pub mass: [u64; 25],
27
28    /// The cumulative mass on each square prior to this miner's deployment on that square.
29    /// TODO: Rename to mass_cumulative.
30    pub cumulative: [u64; 25],
31
32    /// The round ID.
33    pub round_id: u64,
34
35    /// The rewards factor last time rewards were updated on this miner account.
36    pub rewards_factor: Numeric,
37
38    /// The amount of SOL this miner has had returned and may claim.
39    /// TODO: Rename to sol_returned.
40    pub rewards_sol: u64,
41
42    /// The amount of ORE this miner has earned from refining fees and may claim.
43    /// TODO: Rename to ore_refined.
44    pub refined_ore: u64,
45
46    /// The amount of ORE this miner has mined and may claim.
47    /// TODO: Rename to ore_unrefined.
48    pub rewards_ore: u64,
49
50    /// The last time this miner claimed ORE rewards.
51    pub last_claim_ore_at: i64,
52
53    /// The last time this miner claimed SOL rewards.
54    pub last_claim_sol_at: i64,
55
56    /// The total amount of ORE this miner has mined across all blocks.
57    /// TODO: Rename to lifetime_rewards_ore.
58    pub lifetime_rewards_ore: u64,
59
60    /// The total amount of SOL this miner has deployed across all rounds.
61    pub lifetime_deployed: u64,
62
63    /// The total amount of SOL this miner has mined across all blocks.
64    /// TODO: Rename to lifetime_returned_sol.
65    pub lifetime_rewards_sol: u64,
66}
67
68impl Miner {
69    pub fn pda(&self) -> (Pubkey, u8) {
70        miner_pda(self.authority)
71    }
72
73    pub fn claim_ore(&mut self, clock: &Clock, treasury: &mut Treasury, bps: u64) -> (u64, u64) {
74        self.update_rewards(treasury);
75
76        // Compute % claimable
77        // bps = basis points, so 10000 == 100%
78        let bps = bps.min(DENOMINATOR_BPS);
79        let claim_refined = (self.refined_ore * bps) / DENOMINATOR_BPS;
80        let claim_rewards = (self.rewards_ore * bps) / DENOMINATOR_BPS;
81
82        // Withdraw amounts
83        self.refined_ore -= claim_refined;
84        self.rewards_ore -= claim_rewards;
85        treasury.total_refined -= claim_refined;
86        treasury.total_unclaimed -= claim_rewards;
87        self.last_claim_ore_at = clock.unix_timestamp;
88
89        // Apply 10% fee on unrefined portion (rewards_ore)
90        let mut fee = 0;
91        let mut amount = claim_refined + claim_rewards;
92        if claim_rewards > 0 && treasury.total_unclaimed > 0 {
93            fee = 1.max(claim_rewards / 10);
94            amount -= fee;
95            // Distribute the tax
96            treasury.miner_rewards_factor += Numeric::from_fraction(fee, treasury.total_unclaimed);
97            treasury.total_refined += fee;
98            self.lifetime_rewards_ore -= fee;
99        }
100
101        (amount, fee)
102    }
103
104    pub fn claim_sol(&mut self, clock: &Clock) -> u64 {
105        let amount = self.rewards_sol;
106        self.rewards_sol = 0;
107        self.last_claim_sol_at = clock.unix_timestamp;
108        amount
109    }
110
111    pub fn update_rewards(&mut self, treasury: &Treasury) {
112        // Accumulate rewards, weighted by stake balance.
113        if treasury.miner_rewards_factor > self.rewards_factor {
114            let accumulated_rewards = treasury.miner_rewards_factor - self.rewards_factor;
115            if accumulated_rewards < Numeric::ZERO {
116                panic!("Accumulated rewards is negative");
117            }
118            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.rewards_ore);
119            self.refined_ore += personal_rewards.to_u64();
120            self.lifetime_rewards_ore += personal_rewards.to_u64();
121        }
122
123        // Update this miner account's last seen rewards factor.
124        self.rewards_factor = treasury.miner_rewards_factor;
125    }
126}
127
128account!(OreAccount, Miner);