Read-only mode — auth not configured
Robinhood faucet stock tokens are active with simulated testnet prices. Review the test environment.
STONKBACKINGINDEXTREASURY$0.00APY
DocsProduction

Operators

Launch prerequisites, deployment invariants, sequencing and automation operations.

5 min read

Production runbook

Required external inputs

  • Two distinct canonical Safe 1.4.1 proxies deployed on Robinhood Chain: genesis and guardian, each threshold >= 2, no enabled modules, no guard, and either no fallback handler or the pinned canonical Safe 1.4.1 compatibility handler.
  • SafeProxy, singleton, and any permitted fallback-handler runtime code hashes matching the values pinned in Deploy.s.sol. Deployment verifies masterCopy() against the hardcoded canonical Safe 1.4.1 and SafeL2 1.4.1 singleton addresses and runtime code hashes.
  • The signed STK-001 risk acceptance and ACCEPT_UNPROTECTED_SEQUENCER_RISK=true. Do not infer or substitute a sequencer feed while no canonical Robinhood Chain feed exists.
  • A funded, one-use deployer account.
  • Two independent Robinhood Chain RPC endpoints for automation, one production RPC for deployment, and a separate RPC for final-state verification.
  • Privy application ID and production origins for wallet UX.
  • Monitoring for chain RPC, automation health, gas balance, disabled sequencer protection, Chainlink feed freshness, Robinhood oraclePaused(), pending epochs, emergency state, and governance events.

Preflight

  1. Pin the release commit and reproduce all validation commands in the root README.
  2. Run the deployment on a current Robinhood mainnet fork with FORK_MAINNET=true.
  3. Confirm every token and feed in config/chains.json against Robinhood and Chainlink official registries.
  4. Confirm that no canonical sequencer feed is available, review STK-001's scenario exposure and expiry, and collect the two named risk approvals before funding any market. Contract deployment alone does not authorize deposits.
  5. Review risk parameters, especially feed heartbeat, USDG cap, volatile haircuts, aggregate active unsold capacity, per-market capacity, payout limits, zero launch emission rate, voting parameters, and Timelock delay. The values in config/mainnet.json are proposed templates, not economic approval.
  6. Have an independent Solidity audit. Resolve every Critical and either fix each High or satisfy the signed, bounded exception policy. STK-003 and STK-004 are currently open.
  7. Simulate the exact production broadcast and review every transaction.
  8. Build the frontend with the reviewed deployments/4663.json, production browser RPC, Privy application ID, and allowed origin; exercise wallet login and one non-critical transaction in a production-origin browser smoke test.
  9. Install and fire-test the Prometheus alerts. /readyz remains unavailable until one complete automation and monitoring cycle succeeds and then reports the failure threshold; oracle invalidity, emergency state, low gas, and partial RPC failure are metric-driven alerts.

Deployment invariants

After deployment, verify onchain:

  • Kernel executor, Authority governor/policy, and RolesAdmin admin equal the Timelock.
  • Authority guardian equals the guardian Safe and vault equals MINTR.
  • No deployer role remains in ROLES or the Timelock.
  • No external account has Timelock DEFAULT_ADMIN_ROLE.
  • Governor is proposer/canceller, the genesis Safe is proposer-only, and executor role is open.
  • Guardian Safe has emergency_shutdown and Timelock CANCELLER_ROLE, but no proposer/executor/restart authority.
  • Timelock holds all other administrative and restart roles.
  • Every PRICE asset points to the expected Chainlink proxy with correct decimals, heartbeat, cap, haircut, category, and pause check.
  • Every protocol contract's live runtime code hash matches the reviewed deployment manifest.
  • Manifest mode is exactly ACCEPTED_UNPROTECTED, deployed PRICE is StonkPriceUnprotected, sequencerProtectionEnabled() is false, and feed/grace are zero. Any other unprotected production state is invalid.
  • getPrice() equals the corresponding current feed answer after scaling/cap.
  • No bond market exists immediately after Deploy.s.sol, and Distributor rate is zero.

Launch sequence

  1. Deploy and verify source code with explicit STK-001 acknowledgement. Do not create a market during deployment.
  2. Run make verify-deployment from a clean checkout against INDEPENDENT_RPC_MAINNET and archive the output.
  3. Publish the deployment manifest and frontend build from the same commit.
  4. Start two independent permissionless automation instances and monitoring.
  5. Complete the independent audit, close STK-003/STK-004, sign the STK-001 capacity limit, and publish the approved loss budget.
  6. Through the genesis Safe and Timelock, create only the tightly capped bootstrap market or markets covered by that approval.
  7. Distribute and delegate gSTONK sufficiently for quorum.
  8. Exercise a non-critical governance proposal end to end.
  9. Exercise guardian shutdown on testnet/fork and governance-only restart.
  10. Revoke the genesis Safe proposer role through governance.

Do not fund production bond capacity or invite users before the audit, economic/counterparty approvals, signed STK-001 exposure ceiling, fork rehearsal, source verification, production wallet/transaction smoke, alert fire test, and control-plane invariant checks are complete. Aggregate active unsold capacity is the sum of remaining STONK payout capacity across all live markets; it is the maximum additional STONK those markets can mint, not a stock-token sale target.

Strict PRICE upgrade

When Chainlink publishes a canonical Robinhood Chain sequencer uptime feed:

  1. Verify the address through two official sources and directly inspect bytecode, decimals() == 0, answer semantics, current status, startedAt, and operating history.
  2. On a current fork, deploy StonkPrice(kernel, feed, gracePeriod, currentPriceModule). The constructor accepts migration only from the currently installed PRICE module and validates/copies its complete bounded registry.
  3. Compare every asset configuration and strict price to the old module. Rehearse outage, recovery-grace, stale-round, and policy-reconfiguration paths.
  4. Prepare a Timelock proposal executing the Kernel UpgradeModule action for the new PRICE module. Decode and simulate the exact calldata; the Kernel reconfigures dependent policies as part of the upgrade.
  5. Execute after the governance delay, then run the independent deployment verifier against a separate RPC and confirm every policy points to the new module.
  6. Update the committed manifest, keeper and frontend artifacts. Remove the public warning and retire STK-001 only after sequencerProtectionEnabled() is true and a live recovery-grace test passes.

If verification or migration differs at any step, cancel the proposal. Do not install a guessed feed, proxy shim, or module with an empty asset registry.

Automation deployment

keeper/Dockerfile and railway.json package the roleless automation service with a /healthz deployment check and restart-on-failure policy. Build from the repository root so config/ and the committed production deployment manifest are included. Set CHAIN=mainnet, a sealed KEEPER_PRIVATE_KEY, and at least two comma-separated KEEPER_RPC_URLS. Run a second replica in another provider/region with a different key and RPC ordering. Alert from /metrics on RPC divergence/down state, low gas, disabled sequencer protection, pending epochs, inactive MINTR/TRSRY, invalid/stale/paused oracles, unexpected Timelock delay, and Governor/Timelock event activity. Disabled protection is an expected persistent High-risk state under STK-001, not a healthy uptime signal.