QA Report #174
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
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
Table of Contents:
initialize()
functionsabi.encodePacked()
should not be used with dynamic types when passing the result to a hash function such askeccak256()
[L-01] Unsafe casting may overflow
SafeMath and Solidity 0.8.* handles overflows for basic math operations but not for casting.
Consider using OpenZeppelin's SafeCast library to prevent unexpected overflows when casting from uint256 here:
[L-02] Add constructor initializers
As per OpenZeppelin’s (OZ) recommendation, “The guidelines are now to make it impossible for anyone to run
initialize
on an implementation contract, by adding an empty constructor with theinitializer
modifier. So the implementation contract gets initialized automatically upon deployment.”Note that this behaviour is also incorporated the OZ Wizard since the UUPS vulnerability discovery: “Additionally, we modified the code generated by the Wizard 19 to include a constructor that automatically initializes the implementation when deployed.”
Furthermore, this thwarts any attempts to frontrun the initialization tx of these contracts:
[L-03] Deprecated safeApprove() function
Using this deprecated function can lead to unintended reverts and potentially the locking of funds. A deeper discussion on the deprecation of this function is in OZ issue #2219 (OpenZeppelin/openzeppelin-contracts#2219). The OpenZeppelin ERC20 safeApprove() function has been deprecated, as seen in the comments of the OpenZeppelin code.
As recommended by the OpenZeppelin comment, I suggest replacing safeApprove() with safeIncreaseAllowance() or safeDecreaseAllowance() instead:
[L-04] Deprecated approve() function
While
safeApprove()
in itself is deprecated, it is still better thanapprove
which is subject to a known front-running attack and failing for certain token implementations that do not return a boolean value. Consider usingsafeApprove
instead (or better:safeIncreaseAllowance()
/safeDecreaseAllowance()
):[L-05] Lack of event emission after critical
initialize()
functionsTo record the init parameters for off-chain monitoring and transparency reasons, please consider emitting an event after the
initialize()
functions:[L-06] No account existence check for low-level call
Low-level calls call/delegatecall/staticcall return true even if the account called is non-existent (per EVM design). Account existence must be checked prior to calling.
Consider checking for account-existence before the
call()
to make this safely extendable to user-controlled address contexts in future (or, at least, prevent theaddress(0)
entry):[L-07]
abi.encodePacked()
should not be used with dynamic types when passing the result to a hash function such askeccak256()
Use
abi.encode()
instead which will pad items to 32 bytes, which will prevent hash collisions (e.g.abi.encodePacked(0x123,0x456)
=>0x123456
=>abi.encodePacked(0x1,0x23456)
, butabi.encode(0x123,0x456)
=>0x0...1230...456
). If there is only one argument toabi.encodePacked()
it can often be cast tobytes()
orbytes32()
instead.[N-01] Unused named returns
While not consuming more gas with the Optimizer enabled: using both named returns and a return statement isn't necessary. Removing one of those can improve code clarity:
The text was updated successfully, but these errors were encountered: