From fc30eec7395f03bc501aed1baf209d332d298726 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 12:43:42 -0500 Subject: [PATCH 1/6] jit: account for min order size --- programs/jit-proxy/src/instructions/jit.rs | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/programs/jit-proxy/src/instructions/jit.rs b/programs/jit-proxy/src/instructions/jit.rs index 74c8cf2..396efa4 100644 --- a/programs/jit-proxy/src/instructions/jit.rs +++ b/programs/jit-proxy/src/instructions/jit.rs @@ -42,16 +42,16 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams None, )?; - let (oracle_price, tick_size) = if market_type == DriftMarketType::Perp { + let (oracle_price, tick_size, min_order_size) = if market_type == DriftMarketType::Perp { let perp_market = perp_market_map.get_ref(&market_index)?; let oracle_price = oracle_map.get_price_data(&perp_market.amm.oracle)?.price; - (oracle_price, perp_market.amm.order_tick_size) + (oracle_price, perp_market.amm.order_tick_size, perp_market.amm.min_order_size) } else { let spot_market = spot_market_map.get_ref(&market_index)?; let oracle_price = oracle_map.get_price_data(&spot_market.oracle)?.price; - (oracle_price, spot_market.order_tick_size) + (oracle_price, spot_market.order_tick_size, spot_market.min_order_size) }; let taker_price = @@ -83,7 +83,7 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams } let maker_price = taker_price; - let taker_base_asset_amount_unfilled = taker_order.get_base_asset_amount_unfilled(None)?; + let taker_base_asset_amount_unfilled = taker_order.get_base_asset_amount_unfilled(None)?.max(min_order_size); let maker_existing_position = if market_type == DriftMarketType::Perp { let perp_market = perp_market_map.get_ref(&market_index)?; let perp_position = maker.get_perp_position(market_index); @@ -108,6 +108,7 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams maker_direction, taker_base_asset_amount_unfilled, maker_existing_position, + min_order_size, ) { Ok(size) => size, Err(e) => { @@ -210,15 +211,17 @@ fn check_position_limits( maker_direction: PositionDirection, taker_base_asset_amount_unfilled: u64, maker_existing_position: i64, + min_order_size: u64, ) -> Result { if maker_direction == PositionDirection::Long { let size = params.max_position.safe_sub(maker_existing_position)?; - if size <= 0 { + if size <= min_order_size.cast()? { msg!( - "maker existing position {} >= max position {}", + "maker existing position {} >= max position {} + min order size {}", maker_existing_position, - params.max_position + params.max_position, + min_order_size ); return Err(ErrorCode::PositionLimitBreached.into()); } @@ -227,11 +230,12 @@ fn check_position_limits( } else { let size = maker_existing_position.safe_sub(params.min_position)?; - if size <= 0 { + if size <= min_order_size.cast()? { msg!( - "maker existing position {} <= min position {}", + "maker existing position {} <= min position {} + min order size {}", maker_existing_position, - params.min_position + params.min_position, + min_order_size ); return Err(ErrorCode::PositionLimitBreached.into()); } From 300d8260719402f21ea092503952181ecdc5e79a Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 12:53:47 -0500 Subject: [PATCH 2/6] cargo fmt -- --- programs/jit-proxy/src/instructions/jit.rs | 40 ++++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/programs/jit-proxy/src/instructions/jit.rs b/programs/jit-proxy/src/instructions/jit.rs index 396efa4..02491a5 100644 --- a/programs/jit-proxy/src/instructions/jit.rs +++ b/programs/jit-proxy/src/instructions/jit.rs @@ -46,12 +46,20 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams let perp_market = perp_market_map.get_ref(&market_index)?; let oracle_price = oracle_map.get_price_data(&perp_market.amm.oracle)?.price; - (oracle_price, perp_market.amm.order_tick_size, perp_market.amm.min_order_size) + ( + oracle_price, + perp_market.amm.order_tick_size, + perp_market.amm.min_order_size, + ) } else { let spot_market = spot_market_map.get_ref(&market_index)?; let oracle_price = oracle_map.get_price_data(&spot_market.oracle)?.price; - (oracle_price, spot_market.order_tick_size, spot_market.min_order_size) + ( + oracle_price, + spot_market.order_tick_size, + spot_market.min_order_size, + ) }; let taker_price = @@ -83,7 +91,9 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams } let maker_price = taker_price; - let taker_base_asset_amount_unfilled = taker_order.get_base_asset_amount_unfilled(None)?.max(min_order_size); + let taker_base_asset_amount_unfilled = taker_order + .get_base_asset_amount_unfilled(None)? + .max(min_order_size); let maker_existing_position = if market_type == DriftMarketType::Perp { let perp_market = perp_market_map.get_ref(&market_index)?; let perp_position = maker.get_perp_position(market_index); @@ -257,49 +267,49 @@ mod tests { }; // same direction, doesn't breach - let result = check_position_limits(params, PositionDirection::Long, 10, 40); + let result = check_position_limits(params, PositionDirection::Long, 10, 40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 10); - let result = check_position_limits(params, PositionDirection::Short, 10, -40); + let result = check_position_limits(params, PositionDirection::Short, 10, -40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 10); // same direction, whole order breaches, only takes enough to hit limit - let result = check_position_limits(params, PositionDirection::Long, 100, 40); + let result = check_position_limits(params, PositionDirection::Long, 100, 40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 60); - let result = check_position_limits(params, PositionDirection::Short, 100, -40); + let result = check_position_limits(params, PositionDirection::Short, 100, -40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 60); // opposite direction, doesn't breach - let result = check_position_limits(params, PositionDirection::Long, 10, -40); + let result = check_position_limits(params, PositionDirection::Long, 10, -40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 10); - let result = check_position_limits(params, PositionDirection::Short, 10, 40); + let result = check_position_limits(params, PositionDirection::Short, 10, 40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 10); // opposite direction, whole order breaches, only takes enough to take flipped limit - let result = check_position_limits(params, PositionDirection::Long, 200, -40); + let result = check_position_limits(params, PositionDirection::Long, 200, -40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 140); - let result = check_position_limits(params, PositionDirection::Short, 200, 40); + let result = check_position_limits(params, PositionDirection::Short, 200, 40, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 140); // opposite direction, maker already breached, allows reducing - let result = check_position_limits(params, PositionDirection::Long, 200, -150); + let result = check_position_limits(params, PositionDirection::Long, 200, -150, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 200); - let result = check_position_limits(params, PositionDirection::Short, 200, 150); + let result = check_position_limits(params, PositionDirection::Short, 200, 150, 0); assert!(result.is_ok()); assert_eq!(result.unwrap(), 200); // same direction, maker already breached, errors - let result = check_position_limits(params, PositionDirection::Long, 200, 150); + let result = check_position_limits(params, PositionDirection::Long, 200, 150, 0); assert!(result.is_err()); - let result = check_position_limits(params, PositionDirection::Short, 200, -150); + let result = check_position_limits(params, PositionDirection::Short, 200, -150, 0); assert!(result.is_err()); } } From 7a85ff431731d7bcbc3c47980e8dfb35c645551a Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 13:29:08 -0500 Subject: [PATCH 3/6] account for no taker limit price --- programs/jit-proxy/src/instructions/jit.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/programs/jit-proxy/src/instructions/jit.rs b/programs/jit-proxy/src/instructions/jit.rs index 02491a5..15f5629 100644 --- a/programs/jit-proxy/src/instructions/jit.rs +++ b/programs/jit-proxy/src/instructions/jit.rs @@ -63,7 +63,23 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams }; let taker_price = - taker_order.force_get_limit_price(Some(oracle_price), None, slot, tick_size)?; + match taker_order.get_limit_price(Some(oracle_price), None, slot, tick_size)? { + Some(price) => price, + None if market_type == DriftMarketType::Perp => { + // if the order doesn't have a price, drift users amm price for taker price + let perp_market = perp_market_map.get_ref(&market_index)?; + let reserve_price = perp_market.amm.reserve_price()?; + match taker_direction { + PositionDirection::Long => perp_market.amm.ask_price(reserve_price)?, + PositionDirection::Short => perp_market.amm.bid_price(reserve_price)?, + } + } + None => { + // Shouldnt be possible for spot + msg!("taker order didnt have price"); + return Err(ErrorCode::TakerOrderNotFound.into()); + } + }; let maker_direction = taker_direction.opposite(); let maker_worst_price = params.get_worst_price(oracle_price, taker_direction)?; From 846c75856d89d6386cb33d0d670084020702630a Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 13:36:53 -0500 Subject: [PATCH 4/6] revert if order isn't filled --- programs/jit-proxy/src/error.rs | 2 ++ programs/jit-proxy/src/instructions/jit.rs | 23 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/programs/jit-proxy/src/error.rs b/programs/jit-proxy/src/error.rs index 594a7a6..1155ec4 100644 --- a/programs/jit-proxy/src/error.rs +++ b/programs/jit-proxy/src/error.rs @@ -21,4 +21,6 @@ pub enum ErrorCode { UnprofitableArb, #[msg("PositionLimitBreached")] PositionLimitBreached, + #[msg("NoFill")] + NoFill, } diff --git a/programs/jit-proxy/src/instructions/jit.rs b/programs/jit-proxy/src/instructions/jit.rs index 15f5629..63a6aed 100644 --- a/programs/jit-proxy/src/instructions/jit.rs +++ b/programs/jit-proxy/src/instructions/jit.rs @@ -168,7 +168,26 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams drop(taker); drop(maker); - place_and_make(ctx, params.taker_order_id, order_params)?; + place_and_make(&ctx, params.taker_order_id, order_params)?; + + let taker = ctx.accounts.taker.load()?; + + let taker_base_asset_amount_unfilled_after = match taker.get_order(params.taker_order_id) { + Some(order) => order.get_base_asset_amount_unfilled(None)?, + None => 0, + }; + + if taker_base_asset_amount_unfilled_after == taker_base_asset_amount_unfilled { + // taker order failed to fill + msg!("taker order failed to fill"); + msg!( + "taker price = {} maker price ={} oracle price {}", + taker_price, + maker_price, + oracle_price + ); + return Err(ErrorCode::NoFill.into()); + } Ok(()) } @@ -331,7 +350,7 @@ mod tests { } fn place_and_make<'info>( - ctx: Context<'_, '_, '_, 'info, Jit<'info>>, + ctx: &Context<'_, '_, '_, 'info, Jit<'info>>, taker_order_id: u32, order_params: OrderParams, ) -> Result<()> { From 00a0386e89173a2b12d84a029c381f0031819035 Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 13:38:34 -0500 Subject: [PATCH 5/6] update idl --- ts/sdk/src/types/jit_proxy.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ts/sdk/src/types/jit_proxy.ts b/ts/sdk/src/types/jit_proxy.ts index d5e8a33..9193b5d 100644 --- a/ts/sdk/src/types/jit_proxy.ts +++ b/ts/sdk/src/types/jit_proxy.ts @@ -189,6 +189,9 @@ export type JitProxy = { }, { name: 'TryPostOnly'; + }, + { + name: 'Slide'; } ]; }; @@ -262,6 +265,16 @@ export type JitProxy = { code: 6007; name: 'UnprofitableArb'; msg: 'UnprofitableArb'; + }, + { + code: 6008; + name: 'PositionLimitBreached'; + msg: 'PositionLimitBreached'; + }, + { + code: 6009; + name: 'NoFill'; + msg: 'NoFill'; } ]; }; @@ -458,6 +471,9 @@ export const IDL: JitProxy = { { name: 'TryPostOnly', }, + { + name: 'Slide', + }, ], }, }, @@ -531,5 +547,15 @@ export const IDL: JitProxy = { name: 'UnprofitableArb', msg: 'UnprofitableArb', }, + { + code: 6008, + name: 'PositionLimitBreached', + msg: 'PositionLimitBreached', + }, + { + code: 6009, + name: 'NoFill', + msg: 'NoFill', + }, ], }; From f63a6718c3395ed3d3c2c6e85976c526a36c293c Mon Sep 17 00:00:00 2001 From: Chris Heaney Date: Tue, 23 Jan 2024 13:43:32 -0500 Subject: [PATCH 6/6] fix formatting --- programs/jit-proxy/src/instructions/jit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/jit-proxy/src/instructions/jit.rs b/programs/jit-proxy/src/instructions/jit.rs index 63a6aed..51cc6f7 100644 --- a/programs/jit-proxy/src/instructions/jit.rs +++ b/programs/jit-proxy/src/instructions/jit.rs @@ -181,7 +181,7 @@ pub fn jit<'info>(ctx: Context<'_, '_, '_, 'info, Jit<'info>>, params: JitParams // taker order failed to fill msg!("taker order failed to fill"); msg!( - "taker price = {} maker price ={} oracle price {}", + "taker price = {} maker price = {} oracle price {}", taker_price, maker_price, oracle_price