//SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; interface IMintable { function mint(address recipient, uint256 amount) external; function burn(address recipient, uint256 amount) external; } contract TestERC4626 is ERC4626 { bool internal _broken; uint256 public overrideMaxDeposit; uint256 public overrideMaxMint; uint256 public overrideMaxWithdraw; uint256 public overrideMaxRedeem; uint256 public constant OVERRIDE_UNSET = type(uint256).max - 99; enum OverrideOption { deposit, mint, withdraw, redeem } error VaultIsBroken(bytes4 selector); modifier isBroken() { require(!_broken, VaultIsBroken(bytes4(msg.data[0:4]))); _; } constructor(string memory name_, string memory symbol_, IERC20Metadata asset_) ERC20(name_, symbol_) ERC4626(asset_) { overrideMaxRedeem = overrideMaxWithdraw = overrideMaxMint = overrideMaxDeposit = OVERRIDE_UNSET; } function _deposit( address caller, address receiver, uint256 assets, uint256 shares ) internal virtual override isBroken { super._deposit(caller, receiver, assets, shares); } function _withdraw( address caller, address receiver, address owner, uint256 assets, uint256 shares ) internal virtual override isBroken { super._withdraw(caller, receiver, owner, assets, shares); } /* * @dev Adds or remove assets not generated by deposits/withdraw - For testing discrete earnings/losses */ function discreteEarning(int256 assets) external { if (assets > 0) { IMintable(asset()).mint(address(this), uint256(assets)); } else { IMintable(asset()).burn(address(this), uint256(-assets)); } } function setBroken(bool broken_) external { _broken = broken_; } function broken() external view returns (bool) { return _broken; } function maxDeposit(address owner) public view override returns (uint256) { return overrideMaxDeposit == OVERRIDE_UNSET ? super.maxDeposit(owner) : overrideMaxDeposit; } function maxMint(address owner) public view override returns (uint256) { return overrideMaxMint == OVERRIDE_UNSET ? super.maxMint(owner) : overrideMaxMint; } function maxWithdraw(address owner) public view override returns (uint256) { return overrideMaxWithdraw == OVERRIDE_UNSET ? super.maxWithdraw(owner) : overrideMaxWithdraw; } function maxRedeem(address owner) public view override returns (uint256) { return overrideMaxRedeem == OVERRIDE_UNSET ? super.maxRedeem(owner) : overrideMaxRedeem; } function setOverride(OverrideOption option, uint256 newValue) external { if (option == OverrideOption.deposit) overrideMaxDeposit = newValue; if (option == OverrideOption.mint) overrideMaxMint = newValue; if (option == OverrideOption.withdraw) overrideMaxWithdraw = newValue; if (option == OverrideOption.redeem) overrideMaxRedeem = newValue; } }