Use of transferFrom() rather than safeTransferFrom() for NFTs in will lead to the loss of NFTs
1
[L‑02]
Don't use payable.transfer()/payable.send()
1
[L‑03]
Unused/empty receive()/fallback() function
4
[L‑04]
require() should be used instead of assert()
13
[L‑05]
Self-delegation is not automatic
1
[L‑06]
Function may run out of gas
1
[L‑07]
Vulnerable to cross-chain replay attacks due to static DOMAIN_SEPARATOR/domainSeparator
1
[L‑08]
Wrong comment
1
[L‑09]
Missing checks for address(0x0) when assigning values to address state variables
7
[L‑10]
Only a billion checkpoints available
1
Total: 31 instances over 10 issues
Non-critical Issues
Issue
Instances
[N‑01]
Consider addings checks for signature malleability
1
[N‑02]
ecrecover() signature validity not checked
1
[N‑03]
Boilerplate not replaced
2
[N‑04]
Remove commented out code
1
[N‑05]
Invalid/extraneous/optional function definitions in interface
4
[N‑06]
Remove include for hardhat's console
1
[N‑07]
Contract implements interface without extending the interface
1
[N‑08]
require()/revert() statements should have descriptive reason strings
31
[N‑09]
public functions not called by the contract should be declared external instead
13
[N‑10]
Non-assembly method available
2
[N‑11]
constants should be defined rather than using magic numbers
49
[N‑12]
Numeric values having to do with time should use time units for readability
5
[N‑13]
Large multiples of ten should use scientific notation (e.g. 1e6) rather than decimal literals (e.g. 1000000), for readability
2
[N‑14]
Missing event and or timelock for critical parameter change
3
[N‑15]
Use a more recent version of solidity
2
[N‑16]
Use scientific notation (e.g. 1e18) rather than exponentiation (e.g. 10**18)
2
[N‑17]
Inconsistent spacing in comments
2
[N‑18]
Lines are too long
8
[N‑19]
Inconsistent method of specifying a floating pragma
1
[N‑20]
Variable names that consist of all capital letters should be reserved for constant/immutable variables
2
[N‑21]
Non-library/interface files should use fixed compiler versions, not floating ones
1
[N‑22]
Typos
24
[N‑23]
File does not contain an SPDX Identifier
1
[N‑24]
NatSpec is incomplete
19
[N‑25]
Event is missing indexed fields
7
[N‑26]
Duplicated require()/revert() checks should be refactored to a modifier or function
14
Total: 199 instances over 26 issues
Low Risk Issues
[L‑01] Use of transferFrom() rather than safeTransferFrom() for NFTs in will lead to the loss of NFTs
The EIP-721 standard says the following about transferFrom():
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
[L‑02] Don't use payable.transfer()/payable.send()
The use of payable.transfer() is heavily frowned upon because it can lead to the locking of funds. The transfer() call requires that the recipient is either an EOA account, or is a contract that has a payable callback. For the contract case, the transfer() call only provides 2300 gas for the contract to complete its operations. This means the following cases can cause the transfer to fail:
The contract does not have a payable callback
The contract's payable callback spends more than 2300 gas (which is only enough to emit something)
The contract is called through a proxy which itself uses up the 2300 gas
Use OpenZeppelin's Address.sendValue() instead
There is 1 instance of this issue:
File: contracts/core/GolomTrader.sol
154: payable(payAddress).transfer(payAmt); // royalty transfer to royaltyaddress
If the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth)))
[L‑04] require() should be used instead of assert()
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction's available gas rather than returning it, as require()/revert() do. assert() should be avoided even past solidity version 0.8.0 as its documentation states that "The assert function creates an error of type Panic(uint256). ... Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix".
Once the number of epochs grow to a large number, the array allocated will be large, and the number of iterations calling external functions on ve will also be large, leading to the function running out of gas
There is 1 instance of this issue:
File: /contracts/rewards/RewardDistributor.sol
215 function stakerRewards(uint256 tokenid) public view returns (
216 uint256,
217 uint256,
218 uint256[] memory
219 ){
220 require(address(ve) != address(0), ' VE not added yet');
221
222 uint256 reward = 0;
223 uint256 rewardEth = 0;
224 uint256[] memory unclaimedepochs = new uint256[](epoch);
225 // for each epoch
226: for (uint256 index = 0; index < epoch; index++) {
The function description and return values are incorrectly copied from another function
There is 1 instance of this issue:
File: /contracts/rewards/RewardDistributor.sol
252 /// @dev returns unclaimed rewards of an NFT, returns (unclaimed golom rewards, unclaimed eth rewards, unclaimed epochs)
253 /// @param addr the nft id to claim rewards for all ids in the list must belong to 1 address
254 function traderRewards(address addr) public view returns (
255 uint256
256: ){
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/contracts/VotingEscrow.sol
535: mapping(uint => Point[1000000000]) public user_point_history; // user -> Point[user_epoch]
[N‑05] Invalid/extraneous/optional function definitions in interface
There are 4 instances of this issue:
File: contracts/core/GolomTrader.sol
/// @audit withdraw(uint256) isn't defined with those arguments in the standard ERC20 definition
33: function withdraw(uint256 wad) external;
File: contracts/rewards/RewardDistributor.sol
/// @audit mint(address,uint256) isn't defined with those arguments in the standard ERC20 definition
24: function mint(address account, uint256 amount) external;
/// @audit balanceOfNFTAt(uint256,uint256) isn't defined with those arguments in the standard ERC20 definition
26: function balanceOfNFTAt(uint256 _tokenId, uint256 _t) external view returns (uint256);
/// @audit deposit() isn't defined with those arguments in the standard ERC20 definition
28: function deposit() external payable;
[N‑07] Contract implements interface without extending the interface
Not extending the interface may lead to the wrong function signature being used, leading to unexpected behavior. If the interface is in fact being implemented, use the override keyword to indicate that fact
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
File: contracts/vote-escrow/VoteEscrowCore.sol
/// @audit 255
745: for (uint256 i = 0; i < 255; ++i) {
/// @audit 128
1044: for (uint256 i = 0; i < 128; ++i) {
/// @audit 128
1115: for (uint256 i = 0; i < 128; ++i) {
/// @audit 255
1167: for (uint256 i = 0; i < 255; ++i) {
[N‑16] 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
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length
There are 8 instances of this issue:
File: contracts/core/GolomTrader.sol
132: 'order(address collection,uint256 tokenId,address signer,uint256 orderType,uint256 totalAmt,payment exchange,payment prePayment,bool isERC721,uint256 tokenAmt,uint256 refererrAmt,bytes32 root,address reservedAddress,uint256 nonce,uint256 deadline)payment(uint256 paymentAmt,address paymentAddress)'
329: /// to send ether to that address on filling the order, Match an criteria order, ensuring that the supplied proof demonstrates inclusion of the tokenId in the associated merkle root, if root is 0 then any token can be used to fill the order
File: contracts/rewards/RewardDistributor.sol
126: epochTotalFee[0] = address(this).balance; // staking and trading rewards start at epoch 1, for epoch 0 all contract ETH balance is converted to staker rewards rewards.
[N‑19] Inconsistent method of specifying a floating pragma
Some files use >=, some use ^. The instances below are examples of the method that has the fewest instances for a specific version. Note that using >= without also specifying <= will lead to failures to compile, or external project incompatability, when the major version changes and there are breaking-changes, so ^ should be preferred regardless of the instance counts
File: contracts/core/GolomTrader.sol
/// @audit succesful
53: Payment exchange; // payment agreed by maker of the order to pay on succesful filling of trade this amt is subtracted from totalamt
/// @audit facilating
54: Payment prePayment; // another payment , can be used for royalty, facilating trades
/// @audit usefull
60: uint256 nonce; // nonce of order usefull for cancelling in bulk
/// @audit succesful
201: /// @param p any extra payment that the taker of this order wanna send on succesful execution of order
/// @audit succesful
278: /// @param p any extra payment that the taker of this order wanna send on succesful execution of order
/// @audit succesful
333: /// @param p any extra payment that the taker of this order wanna send on succesful execution of order
/// @audit succesfully
370: /// @dev function to settle balances when a bid is filled succesfully
/// @audit succesful
374: /// @param p any extra payment that the taker of this order wanna send on succesful execution of order
File: contracts/rewards/RewardDistributor.sol
/// @audit epoc
61: mapping(uint256 => uint256) public rewardTrader; // reward minted each epoc for trader
/// @audit epoc
/// @audit exhange
62: mapping(uint256 => uint256) public rewardExchange; // reward minted each epoc for exhange
/// @audit epoc
63: mapping(uint256 => uint256) public rewardLP; // reward minted each epoc for LP
/// @audit epoc
64: mapping(uint256 => uint256) public rewardStaker; // reward minted each epoc for stakers
/// @audit upto
66: mapping(uint256 => uint256) public claimedUpto; // epoch upto which tokenid has claimed
/// @audit upto
67: mapping(uint256 => mapping(uint256 => uint256)) public claimed; // epoch upto which tokenid has claimed
/// @audit facilated
95: /// @dev Add fees contributed by the Seller of nft and the exchange/frontend that facilated the trade
/// @audit atleast
107: // this assumes atleast 1 trade is done daily??????
/// @audit begiining
/// @audit begining
111: // emissions is decided by epoch begiining locked/circulating , and amount each nft gets also decided at epoch begining
/// @audit facilated
154: // allows exchange that facilated the nft trades to claim there previous epoch rewards
File: contracts/vote-escrow/VoteEscrowCore.sol
/// @audit blocktimes
267: * and per block could be fairly bad b/c Ethereum changes blocktimes.
/// @audit Exeute
526: /// @dev Exeute transfer of a NFT.
/// @audit Pevious
688: /// @param old_locked Pevious locked amount / end lock time for the user
File: contracts/core/GolomTrader.sol
/// @audit Missing: '@return'
162 /// OrderStatus = 3 , valid order
163 /// @param o the Order struct to be validated
164 function validateOrder(Order calldata o)
165 public
166 view
167 returns (
168 uint256,
169 bytes32,
170: uint256
/// @audit Missing: '@param tokenId'
/// @audit Missing: '@param proof'
328 /// @dev function to fill a signed order of ordertype 2 also has a payment param in case the taker wants
329 /// to send ether to that address on filling the order, Match an criteria order, ensuring that the supplied proof demonstrates inclusion of the tokenId in the associated merkle root, if root is 0 then any token can be used to fill the order
330 /// @param o the Order struct to be filled must be orderType 2
331 /// @param amount the amount of times the order is to be filled(useful for ERC1155)
332 /// @param referrer referrer of the order
333 /// @param p any extra payment that the taker of this order wanna send on succesful execution of order
334 function fillCriteriaBid(
335 Order calldata o,
336 uint256 amount,
337 uint256 tokenId,
338 bytes32[] calldata proof,
339 address referrer,
340 Payment calldata p
341: ) public nonReentrant {
File: contracts/rewards/RewardDistributor.sol
/// @audit Missing: '@return'
213 /// @dev returns unclaimed rewards of an NFT, returns (unclaimed golom rewards, unclaimed eth rewards, unclaimed epochs)
214 /// @param tokenid the nft id to claim rewards for all ids in the list must belong to 1 address
215 function stakerRewards(uint256 tokenid) public view returns (
216 uint256,
217 uint256,
218: uint256[] memory
/// @audit Missing: '@return'
252 /// @dev returns unclaimed rewards of an NFT, returns (unclaimed golom rewards, unclaimed eth rewards, unclaimed epochs)
253 /// @param addr the nft id to claim rewards for all ids in the list must belong to 1 address
254 function traderRewards(address addr) public view returns (
255: uint256
/// @audit Missing: '@return'
267 /// @dev returns unclaimed golom rewards of a trader
268 /// @param addr the nft id to claim rewards for all ids in the list must belong to 1 address
269 function exchangeRewards(address addr) public view returns (
270: uint256
File: contracts/vote-escrow/VoteEscrowCore.sol
/// @audit Missing: '@return'
366 /// @dev Interface identification is specified in ERC-165.
367 /// @param _interfaceID Id of the interface
368: function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
/// @audit Missing: '@return'
396 /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid.
397 /// @param _owner Address for whom to query the balance.
398: function _balance(address _owner) internal view returns (uint256) {
/// @audit Missing: '@return'
403 /// Throws if `_owner` is the zero address. NFTs assigned to the zero address are considered invalid.
404 /// @param _owner Address for whom to query the balance.
405: function balanceOf(address _owner) external view returns (uint256) {
/// @audit Missing: '@return'
409 /// @dev Returns the address of the owner of the NFT.
410 /// @param _tokenId The identifier for an NFT.
411: function ownerOf(uint256 _tokenId) public view returns (address) {
/// @audit Missing: '@return'
415 /// @dev Get the approved address for a single NFT.
416 /// @param _tokenId ID of the NFT to query the approval of.
417: function getApproved(uint256 _tokenId) external view returns (address) {
/// @audit Missing: '@return'
422 /// @param _owner The address that owns the NFTs.
423 /// @param _operator The address that acts on behalf of the owner.
424: function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
/// @audit Missing: '@return'
935 /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
936 /// @param _to Address to deposit
937 function _create_lock(
938 uint256 _value,
939 uint256 _lock_duration,
940 address _to
941: ) internal returns (uint256) {
/// @audit Missing: '@return'
957 /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
958 /// @param _to Address to deposit
959 function create_lock_for(
960 uint256 _value,
961 uint256 _lock_duration,
962 address _to
963: ) external nonreentrant returns (uint256) {
/// @audit Missing: '@return'
968 /// @param _value Amount to deposit
969 /// @param _lock_duration Number of seconds to lock tokens for (rounded down to nearest week)
970: function create_lock(uint256 _value, uint256 _lock_duration) external nonreentrant returns (uint256) {
/// @audit Missing: '@param _tokenId'
974 /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time
975 /// @param _value Amount of tokens to deposit and add to the lock
976: function increase_amount(uint256 _tokenId, uint256 _value) external nonreentrant {
/// @audit Missing: '@param _tokenId'
988 /// @notice Extend the unlock time for `_tokenId`
989 /// @param _lock_duration New number of seconds until tokens unlock
990: function increase_unlock_time(uint256 _tokenId, uint256 _lock_duration) external nonreentrant {
/// @audit Missing: '@return'
1079 /// @dev Returns current token URI metadata
1080 /// @param _tokenId Token ID to fetch URI for.
1081: function tokenURI(uint256 _tokenId) external view returns (string memory) {
/// @audit Missing: '@param t'
1189 /// @notice Calculate total voting power
1190 /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility
1191 /// @return Total voting power
1192: function totalSupplyAtT(uint256 t) public view returns (uint256) {
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 (threefields). 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.
Summary
Low Risk Issues
transferFrom()
rather thansafeTransferFrom()
for NFTs in will lead to the loss of NFTspayable.transfer()
/payable.send()
receive()
/fallback()
functionrequire()
should be used instead ofassert()
DOMAIN_SEPARATOR
/domainSeparator
address(0x0)
when assigning values toaddress
state variablesTotal: 31 instances over 10 issues
Non-critical Issues
ecrecover()
signature validity not checkedinclude
for hardhat's consolerequire()
/revert()
statements should have descriptive reason stringspublic
functions not called by the contract should be declaredexternal
insteadconstant
s should be defined rather than using magic numbers1e6
) rather than decimal literals (e.g.1000000
), for readability1e18
) rather than exponentiation (e.g.10**18
)constant
/immutable
variablesindexed
fieldsrequire()
/revert()
checks should be refactored to a modifier or functionTotal: 199 instances over 26 issues
Low Risk Issues
[L‑01] Use of
transferFrom()
rather thansafeTransferFrom()
for NFTs in will lead to the loss of NFTsThe EIP-721 standard says the following about
transferFrom()
:https://github.com/ethereum/EIPs/blob/78e2c297611f5e92b6a5112819ab71f74041ff25/EIPS/eip-721.md?plain=1#L103-L113 Code must use the
safeTransferFrom()
flavor if it hasn't otherwise verified that the receiving address can handle itThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L236
[L‑02] Don't use
payable.transfer()
/payable.send()
The use of
payable.transfer()
is heavily frowned upon because it can lead to the locking of funds. Thetransfer()
call requires that the recipient is either an EOA account, or is a contract that has apayable
callback. For the contract case, thetransfer()
call only provides 2300 gas for the contract to complete its operations. This means the following cases can cause the transfer to fail:payable
callbackpayable
callback spends more than 2300 gas (which is only enough to emit something)Address.sendValue()
insteadThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L154
[L‑03] Unused/empty
receive()
/fallback()
functionIf the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g.
require(msg.sender == address(weth))
)There are 4 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L459
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L313
[L‑04]
require()
should be used instead ofassert()
Prior to solidity version 0.8.0, hitting an assert consumes the remainder of the transaction's available gas rather than returning it, as
require()
/revert()
do.assert()
should be avoided even past solidity version 0.8.0 as its documentation states that "The assert function creates an error of type Panic(uint256). ... Properly functioning code should never create a Panic, not even on invalid external input. If this happens, then there is a bug in your contract which you should fix".There are 13 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L493
[L‑05] Self-delegation is not automatic
Unlike some of the other functions,
_mint()
isn't overridden to calldelegate()
, which means the user may forget to do so and will miss outThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L677-L684
[L‑06] Function may run out of gas
Once the number of epochs grow to a large number, the array allocated will be large, and the number of iterations calling external functions on
ve
will also be large, leading to the function running out of gasThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L215-L224
[L‑07] Vulnerable to cross-chain replay attacks due to static
DOMAIN_SEPARATOR
/domainSeparator
See this issue from a prior contest for details
There is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L101-L109
[L‑08] Wrong comment
The function description and return values are incorrectly copied from another function
There is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L252-L256
[L‑09] Missing checks for
address(0x0)
when assigning values toaddress
state variablesThere are 7 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L448
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L59
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L81
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L870
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L53
[L‑10] 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:
https://github.com/code-423n4/2022-05-velodrome/blob/7fda97c570b758bbfa7dd6724a336c43d4041740/contracts/contracts/VotingEscrow.sol#L535
Non-critical Issues
[N‑01] Consider addings checks for signature malleability
Use OpenZeppelin's
ECDSA
contract rather than callingecrecover()
directlyThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L176-L180
[N‑02]
ecrecover()
signature validity not checkedecrecover()
returns the zero address if the signature is invalid. If the signer provided is also zero, then all incorrect signatures will be allowedThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L176-L180
[N‑03] Boilerplate not replaced
There are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L5
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L68
[N‑04] Remove commented out code
There is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L218-L225
[N‑05] Invalid/extraneous/optional function definitions in interface
There are 4 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L33
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L24
[N‑06] Remove
include
for hardhat's consoleThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L9
[N‑07] Contract implements interface without extending the interface
Not extending the interface may lead to the wrong function signature being used, leading to unexpected behavior. If the interface is in fact being implemented, use the
override
keyword to indicate that factThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L275
[N‑08]
require()
/revert()
statements should have descriptive reason stringsThere are 31 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L220
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L88
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L360
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L245
[N‑09]
public
functions not called by the contract should be declaredexternal
insteadContracts are allowed to override their parents' functions and change the visibility from
external
topublic
.There are 13 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L203-L209
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L98
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/TokenUriHelper.sol#L66-L71
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L185
[N‑10] 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 necessaryThere are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L98
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L577
[N‑11]
constant
s should be defined rather than using magic numbersEven assembly can benefit from using readable constants instead of hex/numeric literals
There are 49 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L212
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L44
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L84
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/TokenUriHelper.sol#L17
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L745
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L99
[N‑12] Numeric values having to do with time should use time units for readability
There are units for seconds, minutes, hours, days, and weeks, and since they're defined, they should be used
There are 5 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L48
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L296
[N‑13] Large multiples of ten should use scientific notation (e.g.
1e6
) rather than decimal literals (e.g.1000000
), for readabilityThere are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L100
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L308
[N‑14] Missing event and or timelock for critical parameter change
Events help non-contract tools to track changes, and events prevent users from being surprised by changes
There are 3 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L444-L451
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L58-L61
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L868-L871
[N‑15] Use a more recent version of solidity
Use a solidity version of at least 0.8.12 to get
string.concat()
to be used instead ofabi.encodePacked(<str>,<str>)
There are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L3
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/TokenUriHelper.sol#L3
[N‑16] 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 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L48
[N‑17] Inconsistent spacing in comments
Some lines use
// x
and some use//x
. The instances below point out the usages that don't follow the majority, within each fileThere are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L181
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L99
[N‑18] Lines are too long
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. Since the files will most likely reside in GitHub, and GitHub starts using a scroll bar in all cases when the length is over 164 characters, the lines below should be split when they reach that length
There are 8 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L132
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L126
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/TokenUriHelper.sol#L72
[N‑19] Inconsistent method of specifying a floating pragma
Some files use
>=
, some use^
. The instances below are examples of the method that has the fewest instances for a specific version. Note that using>=
without also specifying<=
will lead to failures to compile, or external project incompatability, when the major version changes and there are breaking-changes, so^
should be preferred regardless of the instance countsThere is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L2
[N‑20] Variable names that consist of all capital letters should be reserved for
constant
/immutable
variablesIf the variable needs to be different based on which class it comes from, a
view
/pure
function should be used instead (e.g. like this).There are 2 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L45
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L50
[N‑21] Non-library/interface files should use fixed compiler versions, not floating ones
There is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/governance/GolomToken.sol#L2
[N‑22] Typos
There are 24 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L53
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L61
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L267
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L227
[N‑23] File does not contain an SPDX Identifier
There is 1 instance of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/TokenUriHelper.sol#L0
[N‑24] NatSpec is incomplete
There are 19 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L162-L170
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L213-L218
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L366-L368
[N‑25] Event is missing
indexed
fieldsIndex 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 (threefields). Each
event
should use threeindexed
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 7 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L79
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L70
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L67
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L29
[N‑26] Duplicated
require()
/revert()
checks should be refactored to a modifier or functionThe compiler will inline the function, which will avoid
JUMP
instructions usually associated with functionsThere are 14 instances of this issue:
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/core/GolomTrader.sol#L291
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/rewards/RewardDistributor.sol#L158
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowCore.sol#L1008
https://github.com/code-423n4/2022-07-golom/blob/e5efa8f9d6dda92a90b8b2c4902320acf0c26816/contracts/vote-escrow/VoteEscrowDelegation.sol#L211