Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

OrderRouter

Git Source

Inherits: Ownable2Step, Pausable, OrderEscrowAccounting

Title: OrderRouter (The MEV Shield)

Manages Commit-Reveal, MEV protection, and the un-brickable FIFO queue.

Holds only non-trader-owned keeper execution reserves. Trader collateral remains in MarginClearinghouse.

Note: security-contact: contact@plether.com

Constants

PANIC_SELECTOR

bytes4 internal constant PANIC_SELECTOR = 0x4e487b71

TYPED_ORDER_FAILURE_SELECTOR

bytes4 internal constant TYPED_ORDER_FAILURE_SELECTOR = ICfdEngine.CfdEngine__TypedOrderFailure.selector

MARK_PRICE_OUT_OF_ORDER_SELECTOR

bytes4 internal constant MARK_PRICE_OUT_OF_ORDER_SELECTOR = ICfdEngine.CfdEngine__MarkPriceOutOfOrder.selector

vault

ICfdVault internal immutable vault

TIMELOCK_DELAY

uint256 public constant TIMELOCK_DELAY = 48 hours

MIN_ENGINE_GAS

uint256 internal constant MIN_ENGINE_GAS = 600_000

MIN_MEV_PUBLISH_DELAY

uint256 internal constant MIN_MEV_PUBLISH_DELAY = 5

DEFAULT_MAX_ORDER_AGE

uint256 internal constant DEFAULT_MAX_ORDER_AGE = 60

MAX_EXPIRED_ORDER_SKIPS_PER_CALL

uint256 internal constant MAX_EXPIRED_ORDER_SKIPS_PER_CALL = 32

MAX_BATCH_ORDER_SCANS

uint256 internal constant MAX_BATCH_ORDER_SCANS = 64

MAX_PRUNE_ORDERS_PER_CALL

uint256 internal constant MAX_PRUNE_ORDERS_PER_CALL = 64

RETRYABLE_SKIP_COOLDOWN

uint64 internal constant RETRYABLE_SKIP_COOLDOWN = 5

OPEN_ORDER_EXECUTION_BOUNTY_BPS

uint256 internal constant OPEN_ORDER_EXECUTION_BOUNTY_BPS = 1

MIN_OPEN_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant MIN_OPEN_ORDER_EXECUTION_BOUNTY_USDC = 50_000

MAX_OPEN_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant MAX_OPEN_ORDER_EXECUTION_BOUNTY_USDC = DecimalConstants.ONE_USDC

CLOSE_ORDER_EXECUTION_BOUNTY_USDC

uint256 internal constant CLOSE_ORDER_EXECUTION_BOUNTY_USDC = DecimalConstants.ONE_USDC

MAX_PENDING_ORDERS

uint256 public constant MAX_PENDING_ORDERS = 5

State Variables

pyth

IPyth public pyth

pythFeedIds

bytes32[] public pythFeedIds

quantities

uint256[] public quantities

basePrices

uint256[] public basePrices

inversions

bool[] public inversions

nextCommitId

uint64 public nextCommitId = 1

nextExecuteId

uint64 public nextExecuteId = 1

maxOrderAge

uint256 public maxOrderAge

pendingMaxOrderAge

uint256 public pendingMaxOrderAge

maxOrderAgeActivationTime

uint256 public maxOrderAgeActivationTime

orderExecutionStalenessLimit

uint256 public orderExecutionStalenessLimit = 60

pendingOrderExecutionStalenessLimit

uint256 public pendingOrderExecutionStalenessLimit

orderExecutionStalenessActivationTime

uint256 public orderExecutionStalenessActivationTime

liquidationStalenessLimit

uint256 public liquidationStalenessLimit = 15

pendingLiquidationStalenessLimit

uint256 public pendingLiquidationStalenessLimit

liquidationStalenessActivationTime

uint256 public liquidationStalenessActivationTime

claimableEth

mapping(address => uint256) public claimableEth

pendingHeadOrderId

mapping(bytes32 => uint64) public pendingHeadOrderId

pendingTailOrderId

mapping(bytes32 => uint64) public pendingTailOrderId

globalTailOrderId

uint64 public globalTailOrderId

Functions

onlyEngine

modifier onlyEngine() ;

constructor

constructor(
    address _engine,
    address _vault,
    address _pyth,
    bytes32[] memory _feedIds,
    uint256[] memory _quantities,
    uint256[] memory _basePrices,
    bool[] memory _inversions
) Ownable(msg.sender) OrderEscrowAccounting(_engine);

Parameters

NameTypeDescription
_engineaddressCfdEngine that processes trades and liquidations
_vaultaddressCfdVault used for vault depth queries and liquidation bounty payouts
_pythaddressPyth oracle contract (address(0) enables mock mode on Anvil)
_feedIdsbytes32[]Pyth price feed IDs for each basket component
_quantitiesuint256[]Weight of each component (must sum to 1e18)
_basePricesuint256[]Base price per component for normalization (8 decimals)
_inversionsbool[]Whether to invert each feed (e.g. USD/JPY -> JPY/USD)

proposeMaxOrderAge

Proposes a new maxOrderAge value, subject to 48h timelock.

function proposeMaxOrderAge(
    uint256 _maxOrderAge
) external onlyOwner;

finalizeMaxOrderAge

Finalizes the pending maxOrderAge after timelock expires.

function finalizeMaxOrderAge() external onlyOwner;

cancelMaxOrderAgeProposal

Cancels the pending maxOrderAge proposal.

function cancelMaxOrderAgeProposal() external onlyOwner;

proposeOrderExecutionStalenessLimit

function proposeOrderExecutionStalenessLimit(
    uint256 limit
) external onlyOwner;

finalizeOrderExecutionStalenessLimit

function finalizeOrderExecutionStalenessLimit() external onlyOwner;

cancelOrderExecutionStalenessLimitProposal

function cancelOrderExecutionStalenessLimitProposal() external onlyOwner;

proposeLiquidationStalenessLimit

function proposeLiquidationStalenessLimit(
    uint256 limit
) external onlyOwner;

finalizeLiquidationStalenessLimit

function finalizeLiquidationStalenessLimit() external onlyOwner;

cancelLiquidationStalenessLimitProposal

function cancelLiquidationStalenessLimitProposal() external onlyOwner;

pause

function pause() external onlyOwner;

unpause

function unpause() external onlyOwner;

commitOrder

Submits a trade intent to the FIFO queue. Margin and the order’s execution bounty are reserved immediately.

function commitOrder(
    CfdTypes.Side side,
    uint256 sizeDelta,
    uint256 marginDelta,
    uint256 targetPrice,
    bool isClose
) external;

Parameters

NameTypeDescription
sideCfdTypes.SideBULL or BEAR
sizeDeltauint256Position size change (18 decimals)
marginDeltauint256Margin to add or remove (6 decimals, USDC)
targetPriceuint256Slippage limit price (8 decimals, 0 = market order)
isCloseboolTrue to allow execution even when paused or in FAD close-only mode

quoteOpenOrderExecutionBountyUsdc

Quotes the reserved USDC execution bounty for a new open order using the latest engine mark price.

Falls back to 1.00 USD if the engine has not observed a mark yet. Result is floored at 0.05 USDC and capped at 1 USDC for non-close intents.

function quoteOpenOrderExecutionBountyUsdc(
    uint256 sizeDelta
) external view returns (uint256 executionBountyUsdc);

Parameters

NameTypeDescription
sizeDeltauint256Order size in 18-decimal notional units

Returns

NameTypeDescription
executionBountyUsdcuint256Reserved execution bounty in 6-decimal USDC units

quoteCloseOrderExecutionBountyUsdc

Quotes the flat reserved USDC execution bounty for a close order.

function quoteCloseOrderExecutionBountyUsdc() external pure returns (uint256 executionBountyUsdc);

orders

function orders(
    uint64 orderId
) external view returns (bytes32, uint256, uint256, uint256, uint64, uint64, uint64, CfdTypes.Side, bool);

committedMargins

function committedMargins(
    uint64 orderId
) external view returns (uint256);

executionBountyReserves

function executionBountyReserves(
    uint64 orderId
) external view returns (uint256);

isInMarginQueue

function isInMarginQueue(
    uint64 orderId
) external view returns (bool);

getOrderRecord

function getOrderRecord(
    uint64 orderId
) external view returns (OrderRecord memory);

syncMarginQueue

Returns the total queued escrow state for an account across all pending orders.

function syncMarginQueue(
    bytes32 accountId
) external onlyEngine;

getPendingOrdersForAccount

function getPendingOrdersForAccount(
    bytes32 accountId
) external view returns (IOrderRouterAccounting.PendingOrderView[] memory pending);

executeOrder

Keeper executes the current global queue head. Validates oracle freshness and publish-time ordering against the order commit, checks slippage, then delegates to CfdEngine. Terminal invalid/expired orders pay from router-custodied execution bounty, while retryable slippage misses are requeued to the global tail with cooldown so keepers cannot burn out-of-market intents or pin the FIFO head.

function executeOrder(
    uint64 orderId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
orderIduint64Must equal the current global queue head (expired orders are auto-skipped)
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

executeOrderBatch

Executes queued pending orders against a single Pyth price tick. Updates Pyth once, then loops through the FIFO queue. Aggregates reserved USDC execution bounties across processed orders and refunds excess ETH in a single transfer.

function executeOrderBatch(
    uint64 maxOrderId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
maxOrderIduint64Inclusive upper bound on committed order ids the batch may begin processing from
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

_skipStaleOrders

function _skipStaleOrders(
    uint64 upToId,
    uint256 maxSkips
) internal returns (uint256 skipped);

_currentRouterExecutionContext

function _currentRouterExecutionContext() internal view returns (RouterExecutionContext memory context);

_routedCloseOnlyFailure

function _routedCloseOnlyFailure(
    CfdTypes.Order memory order,
    bool oracleFrozen,
    bool isFadWindow,
    bool degradedMode,
    bool closeOnly
) internal pure returns (OrderFailurePolicyLib.FailureContext memory failure);

_processTypedOrderExecution

function _processTypedOrderExecution(
    CfdTypes.Order memory order,
    uint256 executionPrice,
    uint256 vaultDepth,
    uint64 oraclePublishTime,
    bool oracleFrozen,
    bool isFadWindow,
    bool degradedMode
)
    internal
    returns (
        bool success,
        OrderFailReason failureReason,
        OrderFailurePolicyLib.FailedOrderBountyPolicy failureBountyPolicy
    );

pruneExpiredOrders

function pruneExpiredOrders(
    uint64 upToId,
    uint256 maxPrunes
) external;

_resolveOraclePrice

function _resolveOraclePrice(
    bytes[] calldata pythUpdateData,
    uint256 mockFallbackPrice
) internal returns (uint256 price, uint64 publishTime, uint256 pythFee);

_sendEth

function _sendEth(
    address to,
    uint256 amount
) internal;

_pendingOrder

function _pendingOrder(
    uint64 orderId
) internal view returns (OrderRecord storage record, CfdTypes.Order memory order);

_getQueuedPositionView

function _getQueuedPositionView(
    bytes32 accountId
) internal view returns (QueuedPositionView memory queuedPosition);

_failedOrderBountyPolicy

function _failedOrderBountyPolicy(
    OrderFailurePolicyLib.FailureContext memory context
) internal pure returns (OrderFailurePolicyLib.FailedOrderBountyPolicy);

_decodeTypedOrderFailure

function _decodeTypedOrderFailure(
    bytes memory revertData
)
    internal
    pure
    returns (CfdEnginePlanTypes.ExecutionFailurePolicyCategory failureCategory, uint8 failureCode, bool isClose);

_cleanupOrder

function _cleanupOrder(
    uint64 orderId,
    bool success,
    OrderFailurePolicyLib.FailedOrderBountyPolicy failedPolicy
) internal returns (uint256 executionBountyUsdc);

_finalizeExecution

function _finalizeExecution(
    uint64 orderId,
    uint256 pythFee,
    bool success,
    OrderFailurePolicyLib.FailedOrderBountyPolicy failedPolicy
) internal;

_routedExpiryFailure

function _routedExpiryFailure(
    CfdTypes.Order memory order
) internal view returns (OrderFailurePolicyLib.FailureContext memory context);

_routedRouterPolicyFailure

function _routedRouterPolicyFailure(
    CfdTypes.Order memory order,
    OrderFailurePolicyLib.RouterFailureCode failureCode,
    bool oracleFrozen,
    bool isFad,
    bool degradedMode,
    bool closeOnly
) internal pure returns (OrderFailurePolicyLib.FailureContext memory context);

_routedFailureFromEngineRevert

function _routedFailureFromEngineRevert(
    CfdTypes.Order memory order,
    bytes memory revertData,
    bool oracleFrozen,
    bool isFad,
    bool degradedMode
) internal pure returns (OrderFailurePolicyLib.FailureContext memory context);

_payOrDeferLiquidationBounty

Immediate liquidation bounties still pay directly to the executing keeper wallet. If immediate payment is unavailable or direct transfer fails, the bounty is deferred and later settles as clearinghouse credit via claimDeferredClearerBounty().

function _payOrDeferLiquidationBounty(
    uint256 liquidationBountyUsdc
) internal;

_forfeitEscrowedOrderBountiesOnLiquidation

function _forfeitEscrowedOrderBountiesOnLiquidation(
    bytes32 accountId
) internal;

_clearLiquidatedAccountOrders

function _clearLiquidatedAccountOrders(
    bytes32 accountId
) internal;

_quoteOpenOrderExecutionBountyUsdc

function _quoteOpenOrderExecutionBountyUsdc(
    uint256 sizeDelta,
    uint256 price
) internal pure returns (uint256);

_quoteCloseOrderExecutionBountyUsdc

function _quoteCloseOrderExecutionBountyUsdc() internal pure returns (uint256);

_commitReferencePrice

function _commitReferencePrice() internal view returns (uint256 price);

_canUseCommitMarkForOpenPrefilter

function _canUseCommitMarkForOpenPrefilter() internal view returns (bool);

_linkPendingOrder

function _linkPendingOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_linkGlobalOrder

function _linkGlobalOrder(
    uint64 orderId
) internal;

_unlinkGlobalOrder

function _unlinkGlobalOrder(
    uint64 orderId
) internal;

_skipRetryableOrder

function _skipRetryableOrder(
    uint64 orderId,
    OrderFailReason reason
) internal;

_unlinkPendingOrder

function _unlinkPendingOrder(
    bytes32 accountId,
    uint64 orderId
) internal;

_reserveCloseExecutionBounty

function _reserveCloseExecutionBounty(
    bytes32 accountId,
    uint256 executionBountyUsdc
) internal override;

_deleteOrder

function _deleteOrder(
    uint64 orderId,
    bool advanceHead,
    IOrderRouterAccounting.OrderStatus terminalStatus
) internal;

_releaseCommittedMarginForExecution

function _releaseCommittedMarginForExecution(
    uint64 orderId
) internal;

claimEth

Claims ETH stuck from failed refund transfers.

function claimEth() external;

claimUsdc

Claims USDC bounty refunds that could not be pushed during failed-order cleanup.

function claimUsdc() external;

_computeBasketPrice

function _computeBasketPrice() internal view returns (uint256 basketPrice, uint256 minPublishTime);

_checkSlippage

Opens vs closes have opposing slippage directions: BULL open wants HIGH entry (more room for drop) → exec >= target BULL close wants LOW exit (lock in profit) → exec <= target BEAR open wants LOW entry (more room for rise) → exec <= target BEAR close wants HIGH exit (lock in profit) → exec >= target targetPrice == 0 disables the check (market order).

function _checkSlippage(
    CfdTypes.Order memory order,
    uint256 executionPrice
) internal pure returns (bool);

_isOracleFrozen

Returns true only when FX markets are actually closed and Pyth feeds have stopped publishing. Distinct from isFadWindow() which starts 3 hours earlier for margin purposes. Uses Friday 22:00 UTC (conservative vs 21:00 EDT summer) to guarantee zero latency arbitrage.

function _isOracleFrozen() internal view returns (bool);

_isCloseOnlyWindow

function _isCloseOnlyWindow() internal view returns (bool);

_invertPythPrice

Inverts a Pyth price (e.g. USD/JPY → JPY/USD) and returns 8-decimal output. Formula: 10^(8 - expo) / price

function _invertPythPrice(
    int64 price,
    int32 expo
) internal pure returns (uint256);

_normalizePythPrice

Converts a Pyth price to 8-decimal format. Scales up/down based on exponent difference from -8.

function _normalizePythPrice(
    int64 price,
    int32 expo
) internal pure returns (uint256);

updateMarkPrice

Push a fresh mark price to the engine without processing an order. Required before LP deposits/withdrawals when mark is stale.

function updateMarkPrice(
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

executeLiquidation

Keeper-triggered liquidation using the canonical live-market staleness policy. Forfeits any queued-order execution escrow to the vault instead of crediting it back to trader settlement, then pays the liquidation keeper bounty in USDC directly from the vault.

function executeLiquidation(
    bytes32 accountId,
    bytes[] calldata pythUpdateData
) external payable;

Parameters

NameTypeDescription
accountIdbytes32The account to liquidate (bytes32-encoded address)
pythUpdateDatabytes[]Pyth price update blobs; attach ETH to cover the Pyth fee

_pendingHeadOrderId

function _pendingHeadOrderId(
    bytes32 accountId
) internal view override returns (uint64);

_revertInsufficientFreeEquity

function _revertInsufficientFreeEquity() internal pure override;

_revertMarginOrderLinkCorrupted

function _revertMarginOrderLinkCorrupted() internal pure override;

Events

OrderCommitted

event OrderCommitted(uint64 indexed orderId, bytes32 indexed accountId, CfdTypes.Side side);

OrderExecuted

event OrderExecuted(uint64 indexed orderId, uint256 executionPrice);

OrderFailed

event OrderFailed(uint64 indexed orderId, OrderFailReason reason);

OrderSkipped

event OrderSkipped(uint64 indexed orderId, OrderFailReason reason, uint64 retryAfterTimestamp);

Errors

OrderRouter__ZeroSize

error OrderRouter__ZeroSize();

OrderRouter__CloseMarginDeltaNotAllowed

error OrderRouter__CloseMarginDeltaNotAllowed();

OrderRouter__TimelockNotReady

error OrderRouter__TimelockNotReady();

OrderRouter__NoProposal

error OrderRouter__NoProposal();

OrderRouter__FIFOViolation

error OrderRouter__FIFOViolation();

OrderRouter__OrderNotPending

error OrderRouter__OrderNotPending();

OrderRouter__InsufficientPythFee

error OrderRouter__InsufficientPythFee();

OrderRouter__MockModeDisabled

error OrderRouter__MockModeDisabled();

OrderRouter__NoOrdersToExecute

error OrderRouter__NoOrdersToExecute();

OrderRouter__MaxOrderIdNotCommitted

error OrderRouter__MaxOrderIdNotCommitted();

OrderRouter__OraclePriceTooStale

error OrderRouter__OraclePriceTooStale();

OrderRouter__NothingToClaim

error OrderRouter__NothingToClaim();

OrderRouter__EthTransferFailed

error OrderRouter__EthTransferFailed();

OrderRouter__OraclePriceNegative

error OrderRouter__OraclePriceNegative();

OrderRouter__MevOraclePriceTooStale

error OrderRouter__MevOraclePriceTooStale();

OrderRouter__LengthMismatch

error OrderRouter__LengthMismatch();

OrderRouter__InvalidWeights

error OrderRouter__InvalidWeights();

OrderRouter__InvalidBasePrice

error OrderRouter__InvalidBasePrice();

OrderRouter__EmptyFeeds

error OrderRouter__EmptyFeeds();

OrderRouter__MevDetected

error OrderRouter__MevDetected();

OrderRouter__MissingPythUpdateData

error OrderRouter__MissingPythUpdateData();

OrderRouter__OracleFrozen

error OrderRouter__OracleFrozen();

OrderRouter__InsufficientGas

error OrderRouter__InsufficientGas();

OrderRouter__NoOpenPosition

error OrderRouter__NoOpenPosition();

OrderRouter__CloseSideMismatch

error OrderRouter__CloseSideMismatch();

OrderRouter__CloseSizeExceedsPosition

error OrderRouter__CloseSizeExceedsPosition();

OrderRouter__InsufficientFreeEquity

error OrderRouter__InsufficientFreeEquity();

OrderRouter__MarginOrderLinkCorrupted

error OrderRouter__MarginOrderLinkCorrupted();

OrderRouter__PendingOrderLinkCorrupted

error OrderRouter__PendingOrderLinkCorrupted();

OrderRouter__Unauthorized

error OrderRouter__Unauthorized();

OrderRouter__TooManyPendingOrders

error OrderRouter__TooManyPendingOrders();

OrderRouter__DegradedMode

error OrderRouter__DegradedMode();

OrderRouter__CloseOnlyMode

error OrderRouter__CloseOnlyMode();

OrderRouter__SeedLifecycleIncomplete

error OrderRouter__SeedLifecycleIncomplete();

OrderRouter__TradingNotActive

error OrderRouter__TradingNotActive();

OrderRouter__RetryCooldownActive

error OrderRouter__RetryCooldownActive();

OrderRouter__OraclePublishTimeOutOfOrder

error OrderRouter__OraclePublishTimeOutOfOrder();

OrderRouter__InvalidStalenessLimit

error OrderRouter__InvalidStalenessLimit();

OrderRouter__PredictableOpenInvalid

error OrderRouter__PredictableOpenInvalid(uint8 code);

Structs

QueuedPositionView

struct QueuedPositionView {
    bool exists;
    CfdTypes.Side side;
    uint256 size;
}

RouterExecutionContext

struct RouterExecutionContext {
    bool oracleFrozen;
    bool isFadWindow;
    bool degradedMode;
    OrderOraclePolicyLib.OracleExecutionPolicy policy;
}

Enums

OrderFailReason

enum OrderFailReason {
    Expired,
    CloseOnlyOracleFrozen,
    CloseOnlyFad,
    SlippageExceeded,
    EnginePanic,
    AccountLiquidated,
    EngineRevert
}