Skip to content

Latest commit

 

History

History
163 lines (103 loc) · 8.62 KB

File metadata and controls

163 lines (103 loc) · 8.62 KB
id TIP-1056
title Keep the same order ID when flip orders flip
description Reuses the same order ID when a flip order flips and emits OrderFlipped instead of creating a new order ID and emitting OrderPlaced.
authors Dan Robinson
status Draft
related TIP-1030, TIP-1044
protocolVersion T5

TIP-1056: Keep the same order ID when flip orders flip

Abstract

This TIP adds a new OrderFlipped event and changes flip order execution so that when a flip order is fully filled and flips to the opposite side of the book, it keeps the same orderId. Instead of deleting the filled order and creating a new order with a new ID, the order is rewritten in place and OrderFlipped is emitted.

This makes orderId the stable identity of a flip order across flips. It also avoids allocating a new order ID, and orders no longer emit OrderPlaced when they flip.

Motivation

Today, when a flip order is fully filled, the Stablecoin DEX emits OrderFilled for the filled order, then creates a fresh opposite-side order with a new orderId and emits OrderPlaced. That makes a single logical flip order appear as a sequence of unrelated orders.

This creates avoidable offchain complexity for market makers that use flip orders. To know which orders they currently have open, they must index the chain and watch both OrderFilled and OrderPlaced, then update their own state every time a flip replaces one order ID with another. It also means canceling a flip order is not guaranteed: if the order flips while a cancel is pending, the cancel attempt fails because it targets the old order ID. Keeping the same orderId makes the order a stable handle across flips instead of forcing market makers to chase a moving ID, and makes cancellation target the currently active order.

It also saves substantial gas. Today, a flip costs about 1.5 million gas because it deletes the filled order and creates a fresh opposite-side order with a new ID. Even after TIP-1055 removes the redundant stored orderId, a flip would still cost about 1.25 million gas if it continues creating a new order record on every flip. Rewriting the same order in place avoids most of that overhead.

This TIP is an alternative to TIP-1044. TIP-1044 keeps the current semantics and discounts the gas charged for creating the replacement order. TIP-1056 instead changes the semantics so no replacement order is created at all. Because it removes that work rather than discounting it, it achieves greater gas savings.

Assumptions

  • Flip orders remain orders that automatically rest on the opposite side only after they are fully filled.
  • A flipped order should receive fresh queue priority at its destination tick, even though it keeps the same orderId.
  • Consumers that distinguish ordinary order placement from automatic flipping can switch from OrderPlaced to OrderFlipped for flip transitions.
  • orderId is allowed to represent a logical order across flips rather than a single open-to-close resting-order instance.

Specification

Flip behavior

When a flip order is fully filled, the Stablecoin DEX MUST:

  1. emit OrderFilled(orderId, maker, taker, amountFilled, false) for the fill
  2. rewrite that same order in place to its flipped state
  3. emit OrderFlipped for the newly resting flipped order

It MUST NOT:

  • allocate a new orderId
  • increment nextOrderId
  • emit OrderPlaced for the automatically flipped order

Rewritten order state

When order orderId flips, the stored order with key orderId is updated as follows:

  • isBid is inverted
  • tick becomes the prior flipTick
  • flipTick becomes the prior tick
  • amount is unchanged
  • remaining is reset to amount
  • maker is unchanged
  • bookKey is unchanged
  • isFlip remains true
  • prev and next are reset before reinsertion into the destination tick level

"Rewrite in place" means the order remains stored under the same mapping key and the implementation updates the existing order record rather than deleting it and allocating a new order record.

If TIP-1055 is active and the order is stored in an older order-storage version, the rewrite MUST upgrade the order to the latest active storage version. In particular, a version 0 order that flips after TIP-1055 activates MUST become a version 1 order as part of that rewrite.

That storage-version upgrade MUST clear deprecated slot 0 as part of the upgrade. The order keeps the same mapping key as its canonical orderId, and after the upgrade slot 0 remains zero and MUST remain untouched for the rest of the order's live lifetime.

Outside of the tick-level and linked-list bookkeeping needed to remove and reinsert the order, the implementation MUST write only order-record slots whose post-flip contents differ from their pre-flip contents.

Under the TIP-1055 storage layout, slots 1 and 2 of the order record do not change during a flip and MUST remain untouched. Slot 0 MUST be cleared if and only if the flip upgrades a version 0 order to version 1; otherwise slot 0 MUST remain untouched. Only the slots whose packed contents actually change may be written.

Queue priority

Keeping the same orderId does not preserve queue position.

After a flip, the rewritten order is inserted into the destination tick level as a newly resting order with fresh time priority at that level.

Cancellation

cancel(orderId) and cancelStaleOrder(orderId) apply to the currently active state of that order ID.

If a flip order has already flipped, cancelling that orderId cancels the flipped order.

Getter behavior

getOrder(orderId) continues to return the current active state of that order ID.

For a flip order that has flipped one or more times, getOrder(orderId) returns the latest resting state.

Events

Add a new event:

event OrderFlipped(
    uint128 indexed orderId,
    address indexed maker,
    address indexed token,
    uint128 amount,
    bool isBid,
    int16 tick,
    int16 flipTick
);

OrderFlipped is emitted only when a fully filled flip order is rewritten to its new resting state.

Initial order placement behavior is unchanged:

  • user-submitted order placement emits OrderPlaced
  • automatic flip transitions emit OrderFlipped

No new errors are introduced.

Compatibility

This TIP changes both event semantics and orderId semantics for flip orders.

Indexers

Indexers that currently treat OrderPlaced as the signal that new resting liquidity has appeared MUST also process OrderFlipped. Otherwise they will miss flipped liquidity entirely.

Indexers that currently model one orderId as one open-to-close order lifecycle MUST update that model. After this TIP, a flip order's orderId identifies a logical order that may change side and tick across flips while remaining live.

Indexers that maintain order-history tables keyed by orderId may need to support multiple phases of a single order ID. In particular, a terminal OrderFilled(..., false) for a flip order is no longer necessarily the end of that order ID's life if it is followed by OrderFlipped.

Market makers and trading systems

Market makers that currently track flip orders by listening for OrderFilled and then replacing the old order ID with the new OrderPlaced order ID MUST update that logic. After this TIP, the same orderId remains active across flips and OrderFlipped is the signal that the order changed side.

Trading systems that submit cancellations against the most recently observed replacement order ID must instead treat the original flip-order orderId as the stable cancellation handle.

Analytics and monitoring

Systems that use nextOrderId as a proxy for how many orders have been created will observe lower growth, because automatic flips no longer allocate new IDs.

Systems that count new resting orders by counting OrderPlaced events will undercount unless they also count OrderFlipped.

Summary

External systems remain compatible if they adopt the following rules:

  • OrderPlaced means user-submitted liquidity began resting
  • OrderFlipped means existing flip liquidity began resting on the opposite side
  • orderId for a flip order is a stable logical identifier across flips
  • cancel(orderId) targets the currently active state of that logical order

Invariants

  • Fully filling a flip order does not allocate a new order ID.
  • Fully filling a flip order does not increment nextOrderId.
  • After a flip, getOrder(orderId) returns the flipped resting order under the same orderId.
  • OrderPlaced is not emitted for automatically flipped liquidity.
  • OrderFlipped is emitted exactly once for each successful flip transition.
  • A flipped order receives fresh queue priority at its destination tick level.