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: 51/99
Findings: 2
Award: $83.56
π 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.9769 USDC - $48.98
In the require statement in InfinityStaker.sol
at L193 the intention is to check whether the users total staked tokens is not 0. However the require statement looks like this:
require(totalStaked >= 0, 'nothing staked to rage quit');
This condition will always be true for a uint256
since it can never be below 0 anyways. Thus this require statement will never revert at this point.
It should instead be changed to
require(totalStaked > 0, 'nothing staked to rage quit');
Only variables defined as constant or immutables should be named in capital, see Solidity style guide for constants.
For non-constant variables the mixedCase naming should be used instead, see Solidity style guide for local and state variables.
File InfinityExchange.sol:
address public MATCH_EXECUTOR; uint32 public WETH_TRANSFER_GAS_UNITS = 50000; uint16 public PROTOCOL_FEE_BPS = 250;
File InfinityStaker.sol:
address public INFINITY_TOKEN; address public INFINITY_TREASURY; uint16 public BRONZE_STAKE_THRESHOLD = 1000; uint16 public SILVER_STAKE_THRESHOLD = 5000; uint16 public GOLD_STAKE_THRESHOLD = 10000; uint16 public PLATINUM_STAKE_THRESHOLD = 20000; uint16 public THREE_MONTH_PENALTY = 2; uint16 public SIX_MONTH_PENALTY = 3; uint16 public TWELVE_MONTH_PENALTY = 4;
#0 - nneverlander
2022-06-23T11:29:25Z
Duplicate
π 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
34.5799 USDC - $34.58
There are a few variables throughout the code base that is only assigned in the constructor, and then never assigned a new value - these can be marked as immutable to save some gas every time the variables are used.
File InifityToken.sol L31:
uint256 public currentEpochTimestamp;
File InfinityStaker.sol L25:
address public INFINITY_TOKEN;
The state variable userMinOrderNonce[msg.sender]
in the contract cancelAllOrders()
can be cached to save gas on the expensive SLOAD
operations.
File InfinityExchange.sol at L380-L381:
require(minNonce > userMinOrderNonce[msg.sender], 'nonce too low'); require(minNonce < userMinOrderNonce[msg.sender] + 1000000, 'too many');
As shown in the code example above, the state variable is read from storage twice, meaning two gas expensive SLOAD
operations. Instead, we can cache the variable in memory, such that the 2 SLOAD
operations will be converted into 1 SLOAD
, 1 MSTORE
and 2 MLOAD
operations, which is cheaper.
This means the code can be changed into:
uint256 cachedNonce = userMinOrderNonce[msg.sender]; require(minNonce > cachedNonce, 'nonce too low'); require(minNonce < cachedNonce + 1000000, 'too many');
This will approximately save 152 gas
Using an expression like keccak256()
in a constant will make the expression be evaluated each time the constant is used, which is the opposite of what we try to accomplish with a constant, and thus ends up costing more gas than needed.
Instead the variable should be marked as an immutable and assigned in the constructor, because then the expression is only evaluated once.
File InfinityToken.sol L25-L28:
bytes32 public constant EPOCH_INFLATION = keccak256('Inflation'); bytes32 public constant EPOCH_DURATION = keccak256('EpochDuration'); bytes32 public constant EPOCH_CLIFF = keccak256('Cliff'); bytes32 public constant MAX_EPOCHS = keccak256('MaxEpochs');
When declaring a uint
it will have the value of 0 by default. This means that declaring a uint
variable uint256 var = 0;
will just use unnecessary gas and should instead just be uint256 var;
.
Removing the assignment of 0 will save 8 gas
and since this is done for almost every uint
in the code base, the total amount of gas savings for this can be decent. A few examples:
InfinityExchange L148:
for (uint256 i = 0; i < numMakerOrders; ) {
InfinityExchange L200:
for (uint256 i = 0; i < ordersLength; ) {
InfinityExchange L219:
for (uint256 i = 0; i < ordersLength; ) {
InfinityExchange L272:
for (uint256 i = 0; i < numSells; ) {
InfinityExchange L308:
for (uint256 i = 0; i < numMakerOrders; ) {
#0 - nneverlander
2022-06-23T11:29:17Z
Duplicate