Skip to main content

Borrow

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:

supplyCollateral

Handles the supply of collateral by a user to a specific market.

withdrawCollateral

Handles the withdrawal of collateral by a user from a specific market of a specific amount. The withdrawn funds are going to the receiver.

borrow

Handles the borrowing of assets by a user from a specific market.

repayAmount

Handles the repayment of a specified amount of assets by a user to a specific market.

repay50Percent

Handles the repayment of 50% of the borrowed assets by a user to a specific market.

repayAll

Handles the repayment of all the borrowed assets by a user to a specific market.

repayAmountOrAll

Handles the repayment of a specified amount of assets by the caller to a specific market. If the amount is greater than the total amount borrowed by the user, repays all the shares of the user.

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

import {Id, IMorpho, MarketParams} from "@morpho-blue/interfaces/IMorpho.sol";

import {IIrm} from "@morpho-blue/interfaces/IIrm.sol";
import {IOracle} from "@morpho-blue/interfaces/IOracle.sol";

import {ERC20} from "@openzeppelin4/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin4/token/ERC20/utils/SafeERC20.sol";
import {MorphoBalancesLib} from "@morpho-blue/libraries/periphery/MorphoBalancesLib.sol";
import {MarketParamsLib} from "@morpho-blue/libraries/MarketParamsLib.sol";
import {MorphoLib} from "@morpho-blue/libraries/periphery/MorphoLib.sol";
import {SharesMathLib} from "@morpho-blue/libraries/SharesMathLib.sol";

/// @title Snippets
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice The Morpho Snippets contract.
contract MorphoBlueSnippets {
using MorphoLib for IMorpho;
using MorphoBalancesLib for IMorpho;
using MarketParamsLib for MarketParams;
using SafeERC20 for ERC20;
using SharesMathLib for uint256;

/* IMMUTABLES */

IMorpho public immutable morpho;

/* CONSTRUCTOR */

/// @notice Constructs the contract.
/// @param morphoAddress The address of the Morpho Blue contract.
constructor(address morphoAddress) {
morpho = IMorpho(morphoAddress);
}

/// @notice Handles the supply of collateral by the caller to a specific market.
/// @param marketParams The parameters of the market.
/// @param amount The amount of collateral the user is supplying.
function supplyCollateral(MarketParams memory marketParams, uint256 amount) external {
ERC20(marketParams.collateralToken).forceApprove(address(morpho), type(uint256).max);
ERC20(marketParams.collateralToken).safeTransferFrom(msg.sender, address(this), amount);

address onBehalf = msg.sender;

morpho.supplyCollateral(marketParams, amount, onBehalf, hex"");
}

/// @notice Handles the withdrawal of collateral by the caller from a specific market of a specific amount.
/// @param marketParams The parameters of the market.
/// @param amount The amount of collateral the user is withdrawing.
function withdrawCollateral(MarketParams memory marketParams, uint256 amount) external {
address onBehalf = msg.sender;
address receiver = msg.sender;

morpho.withdrawCollateral(marketParams, amount, onBehalf, receiver);
}

/// @notice Handles the borrowing of assets by the caller from a specific market.
/// @param marketParams The parameters of the market.
/// @param amount The amount of assets the user is borrowing.
/// @return assetsBorrowed The actual amount of assets borrowed.
/// @return sharesBorrowed The shares borrowed in return for the assets.
function borrow(MarketParams memory marketParams, uint256 amount)
external
returns (uint256 assetsBorrowed, uint256 sharesBorrowed)
{
uint256 shares;
address onBehalf = msg.sender;
address receiver = msg.sender;

(assetsBorrowed, sharesBorrowed) = morpho.borrow(marketParams, amount, shares, onBehalf, receiver);
}

/// @notice Handles the repayment of a specified amount of assets by the caller to a specific market.
/// @param marketParams The parameters of the market.
/// @param amount The amount of assets the user is repaying.
/// @return assetsRepaid The actual amount of assets repaid.
/// @return sharesRepaid The shares repaid in return for the assets.
function repayAmount(MarketParams memory marketParams, uint256 amount)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid)
{
ERC20(marketParams.loanToken).forceApprove(address(morpho), type(uint256).max);
ERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), amount);

uint256 shares;
address onBehalf = msg.sender;
(assetsRepaid, sharesRepaid) = morpho.repay(marketParams, amount, shares, onBehalf, hex"");
}

/// @notice Handles the repayment of 50% of the borrowed assets by the caller to a specific market.
/// @param marketParams The parameters of the market.
/// @return assetsRepaid The actual amount of assets repaid.
/// @return sharesRepaid The shares repaid in return for the assets.
function repay50Percent(MarketParams memory marketParams)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid)
{
ERC20(marketParams.loanToken).forceApprove(address(morpho), type(uint256).max);

Id marketId = marketParams.id();

(,, uint256 totalBorrowAssets, uint256 totalBorrowShares) = morpho.expectedMarketBalances(marketParams);
uint256 borrowShares = morpho.position(marketId, msg.sender).borrowShares;

uint256 repaidAmount = (borrowShares / 2).toAssetsUp(totalBorrowAssets, totalBorrowShares);
ERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), repaidAmount);

uint256 amount;
address onBehalf = msg.sender;

(assetsRepaid, sharesRepaid) = morpho.repay(marketParams, amount, borrowShares / 2, onBehalf, hex"");
}

/// @notice Handles the repayment of all the borrowed assets by the caller to a specific market.
/// @param marketParams The parameters of the market.
/// @return assetsRepaid The actual amount of assets repaid.
/// @return sharesRepaid The shares repaid in return for the assets.
function repayAll(MarketParams memory marketParams) external returns (uint256 assetsRepaid, uint256 sharesRepaid) {
ERC20(marketParams.loanToken).forceApprove(address(morpho), type(uint256).max);

Id marketId = marketParams.id();

(,, uint256 totalBorrowAssets, uint256 totalBorrowShares) = morpho.expectedMarketBalances(marketParams);
uint256 borrowShares = morpho.position(marketId, msg.sender).borrowShares;

uint256 repaidAmount = borrowShares.toAssetsUp(totalBorrowAssets, totalBorrowShares);
ERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), repaidAmount);

uint256 amount;
address onBehalf = msg.sender;
(assetsRepaid, sharesRepaid) = morpho.repay(marketParams, amount, borrowShares, onBehalf, hex"");
}

/// @notice Handles the repayment of a specified amount of assets by the caller to a specific market. If the amount
/// is greater than the total amount borrowed by the user it repays all the shares of the user.
/// @param marketParams The parameters of the market.
/// @param amount The amount of assets the user is repaying.
/// @return assetsRepaid The actual amount of assets repaid.
/// @return sharesRepaid The shares repaid in return for the assets.
function repayAmountOrAll(MarketParams memory marketParams, uint256 amount)
external
returns (uint256 assetsRepaid, uint256 sharesRepaid)
{
ERC20(marketParams.loanToken).forceApprove(address(morpho), type(uint256).max);

Id id = marketParams.id();

address onBehalf = msg.sender;

morpho.accrueInterest(marketParams);
uint256 totalBorrowAssets = morpho.totalBorrowAssets(id);
uint256 totalBorrowShares = morpho.totalBorrowShares(id);
uint256 shares = morpho.borrowShares(id, msg.sender);
uint256 assetsMax = shares.toAssetsUp(totalBorrowAssets, totalBorrowShares);

if (amount >= assetsMax) {
ERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), assetsMax);
(assetsRepaid, sharesRepaid) = morpho.repay(marketParams, 0, shares, onBehalf, hex"");
} else {
ERC20(marketParams.loanToken).safeTransferFrom(msg.sender, address(this), amount);
(assetsRepaid, sharesRepaid) = morpho.repay(marketParams, amount, 0, onBehalf, hex"");
}
}
}