Platform: Code4rena
Start Date: 21/04/2022
Pot Size: $75,000 USDC
Total HM: 7
Participants: 45
Period: 7 days
Judge: 0xean
Total Solo HM: 5
Id: 111
League: ETH
Rank: 16/45
Findings: 2
Award: $293.84
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: IllIllI
Also found by: 0v3rf10w, 0xDjango, 0xmint, CertoraInc, Dravee, MaratCerby, Ruhum, VAD37, catchup, csanuragjain, defsec, delfin454000, dipp, fatima_naz, gzeon, hake, hyh, joestakey, kebabsec, oyc_109, rayn, robee, samruna, simon135, sorrynotsorry, teryanarmen
192.8881 USDC - $192.89
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 finding from Consensys Diligence Audit of Fei Protocol: https://consensys.net/diligence/audits/2021/01/fei-protocol/#unchecked-return-value-for-iweth-transfer-call
Navigate to the following contract.
transfer/transferFrom functions are used instead of safe transfer/transferFrom on the following contracts.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L134 https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L137
Code Review
Consider using safeTransfer/safeTransferFrom or require() consistently.
Block timestamps have historically been used for a variety of applications, such as entropy for random numbers (see the Entropy Illusion for further details), locking funds for periods of time, and various state-changing conditional statements that are time-dependent. Miners have the ability to adjust timestamps slightly, which can prove to be dangerous if block timestamps are used incorrectly in smart contracts.
https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L80
Manual Code Review
Block timestamps should not be used for entropy or generating random numbers—i.e., they should not be the deciding factor (either directly or through some derivation) for winning a game or changing an important state.
Time-sensitive logic is sometimes required; e.g., for unlocking contracts (time-locking), completing an ICO after a few weeks, or enforcing expiry dates. It is sometimes recommended to use block.number and an average block time to estimate times; with a 10 second block time, 1 week equates to approximately, 60480 blocks. Thus, specifying a block number at which to change a contract state can be more secure, as miners are unable to easily manipulate the block number.
On several locations in the code precautions are taken not to divide by 0, because this will revert the code. However on some locations this isn’t done.
Especially in the claim function div(initialStake - claimedInitialStake) which isn’t checked.
That will cause to revert on the claim function.
Review
Recommend making sure division by 0 won’t occur by checking the variables beforehand and handling this edge case.
Missing checks for zero-addresses may lead to infunctional protocol, if the variable addresses are updated incorrectly.
https://github.com/fei-protocol/ERC4626/blob/643cd044fac34bcbf64e1c3790a5126fec0dbec1/src/xERC4626.sol#L38 https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L33
Code Review
Consider adding zero-address checks in the discussed constructors: require(newAddr != address(0));.
During the code review, It has been observed that owner is only set in the constructor. It is not inherited from the Ownable (Openzeppelin contract.) If the owner is deployed mistakenly with zero address/wrong address, access will be lost.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L35
Code Review
Consider inheriting contract from Openzeppelin Ownable contract.
🌟 Selected for report: 0xkatana
Also found by: 0v3rf10w, 0x1f8b, 0xNazgul, 0xmint, CertoraInc, Dravee, Fitraldys, Funen, IllIllI, NoamYakov, Scocco, Tomio, catchup, csanuragjain, defsec, delfin454000, djxploit, fatima_naz, gzeon, joestakey, joshie, kebabsec, nahnah, oyc_109, rayn, robee, rotcivegaf, saian, samruna, sorrynotsorry, teryanarmen, z3s
100.9514 USDC - $100.95
++i is more gas efficient than i++ in loops forwarding.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L95
Code Review
It is recommend to use unchecked{++i} and change i declaration to uint256.
When a variable is declared solidity assigns the default value. In case the contract assigns the value again, it costs extra gas.
Example: uint x = 0 costs more gas than uint x without having any different functionality.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L95
Code Review
uint x = 0 costs more gas than uint x without having any different functionality.
Using newer compiler versions and the optimizer gives gas optimizations and additional safety checks are available for free.
All Contracts
Solidity 0.8.10 has a useful change which reduced gas costs of external calls which expect a return value: https://blog.soliditylang.org/2021/11/09/solidity-0.8.10-release-announcement/
Code Generator: Skip existence check for external contract if return data is expected. In this case, the ABI decoder will revert if the contract does not exist
All Contracts
None
Consider to upgrade pragma to at least 0.8.10.
Strict inequalities add a check of non equality which costs around 3 gas.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L95
Code Review
Use >= or <= instead of > and < when possible.
Since _amount can be 0. Checking if (_amount != 0) before the transfer can potentially save an external call and the unnecessary gas cost of a 0 token transfer.
https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L134 https://github.com/fei-protocol/xTRIBE/blob/989e47d176facbb0c38bc1e1ca58672f179159e1/src/xTRIBE.sol#L149
All Contracts
None
Consider checking amount != 0.
A division/multiplication by any number x being a power of 2 can be calculated by shifting log2(x) to the right/left.
While the DIV opcode uses 5 gas, the SHR opcode only uses 3 gas. Furthermore, Solidity's division operation also includes a division-by-0 prevention which is bypassed using shifting.
None
A division/multiplication by any number x being a power of 2 can be calculated by shifting log2(x) to the right/left.