FIAT DAO veFDT contest - IllIllI's results

Unlock liquidity for your DeFi fixed income assets.

General Information

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

FIAT DAO

Findings Distribution

Researcher Performance

Rank: 24/126

Findings: 2

Award: $211.14

๐ŸŒŸ Selected for report: 1

๐Ÿš€ Solo Findings: 0

Summary

Low Risk Issues

IssueInstances
[Lโ€‘01]Blocklist's ve address may not match the VotingEscrow with which it's being used1
[Lโ€‘02]Only a billion checkpoints available1
[Lโ€‘03]Missing checks for address(0x0) when assigning values to address state variables7

Total: 9 instances over 3 issues

Non-critical Issues

IssueInstances
[Nโ€‘01]Invalid/extraneous/optional function definitions in interface2
[Nโ€‘02]public functions not called by the contract should be declared external instead1
[Nโ€‘03]Non-assembly method available1
[Nโ€‘04]constants should be defined rather than using magic numbers6
[Nโ€‘05]Large multiples of ten should use scientific notation (e.g. 1e6) rather than decimal literals (e.g. 1000000), for readability2
[Nโ€‘06]Use scientific notation (e.g. 1e18) rather than exponentiation (e.g. 10**18)3
[Nโ€‘07]Non-library/interface files should use fixed compiler versions, not floating ones2
[Nโ€‘08]Typos4
[Nโ€‘09]File is missing NatSpec1
[Nโ€‘10]NatSpec is incomplete4
[Nโ€‘11]Event is missing indexed fields8
[Nโ€‘12]Not using the named return variables anywhere in the function is confusing3
[Nโ€‘13]Duplicated require()/revert() checks should be refactored to a modifier or function8

Total: 45 instances over 13 issues

Low Risk Issues

[Lโ€‘01] Blocklist's ve address may not match the VotingEscrow with which it's being used

The Blocklist is constructed with an address for the VotingEscrow with which it's meant to be used. The VotingEscrow contract itself only allows its stored Blocklist address to call forceUndelegate(), and if the wrong VotingEscrow is passed to the Blocklist, or the wrong Blocklist is passed to updateBlocklist(), block() will revert when called, and another timelock duration will have to be waited for in order to change to the correct Blocklist

There is 1 instance of this issue:

File: /contracts/features/Blocklist.sol

23       function block(address addr) external {
24           require(msg.sender == manager, "Only manager");
25           require(_isContract(addr), "Only contracts");
26           _blocklist[addr] = true;
27           IVotingEscrow(ve).forceUndelegate(addr);
28:      }

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L23-L28

[Lโ€‘02] Only a billion checkpoints available

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

There is 1 instance of this issue:

File: /contracts/VotingEscrow.sol

58:      mapping(address => Point[1000000000]) public userPointHistory;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L58

[Lโ€‘03] Missing checks for address(0x0) when assigning values to address state variables

There are 7 instances of this issue:

File: contracts/features/Blocklist.sol

15:           manager = _manager;

16:           ve = _ve;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L15

File: contracts/VotingEscrow.sol

120:          owner = _owner;

121:          penaltyRecipient = _penaltyRecipient;

141:          owner = _addr;

148:          blocklist = _addr;

155:          penaltyRecipient = _addr;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L120

Non-critical Issues

[Nโ€‘01] Invalid/extraneous/optional function definitions in interface

There are 2 instances of this issue:

File: contracts/interfaces/IERC20.sol

/// @audit symbol() isn't defined with those arguments in the standard IERC20 definition
5:        function symbol() external view returns (string memory);

/// @audit decimals() isn't defined with those arguments in the standard IERC20 definition
10:       function decimals() external view returns (uint8);

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IERC20.sol#L5

[Nโ€‘02] public functions not called by the contract should be declared external instead

Contracts are allowed to override their parents' functions and change the visibility from external to public.

There is 1 instance of this issue:

File: contracts/features/Blocklist.sol

33:       function isBlocked(address addr) public view returns (bool) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L33

[Nโ€‘03] Non-assembly method available

assembly{ id := chainid() } => uint256 id = block.chainid, assembly { size := extcodesize() } => uint256 size = address().code.length There are some automated tools that will flag a project as having higher complexity if there is inline-assembly, so it's best to avoid using it where it's not necessary

There is 1 instance of this issue:

File: contracts/features/Blocklist.sol

40:               size := extcodesize(addr)

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L40

[Nโ€‘04] constants should be defined rather than using magic numbers

Even assembly can benefit from using readable constants instead of hex/numeric literals

There are 6 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit 18
116:          require(decimals <= 18, "Exceeds max decimals");

/// @audit 255
309:          for (uint256 i = 0; i < 255; i++) {

/// @audit 18
653:          uint256 penaltyAmount = (value * penaltyRate) / 10**18; // quitlock_penalty is in 18 decimals precision

/// @audit 128
717:          for (uint256 i = 0; i < 128; i++) {

/// @audit 128
739:          for (uint256 i = 0; i < 128; i++) {

/// @audit 255
834:          for (uint256 i = 0; i < 255; i++) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L116

[Nโ€‘05] Large multiples of ten should use scientific notation (e.g. 1e6) rather than decimal literals (e.g. 1000000), for readability

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

57:       Point[1000000000000000000] public pointHistory; // 1e9 * userPointHistory-length, so sufficient for 1e9 users

58:       mapping(address => Point[1000000000]) public userPointHistory;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L57

[Nโ€‘06] Use scientific notation (e.g. 1e18) rather than exponentiation (e.g. 10**18)

While the compiler knows to optimize away the exponentiation, it's still better coding practice to use idioms that do not require compiler optimization, if they exist

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

48:       uint256 public constant MULTIPLIER = 10**18;

51:       uint256 public maxPenalty = 10**18; // penalty for quitters with MAXTIME remaining lock

653:          uint256 penaltyAmount = (value * penaltyRate) / 10**18; // quitlock_penalty is in 18 decimals precision

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L48

[Nโ€‘07] Non-library/interface files should use fixed compiler versions, not floating ones

There are 2 instances of this issue:

File: contracts/features/Blocklist.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L2

File: contracts/VotingEscrow.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L2

[Nโ€‘08] Typos

There are 4 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit binarysearch
/// @audit preceeding
705:      // @dev Uses binarysearch to find the most recent point history preceeding block

/// @audit binarysearch
/// @audit preceeding
729:      // @dev Uses binarysearch to find the most recent user point history preceeding block

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L705

[Nโ€‘09] File is missing NatSpec

There is 1 instance of this issue:

File: contracts/interfaces/IERC20.sol

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IERC20.sol

[Nโ€‘10] NatSpec is incomplete

There are 4 instances of this issue:

File: contracts/features/Blocklist.sol

/// @audit Missing: '@return'
31        /// @dev This method will be called by the VotingEscrow contract
32        /// @param addr The contract address to check
33:       function isBlocked(address addr) public view returns (bool) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L31-L33

File: contracts/VotingEscrow.sol

/// @audit Missing: '@return'
699       // @dev Floors a timestamp to the nearest weekly increment
700       // @param _t Timestamp to floor
701:      function _floorToWeek(uint256 _t) internal pure returns (uint256) {

/// @audit Missing: '@return'
706       // @param _block Find the most recent point history before this block
707       // @param _maxEpoch Do not search pointHistories past this index
708       function _findBlockEpoch(uint256 _block, uint256 _maxEpoch)
709           internal
710           view
711:          returns (uint256)

/// @audit Missing: '@return'
730       // @param _addr User for which to search
731       // @param _block Find the most recent point history before this block
732       function _findUserBlockEpoch(address _addr, uint256 _block)
733           internal
734           view
735:          returns (uint256)

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L699-L701

[Nโ€‘11] Event is missing indexed fields

Index event fields make the field more quickly accessible to off-chain tools that parse events. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Each event should use three indexed fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three fields, all of the fields should be indexed.

There are 8 instances of this issue:

File: contracts/interfaces/IERC20.sol

29:       event Transfer(address indexed from, address indexed to, uint256 value);

30        event Approval(
31            address indexed owner,
32            address indexed spender,
33            uint256 value
34:       );

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IERC20.sol#L29

File: contracts/VotingEscrow.sol

25        event Deposit(
26            address indexed provider,
27            uint256 value,
28            uint256 locktime,
29            LockAction indexed action,
30            uint256 ts
31:       );

32        event Withdraw(
33            address indexed provider,
34            uint256 value,
35            LockAction indexed action,
36            uint256 ts
37:       );

38:       event TransferOwnership(address owner);

39:       event UpdateBlocklist(address blocklist);

40:       event UpdatePenaltyRecipient(address recipient);

41:       event CollectPenalty(uint256 amount, address recipient);

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L25-L31

[Nโ€‘12] Not using the named return variables anywhere in the function is confusing

Consider changing the variable to be an unnamed one

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit bias
/// @audit slope
/// @audit ts
201       function getLastUserPoint(address _addr)
202           external
203           view
204           returns (
205               int128 bias,
206               int128 slope,
207:              uint256 ts

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L201-L207

[Nโ€‘13] Duplicated require()/revert() checks should be refactored to a modifier or function

The compiler will inline the function, which will avoid JUMP instructions usually associated with functions

There are 8 instances of this issue:

File: contracts/VotingEscrow.sol

147:          require(msg.sender == owner, "Only owner");

448:          require(_value > 0, "Only non zero amount");

504:          require(unlock_time <= block.timestamp + MAXTIME, "Exceeds maxtime");

485           require(
486               token.transferFrom(msg.sender, address(this), _value),
487               "Transfer failed"
488:          );

502:          require(locked_.amount > 0, "No lock");

636:          require(locked_.end > block.timestamp, "Lock expired");

637:          require(locked_.delegatee == msg.sender, "Lock delegated");

877:          require(_blockNumber <= block.number, "Only past block number");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L147

#0 - lacoop6tu

2022-08-26T15:32:54Z

Good one

Summary

Gas Optimizations

IssueInstances
[Gโ€‘01]Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate1
[Gโ€‘02]State variables only set in the constructor should be declared immutable14
[Gโ€‘03]Structs can be packed into fewer storage slots1
[Gโ€‘04]Using calldata instead of memory for read-only arguments in external functions saves gas2
[Gโ€‘05]Using storage instead of memory for structs/arrays saves gas9
[Gโ€‘06]Avoid contract existence checks by using solidity version 0.8.10 or later3
[Gโ€‘07]State variables should be cached in stack variables rather than re-reading them from storage3
[Gโ€‘08]<x> += <y> costs more gas than <x> = <x> + <y> for state variables1
[Gโ€‘09]internal functions only called once can be inlined to save gas3
[Gโ€‘10]Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement2
[Gโ€‘11]++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops4
[Gโ€‘12]Optimize names to save gas4
[Gโ€‘13]Using bools for storage incurs overhead1
[Gโ€‘14]Use a more recent version of solidity5
[Gโ€‘15]Using > 0 costs more gas than != 0 when used on a uint in a require() statement2
[Gโ€‘16]++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)4
[Gโ€‘17]Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead3
[Gโ€‘18]Using private rather than public for constants, saves gas3
[Gโ€‘19]Division by two should use bit shifting2
[Gโ€‘20]Stack variable used as a cheaper cache for a state variable is only used once1
[Gโ€‘21]require() or revert() statements that check input arguments should be at the top of the function2
[Gโ€‘22]Superfluous event fields2
[Gโ€‘23]Use custom errors rather than revert()/require() strings to save gas42

Total: 114 instances over 23 issues

Gas Optimizations

[Gโ€‘01] Multiple address/ID mappings can be combined into a single mapping of an address/ID to a struct, where appropriate

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. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.

There is 1 instance of this issue:

File: contracts/VotingEscrow.sol

58        mapping(address => Point[1000000000]) public userPointHistory;
59:       mapping(address => uint256) public userPointEpoch;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L58-L59

[Gโ€‘02] State variables only set in the constructor should be declared immutable

Avoids a Gsset (20000 gas) in the constructor, and replaces the first access in each transaction (Gcoldsload - 2100 gas) and each access thereafter (Gwarmacces - 100 gas) with a PUSH32 (3 gas).

There are 14 instances of this issue:

File: contracts/features/Blocklist.sol

/// @audit manager (constructor)
15:           manager = _manager;

/// @audit manager (access)
24:           require(msg.sender == manager, "Only manager");

/// @audit ve (constructor)
16:           ve = _ve;

/// @audit ve (access)
27:           IVotingEscrow(ve).forceUndelegate(addr);

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L15

File: contracts/VotingEscrow.sol

/// @audit token (constructor)
107:          token = IERC20(_token);

/// @audit token (access)
426:              token.transferFrom(msg.sender, address(this), _value),

/// @audit token (access)
486:              token.transferFrom(msg.sender, address(this), _value),

/// @audit token (access)
546:          require(token.transfer(msg.sender, value), "Transfer failed");

/// @audit token (access)
657:          require(token.transfer(msg.sender, remainingAmount), "Transfer failed");

/// @audit token (access)
676:          require(token.transfer(penaltyRecipient, amount), "Transfer failed");

/// @audit name (constructor)
118:          name = _name;

/// @audit symbol (constructor)
119:          symbol = _symbol;

/// @audit decimals (constructor)
115:          decimals = IERC20(_token).decimals();

/// @audit decimals (access)
116:          require(decimals <= 18, "Exceeds max decimals");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L107

diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol
index f15781a..d2c7666 100644
--- a/contracts/VotingEscrow.sol
+++ b/contracts/VotingEscrow.sol
@@ -42,7 +42,7 @@ contract VotingEscrow is IVotingEscrow, ReentrancyGuard {
     event Unlock();
 
     // Shared global state
-    IERC20 public token;
+    IERC20 public immutable token;
     uint256 public constant WEEK = 7 days;
     uint256 public constant MAXTIME = 365 days;
     uint256 public constant MULTIPLIER = 10**18;
@@ -61,9 +61,9 @@ contract VotingEscrow is IVotingEscrow, ReentrancyGuard {
     mapping(address => LockedBalance) public locked;
 
     // Voting token
-    string public name;
-    string public symbol;
-    uint256 public decimals = 18;
+    string public constant name = "veFDT";
+    string public constant symbol = "veFDT";
+    uint256 public immutable decimals;
 
     // Structs
     struct Point {
@@ -112,11 +112,10 @@ contract VotingEscrow is IVotingEscrow, ReentrancyGuard {
             blk: block.number
         });
 
-        decimals = IERC20(_token).decimals();
-        require(decimals <= 18, "Exceeds max decimals");
+        uint256 _dec = IERC20(_token).decimals();
+        require(_dec <= 18, "Exceeds max decimals");
+        decimals = _dec;
 
-        name = _name;
-        symbol = _symbol;
         owner = _owner;
         penaltyRecipient = _penaltyRecipient;
     }
diff --git a/contracts/features/Blocklist.sol b/contracts/features/Blocklist.sol
index 27db9b0..ca3a226 100644
--- a/contracts/features/Blocklist.sol
+++ b/contracts/features/Blocklist.sol
@@ -8,8 +8,8 @@ import { IVotingEscrow } from "../interfaces/IVotingEscrow.sol";
 /// @dev This is a basic implementation using a mapping for address => bool
 contract Blocklist {
     mapping(address => bool) private _blocklist;
-    address public manager;
-    address public ve;
+    address public immutable manager;
+    address public immutable ve;
 
     constructor(address _manager, address _ve) {
         manager = _manager;
diff --git a/tmp/gas_before b/tmp/gas_after
index 3deb415..cf71599 100644
--- a/tmp/gas_before
+++ b/tmp/gas_after
@@ -167,7 +167,7 @@ No need to generate any newer typings.
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  Contract         ยท  Method              ยท  Min        ยท  Max        ยท  Avg          ยท  # calls      ยท  eur (avg)  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  Blocklist        ยท  block               ยท      45000  ยท     409628  ยท       198815  ยท            5  ยท          -  โ”‚
+|  Blocklist        ยท  block               ยท      40797  ยท     405425  ยท       194612  ยท            5  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockERC20        ยท  approve             ยท      46176  ยท      46200  ยท        46196  ยท           96  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
@@ -177,46 +177,46 @@ No need to generate any newer typings.
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockERC20        ยท  transfer            ยท      51588  ยท      51612  ยท        51606  ยท           83  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  createLock          ยท     334002  ยท     378450  ยท       355494  ยท            7  ยท          -  โ”‚
+|  MockSmartWallet  ยท  createLock          ยท     331896  ยท     376344  ยท       353388  ยท            7  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockSmartWallet  ยท  delegate            ยท          -  ยท          -  ยท       340388  ยท            2  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockSmartWallet  ยท  increaseUnlockTime  ยท          -  ยท          -  ยท       208859  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  quitLock            ยท     131158  ยท     256210  ยท       201886  ยท            4  ยท          -  โ”‚
+|  MockSmartWallet  ยท  quitLock            ยท     129058  ยท     254110  ยท       199786  ยท            4  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  withdraw            ยท          -  ยท          -  ยท       666280  ยท            1  ยท          -  โ”‚
+|  MockSmartWallet  ยท  withdraw            ยท          -  ยท          -  ยท       664174  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  checkpoint          ยท      82307  ยท    3715511  ยท      1272491  ยท           10  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  collectPenalty      ยท          -  ยท          -  ยท        49948  ยท            1  ยท          -  โ”‚
+|  VotingEscrow     ยท  collectPenalty      ยท          -  ยท          -  ยท        47863  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  createLock          ยท     293060  ยท    3978208  ยท       414348  ยท           60  ยท          -  โ”‚
+|  VotingEscrow     ยท  createLock          ยท     290954  ยท    3976102  ยท       412242  ยท           60  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  delegate            ยท     246709  ยท    4048411  ยท       650225  ยท           33  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  increaseAmount      ยท     234777  ยท    1077801  ยท       448554  ยท            4  ยท          -  โ”‚
+|  VotingEscrow     ยท  increaseAmount      ยท     232671  ยท    1075695  ยท       446448  ยท            4  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  increaseUnlockTime  ยท      46794  ยท     416024  ยท       143186  ยท           23  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  quitLock            ยท     127639  ยท    1605731  ยท       375486  ยท           13  ยท          -  โ”‚
+|  VotingEscrow     ยท  quitLock            ยท     125539  ยท    1603631  ยท       373386  ยท           13  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  unlock              ยท          -  ยท          -  ยท        14596  ยท            3  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  updateBlocklist     ยท          -  ยท          -  ยท        47186  ยท           14  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  withdraw            ยท     106462  ยท    3752666  ยท       610141  ยท           33  ยท          -  โ”‚
+|  VotingEscrow     ยท  withdraw            ยท     104356  ยท    3750560  ยท       608035  ยท           33  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  Deployments                             ยท                                           ยท  % of limit   ยท             โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  Blocklist                               ยท     278212  ยท     278236  ยท       278231  ยท        2.2 %  ยท          -  โ”‚
+|  Blocklist                               ยท     248613  ยท     248637  ยท       248632  ยท          2 %  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockERC20                               ยท          -  ยท          -  ยท      1278169  ยท       10.3 %  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockSmartWallet                         ยท          -  ยท          -  ยท       416156  ยท        3.3 %  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow                            ยท    4374338  ยท    4374350  ยท      4374350  ยท       35.1 %  ยท          -  โ”‚
+|  VotingEscrow                            ยท    4280168  ยท    4280180  ยท      4280180  ยท       34.4 %  ยท          -  โ”‚
 ยท------------------------------------------|-------------|-------------|---------------|---------------|-------------ยท
 
-  117 passing (48s)
+  117 passing (46s)

[Gโ€‘03] Structs can be packed into fewer storage slots

Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings

There is 1 instance of this issue:

File: contracts/VotingEscrow.sol

/// @audit Variable ordering with 3 slots instead of the current 4:
///           uint256(32):end, address(20):delegatee, int128(16):amount, int128(16):delegated
75        struct LockedBalance {
76            int128 amount;
77            uint256 end;
78            int128 delegated;
79            address delegatee;
80:       }

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L75-L80

diff --git a/contracts/VotingEscrow.sol b/contracts/VotingEscrow.sol
index f15781a..0318bc3 100644
--- a/contracts/VotingEscrow.sol
+++ b/contracts/VotingEscrow.sol
@@ -73,10 +73,10 @@ contract VotingEscrow is IVotingEscrow, ReentrancyGuard {
         uint256 blk;
     }
     struct LockedBalance {
-        int128 amount;
         uint256 end;
-        int128 delegated;
         address delegatee;
+        int128 amount;
+        int128 delegated;
     }
 
     // Miscellaneous
@@ -420,7 +420,7 @@ contract VotingEscrow is IVotingEscrow, ReentrancyGuard {
         locked_.delegated += int128(int256(_value));
         locked_.delegatee = msg.sender;
         locked[msg.sender] = locked_;
-        _checkpoint(msg.sender, LockedBalance(0, 0, 0, address(0)), locked_);
+        _checkpoint(msg.sender, LockedBalance({amount:0, end:0, delegated:0, delegatee:address(0)}), locked_);
         // Deposit locked tokens
         require(
             token.transferFrom(msg.sender, address(this), _value),
diff --git a/test/votingEscrowDelegationMathTest.ts b/test/votingEscrowDelegationMathTest.ts
index 5e43096..088fb9c 100644
--- a/test/votingEscrowDelegationMathTest.ts
+++ b/test/votingEscrowDelegationMathTest.ts
@@ -138,10 +138,10 @@ describe("VotingEscrow Delegation Math test", () => {
   };
 
   interface LockedBalance {
-    amount: BN;
     end: BN;
-    delegated: BN;
     delegatee: string;
+    amount: BN;
+    delegated: BN;
   }
 
   interface Point {
@@ -173,10 +173,10 @@ describe("VotingEscrow Delegation Math test", () => {
       epoch,
       userEpoch,
       userLocked: {
-        amount: locked[0],
-        end: locked[1],
-        delegated: locked[2],
-        delegatee: locked[3],
+        end: locked[0],
+        delegatee: locked[1],
+        amount: locked[2],
+        delegated: locked[3],
       },
       userLastPoint: {
         bias: userLastPoint[0],
diff --git a/test/votingEscrowGasTest.ts b/test/votingEscrowGasTest.ts
index d6d03fd..af94f35 100644
--- a/test/votingEscrowGasTest.ts
+++ b/test/votingEscrowGasTest.ts
@@ -174,10 +174,10 @@ describe("Gas usage tests", () => {
       epoch,
       userEpoch,
       userLocked: {
-        amount: locked[0],
-        end: locked[1],
-        delegated: locked[2],
-        delegatee: locked[3],
+        end: locked[0],
+        delegatee: locked[1],
+        amount: locked[2],
+        delegated: locked[3],
       },
       userLastPoint: {
         bias: userLastPoint[0],
diff --git a/test/votingEscrowMathTest.ts b/test/votingEscrowMathTest.ts
index 9d0b9b6..e084b30 100644
--- a/test/votingEscrowMathTest.ts
+++ b/test/votingEscrowMathTest.ts
@@ -207,8 +207,10 @@ describe("VotingEscrow Math test", () => {
   });
 
   interface LockedBalance {
-    amount: BN;
     end: BN;
+    delegatee: string;
+    amount: BN;
+    delegated: BN;
   }
 
   interface Point {
@@ -252,8 +254,10 @@ describe("VotingEscrow Math test", () => {
       //totalStaticWeight: await votingLockup.totalStaticWeight(),
       // userStaticWeight: await votingLockup.staticBalanceOf(sender.address),
       userLocked: {
-        amount: locked[0],
-        end: locked[1],
+        end: locked[0],
+        delegatee: locked[1],
+        amount: locked[2],
+        delegated: locked[3],
       },
       userLastPoint: {
         bias: userLastPoint[0],
diff --git a/tmp/gas_before b/tmp/gas_after
index 3deb415..09dd64b 100644
--- a/tmp/gas_before
+++ b/tmp/gas_after
@@ -167,7 +167,7 @@ No need to generate any newer typings.
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  Contract         ยท  Method              ยท  Min        ยท  Max        ยท  Avg          ยท  # calls      ยท  eur (avg)  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  Blocklist        ยท  block               ยท      45000  ยท     409628  ยท       198815  ยท            5  ยท          -  โ”‚
+|  Blocklist        ยท  block               ยท      42887  ยท     387472  ยท       188685  ยท            5  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockERC20        ยท  approve             ยท      46176  ยท      46200  ยท        46196  ยท           96  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
@@ -177,35 +177,35 @@ No need to generate any newer typings.
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockERC20        ยท  transfer            ยท      51588  ยท      51612  ยท        51606  ยท           83  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  createLock          ยท     334002  ยท     378450  ยท       355494  ยท            7  ยท          -  โ”‚
+|  MockSmartWallet  ยท  createLock          ยท     311601  ยท     356043  ยท       333090  ยท            7  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  delegate            ยท          -  ยท          -  ยท       340388  ยท            2  ยท          -  โ”‚
+|  MockSmartWallet  ยท  delegate            ยท          -  ยท          -  ยท       350371  ยท            2  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  increaseUnlockTime  ยท          -  ยท          -  ยท       208859  ยท            1  ยท          -  โ”‚
+|  MockSmartWallet  ยท  increaseUnlockTime  ยท          -  ยท          -  ยท       206298  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  quitLock            ยท     131158  ยท     256210  ยท       201886  ยท            4  ยท          -  โ”‚
+|  MockSmartWallet  ยท  quitLock            ยท     140849  ยท     265907  ยท       211580  ยท            4  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  MockSmartWallet  ยท  withdraw            ยท          -  ยท          -  ยท       666280  ยท            1  ยท          -  โ”‚
+|  MockSmartWallet  ยท  withdraw            ยท          -  ยท          -  ยท       676067  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  checkpoint          ยท      82307  ยท    3715511  ยท      1272491  ยท           10  ยท          -  โ”‚
+|  VotingEscrow     ยท  checkpoint          ยท      82319  ยท    3715835  ยท      1272603  ยท           10  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  collectPenalty      ยท          -  ยท          -  ยท        49948  ยท            1  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  createLock          ยท     293060  ยท    3978208  ยท       414348  ยท           60  ยท          -  โ”‚
+|  VotingEscrow     ยท  createLock          ยท     270653  ยท    3956119  ยท       391951  ยท           60  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  delegate            ยท     246709  ยท    4048411  ยท       650225  ยท           33  ยท          -  โ”‚
+|  VotingEscrow     ยท  delegate            ยท     224688  ยท    4026678  ยท       646994  ยท           33  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  increaseAmount      ยท     234777  ยท    1077801  ยท       448554  ยท            4  ยท          -  โ”‚
+|  VotingEscrow     ยท  increaseAmount      ยท     229422  ยท    1072518  ยท       443303  ยท            4  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  increaseUnlockTime  ยท      46794  ยท     416024  ยท       143186  ยท           23  ยท          -  โ”‚
+|  VotingEscrow     ยท  increaseUnlockTime  ยท      44338  ยท     413481  ยท       140686  ยท           23  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  quitLock            ยท     127639  ยท    1605731  ยท       375486  ยท           13  ยท          -  โ”‚
+|  VotingEscrow     ยท  quitLock            ยท     137330  ยท    1615548  ยท       385196  ยท           13  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  unlock              ยท          -  ยท          -  ยท        14596  ยท            3  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  VotingEscrow     ยท  updateBlocklist     ยท          -  ยท          -  ยท        47186  ยท           14  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow     ยท  withdraw            ยท     106462  ยท    3752666  ยท       610141  ยท           33  ยท          -  โ”‚
+|  VotingEscrow     ยท  withdraw            ยท     116189  ยท    3762705  ยท       619911  ยท           33  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  Deployments                             ยท                                           ยท  % of limit   ยท             โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
@@ -215,8 +215,8 @@ No need to generate any newer typings.
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
 |  MockSmartWallet                         ยท          -  ยท          -  ยท       416156  ยท        3.3 %  ยท          -  โ”‚
 ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|ยทยทยทยทยทยทยทยทยทยทยทยทยทยท
-|  VotingEscrow                            ยท    4374338  ยท    4374350  ยท      4374350  ยท       35.1 %  ยท          -  โ”‚
+|  VotingEscrow                            ยท    4245313  ยท    4245325  ยท      4245325  ยท       34.1 %  ยท          -  โ”‚
 ยท------------------------------------------|-------------|-------------|---------------|---------------|-------------ยท
 
-  117 passing (48s)
+  117 passing (44s)
 

[Gโ€‘04] Using calldata instead of memory for read-only arguments in external functions saves gas

When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution. Note that even if an interface defines a function as having memory arguments, it's still valid for implementation contracs to use calldata arguments instead.

If the array is passed to an internal function which passes the array to another internal function where the array is modified and therefore memory is used in the external call, it's still more gass-efficient to use calldata when the external function uses modifiers, since the modifiers may prevent the internal functions from being called. Structs have the same overhead as an array of length one

Note that I've also flagged instances where the function is public but can be marked as external since it's not called by the contract, and cases where a constructor is involved

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit _name
/// @audit _symbol
100       constructor(
101           address _owner,
102           address _penaltyRecipient,
103           address _token,
104           string memory _name,
105:          string memory _symbol

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L100-L105

[Gโ€‘05] Using storage instead of memory for structs/arrays saves gas

When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read. Instead of declearing the variable with the memory keyword, declaring the variable with the storage keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incuring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory, or if the array/struct is being read from another memory array/struct

There are 9 instances of this issue:

File: contracts/VotingEscrow.sol

410:          LockedBalance memory locked_ = locked[msg.sender];

446:          LockedBalance memory locked_ = locked[msg.sender];

499:          LockedBalance memory locked_ = locked[msg.sender];

527:          LockedBalance memory locked_ = locked[msg.sender];

561:          LockedBalance memory locked_ = locked[msg.sender];

633:          LockedBalance memory locked_ = locked[msg.sender];

788:          Point memory point0 = pointHistory[epoch];

866:          Point memory lastPoint = pointHistory[epoch_];

882:          Point memory point = pointHistory[targetEpoch];

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L410

[Gโ€‘06] Avoid contract existence checks by using solidity version 0.8.10 or later

Prior to 0.8.10 the compiler inserted extra code, including EXTCODESIZE (100 gas), to check for contract existence for external calls. In more recent solidity versions, the compiler will not insert these checks if the external call has a return value

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit decimals()
115:          decimals = IERC20(_token).decimals();

/// @audit isBlocked()
126:              !IBlocklist(blocklist).isBlocked(msg.sender),

/// @audit isBlocked()
563:          require(!IBlocklist(blocklist).isBlocked(_addr), "Blocked contract");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L115

[Gโ€‘07] State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit penaltyRecipient on line 676
677:          emit CollectPenalty(amount, penaltyRecipient);

/// @audit pointHistory on line 788
796:              Point memory point1 = pointHistory[epoch + 1];

/// @audit pointHistory on line 882
891:              Point memory pointNext = pointHistory[targetEpoch + 1];

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L677

[Gโ€‘08] <x> += <y> costs more gas than <x> = <x> + <y> for state variables

Using the addition operator instead of plus-equals saves 113 gas

There is 1 instance of this issue:

File: contracts/VotingEscrow.sol

654:          penaltyAccumulated += penaltyAmount;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L654

[Gโ€‘09] internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

There are 3 instances of this issue:

File: contracts/features/Blocklist.sol

37:       function _isContract(address addr) internal view returns (bool) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L37

File: contracts/VotingEscrow.sol

662       function _calculatePenaltyRate(uint256 end)
663           internal
664           view
665:          returns (uint256)

732       function _findUserBlockEpoch(address _addr, uint256 _block)
733           internal
734           view
735:          returns (uint256)

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L662-L665

[Gโ€‘10] Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement

require(a <= b); x = b - a => require(a <= b); unchecked { x = b - a }

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit if-condition on line 299
301:                  (MULTIPLIER * (block.number - lastPoint.blk)) /

/// @audit if-condition on line 299
302:                  (block.timestamp - lastPoint.ts);

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L301

[Gโ€‘11] ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops

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

There are 4 instances of this issue:

File: contracts/VotingEscrow.sol

309:          for (uint256 i = 0; i < 255; i++) {

717:          for (uint256 i = 0; i < 128; i++) {

739:          for (uint256 i = 0; i < 128; i++) {

834:          for (uint256 i = 0; i < 255; i++) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L309

[Gโ€‘12] Optimize names to save gas

public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted

There are 4 instances of this issue:

File: contracts/features/Blocklist.sol

/// @audit block(), isBlocked()
9:    contract Blocklist {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L9

File: contracts/interfaces/IBlocklist.sol

/// @audit isBlocked()
6:    interface IBlocklist {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IBlocklist.sol#L6

File: contracts/interfaces/IVotingEscrow.sol

/// @audit createLock(), increaseAmount(), increaseUnlockTime(), withdraw(), quitLock(), balanceOfAt(), totalSupplyAt(), forceUndelegate()
4:    interface IVotingEscrow {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IVotingEscrow.sol#L4

File: contracts/VotingEscrow.sol

/// @audit updateBlocklist(), updatePenaltyRecipient(), unlock(), lockEnd(), getLastUserPoint(), checkpoint(), collectPenalty()
23:   contract VotingEscrow is IVotingEscrow, ReentrancyGuard {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L23

[Gโ€‘13] Using bools for storage incurs overhead

    // 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.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from false to true, after having been true in the past

There is 1 instance of this issue:

File: contracts/features/Blocklist.sol

10:       mapping(address => bool) private _blocklist;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L10

[Gโ€‘14] Use a more recent version of solidity

Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value

There are 5 instances of this issue:

File: contracts/features/Blocklist.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L2

File: contracts/interfaces/IBlocklist.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IBlocklist.sol#L2

File: contracts/interfaces/IERC20.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IERC20.sol#L2

File: contracts/interfaces/IVotingEscrow.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/interfaces/IVotingEscrow.sol#L2

File: contracts/VotingEscrow.sol

2:    pragma solidity ^0.8.3;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L2

[Gโ€‘15] Using > 0 costs more gas than != 0 when used on a uint in a require() statement

This change saves 6 gas per instance. The optimization works until solidity version 0.8.13 where there is a regression in gas costs.

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

412:          require(_value > 0, "Only non zero amount");

448:          require(_value > 0, "Only non zero amount");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L412

[Gโ€‘16] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 5 gas per loop

There are 4 instances of this issue:

File: contracts/VotingEscrow.sol

309:          for (uint256 i = 0; i < 255; i++) {

717:          for (uint256 i = 0; i < 128; i++) {

739:          for (uint256 i = 0; i < 128; i++) {

834:          for (uint256 i = 0; i < 255; i++) {

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L309

[Gโ€‘17] Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contractโ€™s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.

https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Each operation involving a uint8 costs an extra 22-28 gas (depending on whether the other operand is also a variable of type uint8) as compared to ones involving uint256, due to the compiler having to clear the higher bits of the memory word before operating on the uint8, as well as the associated stack operations of doing so. Use a larger size then downcast where needed

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit int128 oldSlopeDelta
380:                  oldSlopeDelta = oldSlopeDelta + userOldPoint.slope;

/// @audit int128 oldSlopeDelta
382:                      oldSlopeDelta = oldSlopeDelta - userNewPoint.slope; // It was a new deposit, not extension

/// @audit int128 newSlopeDelta
388:                      newSlopeDelta = newSlopeDelta - userNewPoint.slope; // old slope disappeared at this point

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L380

[Gโ€‘18] Using private rather than public for constants, saves gas

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

There are 3 instances of this issue:

File: contracts/VotingEscrow.sol

46:       uint256 public constant WEEK = 7 days;

47:       uint256 public constant MAXTIME = 365 days;

48:       uint256 public constant MULTIPLIER = 10**18;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L46

[Gโ€‘19] Division by two should use bit shifting

<x> / 2 is the same as <x> >> 1. While the compiler uses the SHR opcode to accomplish both, the version that uses division incurs an overhead of 20 gas due to JUMPs to and from a compiler utility function that introduces checks which can be avoided by using unchecked {} around the division by two

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

719:              uint256 mid = (min + max + 1) / 2;

743:              uint256 mid = (min + max + 1) / 2;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L719

[Gโ€‘20] Stack variable used as a cheaper cache for a state variable is only used once

If the variable is only accessed once, it's cheaper to use the state variable directly that one time, and save the 3 gas the extra stack assignment would spend

There is 1 instance of this issue:

File: contracts/VotingEscrow.sol

865:          uint256 epoch_ = globalEpoch;

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L865

[Gโ€‘21] require() or revert() statements that check input arguments should be at the top of the function

Checks that involve constants should come before checks that involve state variables, function calls, and calculations. By doing these checks first, the function is able to revert before wasting a Gcoldsload (2100 gas*) in a function that may ultimately revert in the unhappy case.

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

/// @audit expensive op on line 410
412:          require(_value > 0, "Only non zero amount");

/// @audit expensive op on line 446
448:          require(_value > 0, "Only non zero amount");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L412

[Gโ€‘22] Superfluous event fields

block.timestamp and block.number are added to event information by default so adding them manually wastes gas

There are 2 instances of this issue:

File: contracts/VotingEscrow.sol

30:           uint256 ts

36:           uint256 ts

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L30

[Gโ€‘23] Use custom errors rather than revert()/require() strings to save gas

Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hit by avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas

There are 42 instances of this issue:

File: contracts/features/Blocklist.sol

24:           require(msg.sender == manager, "Only manager");

25:           require(_isContract(addr), "Only contracts");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/features/Blocklist.sol#L24

File: contracts/VotingEscrow.sol

116:          require(decimals <= 18, "Exceeds max decimals");

125           require(
126               !IBlocklist(blocklist).isBlocked(msg.sender),
127               "Blocked contract"
128:          );

140:          require(msg.sender == owner, "Only owner");

147:          require(msg.sender == owner, "Only owner");

154:          require(msg.sender == owner, "Only owner");

162:          require(msg.sender == owner, "Only owner");

171:          require(msg.sender == blocklist, "Only Blocklist");

412:          require(_value > 0, "Only non zero amount");

413:          require(locked_.amount == 0, "Lock exists");

414:          require(unlock_time >= locked_.end, "Only increase lock end"); // from using quitLock, user should increaseAmount instead

415:          require(unlock_time > block.timestamp, "Only future lock end");

416:          require(unlock_time <= block.timestamp + MAXTIME, "Exceeds maxtime");

425           require(
426               token.transferFrom(msg.sender, address(this), _value),
427               "Transfer failed"
428:          );

448:          require(_value > 0, "Only non zero amount");

449:          require(locked_.amount > 0, "No lock");

450:          require(locked_.end > block.timestamp, "Lock expired");

469:              require(locked_.amount > 0, "Delegatee has no lock");

470:              require(locked_.end > block.timestamp, "Delegatee lock expired");

485           require(
486               token.transferFrom(msg.sender, address(this), _value),
487               "Transfer failed"
488:          );

502:          require(locked_.amount > 0, "No lock");

503:          require(unlock_time > locked_.end, "Only increase lock end");

504:          require(unlock_time <= block.timestamp + MAXTIME, "Exceeds maxtime");

511:              require(oldUnlockTime > block.timestamp, "Lock expired");

529:          require(locked_.amount > 0, "No lock");

530:          require(locked_.end <= block.timestamp, "Lock not expired");

531:          require(locked_.delegatee == msg.sender, "Lock delegated");

546:          require(token.transfer(msg.sender, value), "Transfer failed");

563:          require(!IBlocklist(blocklist).isBlocked(_addr), "Blocked contract");

564:          require(locked_.amount > 0, "No lock");

565:          require(locked_.delegatee != _addr, "Already delegated");

587:          require(toLocked.amount > 0, "Delegatee has no lock");

588:          require(toLocked.end > block.timestamp, "Delegatee lock expired");

589:          require(toLocked.end >= fromLocked.end, "Only delegate to longer lock");

635:          require(locked_.amount > 0, "No lock");

636:          require(locked_.end > block.timestamp, "Lock expired");

637:          require(locked_.delegatee == msg.sender, "Lock delegated");

657:          require(token.transfer(msg.sender, remainingAmount), "Transfer failed");

676:          require(token.transfer(penaltyRecipient, amount), "Transfer failed");

776:          require(_blockNumber <= block.number, "Only past block number");

877:          require(_blockNumber <= block.number, "Only past block number");

https://github.com/code-423n4/2022-08-fiatdao/blob/fece3bdb79ccacb501099c24b60312cd0b2e4bb2/contracts/VotingEscrow.sol#L116

#0 - lacoop6tu

2022-08-26T15:34:28Z

Good one

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax ยฉ 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter