29121 - [SC - High] Any rewards sent to the PoolVoter will be undis...

Submitted on Mar 7th 2024 at 18:36:15 UTC by @Trust for Boost | ZeroLend

Report ID: #29121

Report type: Smart Contract

Report severity: High

Target: https://github.com/zerolend/governance

Impacts:

  • Permanent freezing of unclaimed yield

Description

Brief/Intro

The PoolVoter distributes reward tokens to different gauges. Gauges are registered below:

function registerGauge(
    address _asset,
    address _gauge
) external onlyOwner returns (address) {
    if (isPool[_asset]) {
        _pools.push(_asset);
        isPool[_asset] = true;
    }
    bribes[_gauge] = address(0);
    gauges[_asset] = _gauge;
    poolForGauge[_gauge] = _asset;
    _updateFor(_gauge);
    return _gauge;
}

Distribution of rewards other than reward token are done through distributeEx():

The weights are accessed according to the _pools[] entry populated by registerGauge()

Vulnerability Details

Distribution will always fail because there's wrong logic when registering gauges. Specifically this part will never be executed:

The intention is to use !isPool[_asset].

This means _pools will never be populated. After funds are sent to the PoolVoter for dispatch, they can never be claimed by any gauge. There is no escape hatch to unfreeze the rewards.

Impact Details

Rewards sent to the PoolVoter will be forever stuck.

Proof of Concept

The POC is implemented in a single file. Simply run DistributorPOC's PoolFailPOC() which shows that _pools stays empty.

Last updated

Was this helpful?