Buyback and Burn
Run a searcher against the Uniswap buyback and burn recipient, which pays out accumulated creator fees in exchange for burning a fixed amount of the token.
The Uniswap buyback and burn recipient pays out accumulated creator fees to anyone willing to burn a fixed amount of the pool's token. Calling it is permissionless and it pays the caller, so third parties compete to run it.
Some creator fee streams are routed to this contract instead of to a creator. It accumulates those fees per position and releases them only against a burn: the caller takes what has accumulated and sends a fixed amount of the pool's token to the burn address in the same transaction. This page is the searcher side, covering what the calls require and when they are worth making.
Fees reach the burn recipient through a fee splitter and then a vesting contract that releases them gradually, so several calls are in play. All but the last are permissionless plumbing that anyone can run, and the last is the one that pays.
Collect Fees Into the Splitter
Swap fees do not appear in any recipient's accounting until someone collects them. A searcher that
only polls amounts(tokenId) will watch a mapping that never moves and conclude there is nothing
to do.
Launch positions are held permanently by the FeeSplitter, and fees sit in the PoolManager until collectFees(tokenIds) pulls them out and pushes each recipient its immutable share. It is permissionless and takes an array, so a searcher can sweep several positions in one call.
Three things make it revert: an empty array, with NoTokenIds; a position the splitter does not own, with NotOwner; and being called while the PoolManager is already unlocked, with PoolManagerAlreadyUnlocked, so collection cannot be nested inside an existing unlock. A recipient that reverts its notification reverts the whole call and leaves those fees in the pool, so exclude a token ID that behaves that way rather than retrying the batch.
Release Fees From Vesting
VestingClaimRecipient holds the beneficiary NFT for a renounced position and meters the fee stream out over time. Its downstream recipient is immutable, set at deployment, so everything it releases goes to the same place.
Two calls move fees through it, both permissionless:
claimFrom(beneficiaryVault, tokenId, minCurrency0Amount, minCurrency1Amount) pulls whatever the vault has attributed to the position into the vesting contract. The vault must be one of the allowlisted ones fixed at deployment, and the vesting contract must already hold that position's beneficiary NFT, otherwise it reverts with NotPositionOwner. The first successful call starts the clock for that position and emits VestingStarted.
claim(tokenId, minCurrency0Amount, minCurrency1Amount) then releases the vested portion into the buyback and burn recipient and registers it there. The amount released is capped at maxCurrency0PerBlock and maxCurrency1PerBlock multiplied by the blocks elapsed since the last claim, so calling it twice in the same block releases nothing the second time. Both caps are immutable and rejected at deployment if zero.
Neither call pays the caller. They exist so the ETH is sitting in the burn recipient when the trade below becomes worth making.
Claim Accumulated Fees
BuybackAndBurnClaimRecipient is a singleton that holds the amounts attributed to each position and releases them only against a burn. It can hold either side of the pair. Today it holds ETH, because creator fees accrue in ETH, but the accounting is per currency and may carry the token side in future launches.
claim(tokenId, minCurrency0Amount, minCurrency1Amount) runs in this order:
- transfers the amounts attributed to
tokenIdto the caller - reverts unless the position's
currency0is native ETH, withÂInvalidCurrency - calls
onClaimed(poolKey, tokenId, currency0Received, currency1Received)on the caller - pulls
minCurrency1BurnAmountof the position'scurrency1from the caller, sends it to0x000000000000000000000000000000000000dEaD, and emitsÂTokensBurned
The whole sequence is one transaction, so a failure at any step reverts the payout as well.
The callback is not optional. The caller of claim must be a contract implementing IClaimExecutor, and it must have approved the recipient for at least minCurrency1BurnAmount of currency1 by the time the callback returns. claim is non-reentrant, and the minCurrency0Amount and minCurrency1Amount arguments let the caller abort when less than expected is attributed.
The burn amount is fixed and the same for every call, so it does not scale with what has accumulated. Read it from minCurrency1BurnAmount(). The payout is whatever has accrued since the last claim, which means the trade becomes profitable once the attributed amount is worth more than the cost of acquiring the burn amount. A searcher watches for that crossing rather than for a schedule.
Running a Searcher
Index the contracts above, then loop:
- call
collectFees(tokenIds)on the fee splitter so accrued swap fees leave the PoolManager and reach the recipients - call
claimFromand thenclaimon the vesting contract to move the released portion into the burn recipient - read
amounts(tokenId)on the burn recipient for what is attributed to the position, andminCurrency1BurnAmount()for the burn cost - when the attributed value exceeds what it costs to acquire the burn amount, call
claimon the burn recipient from your executor
Steps 1 and 2 cost gas and pay nothing, so in practice whoever intends to take step 4 runs them.
What the executor has to do
The contract you call claim from has to satisfy everything the recipient enforces during that single transaction:
- Implement
IClaimExecutor. The recipient callsonClaimedon the caller unconditionally, so a plain EOA cannot claim. - Accept native ETH. The payout is sent before the callback runs, so a contract that cannot receive ETH reverts the whole claim.
- Hold
minCurrency1BurnAmountof the pool's token and approve the recipient for it before the callback returns. The recipient pulls that exact amount immediately afterwards. Where the tokens come from is up to you: a swap funded by the ETH just received, existing inventory, or any other route. - Account for the token side already paid out.
onClaimedreports both currencies received. If the position carried a token amount, you only need to source the difference. - Have a way to withdraw. Whatever is left after funding the burn is your profit, and it stays in the contract until you move it out.
Bound the price you are willing to pay when you source the burn amount. minCurrency0Amount only floors the payout, so a claim that clears it can still settle at a loss if the token has appreciated.
Where to Go Next
- Deployments for the recipient address
- Collect and Compound Fees for the compounding recipient, a different mechanism
- Instant Launch