Skip to main content
Claiming is a single contract call. You do not need to host anything, custody anything, or send users to another app. This guide covers the full flow, the batch case, and the stacks that do not use viem.

The Flow

  1. Fetch the merkle proof for the user and campaign.
  2. Gate the button on claimable > 0n and the correct wallet chain.
  3. Simulate to catch reverts before asking for a signature.
  4. Submit and update your state from the receipt.

Fetch the Proof

What the SDK hands back:
The raw endpoint returns those amounts as decimal strings and publishedAt as unix seconds. The SDK parses both. Skip the SDK and you own that conversion. See Data Conventions.

Gate the Button

Do not gate on campaign.status. Accrual stops when a campaign is ended or cancelled, but rewards already published in a root stay claimable, and finalized means every earned reward is claimable. Gate on the amount and let it decide.
Remember the wallet must be on the reward chain (campaign.id.chainId), which is not necessarily where the position lives.

Simulate First

simulate runs an eth_call and asks for no signature, so it is safe to call on render or on hover. It costs one RPC round trip and turns an on-chain revert into a message you can act on. The revert reasons are listed in Contracts.

Submit With viem

tbi.claim returns as soon as the transaction is broadcast; it does not wait for confirmation. Omit proof and the SDK fetches it for you, but fetching first lets you check claimable before prompting a wallet.

After the Claim

Do not re-read claims.get() to refresh state after a successful claim. The API is served from short caches and can trail the chain by a few minutes, so it may still report the full amount as claimable while the contract has already paid it. A second click in that window reverts with NothingToClaim().
Mark the campaign claimed client-side once you have a transaction receipt, and let the next natural refresh pick up the settled state. If you need the authoritative answer immediately, read it from the chain. See Reading claim state on-chain.

Claim Several Campaigns at Once

A user with positions in several campaigns on the same reward chain can claim them in one transaction through Multicall3.
Pass chainId to let the SDK find every campaign with claimable rewards on that chain, or pass explicit ids when you want control over the set:
claimAll drops zero-claimable proofs and rejects batches spanning multiple reward chains. It is all or nothing: one failing subcall reverts the whole transaction. If you would rather have partial success, loop tbi.claim() per campaign.

Non-viem Stacks

encodeClaim returns plain calldata and touches no wallet.
Use encodeClaimAll({ proofs }) for the batch equivalent. You still install viem for its types, but you never construct a wallet client. The claim function pays its user argument, not msg.sender. That means you can submit claims through your own relayer and cover the gas without ever holding user rewards. Nothing in the SDK or the contract blocks it. Build the calldata with encodeClaim and send it from your own signer.

Gas Expectations

A claim with a five-node merkle proof measured 132,443 gas. Proof length grows with the number of participants, so treat that as a reference point rather than a fixed cost.

Keep Exploring

How Claiming Works

Merkle roots, cumulative amounts, and cliff state.

Contracts

The claim signature and every revert selector.

Errors

Which errors to catch and which retry themselves.