TIP-1001: Place-only mode for next quote token
Abstract
This TIP adds a createNextPair function to the Stablecoin DEX that creates a trading pair between a base token and its nextQuoteToken(), along with place and placeFlip overloads that accept a book key to target specific pairs. This enables market makers to place orders on the new pair before a quote token update is finalized, providing a smooth liquidity transition.
Motivation
When a token issuer decides to change their quote token (via setNextQuoteToken and completeQuoteTokenUpdate), there is currently no way to establish liquidity on the new pair before the transition completes. This means that market makers will need to wait until the quote token has been updated before they can place orders, which could cause a period where there is no liquidity, or limited liquidity, for the token, which will interrupt swaps involving that token.
By allowing pair creation against nextQuoteToken(), this change allows users and market makers to add liquidity to the DEX before it is used on swaps. Since swaps route through quoteToken() (not nextQuoteToken()), the new pair operates in "place-only" mode: orders can be placed and cancelled, but no swaps route through it until completeQuoteTokenUpdate() is called.
Specification
New functions
Add the following functions to the Stablecoin DEX interface:
/// @notice Creates a trading pair between a base token and its next quote token
/// @param base The base token address
/// @return key The pair key for the created pair
/// @dev Reverts if:
/// - The base token has no next quote token staged (nextQuoteToken is zero)
/// - The pair already exists
/// - Either token is not USD-denominated
function createNextPair(address base) external returns (bytes32 key);
/// @notice Places an order on a specific pair identified by book key
/// @param bookKey The pair key identifying the orderbook
/// @param token The base token of the pair
/// @param amount The order amount in base tokens
/// @param isBid True for buy orders, false for sell orders
/// @param tick The price tick for the order
/// @return orderId The ID of the placed order
function place(bytes32 bookKey, address token, uint128 amount, bool isBid, int16 tick) external returns (uint128 orderId);
/// @notice Places a flip order on a specific pair identified by book key
/// @param bookKey The pair key identifying the orderbook
/// @param token The base token of the pair
/// @param amount The order amount in base tokens
/// @param isBid True for buy orders, false for sell orders
/// @param tick The price tick for the order
/// @param flipTick The price tick for the flipped order when filled
/// @param internalBalanceOnly If true, only use internal balance for the flipped order
/// @return orderId The ID of the placed order
function placeFlip(bytes32 bookKey, address token, uint128 amount, bool isBid, int16 tick, int16 flipTick, bool internalBalanceOnly) external returns (uint128 orderId);Behavior
Pair creation
createNextPair(base) creates a pair between base and base.nextQuoteToken(). The function:
- Calls
nextQuoteToken()on the base token - Reverts with
NO_NEXT_QUOTE_TOKENif the result isaddress(0) - Validates both tokens are USD-denominated (same as
createPair) - Creates the pair using the same mechanism as
createPair - Emits
PairCreated(key, base, nextQuoteToken)
Place-only mode
Once the pair exists, it supports the full order lifecycle:
place(bookKey, ...)andplaceFlip(bookKey, ...)allow placing orders on the paircancelandcancelStaleOrderwork normally (they use order ID, not pair lookup)booksreturns accurate data (it takes the book key directly)
The new place and placeFlip overloads are required because the existing functions derive the pair from token.quoteToken(), which would look up the wrong pair. The overloads accept a bookKey parameter to target the correct pair.
Swap functions (swapExactAmountIn, swapExactAmountOut) and quote functions (quoteSwapExactAmountIn, quoteSwapExactAmountOut) do not route through this pair because routing uses quoteToken() to find paths between tokens.
After quote token update
When the token issuer calls completeQuoteTokenUpdate():
- The token's
quoteToken()changes to what wasnextQuoteToken() - The token's
nextQuoteToken()becomesaddress(0) - The existing pair (created via
createNextPair) is now the active pair - Swaps begin routing through the pair
The old pair (against the previous quote token) remains but will no longer be used for routing swaps involving this base token. Orders on it can be canceled using their ID.
New error
/// @notice The base token has no next quote token staged
error NO_NEXT_QUOTE_TOKEN();Events
No new events. The existing PairCreated event is emitted by createNextPair, and the existing OrderPlaced event is emitted by the place and placeFlip overloads.
Invariants
- A pair created via
createNextPairmust be identical to one created viacreatePaironcecompleteQuoteTokenUpdateis called createNextPairmust revert ifnextQuoteToken()returnsaddress(0)createNextPairmust revert if the pair already exists (same ascreatePair)- Orders placed on a next-quote-token pair must be executable via swaps after the quote token update completes
- Swap routing must not change until
completeQuoteTokenUpdateis called on the base token