Skip to content

BribeDistributor

Direct (non-Merkle) bribe distribution for gauge voters. Deposits spread across future weekly epochs; claims use frozen per-epoch vote snapshots from GaugeController.

Source: khomdev-veforge/src/BribeDistributor.vy (Vyper 0.4.x)

Dependencies: GaugeController · EmissionRouter

Implementation overview

  • Deposits — split evenly across _num_epochs future weeks; remainder → final epoch (M3)
  • Claims — share = bribe * user_bias / gauge_total_bias at closed epoch; reads vote_user_slopes_at + points_weight (C3/C4)
  • Solvencyclaimed_total per bucket prevents overdraw (A2)
  • Sweep — owner reclaims dust/unclaimed after 90 days (A1)
  • Fees — protocol fee on claim, capped at 10% (L3)
flowchart LR
    ER[EmissionRouter] -->|deposit_bribe| BD[BribeDistributor]
    GC[GaugeController] -->|vote_user_slopes_at| BD
    User -->|claim| BD

Immutables

Name Role
GAUGE_CONTROLLER GaugeController for weight snapshots

Constants

Name Value Role
WEEK 604800 Epoch alignment
SWEEP_DELAY 90 days Min age before sweep
MAX_FEE_BPS 1000 (10%) Fee cap
MAX_NUM_EPOCHS 52 Max deposit spread
MAX_BATCH 64 claim_many limit

Roles

Role Powers
owner (2-step) set_fee_params, sweep_unclaimed
fee_recipient withdraw_protocol_fees

Events

Event When
BribeDeposited Deposit recorded
BribeClaimed User claim (net + fee)
FeeParamsUpdated Fee config change
ProtocolFeesWithdrawn Fee sweep
SweepUnclaimed Owner sweep

Views

current_epoch

BribeDistributor.current_epoch() -> uint256

Current week-aligned epoch (start of this week in seconds).

Returns: uint256(block.timestamp // WEEK) * WEEK.

Access: view, any caller.

Source (khomdev-veforge/src/BribeDistributor.vy:145-149):

@external
@view
def current_epoch() -> uint256:
    return (block.timestamp // WEEK) * WEEK

Cross-links: claim · deposit_bribe

Deposit

deposit_bribe

BribeDistributor.deposit_bribe(_gauge, _token, _amount, _num_epochs)

Deposit a bribe for a gauge in a token, spread over future weekly epochs.

Param Type Description
_gauge address Gauge — must be GC-registered (A1)
_token address ERC-20 reward token
_amount uint256 Total to distribute (≥ _num_epochs)
_num_epochs uint256 Spread length; 1..52

Access: Caller. nonreentrant. Pulls tokens via transferFrom.

Events: BribeDeposited.

Reverts if: unknown gauge, zero amount, bad num_epochs, or per_epoch underflow.

Note: Remainder from floor division credited to final epoch (M3).

Source (khomdev-veforge/src/BribeDistributor.vy:178-222):

@external
@nonreentrant
def deposit_bribe(_gauge: address, _token: address, _amount: uint256, _num_epochs: uint256):
    assert staticcall IGaugeController(GAUGE_CONTROLLER).is_gauge_added(_gauge), "BD: unknown gauge"
    per_epoch: uint256 = _amount // _num_epochs
    # ... credit bribes[gauge][target_epoch][token]
    log BribeDeposited(depositor=msg.sender, gauge=_gauge, token=_token, amount=_amount, num_epochs=_num_epochs)

Example:

token.approve(bd.address, amount)
bd.deposit_bribe(gauge, token.address, amount, 4)

Cross-links: EmissionRouter.distribute · GaugeController.is_gauge_added

Claim

claim

BribeDistributor.claim(_gauge, _epoch, _token)

Claim caller's share of bribes for (gauge, epoch, token). Epoch must be closed and week-aligned.

Param Type Description
_gauge address Gauge
_epoch uint256 Closed week-aligned epoch
_token address Reward token

Access: Caller. nonreentrant.

Events: BribeClaimed.

Reverts if: epoch not closed, not aligned, already claimed, no bribes, zero gauge weight, or bucket overdrawn (A2).

Note: Calls checkpoint_gauge internally. Share from frozen vote_user_slopes_at snapshot (C3).

Source (khomdev-veforge/src/BribeDistributor.vy:227-298):

@external
@nonreentrant
def claim(_gauge: address, _epoch: uint256, _token: address):
    self._claim(msg.sender, _gauge, _epoch, _token)

# _claim: user_share = bribe_amount * user_bias // total.bias
# assert claimed_total + user_share <= bribe_amount

Cross-links: GaugeController.vote_user_slopes_at · claim_many

claim_many

BribeDistributor.claim_many(_claims)

Batch claim up to 64 (gauge, epoch, token) tuples. All-or-revert.

Param Type Description
_claims DynArray[ClaimRequest, 64] {gauge, epoch, token} per entry

Access: Caller. nonreentrant.

Events: BribeClaimed per successful claim.

Reverts if: any single claim in batch fails.

Source (khomdev-veforge/src/BribeDistributor.vy:237-246):

@external
@nonreentrant
def claim_many(_claims: DynArray[ClaimRequest, MAX_BATCH]):
    for req: ClaimRequest in _claims:
        self._claim(msg.sender, req.gauge, req.epoch, req.token)

Cross-links: claim

Admin

sweep_unclaimed

BribeDistributor.sweep_unclaimed(_gauge, _epoch, _token, _to)

Reclaim unclaimed + dust after 90 days past epoch. Owner-only (A1).

Param Type Description
_gauge address Gauge
_epoch uint256 Week-aligned epoch
_token address Token
_to address Recipient (non-zero)

Access: Owner only. nonreentrant.

Events: SweepUnclaimed.

Reverts if: zero recipient, epoch not aligned, or sweep too early.

Note: Sets claimed_total = bribes to close bucket after sweep.

Source (khomdev-veforge/src/BribeDistributor.vy:303-333):

@external
@nonreentrant
def sweep_unclaimed(_gauge: address, _epoch: uint256, _token: address, _to: address):
    ownable._check_owner()
    assert block.timestamp >= _epoch + SWEEP_DELAY, "BD: sweep too early"
    remaining: uint256 = total - already
    self.claimed_total[_gauge][_epoch][_token] = total

Cross-links: claim

set_fee_params

BribeDistributor.set_fee_params(_bps, _recipient)

Update protocol fee rate and recipient. Owner-only. Fee capped at 10% (L3).

Param Type Description
_bps uint256 Fee in basis points (≤ 1000)
_recipient address Fee recipient

Access: Owner only.

Events: FeeParamsUpdated.

Reverts if: _bps > MAX_FEE_BPS.

Source (khomdev-veforge/src/BribeDistributor.vy:336-346):

@external
def set_fee_params(_bps: uint256, _recipient: address):
    ownable._check_owner()
    assert _bps <= MAX_FEE_BPS, "BD: fee > MAX_FEE_BPS"
    self.fee_bps = _bps
    self.fee_recipient = _recipient

withdraw_protocol_fees

BribeDistributor.withdraw_protocol_fees(_token)

Sweep accumulated protocol fees for a token to fee_recipient.

Param Type Description
_token address Token to withdraw

Access: fee_recipient only. nonreentrant.

Events: ProtocolFeesWithdrawn.

Reverts if: caller is not fee recipient.

Source (khomdev-veforge/src/BribeDistributor.vy:349-364):

@external
@nonreentrant
def withdraw_protocol_fees(_token: address):
    assert msg.sender == self.fee_recipient, "BD: not fee recipient"
    self._safe_transfer(_token, msg.sender, amount)