OperationsOperator guide

Operate SYMMIO from one menu

Deploy, patch, audit, resume, and safely abandon work without memorising commands or editing deployment JSON by hand.

Start

Install the locked dependency tree once, then launch the checkout-local application in a real terminal.

npm ci
./symmio

The operator interface is intentionally menu-only. Arguments and non-TTY execution are refused. Low-level Hardhat tasks remain internal adapters owned by registered tasks.

  1. Deploy a contract
  2. Patch configurations for deployed contracts
  3. Run the checklist on a new deployment
  4. Other maintenance scripts
  5. Continue active task
  6. Cancel active task
  7. Exit

Guided configuration

Choose a target and network. The form loads reviewed defaults, asks only required decisions and overrides, validates each typed value immediately, then shows public intent grouped by network, governance, Core, Muon, protocol, components, and execution.

After final approval the application writes a portable recipe atomically. Operators review that artifact; they do not need to manually maintain its JSON. Local and fork workflows may deliberately use environment references, but live workflows may not.

One durable task

A live deployment is one connected workflow. It automatically performs:

  1. recipe, RPC, signer, authority, and dependency preflight;
  2. production compilation;
  3. a matching fork rehearsal and receipt review;
  4. typed live-network confirmation;
  5. write-ahead transaction journaling and receipt reconciliation;
  6. explorer verification and current health checks; and
  7. ownership, role, deployer-privilege, and handover proof.

A completed report is historical evidence, never an active task. The active record is bound to task version, source and input hashes, recipe digest, chain, signer set, and stable plan; changed intent cannot be resumed accidentally.

Progress and recovery

The live view shows phase, completed and total steps, current action, confirmed/pending/failed transaction counts, elapsed time, and warnings. Press d for hashes, receipts, gas, explorer links, and recent redacted logs.

The first Ctrl+C requests a cooperative pause at the next safe boundary. A second Ctrl+C exits immediately after preserving resumable state. Choose Continue active task to reconcile recorded broadcasts before doing new work.

Cancel active task means safe abandonment, never rollback. Confirmed on-chain effects remain recorded. Unknown broadcast outcomes hold the task in cancel_pending until reconciliation can prove them.

Handover and external actions

Fresh configuration is completed under temporary deployer roles before those roles are removed, so a normal fresh handover contains ownership acceptance only. The task then classifies the administrator from chain state. An EOA can use a Ledger hardware wallet, Hardhat keystore wallet, transient private key, or an allowed unlocked local account. Safe Transaction Builder and direct proposal choices appear only for an address that passes Safe interface checks; unknown contracts remain manual. The task displays Handover required until exact post-state reads pass. After external actions confirm, launch ./symmio and choose Continue active task. The task rereads chain state, skips completed deployment steps, and closes only after the strict health gate passes.

Replacing the InstantLayer

The InstantLayer is a plain contract, so a code change means a new address. scripts/migrateInstantLayer.ts carries a live deployment across that change in two phases. The deployer phase reads the old layer from chain (AccountLayer, whitelisted targets, registered PartyBs, templates in id order, cooldown, transient flag, and every role holder), deploys and configures the replacement to match, deploys a GaslessLayer implementation that exposes setInstantLayer, grants all four roles to the Safe, and renounces the deployer. Every step checks chain state first, so an interrupted run is resumed by running the same command again with the state file it wrote under scripts/output/.

The admin phase is nine binding transactions: grant INSTANT_LAYER_ROLE on core and SIGNER_SETTER_ROLE on the AccountLayer to the new layer, trust and multicast-whitelist it on every registered SymmioPartyB, and upgrade the GaslessLayer with setInstantLayer as the init data; later, the matching revokes for the old layer. When the governance admin is an EOA whose key is configured as a second signer, the script executes the cutover itself right after the deployer phase, so one command completes the migration. A Ledger admin signs the same actions through ADMIN_SIGNER=cast-ledger (Foundry cast send --ledger, as in the governance handover) in a second command, PHASE=bind. When the admin is a Safe, the actions are written as Transaction Builder batches next to the state file. The old layer keeps its bindings, so users can keep trading on existing delegations while they re-grant on the new address; PHASE=decommission revokes the old layer once that window closes. Delegations, pending revocations, and delegation nonces do not carry over; frontends and relayers must switch the address and the EIP-712 verifyingContract.

# plan (read-only)
npx hardhat run --no-compile scripts/migrateInstantLayer.ts --network arbitrum

# deployer phase (keystore deployer); the cutover runs in the same command when the admin key is a configured signer
EXECUTE=true CONFIRM_CHAIN_ID=42161 npx hardhat run --no-compile scripts/migrateInstantLayer.ts --network arbitrum

# admin phase for a Ledger admin: five cast --ledger transactions, one device confirmation each
EXECUTE=true CONFIRM_CHAIN_ID=42161 PHASE=bind ADMIN_SIGNER=cast-ledger npx hardhat run --no-compile scripts/migrateInstantLayer.ts --network arbitrum

# confirm at any time
CHECK_INSTANT_LAYER=0x<new> npx hardhat run --no-compile scripts/migrateInstantLayer.ts --network arbitrum

# after the transition window
EXECUTE=true CONFIRM_CHAIN_ID=42161 PHASE=decommission ADMIN_SIGNER=cast-ledger npx hardhat run --no-compile scripts/migrateInstantLayer.ts --network arbitrum

Defaults come from tasks/data/<chainId>/deployment-report.json and gaslesslayer.json; templates are replayed from the old layer with their ids and then extended with the recipe's extra templates (TEMPLATES_RECIPE, the Arbitrum production recipe by default), whose leading entries must match the deployed ones exactly; the GaslessLayer implementation links against the library addresses recorded there. Once the cutover is confirmed, update addresses.instantLayer in that report and append the new entry to instantlayer.json, so check:deployment and verify:all follow the new layer. The rehearsal in test/InstantLayerMigration.behavior.ts runs the whole sequence, Safe batches included, against the local full stack, and scripts/rehearseInstantLayerMigration.ts repeats it on a fork of the live chain with the Safe impersonated (--network fork-arbitrum with the upstream RPC exported), which is the step to run before spending real gas.

Evidence

Path Purpose
deployment-recipes/<name>.json Portable, reviewed public intent
.symmio/tasks/active.json Single transient active task
.symmio/tasks/runs/ NDJSON event journal and redacted raw log
.symmio/tasks/history/ Indefinite local terminal history
tasks/data/<chainId>/ Ignored local evidence: reports, receipts, Safe exports, and checklists
tasks/data/<chainId>/deployment-summary.md Human-readable important-address handoff; deployment-report.json remains machine evidence

tasks/data/ is ignored local evidence and is never pushed by Git. Back it up securely when off-machine recovery is required.

For persistent local-node rehearsal, patch semantics, checklist coverage, and maintenance policies, use the complete deployment runbook. For adding a one-time script, use the task-definition and registry standard.