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):
-
Invalid
-
TooVolatile
-
TooUncertain
-
InsufficientDataPoints
-
StaleForMargin
-
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.
Update state variables
Update the relevant on-chain state (e.g., TWAP-related state) with sanitized inputs.
Check validity of unsanitized new data point vs updated state
Validate the unsanitized new data point against the updated state to determine its validity category.
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
For perpetuals markets, there are checks to validate_market_within_price_band for the following actions:
-
fill_order -
settle_pnl -
resolve_perp_pnl_deficit
The check validates that the 5-minute oracle twap vs amm reserve price is within ~10% (see PriceDivergenceGuardRails for exact parameters).
Its important to note that:
-
amm reserve price always update with valid oracle data for amm and;
-
new data points for 5-minute oracle twap are sanitized to be within 10, 20, or 50% of the last twap value (depending on the
ContractTier)
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 the following actions:
-
place_order -
withdraw
A user’s asset / liabilities when calculating total collateral for initial margin checks for withdraws and placing orders 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. Swapping a spot market’s oracle (which re-prices this notional cap) and setting its withdraw guard threshold are both cold-admin-only operations.