Skip to content

Staking & Node-Runners

Smart Engines is designed to be run by node-runners, not by a central operator. Three roles do the work:

Validators

Consensus, threshold signing, rules enforcement.

Hosts

BaaS infrastructure.

Gateways

Edge/CDN/routing.

Each stakes into the network and earns a share of the runner pool.


flowchart TD
    subgraph Roles["Node-runner roles"]
        V["Validator<br/>consensus · threshold signing · rules"]
        H["Host<br/>BaaS infrastructure"]
        G["Gateway<br/>edge / routing / TLS"]
    end
    Stake["Stake deposit<br/>(real HSUITE in a validator-multisig account on XRPL)"] --> V
    Stake --> H
    Stake --> G
    Fees["Settled fees<br/>(40% runner pool, payout not yet switched on)"] --> V
    Fees --> H
    Fees --> G
    V -. "ban by validator vote" .-> Slash["Slashing<br/>(bonded deposit to Protocol Treasury)"]

To operate a node, a runner posts an HSUITE deposit held as real HSUITE in a validator-multisig account on XRPL — not an internal accounting entry. The deposit for each role is:

Role Deposit (HSUITE) Lock
Validator 10,000,000 365 days
Host 5,000,000 365 days
Gateway 2,000,000 365 days

Each deposit is locked for a 365-day term, and the term can be renewed.

Deposits are paid in HSUITE on XRPL. Paying a deposit in another asset is not available.

Role sets: apply for more than one role at once

Section titled “Role sets: apply for more than one role at once”

An operator does not have to run three separate applications to hold three roles. A single application can carry a role set — a roles list ('validator' | 'host' | 'gateway') — and the deposit required is the sum of the individual role deposits:

Role set Deposit (HSUITE)
validator + host 15,000,000
validator + gateway 12,000,000
host + gateway 7,000,000
all three 17,000,000

The single-role form still works unchanged: an application with just networkType: 'validator' is treated as the role set ['validator'] and quoted the 10M deposit. The deposit-requirements endpoint returns both the per-role prices and a roleSets quote map, so a would-be operator can read the combined price before applying:

POST /api/v3/membership/apply
Content-Type: application/json
{
"nodeId": "operator-1",
"accountId": "rOperatorAddressXXXXXXXXXXXXXXXXXXXX",
"chain": "xrpl",
"publicKey": "302a300506032b6570032100...",
"endpoint": "https://my-node.example.com:3000",
"roles": ["validator", "host"],
"creationIntent": { "message": "{...}", "signature": "...", "publicKey": "302a30..." }
}

creationIntent is the applicant operator’s signed create intent for the stake wallet. The deposit wallet holds the operator’s stake, so the operator, not the node that serves the request, signs its rule: build it with the SDK’s signDepositWalletIntent(signer, { network, depositType: 'membership', chain: 'xrpl', tokenId }) (no appId; tokenId is depositTokenIds.xrpl from GET /api/v3/subscription/config, network from GET /api/v3/discovery/network) using the key of accountId. An application without one is refused (400, message starting deposit_intent_required:), and so is one whose intent signs another rule, token, chain, network or payer. A proof is valid for ten minutes.

The application returns deposit instructions for the summed amount — 15000000 for the validator+host set above.

The chain field on a membership application accepts only xrpl. Membership NFTs — the on-chain proof of a staked node’s roles and term — are minted only on XRPL, so an application on any other chain is rejected. The deposit itself is HSUITE on XRPL too.

Deposit accounts are rule-governed primitives, not bare wallets: each is a DKG-multisig account whose canonical rule (full sovereignty, transfer co-signed by the quorum, lifecycle locked) is published to HCS as an auditable record. For subscription deposits specifically, that rule is the real sign-time authority over the money — see Subscription-deposit settle-in.


A registered node’s roles and term are carried by a membership NFT minted on XRPL. Every membership NFT is self-describing — its metadata records {roles, term, expiresAt, tier}:

Field Meaning
roles The role set the node is registered for (validator / host / gateway).
term The membership term in days (e.g. 365).
expiresAt ISO timestamp when the membership lapses, computed as issue time + term.
tier The membership tier (e.g. TIER_10M).

Because the NFT is the on-chain proof of what an operator may run and until when, the fields aren’t cosmetic — a membership NFT without them would prove neither the node’s roles nor whether the membership is still current.

A membership NFT is deliberately immutable, so renewal doesn’t edit it in place: renewal mints a fresh NFT with the updated term first, then burns the old one. The mint-before-burn ordering avoids any window where the operator holds no valid membership NFT. The deposit lock is extended by the same motion.

An operator can always exit. The leave path marks the membership as left and revokes the membership NFT, whether or not the deposit can be returned at that moment. A deposit is locked until its term ends, and a banned validator cannot leave.

Returning a deposit to its operator is not built yet: the ledger-side step that pays a released deposit back has not been written, so the platform refuses every release and the deposit stays in its locked multisig account.


Runner income comes from the 40% runner share of every settled subscription payment (see Value flows). That share is not a phantom accounting entry — it accumulates in a real, protocol-owned runner-pool account on-chain.

The runner pool is a single protocol-owned DKG-multisig account on XRPL that holds the accumulated 40% runner share until it is distributed. It is created the same way as the genesis treasury and the subscription deposit accounts — funded, given a native multisig SignerList from its DKG slots, set up with an HST trust line, and its master key disabled, so no single party controls it. Its signing threshold is set below the full validator set where the set is large enough, so the pool can still sign and reshare if a validator drops out. It is created at genesis, or on validator boot if it is missing.

When a subscription deposit settles 40/40/20, the 40% runners leg is paid into this account — that flow is described in Settlement & migration.

Distribute-out: the pool pays each operator (built, not yet triggered)

Section titled “Distribute-out: the pool pays each operator (built, not yet triggered)”

The pool is meant to do more than accumulate — it is meant to pay out. The reward distributor is built to split a runner-pool amount across every registered node and send a real on-chain transfer to each operator’s own payout wallet.

The split is pro-rata by staked weight: each registered node carries a stake, and its share of the pool is stake / total-stake of all active nodes. The maths runs on integer smallest-units, so every unit in the pool is paid out exactly once — the sum of all operator payouts equals the pool amount, with the rounding remainder assigned deterministically to a single node. A node with zero stake receives nothing that round.

Three guards sit on the payout path:

Sign-gate

A transfer can only land on a wallet that is the registered payoutWallet of an active node. An unregistered destination is refused before any transfer fires — no partial or stray sends.

Co-sign on re-binding

Changing where a node’s rewards go (its payout wallet) is a privileged action: it requires quorum co-sign approval and fails closed if the approver is absent or denies. One operator can’t silently re-route rewards to an arbitrary wallet.

Idempotency

Each distribution is keyed by a stable identifier and recorded once. A retry after a crash returns the recorded result instead of paying anyone twice — even a partial distribution is safe to re-run.

Rewards are denominated in real HSUITE on XRPL. Paying an operator on another chain through the Universal Token Bridge is not available: the bridge is built but not enabled on any network.


Operators need to keep their on-chain accounts funded to pay for the chain operations they perform. The operator-funding endpoint is a helper that lets an operator query their account balance:

GET /api/v3/operator/balance/:chain/:accountId

It returns the account’s balance (HBAR plus associated token balances) so an operator can verify they have enough to keep operating. The endpoint supports Hedera operator accounts only.


Slashing: bonded-escrow executor built, triggered by a validator ban

Section titled “Slashing: bonded-escrow executor built, triggered by a validator ban”

No holder’s balance can ever be slashed. HSUITE is permissionless: nobody, the DAO included, can freeze or claw back a holder’s HSUITE. Genesis never enables XRPL clawback on the HSUITE issuer, and the issuer’s rule disables and locks wipe (XRPL Clawback) and freeze. An HST clawback is impossible by design — the XRP Ledger itself refuses one — so slashing never attempts it.

Slashing therefore moves only stake a validator has bonded into escrow. A validator’s membership deposit account is its bonded escrow: a DKG t-of-n XRPL account with its master key disabled, whose canonical rule allows a slash transfer and whose lock duration is the unbonding delay. The slash executes as a DKG-threshold Payment out of the bonded escrow to the Protocol Treasury, never a clawback.

flowchart LR
    Bond["Validator's membership deposit account<br/>= its bonded escrow<br/>(DKG t-of-n, master key disabled)"] --> Held["Bonded stake<br/>no unilateral withdrawal,<br/>locked for the term"]
    Held -. "ban approved by validator quorum" .-> Slash["Slash: DKG Payment<br/>escrow to Protocol Treasury<br/>(full deposit, bonded stake only)"]

The trigger is a validator ban. Validators vote to ban a peer, with evidence attached. A ban for downtime can be approved by the other validators on their own observations, after a short re-check window that aborts the ban if the validator’s heartbeat comes back. Once a ban is approved, the validator’s whole deposit is forfeited and the slash payment is requested. Before anything irreversible happens, the slash is refused if removing the validator would strand an account it co-signs (one that could no longer be reshared without it).

Every check on the slash executor is fail-closed — a refusal publishes a failure response and writes nothing to any chain:

  • the request must name the genesis HST issuer;
  • the source account must be the bonded escrow recorded for that validator in the replicated, signature-verified entity registry, never an address supplied in the request. A request naming any other holder is refused, with no chain write;
  • the slash amount must not exceed the escrow’s live HST balance, so a slash can never over-confiscate the bond or reach past it — there is no signing path for any other source account;
  • the destination must resolve to the Protocol Treasury, or the slash is refused.

Partial slashes for lesser offences, and returning a deposit after unbonding, are not built.


Node-runner slots are not open to the public yet; HSuite operates the validators today. Running a node is designed as an economic position: capital at stake, and real HSUITE income once the runner pool’s payout is switched on (see Distribute-out), with the bonded deposit at risk if the other validators ban the node.