ore_api/state/
stake.rs

1use serde::{Deserialize, Serialize};
2use steel::*;
3
4use crate::state::{stake_pda, Treasury};
5
6use super::OreAccount;
7
8#[repr(C)]
9#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
10pub struct Stake {
11    /// The authority of this miner account.
12    pub authority: Pubkey,
13
14    /// The balance of this stake account.
15    pub balance: u64,
16
17    /// Buffer a (placeholder)
18    pub buffer_a: u64,
19
20    /// Buffer b (placeholder)
21    pub buffer_b: u64,
22
23    /// Buffer c (placeholder)
24    pub buffer_c: u64,
25
26    /// Buffer d (placeholder)
27    pub buffer_d: u64,
28
29    /// Buffer e (placeholder)
30    pub buffer_e: u64,
31
32    /// The timestamp of last claim.
33    pub last_claim_at: i64,
34
35    /// The timestamp the last time this staker deposited.
36    pub last_deposit_at: i64,
37
38    /// The timestamp the last time this staker withdrew.
39    pub last_withdraw_at: i64,
40
41    /// The rewards factor last time rewards were updated on this stake account.
42    pub rewards_factor: Numeric,
43
44    /// The amount of ORE this staker can claim.
45    pub rewards: u64,
46
47    /// The total amount of ORE this staker has earned over its lifetime.
48    pub lifetime_rewards: u64,
49
50    /// Buffer f (placeholder)
51    pub buffer_f: u64,
52}
53
54impl Stake {
55    pub fn pda(&self) -> (Pubkey, u8) {
56        stake_pda(self.authority)
57    }
58
59    pub fn claim(&mut self, amount: u64, clock: &Clock, treasury: &Treasury) -> u64 {
60        self.update_rewards(treasury);
61        let amount = self.rewards.min(amount);
62        self.rewards -= amount;
63        self.last_claim_at = clock.unix_timestamp;
64        amount
65    }
66
67    pub fn deposit(
68        &mut self,
69        amount: u64,
70        clock: &Clock,
71        treasury: &mut Treasury,
72        sender: &TokenAccount,
73    ) -> u64 {
74        self.update_rewards(treasury);
75        let amount = sender.amount().min(amount);
76        self.balance += amount;
77        self.last_deposit_at = clock.unix_timestamp;
78        treasury.total_staked += amount;
79        amount
80    }
81
82    pub fn withdraw(&mut self, amount: u64, clock: &Clock, treasury: &mut Treasury) -> u64 {
83        self.update_rewards(treasury);
84        let amount = self.balance.min(amount);
85        self.balance -= amount;
86        self.last_withdraw_at = clock.unix_timestamp;
87        treasury.total_staked -= amount;
88        amount
89    }
90
91    pub fn update_rewards(&mut self, treasury: &Treasury) {
92        // Accumulate rewards, weighted by stake balance.
93        if treasury.stake_rewards_factor > self.rewards_factor {
94            let accumulated_rewards = treasury.stake_rewards_factor - self.rewards_factor;
95            if accumulated_rewards < Numeric::ZERO {
96                panic!("Accumulated rewards is negative");
97            }
98            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.balance);
99            self.rewards += personal_rewards.to_u64();
100            self.lifetime_rewards += personal_rewards.to_u64();
101        }
102
103        // Update this stake account's last seen rewards factor.
104        self.rewards_factor = treasury.stake_rewards_factor;
105    }
106}
107
108account!(OreAccount, Stake);