Open code423n4 opened 2 years ago
Disagree as timestamp in seconds is well below that size and will be for the next few thousand years
Because the code doesn't seem upgradeable but uses initializers, I agree with adding the initializer in the constructor
Given the specific uses shown by the warden, I disagree that the code should be changed as all the instances can be proven to go from 0 to X allowance
Idem + agree on using safe
version
Disagree with this being low, per definition an event is an informational component
Can't remember if this was added in 0.8, will mark it as valid for now
This is a really interesting finding, personally believe that in the context of this system it will be fine
Agree
Pretty good report, well formatted, a few findings are very common and would benefit by being shorter but there were also a couple interesting ones
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: