DocsConcepts

Risk Engine (Concept)

The deterministic, fail-closed rule set every copy must pass — twice.

Plain English

Before the desk copies any trade, the trade goes through a fixed list of questions, in a fixed order:

  1. Is this desk configured?
  2. Is this exact token allowed for this desk?
  3. Is the market open? (And which session are we in?)
  4. Is the price fresh — or missing, zero, or from the future?
  5. Is the desk in a drawdown halt?
  6. How big may the copy be — after the session multiplier, the per-fill cap, the per-position cap, the gross-exposure cap, and the cash the vault actually has?

Any "no" or "unknown" ends the trade. There is no override and no discretion: the same inputs always produce the same decision, and every decision carries a human-readable reason.

Technically

The rules exist twice, deliberately:

  • On-chain: RiskModule.evaluate(CheckInput) — a pure view function. DeskVault.executeCopy calls it in the same transaction as the swap and reverts unless it returns Accept. This is the enforcement layer.
  • Off-chain: evaluateRisk in the keeper (keeper/src/executor.ts) — a TypeScript port used to decide whether to submit at all and to record the reason on the tape. This is the explanation layer.

The decision type

On-chain, evaluation returns (decision, allowedSizeUsdg, reason):

  • Reject with a reason string — the vault reverts with "risk rejected".
  • Accept with allowedSizeUsdg ≤ requestedSize — the vault swaps exactly the allowed size.

The keeper mirrors this as accept / resize / skip outcomes on the fill tape.

The rules, in evaluation order

#RuleFailure reason
1Desk configureddesk not configured
2Token allowlisted for this desktoken not allowed
3Session not closedsession closed
4Session multiplier configuredsession not tradable
5Price not from the futureprice in future
6Price age ≤ maxStalenessSec (default 120s)price stale
7Drawdown from high-water < maxDrawdownBps (default 2000 = 20%)drawdown halt
8Requested size > 0zero size
9Session-sized amount > 0size rounds to zero
10Clamp to per-fill cap(resize)
11Buys: clamp to position-cap headroom, reject if noneposition cap reached
12Buys: clamp to gross-exposure headroom, reject if nonegross cap reached
13Sells: require an existing position, clamp to its valueno position to sell
14Final size > 0size reduced to zero

The keeper adds one more practical clamp the pure on-chain function leaves to a revert: cash availability (a buy is resized down to the vault's free USDG; on-chain, insufficient cash reverts the swap).

Deep dive with parameters, defaults and citations: Risk Engine section.