Skip to content

Commit

Permalink
Add CdpRiskEngine for risk assessment
Browse files Browse the repository at this point in the history
  • Loading branch information
jkbpvsc committed Feb 8, 2024
1 parent b86ea74 commit 3488f46
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 6 deletions.
37 changes: 34 additions & 3 deletions programs/marginfi/src/instructions/cdp.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::cell::RefMut;

use anchor_lang::prelude::*;
use anchor_spl::token::{Mint, Token, Transfer};
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},
cdp::{Cdp, CdpBank, CdpCollateralBank, CdpCollateralBankStatus, CdpRiskEngine},
marginfi_group::{Bank, MarginfiGroup},
},
};
Expand Down Expand Up @@ -133,7 +133,7 @@ pub fn cdp_deposit(ctx: Context<CdpDeposit>, amount: u64) -> MarginfiResult {

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

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

bank.deposit_spl_transfer(
Expand Down Expand Up @@ -165,6 +165,8 @@ pub struct CdpDeposit<'info> {
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))
Expand All @@ -173,6 +175,33 @@ pub fn cdp_mint(ctx: Context<CdpMint>, amount: u64) -> MarginfiResult {
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(())
}

Expand All @@ -190,3 +219,5 @@ pub struct CdpMint<'info> {
pub cdp_authority_ta: AccountInfo<'info>,
pub token_program: Program<'info, Token>,
}

pub fn cdp_liquidate()
78 changes: 75 additions & 3 deletions programs/marginfi/src/state/cdp.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
use anchor_lang::prelude::*;
use fixed::types::I80F48;
use bytemuck::Zeroable;
use fixed::types::{I80F48, I89F39};

use crate::{math_error, prelude::MarginfiResult};
use crate::{
check, constants::MAX_PRICE_AGE_SEC, math_error, prelude::MarginfiResult,
state::price::PriceAdapter,
};

use super::marginfi_group::WrappedI80F48;
use super::{
marginfi_group::{Bank, WrappedI80F48},
price::{OraclePriceFeedAdapter, OraclePriceType, PriceBias},
};

// CDP Actions
// ==========
Expand Down Expand Up @@ -80,6 +87,9 @@ pub enum CdpCollateralBankStatus {
ReduceOnly,
}

unsafe impl Pod for CdpCollateralBank {}
unsafe impl Zeroable for CdpCollateralBank {}

/// Supported collateral for a bank
#[account(zero_copy)]
#[repr(C)]
Expand Down Expand Up @@ -132,3 +142,65 @@ impl Cdp {
Ok(())
}
}

pub struct CdpRiskEngine<'a> {
deposit: &'a Cdp,
bank: &'a CdpBank,
collateral_bank: &'a CdpCollateralBank,
lending_bank: &'a Bank,
oracle_adapter: OraclePriceFeedAdapter,
}

impl<'a> CdpRiskEngine<'a> {
pub fn new(
deposit: &'a Cdp,
bank: &'a CdpBank,
collateral_bank: &'a CdpCollateralBank,
lending_bank: &'a Bank,
oracle_ais: &[AccountInfo],
current_timestamp: i64,
) -> Result<Self> {
let oracle_adapter = OraclePriceFeedAdapter::try_from_bank_config(
&lending_bank.config,
oracle_ais,
current_timestamp,
MAX_PRICE_AGE_SEC,
)?;

Ok(Self {
deposit,
bank,
collateral_bank,
lending_bank,
oracle_adapter,
})
}

pub fn check_init_health(&self) -> Result<()> {
let liab_shares = I80F48::from(self.deposit.liability_shares);
let liab_value = self
.bank
.get_liability_amount(liab_shares)
.ok_or_else(math_error!())?;

let collateral_shares = I80F48::from(self.deposit.collateral_shares);
let collateral_price = self
.oracle_adapter
.get_price_of_type(OraclePriceType::TimeWeighted, Some(PriceBias::Low))?;

let collateral_init_weight: I80F48 = self.lending_bank.config.asset_weight_init.into();

let weighted_collateral_value = collateral_shares
.checked_mul(collateral_price)
.ok_or_else(math_error!())?
.checked_mul(collateral_init_weight)
.ok_or_else(math_error!())?;

check!(
weighted_collateral_value >= liab_value,
crate::prelude::MarginfiError::BadAccountHealth
);

Ok(())
}
}

0 comments on commit 3488f46

Please sign in to comment.