Skip to content

Commit

Permalink
feat: last fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Grimal committed Nov 29, 2023
1 parent f836331 commit b897f87
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 57 deletions.
45 changes: 23 additions & 22 deletions src/metamorpho/MetamorphoSnippets.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ contract MetaMorphoSnippets {
// --- VIEW FUNCTIONS ---

/// @notice Returns the total assets deposited into a MetaMorpho `vault`.
/// @dev It doesn't take into account the fees accrued since the last update.
/// @param vault The address of the MetaMorpho vault.
function totalDepositVault(address vault) public view returns (uint256 totalAssets) {
totalAssets = IMetaMorpho(vault).lastTotalAssets();
totalAssets = IMetaMorpho(vault).totalAssets();
}

/// @notice Returns the total assets supplied into a specific morpho blue market by a MetaMorpho `vault`.
Expand Down Expand Up @@ -78,18 +77,27 @@ contract MetaMorphoSnippets {
return withdrawQueueList;
}

/// @notice Returns the supply cap of a market on a MetaMorpho `vault`.
/// @notice Returns the sum of the supply caps of markets with the same collateral `token` on a MetaMorpho `vault`.
/// @dev This is a way to visualize exposure to this token.
/// @param vault The address of the MetaMorpho vault.
/// @param marketParams The morpho blue market.
function capMarket(address vault, MarketParams memory marketParams) public view returns (uint192 cap) {
Id id = marketParams.id();
cap = IMetaMorpho(vault).config(id).cap;
/// @param token The collateral token.
function totalCapAsset(address vault, address token) public view returns (uint192 totalCap) {
uint256 queueLength = IMetaMorpho(vault).withdrawQueueLength();

for (uint256 i; i < queueLength; ++i) {
Id idMarket = IMetaMorpho(vault).withdrawQueue(i);
MarketParams memory marketParams = morpho.idToMarketParams(idMarket);

if (marketParams.collateralToken == token) {
totalCap += IMetaMorpho(vault).config(idMarket).cap;
}
}
}

/// @notice Returns the current APR (Annual Percentage Rate) of a morpho blue market.
/// @notice Returns the current APY of a morpho blue market.
/// @param marketParams The morpho blue market parameters.
/// @param market The morpho blue market state.
function supplyAPRMarket(MarketParams memory marketParams, Market memory market)
function supplyAPYMarket(MarketParams memory marketParams, Market memory market)
public
view
returns (uint256 supplyRate)
Expand All @@ -102,13 +110,13 @@ contract MetaMorphoSnippets {
// Get the supply rate
uint256 utilization = totalBorrowAssets == 0 ? 0 : totalBorrowAssets.wDivUp(totalSupplyAssets);

supplyRate = borrowRate.wMulDown(1 ether - market.fee).wMulDown(utilization);
supplyRate = borrowRate.wTaylorCompounded(1).wMulDown(1 ether - market.fee).wMulDown(utilization);
}

/// @notice Returns the current APR (Annual Percentage Rate) of a MetaMorpho vault.
/// @dev It is computed as the sum of all APR of enabled markets weighted by the supply on these markets.
/// @notice Returns the current APY of a MetaMorpho vault.
/// @dev It is computed as the sum of all APY of enabled markets weighted by the supply on these markets.
/// @param vault The address of the MetaMorpho vault.
function supplyAPRVault(address vault) public view returns (uint256 avgSupplyRate) {
function supplyAPYVault(address vault) public view returns (uint256 avgSupplyRate) {
uint256 ratio;
uint256 queueLength = IMetaMorpho(vault).withdrawQueueLength();

Expand All @@ -120,7 +128,7 @@ contract MetaMorphoSnippets {
MarketParams memory marketParams = morpho.idToMarketParams(idMarket);
Market memory market = morpho.market(idMarket);

uint256 currentSupplyAPR = supplyAPRMarket(marketParams, market);
uint256 currentSupplyAPR = supplyAPYMarket(marketParams, market);
uint256 vaultAsset = vaultAssetsInMarket(vault, marketParams);
ratio += currentSupplyAPR.wMulDown(vaultAsset);
}
Expand All @@ -145,6 +153,7 @@ contract MetaMorphoSnippets {

/// @notice Withdraws `assets` from the `vault` on behalf of the sender, and sends them to `receiver`.
/// @dev Sender must approve the snippets contract to manage his tokens before the call.
/// @dev To withdraw all, it is recommended to use the redeem function.
/// @param vault The address of the MetaMorpho vault.
/// @param assets the amount to withdraw.
/// @param receiver The address that will receive the withdrawn assets.
Expand All @@ -155,14 +164,6 @@ contract MetaMorphoSnippets {
redeemed = IMetaMorpho(vault).withdraw(assets, receiver, msg.sender);
}

/// @notice Withdraws the whole sender's position from the `vault`, and sends the withdrawn amount to `receiver`.
/// @param vault The address of the MetaMorpho vault.
/// @param receiver The address that will receive the withdrawn assets.
function withdrawFromVaultAll(address vault, address receiver) public returns (uint256 redeemed) {
uint256 assets = IMetaMorpho(vault).maxWithdraw(msg.sender);
redeemed = IMetaMorpho(vault).withdraw(assets, receiver, msg.sender);
}

/// @notice Redeems the whole sender's position from the `vault`, and sends the withdrawn amount to `receiver`.
/// @param vault The address of the MetaMorpho vault.
/// @param receiver The address that will receive the withdrawn assets.
Expand Down
62 changes: 27 additions & 35 deletions test/forge/metamorpho/TestMetamorphoSnippets.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;

import {MetamorphoSnippets} from "@snippets/metamorpho/MetamorphoSnippets.sol";
import {MetaMorphoSnippets} from "@snippets/metamorpho/MetamorphoSnippets.sol";
import "@metamorpho-test/helpers/IntegrationTest.sol";

import {SafeCast} from "@openzeppelin/utils/math/SafeCast.sol";

contract TestIntegrationSnippets is IntegrationTest {
MetamorphoSnippets internal snippets;
MetaMorphoSnippets internal snippets;

using MorphoBalancesLib for IMorpho;
using MorphoLib for IMorpho;
Expand All @@ -17,7 +17,7 @@ contract TestIntegrationSnippets is IntegrationTest {

function setUp() public virtual override {
super.setUp();
snippets = new MetamorphoSnippets(address(morpho));
snippets = new MetaMorphoSnippets(address(morpho));

_setCap(allMarkets[0], CAP);
_sortSupplyQueueIdleLast();
Expand Down Expand Up @@ -119,13 +119,23 @@ contract TestIntegrationSnippets is IntegrationTest {
assertEq(Id.unwrap(withdrawQueueList[1]), Id.unwrap(expectedWithdrawQueue[1]));
}

function testCapMarket(MarketParams memory marketParams) public {
Id idMarket = marketParams.id();
function testTotalCapAsset(uint256 capMarket1, uint256 capMarket2, uint256 capMarket3) public {
capMarket1 = bound(capMarket1, MIN_TEST_ASSETS, MAX_TEST_ASSETS);
capMarket2 = bound(capMarket2, MIN_TEST_ASSETS, MAX_TEST_ASSETS);
capMarket3 = bound(capMarket3, MIN_TEST_ASSETS, MAX_TEST_ASSETS);

assertEq(vault.config(idMarket).cap, snippets.capMarket(address(vault), marketParams), "cap per market");
_setCap(allMarkets[0], capMarket1);
_setCap(allMarkets[1], capMarket2);
_setCap(allMarkets[2], capMarket3);

assertEq(
capMarket1 + capMarket2 + capMarket3,
snippets.totalCapAsset(address(vault), address(collateralToken)),
"cap per market"
);
}

function testSupplyAPR0(Market memory market) public {
function testSupplyAPY0(Market memory market) public {
vm.assume(market.totalBorrowAssets == 0);
vm.assume(market.lastUpdate > 0);
vm.assume(market.fee < 1 ether);
Expand All @@ -143,10 +153,10 @@ contract TestIntegrationSnippets is IntegrationTest {
0,
"Diff in snippets vs integration supplyAPR test"
);
assertEq(snippets.supplyAPRMarket(marketParams, market), 0, "Diff in snippets vs integration supplyAPR test");
assertEq(snippets.supplyAPYMarket(marketParams, market), 0, "Diff in snippets vs integration supplyAPR test");
}

function testSupplyAPRMarket(Market memory market) public {
function testSupplyAPYMarket(Market memory market) public {
vm.assume(market.totalBorrowAssets > 0);
vm.assume(market.totalBorrowShares > 0);
vm.assume(market.totalSupplyAssets > 0);
Expand All @@ -159,21 +169,21 @@ contract TestIntegrationSnippets is IntegrationTest {

uint256 borrowTrue = irm.borrowRateView(marketParams, market);
uint256 utilization = totalBorrowAssets == 0 ? 0 : totalBorrowAssets.wDivUp(totalSupplyAssets);
uint256 supplyTrue = borrowTrue.wMulDown(1 ether - market.fee).wMulDown(utilization);
uint256 supplyTrue = borrowTrue.wTaylorCompounded(1).wMulDown(1 ether - market.fee).wMulDown(utilization);

uint256 supplyToTest = snippets.supplyAPRMarket(marketParams, market);
uint256 supplyToTest = snippets.supplyAPYMarket(marketParams, market);

// handling in if-else the situation where utilization = 0 otherwise too many rejects
if (utilization == 0) {
assertEq(supplyTrue, 0, "supply rate ==0");
assertEq(supplyTrue, 0, "supply rate == 0");
assertEq(supplyTrue, supplyToTest, "Diff in snippets vs integration supplyAPR test");
} else {
assertGt(supplyTrue, 0, "supply rate ==0");
assertGt(supplyTrue, 0, "supply rate == 0");
assertEq(supplyTrue, supplyToTest, "Diff in snippets vs integration supplyAPR test");
}
}

function testSupplyAPRVault(uint256 firstDeposit, uint256 secondDeposit, uint256 firstBorrow, uint256 secondBorrow)
function testSupplyAPYVault(uint256 firstDeposit, uint256 secondDeposit, uint256 firstBorrow, uint256 secondBorrow)
public
{
firstDeposit = bound(firstDeposit, MIN_TEST_ASSETS, MAX_TEST_ASSETS / 2);
Expand Down Expand Up @@ -212,13 +222,13 @@ contract TestIntegrationSnippets is IntegrationTest {
Market memory market0 = morpho.market(id0);
Market memory market1 = morpho.market(id1);

uint256 rateMarket0 = snippets.supplyAPRMarket(allMarkets[0], market0);
uint256 rateMarket1 = snippets.supplyAPRMarket(allMarkets[1], market1);
uint256 rateMarket0 = snippets.supplyAPYMarket(allMarkets[0], market0);
uint256 rateMarket1 = snippets.supplyAPYMarket(allMarkets[1], market1);
uint256 avgRateNum = rateMarket0.wMulDown(firstDeposit) + rateMarket1.wMulDown(secondDeposit);

uint256 expectedAvgRate = avgRateNum.wDivUp(firstDeposit + secondDeposit);

uint256 avgSupplyRateSnippets = snippets.supplyAPRVault(address(vault));
uint256 avgSupplyRateSnippets = snippets.supplyAPYVault(address(vault));

assertEq(avgSupplyRateSnippets, expectedAvgRate, "avgSupplyRateSnippets == 0");
}
Expand Down Expand Up @@ -249,24 +259,6 @@ contract TestIntegrationSnippets is IntegrationTest {
assertEq(vault.balanceOf(SUPPLIER), shares - redeemed, "balanceOf(SUPPLIER)");
}

function testWithdrawFromVaultAll(uint256 assets) public {
assets = bound(assets, MIN_TEST_ASSETS, MAX_TEST_ASSETS);

loanToken.setBalance(SUPPLIER, assets);
vm.startPrank(SUPPLIER);
uint256 minted = vault.deposit(assets, SUPPLIER);

assertEq(vault.maxWithdraw(SUPPLIER), assets, "maxWithdraw(SUPPLIER)");

uint256 redeemed = snippets.withdrawFromVaultAll(address(vault), SUPPLIER);
vm.stopPrank();

assertEq(redeemed, minted, "shares");
assertEq(vault.balanceOf(SUPPLIER), 0, "balanceOf(SUPPLIER)");
assertEq(loanToken.balanceOf(SUPPLIER), assets, "loanToken.balanceOf(SUPPLIER)");
assertEq(morpho.expectedSupplyAssets(allMarkets[0], address(vault)), 0, "expectedSupplyAssets(vault)");
}

function testRedeemAllFromVault(uint256 deposited) public {
deposited = bound(deposited, MIN_TEST_ASSETS, MAX_TEST_ASSETS);

Expand Down

0 comments on commit b897f87

Please sign in to comment.