Skip to content

Plan 5 — Emergency Freeze #187

Description

@gravityblast

Stablecoin Plan 5 — Emergency Freeze

Goal: Land the emergency kill switch — freeze and unfreeze instructions that flip ProtocolParameters.is_frozen, plus the propagation of the frozen check into the three Plan 3 instructions that must be blocked while the protocol is frozen (open_position, withdraw_collateral, generate_debt). After this plan ships, the freeze authority can halt new risk-increasing operations end-to-end via the zkVM and resume normal operation later. Operations that REDUCE risk (deposit_collateral, repay_debt, close_position), permissionless keeper pokes, and admin parameter updates remain available throughout a freeze.

Architecture: Two new instructions follow the existing set_* shape from Plan 4: a 2-account input list (freeze_authority, protocol_parameters), an authority-check that mirrors the admin auth helper, and a single-field write that toggles ProtocolParameters.is_frozen. Both instructions are idempotent — calling freeze when already frozen is a no-op success, same for unfreeze. The frozen-check propagation is a single new assert! line in each of the three target Plan 3 host functions, placed immediately after the ProtocolParameters decode so every other precondition is still evaluated when the protocol is NOT frozen.

Tech stack: Rust 2021, RISC Zero zkVM, nssa_core (LEZ runtime types), Borsh + serde, spel_framework_macros::account_type, existing stablecoin_core types (ProtocolParameters, compute_protocol_parameters_pda).

Spec reference: docs/superpowers/specs/2026-06-03-stablecoin-rfp013-design.md. Sections directly implemented by this plan: §10.17 (freeze), §10.18 (unfreeze), and the protocol_parameters.is_frozen = true panic conditions called out in §10.4 (open_position), §10.6 (withdraw_collateral), §10.7 (generate_debt). The "Emergency" walkthrough in §16.2 doubles as the end-to-end integration test sequence.


Dependencies

  • Plan 1 (Foundation + Bootstrap) — REQUIRED. We rely on the ProtocolParameters struct (with is_frozen: bool), the compute_protocol_parameters_pda / compute_protocol_parameters_pda_seed helpers, and the freeze_authority_account_id field. Without Plan 1 there is no ProtocolParameters account to flip.
  • Plan 3 (Position lifecycle) — REQUIRED. We patch open_position, withdraw_collateral, generate_debt host functions to add the frozen-check assert!. These host functions must already exist in their full Plan-3 form (reading protocol_parameters, decoding it as ProtocolParameters). If Plan 3 hasn't landed, the issue 01 step that adds the assert! has nothing to attach to.
  • Plan 4 (Admin parameter updates) — LIGHT dependency. Plan 4 issue 01 introduces the admin authorization helper pattern (verify_admin_and_get_seed or equivalent name — confirm the actual final name when Plan 4 lands). Plan 5 mirrors the structural shape of that helper for the freeze_authority instead of admin. Plan 5 is parallelizable with Plan 4 in scheduling but the freeze-authority helper should reuse the structural shape Plan 4 settled on (separate helper, separate field on ProtocolParameters). If Plan 4 hasn't landed yet, Plan 5 issue 02 should land the helper inline; a small follow-up after Plan 4 can refactor to share patterns if desirable.

Dependency graph

Plan 1 ──────────────────► 01 ──► 02 ──► 03
Plan 3 ─────────────────► 01           ▲
Plan 4 (light, structural) ────────────┘

What is NOT in this plan

  • The ProtocolParameters struct itself, including the is_frozen field — Plan 1 issue 02.
  • The three Plan 3 instructions (open_position, withdraw_collateral, generate_debt) themselves; this plan only adds ONE line per host function (the frozen-check assert!) plus tests covering the new behaviour.
  • deposit_collateral, repay_debt, close_position — these stay ALLOWED when frozen by deliberate design (see §10.5, §10.8, §10.9, §16.2). Do NOT add a frozen check to them.
  • Permissionless pokes (accrue_stability_fee, update_redemption_rate, refresh_globals) — also stay allowed when frozen (Plan 2 owns them; nothing to change here).
  • Admin set_* instructions — also stay allowed when frozen (Plan 4 owns them; the admin can rotate the oracle while frozen, see §16.2). Nothing to change here.

Working in this plan

# Spec ergonomics
cat docs/superpowers/specs/2026-06-03-stablecoin-rfp013-design.md      # full design
docs/superpowers/scripts/render-pdf.sh                                  # regen PDF

# Local build / test loop
make clippy                                                             # all crates
RISC0_DEV_MODE=1 cargo test -p stablecoin_core                          # type-level tests
RISC0_DEV_MODE=1 cargo test -p stablecoin_program                       # host-function tests
RISC0_DEV_MODE=1 cargo test -p integration_tests --test stablecoin      # end-to-end (zkVM)
cargo +nightly fmt --all                                                # nightly required (rustfmt.toml uses unstable opts)
make idl                                                                # regenerate artifacts/stablecoin-idl.json after the guest changes in issue 03

Suggested GitHub labels

When creating issues, optional labels for triage:

  • area/stablecoin — all issues in this plan
  • plan-5 — this plan, to keep them grouped
  • kind/emergency — issues 02, 03 (the freeze kill-switch)
  • kind/guardrail — issue 01 (the frozen-check propagation)

Commits / PRs

One PR per issue, branched off main. Each PR should land green CI (clippy + tests + IDL check). Commit subjects in the body of each issue follow the existing repo style (feat(stablecoin):, test(stablecoin):).

Metadata

Metadata

Assignees

No one assigned

    Type

    Fields

    No fields configured for Task.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions