For the complete documentation index, see llms.txt. This page is also available as Markdown.

Fees

The one number

The fee is 1.5% of every swap, buy or sell, plus 0.1% that is automatically returned to the pool as locked liquidity — so the total charged in-swap is 1.6%, and that total is what a quote from the V4 Quoter already reflects. Never subtract anything again when displaying an expected output.

There is no separate token tax, and nothing else is deducted anywhere.

Nothing to integrate

Because the fee is taken at the pool level, there is no fee step in your integration — nothing to collect, route, register or account for, and no way to accidentally skip it. A swap sent through the Universal Router, or through any other path into the pool, pays the same fee before the trader receives their output. Fee accrual and distribution are handled entirely by the protocol's own contracts.

Fees fund the agent's creator, the agent's own treasury (capital the agent itself uses), and the protocol. The creator-side split is configurable at launch. From an integrator's perspective this is background: it never changes what a trader pays or what your swap needs to encode.

The one fee fact your indexer needs

The total is charged as two legs by two different mechanisms, and only one of them is visible to Uniswap's own accounting:

Leg
Size
Visible where

LP leg

0.1%

The Swap event's fee field

Hook leg

1.5%

Hook deltas — never in Swap.fee

So Swap.fee reads 1000 (0.1%) on a normal trade — displaying it as the trading cost understates by 16x. Use the quoter for cost; the split above is only there to explain why that field looks wrong.

Reconstructing what a trade actually cost

There is no per-swap fee event, and per the table above neither Swap.fee nor amount0/amount1 tells you the trader's real rate.

For a live or pending trade, the quoter is exact and cheap: quoteExactInputSingle is already net of both legs.

For a historical trade there are two options, both with costs worth knowing up front:

  • Token transfers. Sum the Transfer logs to and from the taker in that transaction. This gives what they actually paid and received, and needs no archive node — but you must identify the taker first, which is the transaction's from, not Swap.sender.

  • Re-quote at the block. Simulate quoteExactInputSingle at block N−1 and compare. Exact, but needs an archive node and one call per trade.

If you only need a fee column rather than per-trade precision, showing the pool's standing rate is reasonable — provided you do not present it as measured, and you handle the first ten seconds of a pool's life separately.

What the chart shows: two small sells after every buy

On any trade feed you will see each buy followed by two small Sell rows from 0x4e3468…a544. That is the fee engine executing in-swap, not holders exiting:

Row
Size
What it is

First sell

~1.4% of the buy

The revenue fee, taken on the buy's token output and converted to the numeraire immediately — this is why creators and the protocol earn ETH (or the paired stock) instead of decaying tokens.

Second sell

~0.05% of the buy

The auto-compound rebalance: half of the compound slice is converted so both sides can be re-added as full-range, protocol-owned liquidity.

On sells the fee is taken from the numeraire output directly, so there is no conversion row — you may instead see a tiny hook buy when the compound slice rebalances the other way. The math reconciles to the pool's standing rate to the basis point; treat these rows as protocol activity when rendering feeds.

If you run a screener or terminal: tag 0x4e3468…a544 (the Pool Initializer — full address in Deployed Contract Addresses) as a protocol/AMM address, so its conversion swaps render as protocol activity rather than user selling.

Last updated

Was this helpful?