contracts & integrators
addresses
every address above is rendered from the same config module the app itself trades against — this page cannot drift from the deployment it describes.
rebate attribution — mainnet attribution spec
for teams that route swaps against fairshot-hooked pools — routers, aggregators, wallets, frontends — and want their users to earn the trader rebate. attribution is permissionless: no registration, no allowlist, no coordination with us.
how it works
every fairshot pool is a uniswap v4 pool with a 1% hook fee; 15% of that
fee funds a per-pool, per-epoch trader rebate, paid in WETH. which trades
earn a share is decided by attribution, and attribution is carried in the
swap's hookData. a swap with a valid beneficiary credits that wallet's
volume for the current epoch; a swap without one trades normally, pays the
same fee, and earns nothing.
fairshot pools are identifiable by their pool key: one currency is WETH,
the LP fee is 0, and the hook is the fairshot hook (its address carries
the v4 flag bits 0x2044).
what to send
set the swap's hookData to the ABI-encoding of a single address —
exactly 32 bytes:
bytes memory hookData = abi.encode(beneficiary); // exactly 32 bytes
// viem
import { encodeAbiParameters } from "viem";
const hookData = encodeAbiParameters([{ type: "address" }], [beneficiary]);
hookData is the third argument of IPoolManager.swap(key, params, hookData); the universal router's v4 swap actions and aggregator v4
adapters each carry it per pool hop. only the hop that touches the
fairshot pool needs it.
the beneficiary is the end user — specifically, the address that will
later call claim() itself (claims are strictly msg.sender-gated; there
is no claim-for). for smart-account users that means the smart account's
address — not the signing EOA, not the bundler, and not your router.
never set your own router, solver, or relayer address as the beneficiary. that concentrates all of your users' volume on one address, whose payout is then clipped at the 5% per-wallet epoch cap — stranding the rest of what your users generated, and custodying what's left with you instead of them. one beneficiary per end user, always.
degradation: you can lose the rebate, never the trade
the hook's decode of hookData is total — it can never revert a swap:
| input | result |
|---|---|
empty / absent hookData | swap succeeds, fee routes normally — no attribution |
| wrong length (≠ 32 bytes) | same — no attribution |
| 32 bytes with dirty upper bits | same — no attribution |
| encoded zero address | same — no attribution |
| valid beneficiary, volume below the minimum | swap succeeds — no accrual for that trade |
| valid beneficiary, volume at or above it | volume credited for the current epoch |
unattributed trades also don't enter the epoch's volume denominator, so they never dilute the traders who do attribute. attribution is a hint, not an authorization — it's unsigned, and safely so: it only ever credits the named wallet's own volume counters. naming someone else's address only gifts them volume.
the numbers to build claim UX against
- minimum qualifying trade: 0.001 WETH of WETH-side volume, per swap, either direction.
- per-wallet cap: 5% of an epoch's total pool.
- epochs: 24 hours, per-pool, anchored at the pool's registration — read
currentEpoch(poolId)from the hook; don't compute epochs from wall-clock midnight. - claim window: exactly one epoch. epoch
eis claimable while epoche + 1runs; after that its remainder rolls forward, and after 4 consecutive epochs without full distribution the remainder sweeps to that token's buyback wall — never to the protocol. - useful reads:
currentEpoch,volumeOf,totalVolume,rebatePoolTotal,previewSettleRebateon the hook;claimable,claimedon the rebates contract. volume accrual itself emits no event — read the views for pending amounts.
verify what you integrate against on-chain: the rebates contract's
hook() must return the hook, and the hook address must end in the v4
flag bits 0x2044.