Chains, wallets and validators
The five screens behind on-chain staking — activating a chain, the staking key, the validator policy, the batch ledger and the incident desk — and the one rule they all share, that nothing here ever holds a customer's exit.
On-chain staking takes a customer's coins into a wallet this platform controls and delegates them on a network. Before that can happen for a chain, four records must exist, and this page is where they are made. It is also where the product is paused, and where what the engines find is shown to a person.
| Screen | Path | Answers |
|---|---|---|
| Chains | /admin/staking/chain |
Is this chain switched on, and what is still missing? |
| Wallets | /admin/staking/wallet |
Which key holds the coins, what does it hold, is it frozen? |
| Validators | /admin/staking/validator-set |
Who do we delegate to, and do they still pass the policy? |
| Batches | /admin/staking/batch |
What was signed, what was broadcast, what is stuck? |
| Incidents | /admin/staking/incident |
What needs a human? |
None of these screens can move a customer's coins out of the product. Every exit — unstake, claim, return, refund — runs from the scheduled tasks regardless of anything set here. The switches on this page stop new intake only.
Chains — the activation wizard
One card per chain the product supports: SOL (native delegation from
platform-owned stake accounts) and ETH (Lido stETH, held as shares). The
network is read from the same environment variable the Ecosystem addon uses for
that chain's deposits (SOL_NETWORK, ETH_NETWORK), so an install cannot
gather real coins and delegate on a test network.
Four steps, each a row in the database:
- Staking wallet. A dedicated key, generated once per chain, encrypted with the ecosystem vault. It is never a second master-wallet row: the master wallet pays customer withdrawals and every reader of it keys by chain alone, so a second row could sign a withdrawal. Key material is never returned by any endpoint or shown on any screen.
- Validator set (Solana only). A named list of vote accounts, chosen from the network screened against the policy below. A set that fails the policy cannot be attached to an activation.
- Declaration. The default commission on observed rewards, the notice period before a commission rise, the slashing policy (pass through to holders, or reimburse up to a cap), whether the operator is licensed and by whom, the jurisdictions served, the validator due-diligence note, and two acknowledgements: customer coins are ring-fenced, and no reward is fixed, guaranteed or topped up.
- Operator statement. Five sentences a Super Admin accepts by version. The acceptance is stamped with who, when, from which address and which words.
The card lists every outstanding requirement by name and enables Activate only when the list is empty.
What the declaration implies
The jurisdiction rules are derived from the declaration, never typed, and the card shows them as the declaration changes:
| Declared | Rule |
|---|---|
| Anything | Singapore is blocked and the block cannot be removed |
| Serves AE | The activation is refused: Dubai requires a per-client wallet and a pooled staking wallet cannot serve it |
| Serves HK | The SFC attestation is required, and the Lido venue is refused (third-party custody) |
| Serves GB | The prescribed UK risk warning is shown, and affiliate rewards on staking are forced off |
| Serves US | The contested-state warning is shown |
| Not licensed | US, GB, HK, AE, JP and KR are blocked, non-removably |
The vendor of this software provides tooling and defaults, not a licence.
Pause, resume, retire
Pause stops new stakes on every pool of the chain and records a reason that is shown at the stake door. Observation, unbonding, claims, returns and refunds continue. Resume re-checks every requirement first. Retire is terminal and refused while any position under the activation still holds coins.
An ACTIVE declaration cannot be edited: pause first. A change to the commission or the validator list is a change to the terms every open pool publishes, and the pool's disclosure version moves with it.
Wallets
The table shows chain, network, address, status, the last observed balance and the gas reserve floor. Three actions:
- Freeze, with a reason. A frozen wallet refuses to sign delegations and sweeps and keeps signing exits, claims, returns and refunds. Super Admin only.
- Unfreeze. Super Admin only.
- Gas reserve floor. Below this native balance the reconciler opens a
LOW_GASincident. A staking wallet that cannot pay a fee cannot process an exit, so the floor should cover a week of exits.
Create staking wallet lists the supported chains, whether each has a wallet, and whether its network variable is set. One wallet per chain; a second request is refused.
Validators
A validator set is held to the policy in code, not in a setting:
| Rule | Threshold |
|---|---|
| Members | At least 8 |
| Superminority | None of the validators whose cumulative stake reaches a third of the network |
| Inflation commission | At most 5% |
| MEV commission | At most 10%, where known |
| Delinquent | Refused |
| Vote credits | Some in the last two epochs |
| Pool share | At most 15% of a pool's principal per validator |
| Operators | At least two distinct ASNs, where ASNs are recorded |
New validator set reads the network live, screens every validator, and lists them sorted by stake with the rule each one failed. A failing validator cannot be ticked. Weights decide how a delegation is split; each piece stays at or above the chain's minimum delegation.
Every set is re-screened every six hours. A member that starts failing is suspended (no new delegation; its existing stake keeps running until an exit or a rebalance moves it), the set is marked as failing, and intake on its pools pauses. Evaluate now re-reads the network on demand.
Batches
Every on-chain operation is a row: gathers, delegations, exits, claims, returns, refunds, commission exits and sweeps. Each carries the intent the transaction firewall approved — the decoded instruction list and its SHA-256 — and the hash that was broadcast.
The firewall decodes every instruction a staking key is asked to sign and
refuses by name anything outside the allow-list for the batch kind. On Solana
that is the System program's create and transfer, and the Stake program's
initialize, delegate, deactivate, withdraw, split and merge; authorize,
authorizeWithSeed, setLockup and every other program are refused. On
Ethereum the contract address and the four-byte selector are allow-listed per
network. The approved digest is stored on the batch before anything is signed,
and the sender re-derives it from the exact bytes it broadcasts.
A batch that reached the chain is never marked failed; it retries with backoff until it lands. Only a batch that was never broadcast can fail, and a failed gather is what makes a position refundable. Retry now makes an errored batch due on the runner's next tick; it does not sign anything itself.
Incidents
The reconciler runs hourly and opens an incident for every discrepancy it cannot explain:
| Kind | Opened when | Severity |
|---|---|---|
LOW_GAS |
A wallet's balance is below its gas reserve floor | Critical |
DRIFT |
Holders' shares plus treasury shares differ from the pool total, or the book value differs from the tranche value | Critical / Warning |
BATCH_STUCK |
A batch has been in flight longer than the chain's finality window | Warning |
OBSERVER_LAG |
A pool with shares has not been observed for twice its cadence | Warning |
VALIDATOR_BREACH |
A set no longer passes the policy | Warning |
SLASHING |
The observer recorded a negative reward | Critical |
A condition that persists is one incident with a rising count, and a condition
that clears resolves its own incident. Every new incident notifies everyone
holding access.staking. A critical incident holds new intake on its pool
and nothing else. Reconcile now runs the check on demand.
A SLASHING incident carries Reimburse… when the pool's activation
declared REIMBURSE_CAPPED: it pays up to the cap per incident, pro rata to
the holders, from the Super Admin's ECO wallet, and refuses with the
shortfall named when that wallet cannot fund it. Three further kinds are
raised by the ten-minute alerts job: UNBONDING_OVERDUE, DELEGATION_STALE
and COMMISSION. See Operating on-chain staking.
Compliance records and exports
The Settings screen's Compliance tab reads /api/admin/staking/compliance/records:
the fixed-rate territory gate, every activation with its acceptance and derived
rules, consent counts by disclosure version, the statements written and the
incidents open. Three CSV exports hang off it, at
/api/admin/staking/compliance/export?kind= consents, activations or
observations.
The Compliance console (Staking → Compliance) shows the same records as tabs — activations with their derived rules, consents, monthly statements and the exports — and carries the one write in it: writing a period's missing statements ahead of the nightly run.
Permissions
| Key | Opens |
|---|---|
access.staking.chain · view.staking.chain · create.staking.chain · edit.staking.chain |
The Chains screen, starting and editing a declaration, pause and resume. Activate, retire and wallet creation additionally need the Super Admin role. |
access.staking.wallet · view.staking.wallet · create.staking.wallet · edit.staking.wallet |
The Wallets screen, the gas reserve floor. Create, freeze and unfreeze additionally need the Super Admin role. |
access.staking.validator · view.staking.validator · create.staking.validator · edit.staking.validator |
Validator sets, the screened candidate list, evaluation |
access.staking.batch · view.staking.batch · edit.staking.batch |
The batch ledger and retry |
access.staking.incident · view.staking.incident · edit.staking.incident |
Incidents, acknowledge, resolve, and running the reconciler |
The compliance records and exports reuse view.staking.settings.