You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Github username:@deadrosesxyz Twitter username:@deadrosesxyz Submission hash (on-chain): 0x33ffd4191b604c94bac6b7574d66a833c80587ca8ef5e120a64cccf974d952e2 Severity: high
Description: Description
Wrong logic in _updateForAfterDistribution can lead to massive overdistribution of rewards
Attack Scenario
Let's look at how _updateForAfterDistribution works.
function _updateForAfterDistribution(address_gauge) private {
address _pool = poolForGauge[_gauge];
uint256 _time =_epochTimestamp() -604800;
uint256 _supplied = weightsPerEpoch[_time][_pool];
if (_supplied >0) {
uint256 _supplyIndex = supplyIndex[_gauge];
uint256 _index = index; // get global index0 for accumulated distro
supplyIndex[_gauge] = _index; // update _gauge current position to global positionuint256 _delta = _index - _supplyIndex; // see if there is any difference that need to be accruedif (_delta >0) {
uint256 _share = (_supplied * _delta) /1e18; // add accrued difference for each supplied tokenif (isAlive[_gauge]) {
claimable[_gauge] += _share;
}
}
} else {
supplyIndex[_gauge] = index; // new users are set to the default global state
}
}
The way it works is the following:
It gets the gauge's balance in the last epoch
It gets the index delta
It multiplies the gauge's balance in the last epoch by the delta.
However, this becomes problematic if the gauge has not been updated consistently and has not been updated for a whole epoch for example.
Let's look at a simple example. (assume 1e18 of tokens is distributed per epoch for simplicity).
First epoch, index is 0. There are 2 gauges. One of the gauges ends the epoch with weight 1e18 and the other one with 0 (total weight is 1e18)
New epoch rolls. 1e18 tokens have been distributed, index is now 1e18. The gauge which had weight is updated and now has claimable = 1e18. The other gauge is not updated (important).
Now the 2nd gauge receives 1e18 weight. Total weight is now 2e18
The next epoch rolls and 1e18 is distributed. Index increases by (1e18 * 1e18) / 2e18 = 0.5e18. Index is now 1.5e18
Now after the first gauge's updated, it will be allocated the 0.5e18 tokens as supposed to.
However, when updating the 2nd gauge, since it hasn't been updated since the beginning, the delta will be 1.5e18. The gauge will be allocated 1e18 * 1.5e18 / 1e18 = 1.5e18 tokens for the 2nd round.
The 2nd gauge unfairly received more tokens than it should. Note that this is highly scalable.
This can also work in the opposite direction if a gauge has previously had bigger parts of the pot and is updated after having little weight in an epoch.
This would become even more problematic after reviving a gauge which has been inactive for long period of time (e.g. reviving after 1 year of being killed) as the gauge will get rewards for all the time that has passed.
Attachments
Proof of Concept (PoC) File
Revised Code File (Optional)
The text was updated successfully, but these errors were encountered:
Although this situation is unlikely since any user can do this, and the owners will also ensure the correctness of the work. What reduces the seriousness of it to a medium
since in case of absence of votes, it will be executed:
} else {
supplyIndex[_gauge] = index; // new users are set to the default global state
}
and update the index to the correct value
Since this case is possible only if an update to this gauge was not explicitly triggered, although this means that the protocol administration made a mistake, it reduces the severity to Medium, OOS
Github username: @deadrosesxyz
Twitter username: @deadrosesxyz
Submission hash (on-chain): 0x33ffd4191b604c94bac6b7574d66a833c80587ca8ef5e120a64cccf974d952e2
Severity: high
Description:
Description
Wrong logic in
_updateForAfterDistribution
can lead to massive overdistribution of rewardsAttack Scenario
Let's look at how
_updateForAfterDistribution
works.The way it works is the following:
However, this becomes problematic if the gauge has not been updated consistently and has not been updated for a whole epoch for example.
Let's look at a simple example. (assume 1e18 of tokens is distributed per epoch for simplicity).
claimable = 1e18
. The other gauge is not updated (important).(1e18 * 1e18) / 2e18 = 0.5e18
. Index is now 1.5e181e18 * 1.5e18 / 1e18 = 1.5e18
tokens for the 2nd round.The 2nd gauge unfairly received more tokens than it should. Note that this is highly scalable.
This can also work in the opposite direction if a gauge has previously had bigger parts of the pot and is updated after having little weight in an epoch.
This would become even more problematic after reviving a gauge which has been inactive for long period of time (e.g. reviving after 1 year of being killed) as the gauge will get rewards for all the time that has passed.
Attachments
The text was updated successfully, but these errors were encountered: