From f19c07ea06f379acb10be0ec146d928225d482c9 Mon Sep 17 00:00:00 2001 From: Rubilmax Date: Wed, 27 Sep 2023 14:05:21 +0200 Subject: [PATCH] feat(fee): add max fee --- src/MetaMorpho.sol | 6 +++--- src/libraries/ConstantsLib.sol | 3 +++ test/forge/FeeTest.sol | 18 ++++++++++++++++-- test/forge/TimelockTest.sol | 16 ++++------------ test/forge/helpers/BaseTest.sol | 2 +- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/MetaMorpho.sol b/src/MetaMorpho.sol index 6f0bba87..b78c5009 100644 --- a/src/MetaMorpho.sol +++ b/src/MetaMorpho.sol @@ -152,13 +152,13 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph } function submitFee(uint256 newFee) external onlyOwner { - require(newFee <= WAD, ErrorsLib.MAX_FEE_EXCEEDED); + require(newFee <= MAX_FEE, ErrorsLib.MAX_FEE_EXCEEDED); require(newFee != fee, ErrorsLib.ALREADY_SET); if (newFee < fee || timelock == 0) { _setFee(newFee); } else { - // Safe "unchecked" cast because newFee <= WAD. + // Safe "unchecked" cast because newFee <= MAX_FEE. pendingFee = PendingUint192(uint192(newFee), uint64(block.timestamp)); emit EventsLib.SubmitFee(newFee); @@ -512,7 +512,7 @@ contract MetaMorpho is ERC4626, ERC20Permit, Ownable2Step, Multicall, IMetaMorph function _setFee(uint256 newFee) internal { require(newFee == 0 || feeRecipient != address(0), ErrorsLib.ZERO_FEE_RECIPIENT); - // Safe "unchecked" cast because newFee <= WAD. + // Safe "unchecked" cast because newFee <= MAX_FEE. fee = uint96(newFee); emit EventsLib.SetFee(newFee); diff --git a/src/libraries/ConstantsLib.sol b/src/libraries/ConstantsLib.sol index 51438831..5443a253 100644 --- a/src/libraries/ConstantsLib.sol +++ b/src/libraries/ConstantsLib.sol @@ -14,3 +14,6 @@ uint8 constant DECIMALS_OFFSET = 6; /// @dev The maximum supply/withdraw queue size ensuring the cost of depositing/withdrawing from the vault fits in a /// block. uint256 constant MAX_QUEUE_SIZE = 64; + +/// @dev The maximum fee the vault can have (50%). +uint256 constant MAX_FEE = 0.5e18; diff --git a/test/forge/FeeTest.sol b/test/forge/FeeTest.sol index 2fc92ff2..3bbda13e 100644 --- a/test/forge/FeeTest.sol +++ b/test/forge/FeeTest.sol @@ -182,7 +182,7 @@ contract FeeTest is BaseTest { function testSetFeeAccrueFee(uint256 deposited, uint256 fee, uint256 blocks) public { deposited = bound(deposited, MIN_TEST_ASSETS, MAX_TEST_ASSETS); - fee = bound(fee, 0, WAD); + fee = bound(fee, 0, MAX_FEE); blocks = _boundBlocks(blocks); vm.assume(fee != FEE); @@ -232,8 +232,22 @@ contract FeeTest is BaseTest { vault.submitFee(fee); } + function testSubmitFeeMaxFeeExceeded(uint256 fee) public { + fee = bound(fee, MAX_FEE + 1, type(uint256).max); + + vm.prank(OWNER); + vm.expectRevert(bytes(ErrorsLib.MAX_FEE_EXCEEDED)); + vault.submitFee(fee); + } + + function testSubmitFeeAlreadySet() public { + vm.prank(OWNER); + vm.expectRevert(bytes(ErrorsLib.ALREADY_SET)); + vault.submitFee(FEE); + } + function testAcceptFeeNotOwner(uint256 fee) public { - fee = bound(fee, FEE + 1, WAD); + fee = bound(fee, FEE + 1, MAX_FEE); _setTimelock(1); diff --git a/test/forge/TimelockTest.sol b/test/forge/TimelockTest.sol index 054d750f..53976ec3 100644 --- a/test/forge/TimelockTest.sol +++ b/test/forge/TimelockTest.sol @@ -146,7 +146,7 @@ contract TimelockTest is BaseTest { } function testSubmitFeeIncreased(uint256 fee) public { - fee = bound(fee, FEE + 1, WAD); + fee = bound(fee, FEE + 1, MAX_FEE); vm.prank(OWNER); vault.submitFee(fee); @@ -159,16 +159,8 @@ contract TimelockTest is BaseTest { assertEq(submittedAt, block.timestamp, "submittedAt"); } - function testSubmitFeeIncreasedMaxFeeExceeded(uint256 fee) public { - fee = bound(fee, WAD + 1, type(uint256).max); - - vm.prank(OWNER); - vm.expectRevert(bytes(ErrorsLib.MAX_FEE_EXCEEDED)); - vault.submitFee(fee); - } - function testAcceptFee(uint256 fee) public { - fee = bound(fee, FEE + 1, WAD); + fee = bound(fee, FEE + 1, MAX_FEE); vm.prank(OWNER); vault.submitFee(fee); @@ -192,7 +184,7 @@ contract TimelockTest is BaseTest { } function testAcceptFeeTimelockNotElapsed(uint256 fee, uint256 elapsed) public { - fee = bound(fee, FEE + 1, WAD); + fee = bound(fee, FEE + 1, MAX_FEE); elapsed = bound(elapsed, 1, TIMELOCK - 1); vm.prank(OWNER); @@ -206,7 +198,7 @@ contract TimelockTest is BaseTest { } function testAcceptFeeTimelockExpirationExceeded(uint256 fee, uint256 elapsed) public { - fee = bound(fee, FEE + 1, WAD); + fee = bound(fee, FEE + 1, MAX_FEE); elapsed = bound(elapsed, TIMELOCK + TIMELOCK_EXPIRATION + 1, type(uint64).max); vm.prank(OWNER); diff --git a/test/forge/helpers/BaseTest.sol b/test/forge/helpers/BaseTest.sol index 9451fe3c..7c1e90e3 100644 --- a/test/forge/helpers/BaseTest.sol +++ b/test/forge/helpers/BaseTest.sol @@ -10,7 +10,7 @@ import {MorphoLib} from "@morpho-blue/libraries/periphery/MorphoLib.sol"; import {MorphoBalancesLib} from "@morpho-blue/libraries/periphery/MorphoBalancesLib.sol"; import "src/libraries/ConstantsLib.sol"; -import "@morpho-blue/libraries/ConstantsLib.sol"; +import {ORACLE_PRICE_SCALE} from "@morpho-blue/libraries/ConstantsLib.sol"; import {IrmMock} from "src/mocks/IrmMock.sol"; import {ERC20Mock} from "src/mocks/ERC20Mock.sol";