Open the app

Claiming pot and royalty payouts

Read how pot and royalty payouts accrue on the native block per quote currency, the three functions and the event that move them, and how to surface a claim on your own page.

Introduction

Two of the native block's five mechanics pay out through the same pull-claim ledger: the Nth-buy pot and the royalty share. Both are read and claimed the same way, on HookrNativeMechanicsBlockV2 at 0xD700492b504ba5A72D7de28dDe11Cd7985a7F1ae. This guide covers how the two accrue, the three functions and the one event that move them, and how to surface a claim on your own page.

How Pot and Royalty Accrue

Every pool's pot and royalty terms are set at creation and frozen: potBps, potEveryNBuys and potMinBuyWei size and gate the pot; royaltyBps and royaltyTo size and address the royalty. See Native mechanics for the full fee math.

  • Royalty accrues on every qualifying buy's cut, a royaltyBps share of what is left after the protocol's own share.
  • The pot builds inside that pool's own counter until a buy makes the running count divisible by potEveryNBuys, at which point the whole pot pays out at once, to that buy's recipient.
  • The moment either pays out, it lands in one ledger keyed only by quote currency and account, never by pool: claimable[quote][account]. A wallet earning royalty on three different ETH-quoted pools, or winning a pot on one and earning royalty on another, sees it all as one balance in ETH and claims it in one transaction.
  • ETH is address(0). A pool quoted in USDG, HOOKR or a tokenized stock uses that token's own address instead, and balances never mix across quote currencies: a wallet owed both ETH and USDG reads and claims each separately.

The Three Functions

FunctionSignatureWhat it does
claimablefunction claimable(address quote, address account) external view returns (uint256)The pull-claim ledger's own getter. Read this to see what one account can claim in one quote currency.
claimfunction claim(address quote) externalPays the caller (msg.sender) everything it is owed in that quote currency.
claimTofunction claimTo(address quote, address to) externalPays to instead of the caller. Still the caller's own balance, just redirected.

claimable is the one to read. Do not confuse it with claimBalance(address quote) public view returns (uint256), a different, module-level number: the module's own backed reserve for that quote currency, used for its own solvency check (accountingInvariant), not any one account's balance.

Both claim and claimTo revert NothingToClaim on a zero balance, and ClaimTransferFailed unless the recipient's measured balance rises by exactly the debited amount, so a quote token that under-delivers fails the claim rather than silently paying less. claimTo also reverts ZeroAddress for to == address(0).

The Claimed Event

event Claimed(address indexed quote, address indexed account, address indexed to, uint256 amount);

All three addresses are indexed. The event is not exclusive to pot and royalty: the treasury forwarder pulls the protocol's own share through this same ledger and this same event, so distinguish the three by account: royaltyTo for a royalty claim, a trader's address for a pot win, and the forwarder's own address for the protocol share. See Events for indexers.

Founding-Position Fees Are Separate

These three functions never touch a new-token market's founding-position fees. Anyone can call coordinator.collectLpFees(poolId) on HookrMarketCoordinatorV5 at 0x53A192A3fCeE94Da77916B461E0cCa2Dd6402442, which pays 100% of both currencies to the market's lpFeeRecipient, chosen at launch and frozen. It reverts NoFoundingPosition on an existing-asset market, which has none. See Collecting fees for all four balances that accumulate around a pool.

Reading and Claiming with viem

import { createPublicClient, createWalletClient, custom, http, type Address } from "viem";

// Robinhood Chain. See "Contracts and addresses" for every deployed address.
const robinhoodChain = {
  id: 4663,
  name: "Robinhood Chain",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
} as const;

const nativeMechanicsBlock = "<HookrNativeMechanicsBlockV2 address, from the table above>" as Address;
const abi = [
  {
    type: "function",
    name: "claimable",
    stateMutability: "view",
    inputs: [
      { name: "quote", type: "address" },
      { name: "account", type: "address" },
    ],
    outputs: [{ name: "", type: "uint256" }],
  },
  {
    type: "function",
    name: "claim",
    stateMutability: "nonpayable",
    inputs: [{ name: "quote", type: "address" }],
    outputs: [],
  },
] as const;

const ETH = "0x0000000000000000000000000000000000000000" as Address;
const account = "<the connected wallet>" as Address;

const publicClient = createPublicClient({ chain: robinhoodChain, transport: http() });

const owed = await publicClient.readContract({
  address: nativeMechanicsBlock,
  abi,
  functionName: "claimable",
  args: [ETH, account],
});

if (owed > 0n) {
  const walletClient = createWalletClient({ chain: robinhoodChain, transport: custom(window.ethereum) });
  const hash = await walletClient.writeContract({
    address: nativeMechanicsBlock,
    abi,
    functionName: "claim",
    args: [ETH],
    account,
  });
  await publicClient.waitForTransactionReceipt({ hash });
}

Reading and Claiming with cast

# ETH is address(0). Swap it for a quote token's own address to check a different currency.
cast call <nativeMechanicsBlock> \
  "claimable(address,address)(uint256)" \
  0x0000000000000000000000000000000000000000 <your-address> \
  --rpc-url https://rpc.mainnet.chain.robinhood.com

cast send <nativeMechanicsBlock> \
  "claim(address)" \
  0x0000000000000000000000000000000000000000 \
  --rpc-url https://rpc.mainnet.chain.robinhood.com \
  --private-key <key>

Surfacing This on Your Own Page

  • Track each of your pools' quote currencies; each is frozen at creation, so read it once and cache it.
  • For the connected wallet, read claimable(quote, account) for each distinct quote currency your pools use. One balance covers every pool sharing that quote, so there is no need to read per pool.
  • Show a claim action when the balance is non-zero. Call claim(quote) to pay the connected wallet, or claimTo(quote, to) to redirect the payout to an address the wallet does not itself control.
  • Re-read the balance after the claim transaction confirms, or watch for Claimed, so the displayed balance returns to zero without a page reload.
  • A read that fails is not the same as a zero balance. Show it as unavailable, the way hookr.fun's own claim panel does, rather than a false "nothing to claim."

Where This Shows on hookr.fun

Hookr.fun surfaces this same read and these same two write calls from one shared claim panel, on two pages: the pool page, for a pool on the new Hookr, and the coin page, for a token launched on it. Both re-read the balance while the tab is visible and again after a claim settles, and both say "unavailable" rather than a false zero when the read itself fails.

Next Steps

Read Integrating as a launcher for how a launcher's own users end up in this same ledger.