Lucene search

K
code423n4Code4renaCODE423N4:2023-08-VERWA-FINDINGS-ISSUES-401
HistoryAug 10, 2023 - 12:00 a.m.

GaugeController - Vulnerability with changing gauge weight would make the contract stop working

2023-08-1000:00:00
Code4rena
github.com
6
gaugecontroller
vulnerability
contract malfunction
change_gauge_weight
front-run
manipulation
revert
time_weight
initialized
vote
points_weight
dos

Lines of code

Vulnerability details

Impact

The issue is applied differently based on how change_gauge_weight works.

1. When changing gauge weight is essential for every enabled gauge before any vote happens

An attacker can front-run change_gauge_weight transaction to manipulate slope which can result in reverts in the future in getting the gauge weight

2. When changing gauge weight is optional for gauges

Vote does not have effect before change_gauge_weight is called once.

Proof of Concept

  function _get_weight(address _gauge_addr) private returns (uint256) {
      uint256 t = time_weight[_gauge_addr];
      if (t > 0) {
        // time_weight[_gauge_addr] is updated here
        ...
      } else {
          return 0;
      }
  }

In _get_weight function, time_weight is updated to next_time when original value is set.
The time_weight for a gauge is initialized only through change_gauge_weight.

So when vote_for_gauge_weights is called before time_weight is initialized, _get_weight always return zero and time_weight also remains zero.
Thus, updating points_weight has no effect but changes_weight has effect.

  function _get_weight(address _gauge_addr) private returns (uint256) {
      uint256 t = time_weight[_gauge_addr];
      if (t > 0) {
        ...
          if (pt.bias > d_bias) {
              pt.bias -= d_bias;
              uint256 d_slope = changes_weight[_gauge_addr][t];
              pt.slope -= d_slope; // <-- where issue happens
          } else {
              pt.bias = 0;
              pt.slope = 0;
          }
        ...
      } else {
          return 0;
      }
  }

Assuming there are some vote transactions that are front-run before change_gauge_weight is called, at some point in the future, _get_weight can be reverted on the line mentioned above.
Because, points_weight is not changed so pt.bias > d_bias will be true, but inside it, pt.slope will be smaller than d_slope since there had been changes made to changes_weight.

This will cause revert, once this is reverted, the GaugeController will not work anymore.

Used Tools

Manual Review

Recommended Mitigation Steps

There can be more than one ways to resolve this issue as follows:

1. Update gauge weight to zero when add_gauge is called. (as in remove_gauge)

  function add_gauge(address _gauge) external onlyGovernance { // @audit-ok
      require(!isValidGauge[_gauge], "Gauge already exists");
      _change_gauge_weight(_gauge, 0);
      isValidGauge[_gauge] = true;
      emit NewGauge(_gauge);
  }

2. In vote_for_gauge_weights, set time_weight to next_time

  points_weight[_gauge_addr][next_time].bias = Math.max(old_weight_bias + new_bias, old_bias) - old_bias;
  points_sum[next_time].bias = Math.max(old_sum_bias + new_bias, old_bias) - old_bias;
  time_weight[_gauge_addr] = next_time; // <-- add this line

3. Handle slope error just in case

if (pt.bias > d_bias) {
    pt.bias -= d_bias;
    uint256 d_slope = changes_weight[_gauge_addr][t];

    // update like this
    if (pt.slope > d_slope) {
      pt.slope -= d_slope;
    } else {
      pt.slope = 0;
    }
} else {
    pt.bias = 0;
    pt.slope = 0;
}

Appling one of these would resolve the issue, but appling all of them would make it perfect!

Assessed type

DoS


The text was updated successfully, but these errors were encountered:

All reactions