Skip to Content
DocumentOperatorOperator dashboard
Operate

Build an operator-facing UI: registry status, queue depth, fee stats, exit controls.

If you’re running a relayer, your operator dashboard is the control panel: register, monitor, top up bond, change fee, request exit. The SDK ships every primitive needed — this page assembles them.

What to surface

Registry status

Active / cooldown / offline / unregistered. Bond, fee, registered-at.

Queue depth

Pending authorize orders the matcher is holding. From /api/info.

Settlement throughput

Trades settled per hour, fees collected. Subscribe to PrivateSettledAuth events.

Bond posture

Current bond, headroom over minBond. (No slashing history — the registry does not slash; reputation events live in the Dispute Registry once it ships.)

Read everything in one shot

import { loadOperatorRow, RelayerClient, } from "@zkscatter/sdk/relayer"; const [row, info] = await Promise.all([ loadOperatorRow( network.contracts.relayerRegistry, operatorAddress, readProvider, ), new RelayerClient("https://my-relayer.example.com").getInfo(), ]); // row.status: "active" | "cooldown" | "offline" | "unregistered" // row.bondEth: human-readable bond // info.orderCount: pending queue depth

Drive the UI off row.status:

StatusUI affordances
unregisteredRegister form (URL + fee + bond)
activeUpdate info / Add bond / Request exit
cooldownShow cool-down timer; disable updates
offlineShow “re-register” CTA

Settlement event feed

import { ethers } from "ethers"; import { PRIVATE_SETTLEMENT_IFACE } from "@zkscatter/sdk"; const contract = new ethers.Contract( network.contracts.privateSettlement, PRIVATE_SETTLEMENT_IFACE, readProvider, ); // PrivateSettledAuth indexes 3 fields: makerNullifier, takerNullifier, // makerRelayer. Filter by the relayer address (5th positional, 3rd // indexed) to scope to your own settlements where you matched as // the maker-side relayer. const filter = contract.filters.PrivateSettledAuth(null, null, operatorAddress); contract.on(filter, (makerNull, takerNull, claimsRootMaker, claimsRootTaker, makerRelayer, takerRelayer, submitter, feeTokenMaker, feeTokenTaker) => { // append to UI });

For settlements where you were the taker relayer, scan and filter post-hoc on takerRelayer (non-indexed by Solidity’s 3-indexed cap) or maintain your own secondary index keyed on submitter.

Fee adjustments

import { updateRelayerInfo } from "@zkscatter/sdk/relayer"; await updateRelayerInfo( network.contracts.relayerRegistry, { url: row.url, feeBps: 25 }, // 0.25 % signer, );

Fee changes propagate to apps on their next loadRelayersWithApiInfo refresh — typically within 60s.

Bond posture widget

function BondPosture({ row, minBond }: { row: OperatorRow; minBond: bigint }) { const ratio = Number((row.bond * 1000n) / minBond) / 1000; return ( <div> <div>Current bond: {row.bondEth} (registry bond asset)</div> <div>Minimum: {ethers.formatEther(minBond)} (registry bond asset)</div> <div>Headroom: {(ratio - 1).toFixed(2)}× over minimum</div> {ratio < 1.5 && <Warning>Bond is close to `minBond` — apps doing operator filtering may rank operators with thinner bond margins lower</Warning>} </div> ); }

Exit flow UI

import { requestRelayerExit, executeRelayerExit, EXIT_COOLDOWN_SECONDS } from "@zkscatter/sdk/relayer"; function ExitFlow({ row }: { row: OperatorRow }) { if (row.status === "active") { return <button onClick={() => requestRelayerExit(/* ... */)}>Request exit (7-day cool-down)</button>; } if (row.status === "cooldown") { const unlockAt = row.exitRequestedAt + EXIT_COOLDOWN_SECONDS; const remaining = unlockAt - Math.floor(Date.now() / 1000); if (remaining > 0) { return <div>Bond unlocks in {Math.ceil(remaining / 86400)} days</div>; } return <button onClick={() => executeRelayerExit(/* ... */)}>Withdraw bond</button>; } return null; }

Reference implementation

The Tokamak-shipped operator dashboard lives in apps/operators/ under the monorepo. Patterns to copy:

  • OperatorIdentityBar — header showing status / address / bond
  • useOperator — hook wrapping loadOperatorRow with auto-refresh
  • useRegistryWrite — abstracts the four write operations with toast feedback

If you build your own, point at it via the registry’s url field; apps don’t care which dashboard implementation an operator uses.

Last updated on