Centurion Seat Manager¶
Validator seat lifecycle manager for the Centurion DepositContractCTN allowlist model.
What Is a Seat?¶
A seat is a tracked (pubkey, withdrawal_credentials) pair bound to an on-chain allowlist intent on the deposit contract.
Each seat has an intent hash — keccak256(pubkey || wc) — that the contract uses to allow or deny deposits.
The Seat Manager handles everything from creating seats to watching them go live on the beacon chain.
At a Glance¶
| Capability | What It Does |
|---|---|
| Create seats | Store a (pubkey, wc) pair locally, compute the intent hash |
| Approve / Revoke | Propose or send addAllowedDeposit / removeAllowedDeposit transactions |
| Deposit | Simulate or send deposit() with full verification of on-chain events |
| Watch | Monitor EL nodes for DepositEvent logs and CL nodes for validator visibility |
| Control | Toggle the allowlist switch and manage the irreversible freeze (with strict safety gates) |
| Audit | Write tamper-evident evidence bundles for every admin action |
Operation Modes¶
No private key required. Every command generates calldata and writes an evidence bundle — but never sends a transaction.
This is the recommended mode for planning, review, and governance workflows.
Requires SEAT_MANAGER_OWNER_PRIVATE_KEY env var. When you add the --send flag, the tool actually sends the transaction on-chain.
Evidence is always written first, then the tx is sent. Receipts are recorded in the database and evidence bundle.
Both modes require --send per command
Having the key set alone does not auto-send anything. You must explicitly pass --send on every command.
Quick Start¶
# 1. Build
npm install && npm run build
# 2. Health check (read-only, no key needed)
node dist/index.js status
# 3. Start watchers (Ctrl+C to stop)
node dist/index.js watch
CLI Commands¶
| Command | What It Does |
|---|---|
status |
Run preflight checks, show allowlist state |
seat create --operator <id> --pubkey <0x..> --wc <0x..> |
Store a new seat locally |
seat approve <seatId> [--send] |
Propose or send addAllowedDeposit |
seat deposit <seatId> --amount-ctn <N> [--simulate-only] [--send] |
Simulate or send a deposit |
seat revoke <seatId> [--send] |
Propose or execute revocation |
seat list [--status CREATED,ALLOWLISTED,...] |
List seats with optional status filter |
switch on/off [--send] |
Toggle the allowlist |
freeze schedule --delay-seconds <N> [--send] |
Schedule irreversible allowlist disable |
freeze cancel [--send] |
Cancel a pending freeze schedule |
freeze execute --dangerous [--send] |
Permanently disable the allowlist |
watch |
Run EL + CL watchers continuously |
Seat Lifecycle¶
stateDiagram-v2
[*] --> CREATED : seat create
CREATED --> ALLOWLISTED : seat approve --send
CREATED --> REVOKED : seat revoke
ALLOWLISTED --> DEPOSITED : EL watcher sees DepositEvent
ALLOWLISTED --> REVOKED : seat revoke --send\n(removeAllowedDeposit)
DEPOSITED --> SEEN_BY_CL : CL watcher — 1st label sees validator
DEPOSITED --> REVOKED : seat revoke\n(operational only)
SEEN_BY_CL --> ACTIVE : CL watcher — 2+ labels confirm
SEEN_BY_CL --> REVOKED : seat revoke\n(operational only)
One-way progression
Seats only move forward (CREATED → ALLOWLISTED → DEPOSITED → SEEN_BY_CL → ACTIVE) or to REVOKED from any state. There is no backward transition.
Safety Gates¶
| Gate | What It Protects |
|---|---|
| Preflight checks | Chain ID, contract code, runtime bytecode fingerprint, and owner are verified before any admin action |
| Cross-check (2+ endpoints) | Dangerous operations require confirmation from at least 2 distinct EL clients |
| Freeze execute: 4 gates | --dangerous flag + CONFIRM_FREEZE=I_UNDERSTAND env + cross-check + on-chain timelock maturity |
| Evidence bundles | Written to ./evidence/ for every admin proposal or action — before any tx is sent |
| Labels-only output | Endpoint URLs are never printed — all output uses labels like [aws-a-1] |
Storage¶
SQLite database at ./data/seat-manager.sqlite (gitignored).
| Table | What It Stores |
|---|---|
seats |
Lifecycle state per (pubkey, wc) pair |
allowlist_actions |
On-chain tx records (add/remove) |
deposits |
Observed DepositEvent logs |
cl_observations |
Beacon API visibility checks |
audit_log |
All actions with timestamps |
Configuration¶
seat-manager.config.json points to the centurion-infra root:
Override with CENTURION_INFRA_ROOT env var. All canonical values (chainId, contract address, owner, endpoints) are read from infra files at runtime.
Full configuration details
See the Operator Guide for complete configuration reference including endpoint discovery, RPC modes, and all environment variables.