Launch and rewardsGauge controller
Gauge controller
The per-creator fee collector that splits the ShareOFT buy fee into the lottery pot, voter rewards, and a burn.
CreatorGaugeController receives the fee from every qualifying buy of a creator's ShareOFT () and splits it three ways. The ShareOFT, the Uniswap V4 hook, and bridged spoke flushes pay into it; the lottery manager pays winners out of it.
At a glance
| Role | Fee collector and splitter for one creator vault; holds the lottery pot (jackpotReserve) |
| Deployed | Per creator |
| Key relationships | Paid by ShareOFT; pays winners for LotteryManager; burns vault claims () from CreatorOVault; prices WETH buybacks with CreatorOracle |
How it works
A qualifying DEX buy of ShareOFT (a transfer from a SwapOnly address to a non-SwapOnly address) pays a 6.9% fee to this gauge. Wraps, deposits, and bridge receipts don't pay it. The gauge splits the fee in ShareOFT:
- Intake.
receiveFeespulls the fee and creditspendingFees. Nothing is split yet. - Split. When
pendingFeesis at or above the threshold and the distribution interval has passed, the gauge splits automatically. Anyone can also calldistribute()once the interval has passed, without the threshold. - Pot. 69% stays as ShareOFT in
jackpotReserve, the lottery pot. - Voters. 21.39% goes to ve33 voters who voted for this vault that Thursday week.
- Burn. 9.61% unwraps to vault claims () and burns, which raises price per share.
The split is immutable: there is no setFeeSplit, and the creator treasury share is 0%. Conservation is proven in Lean §4 and on gauge fee split.
Lottery payouts are separate from the split. The LotteryManager draws from the pot only when someone wins.
Fees-on-vote and bribes
ve33 voters earn the 21.39% slice by voting for this vault in that Thursday week. See ve4626.
Fees-on-vote is this vault's 21.39% slice of the 6.9% buy fee. A bribe is an optional extra paid on the same vote. A vault can pay both, and neither changes the split.
Bridged fees from spokes
On remote chains, spokeModule.flushFees sends ShareOFT to this gauge over LayerZero (hubGaugeReceiver). LayerZero's _credit mints directly here and does not call receiveFees.
Anyone can call receiveBridgedFees() to move the unaccounted balance (balance − accountedOFTBalance) into pendingFees. The pot is never swept this way. The call auto-splits on the same threshold-and-interval rule as receiveFees. receiveFees, deposit, distribute, and forceDistribute also account unaccounted ShareOFT first, so a later intake picks it up even without this call.
WETH from the V4 hook
The V4 sell tax arrives as WETH and credits pendingWETHFees via receiveWETHFees (or a native wrap). Intake never swaps.
Later, the owner or the wethFeeKeeper calls processWETHFeesWithRoute with a quoted route through an allowlisted router. It buys back ShareOFT into pendingFees. The gauge is a NoFees recipient, so the buyback pays no buy fee. This credit does not auto-split; the normal split runs on the next distribute(). processWETHFeesWithRoute is the live WETH path.
Key functions
| Function | What it does | Who can call |
|---|---|---|
receiveFees(amount) | Pulls ShareOFT buy fees into pendingFees; auto-splits at threshold + interval | Anyone (called by ShareOFT) |
receiveBridgedFees() | Accounts ShareOFT minted by LayerZero flushes; auto-splits at threshold + interval | Anyone |
deposit(amount) | Manual ShareOFT deposit into pendingFees; no auto-split | Anyone |
distribute() | Runs the split once the interval has passed (needs nonzero pendingFees, not the threshold) | Anyone |
queueForceDistribute() / forceDistribute() | Emergency split that bypasses threshold and interval, after a 1-day delay | Owner |
receiveWETHFees(amount) | Credits V4 hook WETH to pendingWETHFees; never swaps | Anyone (called by the hook) |
processWETHFeesWithRoute(wethAmount, router, swapCalldata, minShareOftOut) | Buys back ShareOFT with pending WETH through an allowlisted router | Owner, or wethFeeKeeper up to its cap |
processWETHFees() | Legacy; always reverts RoutedSwapRequired | — |
payJackpot(winner, amount) | Pays a lottery winner from jackpotReserve | LotteryManager only |
getJackpotReserve() | Current pot size | View |
getFeeSplit() | Returns burn, lottery, creator, protocol bps | View |
setCreatorTreasury(treasury) | Sets the creator treasury (share is 0% today) | Owner |
setWethFeeKeeper(keeper) | Names the WETH keeper; address(0) disables it | Owner |
setWethProcessingConfig(maxPermissionlessWethProcess, autoProcessWethFees) | Sets the keeper's per-call WETH cap; the second argument is ignored | Owner |
setAllowedSwapRouter(router, allowed) / executeRouterAllowlist(router) | Queues a router add (1-day timelock) then executes it; removals are immediate | Owner |
Numbers
| Constant | Value | Meaning |
|---|---|---|
| Buy fee | 6.9% | Paid by qualifying ShareOFT buys on the Base book |
lotteryShareBps | 6900 (69%) | Stays in jackpotReserve as ShareOFT |
protocolShareBps | 2139 (21.39%) | Voter slice, in ShareOFT |
burnShareBps | 961 (9.61%) | Unwrapped to and burned |
creatorShareBps | 0 | Creator treasury share is off |
distributionInterval | 1 hour (default) | Minimum time between splits |
CONFIG_UPDATE_TIMELOCK | 1 day | Router allowlist adds and forceDistribute delay |
A lottery win pays 69% of the pot, which is a different number from the 69% fee slice. The ticket formula (4% at $10k, Solana ×400/690) lives on How it works and LotteryManager.
Gotchas
- Two clocks. Voting epochs roll weekly. Fee notifications in epoch E reward E−1 (epoch zero bootstraps into zero); bribes and partner deposits fund E itself. Claims open after the attributed epoch ends. Updated distributor/depot/stream source prohibits sweeping or rolling earned rewards when vault vote weight is nonzero; grace settings apply only to zero-vote bags. Existing deployments retain their old behavior until migrated. UTC-day cover (
k = 1) remains documented v2 behavior, not live. - Personal boost stays at 1.0× until it is armed. v2 is documented, not live. See Lottery personal boost v2.
- WETH processing clock.
lastWethDistributionis tracked separately fromlastDistribution, so a buyback cannot push back the ShareOFTdistribute()interval. OnCreatorGaugeControllerit is written on each successfulprocessWETHFeesWithRoutebut does not rate-limit the next keeper swap.AgentGaugeControlleradditionally gates keepers withlastWethDistribution + wethKeeperCooldown(default 1 hour;setWethKeeperCooldown; 0 disables). The owner is never gated. - Keeper caps.
maxPermissionlessWethProcess = 0disables keeper swaps; the owner is uncapped.autoProcessWethFeesalways stays false. - Router allowlist. Routers live in
allowedSwapRouters. Unknown routers revertRouterNotAllowed. - Oracle floor.
processWETHFeesWithRouteuses the higher of the caller'sminShareOftOutand an oracle TWAP floor. If the oracle floor is enabled but stale or unavailable, it fails closed and fees stay pending. - Creator treasury. If
creatorShareBpswere ever above 0, the treasury must be nonzero (CreatorTreasuryRequired).