Documentation
Fees and referrals
Where fees come from#
Every trade pays a fee on the quote leg, in the quote asset, from the first trade onward. There are two components:
| Component | Goes to | Set by |
|---|---|---|
| curve / hook fee | split between the protocol and the creator | the launch config and fee policy |
| creator tax | entirely to the creator, never split | TokenParams.creatorTaxBps at launch |
Both are frozen into the launch at creation. A later policy change by the owner affects only launches created after it, so an existing token's economics cannot be altered underneath its holders.
Referrals#
A referred trade is cheaper for the trader and pays the referrer:
- the trader pays a discount on the standard fee,
- the referrer receives a share of what is paid,
- the pool books the remainder.
Bindings are permanent and never rewritten. A user can bind themselves ahead of time with
referralRegistry.setReferrer(address), or a referrer can be passed to the four-argument
curve.buy on their first trade.
On the curve, an invalid referrer reverts the buy. In the pool, the hook is far more forgiving — a rejected binding just charges the standard fee rather than failing the swap.
One security property worth knowing if you build a router: pool-phase hookData can only
ever name the referrer, never the trader. The trader always comes from msgSender(). So
nobody can bind a stranger's referrer with a dust swap.
Claiming#
Everything owed to anyone accumulates in the fee escrow, and every claim is pull-only
by msg.sender — you cannot claim on someone else's behalf. That is deliberate: it means a
recipient who cannot receive a transfer (a blocklisted address, a reverting contract) can
never block a sweep for everybody else.
const owed = await client.readContract({
address: FEE_ESCROW, abi: escrowAbi,
functionName: "balanceOfToken", args: [account, USDC],
});
if (owed > 0n) {
await walletClient.writeContract({
address: FEE_ESCROW, abi: escrowAbi, functionName: "claimToken", args: [USDC],
});
}Fees on Arc are the 6-decimal USDC ERC-20, so claimToken is the path. The native
claim() is unreachable unless a launch quotes in the native asset, which no approved pair
token does.
Pool-phase fees need a sweep first#
Curve fees accrue in the curve and are swept to the escrow by curve.sweepFees(). Pool fees
accrue in the hook and are swept by hook.sweepPoolFees(poolId, minOut) — which may need to
convert memecoin-denominated inventory back to the quote asset against the pool's own
liquidity, which is why it takes a slippage bound.
Referral accruals in the pool are settled with hook.claimReferralFees(referrer, currency),
which is permissionless — anyone can settle anyone's accrual into the escrow. The referrer
then claims from the escrow as above. Two steps, not one.