Sitowise
Protocol

Node model

A node is a small, deliberately boring object: a struct in the factory holding an owner, a creation time, a balance and two running totals. Most of the questions people ask about nodes are answered by what the model leaves out.

What exists on chain

Creating a node writes one struct and one array entry, and nothing else.

SitowiseFactory, the node state
struct Node {
    address owner;
    uint64  createdAt;
    uint128 balance;         // withdrawable right now
    uint128 totalReceived;   // credited over the node's whole life
    uint128 totalWithdrawn;
}

mapping(uint256 => Node)      private _node;    // node id -> node
mapping(address => uint256[]) private _owned;   // owner   -> node ids

uint256 public totalNodes;                      // ids are 1-based

A node id is assigned by ++totalNodes, so ids are sequential from 1 and never reused. See Node numbering. There is no accrual rate in the struct and no status flag; the three numbers are simply what has been credited, what has been taken out, and the difference that is sitting there now.

All five fields come back from one call, which is what the explorer’s Read Contract tab needs:

cast
cast call $FACTORY "nodeInfo(uint256)(address,uint64,uint256,uint256,uint256)" $NODE_ID
# -> owner, createdAt, balance, totalReceived, totalWithdrawn

Ownership

The owner is the address the node was created for, which is the address that sent the payment. Every withdrawal path checks it, and the check is on the node itself, against msg.sender:

SitowiseFactory.withdraw
Node storage node = _node[id];
if (node.owner != msg.sender) revert NotNodeOwner();

Because the check is against the caller, nothing can be presented to the contract on somebody else’s behalf. There is no signature to forge, no approval to grant and no server that could authorise a payout: a withdrawal is a transaction from the owning wallet or it does not happen. withdrawAll sweeps only the ids in _owned[msg.sender], so a batch cannot reach a node the caller does not own either. The destination is a separate question and is covered on Destination addresses.

State and lifecycle

On chain a node has no state to be in. It exists from the moment mintFor creates it, and there is no retirement, no expiry and no burn function in the contract. The active and retired distinction lives in the operator’s ledger and controls one thing: whether a node is included in new distribution rounds. It cannot affect a withdrawal, because the contract does not know it exists.

payment, then mintForretirecredited each roundwithdrawwithdrawNot deployedNo node existsActiveReceives creditsRetiredNo new credits
The states a node can be in. Both live states are ledger states; on chain a node simply exists. Withdrawing does not change state, and retirement does not take credited value with it.

The full description of each state is on Node states.

What a node is not

NotWhy it matters
Not a tokenNo ERC-721, no ownerOf, no transfer, no approvals, no marketplace listing. The owner field is written once and there is no function that changes it, so a node cannot be sold or moved to another address.
Not a depositThe 0.02 ETH is a purchase, sent to the payments wallet outside the contract. It is not held for you, it never enters the factory, and it is not refundable.
Not a share of a fundA node is not a claim on any pool of assets. It receives whatever is credited to it, and nothing more.
Not a validatorNothing is run, staked, or secured by holding one. There is no uptime, no slashing, and no hardware.
Not a yield instrumentNo rate is promised anywhere, and Sitowise publishes no projection of what a node will earn.

Holding several

A wallet may hold up to 25 nodes, enforced in mintFor. Nodes held by the same wallet are independent objects: each has its own balance and its own pair of running totals. The dashboard sums them for display, and withdrawAll sweeps them in one transaction, but the contract still accounts for each id separately and emits one Withdrawn per node.

Reading a wallet's nodes
cast call $FACTORY "nodesOf(address)(uint256[])" $WALLET
cast call $FACTORY "nodeCountOf(address)(uint256)" $WALLET
cast call $FACTORY "balanceOfOwner(address)(uint256)" $WALLET

The same view over HTTP is GET /api/nodes/:address.