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    /// The timestamp of last claim.
18    pub last_claim_at: i64,
19
20    /// The timestamp the last time this staker deposited.
21    pub last_deposit_at: i64,
22
23    /// The timestamp the last time this staker withdrew.
24    pub last_withdraw_at: i64,
25
26    /// The rewards factor last time rewards were updated on this stake account.
27    pub rewards_factor: Numeric,
28
29    /// The amount of ORE this staker can claim.
30    pub rewards: u64,
31
32    /// The total amount of ORE this staker has earned over its lifetime.
33    pub lifetime_rewards: u64,
34
35    /// Flag indicating whether this staker is associated with a Solana Seeker.
36    #[deprecated(since = "3.7.5", note = "This field is no longer used")]
37    pub is_seeker: u64,
38}
39
40impl Stake {
41    pub fn pda(&self) -> (Pubkey, u8) {
42        stake_pda(self.authority)
43    }
44
45    pub fn claim(&mut self, amount: u64, clock: &Clock, treasury: &Treasury) -> u64 {
46        self.update_rewards(treasury);
47        let amount = self.rewards.min(amount);
48        self.rewards -= amount;
49        self.last_claim_at = clock.unix_timestamp;
50        amount
51    }
52
53    pub fn deposit(
54        &mut self,
55        amount: u64,
56        clock: &Clock,
57        treasury: &mut Treasury,
58        sender: &TokenAccount,
59    ) -> u64 {
60        self.update_rewards(treasury);
61        let amount = sender.amount().min(amount);
62        self.balance += amount;
63        self.last_deposit_at = clock.unix_timestamp;
64        treasury.total_staked += amount;
65        amount
66    }
67
68    pub fn withdraw(&mut self, amount: u64, clock: &Clock, treasury: &mut Treasury) -> u64 {
69        self.update_rewards(treasury);
70        let amount = self.balance.min(amount);
71        self.balance -= amount;
72        self.last_withdraw_at = clock.unix_timestamp;
73        treasury.total_staked -= amount;
74        amount
75    }
76
77    pub fn update_rewards(&mut self, treasury: &Treasury) {
78        // Accumulate rewards, weighted by stake balance.
79        if treasury.stake_rewards_factor > self.rewards_factor {
80            let accumulated_rewards = treasury.stake_rewards_factor - self.rewards_factor;
81            if accumulated_rewards < Numeric::ZERO {
82                panic!("Accumulated rewards is negative");
83            }
84            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.balance);
85            self.rewards += personal_rewards.to_u64();
86            self.lifetime_rewards += personal_rewards.to_u64();
87        }
88
89        // Update this stake account's last seen rewards factor.
90        self.rewards_factor = treasury.stake_rewards_factor;
91    }
92}
93
94account!(OreAccount, Stake);