mercurial_vault/
state.rs

1use crate::context::VaultBumps;
2use crate::strategy::base::StrategyType;
3use anchor_lang::prelude::*;
4use std::convert::TryFrom;
5use std::fmt::Debug;
6
7pub const MAX_STRATEGY: usize = 30;
8pub const MAX_BUMPS: usize = 10;
9pub const LOCKED_PROFIT_DEGRADATION_DENOMINATOR: u128 = 1_000_000_000_000;
10
11#[account]
12#[derive(Default, Debug)]
13pub struct Vault {
14    pub enabled: u8,
15    pub bumps: VaultBumps,
16
17    pub total_amount: u64,
18
19    pub token_vault: Pubkey,
20    pub fee_vault: Pubkey,
21    pub token_mint: Pubkey,
22
23    pub lp_mint: Pubkey,
24    pub strategies: [Pubkey; MAX_STRATEGY],
25
26    pub base: Pubkey,
27    pub admin: Pubkey,
28    pub operator: Pubkey, // person to send crank
29    pub locked_profit_tracker: LockedProfitTracker,
30}
31
32#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug)]
33pub struct LockedProfitTracker {
34    pub last_updated_locked_profit: u64,
35    pub last_report: u64,
36    pub locked_profit_degradation: u64,
37}
38
39impl Default for LockedProfitTracker {
40    fn default() -> Self {
41        LockedProfitTracker {
42            last_updated_locked_profit: 0,
43            last_report: 0,
44            locked_profit_degradation: u64::try_from(LOCKED_PROFIT_DEGRADATION_DENOMINATOR)
45                .unwrap()
46                / (6 * 3600), // locked profit is fully dripped in 6 hour
47        }
48    }
49}
50impl LockedProfitTracker {
51    // based from yearn vault
52    // https://github.com/yearn/yearn-vaults/blob/main/contracts/Vault.vy#L825
53    pub fn calculate_locked_profit(&self, current_time: u64) -> Option<u64> {
54        let duration = u128::from(current_time.checked_sub(self.last_report)?);
55        let locked_profit_degradation = u128::from(self.locked_profit_degradation);
56        let locked_fund_ratio = duration.checked_mul(locked_profit_degradation)?;
57
58        if locked_fund_ratio > LOCKED_PROFIT_DEGRADATION_DENOMINATOR {
59            return Some(0);
60        }
61        let locked_profit = u128::from(self.last_updated_locked_profit);
62
63        let locked_profit = (locked_profit
64            .checked_mul(LOCKED_PROFIT_DEGRADATION_DENOMINATOR - locked_fund_ratio)?)
65        .checked_div(LOCKED_PROFIT_DEGRADATION_DENOMINATOR)?;
66        let locked_profit = u64::try_from(locked_profit).ok()?;
67        Some(locked_profit)
68    }
69}
70
71impl Vault {
72    pub fn get_unlocked_amount(&self, current_time: u64) -> Option<u64> {
73        self.total_amount.checked_sub(
74            self.locked_profit_tracker
75                .calculate_locked_profit(current_time)?,
76        )
77    }
78
79    pub fn get_amount_by_share(
80        &self,
81        current_time: u64,
82        share: u64,
83        total_supply: u64,
84    ) -> Option<u64> {
85        let total_amount = self.get_unlocked_amount(current_time)?;
86        u64::try_from(
87            u128::from(share)
88                .checked_mul(u128::from(total_amount))?
89                .checked_div(u128::from(total_supply))?,
90        )
91        .ok()
92    }
93
94    pub fn get_unmint_amount(
95        &self,
96        current_time: u64,
97        out_token: u64,
98        total_supply: u64,
99    ) -> Option<u64> {
100        let total_amount = self.get_unlocked_amount(current_time)?;
101        u64::try_from(
102            u128::from(out_token)
103                .checked_mul(u128::from(total_supply))?
104                .checked_div(u128::from(total_amount))?,
105        )
106        .ok()
107    }
108
109    pub fn is_strategy_existed(&self, pubkey: Pubkey) -> bool {
110        for item in self.strategies.iter() {
111            if *item == pubkey {
112                return true;
113            }
114        }
115        false
116    }
117}
118
119impl Default for StrategyType {
120    fn default() -> Self {
121        StrategyType::PortFinanceWithoutLM
122    }
123}
124
125#[account]
126#[derive(Default, Debug)]
127pub struct Strategy {
128    pub reserve: Pubkey,
129    pub collateral_vault: Pubkey,
130    pub strategy_type: StrategyType,
131    pub current_liquidity: u64,
132    pub bumps: [u8; MAX_BUMPS],
133    pub vault: Pubkey,
134    pub is_disable: u8,
135}