Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 18619527 | 9 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MorphoMarketV1AdapterV2
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 100000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity 0.8.28;
import {IMorpho, MarketParams, Id} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {MarketParamsLib} from "../../lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {SharesMathLib} from "../../lib/morpho-blue/src/libraries/SharesMathLib.sol";
import {IVaultV2} from "../interfaces/IVaultV2.sol";
import {IERC20} from "../interfaces/IERC20.sol";
import {IMorphoMarketV1AdapterV2} from "./interfaces/IMorphoMarketV1AdapterV2.sol";
import {SafeERC20Lib} from "../libraries/SafeERC20Lib.sol";
import {
AdaptiveCurveIrmLib
} from "../../lib/morpho-blue-irm/src/adaptive-curve-irm/libraries/periphery/AdaptiveCurveIrmLib.sol";
/// @dev Morpho Market V1 is also known as Morpho Blue.
/// @dev This adapter must be used with Morpho Market V1 that are protected against inflation attacks with an initial
/// supply. Following resource is relevant: https://docs.openzeppelin.com/contracts/5.x/erc4626#inflation-attack.
/// @dev Rounding error losses on supply/withdraw are realizable.
/// @dev If expectedSupplyAssets reverts for a market of the marketIds, realAssets will revert and the vault will not be
/// able to accrueInterest.
/// @dev Upon interest accrual, the vault calls realAssets(). If there are too many markets, it could cause issues such
/// as expensive interactions, even DOS, because of the gas.
/// @dev Shouldn't be used alongside another adapter that re-uses the last id (abi.encode("this/marketParams",
/// address(this), marketParams)).
/// @dev Markets get removed from the marketIds when the allocation is zero, but it doesn't mean that the adapter has
/// zero shares on the market.
/// @dev This adapter can only be used for markets with the adaptive curve irm.
/// @dev Before adding the adapter to the vault, its timelocks must be properly set.
/// @dev Donated shares are lost forever.
///
/// TIMELOCKS
/// @dev The system is the same as the one used in VaultV2. Dev comments in VaultV2.sol on timelocks also apply here.
///
/// BURN SHARES
/// @dev When submitting burnShares, it's recommended to put the caps of the market to zero to avoid losing more.
/// @dev Burning shares takes time, so reactive depositors might be able to exit before the share price reduction.
/// @dev It is possible to burn the shares of a market whose IRM reverts.
/// @dev Burnt shares are lost forever.
contract MorphoMarketV1AdapterV2 is IMorphoMarketV1AdapterV2 {
using MarketParamsLib for MarketParams;
using SharesMathLib for uint256;
/* IMMUTABLES */
address public immutable factory;
address public immutable parentVault;
address public immutable asset;
address public immutable morpho;
bytes32 public immutable adapterId;
address public immutable adaptiveCurveIrm;
/* TIMELOCKS STORAGE */
mapping(bytes4 selector => uint256) public timelock;
mapping(bytes4 selector => bool) public abdicated;
mapping(bytes data => uint256) public executableAt;
/* OTHER STORAGE */
address public skimRecipient;
bytes32[] public marketIds;
mapping(bytes32 marketId => uint256) public supplyShares;
/* GETTERS */
function marketIdsLength() external view returns (uint256) {
return marketIds.length;
}
/* CONSTRUCTOR */
constructor(address _parentVault, address _morpho, address _adaptiveCurveIrm) {
factory = msg.sender;
parentVault = _parentVault;
morpho = _morpho;
asset = IVaultV2(_parentVault).asset();
adapterId = keccak256(abi.encode("this", address(this)));
adaptiveCurveIrm = _adaptiveCurveIrm;
SafeERC20Lib.safeApprove(asset, _morpho, type(uint256).max);
SafeERC20Lib.safeApprove(asset, _parentVault, type(uint256).max);
}
/* TIMELOCKS FUNCTIONS */
/// @dev Will revert if the timelock value is type(uint256).max or any value that overflows when added to the block
/// timestamp.
function submit(bytes calldata data) external {
require(msg.sender == IVaultV2(parentVault).curator(), Unauthorized());
require(executableAt[data] == 0, DataAlreadyPending());
bytes4 selector = bytes4(data);
uint256 _timelock = selector == IMorphoMarketV1AdapterV2.decreaseTimelock.selector
? timelock[bytes4(data[4:8])]
: timelock[selector];
executableAt[data] = block.timestamp + _timelock;
emit Submit(selector, data, executableAt[data]);
}
function timelocked() internal {
bytes4 selector = bytes4(msg.data);
require(executableAt[msg.data] != 0, DataNotTimelocked());
require(block.timestamp >= executableAt[msg.data], TimelockNotExpired());
require(!abdicated[selector], Abdicated());
executableAt[msg.data] = 0;
emit Accept(selector, msg.data);
}
function revoke(bytes calldata data) external {
require(
msg.sender == IVaultV2(parentVault).curator() || IVaultV2(parentVault).isSentinel(msg.sender),
Unauthorized()
);
require(executableAt[data] != 0, DataNotTimelocked());
executableAt[data] = 0;
bytes4 selector = bytes4(data);
emit Revoke(msg.sender, selector, data);
}
/* CURATOR FUNCTIONS */
/// @dev This function requires great caution because it can irreversibly disable submit for a selector.
/// @dev Existing pending operations submitted before increasing a timelock can still be executed at the initial
/// executableAt.
function increaseTimelock(bytes4 selector, uint256 newDuration) external {
timelocked();
require(selector != IMorphoMarketV1AdapterV2.decreaseTimelock.selector, AutomaticallyTimelocked());
require(newDuration >= timelock[selector], TimelockNotIncreasing());
timelock[selector] = newDuration;
emit IncreaseTimelock(selector, newDuration);
}
function decreaseTimelock(bytes4 selector, uint256 newDuration) external {
timelocked();
require(selector != IMorphoMarketV1AdapterV2.decreaseTimelock.selector, AutomaticallyTimelocked());
require(newDuration <= timelock[selector], TimelockNotDecreasing());
timelock[selector] = newDuration;
emit DecreaseTimelock(selector, newDuration);
}
/// @dev This function requires great caution because it will irreversibly disable submit for a selector.
/// @dev Existing pending operations submitted before abdicating can not be executed at the initial executableAt.
function abdicate(bytes4 selector) external {
timelocked();
abdicated[selector] = true;
emit Abdicate(selector);
}
function setSkimRecipient(address newSkimRecipient) external {
timelocked();
skimRecipient = newSkimRecipient;
emit SetSkimRecipient(newSkimRecipient);
}
/// @dev Deallocate 0 from the vault after burning shares to update the allocation there.
function burnShares(bytes32 marketId) external {
timelocked();
uint256 supplySharesBefore = supplyShares[marketId];
supplyShares[marketId] = 0;
emit BurnShares(marketId, supplySharesBefore);
}
/* OTHER FUNCTIONS */
/// @dev Skims the adapter's balance of `token` and sends it to `skimRecipient`.
/// @dev This is useful to handle rewards that the adapter has earned.
function skim(address token) external {
require(msg.sender == skimRecipient, Unauthorized());
uint256 balance = IERC20(token).balanceOf(address(this));
SafeERC20Lib.safeTransfer(token, skimRecipient, balance);
emit Skim(token, balance);
}
/// @dev Returns the ids of the allocation and the change in allocation.
function allocate(bytes memory data, uint256 assets, bytes4, address) external returns (bytes32[] memory, int256) {
MarketParams memory marketParams = abi.decode(data, (MarketParams));
require(msg.sender == parentVault, Unauthorized());
require(marketParams.loanToken == asset, LoanAssetMismatch());
require(marketParams.irm == adaptiveCurveIrm, IrmMismatch());
bytes32 marketId = Id.unwrap(marketParams.id());
uint256 mintedShares;
if (assets > 0) {
(, mintedShares) = IMorpho(morpho).supply(marketParams, assets, 0, address(this), hex"");
require(mintedShares >= assets, SharePriceAboveOne());
supplyShares[marketId] += mintedShares;
}
uint256 oldAllocation = allocation(marketParams);
uint256 newAllocation = expectedSupplyAssets(marketId);
updateList(marketId, oldAllocation, newAllocation);
emit Allocate(marketId, newAllocation, mintedShares);
// Safe casts because Market V1 bounds the total supply of the underlying token, and allocation is less than the
// max total assets of the vault.
return (ids(marketParams), int256(newAllocation) - int256(oldAllocation));
}
/// @dev Returns the ids of the deallocation and the change in allocation.
function deallocate(bytes memory data, uint256 assets, bytes4, address)
external
returns (bytes32[] memory, int256)
{
MarketParams memory marketParams = abi.decode(data, (MarketParams));
require(msg.sender == parentVault, Unauthorized());
require(marketParams.loanToken == asset, LoanAssetMismatch());
require(marketParams.irm == adaptiveCurveIrm, IrmMismatch());
bytes32 marketId = Id.unwrap(marketParams.id());
uint256 burnedShares;
if (assets > 0) {
(, burnedShares) = IMorpho(morpho).withdraw(marketParams, assets, 0, address(this), address(this));
supplyShares[marketId] -= burnedShares;
}
uint256 oldAllocation = allocation(marketParams);
uint256 newAllocation = expectedSupplyAssets(marketId);
updateList(marketId, oldAllocation, newAllocation);
emit Deallocate(marketId, newAllocation, burnedShares);
// Safe casts because Market V1 bounds the total supply of the underlying token, and allocation is less than the
// max total assets of the vault.
return (ids(marketParams), int256(newAllocation) - int256(oldAllocation));
}
function updateList(bytes32 marketId, uint256 oldAllocation, uint256 newAllocation) internal {
if (oldAllocation > 0 && newAllocation == 0) {
for (uint256 i = 0; i < marketIds.length; i++) {
if (marketIds[i] == marketId) {
marketIds[i] = marketIds[marketIds.length - 1];
marketIds.pop();
break;
}
}
} else if (oldAllocation == 0 && newAllocation > 0) {
marketIds.push(marketId);
}
}
/* VIEW FUNCTIONS */
/// @dev Returns the expected supply assets of the market, taking into account the internal shares accounting.
function expectedSupplyAssets(bytes32 marketId) public view returns (uint256) {
uint256 _supplyShares = supplyShares[marketId];
if (_supplyShares == 0) {
return 0;
} else {
(uint256 totalSupplyAssets, uint256 totalSupplyShares,,) =
AdaptiveCurveIrmLib.expectedMarketBalances(morpho, marketId, adaptiveCurveIrm);
return _supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);
}
}
/// @dev Returns the Vault's allocation for this market.
function allocation(MarketParams memory marketParams) public view returns (uint256) {
return IVaultV2(parentVault).allocation(keccak256(abi.encode("this/marketParams", address(this), marketParams)));
}
/// @dev Returns adapter's ids.
function ids(MarketParams memory marketParams) public view returns (bytes32[] memory) {
bytes32[] memory ids_ = new bytes32[](3);
ids_[0] = adapterId;
ids_[1] = keccak256(abi.encode("collateralToken", marketParams.collateralToken));
ids_[2] = keccak256(abi.encode("this/marketParams", address(this), marketParams));
return ids_;
}
function realAssets() external view returns (uint256) {
uint256 _realAssets = 0;
for (uint256 i = 0; i < marketIds.length; i++) {
_realAssets += expectedSupplyAssets(marketIds[i]);
}
return _realAssets;
}
}// 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 chains sharing the
/// same chain id and on forks because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// - The oracle price should not be able to change instantly such that the new price is less than the old price
/// multiplied by LLTV*LIF. In particular, if the loan asset is a vault that can receive donations, the oracle
/// should not price its shares using the AUM.
/// @dev Here is a list of assumptions on the market's dependencies which, if broken, could break Morpho's liveness
/// properties (funds could get stuck):
/// - The token should not revert on `transfer` and `transferFrom` if balances and approvals are right.
/// - The amount of assets supplied and borrowed should not be too high (max ~1e32), otherwise the number of shares
/// might not fit within 128 bits.
/// - The IRM should not revert on `borrowRate`.
/// - The IRM should not return a very high borrow rate (otherwise the computation of `interest` in
/// `_accrueInterest` can overflow).
/// - The oracle should not revert `price`.
/// - The oracle should not return a very high price (otherwise the computation of `maxBorrow` in `_isHealthy` or of
/// `assetsRepaid` in `liquidate` can overflow).
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoRepay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}// 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.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: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
import {IERC20} from "./IERC20.sol";
import {IERC4626} from "./IERC4626.sol";
import {IERC2612} from "./IERC2612.sol";
struct Caps {
uint256 allocation;
uint128 absoluteCap;
uint128 relativeCap;
}
interface IVaultV2 is IERC4626, IERC2612 {
// State variables
function virtualShares() external view returns (uint256);
function owner() external view returns (address);
function curator() external view returns (address);
function receiveSharesGate() external view returns (address);
function sendSharesGate() external view returns (address);
function receiveAssetsGate() external view returns (address);
function sendAssetsGate() external view returns (address);
function adapterRegistry() external view returns (address);
function isSentinel(address account) external view returns (bool);
function isAllocator(address account) external view returns (bool);
function firstTotalAssets() external view returns (uint256);
function _totalAssets() external view returns (uint128);
function lastUpdate() external view returns (uint64);
function maxRate() external view returns (uint64);
function adapters(uint256 index) external view returns (address);
function adaptersLength() external view returns (uint256);
function isAdapter(address account) external view returns (bool);
function allocation(bytes32 id) external view returns (uint256);
function absoluteCap(bytes32 id) external view returns (uint256);
function relativeCap(bytes32 id) external view returns (uint256);
function forceDeallocatePenalty(address adapter) external view returns (uint256);
function liquidityAdapter() external view returns (address);
function liquidityData() external view returns (bytes memory);
function timelock(bytes4 selector) external view returns (uint256);
function abdicated(bytes4 selector) external view returns (bool);
function executableAt(bytes memory data) external view returns (uint256);
function performanceFee() external view returns (uint96);
function performanceFeeRecipient() external view returns (address);
function managementFee() external view returns (uint96);
function managementFeeRecipient() external view returns (address);
// Gating
function canSendShares(address account) external view returns (bool);
function canReceiveShares(address account) external view returns (bool);
function canSendAssets(address account) external view returns (bool);
function canReceiveAssets(address account) external view returns (bool);
// Multicall
function multicall(bytes[] memory data) external;
// Owner functions
function setOwner(address newOwner) external;
function setCurator(address newCurator) external;
function setIsSentinel(address account, bool isSentinel) external;
function setName(string memory newName) external;
function setSymbol(string memory newSymbol) external;
// Timelocks for curator functions
function submit(bytes memory data) external;
function revoke(bytes memory data) external;
// Curator functions
function setIsAllocator(address account, bool newIsAllocator) external;
function setReceiveSharesGate(address newReceiveSharesGate) external;
function setSendSharesGate(address newSendSharesGate) external;
function setReceiveAssetsGate(address newReceiveAssetsGate) external;
function setSendAssetsGate(address newSendAssetsGate) external;
function setAdapterRegistry(address newAdapterRegistry) external;
function addAdapter(address account) external;
function removeAdapter(address account) external;
function increaseTimelock(bytes4 selector, uint256 newDuration) external;
function decreaseTimelock(bytes4 selector, uint256 newDuration) external;
function abdicate(bytes4 selector) external;
function setPerformanceFee(uint256 newPerformanceFee) external;
function setManagementFee(uint256 newManagementFee) external;
function setPerformanceFeeRecipient(address newPerformanceFeeRecipient) external;
function setManagementFeeRecipient(address newManagementFeeRecipient) external;
function increaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
function decreaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
function increaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
function decreaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
function setMaxRate(uint256 newMaxRate) external;
function setForceDeallocatePenalty(address adapter, uint256 newForceDeallocatePenalty) external;
// Allocator functions
function allocate(address adapter, bytes memory data, uint256 assets) external;
function deallocate(address adapter, bytes memory data, uint256 assets) external;
function setLiquidityAdapterAndData(address newLiquidityAdapter, bytes memory newLiquidityData) external;
// Exchange rate
function accrueInterest() external;
function accrueInterestView()
external
view
returns (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares);
// Force deallocate
function forceDeallocate(address adapter, bytes memory data, uint256 assets, address onBehalf)
external
returns (uint256 penaltyShares);
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
interface IERC20 {
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 shares) external returns (bool success);
function transferFrom(address from, address to, uint256 shares) external returns (bool success);
function approve(address spender, uint256 shares) external returns (bool success);
function allowance(address owner, address spender) external view returns (uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
import {IAdapter} from "../../interfaces/IAdapter.sol";
import {MarketParams} from "../../../lib/morpho-blue/src/interfaces/IMorpho.sol";
interface IMorphoMarketV1AdapterV2 is IAdapter {
/* EVENTS */
event Submit(bytes4 indexed selector, bytes data, uint256 executableAt);
event Revoke(address indexed sender, bytes4 indexed selector, bytes data);
event Accept(bytes4 indexed selector, bytes data);
event Abdicate(bytes4 indexed selector);
event IncreaseTimelock(bytes4 indexed selector, uint256 newDuration);
event DecreaseTimelock(bytes4 indexed selector, uint256 newDuration);
event SetSkimRecipient(address indexed newSkimRecipient);
event Skim(address indexed token, uint256 assets);
event BurnShares(bytes32 indexed marketId, uint256 supplyShares);
event Allocate(bytes32 indexed marketId, uint256 newAllocation, uint256 mintedShares);
event Deallocate(bytes32 indexed marketId, uint256 newAllocation, uint256 burnedShares);
/* ERRORS */
error Abdicated();
error AutomaticallyTimelocked();
error DataAlreadyPending();
error DataNotTimelocked();
error IrmMismatch();
error LoanAssetMismatch();
error SharePriceAboveOne();
error TimelockNotDecreasing();
error TimelockNotExpired();
error TimelockNotIncreasing();
error Unauthorized();
/* VIEW FUNCTIONS */
function factory() external view returns (address);
function parentVault() external view returns (address);
function asset() external view returns (address);
function morpho() external view returns (address);
function marketIds(uint256 index) external view returns (bytes32);
function supplyShares(bytes32 marketId) external view returns (uint256);
function adapterId() external view returns (bytes32);
function skimRecipient() external view returns (address);
function marketIdsLength() external view returns (uint256);
function adaptiveCurveIrm() external view returns (address);
function allocation(MarketParams memory marketParams) external view returns (uint256);
function expectedSupplyAssets(bytes32 marketId) external view returns (uint256);
function ids(MarketParams memory marketParams) external view returns (bytes32[] memory);
function timelock(bytes4 selector) external view returns (uint256);
function abdicated(bytes4 selector) external view returns (bool);
function executableAt(bytes memory data) external view returns (uint256);
/* NON-VIEW FUNCTIONS */
function submit(bytes memory data) external;
function revoke(bytes memory data) external;
function increaseTimelock(bytes4 selector, uint256 newDuration) external;
function decreaseTimelock(bytes4 selector, uint256 newDuration) external;
function abdicate(bytes4 selector) external;
function setSkimRecipient(address newSkimRecipient) external;
function burnShares(bytes32 marketId) external;
function skim(address token) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;
import {IERC20} from "../interfaces/IERC20.sol";
import {ErrorsLib} from "./ErrorsLib.sol";
library SafeERC20Lib {
function safeTransfer(address token, address to, uint256 value) internal {
require(token.code.length > 0, ErrorsLib.NoCode());
(bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));
require(success, ErrorsLib.TransferReverted());
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferReturnedFalse());
}
function safeTransferFrom(address token, address from, address to, uint256 value) internal {
require(token.code.length > 0, ErrorsLib.NoCode());
(bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
require(success, ErrorsLib.TransferFromReverted());
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferFromReturnedFalse());
}
function safeApprove(address token, address spender, uint256 value) internal {
require(token.code.length > 0, ErrorsLib.NoCode());
(bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.approve, (spender, value)));
require(success, ErrorsLib.ApproveReverted());
require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.ApproveReturnedFalse());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Id, Market, IMorpho} from "../../../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IAdaptiveCurveIrm} from "../../interfaces/IAdaptiveCurveIrm.sol";
import {ExpLib} from "../ExpLib.sol";
import {UtilsLib} from "../UtilsLib.sol";
import {ConstantsLib} from "../ConstantsLib.sol";
import {MathLib, WAD_INT as WAD} from "../MathLib.sol";
import {SharesMathLib} from "../../../../lib/morpho-blue/src/libraries/SharesMathLib.sol";
import {MathLib as MorphoMathLib} from "../../../../lib/morpho-blue/src/libraries/MathLib.sol";
import {UtilsLib as MorphoUtilsLib} from "../../../../lib/morpho-blue/src/libraries/UtilsLib.sol";
/// @dev Library to compute borrowRateView and expectedMarketBalances with only the market id.
/// @dev Must be used only for markets with an AdaptiveCurveIrm as irm.
library AdaptiveCurveIrmLib {
using MathLib for int256;
using UtilsLib for int256;
using MorphoMathLib for uint256;
using MorphoMathLib for uint128;
using SharesMathLib for uint256;
using MorphoUtilsLib for uint256;
/// @dev Same as the MorphoBalancesLib.expectedMarketBalances function, but takes the market id as input.
/// @dev Works only for markets with an AdaptiveCurveIrm as irm.
/// @dev Returns the expected totalSupplyAssets, totalSupplyShares, totalBorrowAssets, totalBorrowShares.
function expectedMarketBalances(address morpho, bytes32 id, address adaptiveCurveIrm)
internal
view
returns (uint256, uint256, uint256, uint256)
{
Market memory market = IMorpho(morpho).market(Id.wrap(id));
uint256 elapsed = block.timestamp - market.lastUpdate;
// Skipped if elapsed == 0 or totalBorrowAssets == 0 because interest would be null.
if (elapsed != 0 && market.totalBorrowAssets != 0) {
uint256 borrowRate = borrowRateView(id, market, adaptiveCurveIrm);
uint256 interest = market.totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market.totalBorrowAssets += interest.toUint128();
market.totalSupplyAssets += interest.toUint128();
if (market.fee != 0) {
uint256 feeAmount = interest.wMulDown(market.fee);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact
// that total supply is already updated.
uint256 feeShares =
feeAmount.toSharesDown(market.totalSupplyAssets - feeAmount, market.totalSupplyShares);
market.totalSupplyShares += feeShares.toUint128();
}
}
return (market.totalSupplyAssets, market.totalSupplyShares, market.totalBorrowAssets, market.totalBorrowShares);
}
/// @dev Same as the AdaptiveCurveIrm.borrowRateView function, but takes the market id as input.
/// @dev Works only for markets with an AdaptiveCurveIrm as irm.
/// @dev Returns avgRate.
function borrowRateView(bytes32 id, Market memory market, address adaptiveCurveIrm)
internal
view
returns (uint256)
{
(uint256 avgRate,) = _borrowRate(Id.wrap(id), market, adaptiveCurveIrm);
return avgRate;
}
/// @dev Same as the AdaptiveCurveIrm.borrowRate function, but takes the market id as input.
/// @dev Returns avgRate and endRateAtTarget.
function _borrowRate(Id id, Market memory market, address adaptiveCurveIrm)
internal
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 = IAdaptiveCurveIrm(adaptiveCurveIrm).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) internal 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) internal 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.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
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
import {IERC20} from "./IERC20.sol";
interface IERC4626 is IERC20 {
function asset() external view returns (address);
function totalAssets() external view returns (uint256);
function convertToAssets(uint256 shares) external view returns (uint256 assets);
function convertToShares(uint256 assets) external view returns (uint256 shares);
function deposit(uint256 assets, address onBehalf) external returns (uint256 shares);
function mint(uint256 shares, address onBehalf) external returns (uint256 assets);
function withdraw(uint256 assets, address receiver, address onBehalf) external returns (uint256 shares);
function redeem(uint256 shares, address receiver, address onBehalf) external returns (uint256 assets);
function previewDeposit(uint256 assets) external view returns (uint256 shares);
function previewMint(uint256 shares) external view returns (uint256 assets);
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
function previewRedeem(uint256 shares) external view returns (uint256 assets);
function maxDeposit(address onBehalf) external view returns (uint256 assets);
function maxMint(address onBehalf) external view returns (uint256 shares);
function maxWithdraw(address onBehalf) external view returns (uint256 assets);
function maxRedeem(address onBehalf) external view returns (uint256 shares);
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
interface IERC2612 {
function permit(address owner, address spender, uint256 shares, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;
/// @dev See VaultV2 NatSpec comments for more details on adapter's spec.
interface IAdapter {
/// @dev Returns the market' ids and the change in assets on this market.
function allocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
external
returns (bytes32[] memory ids, int256 change);
/// @dev Returns the market' ids and the change in assets on this market.
function deallocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
external
returns (bytes32[] memory ids, int256 change);
/// @dev Returns the current value of the investments of the adapter (in underlying asset).
function realAssets() external view returns (uint256 assets);
}// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;
library ErrorsLib {
error Abdicated();
error AbsoluteCapExceeded();
error AbsoluteCapNotDecreasing();
error AbsoluteCapNotIncreasing();
error ApproveReturnedFalse();
error ApproveReverted();
error AutomaticallyTimelocked();
error CannotReceiveShares();
error CannotReceiveAssets();
error CannotSendShares();
error CannotSendAssets();
error CapExceeded();
error CastOverflow();
error DataAlreadyPending();
error DataNotTimelocked();
error FeeInvariantBroken();
error FeeTooHigh();
error InvalidSigner();
error MaxRateTooHigh();
error NoCode();
error NotAdapter();
error NotInAdapterRegistry();
error PenaltyTooHigh();
error PermitDeadlineExpired();
error RelativeCapAboveOne();
error RelativeCapExceeded();
error RelativeCapNotDecreasing();
error RelativeCapNotIncreasing();
error TimelockNotDecreasing();
error TimelockNotExpired();
error TimelockNotIncreasing();
error TransferFromReturnedFalse();
error TransferFromReverted();
error TransferReturnedFalse();
error TransferReverted();
error Unauthorized();
error ZeroAbsoluteCap();
error ZeroAddress();
error ZeroAllocation();
}// 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 chains sharing the
/// same chain id and on forks because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// - The oracle price should not be able to change instantly such that the new price is less than the old price
/// multiplied by LLTV*LIF. In particular, if the loan asset is a vault that can receive donations, the oracle
/// should not price its shares using the AUM.
/// @dev Here is a list of assumptions on the market's dependencies which, if broken, could break Morpho's liveness
/// properties (funds could get stuck):
/// - The token should not revert on `transfer` and `transferFrom` if balances and approvals are right.
/// - The amount of assets supplied and borrowed should not be too high (max ~1e32), otherwise the number of shares
/// might not fit within 128 bits.
/// - The IRM should not revert on `borrowRate`.
/// - The IRM should not return a very high borrow rate (otherwise the computation of `interest` in
/// `_accrueInterest` can overflow).
/// - The oracle should not revert `price`.
/// - The oracle should not return a very high price (otherwise the computation of `maxBorrow` in `_isHealthy` or of
/// `assetsRepaid` in `liquidate` can overflow).
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoRepay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}// 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;
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; /// @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 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: 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: 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: 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: 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: 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-v1.1/=lib/vault-v2/lib/metamorpho-v1.1/",
"metamorpho/=lib/vault-v2/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/src/",
"vault-v2-adapter-registries/=lib/vault-v2-adapter-registries/src/",
"vault-v2/=lib/vault-v2/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_parentVault","type":"address"},{"internalType":"address","name":"_morpho","type":"address"},{"internalType":"address","name":"_adaptiveCurveIrm","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Abdicated","type":"error"},{"inputs":[],"name":"ApproveReturnedFalse","type":"error"},{"inputs":[],"name":"ApproveReverted","type":"error"},{"inputs":[],"name":"AutomaticallyTimelocked","type":"error"},{"inputs":[],"name":"DataAlreadyPending","type":"error"},{"inputs":[],"name":"DataNotTimelocked","type":"error"},{"inputs":[],"name":"IrmMismatch","type":"error"},{"inputs":[],"name":"LoanAssetMismatch","type":"error"},{"inputs":[],"name":"NoCode","type":"error"},{"inputs":[],"name":"SharePriceAboveOne","type":"error"},{"inputs":[],"name":"TimelockNotDecreasing","type":"error"},{"inputs":[],"name":"TimelockNotExpired","type":"error"},{"inputs":[],"name":"TimelockNotIncreasing","type":"error"},{"inputs":[],"name":"TransferReturnedFalse","type":"error"},{"inputs":[],"name":"TransferReverted","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"Abdicate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Accept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newAllocation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedShares","type":"uint256"}],"name":"Allocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"supplyShares","type":"uint256"}],"name":"BurnShares","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"newAllocation","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedShares","type":"uint256"}],"name":"Deallocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"DecreaseTimelock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"IncreaseTimelock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Revoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSkimRecipient","type":"address"}],"name":"SetSkimRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"Skim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"executableAt","type":"uint256"}],"name":"Submit","type":"event"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"abdicate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"abdicated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adapterId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adaptiveCurveIrm","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"address","name":"","type":"address"}],"name":"allocate","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"},{"internalType":"int256","name":"","type":"int256"}],"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"}],"name":"allocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"marketId","type":"bytes32"}],"name":"burnShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"address","name":"","type":"address"}],"name":"deallocate","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"decreaseTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"executableAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"marketId","type":"bytes32"}],"name":"expectedSupplyAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","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"}],"name":"ids","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"increaseTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"marketIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketIdsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"morpho","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"parentVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSkimRecipient","type":"address"}],"name":"setSkimRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skimRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"submit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"marketId","type":"bytes32"}],"name":"supplyShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"timelock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61014080604052346101de5760608161313a803803809161002082856101f5565b8339810103126101de576100338161022c565b61004b60406100446020850161022c565b930161022c565b3360805260a082905260e08390526040516338d52e0f60e01b81529092906020816004816001600160a01b0387165afa9081156101ea575f916101a1575b50906100f8936100e79260c05260405160208101906040825260046060820152637468697360e01b6080820152306040820152608081526100cb60a0826101f5565b519020610100526101205260c0516001600160a01b0316610240565b60c0516001600160a01b0316610240565b604051612e0890816103328239608051816105b2015260a05181818161019601528181610cb2015281816113450152818161164e015281816116990152611fa1015260c051818181610d0701528181611203015261139a015260e05181818161051301528181610eee015281816115590152612069015261010051818181610ab60152612732015261012051818181610d5e01528181611195015281816113f101526122ab0152f35b9190506020823d6020116101e2575b816101bd602093836101f5565b810103126101de576100f8936101d56100e79361022c565b91925093610089565b5f80fd5b3d91506101b0565b6040513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761021857604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101de57565b90813b15610322575f91829182604051602081019263095ea7b360e01b845260018060a01b0316602482015281196044820152604481526102826064826101f5565b51925af13d1561031a573d906001600160401b03821161021857604051916102b4601f8201601f1916602001846101f5565b82523d5f602084013e5b1561030b5780519081159182156102e8575b5050156102d957565b631f55ddd960e21b5f5260045ffd5b81925090602091810103126101de576020015180151581036101de575f806102d0565b637cceae2560e01b5f5260045ffd5b6060906102be565b633c11a9c560e21b5f5260045ffdfe6080806040526004361015610012575f80fd5b5f3560e01c9081630b467b9b14611672575080630fe36536146116045780631eadd7781461131d5780632b30997b14611278578063388af5b51461122757806338d52e0f146111b9578063399e3a501461114b5780633b2de5ac146110d35780634796629114610fd35780634e45f1ff14610c7657806356c0757314610c015780635c1a1a4f14610ad95780635fb86b0114610a815780636ead54d814610a39578063779a9683146109e35780638639fb071461096f57806399ee14c31461095757806399f7e86114610913578063ace48b45146108d8578063b2e328481461081c578063bc25cf77146105d6578063c45a015514610568578063cc3802bf14610537578063d8fbc833146104c9578063e470b8bc14610455578063e78ab14e146103e75763ef7fa71b14610145575f80fd5b3461030557610153366118ab565b6040517fe66f53b700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa80156103dc575f9061038f575b73ffffffffffffffffffffffffffffffffffffffff9150163303610367576040518183823760208183810160028152030190205461033f577fffffffff000000000000000000000000000000000000000000000000000000006102288284611cb3565b16917f5c1a1a4f0000000000000000000000000000000000000000000000000000000083036103095781600811610305577f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb917fffffffff000000000000000000000000000000000000000000000000000000006004830135165f525f6020526102b760405f20545b42611dcf565b60405182848237602081848101600281520301902055604051818382376020818381016002815203019020546102fa604051938493604085526040850191611d19565b9060208301520390a2005b5f80fd5b7f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb91835f525f6020526102b760405f20546102b1565b7fd91ff208000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b506020813d6020116103d4575b816103a960209383611963565b81010312610305576103cf73ffffffffffffffffffffffffffffffffffffffff91611c7a565b6101c5565b3d915061039c565b6040513d5f823e3d90fd5b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff0000000000000000000000000000000000000000000000000000000061043f611a24565b165f525f602052602060405f2054604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff000000000000000000000000000000000000000000000000000000006104ad611a24565b165f526001602052602060ff60405f2054166040519015158152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103055761056461055061054b36611ba8565b61270d565b604051918291602083526020830190611b14565b0390f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055761060d611a53565b73ffffffffffffffffffffffffffffffffffffffff600354168033036103675773ffffffffffffffffffffffffffffffffffffffff821691604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481875afa9283156103dc575f936107e8575b50813b156107c0575f9182918260405160208101927fa9059cbb0000000000000000000000000000000000000000000000000000000084526024820152866044820152604481526106db606482611963565b51925af13d156107b8573d906106f0826119a4565b916106fe6040519384611963565b82523d5f602084013e5b15610790578051908115918215610776575b50501561074e5760207f5e99aaf6d3588fb2497fde044168e8c046704a3223559cfe107f8f94b42cefdd91604051908152a2005b7f2f0470fc000000000000000000000000000000000000000000000000000000005f5260045ffd5b6107899250602080918301019101611c9b565b838061071a565b7face2a47e000000000000000000000000000000000000000000000000000000005f5260045ffd5b606090610708565b7ff046a714000000000000000000000000000000000000000000000000000000005f5260045ffd5b9092506020813d602011610814575b8161080460209383611963565b8101031261030557519184610689565b3d91506107f7565b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff00000000000000000000000000000000000000000000000000000000610874611a24565b61087c612993565b16805f52600160205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557fa8480b135a28741e8c059528bf8f82de70278485fb86bfc816a183801f0a85705f80a2005b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305576020600454604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602061094f600435612003565b604051908152f35b3461030557602061094f61096a36611ba8565b611f13565b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043567ffffffffffffffff8111610305576020806109c2819336906004016119de565b604051928184925191829101835e8101600281520301902054604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043560045481101561030557610a2a602091611b63565b90549060031b1c604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305576004355f526005602052602060405f2054604051908152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346103055760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557610b10611a24565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591610b3d612993565b16907f5c1a1a4f000000000000000000000000000000000000000000000000000000008214610bd957815f525f60205260405f20548111610bb15760207f488e0bfafe0a9580c2271bee1f563a47d309f0105ca950ea525d909b43b36daf91835f525f82528060405f2055604051908152a2005b7f17e0a21c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f07e895b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305575f5f906004545b808310610c4857602082604051908152f35b90610c6d600191610c67610c5b86611b63565b90549060031b1c612003565b90611dcf565b92019190610c36565b3461030557610c9a610c8736611a76565b5050919060208082518301019101611d57565b9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036103675773ffffffffffffffffffffffffffffffffffffffff82511673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001603610fab5773ffffffffffffffffffffffffffffffffffffffff60608301511673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001603610f835760a082205f9180610e01575b50610deb83610da1610df19495611f13565b927fc3505702fbdd1c334673aa66559f4546d749681c4d2509c99c07fabf01b3227f6040610dce83612003565b97610dda8988866127f8565b8151908982526020820152a261270d565b92611e09565b9061056460405192839283611b47565b9150604051917f5c2bea49000000000000000000000000000000000000000000000000000000008352610eb760048401856080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b60a48301525f60c48301523060e483015230610104830152604082610124815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af19182156103dc575f92610f4a575b50610deb8293610df19394835f526005602052610f4060405f20918254611e21565b9055939250610d8f565b610df19250610f73610deb9160403d604011610f7c575b610f6b8183611963565b810190611db9565b90509250610f1e565b503d610f61565b7f6a7ca6c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f58ec95f2000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103055760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055761100a611a24565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591611037612993565b16907f5c1a1a4f000000000000000000000000000000000000000000000000000000008214610bd957815f525f60205260405f205481106110ab5760207fed380a7a1f0afc99b313ac7d9f1e52e44430d32b4639c7993bd0021974e30c0e91835f525f82528060405f2055604051908152a2005b7f470f70c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043561110d612993565b5f8181526005602090815260408083208054939055519182527f82234a83a62d451b7758221f55cd21fe22d35d7798bdfea8a44168fd355880cb91a2005b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055773ffffffffffffffffffffffffffffffffffffffff6112c4611a53565b6112cc612993565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003557f2e7908865670e21b9779422cadf5f1cba271a62bb95c71eaaf615c0a1c48ebee5f80a2005b346103055761132e610c8736611a76565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036103675773ffffffffffffffffffffffffffffffffffffffff81511673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001603610fab5773ffffffffffffffffffffffffffffffffffffffff60608201511673ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001603610f835760a08120905f9280611462575b5090610deb82611435610df194611f13565b927f67bd2993814767565e883edd1e76edf105cdd33766384ca8495e53562e20bea76040610dce83612003565b9250906040517fa99aad8900000000000000000000000000000000000000000000000000000000815261151860048201846080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b8360a48201525f60c48201523060e48201526101206101048201525f610124820152604081610144815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af19081156103dc575f916115e3575b50809381106115bb57610df192610deb91835f5260056020526115b160405f20918254611dcf565b9055919250611423565b7fff8d32ad000000000000000000000000000000000000000000000000000000005f5260045ffd5b6115fc915060403d604011610f7c57610f6b8183611963565b905084611589565b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461030557611680366118ab565b909173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016907fe66f53b7000000000000000000000000000000000000000000000000000000008152602081600481855afa80156103dc575f9061185e575b73ffffffffffffffffffffffffffffffffffffffff91501633149081156117e1575b50156103675760405181838237602081838101600281520301902054156117b9575f604051828482376020818481016002815203019020557f70521cf6a7c2458c5ad406081ad7b3bc4afd31b01b586a157a9780fcee6a77cb6117b47fffffffff0000000000000000000000000000000000000000000000000000000061179c8486611cb3565b16936040519182916020835233956020840191611d19565b0390a3005b7f1ea942a8000000000000000000000000000000000000000000000000000000005f5260045ffd5b60249150602090604051928380927fba03a75f0000000000000000000000000000000000000000000000000000000082523360048301525afa9081156103dc575f9161182f575b5083611715565b611851915060203d602011611857575b6118498183611963565b810190611c9b565b83611828565b503d61183f565b506020813d6020116118a3575b8161187860209383611963565b810103126103055761189e73ffffffffffffffffffffffffffffffffffffffff91611c7a565b6116f3565b3d915061186b565b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103055760043567ffffffffffffffff811161030557826023820112156103055780600401359267ffffffffffffffff84116103055760248483010111610305576024019190565b60a0810190811067ffffffffffffffff82111761193657604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761193657604052565b67ffffffffffffffff811161193657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f82011215610305578035906119f5826119a4565b92611a036040519485611963565b8284526020838301011161030557815f926020809301838601378301015290565b600435907fffffffff000000000000000000000000000000000000000000000000000000008216820361030557565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361030557565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610305576004359067ffffffffffffffff821161030557611abf916004016119de565b90602435906044357fffffffff0000000000000000000000000000000000000000000000000000000081168103610305579060643573ffffffffffffffffffffffffffffffffffffffff811681036103055790565b90602080835192838152019201905f5b818110611b315750505090565b8251845260209384019390920191600101611b24565b929190611b5e602091604086526040860190611b14565b930152565b600454811015611b7b5760045f5260205f2001905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a091011261030557604051611bde8161191a565b60043573ffffffffffffffffffffffffffffffffffffffff8116810361030557815260243573ffffffffffffffffffffffffffffffffffffffff8116810361030557602082015260443573ffffffffffffffffffffffffffffffffffffffff8116810361030557604082015260643573ffffffffffffffffffffffffffffffffffffffff81168103610305576060820152608435608082015290565b519073ffffffffffffffffffffffffffffffffffffffff8216820361030557565b90816020910312610305575180151581036103055790565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110611ce7575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b908160a091031261030557608060405191611d718361191a565b611d7a81611c7a565b8352611d8860208201611c7a565b6020840152611d9960408201611c7a565b6040840152611daa60608201611c7a565b60608401520151608082015290565b9190826040910312610305576020825192015190565b91908201809211611ddc57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810392915f138015828513169184121617611ddc57565b91908203918211611ddc57565b916040611f1192949360e08152601160e08201527f746869732f6d61726b6574506172616d7300000000000000000000000000000061010082015273ffffffffffffffffffffffffffffffffffffffff61012082019616602082015201906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b565b604051611f5581611f2960208201943086611e2e565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611963565b519020604051907fc69507dd000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9081156103dc575f91611fd4575090565b90506020813d602011611ffb575b81611fef60209383611963565b81010312610305575190565b3d9150611fe2565b5f90805f52600560205260405f205480155f1461201f57505090565b604051917f5c60e39a00000000000000000000000000000000000000000000000000000000835280600484015260c08360248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9283156103dc575f9361265b575b5060808301906120bc6fffffffffffffffffffffffffffffffff83511642611e21565b908115158061263c575b612146575b5050506fffffffffffffffffffffffffffffffff60208184511693015116926001830180931161211957620f424084018094116121195750612116929161211191612b8c565b612c7a565b90565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b8451929591926fffffffffffffffffffffffffffffffff168015612635576fffffffffffffffffffffffffffffffff60408701511690670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611ddc576121a691612c7a565b670c7d713b49da00008113156126265767016345785d8a0000905b7ffffffffffffffffffffffffffffffffffffffffffffffffff3828ec4b62600008101908113600116611ddc57670de0b6b3a7640000810290808205670de0b6b3a76400001490151715611ddc5781156125f9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f8000000000000000000000000000000000000000000000000000000000000000821416611ddc570595604051917f01977b57000000000000000000000000000000000000000000000000000000008352600483015260208260248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9182156103dc575f926125c5575b5081612536575050634b9a1eff905b5f86121561251a5750670de0b6b3a7640000612310670a688906bd8b0000965f97612c84565b05670de0b6b3a764000081019086670de0b6b3a7640000831291129080158216911516176124ed57670de0b6b3a764000061234f81936123b193612c84565b056123ab61237560408801956fffffffffffffffffffffffffffffffff87511693612b8c565b6123a6671bc16d674ec8000061238b8380612b8c565b046729a2241af62c000061239f8483612b8c565b0492611dcf565b611dcf565b90612b8c565b04906fffffffffffffffffffffffffffffffff6123d96123d084612b9f565b82845116612b5a565b1690526fffffffffffffffffffffffffffffffff6124026123f983612b9f565b82865116612b5a565b1683526fffffffffffffffffffffffffffffffff60a0840151169081612429575b806120cb565b670de0b6b3a76400009161243c91612b8c565b0461245a816fffffffffffffffffffffffffffffffff855116611e21565b60208401916fffffffffffffffffffffffffffffffff83511690620f424082018092116124c057600183018093116124c0576124b16fffffffffffffffffffffffffffffffff936121116124b6946123d094612b8c565b612b9f565b1690525f80612423565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b94612310670de0b6b3a7640000916729a2241af62c0000612c84565b612577906125716fffffffffffffffffffffffffffffffff670de0b6b3a76400006125678b650171268b5ad4612c84565b0592511642611e21565b90612c84565b806125835750906122ea565b8061259e60026125966125a49486612cdd565b920584612cdd565b92612cc2565b8160011b916002830503611ddc576004916125be91612cc2565b05906122ea565b9091506020813d6020116125f1575b816125e160209383611963565b810103126103055751905f6122db565b3d91506125d4565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b670c7d713b49da0000906121c1565b505f6121a6565b506fffffffffffffffffffffffffffffffff60408601511615156120c6565b90925060c0813d60c011612705575b8161267760c09383611963565b81010312610305576040519060c0820182811067ffffffffffffffff821117611936576126f99160a0916040526126ad81612b3d565b84526126bb60208201612b3d565b60208501526126cc60408201612b3d565b60408501526126dd60608201612b3d565b60608501526126ee60808201612b3d565b608085015201612b3d565b60a0820152915f612099565b3d915061266a565b6040519061271c608083611963565b60038252602082016060368237825115611b7b577f0000000000000000000000000000000000000000000000000000000000000000905273ffffffffffffffffffffffffffffffffffffffff602082015116604051602081019160408352600f60608301527f636f6c6c61746572616c546f6b656e000000000000000000000000000000000060808301526040820152608081526127bb60a082611963565b519020825160011015611b7b5760408301526040516127e381611f2960208201943086611e2e565b519020815160021015611b7b57606082015290565b9190159081158061298b575b1561294b5750505f5b60045480821015612946578261282283611b63565b90549060031b1c14612837575060010161280d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810192508211611ddc5761287e6128716128b493611b63565b90549060031b1c91611b63565b9091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83549160031b92831b921b1916179055565b6004548015612919577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff016128e881611b63565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600455565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b505050565b81612981575b506129595750565b60045490680100000000000000008210156119365761287e826001611f119401600455611b63565b905015155f612951565b508015612804565b5f357fffffffff0000000000000000000000000000000000000000000000000000000081169060043610612b09575b50604051365f8237602081368101600281520301902054156117b957604051365f82376020813681016002815203019020544210612ae1577fffffffff0000000000000000000000000000000000000000000000000000000016805f52600160205260ff60405f205416612ab9575f604051368282376020813681016002815203019020557f29aa42fc192ff77ef42105abba283197ac841341e196e417a7fc2784cdc4e5fb60405160208152366020820152365f60408301375f602080368401010152602081817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f360116820101030190a2565b7f281df4aa000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f621e25c3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fffffffff000000000000000000000000000000000000000000000000000000008092503660040360031b1b16165f6129c2565b51906fffffffffffffffffffffffffffffffff8216820361030557565b906fffffffffffffffffffffffffffffffff809116911601906fffffffffffffffffffffffffffffffff8211611ddc57565b81810292918115918404141715611ddc57565b604051612bad604082611963565b6014815260208101907f6d61782075696e7431323820657863656564656400000000000000000000000082526fffffffffffffffffffffffffffffffff8311612c075750506fffffffffffffffffffffffffffffffff1690565b6044907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6040519485937f08c379a0000000000000000000000000000000000000000000000000000000008552602060048601525180918160248701528686015e5f85828601015201168101030190fd5b81156125f9570490565b81810292915f82127f8000000000000000000000000000000000000000000000000000000000000000821416611ddc578184051490151715611ddc57565b9190915f8382019384129112908015821691151617611ddc57565b612cf390612571670de0b6b3a764000093612d14565b056301e3da5f90640ec41a0ddf818112908218021890818113908218021890565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d88112612df6576805168fd0946fc0415f811215612dd8575f811215612db857670de0b6b3a764000067099e8db03256ce5d7ffffffffffffffffffffffffffffffffffffffffffffffffffb30b927e6d498d25b8301059167099e8db03256ce5d8302900360028282800205050101905f8112155f14612db2571b90565b5f031d90565b670de0b6b3a764000067099e8db03256ce5d6704cf46d8192b672e612d88565b50780931d81650c7d88b800000000000000000000000000000000090565b505f9056fea164736f6c634300081c000a00000000000000000000000010f8853060dc79db44384b418ea2609063d51551000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b428
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c9081630b467b9b14611672575080630fe36536146116045780631eadd7781461131d5780632b30997b14611278578063388af5b51461122757806338d52e0f146111b9578063399e3a501461114b5780633b2de5ac146110d35780634796629114610fd35780634e45f1ff14610c7657806356c0757314610c015780635c1a1a4f14610ad95780635fb86b0114610a815780636ead54d814610a39578063779a9683146109e35780638639fb071461096f57806399ee14c31461095757806399f7e86114610913578063ace48b45146108d8578063b2e328481461081c578063bc25cf77146105d6578063c45a015514610568578063cc3802bf14610537578063d8fbc833146104c9578063e470b8bc14610455578063e78ab14e146103e75763ef7fa71b14610145575f80fd5b3461030557610153366118ab565b6040517fe66f53b700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d51551165afa80156103dc575f9061038f575b73ffffffffffffffffffffffffffffffffffffffff9150163303610367576040518183823760208183810160028152030190205461033f577fffffffff000000000000000000000000000000000000000000000000000000006102288284611cb3565b16917f5c1a1a4f0000000000000000000000000000000000000000000000000000000083036103095781600811610305577f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb917fffffffff000000000000000000000000000000000000000000000000000000006004830135165f525f6020526102b760405f20545b42611dcf565b60405182848237602081848101600281520301902055604051818382376020818381016002815203019020546102fa604051938493604085526040850191611d19565b9060208301520390a2005b5f80fd5b7f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb91835f525f6020526102b760405f20546102b1565b7fd91ff208000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b506020813d6020116103d4575b816103a960209383611963565b81010312610305576103cf73ffffffffffffffffffffffffffffffffffffffff91611c7a565b6101c5565b3d915061039c565b6040513d5f823e3d90fd5b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff0000000000000000000000000000000000000000000000000000000061043f611a24565b165f525f602052602060405f2054604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff000000000000000000000000000000000000000000000000000000006104ad611a24565b165f526001602052602060ff60405f2054166040519015158152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc168152f35b346103055761056461055061054b36611ba8565b61270d565b604051918291602083526020830190611b14565b0390f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006d6a3ba62836d6b40277767dcac8fd390d4bcedc168152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055761060d611a53565b73ffffffffffffffffffffffffffffffffffffffff600354168033036103675773ffffffffffffffffffffffffffffffffffffffff821691604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481875afa9283156103dc575f936107e8575b50813b156107c0575f9182918260405160208101927fa9059cbb0000000000000000000000000000000000000000000000000000000084526024820152866044820152604481526106db606482611963565b51925af13d156107b8573d906106f0826119a4565b916106fe6040519384611963565b82523d5f602084013e5b15610790578051908115918215610776575b50501561074e5760207f5e99aaf6d3588fb2497fde044168e8c046704a3223559cfe107f8f94b42cefdd91604051908152a2005b7f2f0470fc000000000000000000000000000000000000000000000000000000005f5260045ffd5b6107899250602080918301019101611c9b565b838061071a565b7face2a47e000000000000000000000000000000000000000000000000000000005f5260045ffd5b606090610708565b7ff046a714000000000000000000000000000000000000000000000000000000005f5260045ffd5b9092506020813d602011610814575b8161080460209383611963565b8101031261030557519184610689565b3d91506107f7565b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305577fffffffff00000000000000000000000000000000000000000000000000000000610874611a24565b61087c612993565b16805f52600160205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557fa8480b135a28741e8c059528bf8f82de70278485fb86bfc816a183801f0a85705f80a2005b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305576020600454604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602061094f600435612003565b604051908152f35b3461030557602061094f61096a36611ba8565b611f13565b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043567ffffffffffffffff8111610305576020806109c2819336906004016119de565b604051928184925191829101835e8101600281520301902054604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043560045481101561030557610a2a602091611b63565b90549060031b1c604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305576004355f526005602052602060405f2054604051908152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760206040517f52b72ee5587f9fec23c983da9d7c6fde133716c7aebb47e3837d5a7da31f6dbd8152f35b346103055760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557610b10611a24565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591610b3d612993565b16907f5c1a1a4f000000000000000000000000000000000000000000000000000000008214610bd957815f525f60205260405f20548111610bb15760207f488e0bfafe0a9580c2271bee1f563a47d309f0105ca950ea525d909b43b36daf91835f525f82528060405f2055604051908152a2005b7f17e0a21c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f07e895b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610305575f5f906004545b808310610c4857602082604051908152f35b90610c6d600191610c67610c5b86611b63565b90549060031b1c612003565b90611dcf565b92019190610c36565b3461030557610c9a610c8736611a76565b5050919060208082518301019101611d57565b9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d515511633036103675773ffffffffffffffffffffffffffffffffffffffff82511673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a8d77f7a47d0a00eccdb257ab157d168274e4ec1603610fab5773ffffffffffffffffffffffffffffffffffffffff60608301511673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b4281603610f835760a082205f9180610e01575b50610deb83610da1610df19495611f13565b927fc3505702fbdd1c334673aa66559f4546d749681c4d2509c99c07fabf01b3227f6040610dce83612003565b97610dda8988866127f8565b8151908982526020820152a261270d565b92611e09565b9061056460405192839283611b47565b9150604051917f5c2bea49000000000000000000000000000000000000000000000000000000008352610eb760048401856080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b60a48301525f60c48301523060e483015230610104830152604082610124815f73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc165af19182156103dc575f92610f4a575b50610deb8293610df19394835f526005602052610f4060405f20918254611e21565b9055939250610d8f565b610df19250610f73610deb9160403d604011610f7c575b610f6b8183611963565b810190611db9565b90509250610f1e565b503d610f61565b7f6a7ca6c7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f58ec95f2000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103055760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055761100a611a24565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591611037612993565b16907f5c1a1a4f000000000000000000000000000000000000000000000000000000008214610bd957815f525f60205260405f205481106110ab5760207fed380a7a1f0afc99b313ac7d9f1e52e44430d32b4639c7993bd0021974e30c0e91835f525f82528060405f2055604051908152a2005b7f470f70c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055760043561110d612993565b5f8181526005602090815260408083208054939055519182527f82234a83a62d451b7758221f55cd21fe22d35d7798bdfea8a44168fd355880cb91a2005b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b428168152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a8d77f7a47d0a00eccdb257ab157d168274e4ec168152f35b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b346103055760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103055773ffffffffffffffffffffffffffffffffffffffff6112c4611a53565b6112cc612993565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003557f2e7908865670e21b9779422cadf5f1cba271a62bb95c71eaaf615c0a1c48ebee5f80a2005b346103055761132e610c8736611a76565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d515511633036103675773ffffffffffffffffffffffffffffffffffffffff81511673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000005a8d77f7a47d0a00eccdb257ab157d168274e4ec1603610fab5773ffffffffffffffffffffffffffffffffffffffff60608201511673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b4281603610f835760a08120905f9280611462575b5090610deb82611435610df194611f13565b927f67bd2993814767565e883edd1e76edf105cdd33766384ca8495e53562e20bea76040610dce83612003565b9250906040517fa99aad8900000000000000000000000000000000000000000000000000000000815261151860048201846080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b8360a48201525f60c48201523060e48201526101206101048201525f610124820152604081610144815f73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc165af19081156103dc575f916115e3575b50809381106115bb57610df192610deb91835f5260056020526115b160405f20918254611dcf565b9055919250611423565b7fff8d32ad000000000000000000000000000000000000000000000000000000005f5260045ffd5b6115fc915060403d604011610f7c57610f6b8183611963565b905084611589565b34610305575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261030557602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d51551168152f35b3461030557611680366118ab565b909173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d5155116907fe66f53b7000000000000000000000000000000000000000000000000000000008152602081600481855afa80156103dc575f9061185e575b73ffffffffffffffffffffffffffffffffffffffff91501633149081156117e1575b50156103675760405181838237602081838101600281520301902054156117b9575f604051828482376020818481016002815203019020557f70521cf6a7c2458c5ad406081ad7b3bc4afd31b01b586a157a9780fcee6a77cb6117b47fffffffff0000000000000000000000000000000000000000000000000000000061179c8486611cb3565b16936040519182916020835233956020840191611d19565b0390a3005b7f1ea942a8000000000000000000000000000000000000000000000000000000005f5260045ffd5b60249150602090604051928380927fba03a75f0000000000000000000000000000000000000000000000000000000082523360048301525afa9081156103dc575f9161182f575b5083611715565b611851915060203d602011611857575b6118498183611963565b810190611c9b565b83611828565b503d61183f565b506020813d6020116118a3575b8161187860209383611963565b810103126103055761189e73ffffffffffffffffffffffffffffffffffffffff91611c7a565b6116f3565b3d915061186b565b9060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103055760043567ffffffffffffffff811161030557826023820112156103055780600401359267ffffffffffffffff84116103055760248483010111610305576024019190565b60a0810190811067ffffffffffffffff82111761193657604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761193657604052565b67ffffffffffffffff811161193657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f82011215610305578035906119f5826119a4565b92611a036040519485611963565b8284526020838301011161030557815f926020809301838601378301015290565b600435907fffffffff000000000000000000000000000000000000000000000000000000008216820361030557565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361030557565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610305576004359067ffffffffffffffff821161030557611abf916004016119de565b90602435906044357fffffffff0000000000000000000000000000000000000000000000000000000081168103610305579060643573ffffffffffffffffffffffffffffffffffffffff811681036103055790565b90602080835192838152019201905f5b818110611b315750505090565b8251845260209384019390920191600101611b24565b929190611b5e602091604086526040860190611b14565b930152565b600454811015611b7b5760045f5260205f2001905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a091011261030557604051611bde8161191a565b60043573ffffffffffffffffffffffffffffffffffffffff8116810361030557815260243573ffffffffffffffffffffffffffffffffffffffff8116810361030557602082015260443573ffffffffffffffffffffffffffffffffffffffff8116810361030557604082015260643573ffffffffffffffffffffffffffffffffffffffff81168103610305576060820152608435608082015290565b519073ffffffffffffffffffffffffffffffffffffffff8216820361030557565b90816020910312610305575180151581036103055790565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110611ce7575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b908160a091031261030557608060405191611d718361191a565b611d7a81611c7a565b8352611d8860208201611c7a565b6020840152611d9960408201611c7a565b6040840152611daa60608201611c7a565b60608401520151608082015290565b9190826040910312610305576020825192015190565b91908201809211611ddc57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810392915f138015828513169184121617611ddc57565b91908203918211611ddc57565b916040611f1192949360e08152601160e08201527f746869732f6d61726b6574506172616d7300000000000000000000000000000061010082015273ffffffffffffffffffffffffffffffffffffffff61012082019616602082015201906080809173ffffffffffffffffffffffffffffffffffffffff815116845273ffffffffffffffffffffffffffffffffffffffff602082015116602085015273ffffffffffffffffffffffffffffffffffffffff604082015116604085015273ffffffffffffffffffffffffffffffffffffffff60608201511660608501520151910152565b565b604051611f5581611f2960208201943086611e2e565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611963565b519020604051907fc69507dd000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000010f8853060dc79db44384b418ea2609063d51551165afa9081156103dc575f91611fd4575090565b90506020813d602011611ffb575b81611fef60209383611963565b81010312610305575190565b3d9150611fe2565b5f90805f52600560205260405f205480155f1461201f57505090565b604051917f5c60e39a00000000000000000000000000000000000000000000000000000000835280600484015260c08360248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc165afa9283156103dc575f9361265b575b5060808301906120bc6fffffffffffffffffffffffffffffffff83511642611e21565b908115158061263c575b612146575b5050506fffffffffffffffffffffffffffffffff60208184511693015116926001830180931161211957620f424084018094116121195750612116929161211191612b8c565b612c7a565b90565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b8451929591926fffffffffffffffffffffffffffffffff168015612635576fffffffffffffffffffffffffffffffff60408701511690670de0b6b3a7640000820291808304670de0b6b3a76400001490151715611ddc576121a691612c7a565b670c7d713b49da00008113156126265767016345785d8a0000905b7ffffffffffffffffffffffffffffffffffffffffffffffffff3828ec4b62600008101908113600116611ddc57670de0b6b3a7640000810290808205670de0b6b3a76400001490151715611ddc5781156125f9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82147f8000000000000000000000000000000000000000000000000000000000000000821416611ddc570595604051917f01977b57000000000000000000000000000000000000000000000000000000008352600483015260208260248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b428165afa9182156103dc575f926125c5575b5081612536575050634b9a1eff905b5f86121561251a5750670de0b6b3a7640000612310670a688906bd8b0000965f97612c84565b05670de0b6b3a764000081019086670de0b6b3a7640000831291129080158216911516176124ed57670de0b6b3a764000061234f81936123b193612c84565b056123ab61237560408801956fffffffffffffffffffffffffffffffff87511693612b8c565b6123a6671bc16d674ec8000061238b8380612b8c565b046729a2241af62c000061239f8483612b8c565b0492611dcf565b611dcf565b90612b8c565b04906fffffffffffffffffffffffffffffffff6123d96123d084612b9f565b82845116612b5a565b1690526fffffffffffffffffffffffffffffffff6124026123f983612b9f565b82865116612b5a565b1683526fffffffffffffffffffffffffffffffff60a0840151169081612429575b806120cb565b670de0b6b3a76400009161243c91612b8c565b0461245a816fffffffffffffffffffffffffffffffff855116611e21565b60208401916fffffffffffffffffffffffffffffffff83511690620f424082018092116124c057600183018093116124c0576124b16fffffffffffffffffffffffffffffffff936121116124b6946123d094612b8c565b612b9f565b1690525f80612423565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b94612310670de0b6b3a7640000916729a2241af62c0000612c84565b612577906125716fffffffffffffffffffffffffffffffff670de0b6b3a76400006125678b650171268b5ad4612c84565b0592511642611e21565b90612c84565b806125835750906122ea565b8061259e60026125966125a49486612cdd565b920584612cdd565b92612cc2565b8160011b916002830503611ddc576004916125be91612cc2565b05906122ea565b9091506020813d6020116125f1575b816125e160209383611963565b810103126103055751905f6122db565b3d91506125d4565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b670c7d713b49da0000906121c1565b505f6121a6565b506fffffffffffffffffffffffffffffffff60408601511615156120c6565b90925060c0813d60c011612705575b8161267760c09383611963565b81010312610305576040519060c0820182811067ffffffffffffffff821117611936576126f99160a0916040526126ad81612b3d565b84526126bb60208201612b3d565b60208501526126cc60408201612b3d565b60408501526126dd60608201612b3d565b60608501526126ee60808201612b3d565b608085015201612b3d565b60a0820152915f612099565b3d915061266a565b6040519061271c608083611963565b60038252602082016060368237825115611b7b577f52b72ee5587f9fec23c983da9d7c6fde133716c7aebb47e3837d5a7da31f6dbd905273ffffffffffffffffffffffffffffffffffffffff602082015116604051602081019160408352600f60608301527f636f6c6c61746572616c546f6b656e000000000000000000000000000000000060808301526040820152608081526127bb60a082611963565b519020825160011015611b7b5760408301526040516127e381611f2960208201943086611e2e565b519020815160021015611b7b57606082015290565b9190159081158061298b575b1561294b5750505f5b60045480821015612946578261282283611b63565b90549060031b1c14612837575060010161280d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810192508211611ddc5761287e6128716128b493611b63565b90549060031b1c91611b63565b9091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83549160031b92831b921b1916179055565b6004548015612919577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff016128e881611b63565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600455565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b505050565b81612981575b506129595750565b60045490680100000000000000008210156119365761287e826001611f119401600455611b63565b905015155f612951565b508015612804565b5f357fffffffff0000000000000000000000000000000000000000000000000000000081169060043610612b09575b50604051365f8237602081368101600281520301902054156117b957604051365f82376020813681016002815203019020544210612ae1577fffffffff0000000000000000000000000000000000000000000000000000000016805f52600160205260ff60405f205416612ab9575f604051368282376020813681016002815203019020557f29aa42fc192ff77ef42105abba283197ac841341e196e417a7fc2784cdc4e5fb60405160208152366020820152365f60408301375f602080368401010152602081817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f360116820101030190a2565b7f281df4aa000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f621e25c3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fffffffff000000000000000000000000000000000000000000000000000000008092503660040360031b1b16165f6129c2565b51906fffffffffffffffffffffffffffffffff8216820361030557565b906fffffffffffffffffffffffffffffffff809116911601906fffffffffffffffffffffffffffffffff8211611ddc57565b81810292918115918404141715611ddc57565b604051612bad604082611963565b6014815260208101907f6d61782075696e7431323820657863656564656400000000000000000000000082526fffffffffffffffffffffffffffffffff8311612c075750506fffffffffffffffffffffffffffffffff1690565b6044907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f6040519485937f08c379a0000000000000000000000000000000000000000000000000000000008552602060048601525180918160248701528686015e5f85828601015201168101030190fd5b81156125f9570490565b81810292915f82127f8000000000000000000000000000000000000000000000000000000000000000821416611ddc578184051490151715611ddc57565b9190915f8382019384129112908015821691151617611ddc57565b612cf390612571670de0b6b3a764000093612d14565b056301e3da5f90640ec41a0ddf818112908218021890818113908218021890565b7ffffffffffffffffffffffffffffffffffffffffffffffffdc0d0570925a462d88112612df6576805168fd0946fc0415f811215612dd8575f811215612db857670de0b6b3a764000067099e8db03256ce5d7ffffffffffffffffffffffffffffffffffffffffffffffffffb30b927e6d498d25b8301059167099e8db03256ce5d8302900360028282800205050101905f8112155f14612db2571b90565b5f031d90565b670de0b6b3a764000067099e8db03256ce5d6704cf46d8192b672e612d88565b50780931d81650c7d88b800000000000000000000000000000000090565b505f9056fea164736f6c634300081c000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000010f8853060dc79db44384b418ea2609063d51551000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b428
-----Decoded View---------------
Arg [0] : _parentVault (address): 0x10f8853060Dc79dB44384b418Ea2609063D51551
Arg [1] : _morpho (address): 0xD50F2DffFd62f94Ee4AEd9ca05C61d0753268aBc
Arg [2] : _adaptiveCurveIrm (address): 0x4F708C0ae7deD3d74736594C2109C2E3c065B428
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000010f8853060dc79db44384b418ea2609063d51551
Arg [1] : 000000000000000000000000d50f2dfffd62f94ee4aed9ca05c61d0753268abc
Arg [2] : 0000000000000000000000004f708c0ae7ded3d74736594c2109c2e3c065b428
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
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.