diff --git a/programs/mango-v4/src/instructions/flash_loan.rs b/programs/mango-v4/src/instructions/flash_loan.rs index d7f912f87..7c9dc8c2d 100644 --- a/programs/mango-v4/src/instructions/flash_loan.rs +++ b/programs/mango-v4/src/instructions/flash_loan.rs @@ -225,11 +225,12 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>( })?; let vaults_index = remaining_len - 2 * vaults_len - 1; - // First initialize to the remaining delegated amount let health_ais = &ctx.remaining_accounts[..vaults_index]; let vaults = &ctx.remaining_accounts[vaults_index..vaults_index + vaults_len]; let token_accounts = &ctx.remaining_accounts[vaults_index + vaults_len..vaults_index + 2 * vaults_len]; + + // Verify that each mentioned vault has a bank in the health accounts let mut vaults_with_banks = vec![false; vaults.len()]; // Loop over the banks, finding matching vaults @@ -313,13 +314,9 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>( ); } - // Check pre-cpi health - // NOTE: This health check isn't strictly necessary. It will be, later, when - // we want to have reduce_only or be able to move an account out of bankruptcy. + // Check health before balance adjustments let retriever = new_fixed_order_account_retriever(health_ais, &account.borrow())?; - let pre_cpi_health = compute_health(&account.borrow(), HealthType::Init, &retriever)?; - require!(pre_cpi_health >= 0, MangoError::HealthMustBePositive); - msg!("pre_cpi_health {:?}", pre_cpi_health); + let _pre_health = compute_health(&account.borrow(), HealthType::Init, &retriever)?; // Prices for logging let mut prices = vec![]; @@ -390,11 +387,14 @@ pub fn flash_loan_end<'key, 'accounts, 'remaining, 'info>( token_loan_details }); - // Check post-cpi health - let post_cpi_health = + // Check health after account position changes + let post_health = compute_health_from_fixed_accounts(&account.borrow(), HealthType::Init, health_ais)?; - require!(post_cpi_health >= 0, MangoError::HealthMustBePositive); - msg!("post_cpi_health {:?}", post_cpi_health); + msg!("post_cpi_health {:?}", post_health); + require!(post_health >= 0, MangoError::HealthMustBePositive); + account + .fixed + .maybe_recover_from_being_liquidated(post_health); // Deactivate inactive token accounts after health check for raw_token_index in deactivated_token_positions { diff --git a/programs/mango-v4/src/instructions/perp_place_order.rs b/programs/mango-v4/src/instructions/perp_place_order.rs index b66257e73..3602fe30a 100644 --- a/programs/mango-v4/src/instructions/perp_place_order.rs +++ b/programs/mango-v4/src/instructions/perp_place_order.rs @@ -136,6 +136,7 @@ pub fn perp_place_order( let health = compute_health(&account.borrow(), HealthType::Init, &retriever)?; msg!("health: {}", health); require!(health >= 0, MangoError::HealthMustBePositive); + account.fixed.maybe_recover_from_being_liquidated(health); Ok(()) } diff --git a/programs/mango-v4/src/instructions/serum3_place_order.rs b/programs/mango-v4/src/instructions/serum3_place_order.rs index 3b33a3224..242f223c7 100644 --- a/programs/mango-v4/src/instructions/serum3_place_order.rs +++ b/programs/mango-v4/src/instructions/serum3_place_order.rs @@ -294,6 +294,7 @@ pub fn serum3_place_order( let health = compute_health(&account.borrow(), HealthType::Init, &retriever)?; msg!("health: {}", health); require!(health >= 0, MangoError::HealthMustBePositive); + account.fixed.maybe_recover_from_being_liquidated(health); vault_difference_result.deactivate_inactive_token_accounts(&mut account.borrow_mut()); diff --git a/programs/mango-v4/src/instructions/token_withdraw.rs b/programs/mango-v4/src/instructions/token_withdraw.rs index 2d25dcbd4..e7b162427 100644 --- a/programs/mango-v4/src/instructions/token_withdraw.rs +++ b/programs/mango-v4/src/instructions/token_withdraw.rs @@ -136,6 +136,7 @@ pub fn token_withdraw(ctx: Context, amount: u64, allow_borrow: bo .context("post-withdraw init health")?; msg!("health: {}", health); require!(health >= 0, MangoError::HealthMustBePositive); + account.fixed.maybe_recover_from_being_liquidated(health); // // Deactivate the position only after the health check because the user passed in diff --git a/programs/mango-v4/src/state/mango_account.rs b/programs/mango-v4/src/state/mango_account.rs index e355039ba..2c84deb44 100644 --- a/programs/mango-v4/src/state/mango_account.rs +++ b/programs/mango-v4/src/state/mango_account.rs @@ -51,7 +51,11 @@ pub struct MangoAccount { pub account_num: u8, - /// This account cannot open new positions or borrow until `init_health >= 0` + /// Tracks that this account should be liquidated until init_health >= 0. + /// + /// Normally accounts can not be liquidated while maint_health >= 0. But when an account + /// reaches maint_health < 0, liquidators will call a liquidation instruction and thereby + /// set this flag. Now the account may be liquidated until init_health >= 0. being_liquidated: u8, padding5: u8,