Sitowise
Nodes

Deploying a node

Deploying a node starts with a plain 0.02 ETH transfer to the payments wallet. You never call the contract yourself. A watcher sees the transfer and the relayer creates the node against it, which is why the sale can be checked in the explorer.

What you do

  1. Open the dashboard and connect the wallet that will own the node. Ownership is fixed when the node is created and cannot be transferred, so connect the address you actually want.
  2. Sign the sign-in message. No gas, no transaction, no approval to move funds. It creates the session the dashboard reads your nodes with.
  3. Press Deploy a node and confirm the transfer. Your wallet sends exactly 0.02 ETH to the payments wallet. That address is an ordinary account, not the factory and not a contract, so the transaction carries no calldata and does nothing but move value.
  4. Wait. The watcher reads the block, records your transaction, and the relayer calls mintFor and pays that gas. The dashboard shows the node once that call confirms.

The wallet-side walkthrough, with what each prompt looks like, is on Quick start.

What the contract does

mintFor is short, and reading it end to end takes less time than reading a description of it.

SitowiseFactory.mintFor
function mintFor(address to, bytes32 paymentRef) external onlyRelayer returns (uint256 id) {
    if (paused) revert IsPaused();
    if (to == address(0)) revert BadInput();
    if (paymentRef == bytes32(0)) revert BadInput();
    if (paymentRefUsed[paymentRef]) revert RefAlreadyUsed();
    if (_owned[to].length >= maxPerWallet) revert WalletLimit();

    paymentRefUsed[paymentRef] = true;

    id = ++totalNodes;
    _node[id] =
        Node({owner: to, createdAt: uint64(block.timestamp), balance: 0, totalReceived: 0, totalWithdrawn: 0});
    _owned[to].push(id);
    emit NodeMinted(id, to, paymentRef, uint64(block.timestamp));
}
  • The relayer calls it, not you. onlyRelayer means the only address that can create a node is the operator’s relayer key. It pays the gas for the call, and it can do nothing else: crediting and withdrawing are separate roles.
  • No money moves through it. The function is not payable. Your 0.02 ETH went to the payments wallet and never touches the factory, so there is nothing to forward and nothing to refund here.
  • paymentRef is your payment transaction hash. It goes into the NodeMinted event and into the paymentRefUsed mapping. One payment therefore backs exactly one node: a second attempt against the same hash reverts with RefAlreadyUsed. Without that mapping the reference would prove nothing, because one payment could back unlimited nodes.
  • Sequential id. ++totalNodes assigns the next id. Ids start at 1 and are never reused, so totalNodes is also the count of nodes ever created. See Node numbering.
  • The node starts empty. balance, totalReceived and totalWithdrawn are all zero. Value arrives later, in a distribution round.

Why a mint can fail

These are reverts on the relayer’s call, not on a transaction of yours. Your transfer has already happened by then, so a failure here means the payment sits in the queue and is retried, and is raised for a human if it keeps failing.

ErrorMeaningWhat to do
WalletLimit()The paying wallet already holds 25 nodes.Do not pay again from that address; use a different wallet. See Limits.
IsPaused()Node creation is paused by the operator.Wait. Pausing blocks new nodes only, and can never block a withdrawal of value already credited.
RefAlreadyUsed()A node already exists against that payment transaction hash.Nothing. It means your node was created and the mint was attempted twice, so check the dashboard before paying again.
BadInput()A zero destination address or a zero payment reference was passed.Report it. It means a misconfigured relayer, not anything you did.

All four are custom errors and none of them carry arguments, so a wallet or an explorer that decodes them shows the name rather than "execution reverted". The full list is on Factory interface.

Checking your own purchase

Two things tie your money to your node, and both are public. First the payment transaction itself: your address, the payments wallet, exactly 0.02 ETH. Then the NodeMinted log on the factory carrying that same transaction hash as paymentRef, with your address as the owner.

cast
# was a node minted against this payment?
cast call $FACTORY "paymentRefUsed(bytes32)(bool)" $PAYMENT_TX_HASH

# which node ids the address holds, and one of them in full
cast call $FACTORY "nodesOf(address)(uint256[])" $YOUR_ADDRESS
cast call $FACTORY "nodeInfo(uint256)(address,uint64,uint256,uint256,uint256)" $NODE_ID

If paymentRefUsed reads true and a NodeMinted log names your address, the sale is complete regardless of what any interface shows. How to find the log yourself is on Events.

Buying without the website

The dashboard is a convenience. A payment is a plain transfer, so it can be sent from anywhere, including a wallet’s send screen or the command line. Read the destination and the exact wei from GET /api/deploy-quote immediately before you send; they are the server’s values, not constants in this page, and a transfer against an out-of-date pair lands in manual review instead of becoming a node.

cast
# the address to pay and the exact wei to send
curl -s https://sitowise.xyz/api/deploy-quote

cast send $PAYMENT_ADDRESS \
  --value 0.02ether \
  --rpc-url $RPC_URL \
  --private-key $YOUR_KEY
A node bought from the command line is identical to one bought through the site. The relayer mints for whichever address sent the payment, and the dashboard reads nodes from the chain, so it appears there once the mint confirms and your session covers that address.

After the node exists

Your node exists on chain 4663 and is included in future distribution rounds. Credits arrive as real ETH on its balance; what the numbers mean is on Balances, and turning a balance into ETH in your wallet is one call you make yourself, described on Withdrawing.

The 0.02 ETH is spent. It went to a wallet outside the contract, it is not held on your behalf, not refundable, and not recoverable. That is stated again, in context, on Risks.