Skip to content

Commit

Permalink
Merge branch 'test/fees' of github.com:morpho-labs/morpho-blue-metamo…
Browse files Browse the repository at this point in the history
…rpho into fix/deposit-fee
  • Loading branch information
Rubilmax committed Sep 12, 2023
2 parents 17e69bc + b1127f5 commit fc73b4c
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 49 deletions.
90 changes: 57 additions & 33 deletions contracts/SupplyVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
emit EventsLib.SubmitPendingFee(newFee);
}

function setFee() external timelockElapsed(pendingFee.timestamp) onlyOwner {
function setFee() external timelockElapsed(pendingFee.timestamp) onlyOwner syncLastTotalAssets {
// Accrue interest using the previous fee set before changing it.
_accrueFee();

Expand All @@ -155,7 +155,7 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
delete pendingFee;
}

function setFeeRecipient(address newFeeRecipient) external onlyOwner {
function setFeeRecipient(address newFeeRecipient) external onlyOwner syncLastTotalAssets {
require(newFeeRecipient != feeRecipient, ErrorsLib.ALREADY_SET);

// Accrue interest to the previous fee recipient set before changing it.
Expand Down Expand Up @@ -236,57 +236,42 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
return _market(id).cap;
}

/* ERC4626 */
/* ERC4626 (PUBLIC) */

function maxWithdraw(address owner) public view virtual override returns (uint256) {
_accruedFeeShares();

return _staticWithdrawOrder(super.maxWithdraw(owner));
}

function maxRedeem(address owner) public view override returns (uint256) {
return _convertToShares(maxWithdraw(owner), Math.Rounding.Down);
}

function deposit(uint256 assets, address receiver) public virtual override syncLastTotalAssets returns (uint256) {
_accrueFee();

return super.deposit(assets, receiver);
function deposit(uint256 assets, address receiver) public virtual override returns (uint256 shares) {
shares = _convertToSharesWithFeeAccrued(assets, Math.Rounding.Down);
_deposit(_msgSender(), receiver, assets, shares);
}

function mint(uint256 shares, address receiver) public virtual override syncLastTotalAssets returns (uint256) {
_accrueFee();

return super.mint(shares, receiver);
function mint(uint256 shares, address receiver) public virtual override returns (uint256 assets) {
assets = _convertToAssetsWithFeeAccrued(shares, Math.Rounding.Up);
_deposit(_msgSender(), receiver, assets, shares);
}

function withdraw(uint256 assets, address receiver, address owner)
public
virtual
override
syncLastTotalAssets
returns (uint256 shares)
{
_accrueFee();

// Do not call expensive `maxWithdraw` and optimistically withdraw assets.

shares = previewWithdraw(assets);
shares = _convertToSharesWithFeeAccrued(assets, Math.Rounding.Up);
_withdraw(_msgSender(), receiver, owner, assets, shares);
}

function redeem(uint256 shares, address receiver, address owner)
public
virtual
override
syncLastTotalAssets
returns (uint256 assets)
{
_accrueFee();

function redeem(uint256 shares, address receiver, address owner) public virtual override returns (uint256 assets) {
// Do not call expensive `maxRedeem` and optimistically redeem shares.

assets = previewRedeem(shares);
assets = _convertToAssetsWithFeeAccrued(shares, Math.Rounding.Down);
_withdraw(_msgSender(), receiver, owner, assets, shares);
}

Expand All @@ -302,8 +287,14 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
assets += ERC20(asset()).balanceOf(address(this));
}

/* ERC4626 (INTERNAL) */

/// @dev Used in mint or deposit to deposit the underlying asset to Blue markets.
function _deposit(address caller, address owner, uint256 assets, uint256 shares) internal override {
function _deposit(address caller, address owner, uint256 assets, uint256 shares)
internal
override
syncLastTotalAssets
{
super._deposit(caller, owner, assets, shares);

require(_depositOrder(assets) == 0, ErrorsLib.DEPOSIT_ORDER_FAILED);
Expand All @@ -313,12 +304,45 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares)
internal
override
syncLastTotalAssets
{
require(_withdrawOrder(assets) == 0, ErrorsLib.WITHDRAW_ORDER_FAILED);

super._withdraw(caller, receiver, owner, assets, shares);
}

function _convertToShares(uint256 assets, Math.Rounding rounding)
internal
view
virtual
override
returns (uint256)
{
return assets.mulDiv(totalSupply() + _accruedFeeShares() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
}

function _convertToAssets(uint256 shares, Math.Rounding rounding)
internal
view
virtual
override
returns (uint256)
{
return shares.mulDiv(totalAssets() + 1, totalSupply() + _accruedFeeShares() + 10 ** _decimalsOffset(), rounding);
}

function _convertToSharesWithFeeAccrued(uint256 assets, Math.Rounding rounding) internal returns (uint256) {
_accrueFee();

return assets.mulDiv(totalSupply() + 10 ** _decimalsOffset(), totalAssets() + 1, rounding);
}

function _convertToAssetsWithFeeAccrued(uint256 shares, Math.Rounding rounding) internal returns (uint256) {
_accrueFee();

return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding);
}

/* INTERNAL */

function _market(Id id) internal view returns (VaultMarket storage) {
Expand Down Expand Up @@ -481,11 +505,11 @@ contract SupplyVault is ERC4626, Ownable2Step, ISupplyVault {
uint256 totalInterest = newTotalAssets.zeroFloorSub(lastTotalAssets);

if (totalInterest != 0) {
uint256 feeAmount = totalInterest.mulDiv(fee, WAD);
// The fee amount is subtracted from the total assets in this calculation to compensate for the fact
// that total assets is already increased by the total interest (including the fee amount).
feeShares = feeAmount.mulDiv(
totalSupply() + 10 ** _decimalsOffset(), newTotalAssets - feeAmount + 1, Math.Rounding.Down
uint256 feeAssets = totalInterest.mulDiv(fee, WAD);
// The fee assets is subtracted from the total assets in this calculation to compensate for the fact
// that total assets is already increased by the total interest (including the fee assets).
feeShares = feeAssets.mulDiv(
totalSupply() + 10 ** _decimalsOffset(), newTotalAssets - feeAssets + 1, Math.Rounding.Down
);
}
}
Expand Down
20 changes: 16 additions & 4 deletions test/forge/BaseTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {UtilsLib} from "@morpho-blue/libraries/UtilsLib.sol";
import {ERC20Mock as ERC20} from "contracts/mocks/ERC20Mock.sol";
import {OracleMock as Oracle} from "contracts/mocks/OracleMock.sol";

import {WAD} from "@morpho-blue/libraries/MathLib.sol";
import {Math} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";
import {SupplyVault, IERC20, ErrorsLib, Pending, MarketAllocation} from "contracts/SupplyVault.sol";
import {Morpho, MarketParamsLib, MarketParams, SharesMathLib, Id} from "@morpho-blue/Morpho.sol";

Expand All @@ -31,10 +33,10 @@ contract BaseTest is Test {
address internal ONBEHALF = _addrFromHashedString("Morpho On Behalf");
address internal RECEIVER = _addrFromHashedString("Morpho Receiver");
address internal LIQUIDATOR = _addrFromHashedString("Morpho Liquidator");
address internal OWNER = _addrFromHashedString("Morpho Owner");
address internal RISK_MANAGER = _addrFromHashedString("Morpho Risk Manager");
address internal ALLOCATOR = _addrFromHashedString("Morpho Allocator");
address internal FEE_RECIPIENT = _addrFromHashedString("MetaMorpho Fee Recipient");
address internal OWNER = _addrFromHashedString("Owner");
address internal RISK_MANAGER = _addrFromHashedString("Risk Manager");
address internal ALLOCATOR = _addrFromHashedString("Allocator");
address internal FEE_RECIPIENT = _addrFromHashedString("Fee Recipient");

uint256 internal constant LLTV = 0.8 ether;
uint256 internal constant TIMELOCK = 0;
Expand Down Expand Up @@ -132,4 +134,14 @@ contract BaseTest is Test {
vault.enableMarket(params.id());
vm.stopPrank();
}

function _borrow(MarketParams memory params, uint256 amount) internal {
deal(address(collateralToken), BORROWER, type(uint256).max);

vm.startPrank(BORROWER);
collateralToken.approve(address(morpho), type(uint256).max);
morpho.supplyCollateral(params, type(uint128).max, BORROWER, hex"");
morpho.borrow(params, amount, 0, BORROWER, BORROWER);
vm.stopPrank();
}
}
Loading

0 comments on commit fc73b4c

Please sign in to comment.