Sitowise
Contracts

Events

The factory emits enough to reconstruct the protocol’s entire history from logs alone: every node and the payment that bought it, every credit, every payout and every configuration change. This page lists all of them.

Factory events

SitowiseFactory
event NodeMinted(uint256 indexed id, address indexed owner, bytes32 paymentRef, uint64 createdAt);
event Credited(uint256 indexed id, uint256 amount, uint256 newBalance);
event Withdrawn(uint256 indexed id, address indexed to, uint256 amount);
event RelayerChanged(address relayer);
event DistributorChanged(address distributor);
event PausedChanged(bool paused);
event MaxPerWalletChanged(uint256 max);
event OwnerChanged(address owner);
event OwnershipOfferStarted(address indexed pendingOwner);
event Funded(address indexed from, uint256 amount);
event Rescued(address indexed to, uint256 amount);
EventEmitted when
NodeMintedThe relayer creates a node. paymentRef is the hash of the transfer that paid for it, which is what makes the sale checkable
CreditedA node’s balance goes up, once per node per batch. newBalance is the balance after the credit, so a single log is enough to know where a node stands
WithdrawnA node owner takes their balance. withdrawAll emits one of these per node it sweeps, inside one transaction
RelayerChanged, DistributorChangedA role is rotated, and also once each from the constructor with the deploy-time values
OwnershipOfferStarted, OwnerChangedThe two halves of the ownership handover. The first is only an offer; the second is the transfer actually taking effect, and it also fires once at deployment
PausedChanged, MaxPerWalletChangedThe owner changes a setting. Neither can affect an existing balance
FundedETH arrives without being attached to a node, through fund() or a plain transfer to the contract. This is what a mistaken transfer to the factory produces
RescuedThe owner takes unattached funds out. It can never exceed freeBalance(), so it can never be a holder’s money
Two of the eleven fire at deployment rather than in response to anything an operator did later: the constructor emits OwnerChanged, RelayerChanged and DistributorChanged so that the initial roles are in the log history and not only in storage.

Reconstructing the protocol from logs

These four are enough to rebuild every number this site displays, without trusting the site:

  1. NodeMinted gives you every node, its owner at mint, and the payment behind it.
  2. Credited summed per node gives totalReceived; summed overall it gives totalDistributed.
  3. Withdrawn summed the same way gives totalWithdrawn.
  4. Credits minus withdrawals equals outstanding, which the contract also reports directly. If the two disagree, one of them is wrong and it is worth knowing which.

Nodes are not tokens and cannot be transferred, so ownership never changes after NodeMinted. There is no transfer log to follow and none is missing.

Hook events

SitowiseHook, not deployed
event SwapAccrued(
    PoolId indexed poolId,
    address indexed currency,
    uint256 amount,
    uint256 cumulative,
    uint16 shareBps
);
event Swept(address indexed currency, address indexed to, uint256 amount);
event FactoryChanged(address indexed oldFactory, address indexed newFactory);
event ShareBpsChanged(uint16 oldShareBps, uint16 newShareBps);
event SweepRecipientChanged(address indexed oldRecipient, address indexed newRecipient);

SwapAccrued would be the one that matters for anyone checking whether the protocol is swap funded. It is designed to fire once per swap that produced a non-zero share, so the day it exists, an empty log is a complete answer: if it has never fired, no swap has ever paid this hook. Today there is no hook address to query at all, which is the same answer arrived at sooner.

Topic hashes

Topic zero is the keccak hash of the event signature with canonical types. Recompute any of these rather than trusting the table: cast keccak "Credited(uint256,uint256,uint256)".

EventTopic 0
NodeMinted(uint256,address,bytes32,uint64)0x01f6c872d9a3a5d1c63c69a4edd6004260f7ac9b086be1468e99f0569307bd1c
Credited(uint256,uint256,uint256)0x3806c51c015e3f5bafa6a64bacc9ec78aa02f9a208d9d22e52635e923ba00f6e
Withdrawn(uint256,address,uint256)0xcf7d23a3cbe4e8b36ff82fd1b05b1b17373dc7804b4ebbd6e2356716ef202372
Funded(address,uint256)0x5af8184bef8e4b45eb9f6ed7734d04da38ced226495548f46e0c8ff8d7d9a524
Rescued(address,uint256)0x8aec0ce3dadffacf4b7a963e0fed1ff2e6151b4c95d4a65acafa9d1299630402
OwnerChanged(address)0xa2ea9883a321a3e97b8266c2b078bfeec6d50c711ed71f874a90d500ae2eaf36
RelayerChanged(address)0x88cb58f8479aba47ccd2dcbc41bf94bc01e3f58a877cbe5e7f3bd978d89773ba
DistributorChanged(address)0xe37acc13f5ed9d0cc83c2842e093fe5a494d5b8fb5b1db06356b327081832f52
PausedChanged(bool)0xd83d5281277e107f080e362699d46082adb74e7dc6a9bccbc87d8ae9533add44
MaxPerWalletChanged(uint256)0x00c836a17ed3a6a59dce35376ae3c2777797dc03f39f463153c0fea5b65f0683
OwnershipOfferStarted(address)0x23a54ba7a990a65d3d8c17e693e5b066e88154ce314d568de26f02e98ac33dd1

Reading logs

cast
# every node minted, from deployment to now
cast logs --from-block 0 \
  --address $FACTORY \
  "NodeMinted(uint256,address,bytes32,uint64)" \
  --rpc-url https://rpc.mainnet.chain.robinhood.com

# every credit to one node, using the indexed id as the second topic
cast logs --from-block 0 \
  --address $FACTORY \
  "Credited(uint256,uint256,uint256)" \
  --rpc-url https://rpc.mainnet.chain.robinhood.com

# payouts, filterable by destination through the second indexed topic
cast logs --from-block 0 \
  --address $FACTORY \
  "Withdrawn(uint256,address,uint256)" \
  --rpc-url https://rpc.mainnet.chain.robinhood.com

With viem, the same thing is a typed getLogs against the generated ABI. The application ships that ABI, including the custom errors, so a revert is decoded into a real reason instead of "execution reverted". The error list is on Factory interface.

Both NodeMinted and Withdrawn index the node id first and an address second, so a wallet’s whole history can be filtered on topics without downloading every log the contract ever wrote.

What is not in the logs

The payment that buys a node is not a factory event, because it does not touch the factory. It is an ordinary transfer to the payments wallet, visible on the explorer as such, and it is tied to the node by its hash appearing as paymentRef in NodeMinted. That is the join between the two halves of the sale. See Settlement.

The decision behind a credit is not on chain either. Which nodes are credited and by how much is computed off chain by the distribution worker; what the chain records is the result, with the ETH attached. The per-node history is also available over HTTP from GET /api/node/:id, which is a convenience, not the source of truth.

Sign-ins are not on chain. Signing in produces a message signature, not a transaction, so it leaves no trace on the network.