Skip to content

Commit

Permalink
anchor: improve integration access control
Browse files Browse the repository at this point in the history
  • Loading branch information
yurushao committed Dec 25, 2024
1 parent 7f897b4 commit bd95511
Show file tree
Hide file tree
Showing 17 changed files with 2,282 additions and 512 deletions.
10 changes: 8 additions & 2 deletions anchor/programs/glam/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use anchor_lang::prelude::*;

#[error_code]
pub enum AccessError {
#[msg("Signer is not authorized")]
NotAuthorized,
#[msg("Integration is disabled")]
IntegrationDisabled,
}

#[error_code]
pub enum ManagerError {
#[msg("Error closing account: not empty")]
CloseNotEmptyError,
#[msg("Error: not authorized")]
NotAuthorizedError,
#[msg("Invalid fund name: max 50 chars")]
InvalidFundName,
#[msg("Too many assets: max 50")]
Expand Down
57 changes: 29 additions & 28 deletions anchor/programs/glam/src/instructions/drift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use anchor_spl::token_interface::TokenAccount;
use drift::{MarketType, PositionDirection};
use glam_macros::treasury_signer_seeds;

use crate::error::AccessError;
use crate::state::*;

use drift::cpi::accounts::{
Expand Down Expand Up @@ -37,24 +38,24 @@ pub struct DriftInitialize<'info> {
pub treasury: SystemAccount<'info>,

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

pub drift_program: Program<'info, Drift>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftInitialize))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftInitialize))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_initialize_handler(ctx: Context<DriftInitialize>) -> Result<()> {
pub fn initialize_handler(ctx: Context<DriftInitialize>) -> Result<()> {
initialize_user_stats(CpiContext::new_with_signer(
ctx.accounts.drift_program.to_account_info(),
InitializeUserStats {
user_stats: ctx.accounts.user_stats.to_account_info(),
state: ctx.accounts.state.to_account_info(),
authority: ctx.accounts.treasury.to_account_info(),
payer: ctx.accounts.manager.to_account_info(),
payer: ctx.accounts.signer.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
},
Expand All @@ -72,7 +73,7 @@ pub fn drift_initialize_handler(ctx: Context<DriftInitialize>) -> Result<()> {
user_stats: ctx.accounts.user_stats.to_account_info(),
state: ctx.accounts.state.to_account_info(),
authority: ctx.accounts.treasury.to_account_info(),
payer: ctx.accounts.manager.to_account_info(),
payer: ctx.accounts.signer.to_account_info(),
rent: ctx.accounts.rent.to_account_info(),
system_program: ctx.accounts.system_program.to_account_info(),
},
Expand All @@ -98,15 +99,15 @@ pub struct DriftUpdate<'info> {
pub treasury: SystemAccount<'info>,

#[account(mut)]
manager: Signer<'info>,
signer: Signer<'info>,

pub drift_program: Program<'info, Drift>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_update_user_custom_margin_ratio_handler(
pub fn update_user_custom_margin_ratio_handler(
ctx: Context<DriftUpdate>,
sub_account_id: u16,
margin_ratio: u32,
Expand All @@ -127,10 +128,10 @@ pub fn drift_update_user_custom_margin_ratio_handler(
Ok(())
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_update_user_margin_trading_enabled_handler(
pub fn update_user_margin_trading_enabled_handler(
ctx: Context<DriftUpdate>,
sub_account_id: u16,
margin_trading_enabled: bool,
Expand All @@ -151,10 +152,10 @@ pub fn drift_update_user_margin_trading_enabled_handler(
Ok(())
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftUpdateUser))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_update_user_delegate_handler(
pub fn update_user_delegate_handler(
ctx: Context<DriftUpdate>,
sub_account_id: u16,
delegate: Pubkey,
Expand Down Expand Up @@ -199,16 +200,16 @@ pub struct DriftDeposit<'info> {
pub treasury_ata: Box<InterfaceAccount<'info, TokenAccount>>,

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

pub drift_program: Program<'info, Drift>,
pub token_program: Program<'info, Token>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftDeposit))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftDeposit))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_deposit_handler<'c: 'info, 'info>(
pub fn deposit_handler<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, DriftDeposit<'info>>,
market_index: u16,
amount: u64,
Expand Down Expand Up @@ -262,16 +263,16 @@ pub struct DriftWithdraw<'info> {
pub drift_ata: Box<InterfaceAccount<'info, TokenAccount>>,

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

pub drift_program: Program<'info, Drift>,
pub token_program: Program<'info, Token>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftWithdraw))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftWithdraw))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_withdraw_handler<'c: 'info, 'info>(
pub fn withdraw_handler<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, DriftWithdraw<'info>>,
market_index: u16,
amount: u64,
Expand Down Expand Up @@ -319,16 +320,16 @@ pub struct DriftDeleteUser<'info> {
pub treasury: SystemAccount<'info>,

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

pub drift_program: Program<'info, Drift>,
pub system_program: Program<'info, System>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftDeleteUser))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftDeleteUser))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_delete_user_handler(ctx: Context<DriftDeleteUser>) -> Result<()> {
pub fn delete_user_handler(ctx: Context<DriftDeleteUser>) -> Result<()> {
delete_user(CpiContext::new_with_signer(
ctx.accounts.drift_program.to_account_info(),
DeleteUser {
Expand Down Expand Up @@ -360,16 +361,16 @@ pub struct DriftPlaceOrders<'info> {
pub treasury: SystemAccount<'info>,

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

pub drift_program: Program<'info, Drift>,
pub token_program: Program<'info, Token>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftPlaceOrders))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftPlaceOrders))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_place_orders_handler<'c: 'info, 'info>(
pub fn place_orders_handler<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, DriftPlaceOrders<'info>>,
order_params: Vec<OrderParams>,
) -> Result<()> {
Expand All @@ -379,7 +380,7 @@ pub fn drift_place_orders_handler<'c: 'info, 'info>(
MarketType::Spot => Permission::DriftSpotMarket,
MarketType::Perp => Permission::DriftPerpMarket,
};
acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, permission)?;
acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, permission)?;

match order.market_type {
MarketType::Spot => {
Expand Down Expand Up @@ -447,16 +448,16 @@ pub struct DriftCancelOrders<'info> {
pub treasury: SystemAccount<'info>,

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

pub drift_program: Program<'info, Drift>,
pub token_program: Program<'info, Token>,
}

#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.manager.key, Permission::DriftCancelOrders))]
#[access_control(acl::check_access(&ctx.accounts.fund, &ctx.accounts.signer.key, Permission::DriftCancelOrders))]
#[access_control(acl::check_integration(&ctx.accounts.fund, IntegrationName::Drift))]
#[treasury_signer_seeds]
pub fn drift_cancel_orders_handler<'c: 'info, 'info>(
pub fn cancel_orders_handler<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, DriftCancelOrders<'info>>,
market_type: Option<MarketType>,
market_index: Option<u16>,
Expand Down
61 changes: 55 additions & 6 deletions anchor/programs/glam/src/instructions/fund.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use crate::{
constants::*,
error::{FundError, ManagerError},
error::{AccessError, FundError, ManagerError},
state::*,
};
use anchor_lang::{prelude::*, system_program};
use anchor_spl::token_interface::{
transfer_checked, Mint, TokenAccount, TokenInterface, TransferChecked,
use anchor_spl::{
token::{close_account as close_token_account, CloseAccount as CloseTokenAccount, Token},
token_2022::{
close_account as close_token_2022_account, CloseAccount as CloseToken2022Account, Token2022,
},
token_interface::{transfer_checked, Mint, TokenAccount, TokenInterface, TransferChecked},
};
use glam_macros::treasury_signer_seeds;

Expand Down Expand Up @@ -284,7 +288,7 @@ pub fn update_fund_handler<'c: 'info, 'info>(

#[derive(Accounts)]
pub struct CloseFund<'info> {
#[account(mut, close = manager, has_one = manager @ ManagerError::NotAuthorizedError)]
#[account(mut, close = manager, has_one = manager @ AccessError::NotAuthorized)]
fund: Account<'info, FundAccount>,

#[account(mut, close = manager)]
Expand Down Expand Up @@ -327,7 +331,7 @@ pub fn close_fund_handler(ctx: Context<CloseFund>) -> Result<()> {

#[derive(Accounts)]
pub struct SetSubscribeRedeemEnabled<'info> {
#[account(mut, has_one = manager @ ManagerError::NotAuthorizedError)]
#[account(mut, has_one = manager @ AccessError::NotAuthorized)]
fund: Box<Account<'info, FundAccount>>,

#[account(mut)]
Expand Down Expand Up @@ -362,7 +366,7 @@ pub fn set_subscribe_redeem_enabled_handler(

#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(mut, has_one = manager @ ManagerError::NotAuthorizedError)]
#[account(mut, has_one = manager @ AccessError::NotAuthorized)]
fund: Account<'info, FundAccount>,

#[account(mut, seeds = [b"treasury".as_ref(), fund.key().as_ref()], bump)]
Expand Down Expand Up @@ -419,3 +423,48 @@ pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {

Ok(())
}

#[derive(Accounts)]
pub struct CloseTokenAccounts<'info> {
#[account(mut, has_one = manager @ AccessError::NotAuthorized)]
fund: Account<'info, FundAccount>,

#[account(mut, seeds = [b"treasury".as_ref(), fund.key().as_ref()], bump)]
treasury: SystemAccount<'info>,

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

token_program: Program<'info, Token>,
token_2022_program: Program<'info, Token2022>,
}

#[treasury_signer_seeds]
pub fn close_token_accounts_handler<'info>(
ctx: Context<'_, '_, '_, 'info, CloseTokenAccounts<'info>>,
) -> Result<()> {
ctx.remaining_accounts.iter().try_for_each(|account| {
if account.owner.eq(&ctx.accounts.token_program.key()) {
close_token_account(CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
CloseTokenAccount {
account: account.to_account_info(),
destination: ctx.accounts.treasury.to_account_info(),
authority: ctx.accounts.treasury.to_account_info(),
},
treasury_signer_seeds,
))
} else {
close_token_2022_account(CpiContext::new_with_signer(
ctx.accounts.token_2022_program.to_account_info(),
CloseToken2022Account {
account: account.to_account_info(),
destination: ctx.accounts.treasury.to_account_info(),
authority: ctx.accounts.treasury.to_account_info(),
},
treasury_signer_seeds,
))
}
})?;
Ok(())
}
7 changes: 5 additions & 2 deletions anchor/programs/glam/src/instructions/investor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ use solana_program::stake::state::warmup_cooldown_rate;

use crate::constants::{self, WSOL};
use crate::error::{FundError, InvestorError, PolicyError};
use crate::instructions::policy_hook::PolicyAccount;
use crate::state::pyth_price::PriceExt;
use crate::{state::*, PolicyAccount};
use crate::state::*;

fn log_decimal(amount: u64, minus_decimals: i32) -> f64 {
amount as f64 * 10f64.powf(minus_decimals as f64)
}

#[derive(Accounts)]
#[instruction(_share_class_id: u8)]
pub struct Subscribe<'info> {
#[account()]
pub fund: Box<Account<'info, FundAccount>>,
Expand All @@ -32,7 +34,7 @@ pub struct Subscribe<'info> {
// the shares to mint
#[account(
mut,
seeds = [b"share".as_ref(), &[0u8], fund.key().as_ref()], //TODO: add share_class_idx to instruction
seeds = [b"share".as_ref(), &[_share_class_id], fund.key().as_ref()],
bump,
mint::authority = share_class,
mint::token_program = token_2022_program
Expand Down Expand Up @@ -82,6 +84,7 @@ pub struct Subscribe<'info> {

pub fn subscribe_handler<'c: 'info, 'info>(
ctx: Context<'_, '_, 'c, 'info, Subscribe<'info>>,
_share_class_id: u8,
amount: u64,
skip_state: bool,
) -> Result<()> {
Expand Down
Loading

0 comments on commit bd95511

Please sign in to comment.