Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $50,000 USDC
Total HM: 19
Participants: 99
Period: 5 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 136
League: ETH
Rank: 56/99
Findings: 2
Award: $80.49
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkowloon, 0xmint, 8olidity, BowTiedWardens, Chom, Cityscape, Czar102, ElKu, FSchmoede, Funen, GimelSec, GreyArt, IllIllI, KIntern, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, Ruhum, Sm4rty, StErMi, TerrierLover, TomJ, Treasure-Seeker, VAD37, WatchPug, Wayne, _Adam, a12jmx, abhinavmir, antonttc, apostle0x01, asutorufos, berndartmueller, cccz, cloudjunky, codexploder, cryptphi, csanuragjain, defsec, delfin454000, fatherOfBlocks, georgypetrov, hake, hansfriese, horsefacts, hyh, k, kenta, nxrblsrpr, oyc_109, peritoflores, rajatbeladiya, reassor, rfa, robee, sach1r0, saian, samruna, shenwilly, simon135, sorrynotsorry, sseefried, throttle, unforgiven, wagmi, zzzitron
48.9771 USDC - $48.98
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L172
@notice Matches one order to many orders. Example: A buy order with 5 specific NFTs with 5 sell orders with those specific NFTs.
There is 1 additional space between one
and order
in the comment.
PRECISION
variableThroughout the codebase, capital letters are only used for the constant. However, PRECISION
is local variable, but its naming is in caplital letters.
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1161
It should simply name precision
instead of PRECISION
.
capital letters with underscore should be used for constant according to solidity doc.
Constants should be named with all capital letters with underscores separating words
These variables are not constant, but their namings are for constants. https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L25-L42
unstake
functionhttps://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L117
require(amount != 0, 'stake amount cant be 0');
It says stake amount
but it is in unstake
function. Should it be unstake amount
?
Following functions define return statement in its function signature. However, inside the function, it uses return
to actually return the value.
For example, calculateConfigId
function can be written like this without return variable.
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L76
function calculateConfigId(string memory name) external pure returns (bytes32) { return keccak256(abi.encodePacked(name)); }
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L113
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L117
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L121
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L125
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L129
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L133
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L76
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L80
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L84
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L88
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L93
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L98
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L102
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L106
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/TimelockConfig.sol#L111
#0 - nneverlander
2022-06-22T16:10:44Z
Thanks
#1 - HardlyDifficult
2022-07-12T12:27:49Z
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xAsm0d3us, 0xDjango, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xkowloon, BowTiedWardens, Chom, ElKu, FSchmoede, Funen, GimelSec, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, PwnedNoMore, StErMi, Tadashi, TerrierLover, TomJ, Tomio, Wayne, Waze, _Adam, antonttc, apostle0x01, asutorufos, c3phas, codexploder, defsec, delfin454000, fatherOfBlocks, hake, hansfriese, hyh, joestakey, k, kenta, oyc_109, peritoflores, reassor, rfa, robee, sach1r0, simon135, slywaters, zer0dot
31.5116 USDC - $31.51
!= 0
instead of > 0
on uint variablesuint variables will never be lower than 0. Therefore, > 0
and != 0
have same meanings. Using != 0
can reduce the gas deployment cost, so it is worth using != 0
wherever possible.
This part can be written as follows:
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L392
require(numNonces != 0, 'cannot be empty');
The default value of uint varibles are 0. Therefore, there is no need to set 0 on uint variables. Not setting 0 on uint variables can reduce the deployment gas cost.
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L148
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L200
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L219
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L272
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L308
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L349
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L393
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1048
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1086
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1109
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1190
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1206
Using custom errors can reduce the gas cost.
There are more than 50 callsites of require check with inline error message. Using the custom errors instead of the inline error messages can reduce the gas cost.
Following variables or operations can be wrapped by unchecked to reduce the gas cost.
[1] The condition startPrice > endPrice
assures that priceDiff will not underflow.
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1156
uint256 priceDiff; unchecked { priceDiff = startPrice > endPrice ? startPrice - endPrice : endPrice - startPrice; }
[2] The condition require(userstakedAmounts[msg.sender][oldDuration].amount >= amount, ...)
assures that userstakedAmounts[msg.sender][oldDuration].amount -= amount
will not underflow
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L99
unchecked { userstakedAmounts[msg.sender][oldDuration].amount -= amount; }
[3] The conditions require(block.timestamp >= previousEpochTimestamp + getEpochDuration(), ...)
and require(currentEpoch < getMaxEpochs(), ...)
assure that block.timestamp - previousEpochTimestamp
and getMaxEpochs() - currentEpoch
will not underflow
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/token/InfinityToken.sol#L65-L66
uint256 epochsPassedSinceLastAdvance; uint256 epochsLeft; unchecked { epochsPassedSinceLastAdvance = (block.timestamp - previousEpochTimestamp) / getEpochDuration(); epochsLeft = getMaxEpochs() - currentEpoch; }
[4] The conditions if (amount > noVesting)
, if (amount > vestedThreeMonths)
and if (amount > vestedSixMonths)
assure that amount = amount - noVesting
, amount = amount - vestedThreeMonths
and amount = amount - vestedSixMonths
will not underflow respectively
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L301
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L305
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L309
if (amount > noVesting) { userstakedAmounts[user][Duration.NONE].amount = 0; userstakedAmounts[user][Duration.NONE].timestamp = 0; unchecked { amount = amount - noVesting; } if (amount > vestedThreeMonths) { userstakedAmounts[user][Duration.THREE_MONTHS].amount = 0; userstakedAmounts[user][Duration.THREE_MONTHS].timestamp = 0; unchecked { amount = amount - vestedThreeMonths; } if (amount > vestedSixMonths) { userstakedAmounts[user][Duration.SIX_MONTHS].amount = 0; userstakedAmounts[user][Duration.SIX_MONTHS].timestamp = 0; unchecked { amount = amount - vestedSixMonths; } if (amount > vestedTwelveMonths) {
[5] Using constant PROTOCOL_FEE_BPS
will not underflow amount - protocolFee
uint256 remainingAmount uint256 protocolFee = (PROTOCOL_FEE_BPS * amount) / 10000; unchecked { remainingAmount = amount - protocolFee; }
_clearUserStakedAmounts
function
_clearUserStakedAmounts
function sets 0 on amount and timestamp at each duration. Using delete
keyword can reduce gas costs.function _clearUserStakedAmounts(address user) internal { // clear amounts delete userstakedAmounts[user][Duration.NONE]; delete userstakedAmounts[user][Duration.THREE_MONTHS]; delete userstakedAmounts[user][Duration.SIX_MONTHS]; delete userstakedAmounts[user][Duration.TWELVE_MONTHS]; }
_updateUserStakedAmounts
function
_updateUserStakedAmounts
function sets 0 on amount and timestamp at each duration. Using delete
keyword can reduce gas costs.function _updateUserStakedAmounts( address user, uint256 amount, uint256 noVesting, uint256 vestedThreeMonths, uint256 vestedSixMonths, uint256 vestedTwelveMonths ) internal { if (amount > noVesting) { delete userstakedAmounts[user][Duration.NONE]; amount = amount - noVesting; if (amount > vestedThreeMonths) { delete userstakedAmounts[user][Duration.THREE_MONTHS]; amount = amount - vestedThreeMonths; if (amount > vestedSixMonths) { delete userstakedAmounts[user][Duration.SIX_MONTHS]; amount = amount - vestedSixMonths; if (amount > vestedTwelveMonths) { delete userstakedAmounts[user][Duration.TWELVE_MONTHS]; } else { userstakedAmounts[user][Duration.TWELVE_MONTHS].amount -= amount; } } else { userstakedAmounts[user][Duration.SIX_MONTHS].amount -= amount; } } else { userstakedAmounts[user][Duration.THREE_MONTHS].amount -= amount; } } else { userstakedAmounts[user][Duration.NONE].amount -= amount; } }