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: 18/39
Findings: 4
Award: $804.59
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: Ruhum
Also found by: TomFrenchBlockchain
700.6157 USDT - $700.62
Ruhum
The owner of the token for which the LaunchEvent was created, has the ability to DOS attack the event. They can prevent the LaunchEvent from creating a JoePair which in turn limits the access to the following two functions: withdrawLiquidity()
& withdrawIncentives()
. Thus, stopping anybody from withdrawing their LP tokens.
The owner of the RocketJoe platform has the ability to enable the emergency withdrawal allowing the depositors to take back their AVAX. But, they lose their burned rJOE tokens and the gas fees.
The dev team might use this attack vector if they think the price of their token is too low. In that case, they can DOS attack the LaunchEvent. If the RocketJoe owner enables the emergency withdrawal, the dev team is able to take back their initial deposit. Thus, they don't lose anything but their reputation.
When createPair()
is called, the function checks whether a pair already exists. If it does, the transaction is reverted: https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L382-L389
Anybody is able to create a new JoePair using the existing TraderJoe contracts. If someone owns both AVAX and the LaunchEvent token, they are able to create a new pair and deposit a small amount of liquidity. Thus, the totalSupply
will be > 0
. Meaning, at that point, the call to createPair()
fails. Per design, the LaunchEvent will be used to issue a token to the public market. So only the dev team and its trusted parties have access to the necessary tokens to create a pair and provide liquidity.
https://github.com/traderjoe-xyz/joe-core/blob/main/contracts/traderjoe/JoeFactory.sol#L30
https://github.com/traderjoe-xyz/joe-core/blob/main/contracts/traderjoe/JoePair.sol#L133
Since createPair()
can't be executed the pair
state variable is never initialized: https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L422
Thus, the following two functions are not reachable any more: https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L439
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L469
If the emergency withdrawal is enabled, the token issuer can take back their deposit: https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L510-L516
none
If a LaunchEvent for a token has started, only the LaunchEvent contract should be able to create a JoePair for that token. But, this change has to be made to the contracts that are not in the scope of this audit. I don't think there's a possibility to fix this issue within the RocketJoe contracts.
Ruhum
Since you're working with arbitrary ERC20 tokens it's a best practice to use SafeERC20. Not every ERC20 token reverts if a function call fails. It might also just return false. SafeERC20 covers those cases.
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L458
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L490
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L514
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L538
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/RocketJoeFactory.sol#L133
none
Either use SafeERC20 or check the return values
#0 - cryptofish7
2022-01-31T00:50:57Z
Duplicate of #232
#1 - dmvt
2022-02-22T19:26:04Z
duplicate of #198
Ruhum
The initialize()
function of RocketJoeToken
can be front-run since there's no access control for the function. There shouldn't be any assets at risk tho.
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/RocketJoeToken.sol#L25
none
add access control
#0 - cryptofish7
2022-01-30T21:37:01Z
Duplicate of #8
Ruhum
Using != 0
is cheaper than > 0
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L314
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L338
and many more. Simply search for > 0
in the codebase to find the rest
#0 - cryptofish7
2022-01-31T11:53:26Z
Duplicate of #240
Ruhum
Using immutable variables is way cheaper.
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/RocketJoeFactory.sol#L21
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/RocketJoeFactory.sol#L25
Those two aren't reset anywhere. They can be turned into immutable state variables.
#0 - cryptofish7
2022-01-31T00:27:34Z
Duplicate of #284
🌟 Selected for report: WatchPug
Also found by: Ruhum, TomFrenchBlockchain, robee
Ruhum
SLOAD and SSTORE uses a lot of gas. Caching the values in memory and working with that is way cheaper
Multiple reads of the same state variables in this function: https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L377
There's a lot to optimize there.
#0 - cryptofish7
2022-01-31T14:23:33Z
Duplicate of #234
🌟 Selected for report: WatchPug
Also found by: Ruhum, TomFrenchBlockchain, WatchPug, byterocket, hyh, kirk-baird
Ruhum
The result of external function calls should be cached to reduce gas costs
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/RocketJoeFactory.sol#L123
https://github.com/code-423n4/2022-01-trader-joe/blob/main/contracts/LaunchEvent.sol#L383
The call to getPair
can be cached.
none
address pair = IJoeFactory(factory).getPair(_token, wavax); require( pair == address(0) || IJoePair(pair).totalSupply() ==0, "RJFactory: liquid pair already exists" );
#0 - cryptofish7
2022-01-31T00:46:46Z
Duplicate #236