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: 10/77
Findings: 2
Award: $1,894.40
π Selected for report: 0
π Solo Findings: 0
π Selected for report: xiaoming90
Also found by: GreyArt, berndartmueller, jonah1005, kenzo, minhquanym
1806.2399 USDC - $1,806.24
https://github.com/code-423n4/2022-06-notional-coop/blob/main/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L85 https://github.com/code-423n4/2022-06-notional-coop/blob/main/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L21 https://github.com/code-423n4/2022-06-notional-coop/blob/main/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L23 https://github.com/code-423n4/2022-06-notional-coop/blob/main/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L71
EIP4626 states that maxWithdraw
, convertToAssets
, convertToShares
, previewRedeem
and previewWithdraw
must not revert (unless due to large input, or due to a reason that will make deposit
/redeem
revert).
However, wfCash4626's implementation of those ends up calling _getMaturedValue
if the asset has matured.
This call will revert if the account has not been settled yet.
Incorrect implementation of EIP4626. Protocols that will build upon wfCash4626 may revert unexpectedly.
All these functions end up calling _getMaturedValue
via totalAssets
.
getMaturedValue
will revert if the account has not been settled yet:
// We cannot settle an account in a view method, so this may fail if the account has not been settled // after maturity. This can be done by anyone so it should not be an issue (int256 cashBalance, /* */, /* */) = NotionalV2.getAccountBalance(currencyId, address(this)); int256 underlyingExternal = NotionalV2.convertCashBalanceToExternal(currencyId, cashBalance, true); require(underlyingExternal > 0, "Must Settle");
Therefore, the functions don't implement EIP4626 correctly, and integration with wfCash might fail.
Create a view method that will simulate the settlement of an account and get the cash balance of the account's currencyId. Then use that cashBalance to calculate the underlyingExternal.
#0 - berndartmueller
2022-06-15T09:21:36Z
Duplicate of #215 - [L-09] wfCashERC4626 contract does not conform to EIP4626
(Disclaimer: That's my QA report)
I explicitly did not submit this finding as medium severity as I thought it does not qualify:
2 β Med: Assets not at direct risk, but the function of the protocol or its availability could be impacted, or leak value with a hypothetical attack path with stated assumptions, but external requirements.
#1 - jeffywu
2022-06-15T13:06:00Z
Agree that this can be a QA report, there is no way for this to result in loss of funds.
#2 - gzeoneth
2022-06-26T14:51:36Z
This might be controversial but I consider this as a duplicate of #155. EIP4626 is aimed to create a consistent and robust implementation patterns for Tokenized Vaults. A slight deviation from 4626 would broke composability and potentially lead to loss of fund (POC in #88 can be an example). It is counterproductive to implement EIP4626 but does not conform to it fully.
π 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
88.1603 USDC - $88.16
withdraw
will revert if the account has not been settled yet.
This is just due to the implementation and can be avoided by, well, settling the account.
withdraw
reverts unnecessarily. Protocols and users which will use wfCash4626 will have to discover this and settle by themselves.
withdraw
calls previewWithdraw
, which ends up calling _getMaturedValue
, which will revert if the account is not settled yet.
Add to withdraw
:
NotionalV2.settleAccount(address(this));
This will ensure that the account is settled and withdraw
will not revert.
#0 - jeffywu
2022-06-15T13:04:05Z
Agree, good find.
There is no loss of funds or functionality here so I would suggest that this is reduced to a QA suggestion, but a good one.
#1 - gzeoneth
2022-06-26T15:46:14Z
As warden's QA report.