Platform: Code4rena
Start Date: 12/08/2022
Pot Size: $35,000 USDC
Total HM: 10
Participants: 126
Period: 3 days
Judge: Justin Goro
Total Solo HM: 3
Id: 154
League: ETH
Rank: 39/126
Findings: 1
Award: $77.72
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Aymen0909
Also found by: 0xSky, 0xf15ers, CertoraInc, JohnSmith, auditor0517, bin2chen, csanuragjain, scaraven, tabish, wagmi, yixxas
https://github.com/code-423n4/2022-08-fiatdao/blob/main/contracts/VotingEscrow.sol#L507-L515 https://github.com/code-423n4/2022-08-fiatdao/blob/main/contracts/VotingEscrow.sol#L355-L362
Global slope and global bias ( i.e voting power ) is not calculated correctly every time someone makes a call to increaseUnlockTime()
when _checkpoint()
VotingEscrow.sol#L514 is called and thus can affect reliability of the protocol.
oldLocked
is a copy of locked_
on L512 and oldLocked.end = unlock_time
on L513, but no change is done as L507 has already set the original locked_.end = unlock_time
. This means that the parameters that are passed into _checkpoint()
L514, oldLocked
and locked_
has the exact same values.
function increaseUnlockTime(uint256 _unlockTime){ ... locked_.end = unlock_time; locked[msg.sender] = locked_; if (locked_.delegatee == msg.sender) { // Undelegated lock require(oldUnlockTime > block.timestamp, "Lock expired"); LockedBalance memory oldLocked = _copyLock(locked_); oldLocked.end = unlock_time; _checkpoint(msg.sender, oldLocked, locked_); } ... }
Every time a user calls increaseUnlockTime()
to extend their lock, lastPoint.slope
and lastPoint.bias
does not change in _checkpoint()
since oldLocked == newLocked
.
function _checkpoint(address _addr,LockedBalance memory _oldLocked,LockedBalance memory _newLocked){ ... lastPoint.slope = lastPoint.slope + userNewPoint.slope - userOldPoint.slope; lastPoint.bias = lastPoint.bias + userNewPoint.bias - userOldPoint.bias; ... }
Make copy of _locked
before making the changes to locked_.end
function increaseUnlockTime(uint256 _unlockTime){ ... LockedBalance memory oldLocked = _copyLock(locked_); locked_.end = unlock_time; locked[msg.sender] = locked_; if (locked_.delegatee == msg.sender) { // Undelegated lock require(oldUnlockTime > block.timestamp, "Lock expired"); _checkpoint(msg.sender, oldLocked, locked_); } ... }
#0 - bahurum
2022-08-16T21:50:07Z
Duplicate of #217
#1 - lacoop6tu
2022-08-17T09:45:15Z
Duplicate of #217