SIP-281: PerpsV2 (Trading fixes & improvements)

ImplementorDavid Vuong (@davidvuong)

Simple Summary

Improves the underlying mechanism of next price orders to be time oriented and takes further consideration into maker/taker fee calculations when a trade flips the market skew.


SIP proposes two changes, (1) delayed orders and (2) cross side maker/taker fees. Delayed orders updates the current next-price orders to allow execution based primarily on time rather than purely on a semi-arbitrary price feed update from CL.

Cross side maker/taker fees is a fix on the current order fee calculation. Currently, if an order flips the market skew, the size in its entirety is charged with just maker fees. This is incorrect. The change involves updating the calculation such that the proportion of size that reduces the skew will be charged a maker fee but the remaining which increases the skew is charged with a taker fee.

Note this SIP depends on SIP-280 as these changes extend on top of PerpsV2.


Delayed Orders

Current next price orders are non-deterministic and gives way to suboptimal user experience for traders. An order is only executable when a new price update occurs. An order operating under the rules of next price will only be executable if a feed's deviation threshold is reached, sometimes during low volatility, the threshold never kicks in and traders are at the mercy of the heartbeat.

If the intent is to minimise frontrunning, the same can be achieved through a time based delay. This provides a win-win-win scenario in that traders receive a better user experience as they have a higher level of confidence their trade will be fulfilled/fulfilled faster, while capitalising on lower fees, and the protocol sees the same benefit to frontrunning as in next price.

Note that next-price is not removed, but incorporated into delayed orders. That is, although time is preferential, if a price update occurs before the delay is reached, the order will still be executable.

Cross Side Maker/Taker Fees

Order fee calculations in the current state do not behave correctly in the scenario where a trade is both a maker and a taker. This can happen when the size of the trade pushes the market skew past equilibrium and into the opposing direction. As a result, fees are miscalculated because the proportion of size in the opposite direction is calculated against a maker fee when it should in fact be a taker fee.



Both features are implemented on top of the existing PerpsV2 duplicated smart contracts and do not change any existing contracts deployed and used in real environments. Aside from renames and the addition of new values configurable by SCCP, all delayed order public API changes are isolated to PerpsV2MarketDelayedOrders.sol. All existing functionality around submission, cancellation, and execution of orders will be updated to incorporate time.

Order fee calculations are even simpler in that changes are isolated to PerpsV2MarketBase.sol._orderFee, utilising existing helper functions for calculations.

Technical Specification

Delayed Orders

The are two primary changes introduced as part of delayed orders. First, the rename of nextPrice to delayedOrder and second, the addition of a new parameter upon submission.

Usage is as follows:

interface IPerpsV2MarketDelayedOrders {
    function submitDelayedOrder(int sizeDelta, uint desiredTimeDelta) external;

    function submitDelayedOrderWithTracking(
        int sizeDelta,
        uint desiredTimeDelta,
        bytes32 trackingCode
    ) external;

    function cancelDelayedOrder(address account) external;

    function executeDelayedOrder(address account) external;

desiredTimeDelta is the additional parameter. It behaves as follows:

  1. A trader must specify the desired amount of time (in seconds) to wait before this trade is executable by a keeper or otherwise
  2. desiredTimeDelta must be between two bounds (minTimeDelta and maxTimeDelta, inclusive)
  3. When desiredTimeDelta=0 then minTimeDelta will be used
  4. A revert will occur if desiredTimeDelta is greater than or less than the min/max delta respectively

Note submitDelayedOrderWithTracking is subsequently also updated to include a desiredTimeDelta parameter.

To incorporate time, delayed orders also track when they can be executable. This can be seen by the addition of the new executableAtTime attribute:

struct DelayedOrder {
    int128 sizeDelta;
    uint128 targetRoundId;
    uint128 targetRoundId;
    uint128 commitDeposit;
    uint128 keeperDeposit;
    uint256 executableAtTime; // The timestamp at which this order is executable at
    bytes32 trackingCode;

In addition to the public API, internal references to nextPrice are also replaced. This includes events. The only exception is nextPriceConfirmWindow as this is still used.

Finally, a delayedOrderConfirmWindow to also be included. It behaves similar to nextPriceConfirmWindow but with respect to time. Currently, an order's confirmation window is considered 'over' if the price feed is updated more than n times where n = numberOfRounds since the specified targetRoundId. To incorporate time, the confirmation predicate will consider, n' where n' = numberOfSecondsSinceOrderWasExecutable together with n. In short a confirm window is also considered 'over' if,

(block.timestamp - executableAtTime) > n'

Cross Side Maker/Taker Fees

There are no changes to the public API. Instead, an internal _orderFee function is updated to incorporate taker fees for the proportion that increases the skew after it is flipped.

Test Cases

Relevant tests will be developed during implementation.

Configurable Values (Via SCCP)

delayedOrdersMinTimeDelta and delayedOrdersMaxTimeDelta values to be added to bound the desiredTimeDelta delay. delayedOrderConfirmWindow as described above to be added. Additionally, takerFeeNextPrice and makerFeeNextPrice, two existing values are renamed to takerFeeDelayedOrder and makerFeeDelayedOrder.

In total 3 new values and 2 values to be renamed. All values are configurable at the market level.

Copyright and related rights waived via CC0.