Selinos
Protocol

How accrual works

A node accrues when the distributor credits it. Every credit is HYPE sent into the factory in the same call that records it, and the value behind it is funded by Selinos from its own treasury. This page covers when a node is credited, what makes a credit real, and what the balance figures mean.

When a node is credited

Every node carries its own timer. When a node is minted it is given a first due time, drawn at random from a configured range of delays, so a new node starts accruing without anyone having to switch it on. Because each node draws its own delay, nodes drift apart instead of all being paid on one shared beat.

  1. On each tick the worker takes the nodes whose timers have come up, up to 200 at a time. The rest wait for the next tick.
  2. It draws a separate amount for each of those nodes from the configured range. One amount reused across the batch would put every node on the same curve, which is what the per-node draw exists to avoid.
  3. The distributor sends one creditBatch call covering all of them, with the HYPE attached, and waits for the receipt.
  4. Only after the receipt confirms are the ledger rows written and each node given a new due time, drawn again and measured from now.

Two consequences follow from that order. A failed chain call leaves the timers in the past, so the next tick retries by itself and nothing is recorded that did not happen. And because the next time is measured from now rather than from when the node was due, an hour of downtime is an hour without credits, not a backlog paid out in one lump. A missed interval is never owed.

The worker also refuses a tick outright when a check fails, for example when the distributor does not hold enough to send the batch and its gas, or when a daily cap on credited value has been reached. A refused tick credits nothing and moves no timers forward. The delay range, the amount range and the cap are operational settings, not promises.

What makes a credit real

The distributor sends creditBatch(ids, amounts) to the factory as a payable call, and msg.value has to equal the sum of amounts or the call reverts with ValueMismatch. The HYPE lands on the balances in the same transaction that records them, so a balance can never exist without the money behind it.

SelinosFactory.creditBatch, the check that backs a balance
uint256 sum;
for (uint256 i; i < n; ++i) {
    uint256 amt = amounts[i];
    if (amt == 0) revert BadInput();
    if (amt > type(uint128).max) revert AmountTooLarge();
    sum += amt;
}
if (sum != msg.value) revert ValueMismatch();

The batch is validated before any storage is touched. An empty batch, mismatched array lengths, a zero amount or an id that was never minted all revert, so a malformed round costs the distributor gas and changes nothing. Each node in a valid batch emits Credited(id, amount, newBalance), documented on Events. The full settlement rules are on Distribution.

Only the distributor can call creditBatch. Anyone can add HYPE to the factory through fund() or a plain transfer, but that money is not attached to any node. It sits as unattached balance, the part rescue is allowed to touch, until a creditBatch call puts value on specific nodes.

Where the value comes from

Node purchases do not feed it directly. A purchase is a plain transfer to the payments wallet, an ordinary account outside the contract, and the factory never sees that HYPE. The money a credit carries is sent by the distributor, and there is no treasury contract in between: the treasury is Selinos’s own funds, topping up the distributor’s float.

Selinos treasuryPaymentA plain transfer tothe payments walletWatcherSees the transfer andrecords the tx hashmintForThe relayer createsthe node, pays the gascreditBatchThe distributor sendsHYPE onto balancesNode balanceHeld on chain,counted in outstandingwithdrawYou call it yourself,the whole balance moves
The path a unit of value takes. The branch dropping into creditBatch is Selinos’s treasury, which is where the credited value comes from.

What the balance numbers mean

FigureWhereMeaning
balancenodeInfo(id)Credited to this node and not yet withdrawn. Withdrawable right now.
totalReceivednodeInfo(id)Everything ever credited to this node. Only increases.
totalWithdrawnByNodenodeInfo(id)Everything ever withdrawn from this node
totalDistributedFactoryEvery wei ever credited to any node
outstandingFactoryThe sum of every node balance: credited, not yet withdrawn
freeBalance()FactoryContract balance above outstanding. The only part rescue can reach.

A node balance is withdrawable the moment the credit confirms, and with Elysium’s blocks landing roughly every 100 ms that is well under a second. There is no unlock, no claim window and nothing to request from Selinos: the owner calls withdraw or withdrawAll from their own wallet. See Withdrawing.

Verifying accrual yourself

You do not have to take any of this on trust. The factory on chain 99901 answers every figure above directly, and its address is listed on Addresses.

cast
# one node: owner, createdAt, balance, totalReceived, totalWithdrawn
cast call $FACTORY "nodeInfo(uint256)(address,uint64,uint256,uint256,uint256)" $ID

# the whole contract
cast call $FACTORY "totalDistributed()(uint256)"
cast call $FACTORY "outstanding()(uint256)"
cast call $FACTORY "freeBalance()(uint256)"
cast call $FACTORY "isSolvent()(bool)"

Every credit also appears as a creditBatch transaction from the distributor, with its HYPE attached, so the value behind a balance can be traced to the transaction that sent it. The public record of rounds is on GET /api/distributions.