Platform: Code4rena
Start Date: 25/01/2022
Pot Size: $50,000 USDT
Total HM: 17
Participants: 39
Period: 3 days
Judge: LSDan
Total Solo HM: 9
Id: 79
League: ETH
Rank: 8/39
Findings: 2
Award: $1,801.02
🌟 Selected for report: 6
🚀 Solo Findings: 0
🌟 Selected for report: robee
518.9746 USDT - $518.97
robee
Not verified address arguments of external/public functions is a low risk issue. It's less severe for onlyOwner methods but for any other method it's crucial since the default address is 0.
Argument tokenA of IJoeFactory.sol.getPair is not verified to be != 0 Argument tokenB of IJoeFactory.sol.getPair is not verified to be != 0 Argument tokenA of IJoeFactory.sol.createPair is not verified to be != 0 Argument tokenB of IJoeFactory.sol.createPair is not verified to be != 0 Argument None of IJoeFactory.sol.setFeeTo is not verified to be != 0
robee
Most contracts use an init pattern (instead of a constructor) to initialize contract parameters. Unless these are enforced to be atomic with contact deployment via deployment script or factory contracts, they are susceptible to front-running race conditions where an attacker/griefer can front-run (cannot access control because admin roles are not initialized) to initially with their own (malicious) parameters upon detecting (if an event is emitted) which the contract deployer has to redeploy wasting gas and risking other transactions from interacting with the attacker-initialized contract.
The init functions do not have an explicit event emission which makes monitoring such scenarios harder. All of them have re-init checks; while many are explicit some (those in auction contracts) have implicit reinit checks in initAccessControls() which is better if converted to an explicit check in the main init function itself. (details credit to: https://github.com/code-423n4/2021-09-sushimiso-findings/issues/64) The vulnerable initialization functions in the codebase are:
RocketJoeStaking.sol, initialize, 57
#0 - cryptofish7
2022-02-11T00:12:00Z
Duplicate of #8
🌟 Selected for report: cccz
Also found by: csanuragjain, defsec, robee
robee
Some tokens (like USDT) do not work when changing the allowance from an existing non-zero allowance value.They must first be approved by zero and then the actual allowance must be approved. You don't first approve 0 in the following places in the codebase:
approve without approving 0 first LaunchEvent.sol, 407, token.approve(address(router), tokenAllocated);
#0 - cryptofish7
2022-02-11T00:08:52Z
Duplicate of #22
🌟 Selected for report: robee
518.9746 USDT - $518.97
robee
To improve algorithm precision instead using division in comparison use multiplication in the following scenario:
Instead a < b / c use a * c < b.
In all of the big and trusted contracts this rule is maintained (for example look at AAVE codebase).
LaunchEvent.sol, 395, if ( floorPrice > (wavaxReserve * 10**token.decimals()) / tokenAllocated ) {
🌟 Selected for report: WatchPug
Also found by: Czar102, Dravee, Jujic, Meta0xNull, byterocket, defsec, p4st13r4, pauliax, robee, sirhashalot
robee
The following require messages are of length more than 32 and we think are short enough to short them into exactly 32 characters such that it will be placed in one slot of memory and the require function will cost less gas. The list:
Solidity file: LaunchEvent.sol, In line 622, Require message length to shorten: 33, The message: LaunchEvent: avax transfer failed Solidity file: RocketJoeToken.sol, In line 26, Require message length to shorten: 35, The message: RocketJoeToken: already initialized Solidity file: RocketJoeFactory.sol, In line 116, Require message length to shorten: 35, The message: RJFactory: token can't be 0 address Solidity file: RocketJoeFactory.sol, In line 115, Require message length to shorten: 36, The message: RJFactory: issuer can't be 0 address
#0 - cryptofish7
2022-02-10T23:57:25Z
Duplicate of #242
robee
Using != 0 is slightly cheaper than > 0. see https://github.com/code-423n4/2021-12-maple-findings/issues/75 for similar issue. LaunchEvent.sol, 355: change '_amount > 0' to '_amount != 0' LaunchEvent.sol, 358: change 'balance > 0' to 'balance != 0' LaunchEvent.sol, 390: change 'wavaxReserve > 0' to 'wavaxReserve != 0' LaunchEvent.sol, 390: change 'balance > 0' to 'balance != 0' LaunchEvent.sol, 455: change 'tokenReserve > 0' to 'tokenReserve != 0' LaunchEvent.sol, 498: change 'balance > 0' to 'balance != 0' RocketJoeFactory.sol, 119: change '_tokenAmount > 0' to '_tokenAmount != 0'
#0 - cryptofish7
2022-02-11T00:06:46Z
Duplicate of #240
🌟 Selected for report: sirhashalot
Also found by: Dravee, Rhynorater, robee
robee
The following functions could be set external to save gas and improve code quality. External call cost is less expensive than of public functions.
LaunchEvent.sol, withdrawAVAX ERC20Token6decimals.sol, decimals RocketJoeStaking.sol, initialize
#0 - cryptofish7
2022-02-11T00:03:13Z
Duplicate of #262
🌟 Selected for report: robee
518.9746 USDT - $518.97
robee
You use safeApprove of openZeppelin although it's deprecated. (see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/566a774222707e424896c0c390a84dc3c13bdcb2/contracts/token/ERC20/utils/SafeERC20.sol#L38) You should change it to increase/decrease Allowance as OpenZeppilin says. This appears in the following locations in the code base:
Deprecated safeApprove in LaunchEvent.sol line 406: WAVAX.approve(address(router), wavaxReserve); Deprecated safeApprove in LaunchEvent.sol line 407: token.approve(address(router), tokenAllocated);
🌟 Selected for report: WatchPug
Also found by: Ruhum, TomFrenchBlockchain, robee
robee
Reading a storage variable is gas costly (SLOAD). In cases of multiple read of a storage variable in the same scope, caching the first read (i.e saving as a local variable) can save gas and decrease the overall gas uses. The following is a list of functions and the storage variables that you read twice:
LaunchEvent.sol: issuer is read twice in depositAVAX LaunchEvent.sol: auctionStart is read twice in currentPhase LaunchEvent.sol: wavaxReserve is read twice in createPair
#0 - cryptofish7
2022-02-11T00:00:42Z
Duplicate of #234
🌟 Selected for report: robee
39.7792 USDT - $39.78
robee
The following functions could skip other steps if the amount is 0. (A similar issue: https://github.com/code-423n4/2021-10-badgerdao-findings/issues/82)
LaunchEvent.sol, receive LaunchEvent.sol, initialize LaunchEvent.sol, currentPhase LaunchEvent.sol, depositAVAX LaunchEvent.sol, createPair LaunchEvent.sol, withdrawLiquidity LaunchEvent.sol, withdrawIncentives
🌟 Selected for report: robee
39.7792 USDT - $39.78
robee
You calculate the power of 10 every time you use it instead of caching it once as a constant variable and using it instead. Fix the following code lines:
LaunchEvent.sol, 395 : You should cache the used power of 10 as constant state variable since it's used several times (2): floorPrice > (wavaxReserve * 10**token.decimals()) / tokenAllocated LaunchEvent.sol, 397 : You should cache the used power of 10 as constant state variable since it's used several times (2): tokenAllocated = (wavaxReserve * 10**token.decimals()) / floorPrice;
🌟 Selected for report: robee
39.7792 USDT - $39.78
robee
The following functions could be set private to save gas and improve code quality:
RocketJoeToken.sol, _beforeTokenTransfer
This is the only one so it's important for quality.