Skip to Content

Protocol Guard Rails

Oracle Validity

Velocity Protocol’s dependence on external oracle accounts requires thoughtful consideration of the data point in the streams received.

In the program [code] , this is encoded as a spectrum from Valid to Invalid, with a few different categories of questionability that depend on the action taken (ordered by severity):

  • NonPositive

  • TooVolatile

  • TooUncertain

  • StaleForMargin

  • InsufficientDataPoints

  • StaleForAMM

  • Valid

The processing of new data is as follows:

Retrieve new data point

Obtain the latest oracle data point.

Sanitize new data point

Sanitize the retrieved data before using it in calculations.

Check validity of the new data point vs the pre-refresh state

Determine the data point’s validity category by comparing the sanitized data against the state as it stood before this update (the pre-refresh TWAP). Computing validity first, against the old state, stops a single too-volatile or too-divergent data point from being able to drag the TWAP toward itself and then pass its own gate within the same instruction.

Update state variables

Only if the validity verdict permits it (i.e. it resolves to UpdateTwap), advance the relevant on-chain state (e.g., TWAP-related state) with the sanitized input.

Processing data this way is meant to prevent a single new data point from creating a shock to the state variables (i.e. TWAP). A complete list of block conditions for actions is described.

Notes:

  • The on-chain oracle TWAP calculation will also be shrunk proportional to the duration of the invalid period to avoid erroneous funding payment magnitudes.

  • Blocking on InsufficientDataPoints can help improve resiliency against oracle manipulation.

Oracle Divergence

Velocity runs two separate oracle-divergence circuit breakers for perpetual markets:

Mark vs 5-minute oracle TWAP. validate_market_within_price_band checks that the AMM reserve (mark) price is within the greater of the market’s configured divergence threshold or 10% (a protocol-wide floor) of the 5-minute oracle TWAP (see PriceDivergenceGuardRails for exact parameters). This check gates:

  • settle_pnl

  • resolve_perp_pnl_deficit

  • draining the PnL pool’s fee sweep

  • VLP hedge settlement

Live oracle vs 5-minute oracle TWAP. Filling an order (fill_order) is gated by a separate check comparing the current oracle price to the 5-minute oracle TWAP, with a threshold floored at 50% (not 10%). A fill that breaches this band is skipped rather than reverted, so the order simply doesn’t fill until the price reverts back within the band. Order placement itself is not gated by either band.

Its important to note that:

  1. amm reserve price always update with valid oracle data for amm and;

  2. new data points for 5-minute oracle twap are sanitized to be within 10%, 20%, or 50% of the last twap value for tiers A, B, and C respectively, or ~33% by default for Speculative, Highly Speculative, and Isolated tiers (see Contract Tiers)

Thus, it may take multiple intervals to bypass these circuit breakers for sufficiently large price moves.

For spot markets, there are safety initial margin requirement checks for withdraw (spot order placement has been removed on Velocity; see Block Conditions).

A user’s asset / liabilities when calculating total collateral for initial margin checks for withdraws will be the lesser / greater (respectively) of the 5-minute oracle twap and current oracle price. This lowers leverage extended by the protocol to users with positions in volatile markets.

Exchange & Market Status

ExchangeStatus and MarketStatus can be updated to prevent certain actions when specific issues are identified. These actions can include:

  • funding rate updates;

  • liquidations;

  • AMM fills;

  • any fills; and

  • withdraws

Solvency Status

Independent of the general exchange pause bits above, Velocity tracks a separate State.solvencyStatus bitflag. Resolving bad debt (resolve_perp_pnl_deficit, resolve_perp_bankruptcy, resolve_spot_bankruptcy) is gated by a dedicated “solvency repair” pause bit rather than the general withdraw-pause bit, so an admin can pause withdrawals without also blocking bankruptcy resolution (or vice versa). Only the cold-admin key can flip solvency status, via update_solvency_status.

Withdraw Guard Threshold

Each spot market has a per-market withdraw guard threshold that limits how much net token outflow can occur in a short window before withdrawals for that market are paused pending admin review. Setting this threshold now requires passing the market’s oracle account, and the protocol rejects any threshold worth more than $10,000 notional (priced at the max of the live oracle price and its 5-minute TWAP), a cap intended to keep the guard rail from being configured into uselessness. Setting this threshold can be done by the warm or cold admin key (check_warm). Swapping a spot market’s oracle (which re-prices this notional cap) is a stricter, cold-admin-only operation (check_cold).

Last updated on