Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deposit limit #52

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
}
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::{token, vault};

#[derive(Accounts)]
Expand All @@ -35,6 +36,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 @@ -47,20 +61,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 @@ -69,8 +73,8 @@ pub struct Deposit<'info> {
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
)?;
Expand All @@ -95,6 +99,8 @@ pub fn handle_deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
&ctx.accounts.vault.load()?.seeds_shares(),
)?;

ctx.accounts.user_data.deposited += amount;

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

Expand Down
44 changes: 26 additions & 18 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,12 +10,16 @@ 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::utils::{token, vault};
use crate::utils::strategy as strategy_utils;
use crate::state::{UserData, Vault, StrategyData};
use crate::utils::{strategy as strategy_utils, token, vault};

#[derive(Accounts)]
pub struct DirectDeposit<'info> {
Expand Down Expand Up @@ -52,6 +56,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 @@ -72,20 +89,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 token_program: Program<'info, Token>,
pub access_control: Program<'info, AccessControl>,
pub strategy_program: Program<'info, Strategy>,
Expand All @@ -94,8 +101,8 @@ pub struct DirectDeposit<'info> {
pub fn handle_direct_deposit<'info>(ctx: Context<'_, '_, '_, 'info, DirectDeposit<'info>>, 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,
true,
amount
)?;
Expand Down Expand Up @@ -140,6 +147,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
17 changes: 6 additions & 11 deletions programs/tokenized_vault/src/instructions/revoke_whitelisting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@ 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};

#[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 +39,12 @@ 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<()> {
pub fn handle_revoke_whitelisting(ctx: Context<RevokeWhitelisting>, _user: Pubkey) -> Result<()> {
ctx.accounts.user_data.whitelisted = false;
Ok(())
}
14 changes: 7 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,24 @@ 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};

#[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 +48,6 @@ 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;
Ok(())
}
32 changes: 26 additions & 6 deletions programs/tokenized_vault/src/instructions/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ use anchor_spl::{
use strategy::program::Strategy;

use crate::events::VaultWithdrawlEvent;
use crate::state::{StrategyDataAccInfo, Vault};
use crate::utils::strategy as strategy_utils;
use crate::utils::token;
use crate::state::{StrategyData, UserData, Vault};
use crate::utils::{strategy as strategy_utils, token, unchecked::*};
use crate::errors::ErrorCode;
use crate::constants::{
UNDERLYING_SEED,
USER_DATA_SEED,
SHARES_SEED,
MAX_BPS
};
Expand All @@ -37,6 +37,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 @@ -129,6 +141,12 @@ pub fn handle_withdraw<'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 @@ -193,7 +211,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 @@ -255,7 +273,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 @@ -322,7 +340,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
Loading