Net borrow limit: Separate out tracking and checking (#534)
That way it's easier to be specific about where the limit should be checked.
This commit is contained in:
parent
e612be219d
commit
da2a7f4e0c
|
@ -859,7 +859,6 @@ mod tests {
|
|||
account.ensure_token_position(4).unwrap().0,
|
||||
I80F48::from(10),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -943,7 +942,6 @@ mod tests {
|
|||
account.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(testcase.token1),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
bank2
|
||||
|
@ -952,7 +950,6 @@ mod tests {
|
|||
account.ensure_token_position(4).unwrap().0,
|
||||
I80F48::from(testcase.token2),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
bank3
|
||||
|
@ -961,7 +958,6 @@ mod tests {
|
|||
account.ensure_token_position(5).unwrap().0,
|
||||
I80F48::from(testcase.token3),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
for (settings, bank) in testcase
|
||||
|
|
|
@ -59,7 +59,8 @@ impl HealthCache {
|
|||
let target_amount = amount * price;
|
||||
|
||||
let mut source_bank = source_bank.clone();
|
||||
source_bank.withdraw_with_fee(&mut source_position, amount, now_ts, source_oracle_price)?;
|
||||
source_bank.withdraw_with_fee(&mut source_position, amount, now_ts)?;
|
||||
source_bank.check_net_borrows(source_oracle_price)?;
|
||||
let mut target_bank = target_bank.clone();
|
||||
target_bank.deposit(&mut target_position, target_amount, now_ts)?;
|
||||
|
||||
|
@ -403,7 +404,8 @@ impl HealthCache {
|
|||
let mut position = account.token_position(bank.token_index)?.clone();
|
||||
|
||||
let mut bank = bank.clone();
|
||||
bank.withdraw_with_fee(&mut position, amount, now_ts, token.prices.oracle)?;
|
||||
bank.withdraw_with_fee(&mut position, amount, now_ts)?;
|
||||
bank.check_net_borrows(token.prices.oracle)?;
|
||||
|
||||
let mut resulting_cache = self.clone();
|
||||
resulting_cache.adjust_token_balance(&bank, -amount)?;
|
||||
|
@ -1133,7 +1135,6 @@ mod tests {
|
|||
account.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(100),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -1216,7 +1217,6 @@ mod tests {
|
|||
account.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(100),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
bank1
|
||||
|
@ -1225,7 +1225,6 @@ mod tests {
|
|||
account2.ensure_token_position(1).unwrap().0,
|
||||
I80F48::from(-100),
|
||||
DUMMY_NOW_TS,
|
||||
DUMMY_PRICE,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -103,12 +103,8 @@ pub fn account_buyback_fees_with_mngo(
|
|||
dao_mngo_token_position.indexed_position >= I80F48::ZERO,
|
||||
MangoError::SomeError
|
||||
);
|
||||
let in_use = mngo_bank.withdraw_without_fee(
|
||||
account_mngo_token_position,
|
||||
max_buyback_mngo,
|
||||
now_ts,
|
||||
mngo_oracle_price,
|
||||
)?;
|
||||
let in_use =
|
||||
mngo_bank.withdraw_without_fee(account_mngo_token_position, max_buyback_mngo, now_ts)?;
|
||||
emit!(TokenBalanceLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
mango_account: ctx.accounts.account.key(),
|
||||
|
@ -132,12 +128,8 @@ pub fn account_buyback_fees_with_mngo(
|
|||
dao_account.ensure_token_position(fees_bank.token_index)?;
|
||||
let dao_fees = dao_fees_token_position.native(&fees_bank);
|
||||
assert!(dao_fees >= max_buyback_fees);
|
||||
let in_use = fees_bank.withdraw_without_fee(
|
||||
dao_fees_token_position,
|
||||
max_buyback_fees,
|
||||
now_ts,
|
||||
fees_oracle_price,
|
||||
)?;
|
||||
let in_use =
|
||||
fees_bank.withdraw_without_fee(dao_fees_token_position, max_buyback_fees, now_ts)?;
|
||||
if !in_use {
|
||||
dao_account.deactivate_token_position_and_log(
|
||||
dao_fees_raw_token_index,
|
||||
|
|
|
@ -351,23 +351,22 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>(
|
|||
);
|
||||
}
|
||||
|
||||
// Enforce min vault to deposits ratio
|
||||
if native_after_change < 0 {
|
||||
let is_active = bank.change_without_fee(
|
||||
position,
|
||||
change_amount,
|
||||
Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
)?;
|
||||
if !is_active {
|
||||
deactivated_token_positions.push(change.raw_token_index);
|
||||
}
|
||||
|
||||
if change_amount < 0 && native_after_change < 0 {
|
||||
let vault_ai = vaults
|
||||
.iter()
|
||||
.find(|vault_ai| vault_ai.key == &bank.vault)
|
||||
.unwrap();
|
||||
bank.enforce_min_vault_to_deposits_ratio(vault_ai)?;
|
||||
}
|
||||
|
||||
let is_active = bank.change_without_fee(
|
||||
position,
|
||||
change.amount - loan_origination_fee,
|
||||
Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
*oracle_price,
|
||||
)?;
|
||||
if !is_active {
|
||||
deactivated_token_positions.push(change.raw_token_index);
|
||||
bank.check_net_borrows(*oracle_price)?;
|
||||
}
|
||||
|
||||
bank.flash_loan_approved_amount = 0;
|
||||
|
|
|
@ -451,12 +451,7 @@ pub(crate) fn liquidation_action(
|
|||
let liqor_token_position = liqor.token_position_mut(settle_token_index)?.0;
|
||||
let liqee_token_position = liqee.token_position_mut(settle_token_index)?.0;
|
||||
settle_bank.deposit(liqee_token_position, token_transfer, now_ts)?;
|
||||
settle_bank.withdraw_without_fee(
|
||||
liqor_token_position,
|
||||
token_transfer,
|
||||
now_ts,
|
||||
settle_token_oracle_price,
|
||||
)?;
|
||||
settle_bank.withdraw_without_fee(liqor_token_position, token_transfer, now_ts)?;
|
||||
liqee_health_cache.adjust_token_balance(&settle_bank, token_transfer)?;
|
||||
}
|
||||
msg!(
|
||||
|
@ -756,16 +751,10 @@ mod tests {
|
|||
token_p(&mut setup.liqee),
|
||||
I80F48::from_num(init_liqee_spot),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.unwrap();
|
||||
settle_bank
|
||||
.change_without_fee(
|
||||
token_p(&mut setup.liqor),
|
||||
I80F48::from_num(1000.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(token_p(&mut setup.liqor), I80F48::from_num(1000.0), 0)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -817,20 +806,10 @@ mod tests {
|
|||
|
||||
let settle_bank = setup.settle_bank.data();
|
||||
settle_bank
|
||||
.change_without_fee(
|
||||
token_p(&mut setup.liqee),
|
||||
I80F48::from_num(5.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(token_p(&mut setup.liqee), I80F48::from_num(5.0), 0)
|
||||
.unwrap();
|
||||
settle_bank
|
||||
.change_without_fee(
|
||||
token_p(&mut setup.liqor),
|
||||
I80F48::from_num(1000.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(token_p(&mut setup.liqor), I80F48::from_num(1000.0), 0)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -125,12 +125,7 @@ pub fn perp_liq_negative_pnl_or_bankruptcy(
|
|||
let liqor_token_position = liqor.token_position_mut(settle_token_index)?.0;
|
||||
let liqee_token_position = liqee.token_position_mut(settle_token_index)?.0;
|
||||
settle_bank.deposit(liqor_token_position, settlement, now_ts)?;
|
||||
settle_bank.withdraw_without_fee(
|
||||
liqee_token_position,
|
||||
settlement,
|
||||
now_ts,
|
||||
settle_token_oracle_price,
|
||||
)?;
|
||||
settle_bank.withdraw_without_fee(liqee_token_position, settlement, now_ts)?;
|
||||
liqee_health_cache.adjust_token_balance(&settle_bank, -settlement)?;
|
||||
|
||||
emit!(PerpLiqNegativePnlOrBankruptcyLog {
|
||||
|
|
|
@ -96,7 +96,6 @@ pub fn perp_settle_fees(ctx: Context<PerpSettleFees>, max_settle_amount: u64) ->
|
|||
token_position,
|
||||
settlement,
|
||||
Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
settle_token_oracle_price,
|
||||
)?;
|
||||
// Update the settled balance on the market itself
|
||||
perp_market.fees_settled += settlement;
|
||||
|
|
|
@ -176,12 +176,7 @@ pub fn perp_settle_pnl(ctx: Context<PerpSettlePnl>) -> Result<()> {
|
|||
// Don't charge loan origination fees on borrows created via settling:
|
||||
// Even small loan origination fees could accumulate if a perp position is
|
||||
// settled back and forth repeatedly.
|
||||
settle_bank.withdraw_without_fee(
|
||||
b_token_position,
|
||||
settlement,
|
||||
now_ts,
|
||||
settle_token_oracle_price,
|
||||
)?;
|
||||
settle_bank.withdraw_without_fee(b_token_position, settlement, now_ts)?;
|
||||
|
||||
emit!(TokenBalanceLog {
|
||||
mango_group: ctx.accounts.group.key(),
|
||||
|
|
|
@ -250,14 +250,9 @@ pub fn serum3_place_order(
|
|||
.token_position_mut(payer_bank.token_index)?
|
||||
.0
|
||||
.native(&payer_bank);
|
||||
if withdrawn_from_vault > position_native {
|
||||
payer_bank.enforce_min_vault_to_deposits_ratio((*ctx.accounts.payer_vault).as_ref())?;
|
||||
}
|
||||
|
||||
// Charge the difference in vault balance to the user's account
|
||||
let vault_difference = {
|
||||
let oracle_price =
|
||||
payer_bank.oracle_price(&AccountInfoRef::borrow(&ctx.accounts.payer_oracle)?, None)?;
|
||||
apply_vault_difference(
|
||||
ctx.accounts.account.key(),
|
||||
&mut account.borrow_mut(),
|
||||
|
@ -265,10 +260,16 @@ pub fn serum3_place_order(
|
|||
&mut payer_bank,
|
||||
after_vault,
|
||||
before_vault,
|
||||
Some(oracle_price),
|
||||
)?
|
||||
};
|
||||
|
||||
if withdrawn_from_vault > position_native {
|
||||
let oracle_price =
|
||||
payer_bank.oracle_price(&AccountInfoRef::borrow(&ctx.accounts.payer_oracle)?, None)?;
|
||||
payer_bank.enforce_min_vault_to_deposits_ratio((*ctx.accounts.payer_vault).as_ref())?;
|
||||
payer_bank.check_net_borrows(oracle_price)?;
|
||||
}
|
||||
|
||||
//
|
||||
// Health check
|
||||
//
|
||||
|
@ -348,7 +349,6 @@ fn apply_vault_difference(
|
|||
bank: &mut Bank,
|
||||
vault_after: u64,
|
||||
vault_before: u64,
|
||||
oracle_price: Option<I80F48>,
|
||||
) -> Result<VaultDifference> {
|
||||
let needed_change = I80F48::from(vault_after) - I80F48::from(vault_before);
|
||||
|
||||
|
@ -358,12 +358,7 @@ fn apply_vault_difference(
|
|||
if needed_change >= 0 {
|
||||
bank.deposit(position, needed_change, now_ts)?;
|
||||
} else {
|
||||
bank.withdraw_without_fee(
|
||||
position,
|
||||
-needed_change,
|
||||
now_ts,
|
||||
oracle_price.unwrap(), // required for withdraws
|
||||
)?;
|
||||
bank.withdraw_without_fee(position, -needed_change, now_ts)?;
|
||||
}
|
||||
let native_after = position.native(bank);
|
||||
let native_change = native_after - native_before;
|
||||
|
@ -470,7 +465,6 @@ pub fn apply_settle_changes(
|
|||
base_bank,
|
||||
after_base_vault,
|
||||
before_base_vault,
|
||||
None, // guaranteed to deposit into bank
|
||||
)?;
|
||||
let quote_difference = apply_vault_difference(
|
||||
account_pk,
|
||||
|
@ -479,7 +473,6 @@ pub fn apply_settle_changes(
|
|||
quote_bank,
|
||||
after_quote_vault_adjusted,
|
||||
before_quote_vault,
|
||||
None, // guaranteed to deposit into bank
|
||||
)?;
|
||||
|
||||
if let Some(health_cache) = health_cache {
|
||||
|
|
|
@ -137,12 +137,8 @@ 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) = liab_bank.withdraw_with_fee(
|
||||
liqor_liab,
|
||||
liab_transfer,
|
||||
now_ts,
|
||||
liab_oracle_price,
|
||||
)?;
|
||||
let (liqor_liab_active, loan_origination_fee) =
|
||||
liab_bank.withdraw_with_fee(liqor_liab, liab_transfer, now_ts)?;
|
||||
|
||||
// liqor liab
|
||||
emit!(TokenBalanceLog {
|
||||
|
|
|
@ -192,12 +192,8 @@ 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) = liab_bank.withdraw_with_fee(
|
||||
liqor_liab_position,
|
||||
liab_transfer,
|
||||
now_ts,
|
||||
liab_oracle_price,
|
||||
)?;
|
||||
let (liqor_liab_active, loan_origination_fee) =
|
||||
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);
|
||||
|
||||
|
@ -211,7 +207,6 @@ pub(crate) fn liquidation_action(
|
|||
liqee_asset_position,
|
||||
asset_transfer,
|
||||
now_ts,
|
||||
asset_oracle_price,
|
||||
)?;
|
||||
let liqee_asset_indexed_position = liqee_asset_position.indexed_position;
|
||||
let liqee_assets_native_after = liqee_asset_position.native(asset_bank);
|
||||
|
@ -444,38 +439,18 @@ mod tests {
|
|||
{
|
||||
let asset_bank = setup.asset_bank.data();
|
||||
asset_bank
|
||||
.change_without_fee(
|
||||
asset_p(&mut setup.liqee),
|
||||
I80F48::from_num(10.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(asset_p(&mut setup.liqee), I80F48::from_num(10.0), 0)
|
||||
.unwrap();
|
||||
asset_bank
|
||||
.change_without_fee(
|
||||
asset_p(&mut setup.liqor),
|
||||
I80F48::from_num(1000.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(asset_p(&mut setup.liqor), I80F48::from_num(1000.0), 0)
|
||||
.unwrap();
|
||||
|
||||
let liab_bank = setup.liab_bank.data();
|
||||
liab_bank
|
||||
.change_without_fee(
|
||||
liab_p(&mut setup.liqor),
|
||||
I80F48::from_num(1000.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(liab_p(&mut setup.liqor), I80F48::from_num(1000.0), 0)
|
||||
.unwrap();
|
||||
liab_bank
|
||||
.change_without_fee(
|
||||
liab_p(&mut setup.liqee),
|
||||
I80F48::from_num(-9.0),
|
||||
0,
|
||||
I80F48::from(1),
|
||||
)
|
||||
.change_without_fee(liab_p(&mut setup.liqee), I80F48::from_num(-9.0), 0)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,6 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
|||
position,
|
||||
amount_i80f48,
|
||||
Clock::get()?.unix_timestamp.try_into().unwrap(),
|
||||
oracle_price,
|
||||
)?;
|
||||
|
||||
// Provide a readable error message in case the vault doesn't have enough tokens
|
||||
|
@ -140,10 +139,11 @@ pub fn token_withdraw(ctx: Context<TokenWithdraw>, amount: u64, allow_borrow: bo
|
|||
});
|
||||
}
|
||||
|
||||
// Enforce min vault to deposits ratio
|
||||
// Enforce min vault to deposits ratio and net borrow limits
|
||||
if is_borrow {
|
||||
ctx.accounts.vault.reload()?;
|
||||
bank.enforce_min_vault_to_deposits_ratio(ctx.accounts.vault.as_ref())?;
|
||||
bank.check_net_borrows(oracle_price)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -386,7 +386,6 @@ impl Bank {
|
|||
position: &mut TokenPosition,
|
||||
native_amount: I80F48,
|
||||
now_ts: u64,
|
||||
oracle_price: I80F48,
|
||||
) -> Result<bool> {
|
||||
let (position_is_active, _) = self.withdraw_internal_wrapper(
|
||||
position,
|
||||
|
@ -394,7 +393,6 @@ impl Bank {
|
|||
false,
|
||||
!position.is_in_use(),
|
||||
now_ts,
|
||||
Some(oracle_price),
|
||||
)?;
|
||||
|
||||
Ok(position_is_active)
|
||||
|
@ -408,16 +406,8 @@ impl Bank {
|
|||
position: &mut TokenPosition,
|
||||
native_amount: I80F48,
|
||||
now_ts: u64,
|
||||
oracle_price: I80F48,
|
||||
) -> Result<bool> {
|
||||
self.withdraw_internal_wrapper(
|
||||
position,
|
||||
native_amount,
|
||||
false,
|
||||
true,
|
||||
now_ts,
|
||||
Some(oracle_price),
|
||||
)
|
||||
self.withdraw_internal_wrapper(position, native_amount, false, true, now_ts)
|
||||
.map(|(not_dusted, _)| not_dusted || position.is_in_use())
|
||||
}
|
||||
|
||||
|
@ -434,16 +424,8 @@ impl Bank {
|
|||
position: &mut TokenPosition,
|
||||
native_amount: I80F48,
|
||||
now_ts: u64,
|
||||
oracle_price: I80F48,
|
||||
) -> Result<(bool, I80F48)> {
|
||||
self.withdraw_internal_wrapper(
|
||||
position,
|
||||
native_amount,
|
||||
true,
|
||||
!position.is_in_use(),
|
||||
now_ts,
|
||||
Some(oracle_price),
|
||||
)
|
||||
self.withdraw_internal_wrapper(position, native_amount, true, !position.is_in_use(), now_ts)
|
||||
}
|
||||
|
||||
/// Internal function to withdraw funds
|
||||
|
@ -454,7 +436,6 @@ impl Bank {
|
|||
with_loan_origination_fee: bool,
|
||||
allow_dusting: bool,
|
||||
now_ts: u64,
|
||||
oracle_price: Option<I80F48>,
|
||||
) -> Result<(bool, I80F48)> {
|
||||
let opening_indexed_position = position.indexed_position;
|
||||
let res = self.withdraw_internal(
|
||||
|
@ -463,7 +444,6 @@ impl Bank {
|
|||
with_loan_origination_fee,
|
||||
allow_dusting,
|
||||
now_ts,
|
||||
oracle_price,
|
||||
);
|
||||
self.update_cumulative_interest(position, opening_indexed_position);
|
||||
res
|
||||
|
@ -477,7 +457,6 @@ impl Bank {
|
|||
with_loan_origination_fee: bool,
|
||||
allow_dusting: bool,
|
||||
now_ts: u64,
|
||||
oracle_price: Option<I80F48>,
|
||||
) -> Result<(bool, I80F48)> {
|
||||
require_gte!(native_amount, 0);
|
||||
let native_position = position.native(self);
|
||||
|
@ -523,9 +502,6 @@ impl Bank {
|
|||
// net borrows requires updating in only this case, since other branches of the method deal with
|
||||
// withdraws and not borrows
|
||||
self.update_net_borrows(native_amount, now_ts);
|
||||
if let Some(oracle_price) = oracle_price {
|
||||
self.check_net_borrows(oracle_price)?;
|
||||
}
|
||||
|
||||
Ok((true, loan_origination_fee))
|
||||
}
|
||||
|
@ -546,7 +522,6 @@ impl Bank {
|
|||
false,
|
||||
!position.is_in_use(),
|
||||
now_ts,
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok((position_is_active, loan_origination_fee))
|
||||
|
@ -558,12 +533,11 @@ impl Bank {
|
|||
position: &mut TokenPosition,
|
||||
native_amount: I80F48,
|
||||
now_ts: u64,
|
||||
oracle_price: I80F48,
|
||||
) -> Result<bool> {
|
||||
if native_amount >= 0 {
|
||||
self.deposit(position, native_amount, now_ts)
|
||||
} else {
|
||||
self.withdraw_without_fee(position, -native_amount, now_ts, oracle_price)
|
||||
self.withdraw_without_fee(position, -native_amount, now_ts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,12 +547,11 @@ impl Bank {
|
|||
position: &mut TokenPosition,
|
||||
native_amount: I80F48,
|
||||
now_ts: u64,
|
||||
oracle_price: I80F48,
|
||||
) -> Result<(bool, I80F48)> {
|
||||
if native_amount >= 0 {
|
||||
Ok((self.deposit(position, native_amount, now_ts)?, I80F48::ZERO))
|
||||
} else {
|
||||
self.withdraw_with_fee(position, -native_amount, now_ts, oracle_price)
|
||||
self.withdraw_with_fee(position, -native_amount, now_ts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -957,8 +930,7 @@ 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, dummy_price)?;
|
||||
let (is_active, _) = bank.change_with_fee(&mut account, change, dummy_now_ts)?;
|
||||
|
||||
let mut expected_native = start_native + change;
|
||||
if expected_native >= 0.0 && expected_native < 1.0 && !is_in_use {
|
||||
|
@ -1034,40 +1006,41 @@ mod tests {
|
|||
|
||||
let mut account = TokenPosition::default();
|
||||
|
||||
bank.change_without_fee(&mut account, I80F48::from(100), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(100), 0)
|
||||
.unwrap();
|
||||
assert_eq!(bank.net_borrows_in_window, 0);
|
||||
bank.change_without_fee(&mut account, I80F48::from(-100), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-100), 0)
|
||||
.unwrap();
|
||||
assert_eq!(bank.net_borrows_in_window, 0);
|
||||
|
||||
account = TokenPosition::default();
|
||||
bank.change_without_fee(&mut account, I80F48::from(10), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(10), 0)
|
||||
.unwrap();
|
||||
bank.change_without_fee(&mut account, I80F48::from(-110), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-110), 0)
|
||||
.unwrap();
|
||||
assert_eq!(bank.net_borrows_in_window, 100);
|
||||
bank.change_without_fee(&mut account, I80F48::from(50), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(50), 0)
|
||||
.unwrap();
|
||||
assert_eq!(bank.net_borrows_in_window, 50);
|
||||
bank.change_without_fee(&mut account, I80F48::from(100), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(100), 0)
|
||||
.unwrap();
|
||||
assert_eq!(bank.net_borrows_in_window, 1); // rounding
|
||||
|
||||
account = TokenPosition::default();
|
||||
bank.net_borrows_in_window = 0;
|
||||
bank.change_without_fee(&mut account, I80F48::from(-450), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-450), 0)
|
||||
.unwrap();
|
||||
bank.change_without_fee(&mut account, I80F48::from(-51), 0, price)
|
||||
.unwrap_err();
|
||||
bank.change_without_fee(&mut account, I80F48::from(-51), 0)
|
||||
.unwrap();
|
||||
bank.check_net_borrows(price).unwrap_err();
|
||||
|
||||
account = TokenPosition::default();
|
||||
bank.net_borrows_in_window = 0;
|
||||
bank.change_without_fee(&mut account, I80F48::from(-450), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-450), 0)
|
||||
.unwrap();
|
||||
bank.change_without_fee(&mut account, I80F48::from(-50), 0, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-50), 0)
|
||||
.unwrap();
|
||||
bank.change_without_fee(&mut account, I80F48::from(-50), 101, price)
|
||||
bank.change_without_fee(&mut account, I80F48::from(-50), 101)
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -219,7 +219,11 @@ async fn test_bank_net_borrows_based_borrow_limit() -> Result<(), TransportError
|
|||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
assert_mango_error(
|
||||
&res,
|
||||
MangoError::BankNetBorrowsLimitReached.into(),
|
||||
"".into(),
|
||||
);
|
||||
|
||||
// succeeds because is not a borrow
|
||||
send_tx(
|
||||
|
@ -308,7 +312,26 @@ async fn test_bank_net_borrows_based_borrow_limit() -> Result<(), TransportError
|
|||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
assert_mango_error(
|
||||
&res,
|
||||
MangoError::BankNetBorrowsLimitReached.into(),
|
||||
"".into(),
|
||||
);
|
||||
|
||||
// can still withdraw
|
||||
send_tx(
|
||||
solana,
|
||||
TokenWithdrawInstruction {
|
||||
amount: 4000,
|
||||
allow_borrow: false,
|
||||
account: account_0,
|
||||
owner,
|
||||
token_account: payer_mint_accounts[0],
|
||||
bank_index: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
set_bank_stub_oracle_price(solana, group, &tokens[0], admin, 5.0).await;
|
||||
|
||||
|
@ -325,7 +348,11 @@ async fn test_bank_net_borrows_based_borrow_limit() -> Result<(), TransportError
|
|||
},
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
assert_mango_error(
|
||||
&res,
|
||||
MangoError::BankNetBorrowsLimitReached.into(),
|
||||
"".into(),
|
||||
);
|
||||
|
||||
// can borrow smaller amounts: (net borrowed 1000 + new borrow 199) * price 5.0 < limit 6000
|
||||
send_tx(
|
||||
|
|
|
@ -337,7 +337,8 @@ async fn test_perp_settle_fees() -> Result<(), TransportError> {
|
|||
max_settle_amount: u64::MAX,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
// No change
|
||||
{
|
||||
let perp_market = solana.get_account::<PerpMarket>(perp_market).await;
|
||||
|
|
Loading…
Reference in New Issue