Skip to content

Commit

Permalink
Merge pull request #52 from Splyce-Finance/deposit_limit
Browse files Browse the repository at this point in the history
Deposit limit
  • Loading branch information
vito-kovalione authored Dec 18, 2024
2 parents 01c13ba + 9e6aebc commit e634688
Show file tree
Hide file tree
Showing 18 changed files with 268 additions and 134 deletions.
2 changes: 1 addition & 1 deletion programs/tokenized_vault/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub const UNDERLYING_SEED: &str = "underlying";
pub const ROLES_SEED: &str = "roles";
pub const CONFIG_SEED: &str = "config";
pub const STRATEGY_DATA_SEED: &str = "strategy_data";
pub const WHITELISTED_SEED: &str = "whitelisted";
pub const USER_DATA_SEED: &str = "user_data";

pub const MAX_BPS: u64 = 10_000;
pub const FEE_BPS: u64 = 10_000;
Expand Down
6 changes: 6 additions & 0 deletions programs/tokenized_vault/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,10 @@ pub enum ErrorCode {

#[msg("Account is not whitelisted")]
NotWhitelisted,

#[msg("User deposit limit exceeded")]
ExceedUserDepositLimit,

#[msg("Serialization error")]
SerializationError,
}
6 changes: 6 additions & 0 deletions programs/tokenized_vault/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,10 @@ pub struct StrategyReportedEvent {
pub protocol_fees: u64,
pub total_fees: u64,
pub timestamp: i64,
}

#[event]
pub struct WhitelistUpdatedEvent {
pub user: Pubkey,
pub whitelisted: bool,
}
36 changes: 21 additions & 15 deletions programs/tokenized_vault/src/instructions/deposit.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use access_control::state::UserRole;
use access_control::{
constants::USER_ROLE_SEED,
program::AccessControl,
Expand All @@ -9,10 +10,10 @@ use anchor_spl::{
token_interface::{Mint, TokenAccount, TokenInterface}
};

use crate::constants::{SHARES_SEED, UNDERLYING_SEED, WHITELISTED_SEED};
use crate::constants::{SHARES_SEED, UNDERLYING_SEED, USER_DATA_SEED};

use crate::events::VaultDepositEvent;
use crate::state::Vault;
use crate::state::{UserData, Vault};
use crate::utils::{accountant, token, vault};

#[derive(Accounts)]
Expand Down Expand Up @@ -46,6 +47,19 @@ pub struct Deposit<'info> {
#[account(mut)]
pub user_shares_account: InterfaceAccount<'info, TokenAccount>,

#[account(
init_if_needed,
payer = user,
space = UserData::LEN,
seeds = [
USER_DATA_SEED.as_bytes(),
vault.key().as_ref(),
user.key().as_ref()
],
bump
)]
pub user_data: Account<'info, UserData>,

/// CHECK: this account may not exist
#[account(
seeds = [
Expand All @@ -58,20 +72,10 @@ pub struct Deposit<'info> {
)]
pub kyc_verified: UncheckedAccount<'info>,

/// CHECK: this account may not exist
#[account(
seeds = [
WHITELISTED_SEED.as_bytes(),
vault.key().as_ref(),
user.key().as_ref(),
],
bump,
)]
pub whitelisted: UncheckedAccount<'info>,

#[account(mut)]
pub user: Signer<'info>,

pub system_program: Program<'info, System>,
pub shares_token_program: Program<'info, Token>,
pub token_program: Interface<'info, TokenInterface>,
pub access_control: Program<'info, AccessControl>,
Expand All @@ -83,8 +87,8 @@ pub fn handle_deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {

vault::validate_deposit(
&ctx.accounts.vault,
ctx.accounts.kyc_verified.to_account_info(),
ctx.accounts.whitelisted.to_account_info(),
&ctx.accounts.kyc_verified,
&ctx.accounts.user_data,
false,
amount_to_deposit
)?;
Expand Down Expand Up @@ -122,6 +126,8 @@ pub fn handle_deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
)?;
}

ctx.accounts.user_data.deposited += amount;

let mut vault = ctx.accounts.vault.load_mut()?;
vault.handle_deposit(amount, shares);

Expand Down
41 changes: 25 additions & 16 deletions programs/tokenized_vault/src/instructions/direct_deposit.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use access_control::{
constants::USER_ROLE_SEED,
program::AccessControl,
state::Role
state::{Role, UserRole}
};
use anchor_lang::prelude::*;
use anchor_spl::{
Expand All @@ -10,10 +10,15 @@ use anchor_spl::{
};
use strategy::program::Strategy;

use crate::constants::{SHARES_SEED, STRATEGY_DATA_SEED, UNDERLYING_SEED, WHITELISTED_SEED};
use crate::constants::{
SHARES_SEED,
STRATEGY_DATA_SEED,
UNDERLYING_SEED,
USER_DATA_SEED
};

use crate::events::{VaultDepositEvent, UpdatedCurrentDebtForStrategyEvent};
use crate::state::{Vault, StrategyData};
use crate::state::{UserData, Vault, StrategyData};
use crate::utils::{accountant, strategy as strategy_utils, token, vault};

#[derive(Accounts)]
Expand Down Expand Up @@ -62,6 +67,19 @@ pub struct DirectDeposit<'info> {
)]
pub strategy_data: Account<'info, StrategyData>,

#[account(
init_if_needed,
payer = user,
space = UserData::LEN,
seeds = [
USER_DATA_SEED.as_bytes(),
vault.key().as_ref(),
user.key().as_ref()
],
bump
)]
pub user_data: Account<'info, UserData>,

#[account(
mut,
seeds = [UNDERLYING_SEED.as_bytes(), strategy.key().as_ref()],
Expand All @@ -82,20 +100,10 @@ pub struct DirectDeposit<'info> {
)]
pub kyc_verified: UncheckedAccount<'info>,

/// CHECK: this account may not exist
#[account(
seeds = [
WHITELISTED_SEED.as_bytes(),
vault.key().as_ref(),
user.key().as_ref(),
],
bump,
)]
pub whitelisted: UncheckedAccount<'info>,

#[account(mut)]
pub user: Signer<'info>,

pub system_program: Program<'info, System>,
pub shares_token_program: Program<'info, Token>,
pub token_program: Interface<'info, TokenInterface>,
pub access_control: Program<'info, AccessControl>,
Expand All @@ -108,8 +116,8 @@ pub fn handle_direct_deposit<'info>(ctx: Context<'_, '_, '_, 'info, DirectDeposi

vault::validate_deposit(
&ctx.accounts.vault,
ctx.accounts.kyc_verified.to_account_info(),
ctx.accounts.whitelisted.to_account_info(),
&ctx.accounts.kyc_verified,
&ctx.accounts.user_data,
true,
amount_to_deposit
)?;
Expand Down Expand Up @@ -167,6 +175,7 @@ pub fn handle_direct_deposit<'info>(ctx: Context<'_, '_, '_, 'info, DirectDeposi
ctx.accounts.strategy_data.increase_current_debt(amount)?;

vault.handle_direct_deposit(amount, shares);
ctx.accounts.user_data.deposited += amount;

emit!(VaultDepositEvent {
vault_key: vault.key,
Expand Down
22 changes: 12 additions & 10 deletions programs/tokenized_vault/src/instructions/revoke_whitelisting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ use access_control::{
state::{UserRole, Role}
};

use crate::constants::WHITELISTED_SEED;
use crate::state::{Vault, Whitelisted};
use crate::constants::USER_DATA_SEED;
use crate::state::{Vault, UserData};
use crate::events::WhitelistUpdatedEvent;

#[derive(Accounts)]
#[instruction(user: Pubkey)]
pub struct RevokeWhitelisting<'info> {
#[account(
mut,
close = recipient,
seeds = [
WHITELISTED_SEED.as_bytes(),
USER_DATA_SEED.as_bytes(),
vault.key().as_ref(),
user.as_ref()
],
bump,
)]
pub whitelisted: Account<'info, Whitelisted>,
pub user_data: Account<'info, UserData>,

#[account(mut)]
pub vault: AccountLoader<'info, Vault>,
Expand All @@ -40,16 +40,18 @@ pub struct RevokeWhitelisting<'info> {
#[account(mut, constraint = roles.check_role()?)]
pub signer: Signer<'info>,

/// CHECK:
#[account(mut)]
pub recipient: UncheckedAccount<'info>,

pub access_control: Program<'info, AccessControl>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
}

pub fn handle_revoke_whitelisting(ctx: Context<RevokeWhitelisting>, _user: Pubkey) -> Result<()> {
ctx.accounts.user_data.whitelisted = false;

emit!(WhitelistUpdatedEvent {
user: _user,
whitelisted: false,
});

pub fn handle_revoke_whitelisting(_ctx: Context<RevokeWhitelisting>, _user: Pubkey) -> Result<()> {
Ok(())
}
21 changes: 14 additions & 7 deletions programs/tokenized_vault/src/instructions/whitelist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,25 @@ use access_control::{
state::{UserRole, Role}
};

use crate::constants::WHITELISTED_SEED;
use crate::state::{Vault, Whitelisted};
use crate::constants::USER_DATA_SEED;
use crate::state::{UserData, Vault};
use crate::events::WhitelistUpdatedEvent;

#[derive(Accounts)]
#[instruction(user: Pubkey)]
pub struct Whitelist<'info> {
#[account(
init,
init_if_needed,
seeds = [
WHITELISTED_SEED.as_bytes(),
USER_DATA_SEED.as_bytes(),
vault.key().as_ref(),
user.as_ref()
],
bump,
payer = signer,
space = Whitelisted::LEN,
space = UserData::LEN,
)]
pub whitelisted: Account<'info, Whitelisted>,
pub user_data: Account<'info, UserData>,

#[account(mut)]
pub vault: AccountLoader<'info, Vault>,
Expand All @@ -48,6 +49,12 @@ pub struct Whitelist<'info> {


pub fn handle_whitelist(ctx: Context<Whitelist>, _user: Pubkey) -> Result<()> {
ctx.accounts.whitelisted.is_whitelisted = true;
ctx.accounts.user_data.whitelisted = true;

emit!(WhitelistUpdatedEvent {
user: _user,
whitelisted: true,
});

Ok(())
}
31 changes: 26 additions & 5 deletions programs/tokenized_vault/src/instructions/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ use anchor_spl::{
use strategy::program::Strategy;

use crate::events::VaultWithdrawlEvent;
use crate::state::{StrategyDataAccInfo, Vault};
use crate::utils::{accountant, strategy as strategy_utils, token};
use crate::state::{StrategyData, UserData, Vault};
use crate::utils::{accountant, strategy as strategy_utils, token, unchecked::*};
use crate::errors::ErrorCode;
use crate::constants::{
UNDERLYING_SEED,
USER_DATA_SEED,
SHARES_SEED,
MAX_BPS
};
Expand Down Expand Up @@ -47,6 +48,18 @@ pub struct Withdraw<'info> {
#[account(mut)]
pub user_shares_account: InterfaceAccount<'info, TokenAccount>,

/// CHECK: can be missing
#[account(
mut,
seeds = [
USER_DATA_SEED.as_bytes(),
vault.key().as_ref(),
user.key().as_ref()
],
bump
)]
pub user_data: UncheckedAccount<'info>,

#[account(mut)]
pub user: Signer<'info>,

Expand Down Expand Up @@ -177,6 +190,12 @@ fn handle_internal<'info>(
&ctx.accounts.vault.load()?.seeds()
)?;

if !ctx.accounts.user_data.data_is_empty() {
let mut user_data: UserData = ctx.accounts.user_data.deserialize()?;
user_data.handle_withdraw(assets_to_transfer)?;
ctx.accounts.user_data.serialize(&user_data)?;
}

let vault = ctx.accounts.vault.load()?;

emit!(VaultWithdrawlEvent {
Expand Down Expand Up @@ -241,7 +260,7 @@ fn validate_max_withdraw<'info>(
let mut loss = 0;

for strategy_accounts in strategies {
let current_debt = strategy_accounts.strategy_data.current_debt();
let current_debt = strategy_accounts.strategy_data.deserialize::<StrategyData>()?.current_debt;

let mut to_withdraw = std::cmp::min(max_assets - have, current_debt);
let mut unrealised_loss = strategy_utils::assess_share_of_unrealised_losses(
Expand Down Expand Up @@ -303,7 +322,7 @@ fn withdraw_assets<'info>(

for i in 0..strategies.len() {
let strategy_acc = &strategies[i].strategy_acc;
let mut current_debt = strategies[i].strategy_data.current_debt();
let mut current_debt = strategies[i].strategy_data.deserialize::<StrategyData>()?.current_debt;

let mut to_withdraw = std::cmp::min(assets_needed as u64, current_debt);
let strategy_limit = strategy_utils::get_max_withdraw(&strategy_acc)?;
Expand Down Expand Up @@ -370,7 +389,9 @@ fn withdraw_assets<'info>(

let vault_mut = &mut vault_acc.load_mut()?;

strategies[i].strategy_data.set_current_debt(new_debt)?;
let mut strategy_data: StrategyData = strategies[i].strategy_data.deserialize()?;
strategy_data.update_current_debt(new_debt)?;
strategies[i].strategy_data.serialize(strategy_data)?;

vault_mut.total_debt = total_debt;
vault_mut.total_idle = total_idle;
Expand Down
2 changes: 1 addition & 1 deletion programs/tokenized_vault/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use anchor_lang::prelude::*;
pub use state::{SharesConfig, VaultConfig};
pub use instructions::*;

declare_id!("HdQsT53sANBQmPb6xWRaZXUzAXydLteNsJW1Y6kJDbMm");
declare_id!("5rcNAxHYxpmNBByNs9N9Te2Crf1a2KxixZqj6fzM3fY1");

#[program]
pub mod tokenized_vault {
Expand Down
4 changes: 2 additions & 2 deletions programs/tokenized_vault/src/state/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pub mod config;
pub mod strategy_data;
pub mod vault;
pub mod whitelist;
pub mod user_data;

pub use config::*;
pub use strategy_data::*;
pub use vault::*;
pub use whitelist::*;
pub use user_data::*;
Loading

0 comments on commit e634688

Please sign in to comment.