Skip to main content

Manage

note

Please read the README section from the repository.

As a reminder, the following snippets are for educational purposes.

Summary

Overview of the snippets implementation of a smart contract exposing the following functions:

depositInVault

Deposit assets into the vault on behalf of onBehalf.

withdrawFromVaultAmount

Withdraws assets from the vault on behalf of the sender, and sends them to receiver.

redeemAllFromVault

Redeems the whole sender's position from the vault, and sends the withdrawn amount to receiver.

reallocateAvailableLiquidity

Withdraws the maximum available liquidity from the markets srcMarketParams, and supply the withdrawn assets into destMarketParams.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IMetaMorpho, MarketAllocation} from "@metamorpho/interfaces/IMetaMorpho.sol";

import {MarketParamsLib} from "../../lib/metamorpho/lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {IMorpho} from "../../lib/metamorpho/lib/morpho-blue/src/interfaces/IMorpho.sol";
import {ERC20} from "@openzeppelin/token/ERC20/ERC20.sol";

contract MetaMorphoSnippets {
IMorpho public immutable morpho;

constructor(address morphoAddress) {
morpho = IMorpho(morphoAddress);
}

/// @notice Deposit `assets` into the `vault` on behalf of `onBehalf`.
/// @dev Sender must approve the snippets contract to manage his tokens before the call.
/// @param vault The address of the MetaMorpho vault.
/// @param assets the amount to deposit.
/// @param onBehalf The address that will own the increased deposit position.
function depositInVault(address vault, uint256 assets, address onBehalf) public returns (uint256 shares) {
ERC20(IMetaMorpho(vault).asset()).transferFrom(msg.sender, address(this), assets);

_approveMaxVault(vault);

shares = IMetaMorpho(vault).deposit(assets, onBehalf);
}

/// @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.
function withdrawFromVaultAmount(address vault, uint256 assets, address receiver)
public
returns (uint256 redeemed)
{
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.
function redeemAllFromVault(address vault, address receiver) public returns (uint256 redeemed) {
uint256 maxToRedeem = IMetaMorpho(vault).maxRedeem(msg.sender);
redeemed = IMetaMorpho(vault).redeem(maxToRedeem, receiver, msg.sender);
}

/// @notice Withdraws the maximum available liquidity from the markets `srcMarketParams`, and supply the withdrawn
/// assets into `destMarketParams`.
/// @dev The contract implementing this function must be registered as an allocator of the vault for the function to
/// be called successfully.
/// @param vault The address of the MetaMorpho vault.
/// @param srcMarketParams A MarketParams list of markets to withdraw from.
/// @param destMarketParams The MarketParams of the market to supply to.
function reallocateAvailableLiquidity(
address vault,
MarketParams[] calldata srcMarketParams,
MarketParams calldata destMarketParams
) public {
uint256 nbMarkets = srcMarketParams.length;
MarketAllocation[] memory allocations = new MarketAllocation[](nbMarkets + 1);

for (uint256 i; i < nbMarkets; ++i) {
MarketParams memory marketParams = srcMarketParams[i];

(uint256 totalSupplyAssets, uint256 totalSupplyShares, uint256 totalBorrowAssets,) =
morpho.expectedMarketBalances(marketParams);

uint256 supplyShares = morpho.supplyShares(marketParams.id(), vault);
uint256 supplyAssets = supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);

uint256 availableLiquidity = totalSupplyAssets - totalBorrowAssets;

allocations[i] =
MarketAllocation({marketParams: marketParams, assets: supplyAssets.zeroFloorSub(availableLiquidity)});
}

allocations[nbMarkets] = MarketAllocation({marketParams: destMarketParams, assets: type(uint256).max});

IMetaMorpho(vault).reallocate(allocations);
}

function _approveMaxVault(address vault) internal {
if (ERC20(IMetaMorpho(vault).asset()).allowance(address(this), vault) == 0) {
ERC20(IMetaMorpho(vault).asset()).approve(vault, type(uint256).max);
}
}
}