Open code423n4 opened 2 years ago
Duplicate #143
Judging this and all duplicate regarding EIP4626 implementation as High Risk.
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 https://github.com/code-423n4/2022-06-notional-coop-findings/issues/88 can be an example). It is counterproductive to implement EIP4626 but does not conform to it fully. Especially it does seems that most of the time deposit
would be successful but not withdraw
, making it even more dangerous when an immutable consumer application mistakenly used the wfcash contract.
Lines of code
https://github.com/code-423n4/2022-06-notional-coop/blob/6f8c325f604e2576e2fe257b6b57892ca181509a/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L52 https://github.com/code-423n4/2022-06-notional-coop/blob/6f8c325f604e2576e2fe257b6b57892ca181509a/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L134
Vulnerability details
Background
Per EIP 4626's Security Considerations (https://eips.ethereum.org/EIPS/eip-4626)
Thus, the result of the
previewMint
andpreviewWithdraw
should be rounded up.Proof-of-Concept
The current implementation of
convertToShares
function will round down the number of shares returned due to how solidity handles Integer Division. ERC4626 expects the returned value ofconvertToShares
to be rounded down. Thus, this function behaves as expected.https://github.com/code-423n4/2022-06-notional-coop/blob/6f8c325f604e2576e2fe257b6b57892ca181509a/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L52
ERC 4626 expects the result returned from
previewWithdraw
function to be rounded up. However, within thepreviewWithdraw
function, it calls theconvertToShares
function. Recall earlier that theconvertToShares
function returned a rounded down value, thuspreviewWithdraw
will return a rounded down value instead of round up value. Thus, this function does not behave as expected.https://github.com/code-423n4/2022-06-notional-coop/blob/6f8c325f604e2576e2fe257b6b57892ca181509a/notional-wrapped-fcash/contracts/wfCashERC4626.sol#L134
previewWithdraw
andpreviewMint
functions rely onNotionalV2.getfCashBorrowFromPrincipal
andNotionalV2.getDepositFromfCashLend
functions. Due to the nature of time-boxed contest, I was unable to verify ifNotionalV2.getfCashBorrowFromPrincipal
andNotionalV2.getDepositFromfCashLend
functions return a rounded down or up value. If a rounded down value is returned from these functions,previewWithdraw
andpreviewMint
functions would not behave as expected.Impact
Other protocols that integrate with Notional's fCash wrapper might wrongly assume that the functions handle rounding as per ERC4626 expectation. Thus, it might cause some intergration problem in the future that can lead to wide range of issues for both parties.
Recommended Mitigation Steps
Ensure that the rounding of vault's functions behave as expected. Following are the expected rounding direction for each vault function:
previewMint(uint256 shares) - Round Up ⬆
previewWithdraw(uint256 assets) - Round Up ⬆
previewRedeem(uint256 shares) - Round Down ⬇
previewDeposit(uint256 assets) - Round Down ⬇
convertToAssets(uint256 shares) - Round Down ⬇
convertToShares(uint256 assets) - Round Down ⬇
previewMint
returns the amount of assets that would be deposited to mint specific amount of shares. Thus, the amount of assets must be rounded up, so that the vault won't be shortchanged.previewWithdraw
returns the amount of shares that would be burned to withdraw specific amount of asset. Thus, the amount of shares must to be rounded up, so that the vault won't be shortchanged.Following is the OpenZeppelin's vault implementation for rounding reference:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20TokenizedVault.sol
Alternatively, if such alignment of rounding could not be achieved due to technical limitation, at the minimum, document this limitation in the comment so that the developer performing the integration is aware of this.