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: 37/126
Findings: 2
Award: $107.61
π 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
77.7206 USDC - $77.72
In increaseUnlockTime()
function, in case itβs undelegated lock, it calls _checkpoint
for msg.sender
with oldLocked
and locked_
. But actually, these 2 locks oldLocked
and locked_
are the same. It makes the logic in _checkpoint()
function works incorrectly.
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; // @audit should be oldUnlockTime _checkpoint(msg.sender, oldLocked, locked_); }
Value end
of locked_
is updated to unlock_time
in line 507 and line 512-513 is copy value of locked_
to oldLocked
and also update value end
to unlock_time
. So basically, values of locked_
and oldLocked
are identical.
Manual Review
Update logic, value end
of oldLocked
should be oldUnlockTime
oldLocked.end = oldUnlockTime;
#0 - lacoop6tu
2022-08-16T13:28:01Z
Duplicate of #217
π Selected for report: oyc_109
Also found by: 0x1f8b, 0x52, 0xDjango, 0xLovesleep, 0xNazgul, 0xNineDec, 0xbepresent, 0xmatt, 0xsolstars, Aymen0909, Bahurum, Bnke0x0, CertoraInc, Chom, CodingNameKiki, DecorativePineapple, Deivitto, Dravee, ElKu, Funen, GalloDaSballo, IllIllI, JC, JohnSmith, Junnon, KIntern_NA, Lambda, LeoS, MiloTruck, Noah3o6, PaludoX0, RedOneN, Respx, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, Ruhum, Sm4rty, TomJ, Vexjon, Waze, Yiko, __141345__, a12jmx, ajtra, ak1, apostle0x01, asutorufos, auditor0517, bin2chen, bobirichman, brgltd, bulej93, byndooa, c3phas, cRat1st0s, cryptphi, csanuragjain, d3e4, defsec, delfin454000, djxploit, durianSausage, ellahi, erictee, exd0tpy, fatherOfBlocks, gogo, jonatascm, ladboy233, medikko, mics, natzuu, neumo, p_crypt0, paribus, pfapostol, rbserver, reassor, ret2basic, robee, rokinot, rvierdiiev, sach1r0, saneryee, seyni, sikorico, simon135, sseefried, wagmi, wastewa
29.8918 USDC - $29.89
https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L257-L264 https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L372
In function _checkpoint()
, new values of userPointHistory
and pointHistory
are override old values instead of appending to the end of the list, i.e creating new element.
The result is if we try to get balanceOf
or totalSupply
at current block number, it just return wrong value because values of globalEpoch
is overrided.
if (uEpoch == 0) { userPointHistory[_addr][uEpoch + 1] = userOldPoint; } userPointEpoch[_addr] = uEpoch + 1; userNewPoint.ts = block.timestamp; userNewPoint.blk = block.number; userPointHistory[_addr][uEpoch + 1] = userNewPoint;
When uEpoch == 0
, values of userPointHistory
with index = uEpoch + 1
is updated to userOldPoint
but in line 264, values of userPointHistory
with index = uEpoch + 1
is overrided to userNewPoint
which basically makes line 257-259 has no meaning.
Similarly issue with value of pointHistory[epoch]
in line 372
Manual Review
Update logic of _checkpoint()
, for example, use ++
operator to make sure epoch
is increased each time it appends new element.
#0 - lacoop6tu
2022-08-16T13:35:24Z
Lines 257-259 are actually meaningless and are not causing any error/side effects, they can be removed. in mStable impl, they used a dynamic array so they had to push an empty point with the first index, while we are using a fixed one which is already there. But i don't see the similarity for "Similarly issue with value of pointHistory[epoch] in line 372"
#1 - elnilz
2022-08-17T12:35:43Z
so essentially the issue is just that lines 257-259 are unnecessary but don't affect in any way the proper functioning of the system. that's why I think its a QA severity
#2 - gititGoro
2022-09-04T22:01:48Z
Duplicate of #316