Skip to content

Commit

Permalink
implement perp purge position
Browse files Browse the repository at this point in the history
  • Loading branch information
mschneider committed Nov 21, 2024
1 parent 3f3eca0 commit 243e51a
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
2 changes: 2 additions & 0 deletions programs/mango-v4/src/accounts_ix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub use perp_liq_force_cancel_orders::*;
pub use perp_liq_negative_pnl_or_bankruptcy::*;
pub use perp_place_order::*;
pub use perp_prune_orders::*;
pub use perp_purge_position::*;
pub use perp_settle_fees::*;
pub use perp_settle_pnl::*;
pub use perp_update_funding::*;
Expand Down Expand Up @@ -127,6 +128,7 @@ mod perp_liq_force_cancel_orders;
mod perp_liq_negative_pnl_or_bankruptcy;
mod perp_place_order;
mod perp_prune_orders;
mod perp_purge_position;
mod perp_settle_fees;
mod perp_settle_pnl;
mod perp_update_funding;
Expand Down
27 changes: 27 additions & 0 deletions programs/mango-v4/src/accounts_ix/perp_purge_position.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use anchor_lang::prelude::*;

use crate::error::*;
use crate::state::*;

#[derive(Accounts)]
pub struct PerpPurgePosition<'info> {
#[account()]
pub group: AccountLoader<'info, Group>,

#[account(
mut,
has_one = group,
// owner is not checked on purpose
)]
pub account: AccountLoader<'info, MangoAccountFixed>,

#[account(has_one = group)]
pub perp_market: AccountLoader<'info, PerpMarket>,

#[account(mut, has_one = group)]
pub settle_bank: AccountLoader<'info, Bank>,

/// CHECK: Oracle can have different account types
#[account(address = settle_bank.load()?.oracle)]
pub settle_oracle: UncheckedAccount<'info>,
}
2 changes: 2 additions & 0 deletions programs/mango-v4/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub use perp_liq_force_cancel_orders::*;
pub use perp_liq_negative_pnl_or_bankruptcy::*;
pub use perp_place_order::*;
pub use perp_prune_orders::*;
pub use perp_purge_position::*;
pub use perp_settle_fees::*;
pub use perp_settle_pnl::*;
pub use perp_update_funding::*;
Expand Down Expand Up @@ -108,6 +109,7 @@ mod perp_liq_force_cancel_orders;
mod perp_liq_negative_pnl_or_bankruptcy;
mod perp_place_order;
mod perp_prune_orders;
mod perp_purge_position;
mod perp_settle_fees;
mod perp_settle_pnl;
mod perp_update_funding;
Expand Down
93 changes: 93 additions & 0 deletions programs/mango-v4/src/instructions/perp_purge_position.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use anchor_lang::prelude::*;
use fixed::types::I80F48;

use crate::accounts_ix::*;
use crate::error::*;
use crate::logs::emit_perp_balances;
use crate::logs::emit_stack;
use crate::logs::TokenBalanceLog;
use crate::require_msg;
use crate::state::*;

pub fn perp_purge_position(ctx: Context<PerpPurgePosition>) -> Result<()> {
let perp_market = ctx.accounts.perp_market.load()?;
// only allow purging positions when market is in force-close
require!(perp_market.is_force_close(), MangoError::SomeError);

let mut settle_bank = ctx.accounts.settle_bank.load_mut()?;
// Verify that the bank is the quote currency bank
require!(
settle_bank.token_index == perp_market.settle_token_index,
MangoError::InvalidBank
);

let mut account = ctx.accounts.account.load_full_mut()?;
let perp_position = account.perp_position_mut(perp_market.perp_market_index)?;

// Base position needs to be zero'd out already and all orders closed
require_msg!(
perp_position.base_position_lots() == 0,
"perp position still has base lots"
);
require_msg!(
perp_position.bids_base_lots == 0 && perp_position.asks_base_lots == 0,
"perp position still has open orders"
);
require_msg!(
perp_position.taker_base_lots == 0 && perp_position.taker_quote_lots == 0,
"perp position still has events on event queue"
);

// Flush funding so that all remaining quote position is accounted for
perp_position.settle_funding(&perp_market);
let settlement = -perp_position.quote_position_native();

// only if there's negative pnl we settle directly with bank
// note: the positive pnl case is not implemented
if settlement != 0 {
require_msg!(
settlement > I80F48::ZERO,
"can only purge negative quote positions"
);

// Set perp quote to 0
perp_position.record_settle(settlement, &perp_market);
emit_perp_balances(
ctx.accounts.group.key(),
ctx.accounts.account.key(),
perp_position,
&perp_market,
);

// Update the accounts' perp_spot_transfer statistics.
let settlement_i64 = settlement.round_to_zero().to_num::<i64>();
perp_position.perp_spot_transfers += settlement_i64;
drop(perp_position);
account.fixed.perp_spot_transfers += settlement_i64;

// Settle quote token balance
let token_position = account
.token_position_mut(perp_market.settle_token_index)?
.0;
let now_ts: u64 = Clock::get()?.unix_timestamp.try_into().unwrap();
settle_bank.withdraw_without_fee(token_position, settlement, now_ts)?;

emit_stack(TokenBalanceLog {
mango_group: ctx.accounts.group.key(),
mango_account: ctx.accounts.account.key(),
token_index: perp_market.settle_token_index,
indexed_position: token_position.indexed_position.to_bits(),
deposit_index: settle_bank.deposit_index.to_bits(),
borrow_index: settle_bank.borrow_index.to_bits(),
});
}

// clean up perp position to free up oracles for users and allow closing market
account.deactivate_perp_position_and_log(
perp_market.perp_market_index,
perp_market.settle_token_index,
ctx.accounts.account.key(),
)?;

Ok(())
}
6 changes: 6 additions & 0 deletions programs/mango-v4/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,12 @@ pub mod mango_v4 {
Ok(())
}

pub fn perp_purge_position(ctx: Context<PerpPurgePosition>) -> Result<()> {
#[cfg(feature = "enable-gpl")]
instructions::perp_purge_position(ctx)?;
Ok(())
}

#[allow(clippy::too_many_arguments)]
pub fn perp_place_order(
ctx: Context<PerpPlaceOrder>,
Expand Down

0 comments on commit 243e51a

Please sign in to comment.