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: 49/126
Findings: 2
Award: $50.11
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
34.9431 USDC - $34.94
Severity: Low
function transferOwnership(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L139
function updateBlocklist(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L146
function updatePenaltyRecipient(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L153
function forceUndelegate(address _addr) external override {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L170
function delegate(address _addr) external override nonReentrant checkBlocklist {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L555
function block(address addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L23
Consider adding zero-address checks in the mentioned codebase.
Severity: Low
It is good to add a require() statement that checks the return value of token transfers or to use something like OpenZeppelin’s safeTransfer/safeTransferFrom unless one is sure the given token reverts in case of a failure. Failure to do so will cause silent failures of transfers and affect token accounting in contract.
Reference: This similar medium-severity (https://consensys.net/diligence/audits/2021/01/fei-protocol/#unchecked-return-value-for-iweth-transfer-call) finding from Consensys Diligence Audit of Fei Protocol.
token.transferFrom(msg.sender, address(this), _value),
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L421
token.transferFrom(msg.sender, address(this), _value),
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L479
require(token.transfer(msg.sender, value), "Transfer failed");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L540
require(token.transfer(msg.sender, remainingAmount), "Transfer failed");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L649
require(token.transfer(penaltyRecipient, amount), "Transfer failed");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L676
Consider using safeTransfer/safeTransferFrom or require() consistently.
Severity: Low
The owner is the authorized user in the solidity contracts. Usually, an owner can be updated with transferOwnership function. However, the process is only completed with single transaction. If the address is updated incorrectly, an owner functionality will be lost forever.
function transferOwnership(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L139
Lack of two-step procedure for critical operations leaves them error-prone. Consider adding two step procedure on the critical functions.
Severity: Low
Users can potentially call functions that create potentially malicicous locks
function createLock(uint256 _value, uint256 _unlockTime)
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L403
Consider adding a mapping of who can call these create functions to avoid malicious use
Severity: Low
According to package.json, the OZ packages are currently set to ^4.4.2
Package.json#L42
Update the versions of @openzeppelin/contracts to be the latest in package.json. I also recommend double checking the versions of other dependencies as a precaution, as they may include important bug fixes.
Severity: Non-Critical
Found usage of floating pragmas ^0.8.3 of Solidity https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L2
Found usage of floating pragmas ^0.8.3 of Solidity https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L2
Severity: Non-Critical
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L293
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L715
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L739
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L832
Severity: Non-Critical
Each event should use three indexed fields if there are three or more fields. In addition, each event should have at least one indexed fields to allow easier filtering of logs.
event Deposit( address indexed provider, uint256 value, uint256 locktime, LockAction indexed action, uint256 ts );
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L25
event Withdraw( address indexed provider, uint256 value, LockAction indexed action, uint256 ts );
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L32
event CollectPenalty(uint256 amount, address recipient);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L41
OpenZeppelin recommends that the initializer modifier be applied to constructors. Per OZs Post implementation contract should be initialized to avoid potential griefs or exploits. https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680/5
Severity: Non-Critical
contract VotingEscrow is IVotingEscrow, ReentrancyGuard
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L23
contract Blocklist
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L9
Severity: Non-Critical
Use a solidity version of at least 0.8.4 to get bytes.concat() instead of abi.encodePacked(<bytes>,<bytes>) Use a solidity version of at least 0.8.12 to get string.concat() instead of abi.encodePacked(<str>,<str>) Use a solidity version of at least 0.8.13 to get the ability to use using for with a list of free functions
Found old version 0.8.3 of Solidity https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L2
Found old version 0.8.3 of Solidity https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L2
Consider updating to a more recent solidity version.
Severity: Non-Critical
Use (e.g. 1e6) rather than decimal literals (e.g. 100000), for better code readability.
Point[1000000000000000000] public pointHistory; // 1e9 * userPointHistory-length, so sufficient for 1e9 users
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L57
mapping(address => Point[1000000000]) public userPointHistory;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L58
Severity: Non-Critical
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.
ts: block.timestamp,
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L111
if (_oldLocked.end > block.timestamp && _oldLocked.delegated > 0) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L236
int128(int256(_oldLocked.end - block.timestamp));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L242
if (_newLocked.end > block.timestamp && _newLocked.delegated > 0) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L244
int128(int256(_newLocked.end - block.timestamp));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L250
userNewPoint.ts = block.timestamp;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L262
ts: block.timestamp,
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L285
if (block.timestamp > lastPoint.ts) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L299
(block.timestamp - lastPoint.ts);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L302
if (iterativeTime > block.timestamp) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L314
iterativeTime = block.timestamp;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L315
if (iterativeTime == block.timestamp) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L341
if (_oldLocked.end > block.timestamp) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L378
if (_newLocked.end > block.timestamp) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L386
require(unlock_time > block.timestamp, "Only future lock end");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L415
require(unlock_time <= block.timestamp + MAXTIME, "Exceeds maxtime");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L416
block.timestamp
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L434
require(locked_.end > block.timestamp, "Lock expired");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L450
require(locked_.end > block.timestamp, "Delegatee lock expired");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L470
block.timestamp
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L479
emit Deposit(msg.sender, _value, unlockTime, action, block.timestamp);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L489
require(oldUnlockTime > block.timestamp, "Lock expired");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L511
require(locked_.end <= block.timestamp, "Lock not expired");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L530
emit Withdraw(msg.sender, value, LockAction.WITHDRAW, block.timestamp);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L547
require(toLocked.end > block.timestamp, "Delegatee lock expired");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L588
emit Withdraw(msg.sender, value, LockAction.QUIT, block.timestamp);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L658
return ((end - block.timestamp) * maxPenalty) / MAXTIME;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L668
(lastPoint.slope * int128(int256(block.timestamp - lastPoint.ts)));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L762
dTime = block.timestamp - point0.ts;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L801
return _supplyAt(lastPoint, block.timestamp);
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L867
((_blockNumber - point.blk) * (block.timestamp - point.ts)) /
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L899
Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.
Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.
Severity: Non-Critical
A user can only have a billion checkpoints which, if the user is a DAO, may cause issues down the line, especially if the last checkpoint involved delegating and can thereafter not be undone
mapping(address => Point[1000000000]) public userPointHistory;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L58
Severity: Non-Critical
function _isContract(address addr) internal view returns (bool) { https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol
Severity: Non-Critical
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol
#0 - lacoop6tu
2022-08-26T15:33:45Z
Good one
🌟 Selected for report: IllIllI
Also found by: 0x040, 0x1f8b, 0xDjango, 0xHarry, 0xLovesleep, 0xNazgul, 0xNineDec, 0xSmartContract, 0xackermann, 0xbepresent, 2997ms, Amithuddar, Aymen0909, Bnke0x0, CRYP70, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, Fitraldys, Funen, GalloDaSballo, JC, JohnSmith, Junnon, LeoS, Metatron, MiloTruck, Noah3o6, NoamYakov, PaludoX0, RedOneN, Respx, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, SooYa, SpaceCake, TomJ, Tomio, Waze, Yiko, __141345__, a12jmx, ajtra, ak1, apostle0x01, asutorufos, bobirichman, brgltd, bulej93, c3phas, cRat1st0s, carlitox477, chrisdior4, csanuragjain, d3e4, defsec, delfin454000, djxploit, durianSausage, ellahi, erictee, fatherOfBlocks, gerdusx, gogo, ignacio, jag, ladboy233, m_Rassska, medikko, mics, natzuu, newfork01, oyc_109, paribus, pfapostol, rbserver, reassor, ret2basic, robee, rokinot, rvierdiiev, sach1r0, saian, sashik_eth, sikorico, simon135
15.1721 USDC - $15.17
Severity: Gas Optimizations
Saves 6 gas per loop
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L293
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L715
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L739
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L832
For example, use ++i instead of i++
Severity: Gas Optimizations
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L293
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L715
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L739
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L832
Severity: Gas Optimizations
This change saves 6 gas per instance
require(_value > 0, "Only non zero amount");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L410
require(_value > 0, "Only non zero amount");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L447
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L448
require(locked_.amount > 0, "Delegatee has no lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L464
require(_value > 0, "Only non zero amount");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L447
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L448
require(locked_.amount > 0, "Delegatee has no lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L464
require(_value > 0, "Only non zero amount");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L447
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L448
require(locked_.amount > 0, "Delegatee has no lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L464
uint256 unlock_time = _floorToWeek(_unlockTime); require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L500
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L528
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L563
require(toLocked.amount > 0, "Delegatee has no lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L581
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L563
require(toLocked.amount > 0, "Delegatee has no lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L581
require(locked_.amount > 0, "No lock");
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L634
Severity: Gas Optimizations
Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot.
mapping(address => Point[1000000000]) public userPointHistory; mapping(address => uint256) public userPointEpoch; mapping(address => LockedBalance) public locked;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L58
Severity: Gas Optimizations
<x> * 2 is equivalent to <x> << 1 and <x> / 2 is the same as <x> >> 1. The MUL and DIV opcodes cost 5 gas, whereas SHL and SHR only cost 3 gas
uint256 mid = (min + max + 1) / 2;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L717
uint256 mid = (min + max + 1) / 2;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L743
Severity: Gas Optimizations
locked_.amount += int128(int256(_value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L414
locked_.delegated += int128(int256(_value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L416
newLocked.amount += int128(int256(_value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L457
newLocked.delegated += int128(int256(_value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L458
locked_.amount += int128(int256(_value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L461
newLocked.delegated -= int128(int256(value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L535
newLocked.delegated += value;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L603
newLocked.delegated -= value;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L612
newLocked.delegated -= int128(int256(value));
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L640
uint256 penaltyAmount = (value * penaltyRate) / 10**18;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L647
Severity: Gas Optimizations
If needed, the value can be read from the verified contract source code. Savings are due to the compiler not having to create non-payable getter functions for deployment calldata, and not adding another entry to the method ID table
uint256 public constant WEEK = 7 days; uint256 public constant MAXTIME = 365 days; uint256 public constant MULTIPLIER = 10**18;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L46-L48
Set variable to private.
Severity: Gas Optimizations
The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.
function balanceOf(address _owner) public view override returns (uint256) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L754
function totalSupply() public view override returns (uint256) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L864
function isBlocked(address addr) public view returns (bool) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L33
Severity: Gas Optimizations
To help the optimizer, declare a storage type variable and use it instead of repeatedly fetching the reference in a map or an array. The effect can be quite significant. As an example, instead of repeatedly calling someMap[someIndex], save its reference like this: SomeStruct storage someStruct = someMap[someIndex] and use it.
fromLocked = locked[delegatee];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L179
lastPoint = pointHistory[epoch];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L280
dSlope = slopeChanges[iterativeTime];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L299
locked_ = locked[delegatee];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L463
fromLocked = locked[delegatee];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L574
if (pointHistory[mid].blk <= _block) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L718
Point memory point0 = pointHistory[epoch];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L786
dSlope = slopeChanges[iterativeTime];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L839
Point memory point = pointHistory[targetEpoch];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L882
return _blocklist[addr];
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L34
Severity: Gas Optimizations
The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas PER LOOP
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L293
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L715
for (uint256 i = 0; i < 128; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L739
for (uint256 i = 0; i < 255; i++) {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L832
Severity: Gas Optimizations
The following functions are missing zero address check. Save 6 gas per instance if using assembly to check for address(0)
e.g. assembly { if iszero(_addr) { mstore(0x00, "AddressZero") revert(0x00, 0x20) } }
function transferOwnership(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L139
function updateBlocklist(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L146
function updatePenaltyRecipient(address _addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L153
function forceUndelegate(address _addr) external override {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L170
function delegate(address _addr) external override nonReentrant checkBlocklist {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L555
function block(address addr) external {
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L23
Severity: Gas Optimizations
In Solidity, a constant expression in a variable will compute the expression everytime the variable is called. It's not the result of the expression that is stored, but the expression itself.
As Solidity supports the scientific notation, constants of form 10**X can be rewritten as 1eX to save the gas cost from the calculation with the exponentiation operator **.
uint256 public constant MULTIPLIER = 10**18;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L48
uint256 public maxPenalty = 10**18; // penalty for quitters with MAXTIME remaining lock
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L51
uint256 penaltyAmount = (value * penaltyRate) / 10**18; // quitlock_penalty is in 18 decimals precision
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/VotingEscrow.sol#L653
Replace 10**X with 1eX
Severity: Gas Optimizations
Booleans are more expensive than uint256 or any type that takes up a full word because each write operation emits an extra SLOAD to first read the slot's contents, replace the bits taken up by the boolean, and then write back. This is the compiler's defense against contract upgrades and pointer aliasing, and it cannot be disabled.
mapping(address => bool) private _blocklist;
https://github.com/code-423n4/2022-08-fiatdao/tree/main/contracts/features/Blocklist.sol#L10