Golom contest - Rolezn's results

An NFT marketplace that offers the lowest industry fee, a publicly available order-book along with analytical tools.

General Information

Platform: Code4rena

Start Date: 26/07/2022

Pot Size: $75,000 USDC

Total HM: 29

Participants: 179

Period: 6 days

Judge: LSDan

Total Solo HM: 6

Id: 148

League: ETH

Golom

Findings Distribution

Researcher Performance

Rank: 47/179

Findings: 2

Award: $262.24

🌟 Selected for report: 0

🚀 Solo Findings: 0

(1) Missing Checks for Address(0x0)

Severity: Low

Proof Of Concept

function setDistributor(address _distributor) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L444

function mintAirdrop(address _airdrop) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L42

function mintGenesisReward(address _rewardDistributor) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L50

function setMinter(address _minter) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L58

function changeTrader(address _trader) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L285

function addVoteEscrow(address _voteEscrow) external onlyOwner {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L298

function setVoter(address _voter) external {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L868

Recommended Mitigation Steps

Consider adding zero-address checks in the mentioned codebase.

(2) Use Safetransfer Instead Of Transfer

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.

Proof Of Concept

payable(payAddress).transfer(payAmt); // royalty transfer to royaltyaddress

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L154

rewardToken.transfer(addr, reward);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L151

rewardToken.transfer(addr, reward);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L165

rewardToken.transfer(tokenowner, reward);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L208

assert(IERC20(token).transfer(msg.sender, value));

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1023

Recommended Mitigation Steps

Consider using safeTransfer/safeTransferFrom or require() consistently.

(3) Unused Receive() Function Will Lock Ether In Contract

Severity: Low

If the intention is for the Ether to be used, the function should call another function, otherwise it should revert

Proof Of Concept

receive() external payable {}

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L461

receive() external payable {}

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L315

Recommended Mitigation Steps

The function should call another function, otherwise it should revert

(4) Incorrect parameter used in zero address check

Severity: Low

(address(distributor) == address(0)) checks for the distributor parameter while the function is set to use _distributor

Proof Of Concept

function setDistributor(address _distributor) external onlyOwner { if (address(distributor) == address(0)) { distributor = Distributor(_distributor); } else { pendingDistributor = _distributor; distributorEnableDate = block.timestamp + 1 days; } }

https://github.com/code-423n4/2022-07-golom/tree/main/contractscore/GolomTrader.sol#L445

Recommended Mitigation Steps

Current: if (address(distributor) == address(0))

New: if (address(_distributor) == address(0))

(5) Variable Names That Consist Of All Capital Letters Should Be Reserved For Const/immutable Variables

Severity: Non-Critical

If the variable needs to be different based on which class it comes from, a view/pure function should be used instead.

Proof Of Concept

MIN_VOTING_POWER_REQUIRED = _newMinVotingPower; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L261

(6) Constants Should Be Defined Rather Than Using Magic Numbers

Severity: Non-Critical

Proof Of Concept

o.totalAmt >= o.exchange.paymentAmt + o.prePayment.paymentAmt + o.refererrAmt + (o.totalAmt * 50) / 10000,

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L212

uint256 protocolfee = ((o.totalAmt * 50) / 10000) * amount;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L381

distributorEnableDate = block.timestamp + 1 days;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L449

_mint(_airdrop, 150_000_000 * 1e18);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L44

_mint(_rewardDistributor, 62_500_000 * 1e18);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L52

minterEnableDate = block.timestamp + 1 days;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L60

uint256 constant dailyEmission = 600000 * 10**18;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L48

if (rewardToken.totalSupply() > 1000000000 * 10**18) {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L100

/// @dev executeChangeTrader needs to be called after 1 days

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L283

traderEnableDate = block.timestamp + 1 days;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L286

voteEscrowEnableDate = block.timestamp + 1 days;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L302

require(_delegatedTokenIds.length < 500, 'VVDelegation: Cannot stake more');

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L99

(7) Event Is Missing Indexed Fields

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.

Proof Of Concept

event NewEpoch(uint256 indexed epochNo, uint256 tokenMinted, uint256 rewardStaker, uint256 previousEpochFee);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L70

event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L67

event Deposit( address indexed provider, uint256 tokenId, uint256 value, uint256 indexed locktime, DepositType deposit_type, uint256 ts );

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L284

event Withdraw(address indexed provider, uint256 tokenId, uint256 value, uint256 ts);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L292

event Supply(uint256 prevSupply, uint256 supply);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L293

event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L29

(8) Inconsistent Spacing In Comments

Severity: Non-Critical

Some lines use // x and some use //x. The instances below point out the usages that don’t follow the majority, within each file

Proof Of Concept

//deadline

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L181

//console.log(block.timestamp,epoch,fee);

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L99

(9) Missing event for critical parameter change

Severity: Non-Critical

Proof Of Concept

function setDistributor(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L444

function setMinter(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L58

function changeTrader(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L285

function setApprovalForAll(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L157

function setVoter(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L868

function changeMinVotingPower(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L260

(10) Use a more recent version of Solidity

Severity: Non-Critical

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

Proof Of Concept

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L3

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L2

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L2

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/TokenUriHelper.sol#L3

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L2

Found old version 0.8.11 of Solidity https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L2

Recommended Mitigation Steps

Consider updating to a more recent solidity version.

(11) Public Functions Not Called By The Contract Should Be Declared External Instead

Severity: Non-Critical

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

Proof Of Concept

function fillAsk(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L203

function fillBid(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L279

function cancelOrder(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L312

function fillCriteriaBid(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L334

function traderClaim(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L141

function exchangeClaim(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L155

function multiStakerClaim(

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L172

(12) NATSPEC is incomplete

Severity: Non-Critical

Proof Of Concept

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol

(13) Commented Code

Severity: Non-Critical

Proof Of Concept

// function removeDelegationByOwner(uint256 delegatedTokenId, uint256 ownerTokenId) external { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L219

//console.log(block.timestamp,epoch,fee); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L99

(14) Invalid file import

Severity: Non-Critical

Proof Of Concept

import 'hardhat/console.sol';

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol

(15) Missing NATSPEC documentation

Severity: Non-Critical

Proof Of Concept

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol

(16) Missing NATSPEC documentation

Severity: Non-Critical

Proof Of Concept

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol

(17) payEther() should emit events when payment fails

Severity: Non-Critical

Proof Of Concept

payable(payAddress).transfer(payAmt); https://github.com/code-423n4/2022-07-golom/tree/main/contractscore/GolomTrader.sol#L154

(1) Abi.encode() Is Less Efficient Than Abi.encodepacked()

Severity: Gas Optimizations

Proof Of Concept

abi.encode( https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L102

abi.encode( https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L115

abi.encode( https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L130

bytes32 computedHash = keccak256(abi.encode(leaf)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L414

(2) <Array>.length Should Not Be Looked Up In Every Loop Of A For-loop

Severity: Gas Optimizations

The overheads outlined below are PER LOOP, excluding the first loop

storage arrays incur a Gwarmaccess (100 gas) memory arrays use MLOAD (3 gas) calldata arrays use CALLDATALOAD (3 gas)

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset

Proof Of Concept

for (uint256 i = 0; i < proof.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L415

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L143

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L157

for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L180

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L183

for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L180

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L183

for (uint256 index = 0; index < delegated.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

for (uint256 index = 0; index < delegatednft.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L189

for (uint256 i; i < _array.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L199

(3) Empty Blocks Should Be Removed Or Emit Something

Severity: Gas Optimizations

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}})

Proof Of Concept

fallback() external payable {} https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L459

fallback() external payable {} https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L313

try IERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) returns (bytes4) {} catch ( https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L107

(4) ++i Costs Less Gas Than i++, Especially When It’s Used In For-loops (--i/i-- Too)

Severity: Gas Optimizations

Saves 6 gas per loop

Proof Of Concept

for (uint256 i = 0; i < proof.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L415

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L143

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L157

for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L180

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L226

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L258

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L273

for (uint256 index = 0; index < delegated.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

for (uint256 index = 0; index < delegatednft.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L189

for (uint256 i; i < _array.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L199

Recommended Mitigation Steps

For example, use ++i instead of i++

(5) It Costs More Gas To Initialize Variables To Zero Than To Let The Default Of Zero Be Applied

Severity: Gas Optimizations

Proof Of Concept

for (uint256 i = 0; i < proof.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L415

for (uint256 i = 0; i < 255; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L745

for (uint256 i = 0; i < 128; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1044

for (uint256 i = 0; i < 128; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1115

for (uint256 i = 0; i < 255; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1167

(6) Using > 0 Costs More Gas Than != 0 When Used On A Uint In A Require() Statement

Severity: Gas Optimizations

This change saves 6 gas per instance

Proof Of Concept

require(_value > 0); // dev: need non-zero value https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L927

require(_locked.amount > 0, 'No existing lock found'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L928

require(_value > 0); // dev: need non-zero value https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L927

require(_locked.amount > 0, 'No existing lock found'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L928

require(_value > 0); // dev: need non-zero value https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L944

require(_locked.amount > 0, 'No existing lock found'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L982

require(_locked.amount > 0, 'Nothing is locked'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L997

(7) Multiple Address Mappings Can Be Combined Into A Single Mapping Of An Address To A Struct, Where Appropriate

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.

Proof Of Concept

mapping(address => mapping(uint256 => uint256)) public feesTrader; mapping(address => mapping(uint256 => uint256)) public feesExchange; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L58

mapping(address => uint256) internal ownerToNFTokenCount; mapping(address => mapping(uint256 => uint256)) internal ownerToNFTokenIdList; mapping(address => mapping(address => bool)) internal ownerToOperators;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L332

(8) Multiplication/division By Two Should Use Bit Shifting

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

Proof Of Concept

uint256 _mid = (_min + _max + 1) / 2; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1049

uint256 _mid = (_min + _max + 1) / 2; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1120

uint256 center = upper - (upper - lower) / 2; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L150

(9) <x> += <y> Costs More Gas Than <x> = <x> + <y> For State Variables

Severity: Gas Optimizations

Proof Of Concept

digits -= 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/TokenUriHelper.sol#L143

ownerToNFTokenCount[_to] += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L499

ownerToNFTokenCount[_from] -= 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L512

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L748

last_point.bias -= last_point.slope * int128(int256(t_i - last_checkpoint)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L755

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L756

_epoch += 1; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L768

last_point.slope += (u_new.slope - u_old.slope); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L784

last_point.bias += (u_new.bias - u_old.bias); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L785

old_dslope += u_old.slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L803

old_dslope -= u_new.slope; // It was a new deposit, not extension https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L805

new_dslope -= u_new.slope; // old slope disappeared at this point https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L812

_locked.amount += int128(int256(_value)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L847

last_point.bias -= last_point.slope * int128(int256(_t) - int256(last_point.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1071

block_time += (d_t * (_block - point_0.blk)) / d_block; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1145

upoint.bias -= upoint.slope * int128(int256(block_time - upoint.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1148

block_time += (d_t * (_block - point_0.blk)) / d_block; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1145

upoint.bias -= upoint.slope * int128(int256(block_time - upoint.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1148

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1168

last_point.bias -= last_point.slope * int128(int256(t_i - last_point.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1175

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1179

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1168

last_point.bias -= last_point.slope * int128(int256(t_i - last_point.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1175

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1179

t_i += WEEK; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1168

last_point.bias -= last_point.slope * int128(int256(t_i - last_point.ts)); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1175

last_point.slope += d_slope; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1179

(10) Using Private Rather Than Public For Constants, Saves Gas

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

Proof Of Concept

string public constant name = 'veNFT'; string public constant symbol = 'veNFT'; string public constant version = '1.0.0'; uint8 public constant decimals = 18; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L317-L320

Recommended Mitigation Steps

Set variable to private.

(11) require()/revert() Strings Longer Than 32 Bytes Cost Extra Gas

Severity: Gas Optimizations

Proof Of Concept

require(minterEnableDate <= block.timestamp, 'GolomToken: wait for timelock'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L69

require(tokenowner == ve.ownerOf(tokenids[tindex]), 'Can only claim for a single Address together'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L181

require(epochs[index] < epoch, 'cant claim for future epochs'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L184

require(claimed[tokenids[tindex]][epochs[index]] == 0, 'cant claim if already claimed'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L185

require(tokenowner == ve.ownerOf(tokenids[tindex]), 'Can only claim for a single Address together'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L181

require(epochs[index] < epoch, 'cant claim for future epochs'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L184

require(claimed[tokenids[tindex]][epochs[index]] == 0, 'cant claim if already claimed'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L185

require(tokenowner == ve.ownerOf(tokenids[tindex]), 'Can only claim for a single Address together'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L181

require(epochs[index] < epoch, 'cant claim for future epochs'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L184

require(claimed[tokenids[tindex]][epochs[index]] == 0, 'cant claim if already claimed'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L185

require(traderEnableDate <= block.timestamp, 'RewardDistributor: time not over yet'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L292

require(voteEscrowEnableDate <= block.timestamp, 'RewardDistributor: time not over yet'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L309

require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L929

require(unlock_time > block.timestamp, 'Can only lock until time in the future'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L945

require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L946

require(unlock_time > block.timestamp, 'Can only lock until time in the future'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L945

require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L946

require(_locked.end > block.timestamp, 'Cannot add to expired lock. Withdraw'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L983

require(unlock_time > _locked.end, 'Can only increase lock duration'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L998

require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L999

require(unlock_time > _locked.end, 'Can only increase lock duration'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L998

require(unlock_time <= block.timestamp + MAXTIME, 'Voting lock can be 4 years max'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L999

require(this.balanceOfNFT(tokenId) >= MIN_VOTING_POWER_REQUIRED, 'VEDelegation: Need more voting power'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L73

require(_delegatedTokenIds.length < 500, 'VVDelegation: Cannot stake more'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L99

require(blockNumber < block.number, 'VEDelegation: not yet determined'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L130

require(blockNumber < block.number, 'VEDelegation: not yet determined'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L186

(12) Splitting Require() Statements That Use && Saves Gas

Severity: Gas Optimizations

See https://github.com/code-423n4/2022-01-xdefi-findings/issues/128 which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper

Proof Of Concept

require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L538

require(attachments[_from] == 0 && !voted[_from], 'attached'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L894

require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1008

require(attachments[_tokenId] == 0 && !voted[_tokenId], 'attached'); https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L239

(13) ++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

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

Proof Of Concept

for (uint256 i = 0; i < proof.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L415

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L143

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L157

for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L180

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L183

for (uint256 tindex = 0; tindex < tokenids.length; tindex++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L180

for (uint256 index = 0; index < epochs.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L183

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L226

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L258

for (uint256 index = 0; index < epoch; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L273

for (uint256 i = 0; i < 255; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L745

for (uint256 i = 0; i < 128; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1044

for (uint256 i = 0; i < 128; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1115

for (uint256 i = 0; i < 255; ++i) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L1167

for (uint256 index = 0; index < delegated.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L171

for (uint256 index = 0; index < delegatednft.length; index++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L189

for (uint256 i; i < _array.length; i++) { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowDelegation.sol#L199

(14) Using Bools For Storage Incurs Overhead

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.

Proof Of Concept

bool public isAirdropMinted; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L20

bool public isGenesisRewardMinted; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L21

bool public isAirdropMinted; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L20

bool public isGenesisRewardMinted; https://github.com/code-423n4/2022-07-golom/tree/main/contracts/governance/GolomToken.sol#L21

mapping(uint256 => bool) public voted;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L314

mapping(address => mapping(address => bool)) internal ownerToOperators;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L341

mapping(bytes4 => bool) internal supportedInterfaces;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L344

mapping(uint256 => bool) public voted;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L314

mapping(address => mapping(address => bool)) internal ownerToOperators;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L341

mapping(bytes4 => bool) internal supportedInterfaces;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L344

mapping(uint256 => bool) public voted;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L314

mapping(address => mapping(address => bool)) internal ownerToOperators;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L341

mapping(bytes4 => bool) internal supportedInterfaces;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/vote-escrow/VoteEscrowCore.sol#L344

(15) Using Calldata Instead Of Memory For Read-only Arguments In External Functions Saves Gas

Severity: Gas Optimizations

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. Structs have the same overhead as an array of length one

Proof Of Concept

function _hashOrderinternal(Order calldata o, uint256[2] memory extra) private pure returns (bytes32) {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L127

function _verifyProof( uint256 leaf, bytes32 root, bytes32[] memory proof ) public pure {

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L409

(16) Remove or Replace unused state variables

Severity: Gas Optimizations

Saves a storage slot. If the variable is assigned a non-zero value, saves Gsset (20000 gas). If it’s assigned a zero value, saves Gsreset (2900 gas). If the variable remains unassigned, there is no gas savings unless the variable is public, in which case the compiler-generated non-payable getter deployment cost is saved. If the state variable is overriding an interface’s public function, mark the variable as constant or immutable so that it does not use a storage slot

Proof Of Concept

address public governance;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/core/GolomTrader.sol#L72

mapping(uint256 => uint256) public claimedUpto;

https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L66

(17) Public function uses more gas, than using external function

Severity: Gas Optimizations

The difference is because in public functions, Solidity immediately copies array arguments to memory, while external functions can read directly from calldata. Memory allocation is expensive, whereas reading from calldata is cheap.

Since there are no internal calls to traderClaim and exchangeClaim, the functions can be changed from public to external.

Proof Of Concept

function traderClaim(address addr, uint256[] memory epochs) public { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L141

function exchangeClaim(address addr, uint256[] memory epochs) public { https://github.com/code-423n4/2022-07-golom/tree/main/contracts/rewards/RewardDistributor.sol#L155

Recommended Mitigation Steps

As for best practices, you should use external if you expect that the function will only ever be called externally, and use public if you need to call the function internally.

Reference: https://ethereum.stackexchange.com/questions/19380/external-vs-public-best-practices

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