use serde::{Deserialize, Serialize};
use steel::*;
use crate::state::{stake_pda, Treasury};
use super::OreAccount;
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable, Serialize, Deserialize)]
pub struct Stake {
pub authority: Pubkey,
pub balance: u64,
pub buffer_a: u64,
pub buffer_b: u64,
pub buffer_c: u64,
pub buffer_d: u64,
pub compound_fee_reserve: u64,
pub last_claim_at: i64,
pub last_deposit_at: i64,
pub last_withdraw_at: i64,
pub rewards_factor: Numeric,
pub rewards: u64,
pub lifetime_rewards: u64,
pub buffer_f: u64,
}
impl Stake {
pub fn pda(&self) -> (Pubkey, u8) {
stake_pda(self.authority)
}
pub fn claim(&mut self, amount: u64, clock: &Clock, treasury: &Treasury) -> u64 {
self.update_rewards(treasury);
let amount = self.rewards.min(amount);
self.rewards -= amount;
self.last_claim_at = clock.unix_timestamp;
amount
}
pub fn deposit(
&mut self,
amount: u64,
clock: &Clock,
treasury: &mut Treasury,
sender: &TokenAccount,
) -> u64 {
self.update_rewards(treasury);
let amount = sender.amount().min(amount);
self.balance += amount;
self.last_deposit_at = clock.unix_timestamp;
treasury.total_staked += amount;
amount
}
pub fn withdraw(&mut self, amount: u64, clock: &Clock, treasury: &mut Treasury) -> u64 {
self.update_rewards(treasury);
let amount = self.balance.min(amount);
self.balance -= amount;
self.last_withdraw_at = clock.unix_timestamp;
treasury.total_staked -= amount;
amount
}
pub fn update_rewards(&mut self, treasury: &Treasury) {
if treasury.stake_rewards_factor > self.rewards_factor {
let accumulated_rewards = treasury.stake_rewards_factor - self.rewards_factor;
if accumulated_rewards < Numeric::ZERO {
panic!("Accumulated rewards is negative");
}
let personal_rewards = accumulated_rewards * Numeric::from_u64(self.balance);
self.rewards += personal_rewards.to_u64();
self.lifetime_rewards += personal_rewards.to_u64();
}
self.rewards_factor = treasury.stake_rewards_factor;
}
}
account!(OreAccount, Stake);