ore_api/state/
stake.rs

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