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

[CT-1327] place post only orders first in prepare check state #2618

Merged
merged 6 commits into from
Dec 2, 2024
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
10 changes: 5 additions & 5 deletions protocol/mocks/MemClob.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions protocol/testutil/constants/stateful_orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,19 @@ var (
}

// Long-Term post-only orders.
LongTermOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTBT5_PO = clobtypes.Order{
OrderId: clobtypes.OrderId{
SubaccountId: Alice_Num0,
ClientId: 0,
OrderFlags: clobtypes.OrderIdFlags_LongTerm,
ClobPairId: 0,
},
Side: clobtypes.Order_SIDE_BUY,
Quantums: 5,
Subticks: 10,
GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{GoodTilBlockTime: 5},
TimeInForce: clobtypes.Order_TIME_IN_FORCE_POST_ONLY,
}
LongTermOrder_Alice_Num0_Id0_Clob0_Buy100_Price10_GTBT15_PO = clobtypes.Order{
OrderId: clobtypes.OrderId{
SubaccountId: Alice_Num0,
Expand Down Expand Up @@ -1360,6 +1373,19 @@ var (
GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{GoodTilBlockTime: 10},
TimeInForce: clobtypes.Order_TIME_IN_FORCE_POST_ONLY,
}
LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO = clobtypes.Order{
OrderId: clobtypes.OrderId{
SubaccountId: Dave_Num0,
ClientId: 0,
OrderFlags: clobtypes.OrderIdFlags_LongTerm,
ClobPairId: 0,
},
Side: clobtypes.Order_SIDE_SELL,
Quantums: 25_000_000,
Subticks: 50_000_000_000,
GoodTilOneof: &clobtypes.Order_GoodTilBlockTime{GoodTilBlockTime: 10},
TimeInForce: clobtypes.Order_TIME_IN_FORCE_POST_ONLY,
}

// Long-Term reduce-only orders.
LongTermOrder_Bob_Num0_Id2_Clob0_Sell10_Price35_GTB20_RO = clobtypes.Order{
Expand Down
47 changes: 37 additions & 10 deletions protocol/x/clob/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,42 @@ func PrepareCheckState(
offchainUpdates,
)

// 3. Place all stateful order placements included in the last block on the memclob.
// 3. Go through the orders two times and only place the post only orders during the first pass.
longTermOrderIds := keeper.GetDeliveredLongTermOrderIds(ctx)
offchainUpdates = keeper.PlaceStatefulOrdersFromLastBlock(
ctx,
longTermOrderIds,
offchainUpdates,
true, // post only
)

offchainUpdates = keeper.PlaceConditionalOrdersTriggeredInLastBlock(
ctx,
processProposerMatchesEvents.ConditionalOrderIdsTriggeredInLastBlock,
offchainUpdates,
true, // post only
)

replayUpdates := keeper.MemClob.ReplayOperations(
ctx,
localValidatorOperationsQueue,
shortTermOrderTxBytes,
offchainUpdates,
true, // post only
)
if replayUpdates != nil {
offchainUpdates = replayUpdates
}

// 4. Place all stateful order placements included in the last block on the memclob.
// Note telemetry is measured outside of the function call because `PlaceStatefulOrdersFromLastBlock`
// is called within `PlaceConditionalOrdersTriggeredInLastBlock`.
startPlaceLongTermOrders := time.Now()
longTermOrderIds := keeper.GetDeliveredLongTermOrderIds(ctx)
offchainUpdates = keeper.PlaceStatefulOrdersFromLastBlock(
ctx,
longTermOrderIds,
offchainUpdates,
false, // post only
)
telemetry.MeasureSince(
startPlaceLongTermOrders,
Expand All @@ -208,27 +235,27 @@ func PrepareCheckState(
metrics.Count,
)

// 4. Place all conditional orders triggered in EndBlocker of last block on the memclob.
// 5. Place all conditional orders triggered in EndBlocker of last block on the memclob.
offchainUpdates = keeper.PlaceConditionalOrdersTriggeredInLastBlock(
ctx,
processProposerMatchesEvents.ConditionalOrderIdsTriggeredInLastBlock,
offchainUpdates,
false, // post only
)

// 5. Replay the local validator’s operations onto the book.
replayUpdates := keeper.MemClob.ReplayOperations(
// 6. Replay the local validator’s operations onto the book.
replayUpdates = keeper.MemClob.ReplayOperations(
ctx,
localValidatorOperationsQueue,
shortTermOrderTxBytes,
offchainUpdates,
false, // post only
)

// TODO(CLOB-275): Do not gracefully handle panics in `PrepareCheckState`.
if replayUpdates != nil {
offchainUpdates = replayUpdates
}

// 6. Get all potentially liquidatable subaccount IDs and attempt to liquidate them.
// 7. Get all potentially liquidatable subaccount IDs and attempt to liquidate them.
liquidatableSubaccountIds := keeper.DaemonLiquidationInfo.GetLiquidatableSubaccountIds()
subaccountsToDeleverage, err := keeper.LiquidateSubaccountsAgainstOrderbook(ctx, liquidatableSubaccountIds)
if err != nil {
Expand All @@ -241,14 +268,14 @@ func PrepareCheckState(
keeper.GetSubaccountsWithPositionsInFinalSettlementMarkets(ctx)...,
)

// 7. Deleverage subaccounts.
// 8. Deleverage subaccounts.
// TODO(CLOB-1052) - decouple steps 6 and 7 by using DaemonLiquidationInfo.NegativeTncSubaccounts
// as the input for this function.
if err := keeper.DeleverageSubaccounts(ctx, subaccountsToDeleverage); err != nil {
panic(err)
}

// 8. Gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any
// 9. Gate withdrawals by inserting a zero-fill deleveraging operation into the operations queue if any
// of the negative TNC subaccounts still have negative TNC after liquidations and deleveraging steps.
negativeTncSubaccountIds := keeper.DaemonLiquidationInfo.GetNegativeTncSubaccountIds()
if err := keeper.GateWithdrawalsIfNegativeTncSubaccountSeen(ctx, negativeTncSubaccountIds); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions protocol/x/clob/e2e/conditional_orders_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ func TestConditionalOrder(t *testing.T) {
constants.Dave_Num0_500000USD,
},
orders: []clobtypes.Order{
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10,
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO,
constants.ConditionalOrder_Carl_Num0_Id0_Clob0_Buy05BTC_Price50000_GTBT10_TP_49999_PO,
},
priceUpdateForFirstBlock: &prices.MsgUpdateMarketPrices{
Expand Down Expand Up @@ -1869,7 +1869,7 @@ func TestConditionalOrder_TriggeringUsingMatchedPrice(t *testing.T) {
constants.Order_Dave_Num1_Id0_Clob0_Sell1BTC_Price49997_GTB10,
constants.Order_Carl_Num1_Id0_Clob0_Buy1BTC_Price50003_GTB10,
// Place the conditional order.
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10,
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential issue with using a post-only order in this test case

In the test case "TakeProfit/Buy post-only conditional order can place, trigger, cross, and be removed from state", you have changed the order to a post-only order by using LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO. Post-only orders are intended to add liquidity and will not execute immediately against existing orders. This may prevent the expected cross and removal from state, which contradicts the test's objective to verify that the conditional order can cross and be removed from state.

Consider using a non-post-only order to ensure the test behaves as intended.

Apply this diff to fix the issue:

-				constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO,
+				constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10_PO,
constants.LongTermOrder_Dave_Num0_Id0_Clob0_Sell025BTC_Price50000_GTBT10,

constants.ConditionalOrder_Carl_Num0_Id0_Clob0_Buy05BTC_Price50000_GTBT10_TP_49999_PO,
},
expectedInTriggeredStateAfterBlock: map[uint32]map[clobtypes.OrderId]bool{
Expand Down
4 changes: 2 additions & 2 deletions protocol/x/clob/e2e/order_removal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestConditionalOrderRemoval(t *testing.T) {
constants.Bob_Num0_10_000USD,
},
orders: []clobtypes.Order{
constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTBT5,
constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTBT5_PO,
constants.ConditionalOrder_Bob_Num0_Id0_Clob0_Sell10_Price10_GTBT10_PO_SL_15,
},

Expand Down Expand Up @@ -629,7 +629,7 @@ func TestOrderRemoval(t *testing.T) {
constants.Alice_Num0_10_000USD,
constants.Bob_Num0_10_000USD,
},
firstOrder: constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTBT5,
firstOrder: constants.LongTermOrder_Alice_Num0_Id0_Clob0_Buy5_Price10_GTBT5_PO,
secondOrder: constants.LongTermOrder_Bob_Num0_Id0_Clob0_Sell10_Price10_GTBT10_PO,

expectedFirstOrderRemoved: false,
Expand Down
21 changes: 20 additions & 1 deletion protocol/x/clob/keeper/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ func (k Keeper) AddPreexistingStatefulOrder(
// PlaceStatefulOrdersFromLastBlock validates and places stateful orders from the last block onto the memclob.
// Note that stateful orders could fail to be placed due to various reasons such as collateralization
// check failures, self-trade errors, etc. In these cases the `checkState` will not be written to.
// Note that this function also takes in a postOnlyFilter variable and only places post-only orders if
// postOnlyFilter is true and non-post-only orders if postOnlyFilter is false.
//
// This function is used in:
// 1. `PrepareCheckState` to place newly placed long term orders from the last
// block from ProcessProposerMatchesEvents.PlacedStatefulOrderIds. This is step 3 in PrepareCheckState.
Expand All @@ -496,6 +499,7 @@ func (k Keeper) PlaceStatefulOrdersFromLastBlock(
ctx sdk.Context,
placedStatefulOrderIds []types.OrderId,
existingOffchainUpdates *types.OffchainUpdates,
postOnlyFilter bool,
) (
offchainUpdates *types.OffchainUpdates,
) {
Expand All @@ -521,6 +525,12 @@ func (k Keeper) PlaceStatefulOrdersFromLastBlock(
}

order := orderPlacement.GetOrder()

// Skip post-only orders if postOnlyFilter is false or non-post-only orders if postOnlyFilter is true.
if postOnlyFilter != order.IsPostOnlyOrder() {
continue
}

// Validate and place order.
_, orderStatus, placeOrderOffchainUpdates, err := k.AddPreexistingStatefulOrder(
ctx,
Expand Down Expand Up @@ -575,10 +585,14 @@ func (k Keeper) PlaceStatefulOrdersFromLastBlock(
// PlaceConditionalOrdersTriggeredInLastBlock takes in a list of conditional order ids that were triggered
// in the last block, verifies they are conditional orders, verifies they are in triggered state, and places
// the orders on the memclob.
//
// Note that this function also takes in a postOnlyFilter variable and only places post-only orders if
// postOnlyFilter is true and non-post-only orders if postOnlyFilter is false.
func (k Keeper) PlaceConditionalOrdersTriggeredInLastBlock(
ctx sdk.Context,
conditionalOrderIdsTriggeredInLastBlock []types.OrderId,
existingOffchainUpdates *types.OffchainUpdates,
postOnlyFilter bool,
) (
offchainUpdates *types.OffchainUpdates,
) {
Expand Down Expand Up @@ -608,7 +622,12 @@ func (k Keeper) PlaceConditionalOrdersTriggeredInLastBlock(
}
}

return k.PlaceStatefulOrdersFromLastBlock(ctx, conditionalOrderIdsTriggeredInLastBlock, existingOffchainUpdates)
return k.PlaceStatefulOrdersFromLastBlock(
ctx,
conditionalOrderIdsTriggeredInLastBlock,
existingOffchainUpdates,
postOnlyFilter,
)
}

// PerformOrderCancellationStatefulValidation performs stateful validation on an order cancellation.
Expand Down
Loading
Loading