feat: set up morpho blue contracts

This commit is contained in:
Shriya Tyagi 2023-12-16 15:38:21 +05:30
parent 3a9dcabc54
commit 8b1daa0313
26 changed files with 3468 additions and 0 deletions

114
README.md
View File

@ -1,2 +1,116 @@
# dsa-connectors-2.0
DSA Connectors 2.0
Connectors are standard proxy logics contract that let DeFi Smart Account (DSA) interact with various smart contracts, and make the important actions accessible like cross protocol interoperability.
DSAs are powerful because they can easily be extended with connectors. Every new connector that is added is immediately usable by any developer building on top of DSAs. Connectors can either be base connectors to protocols, auth connectors, higher level connectors with more specific use cases like optimized lending, or connectors to native liquidity pools.
You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained below.
List of all the mainnet connector for referrence is [here](https://github.com/Instadapp/dsa-connectors/tree/main/contracts/mainnet/connectors)
## Usage
### Pre Requisites
Before running any command, make sure to install dependencies:
```sh
$ npm install
```
### Compile
Compile the smart contracts with Hardhat:
```sh
$ npm run compile
```
### TypeChain
Compile the smart contracts and generate TypeChain artifacts:
```sh
$ npm run typechain
```
### Test
Run tests using interactive CLI
```sh
$ npm run test:runner
```
Run all the tests:
```sh
$ npm run test
```
(Striclty use this envirnment to test, or otherwise make suitable changes in config file before testing).
### Deploy
To deploy a connector using interactive CLI
```sh
$ npm run deploy:runner
```
(To deploy script manually use `scripts/deployment/deployManually.ts` script)
### checks
To check that code is compatible with github actions
```sh
$ npm run check
```
## How to add a new connector
You can create a new PR to add a new connector. To get the PR merged, certain requirements needs to be met which will be explained here.
### New connector should follow the current directory structure
Common files for all connectors are in `contracts/common` directory.
- `math.sol` has methods for mathematical operations (`DSMath`)
- `interfaces.sol` contains the common interfaces
- `TokenInterface` for ERC-20 interface including WETH
- `stores.sol` contains the global constants as well as methods `getId` & `setId` (`Stores`)
- `basic.sol` inherits `DSMath` & `Stores` contracts. This contains few details explained below
- Wrapping & unwrapping ETH (`convertEthToWeth` & `convertWethToEth`)
- Getting token & ETH balance of DSA
Connectors are under `contracts/connectors` directory, and should be formatted as follows:
- Connector events should be in a separate contract: `events.sol`
- Interfaces should be defined in a seperate file: `interface.sol`
- If the connector has helper methods & constants (including interface instances), this should be defined in a separate file: `helpers.sol`
- `Helpers` contract should inherit `Basic` contract from common directory
- If the connector doesn't have any helper methods, the main contract should inherit `Basic` contract
- The main logic of the contract should be under `main.sol`, and the contract should inherit `Helpers` (if exists, otherwise `Basic`) & `Events`
Few things to consider while writing the connector:
- Connector should have a public constant string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1`
- Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound`
- User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables:
- `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)`
- `_eventParam` of `bytes` type: This will be the abi encoded event parameters
- The contracts should not have `selfdestruct()`
- The contracts should not have `delegatecall()`
- Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere
- Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20)
- Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc
- Only `approve()` (declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell.
- User interacting functions should have natspec comments(@dev, @notice, @param).
- Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell
- Use `setUint()` (declared in `Stores`) for setting value to save for the future spell
### Support
If you can't find something you're looking for or have any questions, ask them at our developers community on [Discord](https://discord.gg/83vvrnY) or simply send an [Email](mailto:info@instadapp.io).

View File

@ -0,0 +1,59 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import { TokenInterface } from "./interfaces.sol";
import { Stores } from "./stores.sol";
import { DSMath } from "./math.sol";
abstract contract Basic is DSMath, Stores {
function convert18ToDec(uint _dec, uint256 _amt) internal pure returns (uint256 amt) {
amt = (_amt / 10 ** (18 - _dec));
}
function convertTo18(uint _dec, uint256 _amt) internal pure returns (uint256 amt) {
amt = mul(_amt, 10 ** (18 - _dec));
}
function getTokenBal(TokenInterface token) internal view returns(uint _amt) {
_amt = address(token) == ethAddr ? address(this).balance : token.balanceOf(address(this));
}
function getTokensDec(TokenInterface buyAddr, TokenInterface sellAddr) internal view returns(uint buyDec, uint sellDec) {
buyDec = address(buyAddr) == ethAddr ? 18 : buyAddr.decimals();
sellDec = address(sellAddr) == ethAddr ? 18 : sellAddr.decimals();
}
function encodeEvent(string memory eventName, bytes memory eventParam) internal pure returns (bytes memory) {
return abi.encode(eventName, eventParam);
}
function approve(TokenInterface token, address spender, uint256 amount) internal {
try token.approve(spender, amount) {
} catch {
token.approve(spender, 0);
token.approve(spender, amount);
}
}
function changeEthAddress(address buy, address sell) internal pure returns(TokenInterface _buy, TokenInterface _sell){
_buy = buy == ethAddr ? TokenInterface(wethAddr) : TokenInterface(buy);
_sell = sell == ethAddr ? TokenInterface(wethAddr) : TokenInterface(sell);
}
function changeEthAddrToWethAddr(address token) internal pure returns(address tokenAddr){
tokenAddr = token == ethAddr ? wethAddr : token;
}
function convertEthToWeth(bool isEth, TokenInterface token, uint amount) internal {
if(isEth) token.deposit{value: amount}();
}
function convertWethToEth(bool isEth, TokenInterface token, uint amount) internal {
if(isEth) {
approve(token, address(token), amount);
token.withdraw(amount);
}
}
}

View File

@ -0,0 +1,43 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
interface TokenInterface {
function approve(address, uint256) external;
function transfer(address, uint) external;
function transferFrom(address, address, uint) external;
function deposit() external payable;
function withdraw(uint) external;
function balanceOf(address) external view returns (uint);
function decimals() external view returns (uint);
function totalSupply() external view returns (uint);
function allowance(address owner, address spender) external view returns (uint256);
}
interface MemoryInterface {
function getUint(uint id) external returns (uint num);
function setUint(uint id, uint val) external;
}
interface InstaMapping {
function cTokenMapping(address) external view returns (address);
function gemJoinMapping(bytes32) external view returns (address);
}
interface AccountInterface {
function enable(address) external;
function disable(address) external;
function isAuth(address) external view returns (bool);
function cast(
string[] calldata _targetNames,
bytes[] calldata _datas,
address _origin
) external payable returns (bytes32[] memory responses);
}
interface ListInterface {
function accountID(address) external returns (uint64);
}
interface InstaConnectors {
function isConnectors(string[] calldata) external returns (bool, address[] memory);
}

View File

@ -0,0 +1,56 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract DSMath {
uint constant WAD = 10 ** 18;
uint constant RAY = 10 ** 27;
function add(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(x, y);
}
function sub(uint x, uint y) internal virtual pure returns (uint z) {
z = SafeMath.sub(x, y);
}
function mul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.mul(x, y);
}
function div(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.div(x, y);
}
function wmul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD;
}
function wdiv(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y;
}
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY;
}
function toInt(uint x) internal pure returns (int y) {
y = int(x);
require(y >= 0, "int-overflow");
}
function toUint(int256 x) internal pure returns (uint256) {
require(x >= 0, "int-overflow");
return uint256(x);
}
function toRad(uint wad) internal pure returns (uint rad) {
rad = mul(wad, 10 ** 27);
}
}

View File

@ -0,0 +1,53 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import { MemoryInterface, InstaMapping, ListInterface, InstaConnectors } from "./interfaces.sol";
abstract contract Stores {
/**
* @dev Return ethereum address
*/
address constant internal ethAddr = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @dev Return Wrapped ETH address
*/
address constant internal wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/**
* @dev Return memory variable address
*/
MemoryInterface constant internal instaMemory = MemoryInterface(0x8a5419CfC711B2343c17a6ABf4B2bAFaBb06957F);
/**
* @dev Return InstaDApp Mapping Addresses
*/
InstaMapping constant internal instaMapping = InstaMapping(0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88);
/**
* @dev Return InstaList Address
*/
ListInterface internal constant instaList = ListInterface(0x4c8a1BEb8a87765788946D6B19C6C6355194AbEb);
/**
* @dev Return connectors registry address
*/
InstaConnectors internal constant instaConnectors = InstaConnectors(0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11);
/**
* @dev Get Uint value from InstaMemory Contract.
*/
function getUint(uint getId, uint val) internal returns (uint returnVal) {
returnVal = getId == 0 ? val : instaMemory.getUint(getId);
}
/**
* @dev Set Uint value in InstaMemory Contract.
*/
function setUint(uint setId, uint val) virtual internal {
if (setId != 0) instaMemory.setUint(setId, val);
}
}

View File

@ -0,0 +1,106 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
pragma experimental ABIEncoderV2;
import { MarketParams } from "./interfaces/IMorpho.sol";
contract Events {
event LogSupplyAssets(
MarketParams marketParams,
uint256 assets,
uint256 shares,
uint256 getId,
uint256 setId
);
event LogSupplyOnBehalf(
MarketParams marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
uint256 getId,
uint256 setId
);
event LogSupplyCollateral(
MarketParams marketParams,
uint256 assets,
uint256 getId,
uint256 setId
);
event LogSupplyCollateralOnBehalf(
MarketParams marketParams,
uint256 assets,
address onBehalf,
uint256 getId,
uint256 setId
);
event LogBorrow(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
uint256 getId,
uint256 setId
);
event LogBorrowOnBehalf(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
address onBehalf,
address receiver,
uint256 getId,
uint256 setId
);
event LogWithdraw(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
uint256 getId,
uint256 setId
);
event LogWithdrawOnBehalf(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
address onBehalf,
uint256 getId,
uint256 setId
);
event LogWithdrawCollateral(
MarketParams marketParams,
uint256 amounts,
uint256 getId,
uint256 setId
);
event LogWithdrawCollateralOnBehalf(
MarketParams marketParams,
uint256 amounts,
address onBehalf,
address receiver,
uint256 getId,
uint256 setId
);
event LogRepay(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
uint256 getId,
uint256 setId
);
event LogRepayOnBehalf(
MarketParams marketParams,
uint256 amounts,
uint256 shares,
address onBehalf,
uint256 getId,
uint256 setId
);
}

View File

@ -0,0 +1,181 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
pragma experimental ABIEncoderV2;
import { Id, IMorpho, MarketParams, Position, Market } from "./interfaces/IMorpho.sol";
import "../../common/stores.sol";
import "../../common/basic.sol";
import "../../common/interfaces.sol";
import { MorphoBalancesLib } from "./libraries/periphery/MorphoBalancesLib.sol";
import { UtilsLib } from "./libraries/UtilsLib.sol";
import { MarketParamsLib } from "./libraries/MarketParamsLib.sol";
abstract contract Helpers is Stores, Basic {
using MorphoBalancesLib for IMorpho;
using MarketParamsLib for MarketParams;
using UtilsLib for uint256;
IMorpho public constant MORPHO_BLUE =
IMorpho(0x777777c9898D384F785Ee44Acfe945efDFf5f3E0); // TODO: Update
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
/// @dev The number of virtual assets of 1 enforces a conversion rate between shares and assets when a market is
/// empty.
uint256 internal constant VIRTUAL_ASSETS = 1;
/// @dev The number of virtual shares has been chosen low enough to prevent overflows, and high enough to ensure
/// high precision computations.
uint256 internal constant VIRTUAL_SHARES = 1e6;
enum Mode {
Collateral,
Repay,
Supply
}
/// @notice Handles Eth to Weth conversion if assets are provided.
function _performEthToWethConversion(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
uint256 _getId,
Mode _mode
) internal returns (MarketParams memory, uint256 _amt) {
_amt = getUint(_getId, _assets);
bool _isEth = _mode == Mode.Collateral
? _marketParams.collateralToken == ethAddr
: _marketParams.loanToken == ethAddr;
_marketParams = updateTokenAddresses(_marketParams);
// Check for max value
if (_assets == type(uint256).max) {
uint256 _maxAvailable = _isEth
? address(this).balance
: TokenInterface(_marketParams.loanToken).balanceOf(
address(this)
);
if (_mode == Mode.Repay) {
uint256 _amtDebt = getPaybackBalance(_marketParams, _onBehalf);
_amt = _maxAvailable.min(_amtDebt); // TODO: Ask
} else {
_amt = _maxAvailable;
}
}
// Perform conversion if necessary
convertEthToWeth(
true,
TokenInterface(_marketParams.loanToken),
_amt
);
return (_marketParams, _amt);
}
/// @notice Handles Eth to Weth conversion if shares are provided.
function _performEthToWethSharesConversion(
MarketParams memory _marketParams,
uint256 _shares,
address _onBehalf,
uint256 _getId,
bool _isRepay
) internal returns (MarketParams memory, uint256 _assets) {
uint256 _shareAmt = getUint(_getId, _shares);
bool _isEth = _marketParams.loanToken == ethAddr;
_marketParams = updateTokenAddresses(_marketParams);
// Handle the max share case
if (_shares == type(uint256).max) {
uint256 _maxAvailable = _isEth
? address(this).balance
: TokenInterface(_marketParams.loanToken).balanceOf(
address(this)
);
// If it's repay calculate the min of balance available and debt to repay
if (_isRepay) {
_assets = _maxAvailable.min(
getPaybackBalance(_marketParams, _onBehalf) // TODO: Ask
);
} else {
_assets = _maxAvailable;
}
} else {
(uint256 totalSupplyAssets, uint256 totalSupplyShares, , ) = MORPHO_BLUE.expectedMarketBalances(_marketParams);
_assets = _toAssetsUp(
_shareAmt,
totalSupplyAssets,
totalSupplyShares
);
}
// Perform ETH to WETH conversion if necessary
convertEthToWeth(
true,
TokenInterface(_marketParams.loanToken),
_assets
);
return (_marketParams, _assets);
}
/// @notice Returns the payback balance in assets.
function getPaybackBalance(
MarketParams memory _marketParams,
address _onBehalf
) internal view returns (uint256 _assets) {
Id _id = _marketParams.id();
uint256 _shareAmt = MORPHO_BLUE.position(_id, _onBehalf).supplyShares;
(uint256 totalSupplyAssets, uint256 totalSupplyShares, , ) = MORPHO_BLUE.expectedMarketBalances(_marketParams);
_assets = _toAssetsUp(
_shareAmt,
totalSupplyAssets,
totalSupplyShares
);
}
/// @notice Calculates the value of `shares` quoted in assets, rounding up.
function _toAssetsUp(
uint256 _shares,
uint256 _totalAssets,
uint256 _totalShares
) internal pure returns (uint256) {
return
_mulDivUp(
_shares,
_totalAssets + VIRTUAL_ASSETS,
_totalShares + VIRTUAL_SHARES
);
}
/// @notice Returns (`x` * `y`) / `d` rounded up.
function _mulDivUp(
uint256 x,
uint256 y,
uint256 d
) internal pure returns (uint256) {
return (x * y + (d - 1)) / d;
}
function updateTokenAddresses(
MarketParams memory _marketParams
) internal pure returns (MarketParams memory) {
_marketParams.loanToken = _marketParams.loanToken == ethAddr
? wethAddr
: _marketParams.loanToken;
_marketParams.collateralToken = _marketParams.collateralToken == ethAddr
? wethAddr
: _marketParams.collateralToken;
return _marketParams;
}
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IERC20
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @dev Empty because we only call library functions. It prevents calling transfer (transferFrom) instead of
/// safeTransfer (safeTransferFrom).
interface IERC20 {}

View File

@ -0,0 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {MarketParams, Market} from "./IMorpho.sol";
/// @title IIrm
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement.
interface IIrm {
/// @notice Returns the borrow rate of the market `marketParams`.
/// @dev Assumes that `market` corresponds to `marketParams`.
function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256);
/// @notice Returns the borrow rate of the market `marketParams` without modifying any storage.
/// @dev Assumes that `market` corresponds to `marketParams`.
function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256);
}

View File

@ -0,0 +1,350 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
type Id is bytes32;
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
struct Authorization {
address authorizer;
address authorized;
bool isAuthorized;
uint256 nonce;
uint256 deadline;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
/// @notice The EIP-712 domain separator.
/// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing
/// the same chain id because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s positions.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties
/// (funds could get stuck):
/// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.
/// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and
/// `toSharesDown` overflow.
/// - The IRM can revert on `borrowRate`.
/// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`
/// overflow.
/// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and
/// `liquidate` from being used under certain market conditions.
/// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or
/// the computation of `assetsRepaid` in `liquidate` overflow.
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific amount
/// of shares is given for full compatibility and precision.
/// @dev If the supply of a market gets depleted, the supply share price instantly resets to
/// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the caller
/// is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is given for
/// full compatibility and precision.
/// @dev If the borrow of a market gets depleted, the borrow share price instantly resets to
/// `VIRTUAL_ASSETS`:`VIRTUAL_SHARES`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoReplay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}

View File

@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IMorphoLiquidateCallback
/// @notice Interface that liquidators willing to use `liquidate`'s callback must implement.
interface IMorphoLiquidateCallback {
/// @notice Callback called when a liquidation occurs.
/// @dev The callback is called only if data is not empty.
/// @param repaidAssets The amount of repaid assets.
/// @param data Arbitrary data passed to the `liquidate` function.
function onMorphoLiquidate(uint256 repaidAssets, bytes calldata data) external;
}
/// @title IMorphoRepayCallback
/// @notice Interface that users willing to use `repay`'s callback must implement.
interface IMorphoRepayCallback {
/// @notice Callback called when a repayment occurs.
/// @dev The callback is called only if data is not empty.
/// @param assets The amount of repaid assets.
/// @param data Arbitrary data passed to the `repay` function.
function onMorphoRepay(uint256 assets, bytes calldata data) external;
}
/// @title IMorphoSupplyCallback
/// @notice Interface that users willing to use `supply`'s callback must implement.
interface IMorphoSupplyCallback {
/// @notice Callback called when a supply occurs.
/// @dev The callback is called only if data is not empty.
/// @param assets The amount of supplied assets.
/// @param data Arbitrary data passed to the `supply` function.
function onMorphoSupply(uint256 assets, bytes calldata data) external;
}
/// @title IMorphoSupplyCollateralCallback
/// @notice Interface that users willing to use `supplyCollateral`'s callback must implement.
interface IMorphoSupplyCollateralCallback {
/// @notice Callback called when a supply of collateral occurs.
/// @dev The callback is called only if data is not empty.
/// @param assets The amount of supplied collateral.
/// @param data Arbitrary data passed to the `supplyCollateral` function.
function onMorphoSupplyCollateral(uint256 assets, bytes calldata data) external;
}
/// @title IMorphoFlashLoanCallback
/// @notice Interface that users willing to use `flashLoan`'s callback must implement.
interface IMorphoFlashLoanCallback {
/// @notice Callback called when a flash loan occurs.
/// @dev The callback is called only if data is not empty.
/// @param assets The amount of assets that was flash loaned.
/// @param data Arbitrary data passed to the `flashLoan` function.
function onMorphoFlashLoan(uint256 assets, bytes calldata data) external;
}

View File

@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title IOracle
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Interface that oracles used by Morpho must implement.
/// @dev It is the user's responsibility to select markets with safe oracles.
interface IOracle {
/// @notice Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36.
/// @dev It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in
/// 10**(loan token decimals) assets of loan token with `36 + loan token decimals - collateral token decimals`
/// decimals of precision.
function price() external view returns (uint256);
}

View File

@ -0,0 +1,389 @@
This software is available under your choice of the GNU General Public
License, version 2 or later, or the Business Source License, as set
forth below.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: Morpho Association
Licensed Work: Morpho Blue Core
The Licensed Work is (c) 2023 Morpho Association
Additional Use Grant: Any uses listed and defined at
morpho-blue-core-license-grants.morpho.eth
Change Date: The earlier of (i) 2026-01-01, or (ii) a date specified
at morpho-blue-core-license-date.morpho.eth, or (iii)
upon the activation of the setFee function of the
Licensed Works applicable protocol smart contracts
deployed for production use.
Change License: GNU General Public License v2.0 or later
-----------------------------------------------------------------------------
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
-----------------------------------------------------------------------------
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.
-----------------------------------------------------------------------------
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
/// @dev The maximum fee a market can have (25%).
uint256 constant MAX_FEE = 0.25e18;
/// @dev Oracle price scale.
uint256 constant ORACLE_PRICE_SCALE = 1e36;
/// @dev Liquidation cursor.
uint256 constant LIQUIDATION_CURSOR = 0.3e18;
/// @dev Max liquidation incentive factor.
uint256 constant MAX_LIQUIDATION_INCENTIVE_FACTOR = 1.15e18;
/// @dev The EIP-712 typeHash for EIP712Domain.
bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
/// @dev The EIP-712 typeHash for Authorization.
bytes32 constant AUTHORIZATION_TYPEHASH =
keccak256("Authorization(address authorizer,address authorized,bool isAuthorized,uint256 nonce,uint256 deadline)");

View File

@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
/// @title ErrorsLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library exposing error messages.
library ErrorsLib {
/// @notice Thrown when the caller is not the owner.
string internal constant NOT_OWNER = "not owner";
/// @notice Thrown when the LLTV to enable exceeds the maximum LLTV.
string internal constant MAX_LLTV_EXCEEDED = "max LLTV exceeded";
/// @notice Thrown when the fee to set exceeds the maximum fee.
string internal constant MAX_FEE_EXCEEDED = "max fee exceeded";
/// @notice Thrown when the value is already set.
string internal constant ALREADY_SET = "already set";
/// @notice Thrown when the IRM is not enabled at market creation.
string internal constant IRM_NOT_ENABLED = "IRM not enabled";
/// @notice Thrown when the LLTV is not enabled at market creation.
string internal constant LLTV_NOT_ENABLED = "LLTV not enabled";
/// @notice Thrown when the market is already created.
string internal constant MARKET_ALREADY_CREATED = "market already created";
/// @notice Thrown when the market is not created.
string internal constant MARKET_NOT_CREATED = "market not created";
/// @notice Thrown when not exactly one of the input amount is zero.
string internal constant INCONSISTENT_INPUT = "inconsistent input";
/// @notice Thrown when zero assets is passed as input.
string internal constant ZERO_ASSETS = "zero assets";
/// @notice Thrown when a zero address is passed as input.
string internal constant ZERO_ADDRESS = "zero address";
/// @notice Thrown when the caller is not authorized to conduct an action.
string internal constant UNAUTHORIZED = "unauthorized";
/// @notice Thrown when the collateral is insufficient to `borrow` or `withdrawCollateral`.
string internal constant INSUFFICIENT_COLLATERAL = "insufficient collateral";
/// @notice Thrown when the liquidity is insufficient to `withdraw` or `borrow`.
string internal constant INSUFFICIENT_LIQUIDITY = "insufficient liquidity";
/// @notice Thrown when the position to liquidate is healthy.
string internal constant HEALTHY_POSITION = "position is healthy";
/// @notice Thrown when the authorization signature is invalid.
string internal constant INVALID_SIGNATURE = "invalid signature";
/// @notice Thrown when the authorization signature is expired.
string internal constant SIGNATURE_EXPIRED = "signature expired";
/// @notice Thrown when the nonce is invalid.
string internal constant INVALID_NONCE = "invalid nonce";
/// @notice Thrown when a token transfer reverted.
string internal constant TRANSFER_REVERTED = "transfer reverted";
/// @notice Thrown when a token transfer returned false.
string internal constant TRANSFER_RETURNED_FALSE = "transfer returned false";
/// @notice Thrown when a token transferFrom reverted.
string internal constant TRANSFER_FROM_REVERTED = "transferFrom reverted";
/// @notice Thrown when a token transferFrom returned false
string internal constant TRANSFER_FROM_RETURNED_FALSE = "transferFrom returned false";
/// @notice Thrown when the maximum uint128 is exceeded.
string internal constant MAX_UINT128_EXCEEDED = "max uint128 exceeded";
}

View File

@ -0,0 +1,147 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id, MarketParams} from "../interfaces/IMorpho.sol";
/// @title EventsLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library exposing events.
library EventsLib {
/// @notice Emitted when setting a new owner.
/// @param newOwner The new owner of the contract.
event SetOwner(address indexed newOwner);
/// @notice Emitted when setting a new fee.
/// @param id The market id.
/// @param newFee The new fee.
event SetFee(Id indexed id, uint256 newFee);
/// @notice Emitted when setting a new fee recipient.
/// @param newFeeRecipient The new fee recipient.
event SetFeeRecipient(address indexed newFeeRecipient);
/// @notice Emitted when enabling an IRM.
/// @param irm The IRM that was enabled.
event EnableIrm(address indexed irm);
/// @notice Emitted when enabling an LLTV.
/// @param lltv The LLTV that was enabled.
event EnableLltv(uint256 lltv);
/// @notice Emitted when creating a market.
/// @param id The market id.
/// @param marketParams The market that was created.
event CreateMarket(Id indexed id, MarketParams marketParams);
/// @notice Emitted on supply of assets.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address that received the supply.
/// @param assets The amount of assets supplied.
/// @param shares The amount of shares minted.
event Supply(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
/// @notice Emitted on withdrawal of assets.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address from which the assets were withdrawn.
/// @param receiver The address that received the withdrawn assets.
/// @param assets The amount of assets withdrawn.
/// @param shares The amount of shares burned.
event Withdraw(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 assets,
uint256 shares
);
/// @notice Emitted on borrow of assets.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address from which the assets were borrowed.
/// @param receiver The address that received the borrowed assets.
/// @param assets The amount of assets borrowed.
/// @param shares The amount of shares minted.
event Borrow(
Id indexed id,
address caller,
address indexed onBehalf,
address indexed receiver,
uint256 assets,
uint256 shares
);
/// @notice Emitted on repayment of assets.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address for which the assets were repaid.
/// @param assets The amount of assets repaid. May be 1 over the corresponding market's `totalBorrowAssets`.
/// @param shares The amount of shares burned.
event Repay(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets, uint256 shares);
/// @notice Emitted on supply of collateral.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address that received the collateral.
/// @param assets The amount of collateral supplied.
event SupplyCollateral(Id indexed id, address indexed caller, address indexed onBehalf, uint256 assets);
/// @notice Emitted on withdrawal of collateral.
/// @param id The market id.
/// @param caller The caller.
/// @param onBehalf The address from which the collateral was withdrawn.
/// @param receiver The address that received the withdrawn collateral.
/// @param assets The amount of collateral withdrawn.
event WithdrawCollateral(
Id indexed id, address caller, address indexed onBehalf, address indexed receiver, uint256 assets
);
/// @notice Emitted on liquidation of a position.
/// @param id The market id.
/// @param caller The caller.
/// @param borrower The borrower of the position.
/// @param repaidAssets The amount of assets repaid. May be 1 over the corresponding market's `totalBorrowAssets`.
/// @param repaidShares The amount of shares burned.
/// @param seizedAssets The amount of collateral seized.
/// @param badDebtShares The amount of shares minted as bad debt.
event Liquidate(
Id indexed id,
address indexed caller,
address indexed borrower,
uint256 repaidAssets,
uint256 repaidShares,
uint256 seizedAssets,
uint256 badDebtShares
);
/// @notice Emitted on flash loan.
/// @param caller The caller.
/// @param token The token that was flash loaned.
/// @param assets The amount that was flash loaned.
event FlashLoan(address indexed caller, address indexed token, uint256 assets);
/// @notice Emitted when setting an authorization.
/// @param caller The caller.
/// @param authorizer The authorizer address.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
event SetAuthorization(
address indexed caller, address indexed authorizer, address indexed authorized, bool newIsAuthorized
);
/// @notice Emitted when setting an authorization with a signature.
/// @param caller The caller.
/// @param authorizer The authorizer address.
/// @param usedNonce The nonce that was used.
event IncrementNonce(address indexed caller, address indexed authorizer, uint256 usedNonce);
/// @notice Emitted when accruing interest.
/// @param id The market id.
/// @param prevBorrowRate The previous borrow rate.
/// @param interest The amount of interest accrued.
/// @param feeShares The amount of shares minted as fee.
event AccrueInterest(Id indexed id, uint256 prevBorrowRate, uint256 interest, uint256 feeShares);
}

View File

@ -0,0 +1,389 @@
This software is available under your choice of the GNU General Public
License, version 2 or later, or the Business Source License, as set
forth below.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: Morpho Association
Licensed Work: Morpho Blue Core
The Licensed Work is (c) 2023 Morpho Association
Additional Use Grant: Any uses listed and defined at
morpho-blue-core-license-grants.morpho.eth
Change Date: The earlier of (i) 2026-01-01, or (ii) a date specified
at morpho-blue-core-license-date.morpho.eth, or (iii)
upon the activation of the setFee function of the
Licensed Works applicable protocol smart contracts
deployed for production use.
Change License: GNU General Public License v2.0 or later
-----------------------------------------------------------------------------
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
-----------------------------------------------------------------------------
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.
-----------------------------------------------------------------------------
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id, MarketParams} from "../interfaces/IMorpho.sol";
/// @title MarketParamsLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library to convert a market to its id.
library MarketParamsLib {
/// @notice The length of the data used to compute the id of a market.
/// @dev The length is 5 * 32 because `MarketParams` has 5 variables of 32 bytes each.
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
/// @notice Returns the id of the market `marketParams`.
function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) {
assembly ("memory-safe") {
marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH)
}
}
}

View File

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
uint256 constant WAD = 1e18;
/// @title MathLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library to manage fixed-point arithmetic.
library MathLib {
/// @dev Returns (`x` * `y`) / `WAD` rounded down.
function wMulDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
/// @dev Returns (`x` * `WAD`) / `y` rounded down.
function wDivDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
/// @dev Returns (`x` * `WAD`) / `y` rounded up.
function wDivUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
/// @dev Returns (`x` * `y`) / `d` rounded down.
function mulDivDown(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
return (x * y) / d;
}
/// @dev Returns (`x` * `y`) / `d` rounded up.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
return (x * y + (d - 1)) / d;
}
/// @dev Returns the sum of the first three non-zero terms of a Taylor expansion of e^(nx) - 1, to approximate a
/// continuous compound interest rate.
function wTaylorCompounded(uint256 x, uint256 n) internal pure returns (uint256) {
uint256 firstTerm = x * n;
uint256 secondTerm = mulDivDown(firstTerm, firstTerm, 2 * WAD);
uint256 thirdTerm = mulDivDown(secondTerm, firstTerm, 3 * WAD);
return firstTerm + secondTerm + thirdTerm;
}
}

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IERC20} from "../interfaces/IERC20.sol";
import {ErrorsLib} from "../libraries/ErrorsLib.sol";
interface IERC20Internal {
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
/// @title SafeTransferLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library to manage transfers of tokens, even if calls to the transfer or transferFrom functions are not
/// returning a boolean.
/// @dev It is the responsibility of the market creator to make sure that the address of the token has non-zero code.
library SafeTransferLib {
/// @dev Warning: It does not revert on `token` with no code.
function safeTransfer(IERC20 token, address to, uint256 value) internal {
(bool success, bytes memory returndata) =
address(token).call(abi.encodeCall(IERC20Internal.transfer, (to, value)));
require(success, ErrorsLib.TRANSFER_REVERTED);
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TRANSFER_RETURNED_FALSE);
}
/// @dev Warning: It does not revert on `token` with no code.
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
(bool success, bytes memory returndata) =
address(token).call(abi.encodeCall(IERC20Internal.transferFrom, (from, to, value)));
require(success, ErrorsLib.TRANSFER_FROM_REVERTED);
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TRANSFER_FROM_RETURNED_FALSE);
}
}

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {MathLib} from "./MathLib.sol";
/// @title SharesMathLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Shares management library.
/// @dev This implementation mitigates share price manipulations, using OpenZeppelin's method of virtual shares:
/// https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack.
library SharesMathLib {
using MathLib for uint256;
/// @dev The number of virtual shares has been chosen low enough to prevent overflows, and high enough to ensure
/// high precision computations.
uint256 internal constant VIRTUAL_SHARES = 1e6;
/// @dev A number of virtual assets of 1 enforces a conversion rate between shares and assets when a market is
/// empty.
uint256 internal constant VIRTUAL_ASSETS = 1;
/// @dev Calculates the value of `assets` quoted in shares, rounding down.
function toSharesDown(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return assets.mulDivDown(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
}
/// @dev Calculates the value of `shares` quoted in assets, rounding down.
function toAssetsDown(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return shares.mulDivDown(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
}
/// @dev Calculates the value of `assets` quoted in shares, rounding up.
function toSharesUp(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return assets.mulDivUp(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
}
/// @dev Calculates the value of `shares` quoted in assets, rounding up.
function toAssetsUp(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return shares.mulDivUp(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
}
}

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {ErrorsLib} from "../libraries/ErrorsLib.sol";
/// @title UtilsLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library exposing helpers.
/// @dev Inspired by https://github.com/morpho-org/morpho-utils.
library UtilsLib {
/// @dev Returns true if there is exactly one zero among `x` and `y`.
function exactlyOneZero(uint256 x, uint256 y) internal pure returns (bool z) {
assembly {
z := xor(iszero(x), iszero(y))
}
}
/// @dev Returns the min of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns `x` safely cast to uint128.
function toUint128(uint256 x) internal pure returns (uint128) {
require(x <= type(uint128).max, ErrorsLib.MAX_UINT128_EXCEEDED);
return uint128(x);
}
/// @dev Returns max(x - y, 0).
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
}

View File

@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id, MarketParams, Market, IMorpho} from "../../interfaces/IMorpho.sol";
import {IIrm} from "../../interfaces/IIrm.sol";
import {MathLib} from "../MathLib.sol";
import {UtilsLib} from "../UtilsLib.sol";
import {MorphoLib} from "./MorphoLib.sol";
import {SharesMathLib} from "../SharesMathLib.sol";
import {MarketParamsLib} from "../MarketParamsLib.sol";
/// @title MorphoBalancesLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Helper library exposing getters with the expected value after interest accrual.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
/// @dev The getter to retrieve the expected total borrow shares is not exposed because interest accrual does not apply
/// to it. The value can be queried directly on Morpho using `totalBorrowShares`.
library MorphoBalancesLib {
using MathLib for uint256;
using MathLib for uint128;
using UtilsLib for uint256;
using MorphoLib for IMorpho;
using SharesMathLib for uint256;
using MarketParamsLib for MarketParams;
/// @notice Returns the expected market balances of a market after having accrued interest.
/// @return The expected total supply assets.
/// @return The expected total supply shares.
/// @return The expected total borrow assets.
/// @return The expected total borrow shares.
function expectedMarketBalances(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256, uint256, uint256, uint256)
{
Id id = marketParams.id();
Market memory market = morpho.market(id);
uint256 elapsed = block.timestamp - market.lastUpdate;
// Skipped if elapsed == 0 of if totalBorrowAssets == 0 because interest would be null.
if (elapsed != 0 && market.totalBorrowAssets != 0) {
uint256 borrowRate = IIrm(marketParams.irm).borrowRateView(marketParams, market);
uint256 interest = market.totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market.totalBorrowAssets += interest.toUint128();
market.totalSupplyAssets += interest.toUint128();
if (market.fee != 0) {
uint256 feeAmount = interest.wMulDown(market.fee);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact
// that total supply is already updated.
uint256 feeShares =
feeAmount.toSharesDown(market.totalSupplyAssets - feeAmount, market.totalSupplyShares);
market.totalSupplyShares += feeShares.toUint128();
}
}
return (market.totalSupplyAssets, market.totalSupplyShares, market.totalBorrowAssets, market.totalBorrowShares);
}
/// @notice Returns the expected total supply assets of a market after having accrued interest.
function expectedTotalSupplyAssets(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalSupplyAssets)
{
(totalSupplyAssets,,,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected total borrow assets of a market after having accrued interest.
function expectedTotalBorrowAssets(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalBorrowAssets)
{
(,, totalBorrowAssets,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected total supply shares of a market after having accrued interest.
function expectedTotalSupplyShares(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalSupplyShares)
{
(, totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected supply assets balance of `user` on a market after having accrued interest.
/// @dev Warning: Wrong for `feeRecipient` because their supply shares increase is not taken into account.
/// @dev Warning: Withdrawing a supply position using the expected assets balance can lead to a revert due to
/// conversion roundings between shares and assets.
function expectedSupplyAssets(IMorpho morpho, MarketParams memory marketParams, address user)
internal
view
returns (uint256)
{
Id id = marketParams.id();
uint256 supplyShares = morpho.supplyShares(id, user);
(uint256 totalSupplyAssets, uint256 totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);
return supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);
}
/// @notice Returns the expected borrow assets balance of `user` on a market after having accrued interest.
/// @dev Warning: repaying a borrow position using the expected assets balance can lead to a revert due to
/// conversion roundings between shares and assets.
function expectedBorrowAssets(IMorpho morpho, MarketParams memory marketParams, address user)
internal
view
returns (uint256)
{
Id id = marketParams.id();
uint256 borrowShares = morpho.borrowShares(id, user);
(,, uint256 totalBorrowAssets, uint256 totalBorrowShares) = expectedMarketBalances(morpho, marketParams);
return borrowShares.toAssetsUp(totalBorrowAssets, totalBorrowShares);
}
}

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IMorpho, Id} from "../../interfaces/IMorpho.sol";
import {MorphoStorageLib} from "./MorphoStorageLib.sol";
/// @title MorphoLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Helper library to access Morpho storage variables.
/// @dev Warning: Supply and borrow getters may return outdated values that do not include accrued interest.
library MorphoLib {
function supplyShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionSupplySharesSlot(id, user));
return uint256(morpho.extSloads(slot)[0]);
}
function borrowShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function collateral(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function totalSupplyAssets(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function totalSupplyShares(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function totalBorrowAssets(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function totalBorrowShares(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function lastUpdate(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function fee(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function _array(bytes32 x) private pure returns (bytes32[] memory) {
bytes32[] memory res = new bytes32[](1);
res[0] = x;
return res;
}
}

View File

@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id} from "../../interfaces/IMorpho.sol";
/// @title MorphoStorageLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Helper library exposing getters to access Morpho storage variables' slot.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
library MorphoStorageLib {
/* SLOTS */
uint256 internal constant OWNER_SLOT = 0;
uint256 internal constant FEE_RECIPIENT_SLOT = 1;
uint256 internal constant POSITION_SLOT = 2;
uint256 internal constant MARKET_SLOT = 3;
uint256 internal constant IS_IRM_ENABLED_SLOT = 4;
uint256 internal constant IS_LLTV_ENABLED_SLOT = 5;
uint256 internal constant IS_AUTHORIZED_SLOT = 6;
uint256 internal constant NONCE_SLOT = 7;
uint256 internal constant ID_TO_MARKET_PARAMS_SLOT = 8;
/* SLOT OFFSETS */
uint256 internal constant LOAN_TOKEN_OFFSET = 0;
uint256 internal constant COLLATERAL_TOKEN_OFFSET = 1;
uint256 internal constant ORACLE_OFFSET = 2;
uint256 internal constant IRM_OFFSET = 3;
uint256 internal constant LLTV_OFFSET = 4;
uint256 internal constant SUPPLY_SHARES_OFFSET = 0;
uint256 internal constant BORROW_SHARES_AND_COLLATERAL_OFFSET = 1;
uint256 internal constant TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET = 0;
uint256 internal constant TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET = 1;
uint256 internal constant LAST_UPDATE_AND_FEE_OFFSET = 2;
/* GETTERS */
function ownerSlot() internal pure returns (bytes32) {
return bytes32(OWNER_SLOT);
}
function feeRecipientSlot() internal pure returns (bytes32) {
return bytes32(FEE_RECIPIENT_SLOT);
}
function positionSupplySharesSlot(Id id, address user) internal pure returns (bytes32) {
return bytes32(
uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT))))) + SUPPLY_SHARES_OFFSET
);
}
function positionBorrowSharesAndCollateralSlot(Id id, address user) internal pure returns (bytes32) {
return bytes32(
uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT)))))
+ BORROW_SHARES_AND_COLLATERAL_OFFSET
);
}
function marketTotalSupplyAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET);
}
function marketTotalBorrowAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET);
}
function marketLastUpdateAndFeeSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + LAST_UPDATE_AND_FEE_OFFSET);
}
function isIrmEnabledSlot(address irm) internal pure returns (bytes32) {
return keccak256(abi.encode(irm, IS_IRM_ENABLED_SLOT));
}
function isLltvEnabledSlot(uint256 lltv) internal pure returns (bytes32) {
return keccak256(abi.encode(lltv, IS_LLTV_ENABLED_SLOT));
}
function isAuthorizedSlot(address authorizer, address authorizee) internal pure returns (bytes32) {
return keccak256(abi.encode(authorizee, keccak256(abi.encode(authorizer, IS_AUTHORIZED_SLOT))));
}
function nonceSlot(address authorizer) internal pure returns (bytes32) {
return keccak256(abi.encode(authorizer, NONCE_SLOT));
}
function idToLoanTokenSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LOAN_TOKEN_OFFSET);
}
function idToCollateralTokenSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + COLLATERAL_TOKEN_OFFSET);
}
function idToOracleSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + ORACLE_OFFSET);
}
function idToIrmSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + IRM_OFFSET);
}
function idToLltvSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LLTV_OFFSET);
}
}

View File

@ -0,0 +1,915 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./helpers.sol";
import "./events.sol";
import { MarketParamsLib } from "./libraries/MarketParamsLib.sol";
abstract contract MorphoBlue is Helpers, Events {
using MarketParamsLib for MarketParams;
/**
* @dev Supply ETH/ERC20 Token for lending.
* @notice Supplies assets to Morpho Blue for lending.
* @param _marketParams The market to supply assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _assets The amount of assets to supply. (For max: `uint256(-1)`)
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function supply(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt
) = _performEthToWethConversion(
_marketParams,
_assets,
address(this),
_getId,
Mode.Supply
);
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_amt
);
uint256 _shares;
(_assets, _shares) = MORPHO_BLUE.supply(
_marketParams,
_amt,
0,
address(this),
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogSupplyAssets((address,address,address,address,unit256),unit256,unit256,unit256,unit256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_getId,
_setId
);
}
/**
* @dev Supply ETH/ERC20 Token for lending.
* @notice Supplies assets to Morpho Blue for lending.
* @param _marketParams The market to supply assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _assets The amount of assets to supply. (For max: `uint256(-1)`)
* @param _onBehalf The address that will get the shares.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function supplyOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt
) = _performEthToWethConversion(
_marketParams,
_assets,
_onBehalf,
_getId,
Mode.Supply
);
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_amt
);
uint256 _shares;
(_assets, _shares) = MORPHO_BLUE.supply(
_marketParams,
_amt,
0,
_onBehalf,
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogSupplyOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_onBehalf,
_getId,
_setId
);
}
/**
* @dev Supply ETH/ERC20 Token for lending.
* @notice Supplies assets for a perfect share amount to Morpho Blue for lending.
* @param _marketParams The market to supply assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _shares The exact amount of shares to mint. (For max: `uint256(-1)`)
* @param _onBehalf The address that will get the shares.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function supplySharesOnBehalf(
MarketParams memory _marketParams,
uint256 _shares,
address _onBehalf,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt // Shares amount converted to assets
) = _performEthToWethSharesConversion(
_marketParams,
_shares,
_onBehalf,
_getId,
false
);
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_amt
);
(uint256 _assets, ) = MORPHO_BLUE.supply(
_marketParams,
_amt,
_shares,
_onBehalf,
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogSupplyOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_onBehalf,
_getId,
_setId
);
}
/**
* @notice Supply ETH/ERC20 Token for collateralization.
* @param _marketParams The market to supply assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _assets The amount of assets to supply. (For max: `uint256(-1)`)
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function supplyCollateral(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt
) = _performEthToWethConversion(
_marketParams,
_assets,
address(this),
_getId,
Mode.Collateral
);
// Approving collateral token
approve(
TokenInterface(_marketParams.collateralToken),
address(MORPHO_BLUE),
_amt
);
MORPHO_BLUE.supplyCollateral(
_marketParams,
_amt,
address(this),
new bytes(0)
);
setUint(_setId, _amt);
_eventName = "LogSupplyCollateral((address,address,address,address,unit256),uint256,uint256,uint256)";
_eventParam = abi.encode(_marketParams, _assets, _getId, _setId);
}
/**
* @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's `onMorphoSupplyCollateral` function with the given `data`.
* @param _marketParams The market to supply assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _assets The amount of assets to supply. (For max: `uint256(-1)`)
* @param _onBehalf The address that will get the shares.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function supplyCollateralOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
// Final assets amount and token contract
(
_marketParams, // Updated token contracts in case of Eth
_amt
) = _performEthToWethConversion(
_marketParams,
_assets,
_onBehalf,
_getId,
Mode.Collateral
);
// Approving collateral token
approve(
TokenInterface(_marketParams.collateralToken),
address(MORPHO_BLUE),
_amt
);
MORPHO_BLUE.supplyCollateral(
_marketParams,
_amt,
_onBehalf,
new bytes(0)
);
setUint(_setId, _amt);
_eventName = "LogSupplyCollateralOnBehalf((address,address,address,address,unit256),uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_onBehalf,
_getId,
_setId
);
}
/**
* @notice Handles the collateral withdrawals.
* @dev The market to withdraw assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to withdraw assets from.
* @param _assets The amount of assets to withdraw. (For max: `uint256(-1)`)
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function withdrawCollateral(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
// If amount is max, fetch collateral value from Morpho's contract
if (_amt == type(uint256).max) {
Id _id = _marketParams.id();
Position memory _pos = MORPHO_BLUE.position(_id, address(this));
_amt = _pos.collateral;
}
MORPHO_BLUE.withdrawCollateral(
_marketParams,
_amt,
address(this),
address(this)
);
convertWethToEth(
_marketParams.collateralToken == ethAddr,
TokenInterface(wethAddr),
_amt
);
setUint(_setId, _amt);
_eventName = "LogWithdrawCollateral((address,address,address,address,unit256),uint256,uint256,uint256)";
_eventParam = abi.encode(_marketParams, _amt, _getId, _setId);
}
/**
* @notice Handles the withdrawal of collateral by a user from a specific market of a specific amount.
* @dev The market to withdraw assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to withdraw assets from.
* @param _assets The amount of assets to withdraw. (For max: `uint256(-1)`)
* @param _onBehalf The address that already deposited position.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function withdrawCollateralOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
address _receiver,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
// If amount is max, fetch collateral value from Morpho's contract
if (_amt == type(uint256).max) {
Id _id = _marketParams.id();
Position memory _pos = MORPHO_BLUE.position(_id, _onBehalf);
_amt = _pos.collateral;
}
MORPHO_BLUE.withdrawCollateral(
_marketParams,
_amt,
_onBehalf,
_receiver
);
if (_receiver == address(this))
convertWethToEth(
_marketParams.collateralToken == ethAddr,
TokenInterface(wethAddr),
_amt
);
setUint(_setId, _amt);
_eventName = "LogWithdrawCollateralOnBehalf((address,address,address,address,unit256),uint256,address,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_amt,
_onBehalf,
_receiver,
_getId,
_setId
);
}
/**
* @notice Handles the withdrawal of supply.
* @dev The market to withdraw assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to withdraw assets from.
* @param _assets The amount of assets to withdraw. (For max: `uint256(-1)`)
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function withdraw(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
uint256 _shares = 0;
// Using shares for max amounts to make sure no dust is left on the contract
if (_amt == type(uint256).max) {
Id _id = _marketParams.id();
Position memory _pos = MORPHO_BLUE.position(_id, address(this));
_shares = _pos.supplyShares;
_amt = 0;
}
// In case of max share amount will be used
(_assets, _shares) = MORPHO_BLUE.withdraw(
_marketParams,
_amt,
_shares,
address(this),
address(this)
);
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_assets
);
setUint(_setId, _assets);
_eventName = "LogWithdraw((address,address,address,address,unit256),uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_getId,
_setId
);
}
/**
* @notice Handles the withdrawal of a specified amount of assets by a user from a specific market.
* @dev The market to withdraw assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The parameters of the market.
* @param _assets The amount of assets the user is withdrawing. (For max: `uint256(-1)`)
* @param _onBehalf The address who's position to withdraw from.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function withdrawOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
address _receiver,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
uint256 _shares = 0;
// Using shares for max amounts to make sure no dust is left on the contract
if (_amt == type(uint256).max) {
Id _id = _marketParams.id();
Position memory _pos = MORPHO_BLUE.position(_id, _onBehalf);
_shares = _pos.supplyShares;
_amt = 0;
}
(_assets, _shares) = MORPHO_BLUE.withdraw(
_marketParams,
_amt,
_shares,
_onBehalf,
_receiver
);
if (_receiver == address(this))
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_assets
);
setUint(_setId, _assets);
_eventName = "LogWithdrawOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_onBehalf,
_getId,
_setId
);
}
/**
* @notice Handles the withdrawal of a specified amount of assets by a user from a specific market.
* @dev The market to withdraw assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The parameters of the market.
* @param _shares The amount of shares the user is withdrawing. (For max: `uint256(-1)`)
* @param _onBehalf The address who's position to withdraw from.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens deposited.
*/
function withdrawSharesOnBehalf(
MarketParams memory _marketParams,
uint256 _shares,
address _onBehalf,
address _receiver,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _shareAmt = getUint(_getId, _shares);
_marketParams = updateTokenAddresses(_marketParams);
if (_shareAmt == type(uint256).max) {
Id _id = _marketParams.id();
Position memory _pos = MORPHO_BLUE.position(_id, _onBehalf);
_shareAmt = _pos.supplyShares;
}
(uint256 _assets, ) = MORPHO_BLUE.withdraw(
_marketParams,
0,
_shareAmt,
_onBehalf,
_receiver
);
if (_receiver == address(this))
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_assets
);
setUint(_setId, _assets);
_eventName = "LogWithdrawOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shareAmt,
_onBehalf,
_getId,
_setId
);
}
/**
* @notice Borrows assets.
* @dev The market to borrow assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to borrow assets from.
* @param _assets The amount of assets to borrow.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens borrowed.
*/
function borrow(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
(, uint256 _shares) = MORPHO_BLUE.borrow(
_marketParams,
_amt,
0,
address(this),
address(this)
);
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_amt
);
setUint(_setId, _amt);
_eventName = "LogBorrow((address,address,address,address,unit256),uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(_marketParams, _amt, _shares, _getId, _setId);
}
/**
* @notice Borrows `assets` on behalf of `onBehalf` to `receiver`.
* @dev The market to borrow assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to borrow assets from.
* @param _assets The amount of assets to borrow.
* @param _onBehalf The address that will recieve the borrowing assets and own the borrow position.
* @param _receiver The address that will recieve the borrowed assets.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens borrowed.
*/
function borrowOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
address _receiver,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt = getUint(_getId, _assets);
_marketParams = updateTokenAddresses(_marketParams);
(, uint256 _shares) = MORPHO_BLUE.borrow(
_marketParams,
_amt,
0,
_onBehalf,
_receiver
);
if (_receiver == address(this))
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_amt
);
setUint(_setId, _amt);
_eventName = "LogBorrowOnBehalf((address,address,address,address,unit256),uint256,uint256,address,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_amt,
_shares,
_onBehalf,
_receiver,
_getId,
_setId
);
}
/**
* @notice Borrows `shares` on behalf of `onBehalf` to `receiver`.
* @dev The market to borrow assets from. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to borrow assets from.
* @param _shares The amount of shares to mint.
* @param _onBehalf The address that will own the borrow position.
* @param _receiver The address that will recieve the borrowed assets.
* @param _getId ID to retrieve shares amt.
* @param _setId ID stores the amount of tokens borrowed.
*/
function borrowOnBehalfShares(
MarketParams memory _marketParams,
uint256 _shares,
address _onBehalf,
address _receiver,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _shareAmt = getUint(_getId, _shares);
_marketParams = updateTokenAddresses(_marketParams);
(uint256 _assets, ) = MORPHO_BLUE.borrow(
_marketParams,
0,
_shareAmt,
_onBehalf,
_receiver
);
if (_receiver == address(this))
convertWethToEth(
_marketParams.loanToken == ethAddr,
TokenInterface(wethAddr),
_assets
);
setUint(_setId, _assets);
_eventName = "LogBorrowOnBehalf((address,address,address,address,unit256),uint256,uint256,address,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shareAmt,
_onBehalf,
_receiver,
_getId,
_setId
);
}
/**
* @notice Repay assets.
* @dev The market to repay assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to repay assets to.
* @param _assets The amount of assets to repay. (For max: `uint256(-1)`)
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens repaid.
*/
function repay(
MarketParams memory _marketParams,
uint256 _assets,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt // Assets final amount to repay
) = _performEthToWethConversion(
_marketParams,
_assets,
address(this),
_getId,
Mode.Repay
);
// Approving loan token for repaying
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_amt
);
uint256 _shares;
(_assets, _shares) = MORPHO_BLUE.repay(
_marketParams,
_amt,
0,
address(this),
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogRepay((address,address,address,address,unit256),uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_getId,
_setId
);
}
/**
* @notice Repays assets on behalf.
* @dev The market to repay assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to repay assets to.
* @param _assets The amount of assets to repay. (For max: `uint256(-1)`)
* @param _onBehalf The address whose loan will be repaid.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens repaid.
*/
function repayOnBehalf(
MarketParams memory _marketParams,
uint256 _assets,
address _onBehalf,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _amt;
(
_marketParams, // Updated token contracts in case of Eth
_amt // Assets final amount to repay
) = _performEthToWethConversion(
_marketParams,
_assets,
_onBehalf,
_getId,
Mode.Repay
);
// Approving loan token for repaying
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_amt
);
uint256 _shares;
(_assets, _shares) = MORPHO_BLUE.repay(
_marketParams,
_amt,
0,
_onBehalf,
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogRepayOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_onBehalf,
_getId,
_setId
);
}
/**
* @notice Repays shares on behalf.
* @dev The market to repay assets to. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)
* @param _marketParams The market to repay assets to.
* @param _shares The amount of shares to burn. (For max: `uint256(-1)`)
* @param _onBehalf The address whose loan will be repaid.
* @param _getId ID to retrieve amt.
* @param _setId ID stores the amount of tokens repaid.
*/
function repayOnBehalfShares(
MarketParams memory _marketParams,
uint256 _shares,
address _onBehalf,
uint256 _getId,
uint256 _setId
)
external
payable
returns (string memory _eventName, bytes memory _eventParam)
{
uint256 _assetsAmt;
(
_marketParams, // Updated token contracts in case of Eth
_assetsAmt // Assets final amount to repay
) = _performEthToWethSharesConversion(
_marketParams,
_shares,
_onBehalf,
_getId,
true
);
approve(
TokenInterface(_marketParams.loanToken),
address(MORPHO_BLUE),
_assetsAmt
);
(uint256 _assets, ) = MORPHO_BLUE.repay(
_marketParams,
_assetsAmt,
0,
_onBehalf,
new bytes(0)
);
setUint(_setId, _assets);
_eventName = "LogRepayOnBehalf((address,address,address,address,unit256),uint256,uint256,address,uint256,uint256)";
_eventParam = abi.encode(
_marketParams,
_assets,
_shares,
_onBehalf,
_getId,
_setId
);
}
}
contract ConnectV2MorphoBlue is MorphoBlue {
string public constant name = "Morpho-Blue-v1.0";
}