> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bags.fm/llms.txt
> Use this file to discover all available pages before exploring further.

# Claim Creator Fees

> Understand the Bags fee-share model on Robinhood Chain and claim accrued creator fees from a token's BagsFeeShare contract with viem.

In this guide, you'll read and claim the creator side of trading fees on Robinhood Chain. Each token has its own `BagsFeeShare` contract that accrues **1% of every trade** (in WETH) and splits it among the claimers configured at launch.

## Prerequisites

Before starting, make sure you have:

* Completed the [Environment Setup](/robinhood/setup).
* A token whose `feeShare` address you can resolve (from launch, `factory.feeShareForToken(token)`, or `BagsLens.getTokenState`).
* A wallet with a positive claimable balance — i.e. one of the token's configured fee claimers or the optional partner. Check with `claimableOf(token, user)` (or `feeShare.claimable(user)`).

## 1. How Fee Sharing Works

Of the flat 2% trade fee, half (1%) goes to the platform vault and half (1%) is delivered to the token's `BagsFeeShare`, where it accrues in WETH. That full creator side is split among the recipients configured at launch — there is no separate protocol cut taken here. When fees are notified, the contract splits the notified `amount`:

```text theme={null}
partnerShare = amount * PARTNER_BPS / 10000     -> claimable[partner]   (if a partner was set)
claimerPot   = amount - partnerShare
each claimer : claimerPot * bps[i] / 10000      (last claimer absorbs rounding dust)
```

This mirrors the `FeeNotified(amount, partnerShare, claimerPot)` event: `partnerShare + claimerPot == amount`. Each recipient's balance accumulates in `claimable[address]` until they call `claim`. This happens automatically as trades occur in **both** phases — creators earn from bonding-curve trades and pool trades alike.

<Note>
  Post-migration fees first accrue inside the Bags v4 hook and are periodically swept into the fee-share contract. `claim` pokes that sweep for you, so you don't need a separate sweep transaction.
</Note>

## 2. Read Claimable Fees

Use `BagsLens.claimableOf(token, user)` for the amount claimable **right now** (already notified to the fee-share, in WETH wei):

```typescript read-claimable.ts theme={null}
import { publicClient } from "./clients";
import { ROBINHOOD_LAUNCHPAD } from "./addresses";
import { bagsLensAbi } from "./abi";
import type { Address } from "viem";

export async function readClaimable(token: Address, user: Address): Promise<bigint> {
  return publicClient.readContract({
    address: ROBINHOOD_LAUNCHPAD.lens,
    abi: bagsLensAbi,
    functionName: "claimableOf",
    args: [token, user],
  });
}
```

You can also read directly from the fee-share contract:

| Call                                            | Returns                              |
| ----------------------------------------------- | ------------------------------------ |
| `feeShare.claimable(user)`                      | WETH wei claimable now for `user`    |
| `feeShare.getClaimers()`                        | `(address[] claimers, uint16[] bps)` |
| `feeShare.claimerBps(user)`                     | A user's share in bps                |
| `feeShare.PARTNER()` / `feeShare.PARTNER_BPS()` | Partner address and its bps          |

<Tip>
  `claimableOf` counts only WETH already notified to the fee-share. Fees still sitting un-swept in the v4 hook are not included; they become claimable once `claim` (or another sweep) flushes them.
</Tip>

## 3. Claim Fees

Call `claim(unwrap)` on the token's `BagsFeeShare`. Pass `unwrap: true` to receive native ETH; `false` leaves the payout as WETH.

```typescript claim-fees.ts theme={null}
import "dotenv/config";
import { publicClient, getWalletClient } from "./clients";
import { bagsFeeShareAbi } from "./abi";
import { readClaimable } from "./read-claimable";
import type { Address } from "viem";

export async function claimFees(feeShare: Address, unwrap = true) {
  const walletClient = getWalletClient();
  const txHash = await (async () => {
    // Simulate first so custom errors (e.g. BagsFeeShare_NothingToClaim) decode cleanly.
    const { request } = await publicClient.simulateContract({
      account: walletClient.account,
      address: feeShare,
      abi: bagsFeeShareAbi,
      functionName: "claim",
      args: [unwrap],
    });
    return walletClient.writeContract(request);
  })();

  const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
  if (receipt.status !== "success") throw new Error("Claim reverted.");
  console.log(`Claimed. Tx: https://robinhoodchain.blockscout.com/tx/${txHash}`);
  return { txHash };
}

// Example: resolve feeShare from the token, then claim as native ETH.
async function main() {
  const token = "0xTOKEN_ADDRESS" as Address;
  const user = getWalletClient().account.address;

  const feeShare = await publicClient.readContract({
    address: (await import("./addresses")).ROBINHOOD_LAUNCHPAD.factory,
    abi: (await import("./abi")).bagsFactoryAbi,
    functionName: "feeShareForToken",
    args: [token],
  }) as Address;

  const claimable = await readClaimable(token, user);
  if (claimable <= 0n) {
    console.log("Nothing to claim yet.");
    return;
  }
  console.log(`Claimable: ${claimable} WETH wei`);
  await claimFees(feeShare, true);
}

main().catch(console.error);
```

<Warning>
  Check `claimableOf` (or `feeShare.claimable`) is greater than zero before claiming. Calling `claim` with nothing to claim reverts with `BagsFeeShare_NothingToClaim` and wastes gas.
</Warning>

## 4. Estimate Pending (Un-Swept) Fees

For a fuller picture of what a creator will eventually receive, add the un-swept accrual sitting in the v4 hook for the token's pool. The hook exposes per-pool pending fees; the creator side is half of it, split among the partner (if any) and the claimers by bps.

```typescript pending-estimate.ts theme={null}
import { publicClient } from "./clients";
import { ROBINHOOD_LAUNCHPAD, ROBINHOOD_FEES } from "./addresses";
import { bagsLensAbi, bagsFeeShareAbi, bagsV4HookAbi } from "./abi";
import type { Address } from "viem";

/** Claimable-now plus an estimate of the user's cut of un-swept hook fees. */
export async function readClaimableBreakdown(token: Address, user: Address) {
  const state = await publicClient.readContract({
    address: ROBINHOOD_LAUNCHPAD.lens, abi: bagsLensAbi, functionName: "getTokenState", args: [token],
  });
  if (!state.exists) return null;

  const [claimable, claimers, partnerBps, pool] = await Promise.all([
    publicClient.readContract({ address: ROBINHOOD_LAUNCHPAD.lens, abi: bagsLensAbi, functionName: "claimableOf", args: [token, user] }),
    publicClient.readContract({ address: state.feeShare, abi: bagsFeeShareAbi, functionName: "getClaimers" }),
    publicClient.readContract({ address: state.feeShare, abi: bagsFeeShareAbi, functionName: "PARTNER_BPS" }),
    publicClient.readContract({ address: ROBINHOOD_LAUNCHPAD.hook, abi: bagsV4HookAbi, functionName: "pools", args: [state.poolId] }),
  ]);

  const [addresses, bps] = claimers;
  const i = addresses.findIndex((a) => a.toLowerCase() === user.toLowerCase());
  const userBps = i === -1 ? 0 : bps[i];
  const pendingFees = pool[2]; // un-swept WETH accrual for this pool (both fee legs)

  // On sweep the accrual splits 50/50: half to the platform vault, half is the
  // creator side delivered to the fee-share (there is no separate protocol cut on
  // that leg). A partner, if configured, takes PARTNER_BPS of the creator side
  // before claimers split the remainder by bps. Multiply before dividing to limit
  // truncation. This estimates a claimer's cut; a partner reads their own row.
  const bpsDenom = BigInt(ROBINHOOD_FEES.bpsDenominator);
  const creatorSide = pendingFees / 2n;
  const partnerShare = (creatorSide * BigInt(partnerBps)) / bpsDenom;
  const claimerPot = creatorSide - partnerShare;
  const pendingUserEstimate = (claimerPot * BigInt(userBps)) / bpsDenom;

  return { claimable, pendingFees, userBps, isClaimer: i !== -1, feeShare: state.feeShare, pendingUserEstimate };
}
```

<Note>
  The exact field layout of the hook's `pools(poolId)` return tuple is defined in `BagsV4Hook.json`; `pool[2]` is the pending WETH accrual in the reference implementation. Confirm the index against the ABI you import. `pendingUserEstimate` is an estimate — the exact amount is settled when the sweep runs during a claim.
</Note>

## Troubleshooting

* **`BagsFeeShare_NothingToClaim`** — your `claimable` balance is zero. Wait for trades to accrue fees (or for a sweep to flush hook fees), and check `claimableOf` before claiming.
* **`BagsFeeShare_NotAuthorized`** — only the bonding curve and hook may notify fees; you can't call `notifyFee` yourself. Just call `claim`.
* **Claim succeeds but you received WETH, not ETH** — you passed `unwrap: false`. Pass `true` for native ETH, or unwrap the WETH yourself later.
* **Not a claimer** — only the token's configured `claimers` and its optional `partner` accrue fees. Verify eligibility with `claimableOf(token, user)` (or `feeShare.claimable(user)`) being greater than zero. Note `feeShare.getClaimers()` lists only the configured claimers — it does **not** include the partner.

For the full function, event, and error catalog, see the [Contracts Reference](/robinhood/contracts).
