Platform: Code4rena
Start Date: 07/06/2022
Pot Size: $75,000 USDC
Total HM: 11
Participants: 77
Period: 7 days
Judge: gzeon
Total Solo HM: 7
Id: 124
League: ETH
Rank: 15/77
Findings: 1
Award: $261.90
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: berndartmueller
Also found by: 0x1f8b, 0x29A, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkatana, 0xmint, Bronicle, Chom, Cityscape, Deivitto, Funen, GimelSec, GreyArt, IllIllI, JC, Lambda, Meera, Nethermind, Picodes, PierrickGT, Ruhum, Sm4rty, Tadashi, TerrierLover, TomJ, Trumpero, Waze, _Adam, antonttc, ayeslick, c3phas, catchup, cccz, cloudjunky, cryptphi, csanuragjain, delfin454000, dipp, ellahi, fatherOfBlocks, hake, hansfriese, hyh, joestakey, jonah1005, kenzo, minhquanym, oyc_109, sach1r0, saian, simon135, slywaters, sorrynotsorry, sseefried, unforgiven, xiaoming90, z3s, zzzitron
261.8976 USDC - $261.90
Floating Pragma used in wfCashERC4626.sol
. Contracts should be deployed with the same compiler version and flags that they have been tested with thoroughly. Locking the pragma (i.e. by not using ^) helps to ensure that contracts do not accidentally get deployed using, for example, an outdated compiler version that might introduce bugs that affect the contract system negatively.
Reference
The scoped contracts have different solidity compiler ranges (0.6.10 - 0.8.11) referenced. This leads to potential security flaws between deployed contracts depending on the compiler version chosen for any particular file. It also greatly increases the cost of maintenance as different compiler versions have different semantics and behavior. Current Solidity version available is 0.8.14
OpenZeppelin's safeTransfer
and safeTransferFrom
functions use functionCall
of Address.sol which is a low level call.
However, it's stated that the target must be a contract and code existence should be checked prior using. Reference
It's advised to check code existence prior calling safeTransfer or safeTransferFrom as below;
In wfCashLogic.sol,
84: token.safeTransferFrom(msg.sender, address(this), depositAmountExternal); 311: token.safeTransfer(receiver, tokensTransferred);
No address(0)
or Zero value check at the constructors of:
In WrappedfCashFactory.sol;
constructor(address _beacon) { BEACON = _beacon; }
In wfCashBase.sol;
constructor(INotionalV2 _notional, WETH9 _weth) initializer { NotionalV2 = _notional; WETH = _weth; }
In wfCashERC4626.sol;
constructor(INotionalV2 _notional, WETH9 _weth) wfCashLogic(_notional, _weth) {}
In wfCashLogic.sol;
constructor(INotionalV2 _notional, WETH9 _weth) wfCashBase(_notional, _weth) {}
In NotionalTradeModule.sol;
constructor( IController _controller, IWrappedfCashFactory _wrappedfCashFactory, IERC20 _weth ) public ModuleBase(_controller) { wrappedfCashFactory = _wrappedfCashFactory; weth = _weth; }
WrappedfCashFactory uses Solidity's Create2 function to deploy the wrappers. In case of a deployment failure it will revert as zero address and will throw an error. However, a good practice is to compare the _computedWrapper
address with the deployed wrapper
same as in Solidity's official page here
contract C { function createDSalted(bytes32 salt, uint arg) public { // This complicated expression just tells you how the address // can be pre-computed. It is just there for illustration. // You actually only need ``new D{salt: salt}(arg)``. address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked( bytes1(0xff), address(this), salt, keccak256(abi.encodePacked( type(D).creationCode, abi.encode(arg) )) ))))); D d = new D{salt: salt}(arg); require(address(d) == predictedAddress); } }
Programming patterns such as looping over arrays of unknown size may lead to DoS when the gas cost of execution exceeds the block gas limit. Reference Instances in NotionalTradeModule.sol;
Calls to external contracts inside a loop are dangerous (especially if the loop index can be user-controlled) because it could lead to DoS if one of the calls reverts or execution runs out of gas. Avoid calls within loops, check that loop index cannot be user-controlled or is bounded.Reference
Instances in NotionalTradeModule.sol;
EIP4626 requires deposit
and withdraw
functions having event with indexed parameters for caller
, owner
and receiver
. However, this pattern is not followed.
Reference
require
statements don't throw error messageSome require statements in the scoped contracts don't throw error. In case of any error pops up, it will not be possible to know the error source. The list is as below;
The scoped contracts are missing proper NatSpec comments such as @notice @dev @param on many places.It is recommended that Solidity contracts are fully annotated using NatSpec for all public interfaces (everything in the ABI) Reference
#0 - jeffywu
2022-06-16T17:50:15Z
A couple invalid points on this report
L5: OZ create2 reverts on failed deployment already https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Create2.sol#L42
L3 checking for contract existence would increase gas costs. Tokens are only white listed if they actually exist.