Allow serum/perp order force cancelling on frozen accounts (#374)

This commit is contained in:
Christian Kamm 2023-01-13 08:13:15 +01:00 committed by GitHub
parent 4f0b4da26d
commit 5227daa0b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 83 deletions

View File

@ -71,24 +71,8 @@ pub fn perp_liq_base_position(
let liqee_init_health = liqee_health_cache.health(HealthType::Init);
liqee_health_cache.require_after_phase1_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating,
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee
.fixed
.maybe_recover_from_being_liquidated(liqee_init_health)
{
msg!("Liqee init_health above zero");
return Ok(());
}
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
if !liqee.check_liquidatable(&liqee_health_cache)? {
return Ok(());
}
let mut perp_market = ctx.accounts.perp_market.load_mut()?;

View File

@ -1,5 +1,4 @@
use anchor_lang::prelude::*;
use fixed::types::I80F48;
use crate::error::*;
use crate::health::*;
@ -47,22 +46,20 @@ pub fn perp_liq_force_cancel_orders(
let health_cache =
new_health_cache(&account.borrow(), &retriever).context("create health cache")?;
if account.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if account
.fixed
.maybe_recover_from_being_liquidated(init_health)
{
msg!("Liqee init_health above zero");
return Ok(());
{
let result = account.check_liquidatable(&health_cache);
if account.fixed.is_operational() {
if !result? {
return Ok(());
}
} else {
// Frozen accounts can always have their orders cancelled
if let Err(Error::AnchorError(ref inner)) = result {
if inner.error_code_number != MangoError::HealthMustBeNegative as u32 {
result?;
}
}
}
} else {
let maint_health = health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
account.fixed.set_being_liquidated(true);
}
health_cache

View File

@ -118,24 +118,8 @@ pub fn perp_liq_quote_and_bankruptcy(
let liqee_settle_health = liqee_health_cache.perp_settle_health();
liqee_health_cache.require_after_phase2_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating,
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee
.fixed
.maybe_recover_from_being_liquidated(liqee_init_health)
{
msg!("Liqee init_health above zero");
return Ok(());
}
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
if !liqee.check_liquidatable(&liqee_health_cache)? {
return Ok(());
}
// check positions exist/create them, done early for nicer error messages

View File

@ -1,6 +1,5 @@
use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount};
use fixed::types::I80F48;
use crate::error::*;
use crate::health::*;
@ -126,22 +125,21 @@ pub fn serum3_liq_force_cancel_orders(
let health_cache =
new_health_cache(&account.borrow(), &retriever).context("create health cache")?;
if account.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if account
.fixed
.maybe_recover_from_being_liquidated(init_health)
{
msg!("Liqee init_health above zero");
return Ok(());
{
let result = account.check_liquidatable(&health_cache);
if account.fixed.is_operational() {
if !result? {
return Ok(());
}
} else {
// Frozen accounts can always have their orders cancelled
if let Err(Error::AnchorError(ref inner)) = result {
if inner.error_code_number != MangoError::HealthMustBeNegative as u32 {
// propagate all unexpected errors
result?;
}
}
}
} else {
let maint_health = health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
account.fixed.set_being_liquidated(true);
}
health_cache

View File

@ -69,21 +69,8 @@ pub fn token_liq_with_token(
let init_health = liqee_health_cache.health(HealthType::Init);
liqee_health_cache.require_after_phase1_liquidation()?;
// Once maint_health falls below 0, we want to start liquidating,
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if liqee.being_liquidated() {
if liqee.fixed.maybe_recover_from_being_liquidated(init_health) {
msg!("Liqee init_health above zero");
return Ok(());
}
} else {
let maint_health = liqee_health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
liqee.fixed.set_being_liquidated(true);
if !liqee.check_liquidatable(&liqee_health_cache)? {
return Ok(());
}
//

View File

@ -968,6 +968,30 @@ impl<
Ok(())
}
pub fn check_liquidatable(&mut self, health_cache: &HealthCache) -> Result<bool> {
// Once maint_health falls below 0, we want to start liquidating,
// we want to allow liquidation to continue until init_health is positive,
// to prevent constant oscillation between the two states
if self.being_liquidated() {
let init_health = health_cache.health(HealthType::Init);
if self
.fixed_mut()
.maybe_recover_from_being_liquidated(init_health)
{
msg!("Liqee init_health above zero");
return Ok(false);
}
} else {
let maint_health = health_cache.health(HealthType::Maint);
require!(
maint_health < I80F48::ZERO,
MangoError::HealthMustBeNegative
);
self.fixed_mut().set_being_liquidated(true);
}
Ok(true)
}
// writes length of tokens vec at appropriate offset so that borsh can infer the vector length
// length used is that present in the header
fn write_token_length(&mut self) {