The StrategyArb, StrategyMainnet, and StrategyOp contracts inherit from BaseStrategy and are designed to integrate with the TokenizedStrategy to create fully ERC4626-compliant vaults. However, the strategies fail to implement the availableWithdrawLimit and availableDepositLimit correctly to have EIP4626-compliant maxMint, maxDeposit, maxWithdraw and maxRedeem. leading to incompatibility with EIP4626 standards. This issue can result in unexpected Denial-of-Service (DoS) for other users and contracts.
According to the code comment and documentation, the entire vault should be fully ERC4626 compliant.
A Strategy contract can become a fully ERC-4626 compliant vault by inheriting the
BaseStrategycontract, that uses the fallback function to delegateCall the previously deployed version ofTokenizedStrategy.
A strategist only needs to override a few simple functions that are focused entirely on the strategy specific needs to easily and cheaply deploy their own permissionless 4626 compliant vault.
However, the strategy fails to correctly implement vault-related limits, for example availableWithdrawLimit, leading to incompatibility with EIP4626 standards.
TL&DR: The availableWithdrawLimit function only considers available funds (asset.balanceOf(address(this)) and unexchanged balances from the transmuter). It fails to account for conditions where the transmuter.withdraw function becomes unusable due to the strategy being unwhitelisted or the transmuter being disabled.
Detailed explanation:
Let's take the maxWithdraw function for example(this is also the case for maxDeposit, maxMint and maxRedeem).
In EIP4626, to be compliant.
the
maxWithdrawMUST return the maximum amount of assets that could be transferred fromownerthroughwithdrawand not cause a revert, which MUST NOT be higher than the actual maximum that would be accepted
Let's take a dive into the maxWithdraw function.
In TokenizedStrategy, it's calling _maxWithdraw which will call IBaseStrategy(address(this)).availableWithdrawLimit.
For example, in StrategyArb, the availableWithdrawLimit is defined as below:
However, when we look at the vault's _withdraw function, when the active assets are not enough, the freeFunds is called, which will eventually call transmuter.withdraw.
But in the Transmuter::withdraw, the function requires the strategy to be whitelisted, as defined in the Whitelist contract. If the strategy is unwhitelisted, withdrawals fail, leading to a revert.
There are several cases when isWhitelisted return false according to whitelist.sol: either the transmuter is disabled or the strategy is later unwhitelisted by the admin.
However, this case is not considered by the availableWithdrawLimit: when isWhitelisted returns false, the vault can not withdraw ALETH from the transmuter, thus the entire transaction will revert.
Per EIP4626, the maxWithdraw function must return the maximum amount of assets that can be withdrawn without causing a revert. The current implementation does not meet this requirement, as it fails to consider cases where transmuter.withdraw is inaccessible. This violates the EIP4626 standard as we said before. When others are interacting with the TokenizedStrategy, they could suffer from unexpected DoS.
The implementation of Strategy violates the EIP4626 standard, and is not fully compatible as claimed. Users interacting with the strategy may experience unexpected DoS when withdrawal attempts fail due to unconsidered scenarios.
Manual Review, EIP4626 Documentation
It is recommended to take these cases into account for the strategy to be fully compatible.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.