Mode transitions are managed by the
ModeController contract. In the M2 (External Testnet) deployment, mode changes are controlled by admin roles. M3 plans include multi-sig governance for mode transitions and automated escalation based on additional risk metrics.Operating Modes
The four modes form an escalation path from normal operations to full pause:NORMAL (0)
All operations available. This is the default operating state. Traders can open, close, increase, and reduce positions. LPs can deposit and withdraw. Settlements and liquidations proceed normally.
DEGRADED (1)
Restricted operations. New position opens and increases are blocked. Closes, reductions, margin adjustments, settlements, and liquidations continue. Entered when oracle degradation is detected.
REDUCE_ONLY (2)
Wind-down mode. Same restrictions as DEGRADED — no new positions or increases. Designed for administrative wind-down scenarios where the protocol needs to reduce exposure without full pause.
PAUSED (3)
All operations suspended. No trading, no settlements, no liquidations, no deposits, no withdrawals. This is the emergency mode for severe oracle failures or critical incidents.
Operation Restriction Matrix
Each mode progressively restricts available operations:| Operation | NORMAL | DEGRADED | REDUCE_ONLY | PAUSED |
|---|---|---|---|---|
openPosition | Yes | No | No | No |
increasePosition | Yes | No | No | No |
closePosition | Yes | Yes | Yes | No |
reducePosition | Yes | Yes | Yes | No |
addPositionMargin | Yes | Yes | Yes | No |
removePositionMargin | Yes | Yes | Yes | No |
settleMatured | Yes | Yes | Yes | No |
liquidate | Yes | Yes | Yes | No |
| Vault deposit | Yes | Yes | Yes | No |
| Vault withdraw | Yes | Yes | Yes | No |
State Transition Diagram
Transition Functions
- Pause Controls
- Admin Controls
- Automated Controls
| Transition | Function | Required Role |
|---|---|---|
| Any (except PAUSED) to PAUSED | enterPausedMode(reasonCode) | PAUSER_ROLE |
| PAUSED to NORMAL or REDUCE_ONLY | exitPausedMode(target, reasonCode) | PAUSER_ROLE |
PAUSER_ROLE can enter pause from any non-paused mode. This is the emergency brake. When exiting pause, the operator specifies the target mode (either NORMAL or REDUCE_ONLY). The protocol cannot exit pause directly into DEGRADED mode.Auto-Escalation
ThecheckOracleAndPause() function implements automated mode transitions based on oracle health. It is designed to be called periodically by the keeper service or by any holder of PAUSER_ROLE.
Check Oracle Validity
The function calls
oracleModule.isOracleValid() via staticcall to determine if the oracle is providing fresh, valid forward prices.Oracle Invalid Path
If the oracle is invalid (stale forward prices, disabled pair, or no forward ever published):
- From NORMAL or DEGRADED: escalate to PAUSED with reason
ORACLE_INVALID - From REDUCE_ONLY: escalate to PAUSED with reason
ORACLE_INVALID - Already PAUSED: no change
Oracle Valid + DEGRADED Path
If the oracle is valid and the current mode is DEGRADED, two sub-checks occur:
- Duration check: If
degradedEnteredAt + degradedDurationSeconds <= block.timestamp, the degraded state has lasted too long. Escalate to PAUSED with reasonDEGRADED_TIMEOUT. - Recovery: If the duration has not been exceeded, recover to NORMAL with reason
ORACLE_RECOVERED.
Reason Codes
Every mode transition includes a reason code for auditability and monitoring. Reason codes arebytes32 values computed as keccak256 hashes:
| Reason Code | Value | Trigger |
|---|---|---|
REASON_ADMIN | keccak256("ADMIN") | Manual admin action (pause, unpause, mode change) |
REASON_ORACLE_INVALID | keccak256("ORACLE_INVALID") | Oracle staleness detected by checkOracleAndPause() |
REASON_ORACLE_DEGRADED | keccak256("ORACLE_DEGRADED") | Oracle price deviation above degradedThresholdBps |
REASON_ORACLE_RECOVERED | keccak256("ORACLE_RECOVERED") | Oracle recovered from degraded state |
REASON_DEGRADED_TIMEOUT | keccak256("DEGRADED_TIMEOUT") | Degraded mode duration exceeded without recovery |
Degraded Mode Configuration
DEGRADED mode has its own configuration parameters that control how the protocol behaves when oracle quality is reduced:| Parameter | Default | Description |
|---|---|---|
degradedThresholdBps | 500 (5%) | Price deviation threshold to trigger degraded mode |
degradedDurationSeconds | 3,600 (1 hour) | Maximum time in degraded mode before auto-escalation to PAUSED |
autoDegradeOnDeviation | true | Whether to automatically enter degraded mode on price deviation |
Why a 1-hour degraded timeout?
Why a 1-hour degraded timeout?
DEGRADED mode is a temporary state designed for transient oracle issues. If the oracle cannot recover within one hour, the issue is likely more serious than a temporary glitch. The 1-hour timeout ensures that a “stuck” degraded state does not persist indefinitely with reduced risk protection. The auto-escalation to PAUSED forces human intervention to investigate and resolve the root cause.
What happens to open positions during DEGRADED mode?
What happens to open positions during DEGRADED mode?
Open positions remain active. Traders can close positions, reduce exposure, and adjust margin. Settlements and liquidations continue normally. The key restriction is that no new positions can be opened and no existing positions can be increased. This prevents traders from taking on new exposure with potentially degraded oracle quality.
How does DEGRADED differ from REDUCE_ONLY?
How does DEGRADED differ from REDUCE_ONLY?
Both modes block new position opens and increases. The primary difference is the trigger and intent:
- DEGRADED is triggered by oracle quality issues and has an automatic timeout that escalates to PAUSED. It includes a
degradedEnteredAttimestamp for duration tracking. - REDUCE_ONLY is an administrative decision (e.g., planned wind-down, risk parameter change) with no automatic timeout. It persists until explicitly toggled back to NORMAL.
Can the protocol go directly from NORMAL to PAUSED?
Can the protocol go directly from NORMAL to PAUSED?
Yes. The
enterPausedMode() function can be called from any non-paused mode, including NORMAL. This is the emergency brake for critical situations that require immediate halting of all operations. Additionally, checkOracleAndPause() can escalate directly from NORMAL to PAUSED if the oracle becomes invalid.Escalation Scenarios
- Publisher Goes Down
- Price Deviation Detected
- Admin Emergency
- Publisher stops sending forward price updates
- Forward price becomes stale after 60 seconds (
maxForwardAge) isOracleValid()returnsfalsecheckOracleAndPause()escalates to PAUSED withORACLE_INVALID- Admin investigates, restarts publisher
- Publisher resumes updates, prices become fresh
- Admin calls
exitPausedMode(NORMAL, REASON_ADMIN)to resume operations
M2 vs M3 Governance
In the current M2 deployment, mode transitions are controlled by EOA (Externally Owned Account) addresses assigned the
PAUSER_ROLE and DEFAULT_ADMIN_ROLE. This provides fast response times but relies on trust in the protocol operators.For M3 (Mainnet Ready), the plan includes:- Multi-sig governance for admin mode transitions (timelock + multi-sig)
- Automated oracle monitoring with onchain health metrics
- Decentralized keeper network for
checkOracleAndPause()calls - Graduated pause powers with different timelocks for different severity levels