Platform: Code4rena
Start Date: 04/02/2022
Pot Size: $30,000 USDC
Total HM: 3
Participants: 37
Period: 3 days
Judge: leastwood
Id: 84
League: ETH
Rank: 20/37
Findings: 2
Award: $431.15
🌟 Selected for report: 0
🚀 Solo Findings: 0
366.7457 USDC - $366.75
buy
can charge the user extraWhen a user uses buy
function, it pays as much as _tokenInAmount
. This approach charges users with extra rounding error. If this rounding error is really small with planned parameter, this is a non-critical problem. If it can be more than extra gas cost of calculating exact, I recommend to do so.
setSaleRecipient
posses extra riskIn case the access of owner address gets in control of an hacker, this creates a possibility of theft from buyers. Without setSaleRecipient
, the hacker can directly steal funds and also even if output tokens are stolen by using sweep, it will be easy to keep track of it. For users security, I recommend removing this function.
tokenOutPrice
tokenOutPrice
can be set to maximum value possible. This can be used to make users pay for nothing. In case the owner is not a timelock contract, it is possible to change the price and scam users buying tokens. I recommend having a reasonable maximum cap for tokenOutPrice
to provide better security for users. This will also only cost gas for owners, which is likely not important.
buy
function does not have any functionality for slippage protection. Since setTokenOutPrice
can change the price, it can result in buy orders for an unexpected rate.
Furthermore, if there is enough allowance and the owners might be able to change the price to swap the funds for almost no token.
For users security and best practice, I recommend adding a new input variable to function buy
, which can be used to specify the minimum output. Most popular contracts use this design pattern to avoid such problems.
64.4024 USDC - $64.40
tokenOut.decimals()
Save gas in getAmountOut
and also eliminate the possibility of price manipulations by changing decimals.
totalTokenIn + _tokenInAmount
is calculated twiceL155-158:
require( totalTokenIn + _tokenInAmount <= tokenInLimit, //@audit gas "total amount exceeded" );
L189:
totalTokenIn += _tokenInAmount;
If the addition at L189 is performed before this require
statement, there is no need to add _tokenInAmount
anymore.
saleStart
and guestlist
in buy
Both variables are loaded twice. Therefore caching them can save gas.
sweep
can be optimized to save gasSince amountLeftToBeClaimed
is only used once, it is not needed to use this variable.
if (_token == address(tokenOut)) { uint256 amountLeftToBeClaimed = totalTokenOutBought - totalTokenOutClaimed; amount -= amountLeftToBeClaimed; }
can be replaced with
if (_token == address(tokenOut)) { amount -= totalTokenOutBought - totalTokenOutClaimed; }