liq_token_with_token: Correctly adjust health cache for dusting
Previously the health cache adjustments didn't take into account that positions between 0 and 1 native token would be dusted to 0. This makes a difference for valuable tokens with few decimals. For example 1 BTC-native token is currently worth 500k SOL-native tokens. That means 0.9 BTC-native would easily be enough collateral for a 10k SOL-native borrow -- but if the 0.9 get dusted, then the whole account is bankrupt instead.
This commit is contained in:
parent
3139b0816a
commit
e8479e2e7c
|
@ -85,8 +85,8 @@ pub fn liq_token_with_token(
|
|||
// The main complication here is that we can't keep the liqee_asset_position and liqee_liab_position
|
||||
// borrows alive at the same time. Possibly adding get_mut_pair() would be helpful.
|
||||
let (liqee_asset_position, liqee_asset_raw_index) = liqee.token_get(asset_token_index)?;
|
||||
let liqee_assets_native = liqee_asset_position.native(asset_bank);
|
||||
require!(liqee_assets_native.is_positive(), MangoError::SomeError);
|
||||
let liqee_asset_native = liqee_asset_position.native(asset_bank);
|
||||
require!(liqee_asset_native.is_positive(), MangoError::SomeError);
|
||||
|
||||
let (liqee_liab_position, liqee_liab_raw_index) = liqee.token_get(liab_token_index)?;
|
||||
let liqee_liab_native = liqee_liab_position.native(liab_bank);
|
||||
|
@ -115,7 +115,7 @@ pub fn liq_token_with_token(
|
|||
/ (liab_price * init_liab_weight - init_asset_weight * liab_price_adjusted));
|
||||
|
||||
// How much liab can we get at most for the asset balance?
|
||||
let liab_possible = cm!(liqee_assets_native * asset_price / liab_price_adjusted);
|
||||
let liab_possible = cm!(liqee_asset_native * asset_price / liab_price_adjusted);
|
||||
|
||||
// The amount of liab native tokens we will transfer
|
||||
let liab_transfer = min(
|
||||
|
@ -135,6 +135,7 @@ pub fn liq_token_with_token(
|
|||
liqor.token_get_mut_or_create(liab_token_index)?;
|
||||
let liqor_liab_active = liab_bank.withdraw_with_fee(liqor_liab_position, liab_transfer)?;
|
||||
let liqor_liab_position_indexed = liqor_liab_position.indexed_position;
|
||||
let liqee_liab_native_after = liqee_liab_position.native(&liab_bank);
|
||||
|
||||
let (liqor_asset_position, liqor_asset_raw_index, _) =
|
||||
liqor.token_get_mut_or_create(asset_token_index)?;
|
||||
|
@ -145,10 +146,17 @@ pub fn liq_token_with_token(
|
|||
let liqee_asset_active =
|
||||
asset_bank.withdraw_without_fee(liqee_asset_position, asset_transfer)?;
|
||||
let liqee_asset_position_indexed = liqee_asset_position.indexed_position;
|
||||
let liqee_assets_native_after = liqee_asset_position.native(&asset_bank);
|
||||
|
||||
// Update the health cache
|
||||
liqee_health_cache.adjust_token_balance(liab_token_index, liab_transfer)?;
|
||||
liqee_health_cache.adjust_token_balance(asset_token_index, -asset_transfer)?;
|
||||
liqee_health_cache.adjust_token_balance(
|
||||
liab_token_index,
|
||||
cm!(liqee_liab_native_after - liqee_liab_native),
|
||||
)?;
|
||||
liqee_health_cache.adjust_token_balance(
|
||||
asset_token_index,
|
||||
cm!(liqee_assets_native_after - liqee_asset_native),
|
||||
)?;
|
||||
|
||||
msg!(
|
||||
"liquidated {} liab for {} asset",
|
||||
|
|
|
@ -505,5 +505,73 @@ async fn test_liq_tokens_with_token() -> Result<(), TransportError> {
|
|||
assert!(!liqee.being_liquidated());
|
||||
assert!(!liqee.is_bankrupt());
|
||||
|
||||
//
|
||||
// TEST: bankruptcy when collateral is dusted
|
||||
//
|
||||
|
||||
// Setup: make collateral really valueable, remove nearly all of it
|
||||
send_tx(
|
||||
solana,
|
||||
StubOracleSetInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: collateral_token1.mint.pubkey,
|
||||
payer,
|
||||
price: "100000.0",
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
send_tx(
|
||||
solana,
|
||||
TokenWithdrawInstruction {
|
||||
amount: (account_position(solana, account, collateral_token1.bank).await) as u64 - 1,
|
||||
allow_borrow: false,
|
||||
account,
|
||||
owner,
|
||||
token_account: payer_mint_accounts[2],
|
||||
bank_index: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// Setup: reduce collateral value to trigger liquidatability
|
||||
// We have -93 borrows, so -93*2*1.4 = -260.4 health from that
|
||||
// And 1-2 collateral, so max 2*0.6*X health; say X=150 for max 180 health
|
||||
send_tx(
|
||||
solana,
|
||||
StubOracleSetInstruction {
|
||||
group,
|
||||
admin,
|
||||
mint: collateral_token1.mint.pubkey,
|
||||
payer,
|
||||
price: "150.0",
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
send_tx(
|
||||
solana,
|
||||
LiqTokenWithTokenInstruction {
|
||||
liqee: account,
|
||||
liqor: vault_account,
|
||||
liqor_owner: owner,
|
||||
asset_token_index: collateral_token1.index,
|
||||
liab_token_index: borrow_token1.index,
|
||||
max_liab_transfer: I80F48::from_num(10001.0),
|
||||
asset_bank_index: 0,
|
||||
liab_bank_index: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Liqee's remaining collateral got dusted, only borrows remain: bankrupt
|
||||
let liqee = get_mango_account(solana, account).await;
|
||||
assert_eq!(liqee.token_iter_active().count(), 1);
|
||||
assert!(liqee.is_bankrupt());
|
||||
assert!(liqee.being_liquidated());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue