Address Contract Partially Verified
Address
0x78eFE4C14D6eC324060bF751C82548E52Fd59586
Balance
0 ETH
Nonce
1
Code Size
2872 bytes
Creator
0x6b22171a...a262 at tx 0x3a31d98d...e413ad
Indexed Transactions
0
Contract Bytecode
2872 bytes
0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c80630dc913061461004e57806332cdc4ad146100865780633acb56241461009b578063b2082124146100b6575b5f80fd5b61006973e592427a0aece92de3edee1f18e0157c0586156481565b6040516001600160a01b0390911681526020015b60405180910390f35b6100996100943660046107fb565b6100d3565b005b61006973bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb81565b6100c5670de0b6b3a764000081565b60405190815260200161007d565b8387608001511015604051806040016040528060118152602001701b585e081313151588195e18d959591959607a1b8152509061012c5760405162461bcd60e51b8152600401610123919061091f565b60405180910390fd5b5060408051808201909152600b81526a063616e6e6f7420626520360ac1b60208201528561016d5760405162461bcd60e51b8152600401610123919061091f565b5060408051808201909152600c81526b7a65726f206164647265737360a01b60208201526001600160a01b0384166101b85760405162461bcd60e51b8152600401610123919061091f565b5060208701516040516323b872dd60e01b8152336004820152306024820152604481018790526001600160a01b03909116906323b872dd906064016020604051808303815f875af115801561020f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102339190610938565b50602087015160405163095ea7b360e01b815273bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb6004820152602481018790526001600160a01b039091169063095ea7b3906044016020604051808303815f875af1158015610298573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102bc9190610938565b5060405163238d657960e01b815273bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb9063238d6579906102fc908a908990889088908890600401610996565b5f604051808303815f87803b158015610313575f80fd5b505af1158015610325573d5f803e3d5ffd5b505050505f87604001516001600160a01b031663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561036a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038e91906109ee565b90505f670de0b6b3a76400008080886103a7868c610a05565b6103b19190610a05565b6103bb9190610a2e565b6103c59190610a2e565b6103cf9190610a2e565b6040516350d8cd4b60e01b81529091505f9073bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb906350d8cd4b90610413908d90869086908c903090600401610a4d565b60408051808303815f875af115801561042e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104529190610a89565b508a5160405163095ea7b360e01b815273e592427a0aece92de3edee1f18e0157c058615646004820152602481018390529192506001600160a01b03169063095ea7b3906044016020604051808303815f875af11580156104b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104d99190610938565b506060890181905260405163c04b8d5960e01b81525f9073e592427a0aece92de3edee1f18e0157c058615649063c04b8d599061051a908d90600401610aab565b6020604051808303815f875af1158015610536573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061055a91906109ee565b60208c015160405163095ea7b360e01b815273bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb6004820152602481018390529192506001600160a01b03169063095ea7b3906044016020604051808303815f875af11580156105bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e39190610938565b5060405163238d657960e01b815273bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb9063238d657990610623908e9085908c908c908c90600401610996565b5f604051808303815f87803b15801561063a575f80fd5b505af115801561064c573d5f803e3d5ffd5b505050505050505050505050505050565b634e487b7160e01b5f52604160045260245ffd5b60405160a0810167ffffffffffffffff811182821017156106945761069461065d565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156106c3576106c361065d565b604052919050565b80356001600160a01b03811681146106e1575f80fd5b919050565b5f60a082840312156106f6575f80fd5b6106fe610671565b9050813567ffffffffffffffff811115610716575f80fd5b8201601f81018413610726575f80fd5b803567ffffffffffffffff8111156107405761074061065d565b610753601f8201601f191660200161069a565b818152856020838501011115610767575f80fd5b816020840160208301375f6020838301015280845250505061078b602083016106cb565b6020820152604082810135908201526060808301359082015260809182013591810191909152919050565b5f8083601f8401126107c6575f80fd5b50813567ffffffffffffffff8111156107dd575f80fd5b6020830191508360208285010111156107f4575f80fd5b9250929050565b5f805f805f805f878903610140811215610813575f80fd5b60a0811215610820575f80fd5b50610829610671565b610832896106cb565b815261084060208a016106cb565b602082015261085160408a016106cb565b604082015261086260608a016106cb565b606082015260808981013590820152965060a088013567ffffffffffffffff81111561088c575f80fd5b6108988a828b016106e6565b96505060c0880135945060e088013593506108b661010089016106cb565b925061012088013567ffffffffffffffff8111156108d2575f80fd5b6108de8a828b016107b6565b989b979a50959850939692959293505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f61093160208301846108f1565b9392505050565b5f60208284031215610948575f80fd5b81518015158114610931575f80fd5b80516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015190911690830152608090810151910152565b6109a08187610957565b60a081018590526001600160a01b03841660c082015261010060e08201819052810182905281836101208301375f81830161012090810191909152601f909201601f19160101949350505050565b5f602082840312156109fe575f80fd5b5051919050565b8082028115828204841417610a2857634e487b7160e01b5f52601160045260245ffd5b92915050565b5f82610a4857634e487b7160e01b5f52601260045260245ffd5b500490565b6101208101610a5c8288610957565b60a082019590955260c08101939093526001600160a01b0391821660e08401521661010090910152919050565b5f8060408385031215610a9a575f80fd5b505080516020909101519092909150565b602081525f825160a06020840152610ac660c08401826108f1565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a0840152809150509291505056fea26469706673582212202d3219d8488ef4272399b0f5608af71c5d67c8028df6365fae96ff86c298eee264736f6c634300081a0033
Verified Source Code Partial Match
Compiler: v0.8.26+commit.8a97fa7a
EVM: cancun
Optimization: Yes (200 runs)
IMFMorphoSuperLoop.sol 652 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0 ^0.8.0 ^0.8.19 ^0.8.20;
pragma abicoder v2;
// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
// src/interfaces/IMorpho.sol
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 chains sharing the
/// same chain id and on forks 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 position on all markets.
/// @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`.
/// @param newFee The new fee, scaled by WAD.
/// @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 assumptions on the market's dependencies which, if broken, could break Morpho's liveness
/// properties (funds could get stuck):
/// - The token should not revert on `transfer` and `transferFrom` if balances and approvals are right.
/// - The amount of assets supplied and borrowed should not go above ~1e35 (otherwise the computation of
/// `toSharesUp` and `toSharesDown` can overflow).
/// - The IRM should not revert on `borrowRate`.
/// - The IRM should not return a very high borrow rate (otherwise the computation of `interest` in
/// `_accrueInterest` can overflow).
/// - The oracle should not revert `price`.
/// - The oracle should not return a very high price (otherwise the computation of `maxBorrow` in `_isHealthy` or of
/// `assetsRepaid` in `liquidate` can 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 use cases 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 Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @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` and sends the assets 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` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases 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 `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @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
/// `onMorphoRepay` 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.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @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` and sends the assets 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.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @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 [email protected]
/// @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);
}
// src/interfaces/IOracle.sol
/// @title IOracle
/// @author an IMFer
/// @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);
}
// src/interfaces/ISwapRouter.sol
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}
// src/libraries/ErrorsLib.sol
/// @title ErrorsLib
/// @author an IMFer
/// @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 a token to transfer doesn't have code.
string internal constant NO_CODE = "no code";
/// @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 withdraw collateral.
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";
// Additional errors for this contract:
string internal constant APPROVAL_NOT_SUCCESSFUL = "token approval failed";
string internal constant MARKET_NOT_ENABLED = "market not enabled";
string internal constant MARKET_IS_PAUSED = "market is paused";
string internal constant SYSTEM_IS_PAUSED = "system is paused";
string internal constant CANNOT_BE_ZERO = "cannot be 0";
string internal constant NO_USER_POSITION = "no user position";
string internal constant MARKET_ALREADY_ENABLED = "market already enabled";
string internal constant POOL_DOESNT_EXIST = "pool doesn't exist";
string internal constant POOL_TOKENS_MISMATCH = "pool tokens mismatch";
string internal constant INVALID_TICK_SPACING = "tick spacing must be positive";
string internal constant BASE_TOKEN_MISSING = "base token not in pool";
}
// src/IMFMorphoSuperLoop.sol
contract IMFMorphoSuperLoop {
uint256 public constant ORACLE_PRICE_SCALE = 1 ether;
IMorphoBase public constant MORPHO = IMorphoBase(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
ISwapRouter public constant v3Router = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
constructor() {}
function superLoop(
MarketParams memory marketParams,
ISwapRouter.ExactInputParams memory swapParamsIn,
uint256 collateralAssetAmount,
uint256 borrowPct,
address onBehalf,
bytes calldata data
) external {
require(marketParams.lltv >= borrowPct, ErrorsLib.MAX_LLTV_EXCEEDED);
require(collateralAssetAmount > 0, ErrorsLib.CANNOT_BE_ZERO);
require(onBehalf != address(0), ErrorsLib.ZERO_ADDRESS);
// 1. supply collateral
IERC20(marketParams.collateralToken).transferFrom(msg.sender, address(this), collateralAssetAmount);
IERC20(marketParams.collateralToken).approve(address(MORPHO), collateralAssetAmount);
MORPHO.supplyCollateral(marketParams, collateralAssetAmount, onBehalf, data);
// 2. get collateral price from oracle
uint256 price = IOracle(marketParams.oracle).price();
// 3. Calculate max borrowable amount
uint256 maxBorrowAssets = ((((collateralAssetAmount * price * borrowPct) / ORACLE_PRICE_SCALE) /
ORACLE_PRICE_SCALE) / ORACLE_PRICE_SCALE);
// 4. borrow assets
(uint256 assestBorrowed,) = MORPHO.borrow(marketParams, maxBorrowAssets, 0, onBehalf, address(this));
// 5. swap it back to the collateral asset
IERC20(marketParams.loanToken).approve(address(v3Router), assestBorrowed);
swapParamsIn.amountIn = assestBorrowed;
uint256 collateralReceived = v3Router.exactInput(swapParamsIn);
// 6. close the superloop
IERC20(marketParams.collateralToken).approve(address(MORPHO), collateralReceived);
MORPHO.supplyCollateral(marketParams, collateralReceived, onBehalf, data);
}
}
Read Contract
MORPHO 0x3acb5624 → address
ORACLE_PRICE_SCALE 0xb2082124 → uint256
v3Router 0x0dc91306 → address
Write Contract 1 functions
These functions modify contract state and require a wallet transaction to execute.
superLoop 0xb26c84f3
tuple marketParams
tuple swapParamsIn
uint256 collateralAssetAmount
uint256 borrowPct
address onBehalf
bytes data
Recent Transactions
No transactions found for this address