The system’s doc claims partial or automatic revenue distribution to gauge stakers, but no code path calls the GaugeController’s distributeRevenue(...) from the FeeCollector (or anywhere else). Hence, the synergy for fee distribution across the entire protocol is incomplete or missing, creating a dead portion of the code. Implementing a bridging function or clarifying a manual admin approach ensures the real “80%/20%” revenue share design is actually enforced.
Overview
Fee Collector & Revenue
The FeeCollector contract collects protocol fees and uses a function like distributeCollectedFees() or distribute() for “fees distribution.”
The doc suggests part of these fees should flow to “gauges” or “veToken holders” (like “80% to veRAAC holders” and “20% performance fee”).
GaugeController’s distributeRevenue(...)
The GaugeController declares a function:
This presumably finalizes or routes the revenue to the actual gauges if the protocol picks a “gaugeType.”
No Bridge from Fee Collector to Gauges
Nowhere in the code is there a cross‑call from the FeeCollector to the GaugeController’s distributeRevenue(...).
The FeeCollector never references the gauge or gauge controller.
The GaugeController’s distributeRevenue(...) is never invoked by the FeeCollector.
So the “80% to veRAAC, 20% yield/performance” logic the doc references in multiple places is effectively never triggered or only triggers if some admin manually calls distributeRevenue(...).
Dead “Revenue Distribution” Feature
Even though the code is built to handle “revenue distribution” to gauges or veRAAC holders, there is no actual code path or function that flows from the FeeCollector (where fees accumulate) over to the GaugeController. That means no automatic or triggered revenue sharing per the design.
Contradiction of Documentation
The official doc or code comments say “the protocol revenue is 80% to veRAAC holders, 20% to performance fees (or yield).” In reality, that synergy is never realized—no system component calls the gauge’s distribution function, so the fees remain in the FeeCollector or get stuck in the system unless manually moved by an admin.
Admin-Only Workaround
If the design requires an admin or “EMERGENCY_ADMIN” to call distributeRevenue(...) with some arbitrary amount, that must be documented and consistently used. As is, the code does not show any link from fee accumulation to gauge distribution. This can lead to indefinite hoarding of fees or inconsistent distribution that depends on manual steps.
Protocol Confusion
Users reading the doc about “80% protocol fees allocated to veRAAC holders through gauge distribution” expect an automatic or at least a clear flow. The code includes no bridging call, causing user confusion or an incomplete reward mechanism.
While not a direct exploit that grants an attacker funds, the result is that:
Fees Accrue in the FeeCollector.
The system claims some portion is “destined for gauge rewards or veRAAC holders.”
Since the code never transfers from FeeCollector to the gauge, no user or gauge sees those fees.
Possibly an unscrupulous admin can keep these fees unclaimed or funnel them elsewhere, contradicting the design that automatically or regularly shares them with participants.
Implement Automatic Flow
In the FeeCollector’s distributeCollectedFees() or a new function, call something like:
This ensures the code actually moves the fees from FeeCollector to the gauge system as documented.
Manual Flow
If the design wants a manual approach, clarify in doc that “an admin must pull fees from FeeCollector and call gaugeController.distributeRevenue(...),” ensuring a publicly known procedure.
Possibly define an AccessControl role that calls FeeCollector.transfer(...) to the gauge if that is the intended design.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.