Skip to Content
Security & Guardian

Security, guardian, pausing

This page explains:

  • roles (admin vs guardian)
  • pause surfaces
  • what happens when paused
  • how clients and bots should behave

Roles (high level)

Admin (owner):

  • config wiring before freezeConfig
  • timelock-controlled in production
  • cannot use pause surfaces as a substitute for governance

Guardian:

  • fast incident response
  • pause-only or disable-only capabilities
  • in production, expected to be a multisig with strict op policy

Canonical reference:

  • docs/security/roles-and-permissions-matrix-v1.0.0.md

freezeConfig

Most core contracts have:

  • configFrozen flag (public, readable onchain)
  • freezeConfig() onlyOwner (one-way, irreversible)

Two-phase launch model

The protocol launches before freezeConfig(). This is intentional:

  1. Pre-freeze (launch through external audit): The protocol is live and playable. The admin retains the ability to re-wire contract addresses so that fixes from the external security audit can be applied before locking the protocol permanently.
  2. Post-freeze (permanent): The admin calls freezeConfig() on each core contract. After this, wiring cannot be changed. The protocol runs on code alone.

This is a one-way transition. There is no unfreezeConfig().

After configFrozen:

  • wiring cannot be changed (ex: registry address, router pointers, reward vault pointers)
  • guardian pausing still works
  • setGuardian() remains callable (required for guardian key rotation)

What agents and integrators should do:

  • Check configFrozen on core contracts to detect the current phase
  • Pre-freeze: monitor for ConfigFrozen events and re-read contract addresses from the deployment manifest after any wiring change
  • Post-freeze: contract addresses are permanent; no further monitoring needed

Pause surfaces

MineCore: takeoversPaused

Controlled by:

  • MineCore.guardian

Effect when true:

  • takeover() reverts with Errors.TakeoversPaused
  • takeoverWithToken(…) reverts with Errors.TakeoversPaused
  • getTakeoverPrice still works

Mining safety (important):

  • On pause transitions, MineCore clamps currentReignLastAccrualTime to block.timestamp.
  • This means paused time is never mined later.

Furnace: lockingPaused

Controlled by:

  • Furnace.guardian

Effect when true:

  • enterWithEth / enterWithClaim / enterWithToken reverts with Errors.LockingPaused
  • quoteEnterWithEth / quoteEnterWithClaim / quoteEnterWithToken also reverts (same modifier)
  • ShareholderRoyalties claim mode=lock continues to work only when locking is enabled

Optional single-switch wiring:

  • MineCore.setLockingPaused(bool) forwards to Furnace
  • if using forwarding, Furnace.guardian is set to MineCore before freezeConfig

MarketRouter: tradingPaused

Controlled by:

  • MarketRouter.guardian

Effect when true:

  • listLock / listing settlement / bonus target escrow execution reverts with Errors.TradingPaused
  • exits still work:
    • delistLock(tokenId)
    • cancelBonusTargetEscrow(escrowId)
    • emergencyDelist(tokenId) (after 7 days)

EntryTokenRegistry: disable tokens

Controlled by:

  • owner can enable and disable
  • guardian can disable only

Effect:

  • disabled tokens cannot be used for:
    • Furnace.enterWithToken
    • MineCore.takeoverWithToken

WETH is not allowlisted and is always supported via the WETH special-case.

Guardian activation criteria (practical)

The guardian should pause only for clear protocol safety reasons. Common triggers:

  • takeover pricing anomalies (unexpected getTakeoverPrice outputs, reference price corruption)
  • unexpected revert spikes on core paths (takeover, enter, offer acceptance)
  • swap routing anomalies (registry routes mismatching router.poolFor validation)
  • reserve accounting inconsistencies (reserve underflow attempts, abnormal bonus quotes)
  • suspected exploit paths or dependency failures (DEX router issues, pool hijack risk)

What clients should do when paused

UI behavior:

  • detect pause flags and display a clear banner
  • disable affected CTAs
  • keep exit paths available (delist, cancel offer, withdraw balances)

Bot behavior:

  • stop calling:
    • takeovers when takeoversPaused
    • Furnace entry when lockingPaused
    • executeAutoFurnace when tradingPaused
  • keep calling MaintenanceHub.poke() only if the swap paths are safe

User funds safety (important)

  • Pausing does not seize funds.
  • Pausing only prevents new state transitions on the paused surfaces.
  • Pull-based withdrawals remain available:
    • MineCore.withdrawKingBalance
    • MineCore.withdrawRefundBalance
    • MarketRouter.delistLock / cancelBonusTargetEscrow

FAQ for integrators: what happens when guardian pauses?

Takeovers paused (MineCore.takeoversPaused = true):

  • New takeovers revert.
  • The current reign cannot end.
  • Crown emission accrual is clamped at the pause boundary.
    • There is no “backpay” when unpaused.
  • UI should:
    • hide/disable takeover buttons
    • keep price display, history, and Crown ETH withdrawal UX

Locking paused (Furnace.lockingPaused = true):

  • New Furnace entries revert.
  • All Furnace quoteEnterWith* helpers revert.
  • Barons ETH collection still works in mode 0 (Collect ETH).
  • Auto-compound paths behave safely:
    • ShareholderRoyalties auto-compound uses a best-effort call and restores the user’s ETH available to Collect (claimableEth) on revert.
    • LP vault auto-compound keeps rewards intact on revert.
  • UI should:
    • disable lock actions and compounding CTAs
    • keep Collect ETH CTA available

Trading paused (MarketRouter.tradingPaused = true):

  • Market actions revert (listings, listing settlement, bonus target escrow execution).
  • Exits stay open:
    • delistLock, cancelBonusTargetEscrow, emergencyDelist (after 7d)
  • UI should:
    • disable new listings and bonus target escrow actions
    • keep cancel/delist buttons available

Token disabled (EntryTokenRegistry token enabled=false):

  • enterWithToken and/or takeoverWithToken revert for that token.
  • ETH entry remains available.
  • UI should:
    • gray out the token in token pickers
    • explain that it was disabled for safety