From b4130dd31c023feeef309d53e3a2ecd8378d0f09 Mon Sep 17 00:00:00 2001 From: ellttBen Date: Mon, 25 Jul 2022 15:50:15 +0100 Subject: [PATCH 1/4] Prevent posting orders with a price less than the market's tick size --- program/src/processor/new_order.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/program/src/processor/new_order.rs b/program/src/processor/new_order.rs index 8611171..f6c0a2b 100644 --- a/program/src/processor/new_order.rs +++ b/program/src/processor/new_order.rs @@ -133,6 +133,13 @@ where return Err(AoError::InvalidLimitPrice.into()); } + if params.post_allowed && params.limit_price < market_state.tick_size { + msg!( + "Can't attempt to post an order of price less than market tick size to the orderbook!" + ); + return Err(AoError::InvalidLimitPrice.into()); + } + let mut bids_guard = accounts.bids.data.borrow_mut(); let mut asks_guard = accounts.asks.data.borrow_mut(); From 4a77b779e64e13e78ee49f13e1da7f2a2607fe63 Mon Sep 17 00:00:00 2001 From: ellttBen Date: Thu, 21 Jul 2022 12:01:02 +0100 Subject: [PATCH 2/4] v0.1.3 --- js/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/package.json b/js/package.json index 9703856..bd9af8e 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "@bonfida/aaob", - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "repository": { "type": "git" @@ -49,4 +49,4 @@ "borsh": "^0.6.0", "bs58": "4.0.1" } -} \ No newline at end of file +} From 7247830cec05220d0e5ece52e30ae607a3c2fe91 Mon Sep 17 00:00:00 2001 From: ellttBen Date: Tue, 26 Jul 2022 16:46:34 +0100 Subject: [PATCH 3/4] Switch to safer rounding --- program/Cargo.lock | 10 +++++----- program/Cargo.toml | 2 +- program/src/processor/cancel_order.rs | 6 +++--- program/src/processor/mass_cancel_orders.rs | 4 ++-- program/src/state/orderbook.rs | 16 +++++++++++----- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/program/Cargo.lock b/program/Cargo.lock index bdacd8f..b7d6a20 100644 --- a/program/Cargo.lock +++ b/program/Cargo.lock @@ -273,8 +273,7 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bonfida-macros" version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5560c4eb64bcc9c0eb4ad3975155c30cb353a898299dcc47c5400bf7e21c60ff" +source = "git+https://github.com/Bonfida/bonfida-utils.git?branch=add-rounding-direction#f24f508be40c541a463e308c4dbe05de13b97a5d" dependencies = [ "proc-macro2 1.0.38", "quote 1.0.18", @@ -284,18 +283,19 @@ dependencies = [ [[package]] name = "bonfida-utils" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de55392939054ec60454e98ad8befaadd58aea49027021c2f88ca5dd168695e" +version = "0.3.0" +source = "git+https://github.com/Bonfida/bonfida-utils.git?branch=add-rounding-direction#f24f508be40c541a463e308c4dbe05de13b97a5d" dependencies = [ "bonfida-macros", "borsh", + "bytemuck", "lazy_static", "pyth-sdk-solana", "regex", "serde", "serde_json", "solana-program", + "spl-token", ] [[package]] diff --git a/program/Cargo.toml b/program/Cargo.toml index d1e5b42..1e8a208 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -25,7 +25,7 @@ num-traits = "0.2" num-derive = "0.3" enumflags2 = "0.7.1" spl-token = {version="3.2.0", features= ["no-entrypoint"]} -bonfida-utils = "0.2.11" +bonfida-utils = {git = "https://github.com/Bonfida/bonfida-utils.git", branch = "add-rounding-direction"} [dev-dependencies] hexdump = "0.1.0" diff --git a/program/src/processor/cancel_order.rs b/program/src/processor/cancel_order.rs index 2e8010c..a42e5dc 100644 --- a/program/src/processor/cancel_order.rs +++ b/program/src/processor/cancel_order.rs @@ -1,6 +1,6 @@ //! Cancel an existing order in the orderbook. -use bonfida_utils::fp_math::fp32_mul; +use bonfida_utils::fp_math::fp32_mul_floor; use bonfida_utils::{BorshSize, InstructionsAccount}; use borsh::{BorshDeserialize, BorshSerialize}; use bytemuck::Pod; @@ -97,8 +97,8 @@ where .remove_by_key(params.order_id) .ok_or(AoError::OrderNotFound)?; let total_base_qty = leaf_node.base_quantity; - let total_quote_qty = - fp32_mul(leaf_node.base_quantity, leaf_node.price()).ok_or(AoError::NumericalOverflow)?; + let total_quote_qty = fp32_mul_floor(leaf_node.base_quantity, leaf_node.price()) + .ok_or(AoError::NumericalOverflow)?; let order_summary = OrderSummary { posted_order_id: None, diff --git a/program/src/processor/mass_cancel_orders.rs b/program/src/processor/mass_cancel_orders.rs index ace16b1..1faee75 100644 --- a/program/src/processor/mass_cancel_orders.rs +++ b/program/src/processor/mass_cancel_orders.rs @@ -1,6 +1,6 @@ //! Cancel a series of existing orders in the orderbook. -use bonfida_utils::{fp_math::fp32_mul, BorshSize, InstructionsAccount}; +use bonfida_utils::{fp_math::fp32_mul_floor, BorshSize, InstructionsAccount}; use borsh::{BorshDeserialize, BorshSerialize}; use bytemuck::Pod; use solana_program::{ @@ -101,7 +101,7 @@ where let slab = order_book.get_tree(get_side_from_order_id(order_id)); let (leaf_node, _) = slab.remove_by_key(order_id).ok_or(AoError::OrderNotFound)?; total_base_qty = total_base_qty.checked_add(leaf_node.base_quantity).unwrap(); - total_quote_qty = fp32_mul(leaf_node.base_quantity, leaf_node.price()) + total_quote_qty = fp32_mul_floor(leaf_node.base_quantity, leaf_node.price()) .and_then(|n| n.checked_add(total_quote_qty)) .unwrap(); } diff --git a/program/src/state/orderbook.rs b/program/src/state/orderbook.rs index 941706f..69cc9d3 100644 --- a/program/src/state/orderbook.rs +++ b/program/src/state/orderbook.rs @@ -12,7 +12,7 @@ use crate::{ AccountTag, SelfTradeBehavior, Side, }, }; -use bonfida_utils::fp_math::{fp32_div, fp32_mul}; +use bonfida_utils::fp_math::{fp32_div, fp32_mul_ceil, fp32_mul_floor}; use borsh::{BorshDeserialize, BorshSerialize}; use bytemuck::Pod; use solana_program::{msg, program_error::ProgramError}; @@ -169,8 +169,11 @@ where break; } - let quote_maker_qty = - fp32_mul(base_trade_qty, trade_price).ok_or(AoError::NumericalOverflow)?; + let quote_maker_qty = match side { + Side::Bid => fp32_mul_ceil(base_trade_qty, trade_price), + Side::Ask => fp32_mul_floor(base_trade_qty, trade_price), + } + .ok_or(AoError::NumericalOverflow)?; if quote_maker_qty == 0 { break; @@ -312,8 +315,11 @@ where }; *self.get_tree(side).get_callback_info_mut(k) = callback_info; base_qty_remaining -= base_qty_to_post; - quote_qty_remaining -= - fp32_mul(base_qty_to_post, limit_price).ok_or(AoError::NumericalOverflow)?; + quote_qty_remaining -= match side { + Side::Bid => fp32_mul_ceil(base_qty_to_post, limit_price), + Side::Ask => fp32_mul_floor(base_qty_to_post, limit_price), + } + .ok_or(AoError::NumericalOverflow)?; Ok(OrderSummary { posted_order_id: Some(new_leaf_order_id), total_base_qty: max_base_qty - base_qty_remaining, From 7bf8e5021f7e6d0514e39149165a2cc298d079be Mon Sep 17 00:00:00 2001 From: ellttBen Date: Wed, 27 Jul 2022 12:00:20 +0100 Subject: [PATCH 4/4] Fix potential underflow for Bid taker side matching --- program/src/state/orderbook.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/program/src/state/orderbook.rs b/program/src/state/orderbook.rs index 69cc9d3..0e81cdf 100644 --- a/program/src/state/orderbook.rs +++ b/program/src/state/orderbook.rs @@ -173,6 +173,7 @@ where Side::Bid => fp32_mul_ceil(base_trade_qty, trade_price), Side::Ask => fp32_mul_floor(base_trade_qty, trade_price), } + .map(|q| std::cmp::min(q, quote_qty_remaining)) .ok_or(AoError::NumericalOverflow)?; if quote_maker_qty == 0 {