Skip to content

Commit

Permalink
fix: ensure market position is paid out before closing
Browse files Browse the repository at this point in the history
This is just in case there is ever a bug that allows markets to achieve the
status of ReadyToClose but with market positions that haven't been paid out
yet. Unlikely unless there is a bug, so this is purely defensive.
  • Loading branch information
eoin-betdex committed Dec 21, 2023
1 parent a8e6bb0 commit 409b6e7
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
2 changes: 2 additions & 0 deletions programs/monaco_protocol/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ pub enum CoreError {
*/
#[msg("CloseAccount: Order not complete")]
CloseAccountOrderNotComplete,
#[msg("CloseAccount: MarketPosition not paid")]
CloseAccountMarketPositionNotPaid,
#[msg("CloseAccount: Purchaser does not match")]
CloseAccountPurchaserMismatch,
#[msg("CloseAccount: Payer does not match")]
Expand Down
55 changes: 55 additions & 0 deletions programs/monaco_protocol/src/instructions/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use anchor_lang::prelude::*;
use crate::error::CoreError;
use crate::state::market_account::MarketStatus::ReadyToClose;
use crate::state::market_account::{Market, MarketStatus};
use crate::state::market_position_account::MarketPosition;
use crate::state::order_account::Order;

pub fn close_market_child_account(market: &mut Market) -> Result<()> {
Expand All @@ -21,6 +22,14 @@ pub fn close_order(market: &mut Market, order: &Order) -> Result<()> {
close_market_child_account(market)
}

pub fn close_market_position(market: &mut Market, market_position: &MarketPosition) -> Result<()> {
require!(
market_position.paid,
CoreError::CloseAccountMarketPositionNotPaid
);
close_market_child_account(market)
}

pub fn close_market(
market_status: &MarketStatus,
payment_queue_len: u32,
Expand Down Expand Up @@ -99,6 +108,39 @@ mod tests {
assert_eq!(Err(error!(CoreError::CloseAccountOrderNotComplete)), result);
}

// close market_position validation

#[test]
fn test_close_market_position() {
let market = &mut test_market();
market.market_status = ReadyToClose;
market.unclosed_accounts_count = 1;

let market_position = &mut test_market_position();
market_position.paid = true;

assert!(close_market_position(market, market_position).is_ok());
assert_eq!(market.unclosed_accounts_count, 0);
}

#[test]
fn test_close_market_position_not_paid() {
let market = &mut test_market();
market.market_status = ReadyToClose;
market.unclosed_accounts_count = 1;

let market_position = &mut test_market_position();
market_position.paid = false;

let result = close_market_position(market, market_position);
assert!(result.is_err());
assert_eq!(
Err(error!(CoreError::CloseAccountMarketPositionNotPaid)),
result
);
assert_eq!(market.unclosed_accounts_count, 1);
}

// close market validation

#[test]
Expand Down Expand Up @@ -182,4 +224,17 @@ mod tests {
product_commission_rate: 0.0,
}
}

fn test_market_position() -> MarketPosition {
MarketPosition {
purchaser: Default::default(),
market: Default::default(),
paid: false,
market_outcome_sums: vec![],
unmatched_exposures: vec![],
payer: Default::default(),
matched_risk: 0,
matched_risk_per_product: vec![],
}
}
}
5 changes: 4 additions & 1 deletion programs/monaco_protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,10 @@ pub mod monaco_protocol {
}

pub fn close_market_position(ctx: Context<CloseMarketPosition>) -> Result<()> {
instructions::close::close_market_child_account(&mut ctx.accounts.market)
instructions::close::close_market_position(
&mut ctx.accounts.market,
&ctx.accounts.market_position,
)
}

pub fn close_market_matching_pool(ctx: Context<CloseMarketMatchingPool>) -> Result<()> {
Expand Down

0 comments on commit 409b6e7

Please sign in to comment.