Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
9025669 | 92 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
AdaptiveCurveIrm
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 999999 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {IIrm} from "../../lib/morpho-blue/src/interfaces/IIrm.sol"; import {IAdaptiveCurveIrm} from "./interfaces/IAdaptiveCurveIrm.sol"; import {UtilsLib} from "./libraries/UtilsLib.sol"; import {ErrorsLib} from "./libraries/ErrorsLib.sol"; import {ExpLib} from "./libraries/ExpLib.sol"; import {MathLib, WAD_INT as WAD} from "./libraries/MathLib.sol"; import {ConstantsLib} from "./libraries/ConstantsLib.sol"; import {MarketParamsLib} from "../../lib/morpho-blue/src/libraries/MarketParamsLib.sol"; import {Id, MarketParams, Market} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol"; import {MathLib as MorphoMathLib} from "../../lib/morpho-blue/src/libraries/MathLib.sol"; /// @title AdaptiveCurveIrm /// @author Morpho Labs /// @custom:contact [email protected] contract AdaptiveCurveIrm is IAdaptiveCurveIrm { using MathLib for int256; using UtilsLib for int256; using MorphoMathLib for uint128; using MarketParamsLib for MarketParams; /* EVENTS */ /// @notice Emitted when a borrow rate is updated. event BorrowRateUpdate(Id indexed id, uint256 avgBorrowRate, uint256 rateAtTarget); /* IMMUTABLES */ /// @inheritdoc IAdaptiveCurveIrm address public immutable MORPHO; /* STORAGE */ /// @inheritdoc IAdaptiveCurveIrm mapping(Id => int256) public rateAtTarget; /* CONSTRUCTOR */ /// @notice Constructor. /// @param morpho The address of Morpho. constructor(address morpho) { require(morpho != address(0), ErrorsLib.ZERO_ADDRESS); MORPHO = morpho; } /* BORROW RATES */ /// @inheritdoc IIrm function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256) { (uint256 avgRate,) = _borrowRate(marketParams.id(), market); return avgRate; } /// @inheritdoc IIrm function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256) { require(msg.sender == MORPHO, ErrorsLib.NOT_MORPHO); Id id = marketParams.id(); (uint256 avgRate, int256 endRateAtTarget) = _borrowRate(id, market); rateAtTarget[id] = endRateAtTarget; // Safe "unchecked" cast because endRateAtTarget >= 0. emit BorrowRateUpdate(id, avgRate, uint256(endRateAtTarget)); return avgRate; } /// @dev Returns avgRate and endRateAtTarget. /// @dev Assumes that the inputs `marketParams` and `id` match. function _borrowRate(Id id, Market memory market) private view returns (uint256, int256) { // Safe "unchecked" cast because the utilization is smaller than 1 (scaled by WAD). int256 utilization = int256(market.totalSupplyAssets > 0 ? market.totalBorrowAssets.wDivDown(market.totalSupplyAssets) : 0); int256 errNormFactor = utilization > ConstantsLib.TARGET_UTILIZATION ? WAD - ConstantsLib.TARGET_UTILIZATION : ConstantsLib.TARGET_UTILIZATION; int256 err = (utilization - ConstantsLib.TARGET_UTILIZATION).wDivToZero(errNormFactor); int256 startRateAtTarget = rateAtTarget[id]; int256 avgRateAtTarget; int256 endRateAtTarget; if (startRateAtTarget == 0) { // First interaction. avgRateAtTarget = ConstantsLib.INITIAL_RATE_AT_TARGET; endRateAtTarget = ConstantsLib.INITIAL_RATE_AT_TARGET; } else { // The speed is assumed constant between two updates, but it is in fact not constant because of interest. // So the rate is always underestimated. int256 speed = ConstantsLib.ADJUSTMENT_SPEED.wMulToZero(err); // market.lastUpdate != 0 because it is not the first interaction with this market. // Safe "unchecked" cast because block.timestamp - market.lastUpdate <= block.timestamp <= type(int256).max. int256 elapsed = int256(block.timestamp - market.lastUpdate); int256 linearAdaptation = speed * elapsed; if (linearAdaptation == 0) { // If linearAdaptation == 0, avgRateAtTarget = endRateAtTarget = startRateAtTarget; avgRateAtTarget = startRateAtTarget; endRateAtTarget = startRateAtTarget; } else { // Formula of the average rate that should be returned to Morpho Blue: // avg = 1/T * ∫_0^T curve(startRateAtTarget*exp(speed*x), err) dx // The integral is approximated with the trapezoidal rule: // avg ~= 1/T * Σ_i=1^N [curve(f((i-1) * T/N), err) + curve(f(i * T/N), err)] / 2 * T/N // Where f(x) = startRateAtTarget*exp(speed*x) // avg ~= Σ_i=1^N [curve(f((i-1) * T/N), err) + curve(f(i * T/N), err)] / (2 * N) // As curve is linear in its first argument: // avg ~= curve([Σ_i=1^N [f((i-1) * T/N) + f(i * T/N)] / (2 * N), err) // avg ~= curve([(f(0) + f(T))/2 + Σ_i=1^(N-1) f(i * T/N)] / N, err) // avg ~= curve([(startRateAtTarget + endRateAtTarget)/2 + Σ_i=1^(N-1) f(i * T/N)] / N, err) // With N = 2: // avg ~= curve([(startRateAtTarget + endRateAtTarget)/2 + startRateAtTarget*exp(speed*T/2)] / 2, err) // avg ~= curve([startRateAtTarget + endRateAtTarget + 2*startRateAtTarget*exp(speed*T/2)] / 4, err) endRateAtTarget = _newRateAtTarget(startRateAtTarget, linearAdaptation); int256 midRateAtTarget = _newRateAtTarget(startRateAtTarget, linearAdaptation / 2); avgRateAtTarget = (startRateAtTarget + endRateAtTarget + 2 * midRateAtTarget) / 4; } } // Safe "unchecked" cast because avgRateAtTarget >= 0. return (uint256(_curve(avgRateAtTarget, err)), endRateAtTarget); } /// @dev Returns the rate for a given `_rateAtTarget` and an `err`. /// The formula of the curve is the following: /// r = ((1-1/C)*err + 1) * rateAtTarget if err < 0 /// ((C-1)*err + 1) * rateAtTarget else. function _curve(int256 _rateAtTarget, int256 err) private pure returns (int256) { // Non negative because 1 - 1/C >= 0, C - 1 >= 0. int256 coeff = err < 0 ? WAD - WAD.wDivToZero(ConstantsLib.CURVE_STEEPNESS) : ConstantsLib.CURVE_STEEPNESS - WAD; // Non negative if _rateAtTarget >= 0 because if err < 0, coeff <= 1. return (coeff.wMulToZero(err) + WAD).wMulToZero(int256(_rateAtTarget)); } /// @dev Returns the new rate at target, for a given `startRateAtTarget` and a given `linearAdaptation`. /// The formula is: max(min(startRateAtTarget * exp(linearAdaptation), maxRateAtTarget), minRateAtTarget). function _newRateAtTarget(int256 startRateAtTarget, int256 linearAdaptation) private pure returns (int256) { // Non negative because MIN_RATE_AT_TARGET > 0. return startRateAtTarget.wMulToZero(ExpLib.wExp(linearAdaptation)).bound( ConstantsLib.MIN_RATE_AT_TARGET, ConstantsLib.MAX_RATE_AT_TARGET ); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import {MarketParams, Market} from "./IMorpho.sol"; /// @title IIrm /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement. interface IIrm { /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams`. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256); /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams` without modifying any /// storage. /// @dev Assumes that `market` corresponds to `marketParams`. function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; import {IIrm} from "../../../lib/morpho-blue/src/interfaces/IIrm.sol"; import {Id} from "../../../lib/morpho-blue/src/interfaces/IMorpho.sol"; /// @title IAdaptiveCurveIrm /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Interface exposed by the AdaptiveCurveIrm. interface IAdaptiveCurveIrm is IIrm { /// @notice Address of Morpho. function MORPHO() external view returns (address); /// @notice Rate at target utilization. /// @dev Tells the height of the curve. function rateAtTarget(Id id) external view returns (int256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title UtilsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing helpers. library UtilsLib { /// @dev Bounds `x` between `low` and `high`. /// @dev Assumes that `low` <= `high`. If it is not the case it returns `low`. function bound(int256 x, int256 low, int256 high) internal pure returns (int256 z) { assembly { // z = min(x, high). z := xor(x, mul(xor(x, high), slt(high, x))) // z = max(z, low). z := xor(z, mul(xor(z, low), sgt(low, z))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ErrorsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library exposing error messages. library ErrorsLib { /// @dev Thrown when passing the zero address. string internal constant ZERO_ADDRESS = "zero address"; /// @dev Thrown when the caller is not Morpho. string internal constant NOT_MORPHO = "not Morpho"; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {WAD_INT} from "./MathLib.sol"; /// @title ExpLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library to approximate the exponential function. library ExpLib { /// @dev ln(2). int256 internal constant LN_2_INT = 0.693147180559945309 ether; /// @dev ln(1e-18). int256 internal constant LN_WEI_INT = -41.446531673892822312 ether; /// @dev Above this bound, `wExp` is clipped to avoid overflowing when multiplied with 1 ether. /// @dev This upper bound corresponds to: ln(type(int256).max / 1e36) (scaled by WAD, floored). int256 internal constant WEXP_UPPER_BOUND = 93.859467695000404319 ether; /// @dev The value of wExp(`WEXP_UPPER_BOUND`). int256 internal constant WEXP_UPPER_VALUE = 57716089161558943949701069502944508345128.422502756744429568 ether; /// @dev Returns an approximation of exp. function wExp(int256 x) internal pure returns (int256) { unchecked { // If x < ln(1e-18) then exp(x) < 1e-18 so it is rounded to zero. if (x < LN_WEI_INT) return 0; // `wExp` is clipped to avoid overflowing when multiplied with 1 ether. if (x >= WEXP_UPPER_BOUND) return WEXP_UPPER_VALUE; // Decompose x as x = q * ln(2) + r with q an integer and -ln(2)/2 <= r <= ln(2)/2. // q = x / ln(2) rounded half toward zero. int256 roundingAdjustment = (x < 0) ? -(LN_2_INT / 2) : (LN_2_INT / 2); // Safe unchecked because x is bounded. int256 q = (x + roundingAdjustment) / LN_2_INT; // Safe unchecked because |q * ln(2) - x| <= ln(2)/2. int256 r = x - q * LN_2_INT; // Compute e^r with a 2nd-order Taylor polynomial. // Safe unchecked because |r| < 1e18. int256 expR = WAD_INT + r + (r * r) / WAD_INT / 2; // Return e^x = 2^q * e^r. if (q >= 0) return expR << uint256(q); else return expR >> uint256(-q); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {WAD} from "../../../lib/morpho-blue/src/libraries/MathLib.sol"; int256 constant WAD_INT = int256(WAD); /// @title MathLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library to manage fixed-point arithmetic on signed integers. library MathLib { /// @dev Returns the multiplication of `x` by `y` (in WAD) rounded towards 0. function wMulToZero(int256 x, int256 y) internal pure returns (int256) { return (x * y) / WAD_INT; } /// @dev Returns the division of `x` by `y` (in WAD) rounded towards 0. function wDivToZero(int256 x, int256 y) internal pure returns (int256) { return (x * WAD_INT) / y; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /// @title ConstantsLib /// @author Morpho Labs /// @custom:contact [email protected] library ConstantsLib { /// @notice Curve steepness (scaled by WAD). /// @dev Curve steepness = 4. int256 public constant CURVE_STEEPNESS = 4 ether; /// @notice Adjustment speed per second (scaled by WAD). /// @dev The speed is per second, so the rate moves at a speed of ADJUSTMENT_SPEED * err each second (while being /// continuously compounded). /// @dev Adjustment speed = 50/year. int256 public constant ADJUSTMENT_SPEED = 50 ether / int256(365 days); /// @notice Target utilization (scaled by WAD). /// @dev Target utilization = 90%. int256 public constant TARGET_UTILIZATION = 0.9 ether; /// @notice Initial rate at target per second (scaled by WAD). /// @dev Initial rate at target = 4% (rate between 1% and 16%). int256 public constant INITIAL_RATE_AT_TARGET = 0.04 ether / int256(365 days); /// @notice Minimum rate at target per second (scaled by WAD). /// @dev Minimum rate at target = 0.1% (minimum rate = 0.025%). int256 public constant MIN_RATE_AT_TARGET = 0.001 ether / int256(365 days); /// @notice Maximum rate at target per second (scaled by WAD). /// @dev Maximum rate at target = 200% (maximum rate = 800%). int256 public constant MAX_RATE_AT_TARGET = 2.0 ether / int256(365 days); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.0; import {Id, MarketParams} from "../interfaces/IMorpho.sol"; /// @title MarketParamsLib /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Library to convert a market to its id. library MarketParamsLib { /// @notice The length of the data used to compute the id of a market. /// @dev The length is 5 * 32 because `MarketParams` has 5 variables of 32 bytes each. uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32; /// @notice Returns the id of the market `marketParams`. function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) { assembly ("memory-safe") { marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH) } } }
// 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 /// `onMorphoReplay` function with the given `data`. /// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`. /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow. /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion /// roundings between shares and assets. /// @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; 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; } }
{ "remappings": [ "solmate/=lib/bundler3/lib/permit2/lib/solmate/", "@openzeppelin/contracts/=lib/metamorpho-1.1/lib/openzeppelin-contracts/contracts/", "bundler3/=lib/bundler3/src/", "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/bundler3/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": "paris", "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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"Id","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"avgBorrowRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rateAtTarget","type":"uint256"}],"name":"BorrowRateUpdate","type":"event"},{"inputs":[],"name":"MORPHO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"components":[{"internalType":"uint128","name":"totalSupplyAssets","type":"uint128"},{"internalType":"uint128","name":"totalSupplyShares","type":"uint128"},{"internalType":"uint128","name":"totalBorrowAssets","type":"uint128"},{"internalType":"uint128","name":"totalBorrowShares","type":"uint128"},{"internalType":"uint128","name":"lastUpdate","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"internalType":"struct Market","name":"market","type":"tuple"}],"name":"borrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"components":[{"internalType":"uint128","name":"totalSupplyAssets","type":"uint128"},{"internalType":"uint128","name":"totalSupplyShares","type":"uint128"},{"internalType":"uint128","name":"totalBorrowAssets","type":"uint128"},{"internalType":"uint128","name":"totalBorrowShares","type":"uint128"},{"internalType":"uint128","name":"lastUpdate","type":"uint128"},{"internalType":"uint128","name":"fee","type":"uint128"}],"internalType":"struct Market","name":"market","type":"tuple"}],"name":"borrowRateView","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Id","name":"","type":"bytes32"}],"name":"rateAtTarget","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a03461011c57601f19610a0c38819003601f810183168401936001600160401b03939092909183861085871117610106578084926040978852833960209384918101031261011c5751926001600160a01b03841680850361011c5785519182870190811183821017610106578652600c82526b7a65726f206164647265737360a01b84830152156100ad57505050608052516108ea9081610122823960805181818160bc015261026b0152f35b82855192839162461bcd60e51b835280600484015283519081602485015260005b8281106100ef5750506044935080600085601f938601015201168101030190fd5b8086018201518782016044015286945081016100ce565b634e487b7160e01b600052604160045260246000fd5b600080fdfe6080604090808252600436101561001557600080fd5b600090813560e01c90816301977b571461028f575080633acb5624146102205780638c00bf6b146101f457639451fed41461004f57600080fd5b346101f15761005d366102d6565b8351939184830167ffffffffffffffff8111868210176101c4578352600a85526020947f6e6f74204d6f7270686f000000000000000000000000000000000000000000008682015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036101315750828061011460a07f7120161a7b3d31251e01294ab351ef15a41b91659a36032e4641bb89b121e321942094856104ff565b91878684939952808a52205581519086825287820152a251908152f35b84908685519283917f08c379a0000000000000000000000000000000000000000000000000000000008352806004840152835193846024850152825b8581106101ad57505050601f837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092604480968601015201168101030190fd5b81810183015187820160440152869450820161016d565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80fd5b50903461021c5760209061021460a061020c366102d6565b9190206104ff565b509051908152f35b5080fd5b50903461021c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021c576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b905082346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602092600435815280845220548152f35b8280fd5b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820161016081126104415760a013610441576040805167ffffffffffffffff919060a081018381118282101761044657825273ffffffffffffffffffffffffffffffffffffffff6004358181168103610441578252602435818116810361044157602083015260443581811681036104415783830152606435908116810361044157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c91606060c094015260843560808201529501126104415780519160c08301908111838210176104465781526fffffffffffffffffffffffffffffffff9060a435828116810361044157835260c435828116810361044157602084015260e435908282168203610441578301526101043581811681036104415760608301526101243581811681036104415760808301526101443590811681036104415760a082015290565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8181029291600082127f80000000000000000000000000000000000000000000000000000000000000008214166104b45781840514901517156104b457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b919091600083820193841291129080158216911516176104b457565b81519092916fffffffffffffffffffffffffffffffff91821680156000816107c357508360408401511690670de0b6b3a7640000918281029281840414901517156104b45761078f5704915b670c7d713b49da0000808413156107be575067016345785d8a00005b7ffffffffffffffffffffffffffffffffffffffffffffffffff3828ec4b626000084019384136001166104b457670de0b6b3a764000093848102908082058614901517156104b457811561078f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f80000000000000000000000000000000000000000000000000000000000000008214166104b4570594600052600060205260406000205491600091831560001461067a5750505050634b9a1eff8161064482955b600081121561066c57670a688906bd8b0000610475565b059082820191600084841291129080158216911516176104b45761066791610475565b059190565b6729a2241af62c0000610475565b650171268b5ad49187830292830588036107625760800151164203904282116107355790846106a99205610475565b806106bb57505081610644829561062d565b906106e1826106db6106d1869560029a976107cc565b98899205856107cc565b936104e3565b908260011b926002840503610708575060046107018593610644936104e3565b059261062d565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b610567565b9150509161054b565b6107e8906107e2670de0b6b3a764000093610807565b90610475565b05640ec41a0ddf81811290821802186301e3da5f818113908218021890565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d881126108d7576805168fd0946fc0415f8112156108b95760008112156108aa577ffffffffffffffffffffffffffffffffffffffffffffffffffb30b927e6d498d2905b67099e8db03256ce5d80928201059182029003670de0b6b3a764000090600282828002050501019060008112156000146108a3571b90565b6000031d90565b6704cf46d8192b672e9061086b565b50780931d81650c7d88b800000000000000000000000000000000090565b5060009056fea164736f6c6343000813000a000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432
Deployed Bytecode
0x6080604090808252600436101561001557600080fd5b600090813560e01c90816301977b571461028f575080633acb5624146102205780638c00bf6b146101f457639451fed41461004f57600080fd5b346101f15761005d366102d6565b8351939184830167ffffffffffffffff8111868210176101c4578352600a85526020947f6e6f74204d6f7270686f000000000000000000000000000000000000000000008682015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af4321633036101315750828061011460a07f7120161a7b3d31251e01294ab351ef15a41b91659a36032e4641bb89b121e321942094856104ff565b91878684939952808a52205581519086825287820152a251908152f35b84908685519283917f08c379a0000000000000000000000000000000000000000000000000000000008352806004840152835193846024850152825b8581106101ad57505050601f837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe092604480968601015201168101030190fd5b81810183015187820160440152869450820161016d565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80fd5b50903461021c5760209061021460a061020c366102d6565b9190206104ff565b509051908152f35b5080fd5b50903461021c57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261021c576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432168152f35b905082346102d25760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102d257602092600435815280845220548152f35b8280fd5b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820161016081126104415760a013610441576040805167ffffffffffffffff919060a081018381118282101761044657825273ffffffffffffffffffffffffffffffffffffffff6004358181168103610441578252602435818116810361044157602083015260443581811681036104415783830152606435908116810361044157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c91606060c094015260843560808201529501126104415780519160c08301908111838210176104465781526fffffffffffffffffffffffffffffffff9060a435828116810361044157835260c435828116810361044157602084015260e435908282168203610441578301526101043581811681036104415760608301526101243581811681036104415760808301526101443590811681036104415760a082015290565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8181029291600082127f80000000000000000000000000000000000000000000000000000000000000008214166104b45781840514901517156104b457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b919091600083820193841291129080158216911516176104b457565b81519092916fffffffffffffffffffffffffffffffff91821680156000816107c357508360408401511690670de0b6b3a7640000918281029281840414901517156104b45761078f5704915b670c7d713b49da0000808413156107be575067016345785d8a00005b7ffffffffffffffffffffffffffffffffffffffffffffffffff3828ec4b626000084019384136001166104b457670de0b6b3a764000093848102908082058614901517156104b457811561078f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f80000000000000000000000000000000000000000000000000000000000000008214166104b4570594600052600060205260406000205491600091831560001461067a5750505050634b9a1eff8161064482955b600081121561066c57670a688906bd8b0000610475565b059082820191600084841291129080158216911516176104b45761066791610475565b059190565b6729a2241af62c0000610475565b650171268b5ad49187830292830588036107625760800151164203904282116107355790846106a99205610475565b806106bb57505081610644829561062d565b906106e1826106db6106d1869560029a976107cc565b98899205856107cc565b936104e3565b908260011b926002840503610708575060046107018593610644936104e3565b059261062d565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b610567565b9150509161054b565b6107e8906107e2670de0b6b3a764000093610807565b90610475565b05640ec41a0ddf81811290821802186301e3da5f818113908218021890565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d881126108d7576805168fd0946fc0415f8112156108b95760008112156108aa577ffffffffffffffffffffffffffffffffffffffffffffffffffb30b927e6d498d2905b67099e8db03256ce5d80928201059182029003670de0b6b3a764000090600282828002050501019060008112156000146108a3571b90565b6000031d90565b6704cf46d8192b672e9061086b565b50780931d81650c7d88b800000000000000000000000000000000090565b5060009056fea164736f6c6343000813000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432
-----Decoded View---------------
Arg [0] : morpho (address): 0xE741BC7c34758b4caE05062794E8Ae24978AF432
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ 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.