diff --git a/programs/manifest/rules.json b/programs/manifest/rules.json index c0b3956e3..8e19c5947 100644 --- a/programs/manifest/rules.json +++ b/programs/manifest/rules.json @@ -60,6 +60,12 @@ "prover_options": [], "cargo_features": [] }, + { + "name": "rule_cancel_order_by_index_bid", + "expected_result": "Verified", + "prover_options": [], + "cargo_features": [] + }, { "name": "rule_cancel_order_by_index_ask", "expected_result": "Verified", diff --git a/programs/manifest/src/state/market.rs b/programs/manifest/src/state/market.rs index 62d2c57b9..0666d5ac5 100644 --- a/programs/manifest/src/state/market.rs +++ b/programs/manifest/src/state/market.rs @@ -1362,10 +1362,13 @@ impl< let resting_order: &RestingOrder = get_helper_order(dynamic, order_index).get_value(); let is_bid: bool = resting_order.get_is_bid(); + + // Important to round up because there was an extra atom taken for full + // taker rounding when the order was placed. let amount_atoms: u64 = if is_bid { (resting_order .get_price() - .checked_quote_for_base(resting_order.get_num_base_atoms(), false) + .checked_quote_for_base(resting_order.get_num_base_atoms(), true) .unwrap()) .into() } else { diff --git a/programs/manifest/tests/cases/cancel_order.rs b/programs/manifest/tests/cases/cancel_order.rs index a47488a6c..d9b29ab8f 100644 --- a/programs/manifest/tests/cases/cancel_order.rs +++ b/programs/manifest/tests/cases/cancel_order.rs @@ -42,6 +42,28 @@ async fn cancel_order_bid_test() -> anyhow::Result<()> { Ok(()) } +// This test failed when the rounding on cancel was incorrect. Now it passes. It +// shows that all funds are retrievable. +#[tokio::test] +async fn cancel_order_rounding_test() -> anyhow::Result<()> { + let mut test_fixture: TestFixture = TestFixture::new().await; + test_fixture.claim_seat().await?; + test_fixture + .deposit(Token::USDC, 2 * USDC_UNIT_SIZE) + .await?; + + test_fixture + .place_order(Side::Bid, 1, 11, -1, u32::MAX, OrderType::Limit) + .await?; + + test_fixture.cancel_order(0).await?; + test_fixture + .withdraw(Token::USDC, 2 * USDC_UNIT_SIZE) + .await?; + + Ok(()) +} + #[tokio::test] async fn cancel_order_fail_other_trader_order_test() -> anyhow::Result<()> { let mut test_fixture: TestFixture = TestFixture::new().await;