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

129 cdps #132

Closed
wants to merge 4 commits into from
Closed
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: 2 additions & 0 deletions programs/marginfi/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub const FEE_VAULT_SEED: &str = "fee_vault";
pub const EMISSIONS_AUTH_SEED: &str = "emissions_auth_seed";
pub const EMISSIONS_TOKEN_ACCOUNT_SEED: &str = "emissions_token_account_seed";

pub const CDP_MINT_AUTH_SEED: &str = "cdp_auth_seed";

cfg_if::cfg_if! {
if #[cfg(feature = "devnet")] {
pub const PYTH_ID: Pubkey = pubkey!("gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s");
Expand Down
223 changes: 223 additions & 0 deletions programs/marginfi/src/instructions/cdp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
use std::cell::RefMut;

use anchor_lang::prelude::*;
use anchor_spl::token::{Mint, MintTo, Token, Transfer};
use fixed::types::I80F48;

use crate::{
constants::{CDP_MINT_AUTH_SEED, LIQUIDITY_VAULT_SEED},
math_error,
prelude::MarginfiResult,
state::{
cdp::{Cdp, CdpBank, CdpCollateralBank, CdpCollateralBankStatus, CdpRiskEngine},
marginfi_group::{Bank, MarginfiGroup},
},
};

pub fn create_cdp_bank(ctx: Context<CreateCdpBank>) -> MarginfiResult {
assert_eq!(ctx.accounts.mint.supply, 0, "Mint has existing supply");

let mut cdp_bank = ctx.accounts.cdp_bank.load_init()?;

*cdp_bank = CdpBank {
group: ctx.accounts.group.key(),
mint: ctx.accounts.mint.key(),
mint_authority: ctx.accounts.mint_authority.key(),
mint_authority_bump: *ctx.bumps.get("mint_authority").unwrap(),
total_liability_shares: I80F48::ZERO.into(),
liability_share_value: I80F48::ZERO.into(),
liability_interest_rate: I80F48::ZERO.into(),
liability_limit: 0,
};

Ok(())
}

/// TODO: Make `cdp_bank` unique per (group, mint) -- this should already be the case becasue `cdp_bank` owns the `mint_authority`,
/// but we should make it explicit
/// TODO: What to do with freeze authority, should be probably controlled by the CDP admin.
#[derive(Accounts)]
pub struct CreateCdpBank<'info> {
pub group: AccountLoader<'info, MarginfiGroup>,
#[account(mut, address = group.load()?.admin)]
pub admin: Signer<'info>,
#[account(mint::authority = mint_authority)]
pub mint: Box<Account<'info, Mint>>,
#[account(
seeds = [
CDP_MINT_AUTH_SEED.as_bytes(),
mint.key().as_ref()
],
bump
)]
pub mint_authority: AccountInfo<'info>,
#[account(
init,
space = 8 + std::mem::size_of::<CdpBank>(),
payer = admin,
)]
pub cdp_bank: AccountLoader<'info, CdpBank>,

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

pub fn create_cdp_collateral_bank(ctx: Context<CreateCdpCollateralBank>) -> MarginfiResult {
let mut cdp_collateral_bank = ctx.accounts.cdp_collateral_bank.load_init()?;

*cdp_collateral_bank = CdpCollateralBank {
lending_bank: ctx.accounts.bank.key(),
cdp_bank: ctx.accounts.cdp_bank.key(),
status: CdpCollateralBankStatus::Disabled,
};

Ok(())
}

/// TODO: Make `cdp_collateral_bank` unique per (bank, cpd_bank)
#[derive(Accounts)]
pub struct CreateCdpCollateralBank<'info> {
pub group: AccountLoader<'info, MarginfiGroup>,
#[account(mut, address = group.load()?.admin)]
pub admin: Signer<'info>,
#[account(constraint = bank.load()?.group == group.key())]
pub bank: AccountLoader<'info, Bank>,
#[account(constraint = cdp_bank.load()?.group == group.key())]
pub cdp_bank: AccountLoader<'info, CdpBank>,
#[account(
init,
space = 8 + std::mem::size_of::<CdpCollateralBank>(),
payer = admin,

)]
pub cdp_collateral_bank: AccountLoader<'info, CdpCollateralBank>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}

pub fn create_cdp(ctx: Context<CreateCdp>) -> MarginfiResult {
let mut cdp = ctx.accounts.cdp.load_init()?;

*cdp = Cdp {
authority: ctx.accounts.authority.key(),
cdp_collateral_bank: ctx.accounts.cdp_collateral_bank.key(),
collateral_shares: I80F48::ZERO.into(),
liability_shares: I80F48::ZERO.into(),
flags: 0,
};

Ok(())
}

#[derive(Accounts)]
pub struct CreateCdp<'info> {
#[account(mut)]
pub fee_payer: Signer<'info>,
pub authority: AccountInfo<'info>,
pub cdp_collateral_bank: AccountLoader<'info, CdpCollateralBank>,
#[account(
init,
payer = fee_payer,
space = 8 + std::mem::size_of::<Cdp>(),
)]
pub cdp: AccountLoader<'info, Cdp>,
pub system_program: Program<'info, System>,
}

pub fn cdp_deposit(ctx: Context<CdpDeposit>, amount: u64) -> MarginfiResult {
let mut bank: RefMut<Bank> = ctx.accounts.bank.load_mut()?;

bank.accrue_interest(Clock::get()?.unix_timestamp)?;

let mut cdp: RefMut<Cdp> = ctx.accounts.cdp.load_mut()?;

let deposit_shares = bank.get_asset_shares(I80F48::from_num(amount))?;

bank.change_asset_shares(deposit_shares, false)?;
cdp.change_collateral_shares(deposit_shares)?;

bank.deposit_spl_transfer(
amount,
Transfer {
from: ctx.accounts.cdp_authority_ta.to_account_info(),
to: ctx.accounts.bank_vault.to_account_info(),
authority: ctx.accounts.cdp_authority.to_account_info(),
},
ctx.accounts.token_program.to_account_info(),
)?;

Ok(())
}

#[derive(Accounts)]
pub struct CdpDeposit<'info> {
pub group: AccountLoader<'info, MarginfiGroup>,
pub cdp_bank: AccountLoader<'info, CdpBank>,
pub cdp_collateral_bank: AccountLoader<'info, CdpCollateralBank>,
pub bank: AccountLoader<'info, Bank>,
pub bank_vault: AccountInfo<'info>,
pub cdp: AccountLoader<'info, Cdp>,
pub cdp_authority: Signer<'info>,
pub cdp_authority_ta: AccountInfo<'info>,
pub token_program: Program<'info, Token>,
}

pub fn cdp_mint(ctx: Context<CdpMint>, amount: u64) -> MarginfiResult {
let mut cdp_bank = ctx.accounts.cdp_bank.load_mut()?;
let mut cdp = ctx.accounts.cdp.load_mut()?;
let mut cdp_collateral_bank = ctx.accounts.cdp.load_mut()?;
let mut lending_bank = ctx.accounts.bank.load_mut()?;

let liab_shares = cdp_bank
.get_liability_shares(I80F48::from_num(amount))
.ok_or_else(math_error!())?;

cdp_bank.update_liability_share_amount(liab_shares)?;
cdp.change_liability_shares(liab_shares)?;

CdpRiskEngine::new(
&cdp,
&cdp_bank,
&cdp_collateral_bank,
&lending_bank,
ctx.remaining_accounts,
Clock::get()?.unix_timestamp,
)?
.check_init_health();

anchor_spl::token::mint_to(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
MintTo {
mint: ctx.accounts.cdp_mint.to_account_info(),
to: ctx.accounts.cdp_authority_ta.to_account_info(),
authority: ctx.accounts.cdp_mint_authority.to_account_info(),
},
&[&[
CDP_MINT_AUTH_SEED.as_bytes(),
ctx.accounts.cdp_mint.key().as_ref(),
&[cdp_bank.mint_authority_bump],
]],
),
amount,
)?;

Ok(())
}

/// Remaining accounts have `bank` oracle ais
#[derive(Accounts)]
pub struct CdpMint<'info> {
pub group: AccountLoader<'info, MarginfiGroup>,
pub cdp_bank: AccountLoader<'info, CdpBank>,
pub cdp_collateral_bank: AccountLoader<'info, CdpCollateralBank>,
pub bank: AccountLoader<'info, Bank>,
pub cdp_mint: Box<Account<'info, Mint>>,
pub cdp_mint_authority: AccountInfo<'info>,
pub cdp: AccountLoader<'info, Cdp>,
pub cdp_authority: Signer<'info>,
pub cdp_authority_ta: AccountInfo<'info>,
pub token_program: Program<'info, Token>,
}

pub fn cdp_liquidate()
2 changes: 2 additions & 0 deletions programs/marginfi/src/instructions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub mod cdp;
pub mod marginfi_account;
pub mod marginfi_group;

pub use cdp::*;
pub use marginfi_account::*;
pub use marginfi_group::*;
Loading
Loading