From 3e9f7c5170c0085ddea75c7172edd0bbd6c346e6 Mon Sep 17 00:00:00 2001 From: jgur-psyops Date: Wed, 23 Oct 2024 10:58:46 -0400 Subject: [PATCH] The program (fee state) now gains a proportion of the origination fee, as dictated in the program_fee_rate --- .../instructions/marginfi_account/borrow.rs | 41 +++++++++++++----- .../marginfi/tests/user_actions/borrow.rs | 43 +++++++++++-------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/programs/marginfi/src/instructions/marginfi_account/borrow.rs b/programs/marginfi/src/instructions/marginfi_account/borrow.rs index 86190cb1e..9a29a364a 100644 --- a/programs/marginfi/src/instructions/marginfi_account/borrow.rs +++ b/programs/marginfi/src/instructions/marginfi_account/borrow.rs @@ -12,7 +12,7 @@ use crate::{ }; use anchor_lang::prelude::*; use anchor_spl::token_interface::{TokenAccount, TokenInterface}; -use fixed::types::I80F48; +use fixed::{traits::Fixed, types::I80F48}; use solana_program::{clock::Clock, sysvar::Sysvar}; /// 1. Accrue interest @@ -44,6 +44,8 @@ pub fn lending_account_borrow<'info>( )?; let mut marginfi_account = marginfi_account_loader.load_mut()?; + let group = &marginfi_group_loader.load()?; + let program_fee_rate: I80F48 = group.fee_state_cache.program_fee_rate.into(); check!( !marginfi_account.get_flag(DISABLED_FLAG), @@ -52,7 +54,7 @@ pub fn lending_account_borrow<'info>( bank_loader.load_mut()?.accrue_interest( clock.unix_timestamp, - &*marginfi_group_loader.load()?, + group, #[cfg(not(feature = "client"))] bank_loader.key(), )?; @@ -130,16 +132,35 @@ pub fn lending_account_borrow<'info>( }); } // release mutable borrow of bank - // The bank fee account gains the origination fee + // The program and/or group fee account gains the origination fee { let mut bank = bank_loader.load_mut()?; - let bank_fees_before: I80F48 = bank.collected_group_fees_outstanding.into(); - let bank_fees_after: I80F48 = if origination_fee.is_zero() { - bank_fees_before - } else { - bank_fees_before.saturating_add(origination_fee) - }; - bank.collected_group_fees_outstanding = bank_fees_after.into(); + + if !origination_fee.is_zero() { + let mut bank_fees_after: I80F48 = bank.collected_group_fees_outstanding.into(); + + if !program_fee_rate.is_zero() { + // Some portion of the origination fee to goes to program fees + let program_fee_amount: I80F48 = origination_fee + .checked_mul(program_fee_rate) + .ok_or_else(math_error!())?; + // The remainder of the origination fee go to group fees + bank_fees_after = bank_fees_after + .saturating_add(origination_fee.saturating_sub(program_fee_amount)); + + // Update the bank's program fees + let program_fees_before: I80F48 = bank.collected_program_fees_outstanding.into(); + bank.collected_program_fees_outstanding = program_fees_before + .saturating_add(program_fee_amount) + .into(); + } else { + // If program fee rate is zero, add the full origination fee to group fees + bank_fees_after = bank_fees_after.saturating_add(origination_fee); + } + + // Update the bank's group fees + bank.collected_group_fees_outstanding = bank_fees_after.into(); + } } // Check account health, if below threshold fail transaction diff --git a/programs/marginfi/tests/user_actions/borrow.rs b/programs/marginfi/tests/user_actions/borrow.rs index 665066d27..e905a1360 100644 --- a/programs/marginfi/tests/user_actions/borrow.rs +++ b/programs/marginfi/tests/user_actions/borrow.rs @@ -79,6 +79,7 @@ async fn marginfi_account_borrow_success( // ------------------------------------------------------------------------- let debt_bank_f = test_f.get_bank(&debt_mint); + let bank_before = debt_bank_f.load().await; let pre_vault_balance = debt_bank_f .get_vault_token_account(BankVaultType::Liquidity) @@ -86,11 +87,8 @@ async fn marginfi_account_borrow_success( .balance() .await; let pre_user_debt_accounted = I80F48::ZERO; - let pre_fee_balance: I80F48 = debt_bank_f - .load() - .await - .collected_group_fees_outstanding - .into(); + let pre_fee_group_fees: I80F48 = bank_before.collected_group_fees_outstanding.into(); + let pre_fee_program_fees: I80F48 = bank_before.collected_program_fees_outstanding.into(); let res = user_mfi_account_f .try_bank_borrow(user_debt_token_account_f.key, debt_bank_f, borrow_amount) @@ -107,9 +105,7 @@ async fn marginfi_account_borrow_success( .lending_account .get_balance(&debt_bank_f.key) .unwrap(); - let post_user_debt_accounted = debt_bank_f - .load() - .await + let post_user_debt_accounted = bank_before .get_asset_amount(balance.liability_shares.into()) .unwrap(); @@ -125,16 +121,23 @@ async fn marginfi_account_borrow_success( }) .unwrap_or(0); let borrow_amount_pre_fee = borrow_amount_native + borrow_fee; - let origination_fee_rate: I80F48 = debt_bank_f - .load() // ?? could optimize load calls in this test? - .await + let origination_fee_rate: I80F48 = bank_before .config .interest_rate_config .protocol_origination_fee .into(); + let program_fee_rate: I80F48 = test_f + .marginfi_group + .load() + .await + .fee_state_cache + .program_fee_rate + .into(); let origination_fee: I80F48 = I80F48::from_num(borrow_amount_native) .checked_mul(origination_fee_rate) .unwrap(); + let program_origination_fee: I80F48 = origination_fee.checked_mul(program_fee_rate).unwrap(); + let group_origination_fee: I80F48 = origination_fee.saturating_sub(program_origination_fee); let active_balance_count = marginfi_account .lending_account @@ -157,12 +160,18 @@ async fn marginfi_account_borrow_success( ); // The outstanding origination fee is recorded - let post_fee_balance: I80F48 = debt_bank_f - .load() - .await - .collected_group_fees_outstanding - .into(); - assert_eq!(pre_fee_balance + origination_fee, post_fee_balance); + let bank_after = debt_bank_f.load().await; + let post_fee_program_fees: I80F48 = bank_after.collected_program_fees_outstanding.into(); + assert_eq!( + pre_fee_program_fees + program_origination_fee, + post_fee_program_fees + ); + + let post_fee_group_fees: I80F48 = bank_after.collected_group_fees_outstanding.into(); + assert_eq!( + pre_fee_group_fees + group_origination_fee, + post_fee_group_fees + ); Ok(()) }