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, 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), }
48 }
49}
50impl LockedProfitTracker {
51 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}