Overview
S Balance
S Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 2 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
9102286 | 17 days ago | Contract Creation | 0 S | |||
9102286 | 17 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PreLiquidationFactory
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 999999 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.8.27; import {IPreLiquidation, PreLiquidationParams} from "./interfaces/IPreLiquidation.sol"; import {IPreLiquidationFactory} from "./interfaces/IPreLiquidationFactory.sol"; import {IMorpho, Id} from "../lib/morpho-blue/src/interfaces/IMorpho.sol"; import {ErrorsLib} from "./libraries/ErrorsLib.sol"; import {EventsLib} from "./libraries/EventsLib.sol"; import {PreLiquidation} from "./PreLiquidation.sol"; /// @title PreLiquidationFactory /// @author Morpho Labs /// @custom:contact [email protected] /// @notice A linear LIF and linear LCF pre-liquidation factory contract for Morpho. contract PreLiquidationFactory is IPreLiquidationFactory { /* IMMUTABLE */ /// @notice The address of the Morpho contract. IMorpho public immutable MORPHO; /* STORAGE */ /// @notice Mapping which returns true if the address is a PreLiquidation contract created by this factory. mapping(address => bool) public isPreLiquidation; /* CONSTRUCTOR */ /// @param morpho The address of the Morpho contract. constructor(address morpho) { require(morpho != address(0), ErrorsLib.ZeroAddress()); MORPHO = IMorpho(morpho); } /* EXTERNAL */ /// @notice Creates a PreLiquidation contract. /// @param id The Morpho market for PreLiquidations. /// @param preLiquidationParams The PreLiquidation params for the PreLiquidation contract. /// @dev Warning: This function will revert without data if the pre-liquidation already exists. function createPreLiquidation(Id id, PreLiquidationParams calldata preLiquidationParams) external returns (IPreLiquidation) { IPreLiquidation preLiquidation = IPreLiquidation(address(new PreLiquidation{salt: 0}(address(MORPHO), id, preLiquidationParams))); emit EventsLib.CreatePreLiquidation(address(preLiquidation), id, preLiquidationParams); isPreLiquidation[address(preLiquidation)] = true; return preLiquidation; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >= 0.5.0; import {Id, IMorpho, MarketParams} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol"; /// @notice The pre-liquidation parameters are: /// - preLltv, the maximum LTV of a position before allowing pre-liquidation, scaled by WAD. /// - preLCF1, the pre-liquidation close factor when the position LTV is equal to preLltv, scaled by WAD. /// - preLCF2, the pre-liquidation close factor when the position LTV is equal to LLTV, scaled by WAD. /// - preLIF1, the pre-liquidation incentive factor when the position LTV is equal to preLltv, scaled by WAD. /// - preLIF2, the pre-liquidation incentive factor when the position LTV is equal to LLTV, scaled by WAD. /// - preLiquidationOracle, the oracle used to assess whether or not a position can be preliquidated. struct PreLiquidationParams { uint256 preLltv; uint256 preLCF1; uint256 preLCF2; uint256 preLIF1; uint256 preLIF2; address preLiquidationOracle; } interface IPreLiquidation { function MORPHO() external view returns (IMorpho); function ID() external view returns (Id); function marketParams() external returns (MarketParams memory); function preLiquidationParams() external view returns (PreLiquidationParams memory); function preLiquidate(address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data) external returns (uint256, uint256); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >= 0.5.0; import {Id, IMorpho} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol"; import {IPreLiquidation, PreLiquidationParams} from "./IPreLiquidation.sol"; interface IPreLiquidationFactory { function MORPHO() external view returns (IMorpho); function isPreLiquidation(address) external returns (bool); function createPreLiquidation(Id id, PreLiquidationParams calldata preLiquidationParams) external returns (IPreLiquidation preLiquidation); }
// 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 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 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 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); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @title ErrorsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing errors. library ErrorsLib { /* PRELIQUIDATION ERRORS */ error PreLltvTooHigh(); error PreLCFDecreasing(); error PreLCFTooHigh(); error PreLIFTooLow(); error PreLIFDecreasing(); error PreLIFTooHigh(); error InconsistentInput(); error NotPreLiquidatablePosition(); error LiquidatablePosition(); error PreLiquidationTooLarge(uint256 repaidShares, uint256 repayableShares); error NotMorpho(); error NonexistentMarket(); /* PRELIQUIDATION FACTORY ERRORS */ error ZeroAddress(); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {Id} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol"; import {PreLiquidationParams} from "../interfaces/IPreLiquidation.sol"; /// @title EventsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing events. library EventsLib { /// @dev This event is emitted after calling `onPreLiquidate` which can tamper with the order of events. event PreLiquidate( Id indexed id, address indexed liquidator, address indexed borrower, uint256 repaidAssets, uint256 repaidShares, uint256 seizedAssets ); event CreatePreLiquidation(address indexed preLiquidation, Id id, PreLiquidationParams preLiquidationParams); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity 0.8.27; import {Id, MarketParams, IMorpho, Position, Market} from "../lib/morpho-blue/src/interfaces/IMorpho.sol"; import {IMorphoRepayCallback} from "../lib/morpho-blue/src/interfaces/IMorphoCallbacks.sol"; import {IPreLiquidation, PreLiquidationParams} from "./interfaces/IPreLiquidation.sol"; import {IPreLiquidationCallback} from "./interfaces/IPreLiquidationCallback.sol"; import {IOracle} from "../lib/morpho-blue/src/interfaces/IOracle.sol"; import {ORACLE_PRICE_SCALE} from "../lib/morpho-blue/src/libraries/ConstantsLib.sol"; import {SharesMathLib} from "../lib/morpho-blue/src/libraries/SharesMathLib.sol"; import {SafeTransferLib} from "../lib/solmate/src/utils/SafeTransferLib.sol"; import {WAD, MathLib} from "../lib/morpho-blue/src/libraries/MathLib.sol"; import {UtilsLib} from "../lib/morpho-blue/src/libraries/UtilsLib.sol"; import {ERC20} from "../lib/solmate/src/tokens/ERC20.sol"; import {EventsLib} from "./libraries/EventsLib.sol"; import {ErrorsLib} from "./libraries/ErrorsLib.sol"; /// @title PreLiquidation /// @author Morpho Labs /// @custom:contact [email protected] /// @notice A linear LIF and linear LCF pre-liquidation contract for Morpho. contract PreLiquidation is IPreLiquidation, IMorphoRepayCallback { using SharesMathLib for uint256; using MathLib for uint256; using SafeTransferLib for ERC20; /* IMMUTABLE */ /// @notice The address of the Morpho contract. IMorpho public immutable MORPHO; /// @notice The id of the Morpho Market specific to the PreLiquidation contract. Id public immutable ID; // Market parameters address internal immutable LOAN_TOKEN; address internal immutable COLLATERAL_TOKEN; address internal immutable ORACLE; address internal immutable IRM; uint256 internal immutable LLTV; // Pre-liquidation parameters uint256 internal immutable PRE_LLTV; uint256 internal immutable PRE_LCF_1; uint256 internal immutable PRE_LCF_2; uint256 internal immutable PRE_LIF_1; uint256 internal immutable PRE_LIF_2; address internal immutable PRE_LIQUIDATION_ORACLE; /// @notice The Morpho market parameters specific to the PreLiquidation contract. function marketParams() public view returns (MarketParams memory) { return MarketParams({ loanToken: LOAN_TOKEN, collateralToken: COLLATERAL_TOKEN, oracle: ORACLE, irm: IRM, lltv: LLTV }); } /// @notice The pre-liquidation parameters specific to the PreLiquidation contract. function preLiquidationParams() external view returns (PreLiquidationParams memory) { return PreLiquidationParams({ preLltv: PRE_LLTV, preLCF1: PRE_LCF_1, preLCF2: PRE_LCF_2, preLIF1: PRE_LIF_1, preLIF2: PRE_LIF_2, preLiquidationOracle: PRE_LIQUIDATION_ORACLE }); } /* CONSTRUCTOR */ /// @dev Initializes the PreLiquidation contract. /// @param morpho The address of the Morpho contract. /// @param id The id of the Morpho market on which pre-liquidations will occur. /// @param _preLiquidationParams The pre-liquidation parameters. /// @dev The following requirements should be met: /// - preLltv < LLTV; /// - preLCF1 <= preLCF2; /// - preLCF1 <= 1; /// - 1 <= preLIF1 <= preLIF2 <= 1 / LLTV. constructor(address morpho, Id id, PreLiquidationParams memory _preLiquidationParams) { require(IMorpho(morpho).market(id).lastUpdate != 0, ErrorsLib.NonexistentMarket()); MarketParams memory _marketParams = IMorpho(morpho).idToMarketParams(id); require(_preLiquidationParams.preLltv < _marketParams.lltv, ErrorsLib.PreLltvTooHigh()); require(_preLiquidationParams.preLCF1 <= _preLiquidationParams.preLCF2, ErrorsLib.PreLCFDecreasing()); require(_preLiquidationParams.preLCF1 <= WAD, ErrorsLib.PreLCFTooHigh()); require(WAD <= _preLiquidationParams.preLIF1, ErrorsLib.PreLIFTooLow()); require(_preLiquidationParams.preLIF1 <= _preLiquidationParams.preLIF2, ErrorsLib.PreLIFDecreasing()); require(_preLiquidationParams.preLIF2 <= WAD.wDivDown(_marketParams.lltv), ErrorsLib.PreLIFTooHigh()); MORPHO = IMorpho(morpho); ID = id; LOAN_TOKEN = _marketParams.loanToken; COLLATERAL_TOKEN = _marketParams.collateralToken; ORACLE = _marketParams.oracle; IRM = _marketParams.irm; LLTV = _marketParams.lltv; PRE_LLTV = _preLiquidationParams.preLltv; PRE_LCF_1 = _preLiquidationParams.preLCF1; PRE_LCF_2 = _preLiquidationParams.preLCF2; PRE_LIF_1 = _preLiquidationParams.preLIF1; PRE_LIF_2 = _preLiquidationParams.preLIF2; PRE_LIQUIDATION_ORACLE = _preLiquidationParams.preLiquidationOracle; ERC20(_marketParams.loanToken).safeApprove(morpho, type(uint256).max); } /* PRE-LIQUIDATION */ /// @notice Pre-liquidates the given borrower on the market of this contract and with the parameters of this /// contract. /// @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 `onPreLiquidate` callback. Pass empty data if not needed. /// @return seizedAssets The amount of collateral seized. /// @return repaidAssets The amount of debt repaid. /// @dev Either `seizedAssets` or `repaidShares` should be zero. /// @dev Reverts if the account is still liquidatable on Morpho after the pre-liquidation (withdrawCollateral will /// fail). This can happen if either the LIF is bigger than 1/LLTV, or if the account is already unhealthy on /// Morpho. /// @dev The pre-liquidation close factor (preLCF) is the maximum proportion of debt that can be pre-liquidated at /// once. It increases linearly from preLCF1 at preLltv to preLCF2 at LLTV. /// @dev The pre-liquidation incentive factor (preLIF) is the factor by which the repaid debt is multiplied to /// compute the seized collateral. It increases linearly from preLIF1 at preLltv to preLIF2 at LLTV. function preLiquidate(address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data) external returns (uint256, uint256) { require(UtilsLib.exactlyOneZero(seizedAssets, repaidShares), ErrorsLib.InconsistentInput()); MORPHO.accrueInterest(marketParams()); Market memory market = MORPHO.market(ID); Position memory position = MORPHO.position(ID, borrower); uint256 collateralPrice = IOracle(PRE_LIQUIDATION_ORACLE).price(); uint256 collateralQuoted = uint256(position.collateral).mulDivDown(collateralPrice, ORACLE_PRICE_SCALE); uint256 borrowed = uint256(position.borrowShares).toAssetsUp(market.totalBorrowAssets, market.totalBorrowShares); // The two following require-statements ensure that collateralQuoted is different from zero. require(borrowed <= collateralQuoted.wMulDown(LLTV), ErrorsLib.LiquidatablePosition()); // The following require-statement is equivalent to checking that ltv > PRE_LLTV. require(borrowed > collateralQuoted.wMulDown(PRE_LLTV), ErrorsLib.NotPreLiquidatablePosition()); uint256 ltv = borrowed.wDivUp(collateralQuoted); uint256 quotient = (ltv - PRE_LLTV).wDivDown(LLTV - PRE_LLTV); uint256 preLIF = quotient.wMulDown(PRE_LIF_2 - PRE_LIF_1) + PRE_LIF_1; if (seizedAssets > 0) { uint256 seizedAssetsQuoted = seizedAssets.mulDivUp(collateralPrice, ORACLE_PRICE_SCALE); repaidShares = seizedAssetsQuoted.wDivUp(preLIF).toSharesUp(market.totalBorrowAssets, market.totalBorrowShares); } else { seizedAssets = repaidShares.toAssetsDown(market.totalBorrowAssets, market.totalBorrowShares).wMulDown( preLIF ).mulDivDown(ORACLE_PRICE_SCALE, collateralPrice); } // Note that the pre-liquidation close factor can be greater than WAD (100%). // In this case the position can be fully pre-liquidated. uint256 preLCF = quotient.wMulDown(PRE_LCF_2 - PRE_LCF_1) + PRE_LCF_1; uint256 repayableShares = uint256(position.borrowShares).wMulDown(preLCF); require(repaidShares <= repayableShares, ErrorsLib.PreLiquidationTooLarge(repaidShares, repayableShares)); bytes memory callbackData = abi.encode(seizedAssets, borrower, msg.sender, data); (uint256 repaidAssets,) = MORPHO.repay(marketParams(), 0, repaidShares, borrower, callbackData); emit EventsLib.PreLiquidate(ID, msg.sender, borrower, repaidAssets, repaidShares, seizedAssets); return (seizedAssets, repaidAssets); } /// @notice Morpho callback after repay call. /// @dev During pre-liquidation, Morpho will call the `onMorphoRepay` callback function in `PreLiquidation` using /// the provided `data`. function onMorphoRepay(uint256 repaidAssets, bytes calldata callbackData) external { require(msg.sender == address(MORPHO), ErrorsLib.NotMorpho()); (uint256 seizedAssets, address borrower, address liquidator, bytes memory data) = abi.decode(callbackData, (uint256, address, address, bytes)); MORPHO.withdrawCollateral(marketParams(), seizedAssets, borrower, liquidator); if (data.length > 0) { IPreLiquidationCallback(liquidator).onPreLiquidate(repaidAssets, data); } ERC20(LOAN_TOKEN).safeTransferFrom(liquidator, address(this), repaidAssets); } }
// 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; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >= 0.5.0; /// @title IPreLiquidationCallback /// @notice Interface that "pre-liquidators" willing to use the pre-liquidation callback must implement. interface IPreLiquidationCallback { /// @notice Callback called when a pre-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 `preLiquidate` function. function onPreLiquidate(uint256 repaidAssets, bytes calldata data) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title IOracle /// @author Morpho Labs /// @custom:contact [email protected] /// @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); }
// 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)");
// 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 [email protected] /// @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. /// @dev Virtual shares can never be redeemed for the assets they are entitled to, but it is assumed the share price /// stays low enough not to inflate these assets to a significant value. /// @dev Warning: The assets to which virtual borrow shares are entitled behave like unrealizable bad debt. 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); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; uint256 constant WAD = 1e18; /// @title MathLib /// @author Morpho Labs /// @custom:contact [email protected] /// @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; } }
// 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 [email protected] /// @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(0, x - y). function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := mul(gt(x, y), sub(x, y)) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; /// @title ErrorsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @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 `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"; }
{ "remappings": [ "solmate/=lib/bundler3/lib/permit2/lib/solmate/", "@openzeppelin/contracts/=lib/metamorpho-1.1/lib/openzeppelin-contracts/contracts/", "bundler3/=lib/bundler3/", "ds-test/=lib/metamorpho-1.1/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/metamorpho-1.1/lib/erc4626-tests/", "forge-gas-snapshot/=lib/bundler3/lib/permit2/lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/morpho-blue/lib/halmos-cheatcodes/src/", "metamorpho-1.1/=lib/metamorpho-1.1/", "metamorpho/=lib/public-allocator/lib/metamorpho/", "morpho-blue-irm/=lib/morpho-blue-irm/src/", "morpho-blue-oracles/=lib/morpho-blue-oracles/src/", "morpho-blue/=lib/morpho-blue/", "murky/=lib/universal-rewards-distributor/lib/murky/src/", "openzeppelin-contracts/=lib/metamorpho-1.1/lib/openzeppelin-contracts/", "openzeppelin/=lib/universal-rewards-distributor/lib/openzeppelin-contracts/contracts/", "permit2/=lib/bundler3/lib/permit2/", "pre-liquidation/=lib/pre-liquidation/src/", "public-allocator/=lib/public-allocator/src/", "safe-smart-account/=lib/safe-smart-account/", "universal-rewards-distributor/=lib/universal-rewards-distributor/" ], "optimizer": { "enabled": true, "runs": 999999 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"morpho","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"preLiquidation","type":"address"},{"indexed":false,"internalType":"Id","name":"id","type":"bytes32"},{"components":[{"internalType":"uint256","name":"preLltv","type":"uint256"},{"internalType":"uint256","name":"preLCF1","type":"uint256"},{"internalType":"uint256","name":"preLCF2","type":"uint256"},{"internalType":"uint256","name":"preLIF1","type":"uint256"},{"internalType":"uint256","name":"preLIF2","type":"uint256"},{"internalType":"address","name":"preLiquidationOracle","type":"address"}],"indexed":false,"internalType":"struct PreLiquidationParams","name":"preLiquidationParams","type":"tuple"}],"name":"CreatePreLiquidation","type":"event"},{"inputs":[],"name":"MORPHO","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"},{"components":[{"internalType":"uint256","name":"preLltv","type":"uint256"},{"internalType":"uint256","name":"preLCF1","type":"uint256"},{"internalType":"uint256","name":"preLCF2","type":"uint256"},{"internalType":"uint256","name":"preLIF1","type":"uint256"},{"internalType":"uint256","name":"preLIF2","type":"uint256"},{"internalType":"address","name":"preLiquidationOracle","type":"address"}],"internalType":"struct PreLiquidationParams","name":"preLiquidationParams","type":"tuple"}],"name":"createPreLiquidation","outputs":[{"internalType":"contract IPreLiquidation","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isPreLiquidation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a034608257601f61215838819003918201601f19168301916001600160401b03831184841017608657808492602094604052833981010312608257516001600160a01b0381169081900360825780156073576080526040516120bd908161009b8239608051818181608701526101b30152f35b63d92e233d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f3560e01c9081631c32209214610119575080631ea36725146100af57633acb56241461003d575f80fd5b346100ab575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5f80fd5b346100ab5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab5760043573ffffffffffffffffffffffffffffffffffffffff81168091036100ab575f525f602052602060ff60405f2054166040519015158152f35b346100ab5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab576004359060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126100ab57611dac9081810181811067ffffffffffffffff82111761028a5781610100915f94610305833973ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681528560208201526101e7604082016102b7565b03019082f5801561027f576020917fc36ddf254f2ae7c3a2c82dc525fed9a804cdaf8102b19b3caa5aeda5afcca38273ffffffffffffffffffffffffffffffffffffffff60e093169283926040519081526102438682016102b7565ba2805f525f825260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b602435815260443560208201526064356040820152608435606082015260a435608082015260c4359073ffffffffffffffffffffffffffffffffffffffff82168092036100ab5760a0015256fe61022080604052346104675780611dac803803809161001e8285610545565b83398101039061010082126104675761003681610568565b60c0602083015193603f19011261046757604051916100548361052a565b60408101518352606081015193602084019485526080820151926040850193845260a0830151906060860191825261009a60e060c0860151956080890196875201610568565b60a08701908152604051632e3071cd60e11b8152600481018590526001600160a01b0390921694909160c081602481895afa908115610473575f9161048d575b50608001516001600160801b03161561047e57604051632c3c915760e01b8152600481018590529260a084602481895afa938415610473575f946103c2575b508751966080850197885111156103b35789518151106103a457670de0b6b3a76400008a5111610395578151670de0b6b3a76400001161038657815183511061037757825188518015610363576ec097ce7bc90715b34b9f1000000000041061035457608087905260a09590955283516001600160a01b0390811660c052602085810151821660e052604080870151831661010052606087015183166101205298516101405298516101605298516101805293516101a05292516101c05291516101e052905185166102005251915163095ea7b360e01b815260048101919091525f19602482015291925f9260449290918491165af13d15601f3d1160015f51141617161561031e5760405161181b908161059182396080518181816101ce0152818161028d0152611113015260a0518181816095015281816103b3015281816104180152610a94015260c051818181611361015261167f015260e051816116b8015261010051816116f401526101205181611730015261014051818181610590015281816106a101526117570152610160518181816105ca01528181610655015281816106800152610f740152610180518181816108310152610fbe01526101a0518181816108570152610fe501526101c0518181816106f0015261100d01526101e05181818161071701526110370152610200518181816104b4015261105d0152f35b60405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606490fd5b6331aff75360e01b5f5260045ffd5b634e487b7160e01b5f52601260045260245ffd5b63141da4bd60e21b5f5260045ffd5b630136247b60e51b5f5260045ffd5b630287fe3b60e31b5f5260045ffd5b631bc4f82360e01b5f5260045ffd5b63f0586c2360e01b5f5260045ffd5b90935060a0813d60a01161046b575b816103de60a09383610545565b81010312610467576040519060a08201906001600160401b038211838310176104535760809160405261041081610568565b835261041e60208201610568565b602084015261042f60408201610568565b604084015261044060608201610568565b606084015201516080820152925f610119565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b3d91506103d1565b6040513d5f823e3d90fd5b630ecde9b360e31b5f5260045ffd5b905060c0813d60c011610522575b816104a860c09383610545565b810103126104675761051760a0604051926104c28461052a565b6104cb8161057c565b84526104d96020820161057c565b60208501526104ea6040820161057c565b60408501526104fb6060820161057c565b606085015261050c6080820161057c565b60808501520161057c565b60a08201525f6100da565b3d915061049b565b60c081019081106001600160401b0382111761045357604052565b601f909101601f19168101906001600160401b0382119082101761045357604052565b51906001600160a01b038216820361046757565b51906001600160801b03821682036104675756fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816305b4591c146110a6575080631d553cee14610f165780633078f50a146101f25780633acb5624146101835780637b9e68f2146100bb5763b3cea21714610060575f80fd5b346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b80fd5b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760a06100f4611636565b61018160405180926080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565bf35b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100b85760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760043573ffffffffffffffffffffffffffffffffffffffff81168103610f125760243560643567ffffffffffffffff8111610f0e576102659036906004016114f4565b60443594918391908215871514610ee65773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926102b6611636565b843b15610eb657610371604051917f151c1ade00000000000000000000000000000000000000000000000000000000835260048301906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b858160a48183895af18015610ec257908691610ecd575b5050604051907f5c60e39a0000000000000000000000000000000000000000000000000000000082527f0000000000000000000000000000000000000000000000000000000000000000600483015260c082602481885afa918215610ec2578692610e1f575b50604051917f93c520620000000000000000000000000000000000000000000000000000000083527f0000000000000000000000000000000000000000000000000000000000000000600484015273ffffffffffffffffffffffffffffffffffffffff89166024840152606083604481895afa928315610e14578793610d6c575b50604051917fa035b1fe00000000000000000000000000000000000000000000000000000000835260208360048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa928315610d61578893610d29575b5060206ec097ce7bc90715b34b9f1000000000610517856fffffffffffffffffffffffffffffffff60408901511661177e565b049401926fffffffffffffffffffffffffffffffff8451166fffffffffffffffffffffffffffffffff6040850151166fffffffffffffffffffffffffffffffff6060860151169160018201809211610c7f57620f42408301809311610c7f579061058192916117c8565b94670de0b6b3a76400006105b57f00000000000000000000000000000000000000000000000000000000000000008361177e565b048611610d0157670de0b6b3a76400006105ef7f00000000000000000000000000000000000000000000000000000000000000008361177e565b04861115610cd957670de0b6b3a76400009586810290808204881490151715610cac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820190828211610c7f579161064e6106539261067a94611629565b611791565b7f00000000000000000000000000000000000000000000000000000000000000009061161c565b9b6106c57f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061161c565b9c86810290808204881490151715610b78578a876107429c9d9e9f6106ed9061074894611791565b9c7f0000000000000000000000000000000000000000000000000000000000000000928e61073b857f000000000000000000000000000000000000000000000000000000000000000061161c565b915061177e565b04611629565b9215610ba55750610759908b61177e565b6ec097ce7bc90715b34b9f0fffffffff8101809111610b4b576ec097ce7bc90715b34b9f1000000000900484810290808204861490151715610b4b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820190828211610b78576107ce929161064e91611629565b6fffffffffffffffffffffffffffffffff6060816040850151169301511690620f42408201809211610b4b5760018301809311610b4b5761082861088394936fffffffffffffffffffffffffffffffff9361087b936117c8565b985b856107428c7f00000000000000000000000000000000000000000000000000000000000000009361073b857f000000000000000000000000000000000000000000000000000000000000000061161c565b91511661177e565b04808511610b1b5750610a2f9261093160c0887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f876040988e9873ffffffffffffffffffffffffffffffffffffffff8b519a8b976020890152168b8701523360608701526080808701528160a0870152868601378b8582860101520116810103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810184528361157b565b6109f38661093d611636565b8551968795869485937f20b76e8100000000000000000000000000000000000000000000000000000000855260048501906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b8360a48401528960c484015273ffffffffffffffffffffffffffffffffffffffff8d1660e48401526101206101048401526101248301906115bc565b03925af1928315610b0f578093610ac1575b505073ffffffffffffffffffffffffffffffffffffffff60409485519284845260208401528486840152169033907fd5b01f148b35d6069b626af105bf8881bc2e30ee1ce3de4630903abab0ba858060607f000000000000000000000000000000000000000000000000000000000000000092a482519182526020820152f35b909492506040853d604011610b07575b81610ade6040938361157b565b810103126100b8575073ffffffffffffffffffffffffffffffffffffffff604094519294610a41565b3d9150610ad1565b604051903d90823e3d90fd5b85604491867f44bb1e75000000000000000000000000000000000000000000000000000000008352600452602452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b989a50916fffffffffffffffffffffffffffffffff606081604084015116920151169060018101809111610b7857620f42408201809211610b785791610bf5610bfa9261064e889560443561177e565b61177e565b046ec097ce7bc90715b34b9f10000000008102908082046ec097ce7bc90715b34b9f10000000001490151715610c525761087b610c4c61088394936fffffffffffffffffffffffffffffffff93611791565b9a61082a565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60248c7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60048a7f0bb9a651000000000000000000000000000000000000000000000000000000008152fd5b60048a7ff78266a2000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011610d59575b81610d456020938361157b565b81010312610d555751915f6104e4565b8780fd5b3d9150610d38565b6040513d8a823e3d90fd5b9092506060813d606011610e0c575b81610d886060938361157b565b81010312610e0857604051906060820182811067ffffffffffffffff821117610ddb57610dcf91604091825280518452610dc4602082016115ff565b6020850152016115ff565b6040820152915f61046f565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8680fd5b3d9150610d7b565b6040513d89823e3d90fd5b90915060c0813d60c011610eba575b81610e3b60c0938361157b565b81010312610eb657610eaa60a060405192610e5584611543565b610e5e816115ff565b8452610e6c602082016115ff565b6020850152610e7d604082016115ff565b6040850152610e8e606082016115ff565b6060850152610e9f608082016115ff565b6080850152016115ff565b60a0820152905f6103ee565b8580fd5b3d9150610e2e565b6040513d88823e3d90fd5b81610ed79161157b565b610ee257845f610388565b8480fd5b6004847ff0732dd7000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b5080fd5b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760a0604051610f5381611543565b828152826020820152826040820152826060820152826080820152015260c07f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff604051610fb481611543565b82815260208101907f00000000000000000000000000000000000000000000000000000000000000008252604081017f0000000000000000000000000000000000000000000000000000000000000000815260608201907f0000000000000000000000000000000000000000000000000000000000000000825260a060808401937f000000000000000000000000000000000000000000000000000000000000000085520193857f0000000000000000000000000000000000000000000000000000000000000000168552604051968752516020870152516040860152516060850152516080840152511660a0820152f35b90503461149b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261149b5760043560243567ffffffffffffffff811161149b576110fa9036906004016114f4565b929073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016938433036114cc5781019360808286031261149b5761115460208301611522565b9461116160408401611522565b606084013567ffffffffffffffff811161149b5784019180601f8401121561149b5782359067ffffffffffffffff821161149f576111c760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116018861157b565b8187526020828501011161149b576020815f928273ffffffffffffffffffffffffffffffffffffffff9601838a0137870101521694611204611636565b91803b1561149b575f92836101049273ffffffffffffffffffffffffffffffffffffffff6112e19560405198899788967f8720316d00000000000000000000000000000000000000000000000000000000885260048801906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b3560a48601521660c48401528960e48401525af1801561149057611479575b5090818492516113f7575b50602092606491604051917f23b872dd000000000000000000000000000000000000000000000000000000008352600483015230602483015260448201528273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af13d15601f3d116001845114161716156113995780f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b833b15611475578261144491604051809381927f8e8beec40000000000000000000000000000000000000000000000000000000083528660048401526040602484015260448301906115bc565b038183885af1801561146a571561130b5761146083809261157b565b610f12575f61130b565b6040513d85823e3d90fd5b8280fd5b611487919294505f9061157b565b5f92905f611300565b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fe51b5123000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b60c0810190811067ffffffffffffffff82111761149f57604052565b60a0810190811067ffffffffffffffff82111761149f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761149f57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b51906fffffffffffffffffffffffffffffffff8216820361149b57565b91908203918211610cac57565b91908201809211610cac57565b5f60806040516116458161155f565b82815282602082015282604082015282606082015201526040516116688161155f565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602082015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016604082015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608201527f0000000000000000000000000000000000000000000000000000000000000000608082015290565b81810292918115918404141715610cac57565b811561179b570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b906117d29161177e565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810191818311610cac5761180b9261064e91611629565b9056fea164736f6c634300081b000aa164736f6c634300081b000a000000000000000000000000d6c916eb7542d0ad3f18aed0fcbd50c582cfa95f
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c9081631c32209214610119575080631ea36725146100af57633acb56241461003d575f80fd5b346100ab575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d6c916eb7542d0ad3f18aed0fcbd50c582cfa95f168152f35b5f80fd5b346100ab5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab5760043573ffffffffffffffffffffffffffffffffffffffff81168091036100ab575f525f602052602060ff60405f2054166040519015158152f35b346100ab5760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab576004359060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126100ab57611dac9081810181811067ffffffffffffffff82111761028a5781610100915f94610305833973ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d6c916eb7542d0ad3f18aed0fcbd50c582cfa95f1681528560208201526101e7604082016102b7565b03019082f5801561027f576020917fc36ddf254f2ae7c3a2c82dc525fed9a804cdaf8102b19b3caa5aeda5afcca38273ffffffffffffffffffffffffffffffffffffffff60e093169283926040519081526102438682016102b7565ba2805f525f825260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b602435815260443560208201526064356040820152608435606082015260a435608082015260c4359073ffffffffffffffffffffffffffffffffffffffff82168092036100ab5760a0015256fe61022080604052346104675780611dac803803809161001e8285610545565b83398101039061010082126104675761003681610568565b60c0602083015193603f19011261046757604051916100548361052a565b60408101518352606081015193602084019485526080820151926040850193845260a0830151906060860191825261009a60e060c0860151956080890196875201610568565b60a08701908152604051632e3071cd60e11b8152600481018590526001600160a01b0390921694909160c081602481895afa908115610473575f9161048d575b50608001516001600160801b03161561047e57604051632c3c915760e01b8152600481018590529260a084602481895afa938415610473575f946103c2575b508751966080850197885111156103b35789518151106103a457670de0b6b3a76400008a5111610395578151670de0b6b3a76400001161038657815183511061037757825188518015610363576ec097ce7bc90715b34b9f1000000000041061035457608087905260a09590955283516001600160a01b0390811660c052602085810151821660e052604080870151831661010052606087015183166101205298516101405298516101605298516101805293516101a05292516101c05291516101e052905185166102005251915163095ea7b360e01b815260048101919091525f19602482015291925f9260449290918491165af13d15601f3d1160015f51141617161561031e5760405161181b908161059182396080518181816101ce0152818161028d0152611113015260a0518181816095015281816103b3015281816104180152610a94015260c051818181611361015261167f015260e051816116b8015261010051816116f401526101205181611730015261014051818181610590015281816106a101526117570152610160518181816105ca01528181610655015281816106800152610f740152610180518181816108310152610fbe01526101a0518181816108570152610fe501526101c0518181816106f0015261100d01526101e05181818161071701526110370152610200518181816104b4015261105d0152f35b60405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606490fd5b6331aff75360e01b5f5260045ffd5b634e487b7160e01b5f52601260045260245ffd5b63141da4bd60e21b5f5260045ffd5b630136247b60e51b5f5260045ffd5b630287fe3b60e31b5f5260045ffd5b631bc4f82360e01b5f5260045ffd5b63f0586c2360e01b5f5260045ffd5b90935060a0813d60a01161046b575b816103de60a09383610545565b81010312610467576040519060a08201906001600160401b038211838310176104535760809160405261041081610568565b835261041e60208201610568565b602084015261042f60408201610568565b604084015261044060608201610568565b606084015201516080820152925f610119565b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b3d91506103d1565b6040513d5f823e3d90fd5b630ecde9b360e31b5f5260045ffd5b905060c0813d60c011610522575b816104a860c09383610545565b810103126104675761051760a0604051926104c28461052a565b6104cb8161057c565b84526104d96020820161057c565b60208501526104ea6040820161057c565b60408501526104fb6060820161057c565b606085015261050c6080820161057c565b60808501520161057c565b60a08201525f6100da565b3d915061049b565b60c081019081106001600160401b0382111761045357604052565b601f909101601f19168101906001600160401b0382119082101761045357604052565b51906001600160a01b038216820361046757565b51906001600160801b03821682036104675756fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816305b4591c146110a6575080631d553cee14610f165780633078f50a146101f25780633acb5624146101835780637b9e68f2146100bb5763b3cea21714610060575f80fd5b346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b80fd5b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760a06100f4611636565b61018160405180926080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565bf35b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100b85760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760043573ffffffffffffffffffffffffffffffffffffffff81168103610f125760243560643567ffffffffffffffff8111610f0e576102659036906004016114f4565b60443594918391908215871514610ee65773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926102b6611636565b843b15610eb657610371604051917f151c1ade00000000000000000000000000000000000000000000000000000000835260048301906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b858160a48183895af18015610ec257908691610ecd575b5050604051907f5c60e39a0000000000000000000000000000000000000000000000000000000082527f0000000000000000000000000000000000000000000000000000000000000000600483015260c082602481885afa918215610ec2578692610e1f575b50604051917f93c520620000000000000000000000000000000000000000000000000000000083527f0000000000000000000000000000000000000000000000000000000000000000600484015273ffffffffffffffffffffffffffffffffffffffff89166024840152606083604481895afa928315610e14578793610d6c575b50604051917fa035b1fe00000000000000000000000000000000000000000000000000000000835260208360048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa928315610d61578893610d29575b5060206ec097ce7bc90715b34b9f1000000000610517856fffffffffffffffffffffffffffffffff60408901511661177e565b049401926fffffffffffffffffffffffffffffffff8451166fffffffffffffffffffffffffffffffff6040850151166fffffffffffffffffffffffffffffffff6060860151169160018201809211610c7f57620f42408301809311610c7f579061058192916117c8565b94670de0b6b3a76400006105b57f00000000000000000000000000000000000000000000000000000000000000008361177e565b048611610d0157670de0b6b3a76400006105ef7f00000000000000000000000000000000000000000000000000000000000000008361177e565b04861115610cd957670de0b6b3a76400009586810290808204881490151715610cac577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820190828211610c7f579161064e6106539261067a94611629565b611791565b7f00000000000000000000000000000000000000000000000000000000000000009061161c565b9b6106c57f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061161c565b9c86810290808204881490151715610b78578a876107429c9d9e9f6106ed9061074894611791565b9c7f0000000000000000000000000000000000000000000000000000000000000000928e61073b857f000000000000000000000000000000000000000000000000000000000000000061161c565b915061177e565b04611629565b9215610ba55750610759908b61177e565b6ec097ce7bc90715b34b9f0fffffffff8101809111610b4b576ec097ce7bc90715b34b9f1000000000900484810290808204861490151715610b4b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820190828211610b78576107ce929161064e91611629565b6fffffffffffffffffffffffffffffffff6060816040850151169301511690620f42408201809211610b4b5760018301809311610b4b5761082861088394936fffffffffffffffffffffffffffffffff9361087b936117c8565b985b856107428c7f00000000000000000000000000000000000000000000000000000000000000009361073b857f000000000000000000000000000000000000000000000000000000000000000061161c565b91511661177e565b04808511610b1b5750610a2f9261093160c0887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f876040988e9873ffffffffffffffffffffffffffffffffffffffff8b519a8b976020890152168b8701523360608701526080808701528160a0870152868601378b8582860101520116810103017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810184528361157b565b6109f38661093d611636565b8551968795869485937f20b76e8100000000000000000000000000000000000000000000000000000000855260048501906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b8360a48401528960c484015273ffffffffffffffffffffffffffffffffffffffff8d1660e48401526101206101048401526101248301906115bc565b03925af1928315610b0f578093610ac1575b505073ffffffffffffffffffffffffffffffffffffffff60409485519284845260208401528486840152169033907fd5b01f148b35d6069b626af105bf8881bc2e30ee1ce3de4630903abab0ba858060607f000000000000000000000000000000000000000000000000000000000000000092a482519182526020820152f35b909492506040853d604011610b07575b81610ade6040938361157b565b810103126100b8575073ffffffffffffffffffffffffffffffffffffffff604094519294610a41565b3d9150610ad1565b604051903d90823e3d90fd5b85604491867f44bb1e75000000000000000000000000000000000000000000000000000000008352600452602452fd5b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b989a50916fffffffffffffffffffffffffffffffff606081604084015116920151169060018101809111610b7857620f42408201809211610b785791610bf5610bfa9261064e889560443561177e565b61177e565b046ec097ce7bc90715b34b9f10000000008102908082046ec097ce7bc90715b34b9f10000000001490151715610c525761087b610c4c61088394936fffffffffffffffffffffffffffffffff93611791565b9a61082a565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b60248c7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60048a7f0bb9a651000000000000000000000000000000000000000000000000000000008152fd5b60048a7ff78266a2000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011610d59575b81610d456020938361157b565b81010312610d555751915f6104e4565b8780fd5b3d9150610d38565b6040513d8a823e3d90fd5b9092506060813d606011610e0c575b81610d886060938361157b565b81010312610e0857604051906060820182811067ffffffffffffffff821117610ddb57610dcf91604091825280518452610dc4602082016115ff565b6020850152016115ff565b6040820152915f61046f565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8680fd5b3d9150610d7b565b6040513d89823e3d90fd5b90915060c0813d60c011610eba575b81610e3b60c0938361157b565b81010312610eb657610eaa60a060405192610e5584611543565b610e5e816115ff565b8452610e6c602082016115ff565b6020850152610e7d604082016115ff565b6040850152610e8e606082016115ff565b6060850152610e9f608082016115ff565b6080850152016115ff565b60a0820152905f6103ee565b8580fd5b3d9150610e2e565b6040513d88823e3d90fd5b81610ed79161157b565b610ee257845f610388565b8480fd5b6004847ff0732dd7000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b5080fd5b50346100b857807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100b85760a0604051610f5381611543565b828152826020820152826040820152826060820152826080820152015260c07f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff604051610fb481611543565b82815260208101907f00000000000000000000000000000000000000000000000000000000000000008252604081017f0000000000000000000000000000000000000000000000000000000000000000815260608201907f0000000000000000000000000000000000000000000000000000000000000000825260a060808401937f000000000000000000000000000000000000000000000000000000000000000085520193857f0000000000000000000000000000000000000000000000000000000000000000168552604051968752516020870152516040860152516060850152516080840152511660a0820152f35b90503461149b5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261149b5760043560243567ffffffffffffffff811161149b576110fa9036906004016114f4565b929073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016938433036114cc5781019360808286031261149b5761115460208301611522565b9461116160408401611522565b606084013567ffffffffffffffff811161149b5784019180601f8401121561149b5782359067ffffffffffffffff821161149f576111c760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116018861157b565b8187526020828501011161149b576020815f928273ffffffffffffffffffffffffffffffffffffffff9601838a0137870101521694611204611636565b91803b1561149b575f92836101049273ffffffffffffffffffffffffffffffffffffffff6112e19560405198899788967f8720316d00000000000000000000000000000000000000000000000000000000885260048801906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b3560a48601521660c48401528960e48401525af1801561149057611479575b5090818492516113f7575b50602092606491604051917f23b872dd000000000000000000000000000000000000000000000000000000008352600483015230602483015260448201528273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af13d15601f3d116001845114161716156113995780f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b833b15611475578261144491604051809381927f8e8beec40000000000000000000000000000000000000000000000000000000083528660048401526040602484015260448301906115bc565b038183885af1801561146a571561130b5761146083809261157b565b610f12575f61130b565b6040513d85823e3d90fd5b8280fd5b611487919294505f9061157b565b5f92905f611300565b6040513d5f823e3d90fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fe51b5123000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b60c0810190811067ffffffffffffffff82111761149f57604052565b60a0810190811067ffffffffffffffff82111761149f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761149f57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b51906fffffffffffffffffffffffffffffffff8216820361149b57565b91908203918211610cac57565b91908201809211610cac57565b5f60806040516116458161155f565b82815282602082015282604082015282606082015201526040516116688161155f565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602082015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016604082015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608201527f0000000000000000000000000000000000000000000000000000000000000000608082015290565b81810292918115918404141715610cac57565b811561179b570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b906117d29161177e565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810191818311610cac5761180b9261064e91611629565b9056fea164736f6c634300081b000aa164736f6c634300081b000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d6c916eb7542d0ad3f18aed0fcbd50c582cfa95f
-----Decoded View---------------
Arg [0] : morpho (address): 0xd6c916eB7542D0Ad3f18AEd0FCBD50C582cfa95f
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d6c916eb7542d0ad3f18aed0fcbd50c582cfa95f
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.