ore_boost_api/state/
stake.rs

1use ore_api::state::Proof;
2use steel::*;
3
4use super::{Boost, BoostAccount, Config};
5
6/// Stake tracks the deposits and rewards of a staker.
7#[repr(C)]
8#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
9pub struct Stake {
10    /// The authority of this stake account.
11    pub authority: Pubkey,
12
13    /// The balance of this stake account.
14    pub balance: u64,
15
16    /// The boost this stake account is associated with.
17    pub boost: Pubkey,
18
19    /// The timestamp of the last time rewards were claimed from this account.
20    pub last_claim_at: i64,
21
22    /// The timestamp of the last time stake was added to this account.
23    pub last_deposit_at: i64,
24
25    /// The timestamp of the last time stake was withdrawn from this account.
26    pub last_withdraw_at: i64,
27
28    /// The boost rewards factor last time rewards were updated on this stake account.
29    pub last_rewards_factor: Numeric,
30
31    /// The amount of rewards claimable by this staker.
32    pub rewards: u64,
33
34    /// A buffer for future config variables.
35    pub _buffer: [u8; 1024],
36}
37
38impl Stake {
39    /// Claim rewards.
40    pub fn claim(
41        &mut self,
42        amount: u64,
43        boost: &mut Boost,
44        clock: &Clock,
45        config: &mut Config,
46        proof: &Proof,
47    ) -> u64 {
48        self.collect_rewards(boost, config, &proof);
49        let amount = amount.min(self.rewards);
50        self.last_claim_at = clock.unix_timestamp;
51        self.rewards -= amount;
52        amount
53    }
54
55    /// Deposit into the boost.
56    pub fn deposit(
57        &mut self,
58        amount: u64,
59        boost: &mut Boost,
60        clock: &Clock,
61        config: &mut Config,
62        proof: &Proof,
63        sender: &TokenAccount,
64    ) -> u64 {
65        self.collect_rewards(boost, config, &proof);
66        let amount = amount.min(sender.amount());
67        self.balance += amount;
68        self.last_deposit_at = clock.unix_timestamp;
69        boost.total_deposits += amount;
70        amount
71    }
72
73    /// Withdraw from the boost.
74    pub fn withdraw(
75        &mut self,
76        amount: u64,
77        boost: &mut Boost,
78        clock: &Clock,
79        config: &mut Config,
80        proof: &Proof,
81    ) -> u64 {
82        self.collect_rewards(boost, config, &proof);
83        let amount = amount.min(self.balance);
84        self.balance -= amount;
85        self.last_withdraw_at = clock.unix_timestamp;
86        boost.total_deposits -= amount;
87        amount
88    }
89
90    // Collect staking rewards.
91    fn collect_rewards(&mut self, boost: &mut Boost, config: &mut Config, proof: &Proof) {
92        // Update the boost rewards factor.
93        boost.collect_rewards(config, proof);
94
95        // Accumulate stake-weighted boost rewards into the stake account.
96        if boost.rewards_factor > self.last_rewards_factor {
97            let accumulated_rewards = boost.rewards_factor - self.last_rewards_factor;
98            if accumulated_rewards < Numeric::ZERO {
99                panic!("Accumulated rewards is negative");
100            }
101            let personal_rewards = accumulated_rewards * Numeric::from_u64(self.balance);
102            self.rewards += personal_rewards.to_u64();
103        }
104
105        // Update this stake account's last seen rewards factor.
106        self.last_rewards_factor = boost.rewards_factor;
107    }
108}
109
110account!(BoostAccount, Stake);