Skip to content

Commit

Permalink
New FundAccount + FundModel (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ece authored May 22, 2024
1 parent 59d5aa8 commit dc3e735
Show file tree
Hide file tree
Showing 30 changed files with 1,724 additions and 861 deletions.
7 changes: 4 additions & 3 deletions anchor/Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ cluster = "localnet"
wallet = "~/.config/solana/id.json"

[scripts]
#test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_crud"
#test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_investor"
#test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_drift"
test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_staking"
# test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_investor"
# test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_crud"
# test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_drift"
#test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern glam_openfunds"
#test = "../node_modules/.bin/nx run anchor:jest --verbose --testPathPattern tests/ --testNamePattern devnet"

[test]
Expand Down
23 changes: 23 additions & 0 deletions anchor/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions anchor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ spl-associated-token-account = "3.0.2"
spl-token-metadata-interface = "0.3.3"
spl-transfer-hook-interface = "0.6.3"
pyth-sdk-solana = "0.10.1"
strum = { version = "0.26", features = ["derive"] }

drift = { path = "./deps/drift" }
marinade = { path = "./deps/marinade" }
1 change: 1 addition & 0 deletions anchor/programs/glam/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ spl-associated-token-account = { workspace = true }
spl-token-metadata-interface = { workspace = true }
spl-transfer-hook-interface = { workspace = true }
pyth-sdk-solana = { workspace = true }
strum = { workspace = true }

drift = { workspace = true }
marinade = { workspace = true }
40 changes: 23 additions & 17 deletions anchor/programs/glam/src/instructions/drift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use anchor_spl::token::Token;
use anchor_spl::token_interface::TokenAccount;

use crate::error::ManagerError;
use crate::state::fund::*;
use crate::state::*;

use drift::cpi::accounts::{
DeleteUser, Deposit, InitializeUser, InitializeUserStats, UpdateUserDelegate, Withdraw,
Expand All @@ -17,10 +17,10 @@ use drift::State;
#[derive(Accounts)]
pub struct DriftInitialize<'info> {
#[account(has_one = manager @ ManagerError::NotAuthorizedError)]
pub fund: Account<'info, Fund>,
pub fund: Account<'info, FundAccount>,

/// CHECK: treasury account is the same as fund treasury
pub treasury: AccountInfo<'info>,
#[account(seeds = [b"treasury".as_ref(), fund.key().as_ref()], bump)]
pub treasury: SystemAccount<'info>,

#[account(mut)]
/// CHECK: checks are done inside cpi call
Expand Down Expand Up @@ -52,7 +52,7 @@ pub fn drift_initialize_handler(
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];

Expand Down Expand Up @@ -113,10 +113,10 @@ pub fn drift_initialize_handler(
#[derive(Accounts)]
pub struct DriftUpdate<'info> {
#[account(has_one = manager @ ManagerError::NotAuthorizedError)]
pub fund: Account<'info, Fund>,
pub fund: Account<'info, FundAccount>,

/// CHECK: treasury account is the same as fund treasury
pub treasury: AccountInfo<'info>,
#[account(seeds = [b"treasury".as_ref(), fund.key().as_ref()], bump)]
pub treasury: SystemAccount<'info>,

#[account(mut)]
/// CHECK: checks are done inside cpi call
Expand All @@ -141,7 +141,7 @@ pub fn drift_update_delegated_trader_handler(
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];

Expand All @@ -166,8 +166,10 @@ pub fn drift_update_delegated_trader_handler(
#[derive(Accounts)]
pub struct DriftDeposit<'info> {
#[account(has_one = manager @ ManagerError::NotAuthorizedError)]
pub fund: Account<'info, Fund>,
pub treasury: Account<'info, Treasury>,
pub fund: Account<'info, FundAccount>,

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

#[account(mut)]
/// CHECK: checks are done inside cpi call
Expand Down Expand Up @@ -203,7 +205,7 @@ pub fn drift_deposit_handler<'c: 'info, 'info>(
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];

Expand Down Expand Up @@ -236,7 +238,9 @@ pub fn drift_deposit_handler<'c: 'info, 'info>(
pub struct DriftWithdraw<'info> {
#[account(has_one = manager @ ManagerError::NotAuthorizedError)]
pub fund: Account<'info, Fund>,
pub treasury: Account<'info, Treasury>,

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

#[account(mut)]
/// CHECK: checks are done inside cpi call
Expand Down Expand Up @@ -274,7 +278,7 @@ pub fn drift_withdraw_handler<'c: 'info, 'info>(
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];

Expand Down Expand Up @@ -307,8 +311,10 @@ pub fn drift_withdraw_handler<'c: 'info, 'info>(
#[derive(Accounts)]
pub struct DriftClose<'info> {
#[account(has_one = manager @ ManagerError::NotAuthorizedError)]
pub fund: Account<'info, Fund>,
pub treasury: Account<'info, Treasury>,
pub fund: Account<'info, FundAccount>,

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

#[account(mut)]
/// CHECK: checks are done inside cpi call
Expand Down Expand Up @@ -336,7 +342,7 @@ pub fn drift_close_handler(ctx: Context<DriftClose>) -> Result<()> {
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];

Expand Down
52 changes: 31 additions & 21 deletions anchor/programs/glam/src/instructions/investor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use pyth_sdk_solana::state::SolanaPriceAccount;
use pyth_sdk_solana::Price;

use crate::error::{FundError, InvestorError};
use crate::state::fund::*;
use crate::state::*;

//TODO(security): check that treasury belongs to the fund

Expand Down Expand Up @@ -69,11 +69,17 @@ fn check_pricing_account(_asset: &str, _pricing_account: &str) -> bool {

#[derive(Accounts)]
pub struct Subscribe<'info> {
pub fund: Box<Account<'info, Fund>>,
pub fund: Box<Account<'info, FundAccount>>,

// the shares to mint
#[account(mut, mint::authority = share_class, mint::token_program = token_2022_program)]
#[account(mut, seeds = [
b"share".as_ref(),
&[0u8], //TODO: add share_class_idx to instruction
fund.key().as_ref()
],
bump, mint::authority = share_class, mint::token_program = token_2022_program)]
pub share_class: Box<InterfaceAccount<'info, Mint>>, // mint

#[account(
init_if_needed,
payer = signer,
Expand Down Expand Up @@ -109,16 +115,19 @@ pub fn subscribe_handler<'c: 'info, 'info>(
skip_state: bool,
) -> Result<()> {
let fund = &ctx.accounts.fund;
require!(fund.is_active, InvestorError::FundNotActive);
require!(fund.is_enabled(), InvestorError::FundNotActive);

let assets = fund.assets().unwrap();
// msg!("assets: {:?}", assets);

if fund.share_classes.len() > 1 {
// we need to define how to split the total amount into share classes
panic!("not implemented")
}
require!(fund.share_classes.len() > 0, FundError::NoShareClassInFund);

msg!("fund.share_class[0]: {}", fund.share_classes[0]);
msg!("expected share class: {}", ctx.accounts.share_class.key());
// msg!("fund.share_class[0]: {}", fund.share_classes[0]);
// msg!("expected share class: {}", ctx.accounts.share_class.key());

require!(
fund.share_classes[0] == ctx.accounts.share_class.key(),
Expand All @@ -127,7 +136,8 @@ pub fn subscribe_handler<'c: 'info, 'info>(

let asset_info = ctx.accounts.asset.to_account_info();
let asset_key = asset_info.key();
let asset_idx = fund.assets.iter().position(|&asset| asset == asset_key);
let asset_idx = assets.iter().position(|&asset| asset == asset_key);
// msg!("asset={:?} idx={:?}", asset_key, asset_idx);

require!(asset_idx.is_some(), InvestorError::InvalidAssetSubscribe);
let asset_idx = asset_idx.unwrap();
Expand All @@ -153,7 +163,7 @@ pub fn subscribe_handler<'c: 'info, 'info>(
// the assets should be the fund.assets, including the base asset,
// and in the correct order.
require!(
ctx.remaining_accounts.len() == 2 * fund.assets.len(),
ctx.remaining_accounts.len() == 2 * assets.len(),
InvestorError::InvalidAssetSubscribe
);

Expand Down Expand Up @@ -276,9 +286,9 @@ pub fn subscribe_handler<'c: 'info, 'info>(
let fund_key = ctx.accounts.fund.key();
let seeds = &[
"share".as_bytes(),
share_class_symbol.as_bytes(),
&[0u8],
fund_key.as_ref(),
&[ctx.accounts.fund.share_classes_bumps[0]],
&[ctx.bumps.share_class],
];
let signer_seeds = &[&seeds[..]];
mint_to(
Expand All @@ -303,7 +313,7 @@ pub fn subscribe_handler<'c: 'info, 'info>(

#[derive(Accounts)]
pub struct Redeem<'info> {
pub fund: Account<'info, Fund>,
pub fund: Account<'info, FundAccount>,

// the shares to burn
#[account(mut, mint::authority = share_class, mint::token_program = token_2022_program)]
Expand All @@ -315,8 +325,8 @@ pub struct Redeem<'info> {
#[account(mut)]
pub signer: Signer<'info>,

/// CHECK: skip
pub treasury: AccountInfo<'info>,
#[account(seeds = [b"treasury".as_ref(), fund.key().as_ref()], bump)]
pub treasury: SystemAccount<'info>,

// programs
pub token_program: Program<'info, Token>,
Expand Down Expand Up @@ -364,14 +374,17 @@ pub fn redeem_handler<'c: 'info, 'info>(
let signer = &ctx.accounts.signer;
let treasury = &ctx.accounts.treasury;

let assets = fund.assets().unwrap();
let assets_weights = fund.assets_weights().unwrap();

// if we skip the redeem state, we attempt to do in_kind redeem,
// i.e. transfer to the user a % of each asset in the fund (assuming
// the fund is balanced, if it's not the redeem may fail).
// ctx.remaining_accounts must contain tuples of (asset, signer_ata, treasury_ata, pricing).
// the assets should be the fund.assets, including the base asset,
// and in the correct order.
require!(
ctx.remaining_accounts.len() == 4 * fund.assets.len(),
ctx.remaining_accounts.len() == 4 * assets.len(),
InvestorError::InvalidAssetsRedeem
);

Expand All @@ -386,10 +399,7 @@ pub fn redeem_handler<'c: 'info, 'info>(
.expect("invalid treasury account");
let pricing_account = &accounts[3];

require!(
asset.key() == fund.assets[i],
InvestorError::InvalidAssetsRedeem
);
require!(asset.key() == assets[i], InvestorError::InvalidAssetsRedeem);
require!(
signer_asset_ata.owner == signer.key(),
InvestorError::InvalidAssetsRedeem
Expand Down Expand Up @@ -476,7 +486,7 @@ pub fn redeem_handler<'c: 'info, 'info>(
// value_to_redeem.price,
// value_to_redeem.expo
// );
let total_weight: u32 = fund.assets_weights.iter().sum();
let total_weight: u32 = assets_weights.iter().sum();

burn(
CpiContext::new(
Expand All @@ -503,7 +513,7 @@ pub fn redeem_handler<'c: 'info, 'info>(
((value.price as u128 * 10u128.pow(att.asset_decimals as u32))
/ att.asset_price.price as u128) as u64
} else {
let weight: u32 = fund.assets_weights[i];
let weight: u32 = assets_weights[i];
if weight == 0 {
continue;
}
Expand Down Expand Up @@ -534,7 +544,7 @@ pub fn redeem_handler<'c: 'info, 'info>(
let seeds = &[
"treasury".as_bytes(),
fund_key.as_ref(),
&[ctx.accounts.fund.bump_treasury],
&[ctx.bumps.treasury],
];
let signer_seeds = &[&seeds[..]];
// msg!(
Expand Down
Loading

0 comments on commit dc3e735

Please sign in to comment.