Pre-launch. The protocol is not publicly live yet. This documentation describes the contracts as implemented; deployed addresses are published at launch.

Fee Distribution

Every post-graduation fee operation is permissionless. Anyone can trigger distribution; the split is enforced on-chain with no admin override and no discretion.

The split

distributeFees(token) divides accumulated pendingFees[token]:

RecipientV4 familyGnosisMechanism
Deployer30%40%Credited to deployerBalance[token], withdrawn via withdrawDeployerFees()
Protocol10%20%Added to protocolBalance, processed via processProtocolFees()
Reinvest60%40%Swapped and added as permanent liquidity

The deployer and protocol cuts are credited immediately and pendingFees is zeroed before the reinvest swap runs, so nothing is held back to be taxed twice.

Reinvestment

  1. Half the reinvest budget is swapped into tokens (fee-free internal swap)
  2. The other half plus the acquired tokens are added to the existing position
  3. Leftover token dust above 1,000,000 wei is burned to the dead address

If the pool holds too few tokens for a meaningful liquidity add, the branch flips: the remaining native is swapped and burned instead, emitting BuyAndBurn rather than Reinvested.

Capped processing and roll-forward

Reinvestment is bounded by the MEV cap, so a single call may not be able to process the whole pending balance. Rather than reverting, _reinvestAsLiquidity processes the safe portion and returns the remainder, which the caller re-accounts:

  • From distributeFees the remainder goes to protocolBalance — it has already been split, so routing it back to pendingFees would tax it a second time.
  • From processProtocolFees it goes back to protocolBalance and is picked up on the next call.
Dust guards, not economic gates

The only precondition on distribution is a dust check (1,000,000 wei). An earlier design gated processing on an economic floor, which bricked distribution entirely on chains where the MEV cap shrank the safe swap size below that floor — and since pending fees only grow, a bricked distribution never unbricks itself. The floor was removed; sizing is handled by the cap and the roll-forward instead.

$LP24 is handled separately

Fees from the $LP24 pool go 100% to protocolBalance — there is no deployer to pay. distributeFees() rejects $LP24 outright and directs callers to processProtocolFees(), which chooses between two paths based on how many tokens the pool holds:

Pool token sideAction
≥ 24,000,000 tokensBuy and burn — swap the capped native chunk into $LP24 and send it to the dead address
< 24,000,000 tokensReinvest — the pool has been drained by buying pressure, so deepen it instead

The reserve is read from pool state, not from balanceOf on the pool manager — the latter conflates this pool with any other pool holding the same token, which would send the branch the wrong way.

Gnosis: two buckets

V3 pays fees in both currencies, and the manager treats them differently under a hard rule: token-side fees are never sold to the market. The deployer and protocol cuts come exclusively from the native side.

BucketSourceFate
pendingFees[token]Native side of collected V3 feesSplit 40 / 20 / 40
pendingTokens[token]Token side of collected V3 feesBurned, or paired back into liquidity — never sold

Fees must be pulled out of the position first with collectFees(token), which anyone can call. Distribution then follows one of two paths depending on pool depth:

PathConditionBehaviour
DEEPPool ≥ 48,000,000 × 10⁹ (48M tokens)Burn all pending tokens outright; buy-and-burn the entire reinvest budget. No LP'ing — the pool is healthy, so remove supply.
THINPool < 48,000,000 × 10⁹ (48M tokens)Pair pending tokens with the reinvest budget into liquidity to refill depth. Excess tokens are burned; leftover native runs through the normal buy-half-and-LP path.

Buy-and-burn genuinely buys tokens, reducing supply — the inverse of selling. That is why it does not violate the no-selling rule.

Buy-and-burn is not a separate call

There is no buyAndBurn() function and no way for a deployer to elect it. Burning is a branch the contract selects from live pool state inside the ordinary distribution calls:

  • On the V4 hooks, _reinvestAsLiquidity falls through to buy-and-burn when the pool holds too few tokens for a meaningful liquidity add, and processProtocolFees chooses it when the $LP24 pool is token-rich.
  • On Gnosis it is the DEEP path: pool at or above 48,000,000 × 10⁹ (48M tokens) means burn rather than LP.

Which branch ran is visible in the logs — BuyAndBurn(token, nativeSpent) versus Reinvested(token, nativeAmount, tokensAdded, liquidityAdded) — but neither is selectable by the caller.

Deployer withdrawal

After distribution the deployer calls withdrawDeployerFees(token) to withdraw their accrued balance. Only the address currently registered as deployer can call it — which, after a successful CTO, is the new one.

Gnosis thresholds

ThresholdValuePurpose
DISTRIBUTE_THRESHOLD96 xDAITHIN-path mechanism selection: swap now or carry forward
PROTOCOL_THRESHOLD240 xDAISame, for protocol fee processing
POOL_DEPTH_THRESHOLD48,000,000 × 10⁹ (48M tokens)DEEP vs THIN path selection

These select a mechanism; they do not gate whether fees get processed at all. That distinction matters — gating on them was what previously bricked distribution.