Skip to content

Functions

Note

The gauge system spans three contracts. GaugeController holds votes, weights and the emergency switches; GaugeRewardsDistributor holds the reward token and hands each gauge its per-epoch share; BaseGauge (extended by RAACGauge and RWAGauge) holds stake and streams rewards. Read Gauge States first — almost every gate on this page depends on them.

whenGaugeLive means both switches off

On a gauge, whenGaugeLive requires the controller's global pause and the gauge's own pause to be off. It is not OpenZeppelin's whenNotPaused. withdraw is the one user entry point that carries neither.


GaugeController — Voting

vote

vote(address gaugeAddress, uint256 voteWeight)

Summary Allocates voteWeight basis points of the caller's veRAAC power to a gauge, replacing any previous allocation on that gauge. The vote is snapshotted per underlying veRAAC lock so it decays on its own as those locks expire.

Guarded Method Callable by any veRAAC holder. Subject to whenNotPaused (the controller's global switch) and nonReentrant.

Parameters

Name Type Description
gaugeAddress address Registered gauge to vote on
voteWeight uint256 Basis points, 0 or MIN_VOTE_WEIGHT–MAX_VOTE_WEIGHT

Reverts

Error Condition
VoteDelayNotElapsed() less than WEIGHT_VOTE_DELAY (10 days) since the caller's last vote on this gauge
GaugePaused() non-zero weight on an emergency-paused gauge
GaugeNotActive() the gauge is not registered
InvalidWeight() weight outside the allowed range

Leaving a gauge is always allowed

voteWeight = 0 skips the paused check entirely, so a voter can exit a paused gauge and reallocate elsewhere.


batchVote

batchVote(address[] calldata gaugeAddresses, uint256[] calldata voteWeights)

Summary Votes on several gauges in one transaction. The caller's lock set and epoch context are read once for the whole batch rather than per gauge, which is what makes it cheaper than repeated vote calls.

Guarded Method — whenNotPaused, nonReentrant.

Reverts

Error Condition
ArrayLengthMismatch() empty arrays, or lengths differ
InvalidWeight() the weights sum above MAX_VOTE_WEIGHT
VoteDelayNotElapsed() the cooldown is still running on any gauge in the batch

All-or-nothing

The cooldown is checked per gauge inside the loop, so one gauge still in cooldown reverts the entire batch.


kick

kick(address user)

Summary Removes the phantom votes of a user whose veRAAC power has gone to zero through a ragequit. Without it, their slope keeps decaying gauge aggregates until the originally scheduled expiries fire.

Guarded Method Permissionless. Subject to whenNotPaused and nonReentrant.

Reverts — UserStillHasPower() unless the user has an open veRAAC ragequit request.

Only ragequitters are kickable

The function reads veToken.ragequitRequests(user) and refuses anyone without a pending request. A user who has called finalizeRagequit has their power back and is no longer kickable.


removePowerFromGauge

removePowerFromGauge(address gauge)

Summary Releases the caller's allocation on a removed gauge so it can be reused elsewhere. It clears only the caller's own bookkeeping — the gauge's weight was already stripped from the aggregate by removeGauge.

Guarded Method — whenNotPaused, nonReentrant.

Reverts

Error Condition
ActiveGauge() the gauge is still registered — use vote(gauge, 0) instead
NoPower() the caller has no allocation on it

Removed gauges only, never paused ones

A paused gauge is still active and was never kicked. Calling this on one would double-subtract; the guard prevents it.


forceCompleteCheckpoint

forceCompleteCheckpoint(address gauge) → bool

Summary Advances a gauge's weight checkpoint and the global sum to the current epoch. Permissionless, whenNotPaused, always returns true — the lazy walk completes in one call.


GaugeController — Administration

Function Gate Effect
addGauge(gauge) GAUGE_ADMIN, whenNotPaused registers a gauge, bootstraps its checkpoint pointer and its distributor epoch
removeGauge(gauge, recipient) GAUGE_ADMIN kicks the weight, unregisters, and redirects the unclaimed entitlement to recipient
setDistributor(addr) GAUGE_ADMIN points the controller at a rewards distributor
setMaxVoteBuckets(k) GAUGE_ADMIN 0 = exact per-lock scheduling; 2–64 = bucketed
setBoostAmplificationEnabled(gauge, bool) GAUGE_ADMIN per-gauge boost amplification toggle
setEmergencyGaugePause(gauge, bool) EMERGENCY_ADMIN flips one gauge's own switch
setEmergencyGaugePauseBatch(gauges[], status[]) EMERGENCY_ADMIN same, for a caller-chosen list
setEmergencyPause(bool) EMERGENCY_ADMIN the global switch

addGauge refuses a paused gauge

A gauge that is removed while paused must be unpaused first — which is why setEmergencyGaugePause(gauge, false) is allowed on an unregistered gauge. Without that exception the gauge would be permanently stuck.

removeGauge and the pause functions are not whenNotPaused

Both are deliberately usable during a global pause, so a broken gauge can be removed or isolated while everything else is frozen. setMaxVoteBuckets(1) reverts with InvalidWeight — K = 1 is the degenerate single-average case the per-lock design exists to avoid.

The batch pause is all-or-nothing

setEmergencyGaugePauseBatch reverts the whole call on a zero address, an unregistered gauge being paused, or any gauge already in its requested state. In an incident, a list containing one already-paused gauge fails entirely — build the list from current state.


GaugeController — Views

Function Returns Notes
getActiveGauges() (addresses, weights, totalWeight) registered gauges, projected to the next epoch; paused gauges are included
activeGaugeCount() uint256 count of registered gauges
isGaugeActive(gauge) bool registered, not "unpaused"
getRegisteredGaugeList() address[] raw list
getGaugeRelativeWeight(gauge, epoch) (weight, ...) state-modifying — checkpoints lazily; whenNotPaused
getGaugeRelativeWeightView(gauge, epoch) (weight, ...) pure view; projects forward in memory with the same decay logic
calculateBoost(user, gauge, amount) (boost, ...) ungated view; reverts for an unregistered gauge
getUserVotePowerRemaining(user) uint256 unallocated basis points
getUserGaugeVotePower(user, gauge) uint256 the caller's allocation on a gauge
getExpiredGaugeVotePower(user) (power, gauges[]) allocation sitting on expired locks
getCurrentEpoch() / getNextEpoch() uint256 week boundaries

getGaugeRelativeWeight writes

Despite the name it is not a view: it advances the gauge's checkpoint. Use getGaugeRelativeWeightView from off-chain callers and anything that must not mutate state.


BaseGauge — Staking

stake

stake(uint256 amount)

Summary Pulls staking tokens from the caller, settles their pending rewards, and refreshes their working balance at the current boost.

Guarded Method — whenGaugeLive, gaugeStarted, nonReentrant.

Reverts

Error Condition
InvalidAmount() amount == 0
GaugeNotActive() the gauge is not registered on the controller
GaugeNotStarted() before gaugeInitialStartTime
EnforcedPause() either pause switch is on

Blocked for the whole of either pause

Staking is frozen during a pause on purpose: the reward backlog accruing behind the pause stays with the stakers who were already there, rather than going to whoever enters to catch it.


withdraw

withdraw(uint256 amount)

Summary Settles rewards into claimable, updates the working balance, and returns the staking tokens.

Guarded Method gaugeStarted and nonReentrant only — deliberately not whenGaugeLive, so a pause can never trap principal.

Reverts — InvalidAmount() on zero; InsufficientStakedBalance() if amount exceeds the stake.

No distributor pull

withdraw settles rewards without pulling from the distributor, so it touches only ungated controller views and works in every pause state.


BaseGauge — Rewards

claimRewardToken

claimRewardToken() → uint256

Summary Advances the period, pulls the gauge's share from the distributor if the gauge is registered, settles the caller's rewards and transfers them. RAAC rewards above raacAutolockMin are deposited into the Liquid Locker instead of transferred, while depositRAACOnClaim is set.

Guarded Method — whenGaugeLive, gaugeStarted, nonReentrant.


pullRewardsFromDistributor

pullRewardsFromDistributor() → uint256 transferred

Summary Permissionless. Advances the period and pulls this gauge's accrued share from the distributor, rolling it into the active period's rate.

Guarded Method — whenGaugeLive, gaugeStarted, nonReentrant.

Nothing is stranded by a pause

The gauge's share is held in the distributor across a pause. The first call after the pause is lifted walks every missed epoch and collects the backlog.


claimOnBehalfOf

claimOnBehalfOf(address token, uint256 amount, address user) → uint256

Summary Lets the Liquid Locker claim from its pooled position and route the tokens to an individual user. Works for the main reward token and for registered extra tokens.

Guarded Method — CLAIM_FOR_ROLE, whenGaugeLive, gaugeStarted.

Reverts — InvalidAmount() on zero or when amount exceeds the claimable; InvalidAddress() for a zero user or an unregistered token.

Reward state settles against the caller, not user

The reward accounting (_updateUserReward, the claimable ledger, _updateWorkingBalance) is applied to msg.sender — the locker — while the tokens are transferred to user. That is correct for a pooled position, where the locker holds the stake and user is only a payout destination, but integrators should not read it as a per-user claim.


claimRewardsFor / updateUserRewards

Function Gate Effect
claimRewardsFor(user) DISTRIBUTOR_ROLE, whenGaugeLive batch-claims the main reward token for a user
updateUserRewards(user) permissionless, whenGaugeLive settles a user at their current working balance, then refreshes it

updateUserRewards is also the kick

Refreshing a staker whose veRAAC lock has decayed writes their working balance down, so they stop accruing on a stale boost. It is gated by whenGaugeLive so it cannot be used against stakers during a pause, and it reverts with NotKickable for the Liquid Locker.


Extra reward tokens

Function Gate Notes
addRewardToken(token) GAUGE_ADMIN max MAX_EXTRA_REWARDS (8); reverts FailedToGetTokenDecimals if decimals() is missing
depositRewardToken(token, amount) an approved distributor of this gauge funds an extra-token stream
claimExtraRewards() staker, whenGaugeLive claims every extra token
claimExtraReward(token) staker, whenGaugeLive claims one

Extra rewards stream on raw stake, not working balance

Extra reward tokens are distributed against staked LP balances rather than boosted working balances, so veRAAC boost does not apply to them.


BaseGauge — Administration

Function Gate Effect
manageDistributor(distributor, bool) GAUGE_ADMIN adds or removes an approved extra-reward distributor
setController(addr) GAUGE_ADMIN repoints the gauge at a controller
setDepositRAACOnClaim(bool) DEFAULT_ADMIN_ROLE toggles RAAC autolock on claim
setRaacAutolockMin(uint256) DEFAULT_ADMIN_ROLE threshold below which RAAC is transferred raw
setGaugeRewardDistributor(addr) DEFAULT_ADMIN_ROLE moves DISTRIBUTOR_ROLE to a new distributor
setEmergencyPaused(bool) CONTROLLER_ROLE this gauge's own switch; reverts AlreadyPaused/NotPaused

BaseGauge — Views

Function Returns Notes
balanceOf(account) uint256 working balance — what rewards accrue on
rawBalanceOf(account) uint256 actual staked amount
totalSupply() / rawTotalSupply() uint256 working supply / raw staked supply
earnedReward(token, user) uint256 settled main-token rewards
pendingRewards(token, account) uint256 main-token rewards not yet settled
pendingExtraRewards(token, user) uint256 one extra token
allPendingExtraRewards(user) (tokens[], amounts[]) every extra token at once
getPeriodBoundaries() (start, end) current period
periodDuration() uint256 7 days or 14 days
getRewardTokens() / getExtraRewardTokens() address[] main token first
getUserWeight(account) uint256 the account's voting weight on this gauge
isPaused() bool this gauge's own switch only

balanceOf is the working balance

BaseGauge.balanceOf does not return the staked amount. Integrators wanting the stake must call rawBalanceOf.


GaugeRewardsDistributor

deposit

deposit(address token, uint256 amount)

Summary Permissionless. Records amount of the silo's reward token against the current epoch. It is not split across gauges — each gauge computes its own share when it claims.

Reverts

Error Condition
TokenNotApproved() token is not this silo's reward token
InvalidAmount() zero amount
Unauthorized() no gauge is registered on the controller

claimForGauge

claimForGauge(address gauge) → uint256 totalClaimed

Summary Walks every epoch since the gauge's last claim, sizing its share at each as deposited × relativeWeight / 1e18, and transfers the total.

Guarded Method Callable only by the gauge itself (msg.sender != gauge reverts). nonReentrant.

Reverts — Unauthorized() for any other caller; GaugeNotActive() if the gauge is unregistered.

Double-claim guard

Each claim snapshots depositedAtEpoch in depositedSnapshotAtLastClaim. An epoch whose deposit has not grown since the last claim is skipped, so a gauge cannot drain the same deposit twice.

The walk is unbounded unless capped

With enableMaxClaimBound off, a gauge with a very stale lastClaimedEpoch walks every epoch in one call. setMaxClaimBound(true) caps it at MAX_EPOCHS (52), at the cost of needing repeated calls to catch up.


Administration & recovery

Function Gate Effect
setLastClaimedEpoch(gauge) CONTROLLER_ROLE initialises a new gauge's pointer; no-op if already set
setMaxClaimBound(bool) DISTRIBUTOR_ADMIN caps the epoch walk at MAX_EPOCHS
setController(addr) DEFAULT_ADMIN_ROLE repoints at a controller
withdrawRemovedGaugeRewards(gauge, recipient) CONTROLLER_ROLE pays a removed gauge's unclaimed entitlement out; called by removeGauge
withdrawDust(recipient) DEFAULT_ADMIN_ROLE sweeps deposits from epochs every registered gauge has already passed
claimAll(gauges[]) permissionless calls claimRewardsFor(msg.sender) on each gauge
getClaimableForGauge(gauge) view estimate of a gauge's unclaimed share
getRewardTokenInfo() view totals deposited, distributed, claimable and the live balance

withdrawDust is bounded by the laggard

The sweep only covers epochs below the lowest lastClaimedEpoch across every registered gauge. One gauge that never claims holds the sweep back indefinitely. It reverts with Unauthorized when there is nothing new to process.


Errors

Error Meaning
EnforcedPause() a gauge entry point was called while either switch is on
GaugePaused() non-zero vote on an emergency-paused gauge
GaugeNotActive() the gauge is not registered
GaugeNotStarted() before the gauge's initial start time
ActiveGauge() removePowerFromGauge on a still-registered gauge
VoteDelayNotElapsed() inside the 10-day per-gauge vote cooldown
UserStillHasPower() kick on a user with no pending ragequit
NoPower() no allocation to release
NotKickable() updateUserRewards on the Liquid Locker
InvalidWeight() weight out of range, or setMaxVoteBuckets(1) / > 64
InvalidVeToken() veRAAC's max lock is not 52 weeks
InsufficientStakedBalance() withdrawing more than staked
MaxExtraRewardsReached() more than 8 extra reward tokens
TokenAlreadyInitialized() / NotSupportedToken() extra-token registry
FailedToGetTokenDecimals() the token has no decimals()
DistributorNotAdded() / DistributorNotApproved() depositRewardToken from an unapproved source
TokenNotApproved() wrong token deposited into the distributor
AlreadyPaused() / NotPaused() gauge already in the requested pause state
ArrayLengthMismatch() batch arrays differ in length
Unauthorized() / InvalidAddress() / InvalidAmount() / InvalidGauge() argument and caller validation