Skip to main content

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​

RoleFee collector and splitter for one creator vault; holds the lottery pot (jackpotReserve)
DeployedPer creator
Key relationshipsPaid 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:

  1. Intake. receiveFees pulls the fee and credits pendingFees. Nothing is split yet.
  2. Split. When pendingFees is at or above the threshold and the distribution interval has passed, the gauge splits automatically. Anyone can also call distribute() once the interval has passed, without the threshold.
  3. Pot. 69% stays as ShareOFT in jackpotReserve, the lottery pot.
  4. Voters. 21.39% goes to ve33 voters who voted for this vault that Thursday week.
  5. 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.

A bribe is not fees-on-vote

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​

FunctionWhat it doesWho can call
receiveFees(amount)Pulls ShareOFT buy fees into pendingFees; auto-splits at threshold + intervalAnyone (called by ShareOFT)
receiveBridgedFees()Accounts ShareOFT minted by LayerZero flushes; auto-splits at threshold + intervalAnyone
deposit(amount)Manual ShareOFT deposit into pendingFees; no auto-splitAnyone
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 delayOwner
receiveWETHFees(amount)Credits V4 hook WETH to pendingWETHFees; never swapsAnyone (called by the hook)
processWETHFeesWithRoute(wethAmount, router, swapCalldata, minShareOftOut)Buys back ShareOFT with pending WETH through an allowlisted routerOwner, or wethFeeKeeper up to its cap
processWETHFees()Legacy; always reverts RoutedSwapRequired—
payJackpot(winner, amount)Pays a lottery winner from jackpotReserveLotteryManager only
getJackpotReserve()Current pot sizeView
getFeeSplit()Returns burn, lottery, creator, protocol bpsView
setCreatorTreasury(treasury)Sets the creator treasury (share is 0% today)Owner
setWethFeeKeeper(keeper)Names the WETH keeper; address(0) disables itOwner
setWethProcessingConfig(maxPermissionlessWethProcess, autoProcessWethFees)Sets the keeper's per-call WETH cap; the second argument is ignoredOwner
setAllowedSwapRouter(router, allowed) / executeRouterAllowlist(router)Queues a router add (1-day timelock) then executes it; removals are immediateOwner

Numbers​

ConstantValueMeaning
Buy fee6.9%Paid by qualifying ShareOFT buys on the Base book
lotteryShareBps6900 (69%)Stays in jackpotReserve as ShareOFT
protocolShareBps2139 (21.39%)Voter slice, in ShareOFT
burnShareBps961 (9.61%)Unwrapped to and burned
creatorShareBps0Creator treasury share is off
distributionInterval1 hour (default)Minimum time between splits
CONFIG_UPDATE_TIMELOCK1 dayRouter 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. lastWethDistribution is tracked separately from lastDistribution, so a buyback cannot push back the ShareOFT distribute() interval. On CreatorGaugeController it is written on each successful processWETHFeesWithRoute but does not rate-limit the next keeper swap. AgentGaugeController additionally gates keepers with lastWethDistribution + wethKeeperCooldown (default 1 hour; setWethKeeperCooldown; 0 disables). The owner is never gated.
  • Keeper caps. maxPermissionlessWethProcess = 0 disables keeper swaps; the owner is uncapped. autoProcessWethFees always stays false.
  • Router allowlist. Routers live in allowedSwapRouters. Unknown routers revert RouterNotAllowed.
  • Oracle floor. processWETHFeesWithRoute uses the higher of the caller's minShareOftOut and an oracle TWAP floor. If the oracle floor is enabled but stale or unavailable, it fails closed and fees stay pending.
  • Creator treasury. If creatorShareBps were ever above 0, the treasury must be nonzero (CreatorTreasuryRequired).

Source​