Skip to content

Wallets and portfolio apps

What a wallet shows and calls: balances, income per asset, drops, claims, signed claims and x402 payments, and the token's mark.

On this page

A revenue token is a plain ERC-20 with 18 decimals and a fixed supply, so a wallet already shows its balance and sends it. What a wallet can add is the holder's income: what it can claim now, in each asset, and the claim itself.

Tell a revenue token apart

Ask the tokenizer: tokenizations(token) has a nonzero way only for a token it made. Any contract can answer tokenizer() with the tokenizer's address, so the token's own answer proves nothing on its own.

What to show

WhatRead it withNote
BalancebalanceOf(account)Income never changes a balance; it is claimed apart.
Whether it earnsearns(account)False only for the Uniswap v4 PoolManager, 0xdead, the token's drop box and the token itself. Tokens in a Uniswap v4 position sit in the PoolManager, so they earn nothing while there.
Income to claim, per assetclaimable(account, i) for each i below assetCount()Asset 0 is ETH; assetAt(i).currency names each other asset, shown in its own decimals. It grows every second while income is released.
Drops to claimdropBox(), then on the box dropCount() and claimable(dropId, account)Each drop is claimed once; one call claims many.
Release periodstreamSeconds()How long each arrival of income takes to release.
Streams and how they endstreamsOf(token) on the tokenizerShow a revenue token turns each record into words.

claimable counts income the token has already recognized. Income still waiting in a door is not in it: the next sync brings it in and releases it over the release period, so the number grows smoothly and never jumps at a sync.

Claims

  • claim(asset, to) pays one asset; claimAll(to) pays every asset with something due. If one asset's payout fails, claimAll reverts as a whole, so fall back to claim asset by asset.
  • to can be any address but zero, the token and its drop box. An ETH payout to a contract that cannot take ETH reverts.
  • A claim that would pay nothing reverts with NothingToClaim, so read claimable first.
  • Drops are claimed from the drop box with claim(dropIds, to), each drop once.

Signed actions

Every holder action can be signed by the holder and sent by anyone else, so a holder can act without ETH for gas as long as someone sends the signed call. The token's EIP-712 domain is its ERC-20 name(), version "1", chain 4663 and the token's address; eip712Domain() answers all of it. The drop box's domain is "Hookr Drop Box", version "1", chain 4663 and the box.

ActionCallSigned over
Approvepermit, with v, r, s or with the signature as bytes for a contract walletPermit(owner, spender, value, nonce, deadline), the nonce from nonces(owner)
Claim one assetclaimWithSig(holder, asset, to, nonce, deadline, signature)Claim(holder, asset, to, nonce, deadline)
Claim every assetclaimAllWithSig(holder, to, nonce, deadline, signature)ClaimAll(holder, to, nonce, deadline)
Claim dropsclaimWithSig(holder, dropIds, to, nonce, deadline, signature) on the drop boxClaimDrops(holder, dropIds, to, nonce, deadline)
PaytransferWithAuthorization sent by anyone, or receiveWithAuthorization sent by the payeeTransferWithAuthorization or ReceiveWithAuthorization (from, to, value, validAfter, validBefore, nonce)
  • Every nonce but the permit's is a random bytes32 the signer picks, used once. authorizationState(signer, nonce) says whether it is spent, and cancelAuthorization, signed by the same signer, spends an unused one.
  • A signed claim pays only the to the holder signed. One that would pay nothing reverts and leaves its nonce unused, so it can be sent again once income is due.
  • A signature can come from a key or, through ERC-1271, from a contract wallet.
  • Hookr runs no relayer. The holder's wallet, your app or any relayer sends the signed call and pays its gas.
  • transferWithAuthorization is the form x402's EVM "exact" scheme settles with: the payer signs under the token's domain above. A signed transfer settles income on both sides like any transfer.

The mark and the code

  • The token's mark is an SVG at https://hookr.fun/api/revenue-tokens/<address>/mark: its underlying token's logo in the tokenizer's ring, or the ring around its letters when there is no logo. A browser will not draw it on a page of another site, so fetch it on your server and serve your own copy.
  • Soon after each mint, Hookr submits the token, its drop box and the doors its own tokenizer and factories made to Sourcify, so a wallet can read their verified code there. Any other door is its builder's to verify.
  • The token's page is https://hookr.fun/revenue/<address>.

Before a holder sends revenue tokens

  • A transfer never carries income with it: the sender keeps what was released while it held the tokens, and the receiver earns from the transfer on. How income accrues has the rule.
  • A transfer to the token's own address reverts. Tokens sent to its drop box earn nothing and can never come back.
  • A contract that cannot claim keeps its share of the income for good: Before you send revenue tokens anywhere.

Show a revenue token and Claim income from a script do all of this in code.