Add loan amount to WithdrawLoanLog. Add withdraw loan logging to toke… (#599)

* Add loan amount to WithdrawLoanLog. Add withdraw loan logging to token_force_close_borrows_with_token

* Address review comments.
This commit is contained in:
Nicholas Clarke 2023-06-11 15:37:33 -07:00 committed by GitHub
parent 7803f1dc9d
commit defbd8c2b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 113 additions and 57 deletions

View File

@ -9,7 +9,7 @@ use crate::state::*;
use super::{apply_settle_changes, OpenOrdersAmounts, OpenOrdersSlim};
use crate::accounts_ix::*;
use crate::logs::Serum3OpenOrdersBalanceLogV2;
use crate::logs::{LoanOriginationFeeInstruction, WithdrawLoanOriginationFeeLog};
use crate::logs::{LoanOriginationFeeInstruction, WithdrawLoanLog};
/// Settling means moving free funds from the serum3 open orders account
/// back into the mango account wallet.
@ -171,17 +171,18 @@ pub fn charge_loan_origination_fees(
// now that the loan is actually materialized, charge the loan origination fee
// note: the withdraw has already happened while placing the order
let base_token_account = account.token_position_mut(base_bank.token_index)?.0;
let (_, fee) = base_bank.withdraw_loan_origination_fee(
let withdraw_result = base_bank.withdraw_loan_origination_fee(
base_token_account,
actualized_base_loan,
now_ts,
)?;
emit!(WithdrawLoanOriginationFeeLog {
emit!(WithdrawLoanLog {
mango_group: *group_pubkey,
mango_account: *account_pubkey,
token_index: base_bank.token_index,
loan_origination_fee: fee.to_bits(),
loan_amount: withdraw_result.loan_amount.to_bits(),
loan_origination_fee: withdraw_result.loan_origination_fee.to_bits(),
instruction: LoanOriginationFeeInstruction::Serum3SettleFunds,
});
}
@ -199,17 +200,18 @@ pub fn charge_loan_origination_fees(
// now that the loan is actually materialized, charge the loan origination fee
// note: the withdraw has already happened while placing the order
let quote_token_account = account.token_position_mut(quote_bank.token_index)?.0;
let (_, fee) = quote_bank.withdraw_loan_origination_fee(
let withdraw_result = quote_bank.withdraw_loan_origination_fee(
quote_token_account,
actualized_quote_loan,
now_ts,
)?;
emit!(WithdrawLoanOriginationFeeLog {
emit!(WithdrawLoanLog {
mango_group: *group_pubkey,
mango_account: *account_pubkey,
token_index: quote_bank.token_index,
loan_origination_fee: fee.to_bits(),
loan_amount: withdraw_result.loan_amount.to_bits(),
loan_origination_fee: withdraw_result.loan_origination_fee.to_bits(),
instruction: LoanOriginationFeeInstruction::Serum3SettleFunds,
});
}

View File

@ -98,7 +98,7 @@ pub fn token_force_close_borrows_with_token(
liab_bank.deposit_with_dusting(liqee_liab_position, liab_transfer, now_ts)?;
let liqee_liab_indexed_position = liqee_liab_position.indexed_position;
let (liqor_liab_active, loan_origination_fee) =
let liqor_liab_withdraw_result =
liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer, now_ts)?;
let liqor_liab_indexed_position = liqor_liab_position.indexed_position;
let liqee_liab_native_after = liqee_liab_position.native(liab_bank);
@ -174,6 +174,12 @@ pub fn token_force_close_borrows_with_token(
fee_factor: fee_factor.to_bits(),
});
// liqor should never have a borrow
require!(
liqor_liab_withdraw_result.loan_amount.is_zero(),
MangoError::SomeError
);
let liqee_health_cache = new_health_cache(&liqee.borrow(), &mut account_retriever)
.context("create liqee health cache")?;
let liqee_liq_end_health = liqee_health_cache.health(HealthType::LiquidationEnd);
@ -191,7 +197,7 @@ pub fn token_force_close_borrows_with_token(
if !liqor_asset_active {
liqor.deactivate_token_position_and_log(liqor_asset_raw_index, liqor_key);
}
if !liqor_liab_active {
if !liqor_liab_withdraw_result.position_is_active {
liqor.deactivate_token_position_and_log(liqor_liab_raw_index, liqor_key)
}
};

View File

@ -9,8 +9,7 @@ use crate::state::*;
use crate::accounts_ix::*;
use crate::logs::{
LoanOriginationFeeInstruction, TokenBalanceLog, TokenLiqBankruptcyLog,
WithdrawLoanOriginationFeeLog,
LoanOriginationFeeInstruction, TokenBalanceLog, TokenLiqBankruptcyLog, WithdrawLoanLog,
};
pub fn token_liq_bankruptcy(
@ -149,7 +148,7 @@ pub fn token_liq_bankruptcy(
// transfer liab from liqee to liqor
let (liqor_liab, liqor_liab_raw_token_index, _) =
liqor.ensure_token_position(liab_token_index)?;
let (liqor_liab_active, loan_origination_fee) =
let liqor_liab_withdraw_result =
liab_bank.withdraw_with_fee(liqor_liab, liab_transfer, now_ts)?;
// liqor liab
@ -169,12 +168,16 @@ pub fn token_liq_bankruptcy(
require!(liqor_health >= 0, MangoError::HealthMustBePositive);
}
if loan_origination_fee.is_positive() {
emit!(WithdrawLoanOriginationFeeLog {
if liqor_liab_withdraw_result
.loan_origination_fee
.is_positive()
{
emit!(WithdrawLoanLog {
mango_group: ctx.accounts.group.key(),
mango_account: ctx.accounts.liqor.key(),
token_index: liab_token_index,
loan_origination_fee: loan_origination_fee.to_bits(),
loan_amount: liqor_liab_withdraw_result.loan_amount.to_bits(),
loan_origination_fee: liqor_liab_withdraw_result.loan_origination_fee.to_bits(),
instruction: LoanOriginationFeeInstruction::LiqTokenBankruptcy
});
}
@ -185,7 +188,7 @@ pub fn token_liq_bankruptcy(
ctx.accounts.liqor.key(),
);
}
if !liqor_liab_active {
if !liqor_liab_withdraw_result.position_is_active {
liqor.deactivate_token_position_and_log(
liqor_liab_raw_token_index,
ctx.accounts.liqor.key(),

View File

@ -5,8 +5,7 @@ use crate::accounts_ix::*;
use crate::error::*;
use crate::health::*;
use crate::logs::{
LoanOriginationFeeInstruction, TokenBalanceLog, TokenLiqWithTokenLog,
WithdrawLoanOriginationFeeLog,
LoanOriginationFeeInstruction, TokenBalanceLog, TokenLiqWithTokenLog, WithdrawLoanLog,
};
use crate::state::*;
@ -221,7 +220,7 @@ pub(crate) fn liquidation_action(
let (liqor_liab_position, liqor_liab_raw_index, _) =
liqor.ensure_token_position(liab_token_index)?;
let (liqor_liab_active, loan_origination_fee) =
let liqor_liab_withdraw_result =
liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer, now_ts)?;
let liqor_liab_indexed_position = liqor_liab_position.indexed_position;
let liqee_liab_native_after = liqee_liab_position.native(liab_bank);
@ -289,12 +288,16 @@ pub(crate) fn liquidation_action(
borrow_index: liab_bank.borrow_index.to_bits(),
});
if loan_origination_fee.is_positive() {
emit!(WithdrawLoanOriginationFeeLog {
if liqor_liab_withdraw_result
.loan_origination_fee
.is_positive()
{
emit!(WithdrawLoanLog {
mango_group: liqee.fixed.group,
mango_account: liqor_key,
token_index: liab_token_index,
loan_origination_fee: loan_origination_fee.to_bits(),
loan_amount: liqor_liab_withdraw_result.loan_amount.to_bits(),
loan_origination_fee: liqor_liab_withdraw_result.loan_origination_fee.to_bits(),
instruction: LoanOriginationFeeInstruction::LiqTokenWithToken
});
}
@ -309,7 +312,7 @@ pub(crate) fn liquidation_action(
if !liqor_asset_active {
liqor.deactivate_token_position_and_log(liqor_asset_raw_index, liqor_key);
}
if !liqor_liab_active {
if !liqor_liab_withdraw_result.position_is_active {
liqor.deactivate_token_position_and_log(liqor_liab_raw_index, liqor_key)
}

View File

@ -7,9 +7,7 @@ use anchor_spl::token;
use fixed::types::I80F48;
use crate::accounts_ix::*;
use crate::logs::{
LoanOriginationFeeInstruction, TokenBalanceLog, WithdrawLoanOriginationFeeLog, WithdrawLog,
};
use crate::logs::{LoanOriginationFeeInstruction, TokenBalanceLog, WithdrawLoanLog, WithdrawLog};
pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bool) -> Result<()> {
require_msg!(amount > 0, "withdraw amount must be positive");
@ -65,7 +63,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
)?;
// Update the bank and position
let (position_is_active, loan_origination_fee) = bank.withdraw_with_fee(
let withdraw_result = bank.withdraw_with_fee(
position,
amount_i80f48,
Clock::get()?.unix_timestamp.try_into().unwrap(),
@ -116,7 +114,7 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
// remaining_accounts for all banks/oracles, including the account that will now be
// deactivated.
//
if !position_is_active {
if !withdraw_result.position_is_active {
account.deactivate_token_position_and_log(raw_token_index, ctx.accounts.account.key());
}
@ -129,12 +127,13 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
price: oracle_price.to_bits(),
});
if loan_origination_fee.is_positive() {
emit!(WithdrawLoanOriginationFeeLog {
if withdraw_result.loan_origination_fee.is_positive() {
emit!(WithdrawLoanLog {
mango_group: ctx.accounts.group.key(),
mango_account: ctx.accounts.account.key(),
token_index,
loan_origination_fee: loan_origination_fee.to_bits(),
loan_amount: withdraw_result.loan_amount.to_bits(),
loan_origination_fee: withdraw_result.loan_origination_fee.to_bits(),
instruction: LoanOriginationFeeInstruction::TokenWithdraw,
});
}

View File

@ -257,6 +257,16 @@ pub struct WithdrawLoanOriginationFeeLog {
pub instruction: LoanOriginationFeeInstruction,
}
#[event]
pub struct WithdrawLoanLog {
pub mango_group: Pubkey,
pub mango_account: Pubkey,
pub token_index: u16,
pub loan_amount: i128,
pub loan_origination_fee: i128,
pub instruction: LoanOriginationFeeInstruction,
}
#[event]
pub struct TokenLiqBankruptcyLog {
pub mango_group: Pubkey,

View File

@ -170,6 +170,12 @@ const_assert_eq!(
const_assert_eq!(size_of::<Bank>(), 3064);
const_assert_eq!(size_of::<Bank>() % 8, 0);
pub struct WithdrawResult {
pub position_is_active: bool,
pub loan_origination_fee: I80F48,
pub loan_amount: I80F48,
}
impl Bank {
pub fn from_existing_bank(
existing_bank: &Bank,
@ -403,13 +409,15 @@ impl Bank {
native_amount: I80F48,
now_ts: u64,
) -> Result<bool> {
let (position_is_active, _) = self.withdraw_internal_wrapper(
position,
native_amount,
false,
!position.is_in_use(),
now_ts,
)?;
let position_is_active = self
.withdraw_internal_wrapper(
position,
native_amount,
false,
!position.is_in_use(),
now_ts,
)?
.position_is_active;
Ok(position_is_active)
}
@ -424,7 +432,7 @@ impl Bank {
now_ts: u64,
) -> Result<bool> {
self.withdraw_internal_wrapper(position, native_amount, false, true, now_ts)
.map(|(not_dusted, _)| not_dusted || position.is_in_use())
.map(|withdraw_result| withdraw_result.position_is_active || position.is_in_use())
}
/// Withdraws `native_amount` while applying the loan origination fee if a borrow is created.
@ -440,7 +448,7 @@ impl Bank {
position: &mut TokenPosition,
native_amount: I80F48,
now_ts: u64,
) -> Result<(bool, I80F48)> {
) -> Result<WithdrawResult> {
self.withdraw_internal_wrapper(position, native_amount, true, !position.is_in_use(), now_ts)
}
@ -452,7 +460,7 @@ impl Bank {
with_loan_origination_fee: bool,
allow_dusting: bool,
now_ts: u64,
) -> Result<(bool, I80F48)> {
) -> Result<WithdrawResult> {
let opening_indexed_position = position.indexed_position;
let res = self.withdraw_internal(
position,
@ -473,7 +481,7 @@ impl Bank {
with_loan_origination_fee: bool,
allow_dusting: bool,
now_ts: u64,
) -> Result<(bool, I80F48)> {
) -> Result<WithdrawResult> {
require_gte!(native_amount, 0);
let native_position = position.native(self);
@ -486,13 +494,21 @@ impl Bank {
self.dust += new_native_position;
self.indexed_deposits -= position.indexed_position;
position.indexed_position = I80F48::ZERO;
return Ok((false, I80F48::ZERO));
return Ok(WithdrawResult {
position_is_active: false,
loan_origination_fee: I80F48::ZERO,
loan_amount: I80F48::ZERO,
});
} else {
// withdraw some deposits leaving a positive balance
let indexed_change = native_amount / self.deposit_index;
self.indexed_deposits -= indexed_change;
position.indexed_position -= indexed_change;
return Ok((true, I80F48::ZERO));
return Ok(WithdrawResult {
position_is_active: true,
loan_origination_fee: I80F48::ZERO,
loan_amount: I80F48::ZERO,
});
}
}
@ -519,7 +535,11 @@ impl Bank {
// withdraws and not borrows
self.update_net_borrows(native_amount, now_ts);
Ok((true, loan_origination_fee))
Ok(WithdrawResult {
position_is_active: true,
loan_origination_fee,
loan_amount: native_amount,
})
}
// withdraw the loan origination fee for a borrow that happenend earlier
@ -528,19 +548,26 @@ impl Bank {
position: &mut TokenPosition,
already_borrowed_native_amount: I80F48,
now_ts: u64,
) -> Result<(bool, I80F48)> {
) -> Result<WithdrawResult> {
let loan_origination_fee = self.loan_origination_fee_rate * already_borrowed_native_amount;
self.collected_fees_native += loan_origination_fee;
let (position_is_active, _) = self.withdraw_internal_wrapper(
position,
loan_origination_fee,
false,
!position.is_in_use(),
now_ts,
)?;
let position_is_active = self
.withdraw_internal_wrapper(
position,
loan_origination_fee,
false,
!position.is_in_use(),
now_ts,
)?
.position_is_active;
Ok((position_is_active, loan_origination_fee))
Ok(WithdrawResult {
position_is_active,
loan_origination_fee,
// To avoid double counting of loans return loan_amount of 0 here (as the loan_amount has already been returned earlier with loan_origination_fee == 0)
loan_amount: I80F48::ZERO,
})
}
/// Change a position without applying the loan origination fee
@ -563,9 +590,13 @@ impl Bank {
position: &mut TokenPosition,
native_amount: I80F48,
now_ts: u64,
) -> Result<(bool, I80F48)> {
) -> Result<WithdrawResult> {
if native_amount >= 0 {
Ok((self.deposit(position, native_amount, now_ts)?, I80F48::ZERO))
Ok(WithdrawResult {
position_is_active: self.deposit(position, native_amount, now_ts)?,
loan_origination_fee: I80F48::ZERO,
loan_amount: I80F48::ZERO,
})
} else {
self.withdraw_with_fee(position, -native_amount, now_ts)
}
@ -948,7 +979,9 @@ mod tests {
let change = I80F48::from(change);
let dummy_now_ts = 1 as u64;
let dummy_price = I80F48::ZERO;
let (is_active, _) = bank.change_with_fee(&mut account, change, dummy_now_ts)?;
let is_active = bank
.change_with_fee(&mut account, change, dummy_now_ts)?
.position_is_active;
let mut expected_native = start_native + change;
if expected_native >= 0.0 && expected_native < 1.0 && !is_in_use {