Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cancel_all_and_place_orders #204

Merged
merged 6 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions programs/openbook-v2/fuzz/fuzz_targets/multiple_orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl FuzzData {
FuzzInstruction::PlaceOrder { .. }
| FuzzInstruction::PlaceOrderPegged { .. }
| FuzzInstruction::PlaceTakeOrder { .. }
| FuzzInstruction::CancelAndPlaceOrders { .. }
| FuzzInstruction::CancelAllAndPlaceOrders { .. }
)
})
}
Expand Down Expand Up @@ -73,9 +73,9 @@ enum FuzzInstruction {
data: openbook_v2::instruction::EditOrderPegged,
makers: Option<HashSet<UserId>>,
},
CancelAndPlaceOrders {
CancelAllAndPlaceOrders {
user_id: UserId,
data: openbook_v2::instruction::CancelAndPlaceOrders,
data: openbook_v2::instruction::CancelAllAndPlaceOrders,
makers: Option<HashSet<UserId>>,
},
CancelOrder {
Expand Down Expand Up @@ -171,13 +171,13 @@ impl FuzzRunner for FuzzContext {
.edit_order_pegged(user_id, data, makers.as_ref())
.map_or_else(error_parser::edit_order_pegged, keep),

FuzzInstruction::CancelAndPlaceOrders {
FuzzInstruction::CancelAllAndPlaceOrders {
user_id,
data,
makers,
} => self
.cancel_and_place_orders(user_id, data, makers.as_ref())
.map_or_else(error_parser::cancel_and_place_orders, keep),
.cancel_all_and_place_orders(user_id, data, makers.as_ref())
.map_or_else(error_parser::cancel_all_and_place_orders, keep),

FuzzInstruction::CancelOrder { user_id, data } => self
.cancel_order(user_id, data)
Expand Down Expand Up @@ -534,7 +534,7 @@ mod error_parser {
}
}

pub fn cancel_and_place_orders(err: ProgramError) -> Corpus {
pub fn cancel_all_and_place_orders(err: ProgramError) -> Corpus {
match err {
e if e == OpenBookError::InvalidInputLots.into() => Corpus::Reject,
e if e == OpenBookError::InvalidInputLotsSize.into() => Corpus::Reject,
Expand Down
6 changes: 3 additions & 3 deletions programs/openbook-v2/fuzz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,15 +603,15 @@ impl FuzzContext {
process_instruction(&mut self.state, data, &accounts, &remaining)
}

pub fn cancel_and_place_orders(
pub fn cancel_all_and_place_orders(
&mut self,
user_id: &UserId,
data: &openbook_v2::instruction::CancelAndPlaceOrders,
data: &openbook_v2::instruction::CancelAllAndPlaceOrders,
makers: Option<&HashSet<UserId>>,
) -> ProgramResult {
let user = self.get_or_create_new_user(user_id);

let accounts = openbook_v2::accounts::CancelAndPlaceOrders {
let accounts = openbook_v2::accounts::CancelAllAndPlaceOrders {
open_orders_account: user.open_orders,
signer: user.owner,
user_base_account: user.base_vault,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use anchor_lang::prelude::*;
use anchor_spl::token::{Token, TokenAccount};

#[derive(Accounts)]
pub struct CancelAndPlaceOrders<'info> {
pub struct CancelAllAndPlaceOrders<'info> {
pub signer: Signer<'info>,
#[account(
mut,
Expand Down
4 changes: 2 additions & 2 deletions programs/openbook-v2/src/accounts_ix/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub use cancel_and_place_orders::*;
pub use cancel_all_and_place_orders::*;
pub use cancel_order::*;
pub use close_market::*;
pub use close_open_orders_account::*;
Expand All @@ -20,7 +20,7 @@ pub use stub_oracle_create::*;
pub use stub_oracle_set::*;
pub use sweep_fees::*;

mod cancel_and_place_orders;
mod cancel_all_and_place_orders;
mod cancel_order;
mod close_market;
mod close_open_orders_account;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ use crate::state::*;
use crate::token_utils::*;

#[allow(clippy::too_many_arguments)]
pub fn cancel_and_place_orders(
ctx: Context<CancelAndPlaceOrders>,
cancel_client_orders_ids: Vec<u64>,
pub fn cancel_all_and_place_orders(
ctx: Context<CancelAllAndPlaceOrders>,
mut orders: Vec<Order>,
limits: Vec<u8>,
limit: u8,
) -> Result<Vec<Option<u128>>> {
let mut open_orders_account = ctx.accounts.open_orders_account.load_mut()?;
let open_orders_account_pk = ctx.accounts.open_orders_account.key();
Expand Down Expand Up @@ -40,31 +39,13 @@ pub fn cancel_and_place_orders(
clock.slot,
)?;

for client_order_id in cancel_client_orders_ids {
let oo = open_orders_account.find_order_with_client_order_id(client_order_id);
if let Some(oo) = oo {
let order_id = oo.id;
let order_side_and_tree = oo.side_and_tree();

let cancel_result = book.cancel_order(
&mut open_orders_account,
order_id,
order_side_and_tree,
*market,
Some(ctx.accounts.open_orders_account.key()),
);
// Allow cancel fails due order ID not found. Otherwise propagates error
if !cancel_result.is_anchor_error_with_code(OpenBookError::OrderIdNotFound.into()) {
cancel_result?;
}
};
}
book.cancel_all_orders(&mut open_orders_account, *market, u8::MAX, None)?;

let mut base_amount = 0_u64;
let mut quote_amount = 0_u64;
let mut order_ids = Vec::new();
for (order, limit) in orders.iter_mut().zip(limits) {
require_gte!(order.max_base_lots, 0, OpenBookError::InvalidInputLots);
for order in orders.iter_mut() {
order.max_base_lots = market.max_base_lots();
require_gte!(
order.max_quote_lots_including_fees,
0,
Expand Down
4 changes: 2 additions & 2 deletions programs/openbook-v2/src/instructions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub use cancel_all_and_place_orders::*;
pub use cancel_all_orders::*;
pub use cancel_and_place_orders::*;
pub use cancel_order::*;
pub use cancel_order_by_client_order_id::*;
pub use close_market::*;
Expand All @@ -23,8 +23,8 @@ pub use stub_oracle_create::*;
pub use stub_oracle_set::*;
pub use sweep_fees::*;

mod cancel_all_and_place_orders;
mod cancel_all_orders;
mod cancel_and_place_orders;
mod cancel_order;
mod cancel_order_by_client_order_id;
mod close_market;
Expand Down
62 changes: 32 additions & 30 deletions programs/openbook-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,54 +257,48 @@ pub mod openbook_v2 {
}

/// Cancel orders and place multiple orders.
pub fn cancel_and_place_orders(
ctx: Context<CancelAndPlaceOrders>,
cancel_client_orders_ids: Vec<u64>,
place_orders: Vec<PlaceOrderArgs>,
pub fn cancel_all_and_place_orders(
ctx: Context<CancelAllAndPlaceOrders>,
orders_type: PlaceOrderType,
bids: Vec<PlaceMultipleOrdersArgs>,
asks: Vec<PlaceMultipleOrdersArgs>,
limit: u8,
) -> Result<Vec<Option<u128>>> {
let mut orders = Vec::new();
let mut limits = Vec::new();
for place_order in place_orders.iter() {
require_gte!(
place_order.price_lots,
1,
OpenBookError::InvalidInputPriceLots
);

let time_in_force = match Order::tif_from_expiry(place_order.expiry_timestamp) {
let n_bids = bids.len();

let mut orders = vec![];
for (i, order) in bids.into_iter().chain(asks).enumerate() {
require_gte!(order.price_lots, 1, OpenBookError::InvalidInputPriceLots);

let time_in_force = match Order::tif_from_expiry(order.expiry_timestamp) {
Some(t) => t,
None => {
msg!("Order is already expired");
continue;
}
};
orders.push(Order {
side: place_order.side,
max_base_lots: place_order.max_base_lots,
max_quote_lots_including_fees: place_order.max_quote_lots_including_fees,
client_order_id: place_order.client_order_id,
side: if i < n_bids { Side::Bid } else { Side::Ask },
max_base_lots: i64::MIN, // this will be overriden to max_base_lots
max_quote_lots_including_fees: order.max_quote_lots_including_fees,
client_order_id: i as u64,
time_in_force,
self_trade_behavior: place_order.self_trade_behavior,
params: match place_order.order_type {
self_trade_behavior: SelfTradeBehavior::CancelProvide,
params: match orders_type {
PlaceOrderType::Market => OrderParams::Market,
PlaceOrderType::ImmediateOrCancel => OrderParams::ImmediateOrCancel {
price_lots: place_order.price_lots,
price_lots: order.price_lots,
},
_ => OrderParams::Fixed {
price_lots: place_order.price_lots,
order_type: place_order.order_type.to_post_order_type()?,
price_lots: order.price_lots,
order_type: orders_type.to_post_order_type()?,
},
},
});
limits.push(place_order.limit);
}

#[cfg(feature = "enable-gpl")]
return instructions::cancel_and_place_orders(
ctx,
cancel_client_orders_ids,
orders,
limits,
);
return instructions::cancel_all_and_place_orders(ctx, orders, limit);

#[cfg(not(feature = "enable-gpl"))]
Ok(vec![])
Expand Down Expand Up @@ -573,6 +567,14 @@ pub struct PlaceOrderArgs {
pub limit: u8,
}

#[derive(AnchorSerialize, AnchorDeserialize, Debug, Copy, Clone)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct PlaceMultipleOrdersArgs {
pub price_lots: i64,
pub max_quote_lots_including_fees: i64,
pub expiry_timestamp: u64,
}

#[derive(AnchorSerialize, AnchorDeserialize, Debug, Copy, Clone)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
pub struct PlaceOrderPeggedArgs {
Expand Down
60 changes: 17 additions & 43 deletions programs/openbook-v2/tests/cases/test_multiple_orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ use super::*;

#[tokio::test]
async fn insufficient_funds() -> Result<(), TransportError> {
let base_lot_size = 100;
let quote_lot_size = 10;

let TestInitialize {
context,
owner,
Expand All @@ -16,15 +13,12 @@ async fn insufficient_funds() -> Result<(), TransportError> {
market_base_vault,
market_quote_vault,
..
} = TestContext::new_with_market(TestNewMarketInitialize {
base_lot_size,
quote_lot_size,
..TestNewMarketInitialize::default()
})
.await?;
} = TestContext::new_with_market(TestNewMarketInitialize::default()).await?;

let solana = &context.solana.clone();

let max_quote_lots_including_fees = 104;

// there's an ask on the book
send_tx(
solana,
Expand All @@ -37,8 +31,8 @@ async fn insufficient_funds() -> Result<(), TransportError> {
market_vault: market_base_vault,
side: Side::Ask,
price_lots: 1,
max_base_lots: 10,
max_quote_lots_including_fees: i64::MAX / 1_000_000,
max_base_lots: i64::MAX / 1_000,
max_quote_lots_including_fees,
client_order_id: 0,
expiry_timestamp: 0,
order_type: PlaceOrderType::Limit,
Expand Down Expand Up @@ -72,47 +66,27 @@ async fn insufficient_funds() -> Result<(), TransportError> {

// note that a priori, we only have enough lamports to place 2.5 Ask. But as the bid will be
// filled & the taker executed immediately, we will have 10 extra base lots available
let place_orders = (0..5)
.map(|i| {
if i == 1 {
openbook_v2::PlaceOrderArgs {
side: Side::Bid,
price_lots: 1,
max_base_lots: 10,
max_quote_lots_including_fees: i64::MAX / 1_000_000,
client_order_id: 0,
order_type: PlaceOrderType::Limit,
expiry_timestamp: 0,
self_trade_behavior: SelfTradeBehavior::default(),
limit: 10,
}
} else {
openbook_v2::PlaceOrderArgs {
side: Side::Ask,
price_lots: 1,
max_base_lots: 10,
max_quote_lots_including_fees: i64::MAX / 1_000_000,
client_order_id: 0,
order_type: PlaceOrderType::Limit,
expiry_timestamp: 0,
self_trade_behavior: SelfTradeBehavior::default(),
limit: 10,
}
}
})
.collect::<Vec<_>>();
let order = openbook_v2::PlaceMultipleOrdersArgs {
price_lots: 1,
max_quote_lots_including_fees,
expiry_timestamp: 0,
};

let bids = vec![order];
let asks = vec![order; 4];

send_tx(
solana,
CancelAndPlaceOrdersInstruction {
CancelAllAndPlaceOrdersInstruction {
open_orders_account: account_1,
open_orders_admin: None,
market,
signer: owner,
orders_type: PlaceOrderType::Limit,
user_base_account: owner_token_0,
user_quote_account: owner_token_1,
cancel_client_orders_ids: vec![],
place_orders,
bids,
asks,
},
)
.await
Expand Down
Loading
Loading