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
- 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.
- Sign the sign-in message. No gas, no transaction, no approval to move funds. It creates the session the dashboard reads your nodes with.
- 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.
- Wait. The watcher reads the block, records your transaction, and the relayer calls
mintForand 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.
GET /api/deploy-quote, which is what the deploy flow fills the transfer in from. Read them at the moment you pay rather than from a saved copy: the contract has no price() and never sees the payment, so that endpoint is the only source that cannot go stale, and it answers 503 rather than quoting a zero address if the payments wallet is not configured.What the contract does
mintFor is short, and reading it end to end takes less time than reading a description of it.
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.
onlyRelayermeans 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. paymentRefis your payment transaction hash. It goes into theNodeMintedevent and into thepaymentRefUsedmapping. One payment therefore backs exactly one node: a second attempt against the same hash reverts withRefAlreadyUsed. Without that mapping the reference would prove nothing, because one payment could back unlimited nodes.- Sequential id.
++totalNodesassigns the next id. Ids start at 1 and are never reused, sototalNodesis also the count of nodes ever created. See Node numbering. - The node starts empty.
balance,totalReceivedandtotalWithdrawnare 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.
| Error | Meaning | What 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.
# 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_IDIf 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.
# 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_KEYAfter 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.