Skip to main content

Safety Mechanisms

Olla uses multiple layers of protection to safeguard user assets: automatic circuit breakers, a guardian role for manual intervention, and a governance timelock for parameter changes.

Circuit breakers

The SafetyModule monitors protocol health and automatically pauses operations when predefined thresholds are breached. It runs three independent checks:

Rate drop breaker

Triggers when the exchange rate drops by more than a configured threshold between accounting updates. A sudden rate drop typically indicates a slashing event on the Aztec rollup.

ParameterRangeSetter
minRateDropBps1 – 5,000 bps (0.01% – 50%)setMinRateDropBps()

When it fires: During updateAccounting(), the protocol compares the new exchange rate against the previous one. If the drop exceeds minRateDropBps, the circuit breaker triggers and pauses the protocol.

Queue ratio breaker

Triggers when pending withdrawal requests grow too large relative to total protocol assets. High queue pressure may indicate a bank-run scenario or an impending liquidity crisis.

ParameterRangeSetter
maxQueueRatioBps100 – 9,000 bps (1% – 90%)setMaxQueueRatioBps()

When it fires: During rebalance (step 3: finalize withdrawals) and during updateAccounting(), the protocol checks queued assets / total assets. If it exceeds maxQueueRatioBps, the breaker triggers.

Accounting staleness breaker

Triggers when too much time passes without an accounting update. Stale accounting means the exchange rate doesn't reflect current on-chain state, which could mask slashing or reward changes.

ParameterRangeSetter
maxAccountingDelay1 hour – 7 dayssetMaxAccountingDelay()

When it fires: During deposit and withdrawal operations, the protocol checks how long it's been since the last accounting update. If the elapsed time exceeds maxAccountingDelay, the breaker triggers.

What happens when a breaker triggers

When any circuit breaker fires, the SafetyModule:

  1. Sets its internal paused flag to true.
  2. Emits a CircuitBreakerTriggered(reason) event identifying which breaker fired.
  3. Emits a Paused() event.

While paused, the protocol blocks:

  • New deposits
  • Instant redemptions
  • New withdrawal requests

Existing queued withdrawals that are already finalized can still be claimed. Rebalance cycles in progress can still be continued. The guardian must manually unpause after investigating the cause.

Guardian role

The guardian is a privileged role (expected to be a multisig) that can respond to emergencies faster than governance. The guardian holds GUARDIAN_ROLE on OllaCore, OllaVault, and SafetyModule.

Guardian capabilities

ActionContractPurpose
pause()OllaCoreHalt rebalancing and staking operations
unpause()OllaCoreResume operations after investigation
pause()OllaVaultHalt deposits, redemptions, and withdrawals
unpause()OllaVaultResume vault operations
pause()SafetyModuleManually trigger protocol-wide pause
unpause()SafetyModuleResume after circuit breaker or manual pause
forceRebalanceReset()OllaCoreReset a stuck rebalance state machine

What the guardian cannot do

The guardian is deliberately separated from governance to limit blast radius:

  • Cannot upgrade contracts
  • Cannot change fee parameters
  • Cannot grant or revoke roles
  • Cannot move user funds
  • Cannot change the treasury or provider addresses

These actions require governance (the timelock), giving the community time to react.

Force rebalance reset

If a rebalance cycle gets stuck mid-execution (e.g., due to an external contract failure), the guardian can call forceRebalanceReset() to reset the state machine back to Done. This discards any in-progress work for that cycle:

  • Unharvested rewards are not lost — they wait for the next cycle.
  • Partial unstakes are tracked on-chain by the rollup and will be picked up in the next refreshAttesterState() call.

The reset also updates lastRebalanceTimestamp, so the cooldown must elapse before a new cycle can start.

Deposit cap

Governance can set a maximum total deposit to limit protocol exposure during early operation or risk events.

ParameterSetter
depositCapsetDepositCap(uint256)

When set, checkDepositAllowed() rejects deposits that would push total assets above the cap. Setting the cap to type(uint256).max effectively disables it.

Withdrawal minimum

To prevent dust withdrawals that waste gas, governance can set a minimum share amount for withdrawal requests.

ParameterRangeSetter
withdrawalMinimum0 – 1,000e18 sharessetWithdrawalMinimum(uint256)

Both queued withdrawals (requestRedeem) and instant redemptions (instantRedeem) enforce this minimum.

Governance timelock

All governance actions — fee changes, parameter updates, contract upgrades, role grants — flow through OllaGovernance, which embeds a TimelockController. Actions must be:

  1. Scheduled by the governance admin (proposer role).
  2. Delayed for the configured timelock duration.
  3. Executed by the governance admin (executor role) after the delay.

This gives the community a window to review proposed changes and react (e.g., by exiting the protocol) before they take effect. The only exceptions are emergencyPauseAll() and emergencyUnpauseAll(), which bypass the timelock for rapid incident response.

Non-upgradeable SafetyModule

The SafetyModule is intentionally not upgradeable via UUPS proxy. This is a deliberate trust decision: as the protocol's circuit breaker, users need confidence that its behavior cannot be silently changed through a proxy upgrade. If the SafetyModule needs to be replaced, governance uses OllaCore.setSafetyModule() to point to a new deployment — a visible, auditable action that requires the protocol to be unpaused with no active rebalance.

See Trust Assumptions for the full security model.