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: 36/126
Findings: 2
Award: $107.62
🌟 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
increaseUnlockTime() set oldLocked.end error, set to new end time. Causes _checkpoint() calculation slopeChanges and userOldPoint may be incorrect
function increaseUnlockTime(uint256 _unlockTime) external override nonReentrant checkBlocklist { ... if (locked_.delegatee == msg.sender) { // Undelegated lock require(oldUnlockTime > block.timestamp, "Lock expired"); LockedBalance memory oldLocked = _copyLock(locked_); oldLocked.end = unlock_time; //**** must oldLocked.end = oldUnlockTime ***/ _checkpoint(msg.sender, oldLocked, locked_); }
function _checkpoint( address _addr, LockedBalance memory _oldLocked, LockedBalance memory _newLocked ) internal { ... //***** Use the wrong _oldLocked.end ****// if (_oldLocked.end > block.timestamp && _oldLocked.delegated > 0) { userOldPoint.slope = _oldLocked.delegated / int128(int256(MAXTIME)); userOldPoint.bias = userOldPoint.slope * int128(int256(_oldLocked.end - block.timestamp)); } .... //***** Use the wrong _oldLocked.end ****// oldSlopeDelta = slopeChanges[_oldLocked.end];
function increaseUnlockTime(uint256 _unlockTime) external override nonReentrant checkBlocklist { ... if (locked_.delegatee == msg.sender) { // Undelegated lock require(oldUnlockTime > block.timestamp, "Lock expired"); LockedBalance memory oldLocked = _copyLock(locked_); ---- oldLocked.end = unlock_time; ++++ oldLocked.end = oldUnlockTime _checkpoint(msg.sender, oldLocked, locked_); }
#0 - lacoop6tu
2022-08-17T08:48:45Z
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.9022 USDC - $29.90
1._checkpoint() when uEpoch=0, userPointHistory is set incorrectly https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L258
function _checkpoint( address _addr, LockedBalance memory _oldLocked, LockedBalance memory _newLocked ) internal { ... uint256 uEpoch = userPointEpoch[_addr]; if (uEpoch == 0) { ---- userPointHistory[_addr][uEpoch + 1] = userOldPoint; //**** [uEpoch + 1] will set to userNewPoint In the following code ++++ userPointHistory[_addr][uEpoch] = userOldPoint; } userPointEpoch[_addr] = uEpoch + 1; userNewPoint.ts = block.timestamp; userNewPoint.blk = block.number; userPointHistory[_addr][uEpoch + 1] = userNewPoint; //****** [uEpoch + 1] will set to userNewPoint
L-01: VotingEscrow.sol transferOwnership() Not determine whether the owner is address(0), may lose control https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L141
function transferOwnership(address _addr) external { require(msg.sender == owner, "Only owner"); +++ require(_addr != address(0) && _addr != owner, "invalid addr"); owner = _addr; emit TransferOwnership(_addr); }
L-02: VotingEscrow.sol updatePenaltyRecipient() Not determine whether the owner is address(0) https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L155
function updatePenaltyRecipient(address _addr) external { require(msg.sender == owner, "Only owner"); +++ require(_addr != address(0) && _addr != penaltyRecipient, "invalid addr"); penaltyRecipient = _addr; emit UpdatePenaltyRecipient(_addr); }
L-03: VotingEscrow.sol createLock() locked_.amount can be assigned directly to save GAS, this old amount must be 0 https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L418
function createLock(uint256 _value, uint256 _unlockTime) external override nonReentrant checkBlocklist { ... --- locked_.amount += int128(int256(_value)); +++ locked_.amount = int128(int256(_value));
L-04: Blocklist.sol block() recommended that the method name be changed, “block” is reserved variable https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L23
+++ function setBlock(address addr) external { --- function block(address addr) external { require(msg.sender == manager, "Only manager"); require(_isContract(addr), "Only contracts"); _blocklist[addr] = true; IVotingEscrow(ve).forceUndelegate(addr); }