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