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

Merged
merged 6 commits into from
Dec 18, 2024
Merged
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,
}
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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice of revoke whitelist event gets emitted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event was added


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(())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nice if a whitelist event gets emitted.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Front-end engineers were asking how to check whether a user was whitelisted, I had to tell them a way to check whether a PDA initialized or not when there was whitelist PDa. Ideally it's good if the subgraph can provide such info.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event was added, checking if PDA initialized won't work, cause now we have UserData PDA istead

}
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
Loading