QA Report #106
Labels
bug
Something isn't working
QA (Quality Assurance)
Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax
QA Report
Table of Contents:
File: TokenSaleUpgradeable.sol (contract TokenSaleUpgradeable)
Contract declaration
While only a comment, there an open TODO which reminds the sponsor to write better revert strings at line 13:
As said in the gas report: revert strings are more expensive than custom errors, therefore you should use them instead (they exist since Solidity 0.8.4). If you decide to keep revert strings, make sure their length don't exceed 32 characters.
Also, don't forget to delete the comment before deploying, of course.
Storage variables
Related data should be grouped in a struct: For maps that use the same key value: having separate fields is error prone (like in case of deletion or future new fields).
In this contract, those 3 maps use the same key:
Proof:
I'd suggest these 3 related data get grouped in a struct, let's name it
AccountInfo
:And it would be used as a state variable in this manner:
Even if you could then delete all related fields with a simple
delete accountInfo[address]
, I understand thatboughtAmounts
needs to be persisted. Still, for maintainability and consistency, grouping these related data together is a good practice.Furthermore, the tight-packing of structs (2 storage slots as uint256 is 32 bytes, bool is 1 byte and uint8 is 1 byte) would save gas.
function initialize()
The
onlyOwner
modifier is missing (the defaultowner
of a contract is the one who creates it). This missing access controls allows any user to initialize the contract. By front-running, the incorrect parameters may be supplied, leaving the contract needing to be redeployed (there are no setters for_tokenOut
and_tokenIn
, andinitialize
can only be called once because of theinitializer
modifier).I suggest adding the missing
onlyOwner
modifieraddress(0)
check on_tokenOut
address(0)
check on_tokenIn
As these addresses don't have setters, an error would result in the contract needing to be redeployed.
0
check on_tokenInLimit
While this can be corrected by calling
setTokenInLimit
:_tokenInLimit
should be 0 checked as this would instantly end sales (Line 243). The 0 check should also be added insetTokenInLimit
as this would make theowner
able to instant-terminate the sales, which is a permission that requires a lot of trust from users. Furthermore, adding a timelock behindsetTokenInLimit
is a Medium level issue that you should consider."TokenSale: start date may not be in the past"
The first thing someone can understand is that the error is due to the fact that the start date isn't in the past. But the revert string's "may" isn't the probability one, but the permission one, which actually means the opposite. It would be clearer to write:
"TokenSale: start date cannot be in the past"
or"TokenSale: start date shouldn't be in the past"
. This correction can also be applied in thesetSaleStart()
function (line 274)._saleDuration
should have a lower boundaryWhile
_saleDuration
is indeed 0 checked, this require statement can easily fail almost instantly:Consider adding a lower boundary to
_saleDuration
ininitialize()
andsetSaleDuration()
.function claim()
tokenOut
bought"https://github.com/code-423n4/2022-02-badger-citadel/blob/main/contracts/TokenSaleUpgradeable.sol#L188-L190
functions setTokenOutPrice()
tokenOutPrice
should have an upper-boundaryWhile it may seem unlikely to set it that way,
tokenOutPrice
can take the max value of uint256 (line 306):This would make the "amount received when exchanging
tokenIn
" drop to a negligible amount:I believe an upper-boundary is needed, this would also be good for users' trust.
function setSaleRecipient()
function setGuestlist()
The text was updated successfully, but these errors were encountered: