Skip to content

Commit

Permalink
The program (fee state) now gains a proportion of the origination fee…
Browse files Browse the repository at this point in the history
…, as dictated in the program_fee_rate
  • Loading branch information
jgur-psyops committed Oct 23, 2024
1 parent b670878 commit 3e9f7c5
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 27 deletions.
41 changes: 31 additions & 10 deletions programs/marginfi/src/instructions/marginfi_account/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand All @@ -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(),
)?;
Expand Down Expand Up @@ -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
Expand Down
43 changes: 26 additions & 17 deletions programs/marginfi/tests/user_actions/borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,16 @@ 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)
.await
.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)
Expand All @@ -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();

Expand All @@ -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
Expand All @@ -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(())
}
Expand Down

0 comments on commit 3e9f7c5

Please sign in to comment.