Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MorphoHelper
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
No with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
// Morpho Blue interfaces
import {Id, IMorpho, MarketParams, Market, Position} from "../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IOracle} from "../lib/morpho-blue/src/interfaces/IOracle.sol";
import {IIrm} from "../lib/morpho-blue/src/interfaces/IIrm.sol";
// Morpho Blue libraries
import {MathLib} from "../lib/morpho-blue/src/libraries/MathLib.sol";
import {MarketParamsLib} from "../lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {MorphoBalancesLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoBalancesLib.sol";
import {MorphoStorageLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoStorageLib.sol";
import {MorphoLib} from "../lib/morpho-blue/src/libraries/periphery/MorphoLib.sol";
import "../lib/morpho-blue/src/libraries/ConstantsLib.sol";
// OpenZeppelin upgradeability
import {Initializable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import {UUPSUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol";
import {AccessControlUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol";
// Project interfaces
import {IMetaMorpho, MarketAllocation} from "./interfaces/IMetaMorpho.sol";
import {IPublicAllocator, FlowCapsConfig} from "./interfaces/IPublicAllocator.sol";
import {IMorphoReader, MarketDataExt, PositionExt} from "./interfaces/IMorphoReader.sol";
/**
* @title MorphoHelper
* @author Morpho Labs
* @notice Helper contract facilitating interactions with Morpho Blue and MetaMorpho vaults.
* @dev Provides restricted functions for operators/admins to manage vaults and public allocator settings,
* as well as view functions to read data from Morpho Blue.
* Upgradeable using the UUPS pattern.
*/
contract MorphoHelper is Initializable, UUPSUpgradeable, AccessControlUpgradeable {
using MathLib for uint256;
using MorphoBalancesLib for IMorpho;
using MorphoStorageLib for IMorpho;
using MorphoLib for IMorpho;
using MarketParamsLib for MarketParams;
// =========================================================================
// Custom Structs
// =========================================================================
/// @notice Represents a withdrawal/deposit instruction for a specific market.
struct Withdrawal {
MarketParams market; /// The market parameters.
int256 amount; /// The amount of assets to withdraw (positive) or deposit (negative).
}
/// @notice Represents a withdrawal/deposit instruction for a market ID.
struct WithdrawalById {
Id marketId; /// The market ID.
int256 amount; /// The amount of assets to withdraw (positive) or deposit (negative).
}
// =========================================================================
// Constants & State
// =========================================================================
/// @notice Role for operators allowed to perform restricted actions.
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
/// @notice Role for accounts allowed to upgrade the contract.
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
/// @notice The Morpho Blue core contract instance.
IMorpho public morpho;
/// @notice The Public Allocator contract instance.
IPublicAllocator public public_allocator;
// =========================================================================
// Constructor & Initializer
// =========================================================================
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
if (block.chainid == 1) { // Ethereum Mainnet
morpho = IMorpho(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
public_allocator = IPublicAllocator(0xfd32fA2ca22c76dD6E550706Ad913FC6CE91c75D);
} else if (block.chainid == 8453) { // Base Mainnet
morpho = IMorpho(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb);
public_allocator = IPublicAllocator(0xA090dD1a701408Df1d4d0B85b716c87565f90467);
} else if (block.chainid == 130) { // Unichain Mainnet
morpho = IMorpho(0x8f5ae9CddB9f68de460C77730b018Ae7E04a140A);
public_allocator = IPublicAllocator(0xB0c9a107fA17c779B3378210A7a593e88938C7C9);
} else if (block.chainid == 747474) { // Katana Mainnet
morpho = IMorpho(0xD50F2DffFd62f94Ee4AEd9ca05C61d0753268aBc);
public_allocator = IPublicAllocator(0x39EB6Da5e88194C82B13491Df2e8B3E213eD2412);
}
_disableInitializers();
}
/**
* @notice Initializes the contract, setting up access control and UUPS upgradeability.
* @param initialAdmin The address to grant initial admin, upgrader, and operator roles.
*/
function initialize(address initialAdmin) public initializer {
__AccessControl_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, initialAdmin);
_grantRole(UPGRADER_ROLE, initialAdmin);
_grantRole(OPERATOR_ROLE, initialAdmin);
}
// =========================================================================
// Modifiers
// =========================================================================
/**
* @notice Restricts execution to OPERATOR_ROLE or DEFAULT_ADMIN_ROLE.
*/
modifier onlyOperator() {
address sender = _msgSender();
require(hasRole(OPERATOR_ROLE, sender) || hasRole(DEFAULT_ADMIN_ROLE, sender), "MorphoHelper: Caller is not an operator");
_;
}
modifier onlyUpgrader() {
address sender = _msgSender();
require(hasRole(UPGRADER_ROLE, sender) || hasRole(DEFAULT_ADMIN_ROLE, sender), "MorphoHelper: Caller is not an upgrader");
_;
}
modifier onlyAdmin() {
address sender = _msgSender();
require(hasRole(DEFAULT_ADMIN_ROLE, sender), "MorphoHelper: Caller is not an admin");
_;
}
// =========================================================================
// Admin & Configuration
// =========================================================================
/**
* @notice Authorizes an upgrade to a new implementation.
* @dev Only callable by UPGRADER_ROLE. Part of OpenZeppelin UUPS pattern.
* @param newImplementation The address of the new implementation contract.
*/
function _authorizeUpgrade(address newImplementation) internal override onlyUpgrader {}
/**
* @notice Updates the Morpho Blue core contract address.
* @dev Only callable by UPGRADER_ROLE.
* @param morpho_ The new Morpho Blue contract address.
*/
function setMorpho(address morpho_) external onlyUpgrader {
morpho = IMorpho(morpho_);
}
/**
* @notice Updates the Public Allocator contract address.
* @dev Only callable by UPGRADER_ROLE.
* @param publicAllocator_ The new Public Allocator contract address.
*/
function setPublicAllocator(address publicAllocator_) external onlyUpgrader {
public_allocator = IPublicAllocator(publicAllocator_);
}
/**
* @notice Grants or revokes the OPERATOR_ROLE.
* @dev Only callable by UPGRADER_ROLE.
* @param operator The address to grant or revoke the role from.
* @param grant True to grant the role, false to revoke it.
*/
function setOperatorRole(address operator, bool grant) external onlyUpgrader {
if (grant) {
_grantRole(OPERATOR_ROLE, operator);
} else {
_revokeRole(OPERATOR_ROLE, operator);
}
}
// =========================================================================
// Vault Operations
// =========================================================================
/**
* @notice Reallocates assets for a MetaMorpho vault.
* @dev Wrapper for `IMetaMorpho.reallocate`.
* @param vault The MetaMorpho vault instance.
* @param allocations Target assets for each market.
*/
function reallocate(IMetaMorpho vault, MarketAllocation[] calldata allocations) external onlyOperator {
vault.reallocate(allocations);
}
/**
* @notice Sets the supply queue for a MetaMorpho vault.
* @dev Wrapper for `IMetaMorpho.setSupplyQueue`.
* @param vault The MetaMorpho vault instance.
* @param newSupplyQueue Market IDs for the new supply queue order.
*/
function vault_setSupplyQueue(IMetaMorpho vault, Id[] calldata newSupplyQueue) external onlyOperator {
vault.setSupplyQueue(newSupplyQueue);
}
/**
* @notice Updates the withdraw queue for a MetaMorpho vault.
* @dev Wrapper for `IMetaMorpho.updateWithdrawQueue`.
* @param vault The MetaMorpho vault instance.
* @param indexes Indexes to update in the withdraw queue.
*/
function vault_updateWithdrawQueue(IMetaMorpho vault, uint256[] calldata indexes) external onlyOperator {
vault.updateWithdrawQueue(indexes);
}
/**
* @notice Gets the supplied assets of a vault in a specific market.
* @param vault The MetaMorpho vault instance.
* @param market The market parameters.
* @return The amount of assets supplied by the vault.
*/
function vaultPosition(IMetaMorpho vault, MarketParams memory market) public view returns (uint256) {
return morpho.expectedSupplyAssets(market, address(vault));
}
/**
* @notice Moves assets between two markets for a vault.
* @dev Calls `reallocate` setting the destination allocation to `type(uint256).max`.
* @param vault The MetaMorpho vault instance.
* @param sourceMarket Market to move assets from.
* @param destinationMarket Market to move assets to.
* @param amount Net amount to move. Positive withdraws from source, negative deposits to source.
*/
function move(
IMetaMorpho vault,
MarketParams memory sourceMarket,
MarketParams memory destinationMarket,
int256 amount
) public onlyOperator {
MarketAllocation[] memory allocations = new MarketAllocation[](2);
uint256 sourcePosition = vaultPosition(vault, sourceMarket);
uint256 newSourcePosition;
if (amount < 0) { // Deposit to source
newSourcePosition = sourcePosition + uint256(-amount);
} else { // Withdraw from source
newSourcePosition = uint256(amount) <= sourcePosition ? sourcePosition - uint256(amount) : 0;
}
allocations[0] = MarketAllocation({marketParams: sourceMarket, assets: newSourcePosition});
allocations[1] = MarketAllocation({marketParams: destinationMarket, assets: type(uint256).max});
vault.reallocate(allocations);
}
/**
* @notice Moves assets between two markets (by ID) for a vault.
* @dev Converts IDs to `MarketParams` and calls the internal `move` logic.
* @param vault The MetaMorpho vault instance.
* @param sourceMarketId ID of the market to move assets from.
* @param destinationMarketId ID of the market to move assets to.
* @param amount Net amount to move. Positive withdraws from source, negative deposits to source.
*/
function move(IMetaMorpho vault, Id sourceMarketId, Id destinationMarketId, int256 amount) external onlyOperator {
move(vault, morpho.idToMarketParams(sourceMarketId), morpho.idToMarketParams(destinationMarketId), amount);
}
/**
* @notice Moves assets from multiple source markets to a single destination market.
* @dev Aggregates withdrawals/deposits into one `reallocate` call.
* @param vault The MetaMorpho vault instance.
* @param withdrawals Amounts to move from each source market.
* @param destinationMarket Market to move assets to.
*/
function move(
IMetaMorpho vault,
Withdrawal[] calldata withdrawals,
MarketParams calldata destinationMarket
) external onlyOperator {
_moveInternal(vault, withdrawals, destinationMarket);
}
/**
* @notice Moves assets from multiple source markets (by ID) to a single destination market (by ID).
* @dev Converts IDs to `MarketParams` and calls the internal move logic.
* @param vault The MetaMorpho vault instance.
* @param withdrawals Amounts to move from each source market (by ID).
* @param destinationMarketId ID of the market to move assets to.
*/
function move(IMetaMorpho vault, WithdrawalById[] calldata withdrawals, Id destinationMarketId) external onlyOperator {
Withdrawal[] memory withdrawals_ = new Withdrawal[](withdrawals.length);
for (uint256 i = 0; i < withdrawals.length; i++) {
withdrawals_[i] = Withdrawal({market: morpho.idToMarketParams(withdrawals[i].marketId), amount: withdrawals[i].amount});
}
_moveInternal(vault, withdrawals_, morpho.idToMarketParams(destinationMarketId));
}
/**
* @notice Internal logic for moving assets from multiple sources to one destination.
*/
function _moveInternal(IMetaMorpho vault, Withdrawal[] memory withdrawals, MarketParams memory destinationMarket) internal {
MarketAllocation[] memory allocations = new MarketAllocation[](withdrawals.length + 1);
for (uint256 i = 0; i < withdrawals.length; i++) {
uint256 sourcePosition = vaultPosition(vault, withdrawals[i].market);
uint256 newSourcePosition;
if (withdrawals[i].amount < 0) { // Deposit to source
newSourcePosition = sourcePosition + uint256(-withdrawals[i].amount);
} else { // Withdraw from source
newSourcePosition = uint256(withdrawals[i].amount) <= sourcePosition
? sourcePosition - uint256(withdrawals[i].amount)
: 0;
}
allocations[i] = MarketAllocation({marketParams: withdrawals[i].market, assets: newSourcePosition});
}
allocations[withdrawals.length] = MarketAllocation({marketParams: destinationMarket, assets: type(uint256).max});
vault.reallocate(allocations);
}
// =========================================================================
// Public Allocator Operations
// =========================================================================
/**
* @notice Sets flow caps for a vault via the Public Allocator.
* @dev Wrapper for `IPublicAllocator.setFlowCaps`.
* @param vault Address used as identifier in Public Allocator.
* @param flowCaps Flow caps definitions for each market.
*/
function pa_setFlowCaps(IMetaMorpho vault, FlowCapsConfig[] calldata flowCaps) external onlyOperator {
public_allocator.setFlowCaps(address(vault), flowCaps);
}
/**
* @notice Sets the fee for a vault within the Public Allocator.
* @dev Wrapper for `IPublicAllocator.setFee`.
* @param vault Address used as identifier in Public Allocator.
* @param newFee New fee basis points.
*/
function pa_setFee(address vault, uint256 newFee) external onlyOperator {
public_allocator.setFee(vault, newFee);
}
/**
* @notice Transfers accumulated fees for a vault from the Public Allocator.
* @dev Wrapper for `IPublicAllocator.transferFee`.
* @param vault Address used as identifier in Public Allocator.
* @param feeRecipient Address to receive the fees.
*/
function pa_transferFee(address vault, address payable feeRecipient) external onlyOperator {
public_allocator.transferFee(vault, feeRecipient);
}
/**
* @notice Sets the admin for a vault within the Public Allocator.
* @dev Wrapper for `IPublicAllocator.setAdmin`. Requires DEFAULT_ADMIN_ROLE.
* @param vault Address used as identifier in Public Allocator.
* @param newAdmin New admin address for the vault in the Public Allocator.
*/
function pa_setAdmin(address vault, address newAdmin) external onlyUpgrader {
public_allocator.setAdmin(vault, newAdmin);
}
// =========================================================================
// Morpho Reader Views
// =========================================================================
/**
* @notice Converts Morpho Blue market parameters to its unique identifier.
* @param marketParams The market parameters.
* @return id The unique identifier for the market.
*/
function marketParamsToId(MarketParams memory marketParams) public pure returns (Id) {
return marketParams.id();
}
/**
* @notice Retrieves extended data for a Morpho Blue market.
* @param id The unique identifier of the market.
* @return marketData A `MarketDataExt` struct with detailed market information.
*/
function getMarketData(Id id) public view returns (MarketDataExt memory marketData) {
Market memory market = morpho.market(id);
MarketParams memory marketParams = morpho.idToMarketParams(id);
(marketData.totalSupplyAssets, marketData.totalSupplyShares, marketData.totalBorrowAssets, marketData.totalBorrowShares) = morpho
.expectedMarketBalances(marketParams);
marketData.fee = morpho.fee(id);
// Get the borrow rate
marketData.borrowRate = 0;
if (address(marketParams.irm) != address(0)) {
marketData.borrowRate = IIrm(marketParams.irm).borrowRateView(marketParams, market).wTaylorCompounded(365 days);
}
// Get the supply rate
marketData.utilization = marketData.totalSupplyAssets == 0 ? 0 : marketData.totalBorrowAssets.wDivUp(marketData.totalSupplyAssets);
marketData.supplyRate = marketData.borrowRate.wMulDown(1 ether - market.fee).wMulDown(marketData.utilization);
}
/**
* @notice Retrieves extended position data for a user in a Morpho Blue market.
* @param id The unique identifier of the market.
* @param user The address of the user.
* @return position A `PositionExt` struct with detailed position information.
*/
function getPosition(Id id, address user) public view returns (PositionExt memory position) {
MarketParams memory marketParams = morpho.idToMarketParams(id);
Position memory p = morpho.position(id, user);
uint256 collateralPrice = (address(marketParams.oracle) == address(0)) ? 0 : IOracle(marketParams.oracle).price();
position.collateral = p.collateral;
position.collateralValue = position.collateral.mulDivDown(collateralPrice, ORACLE_PRICE_SCALE);
position.borrowedAssets = morpho.expectedBorrowAssets(marketParams, user);
position.borrowedShares = p.borrowShares;
position.suppliedAssets = morpho.expectedSupplyAssets(marketParams, user);
position.suppliedShares = p.supplyShares;
position.ltv = (position.collateralValue == 0) ? 0 : position.borrowedAssets.wDivUp(position.collateralValue);
uint256 maxBorrow = position.collateral.mulDivDown(collateralPrice, ORACLE_PRICE_SCALE).wMulDown(marketParams.lltv);
position.healthFactor = (position.borrowedAssets == 0) ? type(uint256).max : maxBorrow.wDivDown(position.borrowedAssets);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id} from "../../interfaces/IMorpho.sol";
/// @title MorphoStorageLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library exposing getters to access Morpho storage variables' slot.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
library MorphoStorageLib {
/* SLOTS */
uint256 internal constant OWNER_SLOT = 0;
uint256 internal constant FEE_RECIPIENT_SLOT = 1;
uint256 internal constant POSITION_SLOT = 2;
uint256 internal constant MARKET_SLOT = 3;
uint256 internal constant IS_IRM_ENABLED_SLOT = 4;
uint256 internal constant IS_LLTV_ENABLED_SLOT = 5;
uint256 internal constant IS_AUTHORIZED_SLOT = 6;
uint256 internal constant NONCE_SLOT = 7;
uint256 internal constant ID_TO_MARKET_PARAMS_SLOT = 8;
/* SLOT OFFSETS */
uint256 internal constant LOAN_TOKEN_OFFSET = 0;
uint256 internal constant COLLATERAL_TOKEN_OFFSET = 1;
uint256 internal constant ORACLE_OFFSET = 2;
uint256 internal constant IRM_OFFSET = 3;
uint256 internal constant LLTV_OFFSET = 4;
uint256 internal constant SUPPLY_SHARES_OFFSET = 0;
uint256 internal constant BORROW_SHARES_AND_COLLATERAL_OFFSET = 1;
uint256 internal constant TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET = 0;
uint256 internal constant TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET = 1;
uint256 internal constant LAST_UPDATE_AND_FEE_OFFSET = 2;
/* GETTERS */
function ownerSlot() internal pure returns (bytes32) {
return bytes32(OWNER_SLOT);
}
function feeRecipientSlot() internal pure returns (bytes32) {
return bytes32(FEE_RECIPIENT_SLOT);
}
function positionSupplySharesSlot(Id id, address user) internal pure returns (bytes32) {
return bytes32(
uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT))))) + SUPPLY_SHARES_OFFSET
);
}
function positionBorrowSharesAndCollateralSlot(Id id, address user) internal pure returns (bytes32) {
return bytes32(
uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT)))))
+ BORROW_SHARES_AND_COLLATERAL_OFFSET
);
}
function marketTotalSupplyAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET);
}
function marketTotalBorrowAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET);
}
function marketLastUpdateAndFeeSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + LAST_UPDATE_AND_FEE_OFFSET);
}
function isIrmEnabledSlot(address irm) internal pure returns (bytes32) {
return keccak256(abi.encode(irm, IS_IRM_ENABLED_SLOT));
}
function isLltvEnabledSlot(uint256 lltv) internal pure returns (bytes32) {
return keccak256(abi.encode(lltv, IS_LLTV_ENABLED_SLOT));
}
function isAuthorizedSlot(address authorizer, address authorizee) internal pure returns (bytes32) {
return keccak256(abi.encode(authorizee, keccak256(abi.encode(authorizer, IS_AUTHORIZED_SLOT))));
}
function nonceSlot(address authorizer) internal pure returns (bytes32) {
return keccak256(abi.encode(authorizer, NONCE_SLOT));
}
function idToLoanTokenSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LOAN_TOKEN_OFFSET);
}
function idToCollateralTokenSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + COLLATERAL_TOKEN_OFFSET);
}
function idToOracleSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + ORACLE_OFFSET);
}
function idToIrmSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + IRM_OFFSET);
}
function idToLltvSlot(Id id) internal pure returns (bytes32) {
return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LLTV_OFFSET);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {Id} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
struct MarketDataExt {
uint256 totalSupplyAssets;
uint256 totalSupplyShares;
uint256 totalBorrowAssets;
uint256 totalBorrowShares;
uint256 fee;
uint256 utilization;
uint256 supplyRate;
uint256 borrowRate;
}
struct PositionExt {
uint256 suppliedShares;
uint256 suppliedAssets;
uint256 borrowedShares;
uint256 borrowedAssets;
uint256 collateral;
uint256 collateralValue;
uint256 ltv;
uint256 healthFactor;
}
interface IMorphoReader {
function getMarketData(Id id) external view returns (MarketDataExt memory);
function getPosition(
Id id,
address user
) external view returns (PositionExt memory);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {
IMetaMorpho,
IMorpho,
MarketAllocation,
Id,
MarketParams
} from "./IMetaMorpho.sol";
/// @dev Max settable flow cap, such that caps can always be stored on 128 bits.
/// @dev The actual max possible flow cap is type(uint128).max-1.
/// @dev Equals to 170141183460469231731687303715884105727;
uint128 constant MAX_SETTABLE_FLOW_CAP = type(uint128).max / 2;
struct FlowCaps {
/// @notice The maximum allowed inflow in a market.
uint128 maxIn;
/// @notice The maximum allowed outflow in a market.
uint128 maxOut;
}
struct FlowCapsConfig {
/// @notice Market for which to change flow caps.
Id id;
/// @notice New flow caps for this market.
FlowCaps caps;
}
struct Withdrawal {
/// @notice The market from which to withdraw.
MarketParams marketParams;
/// @notice The amount to withdraw.
uint128 amount;
}
/// @dev This interface is used for factorizing IPublicAllocatorStaticTyping and IPublicAllocator.
/// @dev Consider using the IPublicAllocator interface instead of this one.
interface IPublicAllocatorBase {
/// @notice The Morpho contract.
function MORPHO() external view returns (IMorpho);
/// @notice The admin for a given vault.
function admin(address vault) external view returns (address);
/// @notice The current ETH fee for a given vault.
function fee(address vault) external view returns (uint256);
/// @notice The accrued ETH fee for a given vault.
function accruedFee(address vault) external view returns (uint256);
/// @notice Reallocates from a list of markets to one market.
/// @param vault The MetaMorpho vault to reallocate.
/// @param withdrawals The markets to withdraw from,and the amounts to withdraw.
/// @param supplyMarketParams The market receiving total withdrawn to.
/// @dev Will call MetaMorpho's `reallocate`.
/// @dev Checks that the flow caps are respected.
/// @dev Will revert when `withdrawals` contains a duplicate or is not sorted.
/// @dev Will revert if `withdrawals` contains the supply market.
/// @dev Will revert if a withdrawal amount is larger than available liquidity.
function reallocateTo(address vault, Withdrawal[] calldata withdrawals, MarketParams calldata supplyMarketParams)
external
payable;
/// @notice Sets the admin for a given vault.
function setAdmin(address vault, address newAdmin) external;
/// @notice Sets the fee for a given vault.
function setFee(address vault, uint256 newFee) external;
/// @notice Transfers the current balance to `feeRecipient` for a given vault.
function transferFee(address vault, address payable feeRecipient) external;
/// @notice Sets the maximum inflow and outflow through public allocation for some markets for a given vault.
/// @dev Max allowed inflow/outflow is MAX_SETTABLE_FLOW_CAP.
/// @dev Doesn't revert if it doesn't change the storage at all.
function setFlowCaps(address vault, FlowCapsConfig[] calldata config) external;
}
/// @dev This interface is inherited by PublicAllocator so that function signatures are checked by the compiler.
/// @dev Consider using the IPublicAllocator interface instead of this one.
interface IPublicAllocatorStaticTyping is IPublicAllocatorBase {
/// @notice Returns (maximum inflow, maximum outflow) through public allocation of a given market for a given vault.
function flowCaps(address vault, Id) external view returns (uint128, uint128);
}
/// @title IPublicAllocator
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for PublicAllocator to have access to all the functions with the appropriate function
/// signatures.
interface IPublicAllocator is IPublicAllocatorBase {
/// @notice Returns the maximum inflow and maximum outflow through public allocation of a given market for a given
/// vault.
function flowCaps(address vault, Id) external view returns (FlowCaps memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title IOracle /// @author Morpho Labs /// @custom:contact [email protected] /// @notice Interface that oracles used by Morpho must implement. /// @dev It is the user's responsibility to select markets with safe oracles. interface IOracle { /// @notice Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36. /// @dev It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in /// 10**(loan token decimals) assets of loan token with `36 + loan token decimals - collateral token decimals` /// decimals of precision. function price() external view returns (uint256); }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {IMorpho, Id} from "../../interfaces/IMorpho.sol";
import {MorphoStorageLib} from "./MorphoStorageLib.sol";
/// @title MorphoLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library to access Morpho storage variables.
/// @dev Warning: Supply and borrow getters may return outdated values that do not include accrued interest.
library MorphoLib {
function supplyShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionSupplySharesSlot(id, user));
return uint256(morpho.extSloads(slot)[0]);
}
function borrowShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function collateral(IMorpho morpho, Id id, address user) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function totalSupplyAssets(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function totalSupplyShares(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function totalBorrowAssets(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function totalBorrowShares(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function lastUpdate(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
return uint128(uint256(morpho.extSloads(slot)[0]));
}
function fee(IMorpho morpho, Id id) internal view returns (uint256) {
bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
return uint256(morpho.extSloads(slot)[0] >> 128);
}
function _array(bytes32 x) private pure returns (bytes32[] memory) {
bytes32[] memory res = new bytes32[](1);
res[0] = x;
return res;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// 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.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"; }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IMorpho, Id, MarketParams} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IERC4626} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {MarketConfig, PendingUint192, PendingAddress} from "../libraries/PendingLib.sol";
struct MarketAllocation {
/// @notice The market to allocate.
MarketParams marketParams;
/// @notice The amount of assets to allocate.
uint256 assets;
}
interface IMulticall {
function multicall(bytes[] calldata) external returns (bytes[] memory);
}
interface IOwnable {
function owner() external view returns (address);
function transferOwnership(address) external;
function renounceOwnership() external;
function acceptOwnership() external;
function pendingOwner() external view returns (address);
}
/// @dev This interface is used for factorizing IMetaMorphoStaticTyping and IMetaMorpho.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoBase {
/// @notice The address of the Morpho contract.
function MORPHO() external view returns (IMorpho);
function DECIMALS_OFFSET() external view returns (uint8);
/// @notice The address of the curator.
function curator() external view returns (address);
/// @notice Stores whether an address is an allocator or not.
function isAllocator(address target) external view returns (bool);
/// @notice The current guardian. Can be set even without the timelock set.
function guardian() external view returns (address);
/// @notice The current fee.
function fee() external view returns (uint96);
/// @notice The fee recipient.
function feeRecipient() external view returns (address);
/// @notice The skim recipient.
function skimRecipient() external view returns (address);
/// @notice The current timelock.
function timelock() external view returns (uint256);
/// @dev Stores the order of markets on which liquidity is supplied upon deposit.
/// @dev Can contain any market. A market is skipped as soon as its supply cap is reached.
function supplyQueue(uint256) external view returns (Id);
/// @notice Returns the length of the supply queue.
function supplyQueueLength() external view returns (uint256);
/// @dev Stores the order of markets from which liquidity is withdrawn upon withdrawal.
/// @dev Always contain all non-zero cap markets as well as all markets on which the vault supplies liquidity,
/// without duplicate.
function withdrawQueue(uint256) external view returns (Id);
/// @notice Returns the length of the withdraw queue.
function withdrawQueueLength() external view returns (uint256);
/// @notice Stores the total assets managed by this vault when the fee was last accrued.
/// @dev May be greater than `totalAssets()` due to removal of markets with non-zero supply or socialized bad debt.
/// This difference will decrease the fee accrued until one of the functions updating `lastTotalAssets` is
/// triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
function lastTotalAssets() external view returns (uint256);
/// @notice Submits a `newTimelock`.
/// @dev Warning: Reverts if a timelock is already pending. Revoke the pending timelock to overwrite it.
/// @dev In case the new timelock is higher than the current one, the timelock is set immediately.
function submitTimelock(uint256 newTimelock) external;
/// @notice Accepts the pending timelock.
function acceptTimelock() external;
/// @notice Revokes the pending timelock.
/// @dev Does not revert if there is no pending timelock.
function revokePendingTimelock() external;
/// @notice Submits a `newSupplyCap` for the market defined by `marketParams`.
/// @dev Warning: Reverts if a cap is already pending. Revoke the pending cap to overwrite it.
/// @dev Warning: Reverts if a market removal is pending.
/// @dev In case the new cap is lower than the current one, the cap is set immediately.
function submitCap(MarketParams memory marketParams, uint256 newSupplyCap) external;
/// @notice Accepts the pending cap of the market defined by `marketParams`.
function acceptCap(MarketParams memory marketParams) external;
/// @notice Revokes the pending cap of the market defined by `id`.
/// @dev Does not revert if there is no pending cap.
function revokePendingCap(Id id) external;
/// @notice Submits a forced market removal from the vault, eventually losing all funds supplied to the market.
/// @notice This forced removal is expected to be used as an emergency process in case a market constantly reverts.
/// To softly remove a sane market, the curator role is expected to bundle a reallocation that empties the market
/// first (using `reallocate`), followed by the removal of the market (using `updateWithdrawQueue`).
/// @dev Warning: Removing a market with non-zero supply will instantly impact the vault's price per share.
/// @dev Warning: Reverts for non-zero cap or if there is a pending cap. Successfully submitting a zero cap will
/// prevent such reverts.
function submitMarketRemoval(MarketParams memory marketParams) external;
/// @notice Revokes the pending removal of the market defined by `id`.
/// @dev Does not revert if there is no pending market removal.
function revokePendingMarketRemoval(Id id) external;
/// @notice Submits a `newGuardian`.
/// @notice Warning: a malicious guardian could disrupt the vault's operation, and would have the power to revoke
/// any pending guardian.
/// @dev In case there is no guardian, the gardian is set immediately.
/// @dev Warning: Submitting a gardian will overwrite the current pending gardian.
function submitGuardian(address newGuardian) external;
/// @notice Accepts the pending guardian.
function acceptGuardian() external;
/// @notice Revokes the pending guardian.
function revokePendingGuardian() external;
/// @notice Skims the vault `token` balance to `skimRecipient`.
function skim(address) external;
/// @notice Sets `newAllocator` as an allocator or not (`newIsAllocator`).
function setIsAllocator(address newAllocator, bool newIsAllocator) external;
/// @notice Sets `curator` to `newCurator`.
function setCurator(address newCurator) external;
/// @notice Sets the `fee` to `newFee`.
function setFee(uint256 newFee) external;
/// @notice Sets `feeRecipient` to `newFeeRecipient`.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Sets `skimRecipient` to `newSkimRecipient`.
function setSkimRecipient(address newSkimRecipient) external;
/// @notice Sets `supplyQueue` to `newSupplyQueue`.
/// @param newSupplyQueue is an array of enabled markets, and can contain duplicate markets, but it would only
/// increase the cost of depositing to the vault.
function setSupplyQueue(Id[] calldata newSupplyQueue) external;
/// @notice Updates the withdraw queue. Some markets can be removed, but no market can be added.
/// @notice Removing a market requires the vault to have 0 supply on it, or to have previously submitted a removal
/// for this market (with the function `submitMarketRemoval`).
/// @notice Warning: Anyone can supply on behalf of the vault so the call to `updateWithdrawQueue` that expects a
/// market to be empty can be griefed by a front-run. To circumvent this, the allocator can simply bundle a
/// reallocation that withdraws max from this market with a call to `updateWithdrawQueue`.
/// @dev Warning: Removing a market with supply will decrease the fee accrued until one of the functions updating
/// `lastTotalAssets` is triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
/// @dev Warning: `updateWithdrawQueue` is not idempotent. Submitting twice the same tx will change the queue twice.
/// @param indexes The indexes of each market in the previous withdraw queue, in the new withdraw queue's order.
function updateWithdrawQueue(uint256[] calldata indexes) external;
/// @notice Reallocates the vault's liquidity so as to reach a given allocation of assets on each given market.
/// @dev The behavior of the reallocation can be altered by state changes, including:
/// - Deposits on the vault that supplies to markets that are expected to be supplied to during reallocation.
/// - Withdrawals from the vault that withdraws from markets that are expected to be withdrawn from during
/// reallocation.
/// - Donations to the vault on markets that are expected to be supplied to during reallocation.
/// - Withdrawals from markets that are expected to be withdrawn from during reallocation.
/// @dev Sender is expected to pass `assets = type(uint256).max` with the last MarketAllocation of `allocations` to
/// supply all the remaining withdrawn liquidity, which would ensure that `totalWithdrawn` = `totalSupplied`.
/// @dev A supply in a reallocation step will make the reallocation revert if the amount is greater than the net
/// amount from previous steps (i.e. total withdrawn minus total supplied).
function reallocate(MarketAllocation[] calldata allocations) external;
}
/// @dev This interface is inherited by MetaMorpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoStaticTyping is IMetaMorphoBase {
/// @notice Returns the current configuration of each market.
function config(Id) external view returns (uint184 cap, bool enabled, uint64 removableAt);
/// @notice Returns the pending guardian.
function pendingGuardian() external view returns (address guardian, uint64 validAt);
/// @notice Returns the pending cap for each market.
function pendingCap(Id) external view returns (uint192 value, uint64 validAt);
/// @notice Returns the pending timelock.
function pendingTimelock() external view returns (uint192 value, uint64 validAt);
}
/// @title IMetaMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for MetaMorpho to have access to all the functions with the appropriate function signatures.
interface IMetaMorpho is IMetaMorphoBase, IERC4626, IERC20Permit, IOwnable, IMulticall {
/// @notice Returns the current configuration of each market.
function config(Id) external view returns (MarketConfig memory);
/// @notice Returns the pending guardian.
function pendingGuardian() external view returns (PendingAddress memory);
/// @notice Returns the pending cap for each market.
function pendingCap(Id) external view returns (PendingUint192 memory);
/// @notice Returns the pending timelock.
function pendingTimelock() external view returns (PendingUint192 memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// 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;
struct MarketConfig {
/// @notice The maximum amount of assets that can be allocated to the market.
uint184 cap;
/// @notice Whether the market is in the withdraw queue.
bool enabled;
/// @notice The timestamp at which the market can be instantly removed from the withdraw queue.
uint64 removableAt;
}
struct PendingUint192 {
/// @notice The pending value to set.
uint192 value;
/// @notice The timestamp at which the pending value becomes valid.
uint64 validAt;
}
struct PendingAddress {
/// @notice The pending value to set.
address value;
/// @notice The timestamp at which the pending value becomes valid.
uint64 validAt;
}
/// @title PendingLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to manage pending values and their validity timestamp.
library PendingLib {
/// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
/// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
function update(PendingUint192 storage pending, uint184 newValue, uint256 timelock) internal {
pending.value = newValue;
// Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
pending.validAt = uint64(block.timestamp + timelock);
}
/// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
/// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
function update(PendingAddress storage pending, address newValue, uint256 timelock) internal {
pending.value = newValue;
// Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
pending.validAt = uint64(block.timestamp + timelock);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id, MarketParams, Market, IMorpho} from "../../interfaces/IMorpho.sol";
import {IIrm} from "../../interfaces/IIrm.sol";
import {MathLib} from "../MathLib.sol";
import {UtilsLib} from "../UtilsLib.sol";
import {MorphoLib} from "./MorphoLib.sol";
import {SharesMathLib} from "../SharesMathLib.sol";
import {MarketParamsLib} from "../MarketParamsLib.sol";
/// @title MorphoBalancesLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library exposing getters with the expected value after interest accrual.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
/// @dev The getter to retrieve the expected total borrow shares is not exposed because interest accrual does not apply
/// to it. The value can be queried directly on Morpho using `totalBorrowShares`.
library MorphoBalancesLib {
using MathLib for uint256;
using MathLib for uint128;
using UtilsLib for uint256;
using MorphoLib for IMorpho;
using SharesMathLib for uint256;
using MarketParamsLib for MarketParams;
/// @notice Returns the expected market balances of a market after having accrued interest.
/// @return The expected total supply assets.
/// @return The expected total supply shares.
/// @return The expected total borrow assets.
/// @return The expected total borrow shares.
function expectedMarketBalances(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256, uint256, uint256, uint256)
{
Id id = marketParams.id();
Market memory market = morpho.market(id);
uint256 elapsed = block.timestamp - market.lastUpdate;
// Skipped if elapsed == 0 or totalBorrowAssets == 0 because interest would be null, or if irm == address(0).
if (elapsed != 0 && market.totalBorrowAssets != 0 && marketParams.irm != address(0)) {
uint256 borrowRate = IIrm(marketParams.irm).borrowRateView(marketParams, market);
uint256 interest = market.totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
market.totalBorrowAssets += interest.toUint128();
market.totalSupplyAssets += interest.toUint128();
if (market.fee != 0) {
uint256 feeAmount = interest.wMulDown(market.fee);
// The fee amount is subtracted from the total supply in this calculation to compensate for the fact
// that total supply is already updated.
uint256 feeShares =
feeAmount.toSharesDown(market.totalSupplyAssets - feeAmount, market.totalSupplyShares);
market.totalSupplyShares += feeShares.toUint128();
}
}
return (market.totalSupplyAssets, market.totalSupplyShares, market.totalBorrowAssets, market.totalBorrowShares);
}
/// @notice Returns the expected total supply assets of a market after having accrued interest.
function expectedTotalSupplyAssets(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalSupplyAssets)
{
(totalSupplyAssets,,,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected total borrow assets of a market after having accrued interest.
function expectedTotalBorrowAssets(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalBorrowAssets)
{
(,, totalBorrowAssets,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected total supply shares of a market after having accrued interest.
function expectedTotalSupplyShares(IMorpho morpho, MarketParams memory marketParams)
internal
view
returns (uint256 totalSupplyShares)
{
(, totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);
}
/// @notice Returns the expected supply assets balance of `user` on a market after having accrued interest.
/// @dev Warning: Wrong for `feeRecipient` because their supply shares increase is not taken into account.
/// @dev Warning: Withdrawing using the expected supply assets can lead to a revert due to conversion roundings from
/// assets to shares.
function expectedSupplyAssets(IMorpho morpho, MarketParams memory marketParams, address user)
internal
view
returns (uint256)
{
Id id = marketParams.id();
uint256 supplyShares = morpho.supplyShares(id, user);
(uint256 totalSupplyAssets, uint256 totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);
return supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);
}
/// @notice Returns the expected borrow assets balance of `user` on a market after having accrued interest.
/// @dev Warning: The expected balance is rounded up, so it may be greater than the market's expected total borrow
/// assets.
function expectedBorrowAssets(IMorpho morpho, MarketParams memory marketParams, address user)
internal
view
returns (uint256)
{
Id id = marketParams.id();
uint256 borrowShares = morpho.borrowShares(id, user);
(,, uint256 totalBorrowAssets, uint256 totalBorrowShares) = expectedMarketBalances(morpho, marketParams);
return borrowShares.toAssetsUp(totalBorrowAssets, totalBorrowShares);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
import {Id, MarketParams} from "../interfaces/IMorpho.sol";
/// @title MarketParamsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to convert a market to its id.
library MarketParamsLib {
/// @notice The length of the data used to compute the id of a market.
/// @dev The length is 5 * 32 because `MarketParams` has 5 variables of 32 bytes each.
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
/// @notice Returns the id of the market `marketParams`.
function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) {
assembly ("memory-safe") {
marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH)
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
type Id is bytes32;
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
struct Authorization {
address authorizer;
address authorized;
bool isAuthorized;
uint256 nonce;
uint256 deadline;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
/// @notice The EIP-712 domain separator.
/// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing
/// the same chain id because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties
/// (funds could get stuck):
/// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.
/// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and
/// `toSharesDown` overflow.
/// - The IRM can revert on `borrowRate`.
/// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`
/// overflow.
/// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and
/// `liquidate` from being used under certain market conditions.
/// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or
/// the computation of `assetsRepaid` in `liquidate` overflow.
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoReplay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
/// @dev The maximum fee a market can have (25%).
uint256 constant MAX_FEE = 0.25e18;
/// @dev Oracle price scale.
uint256 constant ORACLE_PRICE_SCALE = 1e36;
/// @dev Liquidation cursor.
uint256 constant LIQUIDATION_CURSOR = 0.3e18;
/// @dev Max liquidation incentive factor.
uint256 constant MAX_LIQUIDATION_INCENTIVE_FACTOR = 1.15e18;
/// @dev The EIP-712 typeHash for EIP712Domain.
bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
/// @dev The EIP-712 typeHash for Authorization.
bytes32 constant AUTHORIZATION_TYPEHASH =
keccak256("Authorization(address authorizer,address authorized,bool isAuthorized,uint256 nonce,uint256 deadline)");// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}{
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"ds-auth/=lib/dss-psm/lib/dss/lib/ds-token/lib/ds-auth/src/",
"ds-math/=lib/dss-psm/lib/dss/lib/ds-token/lib/ds-math/src/",
"ds-note/=lib/dss-psm/lib/dss/lib/ds-value/lib/ds-thing/lib/ds-note/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"ds-thing/=lib/dss-psm/lib/dss/lib/ds-value/lib/ds-thing/src/",
"ds-token/=lib/dss-psm/lib/dss/lib/ds-token/src/",
"ds-value/=lib/dss-psm/lib/dss/lib/ds-value/src/",
"dss-interfaces/=lib/dss-psm/lib/dss-interfaces/src/",
"dss-psm/=lib/dss-psm/src/",
"dss/=lib/dss-psm/lib/dss/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"morpho-blue-oracles/=lib/morpho-blue-oracles/src/",
"@morpho-blue-oracles/=lib/morpho-blue-oracles/",
"morpho-blue/=lib/morpho-blue/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"@uniswap/v3-periphery/=lib/v3-periphery/",
"@uniswap/v3-core/=lib/v3-core/",
"@slipstream/=lib/slipstream/",
"@ensdomains/=lib/slipstream/node_modules/@ensdomains/",
"@nomad-xyz/=lib/slipstream/lib/ExcessivelySafeCall/",
"@solidity-parser/=lib/slipstream/node_modules/solhint/node_modules/@solidity-parser/",
"ExcessivelySafeCall/=lib/slipstream/lib/ExcessivelySafeCall/src/",
"base64-sol/=lib/slipstream/lib/base64/",
"base64/=lib/slipstream/lib/base64/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"hardhat/=lib/slipstream/node_modules/hardhat/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"slipstream/=lib/slipstream/",
"solidity-lib/=lib/slipstream/lib/solidity-lib/contracts/",
"v3-core/=lib/v3-core/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"implementation","type":"address"}],"name":"ERC1967InvalidImplementation","type":"error"},{"inputs":[],"name":"ERC1967NonPayable","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"UUPSUnauthorizedCallContext","type":"error"},{"inputs":[{"internalType":"bytes32","name":"slot","type":"bytes32"}],"name":"UUPSUnsupportedProxiableUUID","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPGRADE_INTERFACE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"getMarketData","outputs":[{"components":[{"internalType":"uint256","name":"totalSupplyAssets","type":"uint256"},{"internalType":"uint256","name":"totalSupplyShares","type":"uint256"},{"internalType":"uint256","name":"totalBorrowAssets","type":"uint256"},{"internalType":"uint256","name":"totalBorrowShares","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"utilization","type":"uint256"},{"internalType":"uint256","name":"supplyRate","type":"uint256"},{"internalType":"uint256","name":"borrowRate","type":"uint256"}],"internalType":"struct MarketDataExt","name":"marketData","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"},{"internalType":"address","name":"user","type":"address"}],"name":"getPosition","outputs":[{"components":[{"internalType":"uint256","name":"suppliedShares","type":"uint256"},{"internalType":"uint256","name":"suppliedAssets","type":"uint256"},{"internalType":"uint256","name":"borrowedShares","type":"uint256"},{"internalType":"uint256","name":"borrowedAssets","type":"uint256"},{"internalType":"uint256","name":"collateral","type":"uint256"},{"internalType":"uint256","name":"collateralValue","type":"uint256"},{"internalType":"uint256","name":"ltv","type":"uint256"},{"internalType":"uint256","name":"healthFactor","type":"uint256"}],"internalType":"struct PositionExt","name":"position","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialAdmin","type":"address"}],"name":"initialize","outputs":[],"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":"marketParamsToId","outputs":[{"internalType":"Id","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"morpho","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"components":[{"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":"market","type":"tuple"},{"internalType":"int256","name":"amount","type":"int256"}],"internalType":"struct MorphoHelper.Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"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":"destinationMarket","type":"tuple"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"internalType":"Id","name":"sourceMarketId","type":"bytes32"},{"internalType":"Id","name":"destinationMarketId","type":"bytes32"},{"internalType":"int256","name":"amount","type":"int256"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"components":[{"internalType":"Id","name":"marketId","type":"bytes32"},{"internalType":"int256","name":"amount","type":"int256"}],"internalType":"struct MorphoHelper.WithdrawalById[]","name":"withdrawals","type":"tuple[]"},{"internalType":"Id","name":"destinationMarketId","type":"bytes32"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"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":"sourceMarket","type":"tuple"},{"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":"destinationMarket","type":"tuple"},{"internalType":"int256","name":"amount","type":"int256"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"pa_setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"pa_setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"components":[{"internalType":"Id","name":"id","type":"bytes32"},{"components":[{"internalType":"uint128","name":"maxIn","type":"uint128"},{"internalType":"uint128","name":"maxOut","type":"uint128"}],"internalType":"struct FlowCaps","name":"caps","type":"tuple"}],"internalType":"struct FlowCapsConfig[]","name":"flowCaps","type":"tuple[]"}],"name":"pa_setFlowCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address payable","name":"feeRecipient","type":"address"}],"name":"pa_transferFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"public_allocator","outputs":[{"internalType":"contract IPublicAllocator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"components":[{"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"},{"internalType":"uint256","name":"assets","type":"uint256"}],"internalType":"struct MarketAllocation[]","name":"allocations","type":"tuple[]"}],"name":"reallocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"morpho_","type":"address"}],"name":"setMorpho","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"grant","type":"bool"}],"name":"setOperatorRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"publicAllocator_","type":"address"}],"name":"setPublicAllocator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"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":"market","type":"tuple"}],"name":"vaultPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"internalType":"Id[]","name":"newSupplyQueue","type":"bytes32[]"}],"name":"vault_setSupplyQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetaMorpho","name":"vault","type":"address"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"name":"vault_updateWithdrawQueue","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234620000445762000014620001e3565b6200001e6200004a565b615ea7620006558239608051818181611baf01528181611c1b0152611c5d0152615ea790f35b62000050565b60405190565b5f80fd5b90565b90565b90565b62000076620000706200007c9262000057565b6200005a565b62000054565b90565b90565b6200009b62000095620000a1926200007f565b6200005a565b62000054565b90565b90565b620000c0620000ba620000c692620000a4565b6200005a565b62000054565b90565b90565b620000e5620000df620000eb92620000c9565b6200005a565b62000054565b90565b60018060a01b031690565b620001126200010c6200011892620000ee565b6200005a565b620000ee565b90565b6200012690620000f9565b90565b62000134906200011b565b90565b5f1b90565b906200014f60018060a01b039162000137565b9181191691161790565b62000164906200011b565b90565b90565b90620001846200017e6200018c9262000159565b62000167565b82546200013c565b9055565b6200019b90620000f9565b90565b620001a99062000190565b90565b620001b79062000190565b90565b90565b90620001d7620001d1620001df92620001ac565b620001ba565b82546200013c565b9055565b620001ed620003ea565b4662000205620001fe60016200005d565b9162000054565b145f146200026f57620002376200023073bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb62000129565b5f6200016a565b620002626200025a73fd32fa2ca22c76dd6e550706ad913fc6ce91c75d6200019e565b6001620001bd565b5b6200026d6200055a565b565b46620002886200028161210562000082565b9162000054565b145f14620002ec57620002ba620002b373bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb62000129565b5f6200016a565b620002e5620002dd73a090dd1a701408df1d4d0b85b716c87565f904676200019e565b6001620001bd565b5b62000263565b4662000304620002fd6082620000a7565b9162000054565b145f146200036857620003366200032f738f5ae9cddb9f68de460c77730b018ae7e04a140a62000129565b5f6200016a565b620003616200035973b0c9a107fa17c779b3378210a7a593e88938c7c96200019e565b6001620001bd565b5b620002e6565b46620003826200037b620b67d2620000cc565b9162000054565b146200038f575b62000362565b620003b9620003b273d50f2dfffd62f94ee4aed9ca05c61d0753268abc62000129565b5f6200016a565b620003e4620003dc7339eb6da5e88194c82b13491df2e8b3e213ed24126200019e565b6001620001bd565b62000389565b620003f4620003f6565b565b6200040062000402565b565b6200040c6200040e565b565b620004186200041a565b565b6200042462000442565b565b6200043190620000f9565b90565b6200043f9062000426565b90565b6200044d3062000434565b608052565b60401c90565b60ff1690565b6200046d620004739162000452565b62000458565b90565b6200048290546200045e565b90565b5f0190565b5f1c90565b60018060401b031690565b620004a9620004af916200048a565b6200048f565b90565b620004be90546200049a565b90565b60018060401b031690565b90620004df60018060401b039162000137565b9181191691161790565b62000502620004fc6200050892620004c1565b6200005a565b620004c1565b90565b90565b9062000528620005226200053092620004e9565b6200050b565b8254620004cc565b9055565b6200053f90620004c1565b9052565b919062000558905f6020850194019062000534565b565b6200056462000630565b620005715f820162000476565b6200060957620005835f8201620004b2565b6200059f6200059860018060401b03620004c1565b91620004c1565b03620005a9575b50565b620005be905f60018060401b0391016200050e565b60018060401b03620005ff7fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d291620005f56200004a565b9182918262000543565b0390a15f620005a6565b620006136200004a565b63f92ee8a960e01b8152806200062c6004820162000485565b0390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009056fe60806040526004361015610013575b6116a1565b61001d5f3561022b565b8062fb0d821461022657806301ffc9a71461022157806312440f5a1461021c5780631da98c9214610217578063248a9ca3146102125780632f2ff15d1461020d57806330c9d4ac1461020857806330f4f4bb14610203578063364f5732146101fe57806336568abe146101f957806344fe5295146101f45780634844da13146101ef5780634f1ef286146101ea57806352d1902d146101e55780635c388821146101e057806367756192146101db578063784980b8146101d6578063919b56f6146101d157806391d14854146101cc57806393512617146101c75780639388e8f3146101c2578063a217fddf146101bd578063ab6a48d9146101b8578063ad3cb1cc146101b3578063afe0e35a146101ae578063b3f57300146101a9578063c4d66de8146101a4578063d547741f1461019f578063d8fbc8331461019a578063db35ce8414610195578063eb7499cf14610190578063f5b541a61461018b5763f72c0d8b0361000e5761166c565b611608565b6115a5565b6114ec565b611432565b611392565b61135f565b61132b565b6112c8565b611244565b6110fc565b61106b565b610ff9565b610f7d565b610ef7565b610ec0565b610df7565b610d58565b610d22565b610c1a565b610bf0565b610aec565b610a30565b610953565b61091f565b61082a565b610701565b610621565b6105bf565b610529565b6104d7565b610470565b6103c7565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061026f90610247565b810190811067ffffffffffffffff82111761028957604052565b610251565b906102a161029a610231565b9283610265565b565b60018060a01b031690565b6102b7906102a3565b90565b6102c3816102ae565b036102ca57565b5f80fd5b905035906102db826102ba565b565b90565b6102e9816102dd565b036102f057565b5f80fd5b90503590610301826102e0565b565b919060a0838203126103735761036c9061031d60a061028e565b9361032a825f83016102ce565b5f86015261033b82602083016102ce565b602086015261034d82604083016102ce565b604086015261035f82606083016102ce565b60608601526080016102f4565b6080830152565b610243565b9060a0828203126103915761038e915f01610303565b90565b61023b565b90565b6103a290610396565b90565b6103ae90610399565b9052565b91906103c5905f602085019401906103a5565b565b346103f7576103f36103e26103dd366004610378565b6150ce565b6103ea610231565b918291826103b2565b0390f35b610237565b63ffffffff60e01b1690565b610411816103fc565b0361041857565b5f80fd5b9050359061042982610408565b565b9060208282031261044457610441915f0161041c565b90565b61023b565b151590565b61045790610449565b9052565b919061046e905f6020850194019061044e565b565b346104a05761049c61048b61048636600461042b565b6116a9565b610493610231565b9182918261045b565b0390f35b610237565b91906040838203126104cd57806104c16104ca925f86016102ce565b936020016102ce565b90565b61023b565b5f0190565b34610506576104f06104ea3660046104a5565b906150c2565b6104f8610231565b80610502816104d2565b0390f35b610237565b9060208282031261052457610521915f016102ce565b90565b61023b565b346105575761054161053c36600461050b565b6126ff565b610549610231565b80610553816104d2565b0390f35b610237565b61056581610396565b0361056c57565b5f80fd5b9050359061057d8261055c565b565b9060208282031261059857610595915f01610570565b90565b61023b565b6105a690610396565b9052565b91906105bd905f6020850194019061059d565b565b346105ef576105eb6105da6105d536600461057f565b6117cb565b6105e2610231565b918291826105aa565b0390f35b610237565b919060408382031261061c5780610610610619925f8601610570565b936020016102ce565b90565b61023b565b346106505761063a6106343660046105f4565b9061181f565b610642610231565b8061064c816104d2565b0390f35b610237565b5f91031261065f57565b61023b565b1c90565b60018060a01b031690565b6106839060086106889302610664565b610668565b90565b906106969154610673565b90565b6106a560015f9061068b565b90565b90565b6106bf6106ba6106c4926102a3565b6106a8565b6102a3565b90565b6106d0906106ab565b90565b6106dc906106c7565b90565b6106e8906106d3565b9052565b91906106ff905f602085019401906106df565b565b3461073157610711366004610655565b61072d61071c610699565b610724610231565b918291826106ec565b0390f35b610237565b61073f81610396565b0361074657565b5f80fd5b9050359061075782610736565b565b906020828203126107725761076f915f0161074a565b90565b61023b565b610780906102dd565b9052565b9060e0806108129361079c5f8201515f860190610777565b6107ae60208201516020860190610777565b6107c060408201516040860190610777565b6107d260608201516060860190610777565b6107e460808201516080860190610777565b6107f660a082015160a0860190610777565b61080860c082015160c0860190610777565b0151910190610777565b565b9190610828905f6101008501940190610784565b565b3461085a57610856610845610840366004610759565b6151e5565b61084d610231565b91829182610814565b0390f35b610237565b610868906102ae565b90565b6108748161085f565b0361087b57565b5f80fd5b9050359061088c8261086b565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156108d45781359167ffffffffffffffff83116108cf5760200192602083028401116108ca57565b610896565b610892565b61088e565b91909160408184031261091a576108f2835f830161087f565b92602082013567ffffffffffffffff811161091557610911920161089a565b9091565b61023f565b61023b565b3461094e576109386109323660046108d9565b91612e46565b610940610231565b8061094a816104d2565b0390f35b610237565b346109825761096c6109663660046105f4565b906118e7565b610974610231565b8061097e816104d2565b0390f35b610237565b909182601f830112156109c15781359167ffffffffffffffff83116109bc576020019260c083028401116109b757565b610896565b610892565b61088e565b5f80fd5b908160a09103126109d85790565b6109c6565b9060e082820312610a2b576109f4815f840161087f565b92602083013567ffffffffffffffff8111610a2657610a1883610a23928601610987565b9390946040016109ca565b90565b61023f565b61023b565b34610a6257610a4c610a433660046109dd565b92919091614548565b610a54610231565b80610a5e816104d2565b0390f35b610237565b909182601f83011215610aa15781359167ffffffffffffffff8311610a9c576020019260608302840111610a9757565b610896565b610892565b61088e565b919091604081840312610ae757610abf835f830161087f565b92602082013567ffffffffffffffff8111610ae257610ade9201610a67565b9091565b61023f565b61023b565b34610b1b57610b05610aff366004610aa6565b91614d84565b610b0d610231565b80610b17816104d2565b0390f35b610237565b5f80fd5b67ffffffffffffffff8111610b4257610b3e602091610247565b0190565b610251565b90825f939282370152565b90929192610b67610b6282610b24565b61028e565b93818552602085019082840111610b8357610b8192610b47565b565b610b20565b9080601f83011215610ba657816020610ba393359101610b52565b90565b61088e565b919091604081840312610beb57610bc4835f83016102ce565b92602082013567ffffffffffffffff8111610be657610be39201610b88565b90565b61023f565b61023b565b610c04610bfe366004610bab565b90611b86565b610c0c610231565b80610c16816104d2565b0390f35b34610c4a57610c2a366004610655565b610c46610c35611b4a565b610c3d610231565b918291826105aa565b0390f35b610237565b9190604083820312610c775780610c6b610c74925f860161074a565b936020016102ce565b90565b61023b565b9060e080610d0a93610c945f8201515f860190610777565b610ca660208201516020860190610777565b610cb860408201516040860190610777565b610cca60608201516060860190610777565b610cdc60808201516080860190610777565b610cee60a082015160a0860190610777565b610d0060c082015160c0860190610777565b0151910190610777565b565b9190610d20905f6101008501940190610c7c565b565b34610d5357610d4f610d3e610d38366004610c4f565b906158ab565b610d46610231565b91829182610d0c565b0390f35b610237565b34610d8657610d70610d6b36600461050b565b6127b4565b610d78610231565b80610d82816104d2565b0390f35b610237565b90565b610d9781610d8b565b03610d9e57565b5f80fd5b90503590610daf82610d8e565b565b608081830312610df257610dc7825f830161087f565b92610def610dd8846020850161074a565b93610de6816040860161074a565b93606001610da2565b90565b61023b565b34610e2957610e13610e0a366004610db1565b929190916143f7565b610e1b610231565b80610e25816104d2565b0390f35b610237565b909182601f83011215610e685781359167ffffffffffffffff8311610e63576020019260408302840111610e5e57565b610896565b610892565b61088e565b90606082820312610ebb57610e84815f840161087f565b92602083013567ffffffffffffffff8111610eb657610ea883610eb3928601610e2e565b93909460400161074a565b90565b61023f565b61023b565b34610ef257610edc610ed3366004610e6d565b929190916148af565b610ee4610231565b80610eee816104d2565b0390f35b610237565b34610f2857610f24610f13610f0d3660046105f4565b9061174d565b610f1b610231565b9182918261045b565b0390f35b610237565b610f3681610449565b03610f3d57565b5f80fd5b90503590610f4e82610f2d565b565b9190604083820312610f785780610f6c610f75925f86016102ce565b93602001610f41565b90565b61023b565b34610fac57610f96610f90366004610f50565b90612841565b610f9e610231565b80610fa8816104d2565b0390f35b610237565b61018081830312610ff457610fc8825f830161087f565b92610ff1610fd98460208501610303565b93610fe78160c08601610303565b9361016001610da2565b90565b61023b565b3461102b5761101561100c366004610fb1565b929190916141d9565b61101d610231565b80611027816104d2565b0390f35b610237565b90565b5f1b90565b61104c61104761105192611030565b611033565b610396565b90565b61105d5f611038565b90565b611068611054565b90565b3461109b5761107b366004610655565b611097611086611060565b61108e610231565b918291826105aa565b0390f35b610237565b6110a9906102a3565b90565b6110b5816110a0565b036110bc57565b5f80fd5b905035906110cd826110ac565b565b91906040838203126110f757806110eb6110f4925f86016102ce565b936020016110c0565b90565b61023b565b3461112b5761111561110f3660046110cf565b90614fb2565b61111d610231565b80611127816104d2565b0390f35b610237565b67ffffffffffffffff811161114e5761114a602091610247565b0190565b610251565b9061116561116083611130565b61028e565b918252565b5f7f352e302e30000000000000000000000000000000000000000000000000000000910152565b61119b6005611153565b906111a86020830161116a565b565b6111b2611191565b90565b6111bd6111aa565b90565b6111c86111b5565b90565b5190565b60209181520190565b5f5b8381106111ea575050905f910152565b8060209183015181850152016111da565b61121a61122360209361122893611211816111cb565b938480936111cf565b958691016111d8565b610247565b0190565b6112419160208201915f8184039101526111fb565b90565b3461127457611254366004610655565b61127061125f6111c0565b611267610231565b9182918261122c565b0390f35b610237565b919060c0838203126112a1578061129561129e925f860161087f565b93602001610303565b90565b61023b565b6112af906102dd565b9052565b91906112c6905f602085019401906112a6565b565b346112f9576112f56112e46112de366004611279565b90612e78565b6112ec610231565b918291826112b3565b0390f35b610237565b9190604083820312611326578061131a611323925f86016102ce565b936020016102f4565b90565b61023b565b3461135a5761134461133e3660046112fe565b90614e95565b61134c610231565b80611356816104d2565b0390f35b610237565b3461138d5761137761137236600461050b565b6124ae565b61137f610231565b80611389816104d2565b0390f35b610237565b346113c1576113ab6113a53660046105f4565b906118db565b6113b3610231565b806113bd816104d2565b0390f35b610237565b60018060a01b031690565b6113e19060086113e69302610664565b6113c6565b90565b906113f491546113d1565b90565b6114015f806113e9565b90565b61140d906106c7565b90565b61141990611404565b9052565b9190611430905f60208501940190611410565b565b3461146257611442366004610655565b61145e61144d6113f7565b611455610231565b9182918261141d565b0390f35b610237565b909182601f830112156114a15781359167ffffffffffffffff831161149c57602001926020830284011161149757565b610896565b610892565b61088e565b9190916040818403126114e7576114bf835f830161087f565b92602082013567ffffffffffffffff81116114e2576114de9201611467565b9091565b61023f565b61023b565b3461151b576115056114ff3660046114a6565b91612d01565b61150d610231565b80611517816104d2565b0390f35b610237565b909182601f8301121561155a5781359167ffffffffffffffff8311611555576020019260c0830284011161155057565b610896565b610892565b61088e565b9190916040818403126115a057611578835f830161087f565b92602082013567ffffffffffffffff811161159b576115979201611520565b9091565b61023f565b61023b565b346115d4576115be6115b836600461155f565b91612b6b565b6115c6610231565b806115d0816104d2565b0390f35b610237565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92990565b6116056115d9565b90565b3461163857611618366004610655565b6116346116236115fd565b61162b610231565b918291826105aa565b0390f35b610237565b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e390565b61166961163d565b90565b3461169c5761167c366004610655565b611698611687611661565b61168f610231565b918291826105aa565b0390f35b610237565b5f80fd5b5f90565b6116b16116a5565b50806116cc6116c6637965db0b60e01b6103fc565b916103fc565b149081156116d9575b5090565b6116e39150611e4e565b5f6116d5565b906116f390610399565b5f5260205260405f2090565b611708906106c7565b90565b90611715906116ff565b5f5260205260405f2090565b5f1c90565b60ff1690565b61173861173d91611721565b611726565b90565b61174a905461172c565b90565b61177c915f611771611777936117616116a5565b508261176b61177f565b016116e9565b0161170b565b611740565b90565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b5f90565b90565b6117b66117bb91611721565b6117a7565b90565b6117c890546117aa565b90565b60016117ec6117f2926117dc6117a3565b505f6117e661177f565b016116e9565b016117be565b90565b906118109161180b611806826117cb565b61182b565b611812565b565b9061181c9161197b565b50565b90611829916117f5565b565b61183d90611837611e41565b9061186f565b565b611848906102ae565b9052565b91602061186d92949361186660408201965f83019061183f565b019061059d565b565b9061188461187e83839061174d565b15610449565b61188c575050565b6118ad611897610231565b92839263e2517d3f60e01b84526004840161184c565b0390fd5b906118cc916118c76118c2826117cb565b61182b565b6118ce565b565b906118d891611a32565b50565b906118e5916118b1565b565b90806119026118fc6118f7611e41565b6102ae565b916102ae565b036119135761191091611a32565b50565b61191b610231565b63334bd91960e11b815280611932600482016104d2565b0390fd5b9061194260ff91611033565b9181191691161790565b61195590610449565b90565b90565b9061197061196b6119779261194c565b611958565b8254611936565b9055565b6119836116a5565b5061198c61177f565b6119a061199a83859061174d565b15610449565b5f14611a2b576119ca906119c55f6119bd816001940186906116e9565b01859061170b565b61195b565b906119d3611e41565b90611a10611a0a611a047f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d95610399565b926116ff565b926116ff565b92611a19610231565b80611a23816104d2565b0390a4600190565b5050505f90565b611a3a6116a5565b50611a4361177f565b611a4e82849061174d565b5f14611ad857611a7790611a725f611a6a8180940186906116e9565b01859061170b565b61195b565b90611a80611e41565b90611abd611ab7611ab17ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b95610399565b926116ff565b926116ff565b92611ac6610231565b80611ad0816104d2565b0390a4600190565b5050505f90565b611af090611aeb611c4c565b611b3e565b90565b90565b611b0a611b05611b0f92611af3565b611033565b610396565b90565b611b3b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc611af6565b90565b50611b47611b12565b90565b611b5a611b556117a3565b611adf565b90565b90611b6f91611b6a611b9e565b611b71565b565b90611b8491611b7f8161264b565b611d31565b565b90611b9091611b5d565b565b611b9b906106c7565b90565b611ba730611b92565b611bd9611bd37f00000000000000000000000000000000000000000000000000000000000000006102ae565b916102ae565b148015611c0a575b611be757565b611bef610231565b63703e46dd60e11b815280611c06600482016104d2565b0390fd5b50611c13611ea0565b611c45611c3f7f00000000000000000000000000000000000000000000000000000000000000006102ae565b916102ae565b1415611be1565b611c5530611b92565b611c87611c817f00000000000000000000000000000000000000000000000000000000000000006102ae565b916102ae565b03611c8e57565b611c96610231565b63703e46dd60e11b815280611cad600482016104d2565b0390fd5b611cba906106ab565b90565b611cc690611cb1565b90565b611cd2906106c7565b90565b5f80fd5b60e01b90565b90505190611cec8261055c565b565b90602082820312611d0757611d04915f01611cdf565b90565b61023b565b611d14610231565b3d5f823e3d90fd5b9190611d2f905f6020850194019061183f565b565b9190611d5f6020611d49611d4486611cbd565b611cc9565b6352d1902d90611d57610231565b938492611cd9565b82528180611d6f600482016104d2565b03915afa80915f92611e0d575b50155f14611db7575050906001611d9157505b565b611db390611d9d610231565b918291634c9c8ce360e01b835260048301611d1c565b0390fd5b9283611dd2611dcc611dc7611b12565b610396565b91610396565b03611de757611de2929350611ee6565b611d8f565b611e0984611df3610231565b918291632a87526960e21b8352600483016105aa565b0390fd5b611e2f91925060203d8111611e36575b611e278183610265565b810190611cee565b905f611d7c565b503d611e1d565b5f90565b611e49611e3d565b503390565b611e566116a5565b50611e70611e6a6301ffc9a760e01b6103fc565b916103fc565b1490565b60018060a01b031690565b611e8b611e9091611721565b611e74565b90565b611e9d9054611e7f565b90565b611ea8611e3d565b50611ec35f611ebd611eb8611b12565b612192565b01611e93565b90565b5190565b611ede611ed9611ee392611030565b6106a8565b6102dd565b90565b90611ef082611fad565b81611f1b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b916116ff565b90611f24610231565b80611f2e816104d2565b0390a2611f3a81611ec6565b611f4c611f465f611eca565b916102dd565b115f14611f6057611f5c9161208b565b505b565b5050611f6a612009565b611f5e565b90611f8060018060a01b0391611033565b9181191691161790565b90565b90611fa2611f9d611fa9926116ff565b611f8a565b8254611f6f565b9055565b803b611fc1611fbb5f611eca565b916102dd565b14611fe357611fe1905f611fdb611fd6611b12565b612192565b01611f8d565b565b61200590611fef610231565b918291634c9c8ce360e01b835260048301611d1c565b0390fd5b3461201c6120165f611eca565b916102dd565b1161202357565b61202b610231565b63b398979f60e01b815280612042600482016104d2565b0390fd5b606090565b9061205d61205883610b24565b61028e565b918252565b3d5f1461207d576120723d61204b565b903d5f602084013e5b565b612085612046565b9061207b565b5f806120b793612099612046565b508390602081019051915af4906120ae612062565b909190916120ba565b90565b906120ce906120c7612046565b5015610449565b5f146120da5750612145565b6120e382611ec6565b6120f56120ef5f611eca565b916102dd565b148061212a575b612104575090565b61212690612110610231565b918291639996b31560e01b835260048301611d1c565b0390fd5b50803b61213f6121395f611eca565b916102dd565b146120fc565b61214e81611ec6565b61216061215a5f611eca565b916102dd565b115f1461216f57805190602001fd5b612177610231565b630a12f52160e11b81528061218e600482016104d2565b0390fd5b90565b60401c90565b6121a76121ac91612195565b611726565b90565b6121b9905461219b565b90565b67ffffffffffffffff1690565b6121d56121da91611721565b6121bc565b90565b6121e790546121c9565b90565b67ffffffffffffffff1690565b61220b61220661221092611030565b6106a8565b6121ea565b90565b90565b61222a61222561222f92612213565b6106a8565b6121ea565b90565b61223b906106c7565b90565b9061225167ffffffffffffffff91611033565b9181191691161790565b61226f61226a612274926121ea565b6106a8565b6121ea565b90565b90565b9061228f61228a6122969261225b565b612277565b825461223e565b9055565b60401b90565b906122b468ff00000000000000009161229a565b9181191691161790565b906122d36122ce6122da9261194c565b611958565b82546122a0565b9055565b6122e790612216565b9052565b91906122fe905f602085019401906122de565b565b612308612525565b9061231d6123175f84016121af565b15610449565b906123295f84016121dd565b8061233c6123365f6121f7565b916121ea565b148061245d575b906123576123516001612216565b916121ea565b1480612435575b612369909115610449565b9081612424575b50612401576123999061238e6123866001612216565b5f860161227a565b826123ef575b612464565b6123a1575b50565b6123ae905f8091016122be565b60016123e67fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2916123dd610231565b918291826122eb565b0390a15f61239e565b6123fc60015f86016122be565b612394565b612409610231565b63f92ee8a960e01b815280612420600482016104d2565b0390fd5b61242f915015610449565b5f612370565b5061236961244230612232565b3b61245561244f5f611eca565b916102dd565b14905061235e565b5082612343565b6124ab906124706124c3565b612478612553565b61248a612483611054565b829061197b565b5061249d61249661163d565b829061197b565b506124a66115d9565b61197b565b50565b6124b790612300565b565b6124c16124cd565b565b6124cb6124b9565b565b6124de6124d8612507565b15610449565b6124e457565b6124ec610231565b631afcd79f60e31b815280612503600482016104d2565b0390fd5b61250f6116a5565b506125225f61251c612525565b016121af565b90565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0090565b6125516124cd565b565b61255b612549565b565b60207f7067726164657200000000000000000000000000000000000000000000000000917f4d6f7270686f48656c7065723a2043616c6c6572206973206e6f7420616e20755f8201520152565b6125b760276040926111cf565b6125c08161255d565b0190565b6125d99060208101905f8183039101526125aa565b90565b156125e357565b6125eb610231565b62461bcd60e51b815280612601600482016125c4565b0390fd5b50612631612611611e41565b61262361261c61163d565b829061174d565b908115612633575b506125dc565b565b6126459150612640611054565b61174d565b5f61262b565b61265490612605565b565b61268a90612685612665611e41565b61267761267061163d565b829061174d565b90811561268c575b506125dc565b6126eb565b565b61269e9150612699611054565b61174d565b5f61267f565b6126ad906106ab565b90565b6126b9906126a4565b90565b6126c5906126a4565b90565b90565b906126e06126db6126e7926126bc565b6126c8565b8254611f6f565b9055565b6126f76126fd916126b0565b5f6126cb565b565b61270890612656565b565b61273e90612739612719611e41565b61272b61272461163d565b829061174d565b908115612740575b506125dc565b61279f565b565b612752915061274d611054565b61174d565b5f612733565b612761906106ab565b90565b61276d90612758565b90565b61277990612758565b90565b90565b9061279461278f61279b92612770565b61277c565b8254611f6f565b9055565b6127ab6127b291612764565b600161277f565b565b6127bd9061270a565b565b906127f4916127ef6127cf611e41565b6127e16127da61163d565b829061174d565b9081156127f6575b506125dc565b61280e565b565b6128089150612803611054565b61174d565b5f6127e9565b905f1461282a57612826906128216115d9565b61197b565b505b565b61283b906128366115d9565b611a32565b50612828565b9061284b916127bf565b565b60207f70657261746f7200000000000000000000000000000000000000000000000000917f4d6f7270686f48656c7065723a2043616c6c6572206973206e6f7420616e206f5f8201520152565b6128a760276040926111cf565b6128b08161284d565b0190565b6128c99060208101905f81830391015261289a565b90565b156128d357565b6128db610231565b62461bcd60e51b8152806128f1600482016128b4565b0390fd5b9061292b9291612926612906611e41565b6129186129116115d9565b829061174d565b90811561292d575b506128cc565b612ae2565b565b61293f915061293a611054565b61174d565b5f612920565b61294e906106c7565b90565b5f91031261295b57565b61023b565b60209181520190565b90565b5090565b5061297f9060208101906102ce565b90565b61298b906102ae565b9052565b5061299e9060208101906102f4565b90565b906080612a1a612a22936129c36129ba5f830183612970565b5f860190612982565b6129dd6129d36020830183612970565b6020860190612982565b6129f76129ed6040830183612970565b6040860190612982565b612a11612a076060830183612970565b6060860190612982565b8281019061298f565b910190610777565b565b9060a0612a4f612a5793612a46612a3d5f83018361296c565b5f8601906129a1565b8281019061298f565b910190610777565b565b90612a668160c093612a24565b0190565b5090565b60c00190565b91612a8282612a8892612960565b92612969565b90815f905b828210612a9b575050505090565b90919293612abd612ab7600192612ab28886612a6a565b612a59565b95612a6e565b920190929192612a8d565b9091612adf9260208301925f818503910152612a74565b90565b612aeb90612945565b91637299aa31919092803b15612b6657612b185f8094612b23612b0c610231565b97889687958694611cd9565b845260048401612ac8565b03925af18015612b6157612b35575b50565b612b54905f3d8111612b5a575b612b4c8183610265565b810190612951565b5f612b32565b503d612b42565b611d0c565b611cd5565b90612b7692916128f5565b565b90612bae9291612ba9612b89611e41565b612b9b612b946115d9565b829061174d565b908115612bb0575b506128cc565b612c78565b565b612bc29150612bbd611054565b61174d565b5f612ba3565b60209181520190565b90565b612bdd90610399565b9052565b90612bee81602093612bd4565b0190565b50612c0190602081019061074a565b90565b60200190565b91612c1882612c1e92612bc8565b92612bd1565b90815f905b828210612c31575050505090565b90919293612c53612c4d600192612c488886612bf2565b612be1565b95612c04565b920190929192612c23565b9091612c759260208301925f818503910152612c0a565b90565b612c8190612945565b91632acc56f9919092803b15612cfc57612cae5f8094612cb9612ca2610231565b97889687958694611cd9565b845260048401612c5e565b03925af18015612cf757612ccb575b50565b612cea905f3d8111612cf0575b612ce28183610265565b810190612951565b5f612cc8565b503d612cd8565b611d0c565b611cd5565b90612d0c9291612b78565b565b90612d449291612d3f612d1f611e41565b612d31612d2a6115d9565b829061174d565b908115612d46575b506128cc565b612dbd565b565b612d589150612d53611054565b61174d565b5f612d39565b60209181520190565b5f80fd5b9037565b909182612d7b91612d5e565b9160018060fb1b038111612d9e5782916020612d9a9202938491612d6b565b0190565b612d67565b9091612dba9260208301925f818503910152612d6f565b90565b612dc690612945565b916341b67833919092803b15612e4157612df35f8094612dfe612de7610231565b97889687958694611cd9565b845260048401612da3565b03925af18015612e3c57612e10575b50565b612e2f905f3d8111612e35575b612e278183610265565b810190612951565b5f612e0d565b503d612e1d565b611d0c565b611cd5565b90612e519291612d0e565b565b5f90565b612e63612e6891611721565b6113c6565b90565b612e759054612e57565b90565b90612e9f91612e85612e53565b50612e99612e925f612e6b565b9291612945565b91612ea2565b90565b90612ed090612eca612ede94612eb6612e53565b50612ec083612ee5565b9085919091613aa2565b9261334e565b505091909190919091612f85565b90565b5f90565b60a090612ef0612ee1565b502090565b612f09612f04612f0e92612213565b6106a8565b6102dd565b90565b612f1b6001612ef5565b90565b634e487b7160e01b5f52601160045260245ffd5b612f41612f47919392936102dd565b926102dd565b8201809211612f5257565b612f1e565b90565b612f6e612f69612f7392612f57565b6106a8565b6102dd565b90565b612f82620f4240612f5a565b90565b91612fb7612fa8612fbd94612f98612e53565b5093612fa2612f11565b90612f32565b91612fb1612f76565b90612f32565b9161302b565b90565b612fcf612fd5919392936102dd565b926102dd565b91612fe18382026102dd565b928184041490151715612ff057565b612f1e565b634e487b7160e01b5f52601260045260245ffd5b61301561301b916102dd565b916102dd565b908115613026570490565b612ff5565b61304792916130429161303c612e53565b50612fc0565b613009565b90565b6fffffffffffffffffffffffffffffffff1690565b6130688161304a565b0361306f57565b5f80fd5b905051906130808261305f565b565b919060c083820312613104576130fd9061309c60c061028e565b936130a9825f8301613073565b5f8601526130ba8260208301613073565b60208601526130cc8260408301613073565b60408601526130de8260608301613073565b60608601526130f08260808301613073565b608086015260a001613073565b60a0830152565b610243565b9060c0828203126131225761311f915f01613082565b90565b61023b565b613131905161304a565b90565b61314861314361314d9261304a565b6106a8565b6102dd565b90565b61315f613165919392936102dd565b926102dd565b820391821161317057565b612f1e565b61318961318461318e92611030565b6106a8565b61304a565b90565b61319b90516102ae565b90565b6131b26131ad6131b792611030565b6106a8565b6102a3565b90565b6131c39061319e565b90565b6131cf906106ab565b90565b6131db906131c6565b90565b6131e7906106c7565b90565b905051906131f7826102e0565b565b906020828203126132125761320f915f016131ea565b90565b61023b565b9060808061326f9361322f5f8201515f860190612982565b61324160208201516020860190612982565b61325360408201516040860190612982565b61326560608201516060860190612982565b0151910190610777565b565b61327a9061304a565b9052565b9060a0806132e8936132965f8201515f860190613271565b6132a860208201516020860190613271565b6132ba60408201516040860190613271565b6132cc60608201516060860190613271565b6132de60808201516080860190613271565b0151910190613271565b565b9160a061330c9294936133056101608201965f830190613217565b019061327e565b565b61331a6133209161304a565b9161304a565b01906fffffffffffffffffffffffffffffffff821161333b57565b612f1e565b9061334a9061304a565b9052565b60c06133b19161335c612e53565b50613365612e53565b5061336e612e53565b50613377612e53565b5061338a61338485612ee5565b91611404565b6133a6635c60e39a61339a610231565b95869485938493611cd9565b8352600483016103b2565b03915afa90811561369c575f9161366e575b50906133e3426133dd6133d860808601613127565b613134565b90613150565b806133f66133f05f611eca565b916102dd565b141580613648575b8061361a575b613462575b50506134165f8201613127565b61342260208301613127565b9261345f61345961345361344d613447606061344060408a01613127565b9801613127565b95613134565b96613134565b94613134565b92613134565b90565b602061348061347b61347660608601613191565b6131d2565b6131de565b638c00bf6b93906134a386956134ae613497610231565b97889586948594611cd9565b8452600484016132ea565b03915afa918215613615576134ea926134e4915f916135e7575b50916134de6134d960408701613127565b613134565b92613732565b906136d4565b6135126134f682613884565b61350c604085019161350783613127565b61330e565b90613340565b61353961351e82613884565b6135335f85019161352e83613127565b61330e565b90613340565b61354560a08301613127565b6135576135515f613175565b9161304a565b03613563575b80613409565b6135c56135c061358a6135e19361358461357f60a08801613127565b613134565b906136d4565b6135a6816135a161359c5f8901613127565b613134565b613150565b6135ba6135b560208801613127565b613134565b916137a5565b613884565b6135db60208401916135d683613127565b61330e565b90613340565b5f61355d565b613608915060203d811161360e575b6136008183610265565b8101906131f9565b5f6134c8565b503d6135f6565b611d0c565b5061362760608301613191565b61364161363b6136365f6131ba565b6102ae565b916102ae565b1415613404565b5061365560408401613127565b6136676136615f613175565b9161304a565b14156133fe565b61368f915060c03d8111613695575b6136878183610265565b810190613109565b5f6133c3565b503d61367d565b611d0c565b90565b6136b86136b36136bd926136a1565b6106a8565b6102dd565b90565b6136d1670de0b6b3a76400006136a4565b90565b906136f1916136e1612e53565b50906136eb6136c0565b9161302b565b90565b90565b61370b613706613710926136f4565b6106a8565b6102dd565b90565b90565b61372a61372561372f92613713565b6106a8565b6102dd565b90565b6137a29161374891613742612e53565b50612fc0565b61379d613771828361376b60026137666137606136c0565b916136f7565b612fc0565b9161302b565b6137978184613791600361378c6137866136c0565b91613716565b612fc0565b9161302b565b92612f32565b612f32565b90565b906137d86137c96137de94936137b9612e53565b50936137c3612f76565b90612f32565b916137d2612f11565b90612f32565b9161302b565b90565b5f90565b5f7f6d61782075696e74313238206578636565646564000000000000000000000000910152565b6138166014611153565b90613823602083016137e5565b565b61382d61380c565b90565b613838613825565b90565b156138435750565b6138649061384f610231565b91829162461bcd60e51b83526004830161122c565b0390fd5b61387c613877613881926102dd565b6106a8565b61304a565b90565b6138cc906138906137e1565b506138c7816138b76138b16fffffffffffffffffffffffffffffffff613134565b916102dd565b11156138c1613830565b9061383b565b613868565b90565b67ffffffffffffffff81116138e75760208091020190565b610251565b909291926139016138fc826138cf565b61028e565b938185526020808601920283019281841161393e57915b8383106139255750505050565b602080916139338486611cdf565b815201920191613918565b610896565b9080601f830112156139615781602061395e935191016138ec565b90565b61088e565b90602082820312613996575f82015167ffffffffffffffff81116139915761398e9201613943565b90565b61023f565b61023b565b5190565b60200190565b6139ae90610396565b9052565b906139bf816020936139a5565b0190565b60200190565b906139e66139e06139d98461399b565b8093612bc8565b9261399f565b905f5b8181106139f65750505090565b909192613a0f613a0960019286516139b2565b946139c3565b91019190916139e9565b613a2e9160208201915f8184039101526139c9565b90565b634e487b7160e01b5f52603260045260245ffd5b90613a4f8261399b565b811015613a60576020809102010190565b613a31565b613a6f9051610396565b90565b613a86613a81613a8b926102dd565b6106a8565b6102dd565b90565b613a9a613a9f91611721565b613a72565b90565b613aca613ac4613abf613af1955f95613ab9612e53565b50613c3f565b613ba7565b91611404565b613ae6637784c685613ada610231565b95869485938493611cd9565b835260048301613a19565b03915afa8015613b4c57613b1d613b2291613b27935f91613b2a575b50613b175f611eca565b90613a45565b613a65565b613a8e565b90565b613b4691503d805f833e613b3e8183610265565b810190613966565b5f613b0d565b611d0c565b606090565b90613b68613b63836138cf565b61028e565b918252565b369037565b90613b97613b7f83613b56565b92602080613b8d86936138cf565b9201910390613b6d565b565b90613ba390610396565b9052565b613baf613b51565b50613bde613bc5613bc06001612ef5565b613b72565b91613bd983613bd35f611eca565b90613a45565b613b99565b90565b613beb60026136f7565b90565b916020613c0f929493613c0860408201965f8301906103a5565b01906112a6565b565b60200190565b613c205f611eca565b90565b613c37613c32613c3c926102dd565b611033565b610396565b90565b613cdb613ce991613cc3613cee94613c556117a3565b5091613c89613c62613be1565b91613c7a613c6e610231565b93849260208401613bee565b60208201810382520382610265565b613c9b613c9582611ec6565b91613c11565b2091613cb4613ca8610231565b9384926020840161184c565b60208201810382520382610265565b613cd5613ccf82611ec6565b91613c11565b20613a8e565b613ce3613c17565b90612f32565b613c23565b90565b90613d28939291613d23613d03611e41565b613d15613d0e6115d9565b829061174d565b908115613d2a575b506128cc565b614004565b565b613d3c9150613d37611054565b61174d565b5f613d1d565b67ffffffffffffffff8111613d5a5760208091020190565b610251565b90613d71613d6c83613d42565b61028e565b918252565b613d80604061028e565b90565b613d8d60a061028e565b90565b5f90565b5f90565b613da0613d83565b9060208080808086613db0613d90565b815201613dbb613d90565b815201613dc6613d90565b815201613dd1613d90565b815201613ddc613d94565b81525050565b613dea613d98565b90565b613df5613d76565b9060208083613e02613de2565b815201613e0d613d94565b81525050565b613e1b613ded565b90565b5f5b828110613e2c57505050565b602090613e37613e13565b8184015201613e20565b90613e66613e4e83613d5f565b92602080613e5c8693613d42565b9201910390613e1e565b565b613e7c613e77613e8192611030565b6106a8565b610d8b565b90565b613e98613e93613e9d92610d8b565b6106a8565b6102dd565b90565b613ea990610d8b565b600160ff1b8114613eb9575f0390565b612f1e565b613ec8604061028e565b90565b52565b90613ed8906102dd565b9052565b5190565b90613eea82613edc565b811015613efb576020809102010190565b613a31565b60200190565b90608080613f5e93613f1e5f8201515f860190612982565b613f3060208201516020860190612982565b613f4260408201516040860190612982565b613f5460608201516060860190612982565b0151910190610777565b565b9060a06020613f8393613f795f8201515f860190613f06565b0151910190610777565b565b90613f928160c093613f60565b0190565b60200190565b90613fb9613fb3613fac84613edc565b8093612960565b92613f00565b905f5b818110613fc95750505090565b909192613fe2613fdc6001928651613f85565b94613f96565b9101919091613fbc565b6140019160208201915f818403910152613f9c565b90565b90614106926140b56140ff9261402261401d60026136f7565b613e41565b9661402e868390612e78565b614036612e53565b508161404a6140445f613e68565b91610d8b565b125f14614185576140909161406a6140656140709392613ea0565b613e84565b90612f32565b915b9161408761407e613ebe565b935f8501613ecb565b60208301613ece565b6140af87915f906140a96140a383611eca565b85613ee0565b52611eca565b90613ee0565b51506140d95f196140d06140c7613ebe565b935f8501613ecb565b60208301613ece565b6140f985916001906140f36140ed83612ef5565b85613ee0565b52612ef5565b90613ee0565b5150612945565b90637299aa3190823b156141805761413d926141325f8094614126610231565b96879586948593611cd9565b835260048301613fec565b03925af1801561417b5761414f575b50565b61416e905f3d8111614174575b6141668183610265565b810190612951565b5f61414c565b503d61415c565b611d0c565b611cd5565b61418e82613e84565b6141a061419a836102dd565b916102dd565b11155f146141c657614090916141b96141bf9291613e84565b90613150565b5b91614072565b50506140906141d45f611eca565b6141c0565b906141e5939291613cf1565b565b9061421e9392916142196141f9611e41565b61420b6142046115d9565b829061174d565b908115614220575b506128cc565b6142da565b565b614232915061422d611054565b61174d565b5f614213565b90505190614245826102ba565b565b919060a0838203126142b7576142b09061426160a061028e565b9361426e825f8301614238565b5f86015261427f8260208301614238565b60208601526142918260408301614238565b60408601526142a38260608301614238565b60608601526080016131ea565b6080830152565b610243565b9060a0828203126142d5576142d2915f01614247565b90565b61023b565b9160a061431a94926142f36142ee5f612e6b565b611404565b61430f632c3c9157614303610231565b98899485938493611cd9565b8352600483016103b2565b03915afa9081156143f25761436c945f926143c0575b5060a0906143456143405f612e6b565b611404565b614361632c3c9157614355610231565b98899485938493611cd9565b8352600483016103b2565b03915afa9182156143bb57614389945f9361438b575b50926141d9565b565b6143ad91935060a03d81116143b4575b6143a58183610265565b8101906142bc565b915f614382565b503d61439b565b611d0c565b60a09192506143e490823d81116143eb575b6143dc8183610265565b8101906142bc565b9190614330565b503d6143d2565b611d0c565b906144039392916141e7565b565b9061443c939291614437614417611e41565b6144296144226115d9565b829061174d565b90811561443e575b506128cc565b614527565b565b614450915061444b611054565b61174d565b5f614431565b67ffffffffffffffff811161446e5760208091020190565b610251565b919060c0838203126144ad576144a69061448d604061028e565b9361449a825f8301610303565b5f86015260a001610da2565b6020830152565b610243565b909291926144c76144c282614456565b61028e565b9381855260c060208601920283019281841161450657915b8383106144ec5750505050565b602060c0916144fb8486614473565b8152019201916144df565b610896565b6145169136916144b2565b90565b614524903690610303565b90565b61453a614546946145409294909361450b565b91614519565b916148ca565b565b90614554939291614405565b565b9061458d939291614588614568611e41565b61457a6145736115d9565b829061174d565b90811561458f575b506128cc565b6146d8565b565b6145a1915061459c611054565b61174d565b5f614582565b5090565b906145bd6145b883614456565b61028e565b918252565b6145cc604061028e565b90565b5f90565b6145db6145c2565b90602080836145e8613de2565b8152016145f36145cf565b81525050565b6146016145d3565b90565b5f5b82811061461257505050565b60209061461d6145f9565b8184015201614606565b9061464c614634836145ab565b926020806146428693614456565b9201910390614604565b565b614657906102dd565b5f1981146146655760010190565b612f1e565b919081101561467a576040020190565b613a31565b3561468981610736565b90565b3561469681610d8e565b90565b6146a3604061028e565b90565b906146b090610d8b565b9052565b5190565b906146c2826146b4565b8110156146d3576020809102010190565b613a31565b9290936146ee6146e98685906145a7565b614627565b916146f85f611eca565b5b8061471661471061470b8a89906145a7565b6102dd565b916102dd565b1015614816576147729060a08861473461472f5f612e6b565b611404565b6147676147525f61474c632c3c9157958d899161466a565b0161467f565b9261475b610231565b96879485938493611cd9565b8352600483016103b2565b03915afa918215614811576147de926147d7915f916147e3575b506147c46147a760206147a18d8c889161466a565b0161468c565b6147bb6147b2614699565b935f8501613ecb565b602083016146a6565b8683916147d183836146b8565b526146b8565b515061464e565b6146f9565b614804915060a03d811161480a575b6147fc8183610265565b8101906142bc565b5f61478c565b503d6147f2565b611d0c565b50919250935060a061485c9392916148356148305f612e6b565b611404565b614851632c3c9157614845610231565b97889485938493611cd9565b8352600483016103b2565b03915afa9182156148aa57614878935f9361487a575b506148ca565b565b61489c91935060a03d81116148a3575b6148948183610265565b8101906142bc565b915f614872565b503d61488a565b611d0c565b906148bb939291614556565b565b6148c79051610d8b565b90565b9290926148f16148ec6148dc866146b4565b6148e66001612ef5565b90612f32565b613e41565b916148fb5f611eca565b5b8061491761491161490c896146b4565b6102dd565b916102dd565b1015614a76576149f49061493a845f6149318a85906146b8565b51015190612e78565b614942612e53565b508761495b60206149548386906146b8565b51016148bd565b61496d6149675f613e68565b91610d8b565b125f146149f9576149a9906149a361499e61499960206149926149ed979589906146b8565b51016148bd565b613ea0565b613e84565b90612f32565b5b6149da5f6149b98b86906146b8565b510151916149d16149c8613ebe565b935f8501613ecb565b60208301613ece565b8683916149e78383613ee0565b52613ee0565b515061464e565b6148fc565b614a136020614a0c614a189386906146b8565b51016148bd565b613e84565b614a2a614a24836102dd565b916102dd565b11155f14614a6457614a5e6149ed91614a58614a536020614a4c8d88906146b8565b51016148bd565b613e84565b90613150565b5b6149aa565b506149ed614a715f611eca565b614a5f565b5093614abf90614ac6939490614aa45f19614a9b614a92613ebe565b945f8601613ecb565b60208401613ece565b614aae86916146b4565b91614ab98383613ee0565b52613ee0565b5150612945565b90637299aa3190823b15614b4057614afd92614af25f8094614ae6610231565b96879586948593611cd9565b835260048301613fec565b03925af18015614b3b57614b0f575b50565b614b2e905f3d8111614b34575b614b268183610265565b810190612951565b5f614b0c565b503d614b1c565b611d0c565b611cd5565b90614b7b9291614b76614b56611e41565b614b68614b616115d9565b829061174d565b908115614b7d575b506128cc565b614ce8565b565b614b8f9150614b8a611054565b61174d565b5f614b70565b614ba1614ba691611721565b610668565b90565b614bb39054614b95565b90565b60209181520190565b90565b5090565b90503590614bd38261305f565b565b50614be4906020810190614bc6565b90565b906020614c12614c1a93614c09614c005f830183614bd5565b5f860190613271565b82810190614bd5565b910190613271565b565b906020614c47614c4f93614c3e614c355f830183612bf2565b5f860190612bd4565b82810190614bc2565b910190614be7565b565b90614c5e81606093614c1c565b0190565b5090565b60600190565b91614c7a82614c8092614bb6565b92614bbf565b90815f905b828210614c93575050505090565b90919293614cb5614caf600192614caa8886614c62565b614c51565b95614c66565b920190929192614c85565b91614ce5939192614cd860408201945f83019061183f565b6020818503910152614c6c565b90565b90614cfb614cf66001614ba9565b6106d3565b614d0963f461804693612945565b919392813b15614d7f575f614d3191614d3c8296614d25610231565b98899788968795611cd9565b855260048501614cc0565b03925af18015614d7a57614d4e575b50565b614d6d905f3d8111614d73575b614d658183610265565b810190612951565b5f614d4b565b503d614d5b565b611d0c565b611cd5565b90614d8f9291614b45565b565b90614dc691614dc1614da1611e41565b614db3614dac6115d9565b829061174d565b908115614dc8575b506128cc565b614e03565b565b614dda9150614dd5611054565b61174d565b5f614dbb565b916020614e01929493614dfa60408201965f83019061183f565b01906112a6565b565b614e15614e106001614ba9565b6106d3565b9163e55156b5919092803b15614e9057614e425f8094614e4d614e36610231565b97889687958694611cd9565b845260048401614de0565b03925af18015614e8b57614e5f575b50565b614e7e905f3d8111614e84575b614e768183610265565b810190612951565b5f614e5c565b503d614e6c565b611d0c565b611cd5565b90614e9f91614d91565b565b90614ed691614ed1614eb1611e41565b614ec3614ebc6115d9565b829061174d565b908115614ed8575b506128cc565b614f20565b565b614eea9150614ee5611054565b61174d565b5f614ecb565b614ef9906110a0565b9052565b916020614f1e929493614f1760408201965f83019061183f565b0190614ef0565b565b614f32614f2d6001614ba9565b6106d3565b91630e4eecf8919092803b15614fad57614f5f5f8094614f6a614f53610231565b97889687958694611cd9565b845260048401614efd565b03925af18015614fa857614f7c575b50565b614f9b905f3d8111614fa1575b614f938183610265565b810190612951565b5f614f79565b503d614f89565b611d0c565b611cd5565b90614fbc91614ea1565b565b90614ff391614fee614fce611e41565b614fe0614fd961163d565b829061174d565b908115614ff5575b506125dc565b615030565b565b6150079150615002611054565b61174d565b5f614fe8565b91602061502e92949361502760408201965f83019061183f565b019061183f565b565b61504261503d6001614ba9565b6106d3565b9163c55b6bb7919092803b156150bd5761506f5f809461507a615063610231565b97889687958694611cd9565b84526004840161500d565b03925af180156150b85761508c575b50565b6150ab905f3d81116150b1575b6150a38183610265565b810190612951565b5f615089565b503d615099565b611d0c565b611cd5565b906150cc91614fbe565b565b6150e0906150da612ee1565b50612ee5565b90565b6150ee61010061028e565b90565b6150f96150e3565b906020808080808080808961510c613d94565b815201615117613d94565b815201615122613d94565b81520161512d613d94565b815201615138613d94565b815201615143613d94565b81520161514e613d94565b815201615159613d94565b81525050565b6151676150f1565b90565b90565b61518161517c6151869261516a565b6106a8565b6102dd565b90565b61519390516102dd565b90565b6151aa6151a56151af926136a1565b6106a8565b61304a565b90565b6151be6151c49161304a565b9161304a565b9003906fffffffffffffffffffffffffffffffff82116151e057565b612f1e565b906151ee61515f565b9161522f60c06152056152005f612e6b565b611404565b635c60e39a906152248592615218610231565b95869485938493611cd9565b8352600483016103b2565b03915afa908115615536575f91615508575b509061528360a06152596152545f612e6b565b611404565b632c3c915790615278859261526c610231565b95869485938493611cd9565b8352600483016103b2565b03915afa90811561550357615301916152f8915f916154d5575b50926152ea6152e46152b86152b15f612e6b565b879061334e565b9093916152de8d5f8101966152d860208301956060604085019401613ece565b90613ece565b90613ece565b90613ece565b6152f35f612e6b565b6155e4565b60808601613ece565b61531661530d5f611eca565b60e08601613ece565b61532260608201613191565b61533c6153366153315f6131ba565b6102ae565b916102ae565b0361540d575b506153da6153c86153e3926153585f8701615189565b61536a6153645f611eca565b916102dd565b145f146153e55761538761537d5f611eca565b5b60a08801613ece565b6153c26153bd61539960e08901615189565b926153b86153b260a0670de0b6b3a76400009301613127565b91615196565b6151b2565b613134565b906136d4565b6153d460a08601615189565b906136d4565b60c08401613ece565b565b6153876154086153f760408901615189565b6154025f8a01615189565b9061553b565b61537e565b602061542b61542661542160608501613191565b6131d2565b6131de565b638c00bf6b929061544e8594615459615442610231565b96879586948594611cd9565b8452600484016132ea565b03915afa9081156154d0576153e39261549a6154916153da946153c8945f916154a2575b5061548b6301e1338061516d565b90613732565b60e08801613ece565b925050615342565b6154c3915060203d81116154c9575b6154bb8183610265565b8101906131f9565b5f61547d565b503d6154b1565b611d0c565b6154f6915060a03d81116154fc575b6154ee8183610265565b8101906142bc565b5f61529d565b503d6154e4565b611d0c565b615529915060c03d811161552f575b6155218183610265565b810190613109565b5f615241565b503d615517565b611d0c565b9061555991615548612e53565b50906155526136c0565b909161555c565b90565b615576615595939261559092615570612e53565b50612fc0565b61558a836155846001612ef5565b90613150565b90612f32565b613009565b90565b90565b60ff1690565b6155b56155b06155ba92615598565b6106a8565b61559b565b90565b6155dc906155d66155d06155e19461559b565b91610396565b90610664565b610396565b90565b5f9061560c615606615601615633956155fb612e53565b506156c1565b613ba7565b91611404565b615628637784c68561561c610231565b95869485938493611cd9565b835260048301613a19565b03915afa9081156156a25761566861566361567d93615678935f91615680575b5061565d5f611eca565b90613a45565b613a65565b61567260806155a1565b906155bd565b613a8e565b90565b61569c91503d805f833e6156948183610265565b810190613966565b5f615653565b611d0c565b6156b16003613716565b90565b6156be60026136f7565b90565b61572c61571e615731926156d36117a3565b506157066156df6156a7565b916156f76156eb610231565b93849260208401613bee565b60208201810382520382610265565b61571861571282611ec6565b91613c11565b20613a8e565b6157266156b4565b90612f32565b613c23565b90565b61573f61010061028e565b90565b61574a615734565b906020808080808080808961575d613d94565b815201615768613d94565b815201615773613d94565b81520161577e613d94565b815201615789613d94565b815201615794613d94565b81520161579f613d94565b8152016157aa613d94565b81525050565b6157b8615742565b90565b919060608382031261580757615800906157d5606061028e565b936157e2825f83016131ea565b5f8601526157f38260208301613073565b6020860152604001613073565b6040830152565b610243565b9060608282031261582557615822915f016157bb565b90565b61023b565b91602061584b92949361584460408201965f8301906103a5565b019061183f565b565b615856906106ab565b90565b6158629061584d565b90565b61586e906106c7565b90565b90565b61588861588361588d92615871565b6106a8565b6102dd565b90565b6158a86ec097ce7bc90715b34b9f1000000000615874565b90565b91906158b56157b0565b926158f660a06158cc6158c75f612e6b565b611404565b632c3c9157906158eb85926158df610231565b95869485938493611cd9565b8352600483016103b2565b03915afa908115615c52575f91615c24575b5090606061591d6159185f612e6b565b611404565b6393c520629290615940869461594b615934610231565b96879586948594611cd9565b84526004840161582a565b03915afa908115615c1f575f91615bf1575b5061596a60408301613191565b61598461597e6159795f6131ba565b6102ae565b916102ae565b145f14615b41576080615ab6615ac394615a61615a595f615abd96615a538c6020615a4c8c6159b287611eca565b5b996159d36159cb6159c660408a01613127565b613134565b8e8701613ece565b6159fc6159f36159e48f8801615189565b8d6159ed615890565b9161302b565b60a08701613ece565b615a1c615a13615a0b8a612e6b565b848491615c78565b60608701613ece565b615a3b615a32615a2d868a01613127565b613134565b60408701613ece565b615a4488612e6b565b919091612ea2565b9101613ece565b01615189565b5f8a01613ece565b615a6d60a08901615189565b615a7f615a795f611eca565b916102dd565b145f14615b1857615a9c615a925f611eca565b5b60c08a01613ece565b615aa7838901615189565b90615ab0615890565b9161302b565b9201615189565b906136d4565b615acf60608401615189565b615ae1615adb5f611eca565b916102dd565b145f14615afa5750615af85f195b60e08401613ece565b565b615b13615af891615b0d60608601615189565b90615c57565b615aef565b615a9c615b3c615b2a60608b01615189565b615b3660a08c01615189565b9061553b565b615a93565b615b786020615b62615b5d615b5860408701613191565b615859565b615865565b63a035b1fe90615b70610231565b938492611cd9565b82528180615b88600482016104d2565b03915afa8015615bec57615ac394615a61615a595f615abd96615a538c6020615a4c8c615ab69a60809c8891615bbf575b506159b3565b615bdf9150843d8111615be5575b615bd78183610265565b8101906131f9565b5f615bb9565b503d615bcd565b611d0c565b615c12915060603d8111615c18575b615c0a8183610265565b81019061580c565b5f61595d565b503d615c00565b611d0c565b615c45915060a03d8111615c4b575b615c3d8183610265565b8101906142bc565b5f615908565b503d615c33565b611d0c565b90615c7591615c64612e53565b5090615c6e6136c0565b909161302b565b90565b90615ca690615ca0615cb594615c8c612e53565b50615c9683612ee5565b9085919091615cf3565b9261334e565b93925090509190919091615cb8565b90565b91615cea615cdb615cf094615ccb612e53565b5093615cd5612f11565b90612f32565b91615ce4612f76565b90612f32565b9161555c565b90565b615d1b615d15615d10615d42955f95615d0a612e53565b50615dbf565b613ba7565b91611404565b615d37637784c685615d2b610231565b95869485938493611cd9565b835260048301613a19565b03915afa8015615dad57615d7e615d79615d74615d8393615d88955f91615d8b575b50615d6e5f611eca565b90613a45565b613a65565b613a8e565b613868565b613134565b90565b615da791503d805f833e615d9f8183610265565b810190613966565b5f615d64565b611d0c565b615dbc6001612ef5565b90565b615e5b615e6991615e43615e6e94615dd56117a3565b5091615e09615de2613be1565b91615dfa615dee610231565b93849260208401613bee565b60208201810382520382610265565b615e1b615e1582611ec6565b91613c11565b2091615e34615e28610231565b9384926020840161184c565b60208201810382520382610265565b615e55615e4f82611ec6565b91613c11565b20613a8e565b615e63615db2565b90612f32565b613c23565b9056fea2646970667358221220a22232bfdc3a9e0decdaa178b9a6155dd02be7b15e95d1b327ebda4fda5a702e64736f6c63430008150033
Deployed Bytecode
0x60806040526004361015610013575b6116a1565b61001d5f3561022b565b8062fb0d821461022657806301ffc9a71461022157806312440f5a1461021c5780631da98c9214610217578063248a9ca3146102125780632f2ff15d1461020d57806330c9d4ac1461020857806330f4f4bb14610203578063364f5732146101fe57806336568abe146101f957806344fe5295146101f45780634844da13146101ef5780634f1ef286146101ea57806352d1902d146101e55780635c388821146101e057806367756192146101db578063784980b8146101d6578063919b56f6146101d157806391d14854146101cc57806393512617146101c75780639388e8f3146101c2578063a217fddf146101bd578063ab6a48d9146101b8578063ad3cb1cc146101b3578063afe0e35a146101ae578063b3f57300146101a9578063c4d66de8146101a4578063d547741f1461019f578063d8fbc8331461019a578063db35ce8414610195578063eb7499cf14610190578063f5b541a61461018b5763f72c0d8b0361000e5761166c565b611608565b6115a5565b6114ec565b611432565b611392565b61135f565b61132b565b6112c8565b611244565b6110fc565b61106b565b610ff9565b610f7d565b610ef7565b610ec0565b610df7565b610d58565b610d22565b610c1a565b610bf0565b610aec565b610a30565b610953565b61091f565b61082a565b610701565b610621565b6105bf565b610529565b6104d7565b610470565b6103c7565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061026f90610247565b810190811067ffffffffffffffff82111761028957604052565b610251565b906102a161029a610231565b9283610265565b565b60018060a01b031690565b6102b7906102a3565b90565b6102c3816102ae565b036102ca57565b5f80fd5b905035906102db826102ba565b565b90565b6102e9816102dd565b036102f057565b5f80fd5b90503590610301826102e0565b565b919060a0838203126103735761036c9061031d60a061028e565b9361032a825f83016102ce565b5f86015261033b82602083016102ce565b602086015261034d82604083016102ce565b604086015261035f82606083016102ce565b60608601526080016102f4565b6080830152565b610243565b9060a0828203126103915761038e915f01610303565b90565b61023b565b90565b6103a290610396565b90565b6103ae90610399565b9052565b91906103c5905f602085019401906103a5565b565b346103f7576103f36103e26103dd366004610378565b6150ce565b6103ea610231565b918291826103b2565b0390f35b610237565b63ffffffff60e01b1690565b610411816103fc565b0361041857565b5f80fd5b9050359061042982610408565b565b9060208282031261044457610441915f0161041c565b90565b61023b565b151590565b61045790610449565b9052565b919061046e905f6020850194019061044e565b565b346104a05761049c61048b61048636600461042b565b6116a9565b610493610231565b9182918261045b565b0390f35b610237565b91906040838203126104cd57806104c16104ca925f86016102ce565b936020016102ce565b90565b61023b565b5f0190565b34610506576104f06104ea3660046104a5565b906150c2565b6104f8610231565b80610502816104d2565b0390f35b610237565b9060208282031261052457610521915f016102ce565b90565b61023b565b346105575761054161053c36600461050b565b6126ff565b610549610231565b80610553816104d2565b0390f35b610237565b61056581610396565b0361056c57565b5f80fd5b9050359061057d8261055c565b565b9060208282031261059857610595915f01610570565b90565b61023b565b6105a690610396565b9052565b91906105bd905f6020850194019061059d565b565b346105ef576105eb6105da6105d536600461057f565b6117cb565b6105e2610231565b918291826105aa565b0390f35b610237565b919060408382031261061c5780610610610619925f8601610570565b936020016102ce565b90565b61023b565b346106505761063a6106343660046105f4565b9061181f565b610642610231565b8061064c816104d2565b0390f35b610237565b5f91031261065f57565b61023b565b1c90565b60018060a01b031690565b6106839060086106889302610664565b610668565b90565b906106969154610673565b90565b6106a560015f9061068b565b90565b90565b6106bf6106ba6106c4926102a3565b6106a8565b6102a3565b90565b6106d0906106ab565b90565b6106dc906106c7565b90565b6106e8906106d3565b9052565b91906106ff905f602085019401906106df565b565b3461073157610711366004610655565b61072d61071c610699565b610724610231565b918291826106ec565b0390f35b610237565b61073f81610396565b0361074657565b5f80fd5b9050359061075782610736565b565b906020828203126107725761076f915f0161074a565b90565b61023b565b610780906102dd565b9052565b9060e0806108129361079c5f8201515f860190610777565b6107ae60208201516020860190610777565b6107c060408201516040860190610777565b6107d260608201516060860190610777565b6107e460808201516080860190610777565b6107f660a082015160a0860190610777565b61080860c082015160c0860190610777565b0151910190610777565b565b9190610828905f6101008501940190610784565b565b3461085a57610856610845610840366004610759565b6151e5565b61084d610231565b91829182610814565b0390f35b610237565b610868906102ae565b90565b6108748161085f565b0361087b57565b5f80fd5b9050359061088c8261086b565b565b5f80fd5b5f80fd5b5f80fd5b909182601f830112156108d45781359167ffffffffffffffff83116108cf5760200192602083028401116108ca57565b610896565b610892565b61088e565b91909160408184031261091a576108f2835f830161087f565b92602082013567ffffffffffffffff811161091557610911920161089a565b9091565b61023f565b61023b565b3461094e576109386109323660046108d9565b91612e46565b610940610231565b8061094a816104d2565b0390f35b610237565b346109825761096c6109663660046105f4565b906118e7565b610974610231565b8061097e816104d2565b0390f35b610237565b909182601f830112156109c15781359167ffffffffffffffff83116109bc576020019260c083028401116109b757565b610896565b610892565b61088e565b5f80fd5b908160a09103126109d85790565b6109c6565b9060e082820312610a2b576109f4815f840161087f565b92602083013567ffffffffffffffff8111610a2657610a1883610a23928601610987565b9390946040016109ca565b90565b61023f565b61023b565b34610a6257610a4c610a433660046109dd565b92919091614548565b610a54610231565b80610a5e816104d2565b0390f35b610237565b909182601f83011215610aa15781359167ffffffffffffffff8311610a9c576020019260608302840111610a9757565b610896565b610892565b61088e565b919091604081840312610ae757610abf835f830161087f565b92602082013567ffffffffffffffff8111610ae257610ade9201610a67565b9091565b61023f565b61023b565b34610b1b57610b05610aff366004610aa6565b91614d84565b610b0d610231565b80610b17816104d2565b0390f35b610237565b5f80fd5b67ffffffffffffffff8111610b4257610b3e602091610247565b0190565b610251565b90825f939282370152565b90929192610b67610b6282610b24565b61028e565b93818552602085019082840111610b8357610b8192610b47565b565b610b20565b9080601f83011215610ba657816020610ba393359101610b52565b90565b61088e565b919091604081840312610beb57610bc4835f83016102ce565b92602082013567ffffffffffffffff8111610be657610be39201610b88565b90565b61023f565b61023b565b610c04610bfe366004610bab565b90611b86565b610c0c610231565b80610c16816104d2565b0390f35b34610c4a57610c2a366004610655565b610c46610c35611b4a565b610c3d610231565b918291826105aa565b0390f35b610237565b9190604083820312610c775780610c6b610c74925f860161074a565b936020016102ce565b90565b61023b565b9060e080610d0a93610c945f8201515f860190610777565b610ca660208201516020860190610777565b610cb860408201516040860190610777565b610cca60608201516060860190610777565b610cdc60808201516080860190610777565b610cee60a082015160a0860190610777565b610d0060c082015160c0860190610777565b0151910190610777565b565b9190610d20905f6101008501940190610c7c565b565b34610d5357610d4f610d3e610d38366004610c4f565b906158ab565b610d46610231565b91829182610d0c565b0390f35b610237565b34610d8657610d70610d6b36600461050b565b6127b4565b610d78610231565b80610d82816104d2565b0390f35b610237565b90565b610d9781610d8b565b03610d9e57565b5f80fd5b90503590610daf82610d8e565b565b608081830312610df257610dc7825f830161087f565b92610def610dd8846020850161074a565b93610de6816040860161074a565b93606001610da2565b90565b61023b565b34610e2957610e13610e0a366004610db1565b929190916143f7565b610e1b610231565b80610e25816104d2565b0390f35b610237565b909182601f83011215610e685781359167ffffffffffffffff8311610e63576020019260408302840111610e5e57565b610896565b610892565b61088e565b90606082820312610ebb57610e84815f840161087f565b92602083013567ffffffffffffffff8111610eb657610ea883610eb3928601610e2e565b93909460400161074a565b90565b61023f565b61023b565b34610ef257610edc610ed3366004610e6d565b929190916148af565b610ee4610231565b80610eee816104d2565b0390f35b610237565b34610f2857610f24610f13610f0d3660046105f4565b9061174d565b610f1b610231565b9182918261045b565b0390f35b610237565b610f3681610449565b03610f3d57565b5f80fd5b90503590610f4e82610f2d565b565b9190604083820312610f785780610f6c610f75925f86016102ce565b93602001610f41565b90565b61023b565b34610fac57610f96610f90366004610f50565b90612841565b610f9e610231565b80610fa8816104d2565b0390f35b610237565b61018081830312610ff457610fc8825f830161087f565b92610ff1610fd98460208501610303565b93610fe78160c08601610303565b9361016001610da2565b90565b61023b565b3461102b5761101561100c366004610fb1565b929190916141d9565b61101d610231565b80611027816104d2565b0390f35b610237565b90565b5f1b90565b61104c61104761105192611030565b611033565b610396565b90565b61105d5f611038565b90565b611068611054565b90565b3461109b5761107b366004610655565b611097611086611060565b61108e610231565b918291826105aa565b0390f35b610237565b6110a9906102a3565b90565b6110b5816110a0565b036110bc57565b5f80fd5b905035906110cd826110ac565b565b91906040838203126110f757806110eb6110f4925f86016102ce565b936020016110c0565b90565b61023b565b3461112b5761111561110f3660046110cf565b90614fb2565b61111d610231565b80611127816104d2565b0390f35b610237565b67ffffffffffffffff811161114e5761114a602091610247565b0190565b610251565b9061116561116083611130565b61028e565b918252565b5f7f352e302e30000000000000000000000000000000000000000000000000000000910152565b61119b6005611153565b906111a86020830161116a565b565b6111b2611191565b90565b6111bd6111aa565b90565b6111c86111b5565b90565b5190565b60209181520190565b5f5b8381106111ea575050905f910152565b8060209183015181850152016111da565b61121a61122360209361122893611211816111cb565b938480936111cf565b958691016111d8565b610247565b0190565b6112419160208201915f8184039101526111fb565b90565b3461127457611254366004610655565b61127061125f6111c0565b611267610231565b9182918261122c565b0390f35b610237565b919060c0838203126112a1578061129561129e925f860161087f565b93602001610303565b90565b61023b565b6112af906102dd565b9052565b91906112c6905f602085019401906112a6565b565b346112f9576112f56112e46112de366004611279565b90612e78565b6112ec610231565b918291826112b3565b0390f35b610237565b9190604083820312611326578061131a611323925f86016102ce565b936020016102f4565b90565b61023b565b3461135a5761134461133e3660046112fe565b90614e95565b61134c610231565b80611356816104d2565b0390f35b610237565b3461138d5761137761137236600461050b565b6124ae565b61137f610231565b80611389816104d2565b0390f35b610237565b346113c1576113ab6113a53660046105f4565b906118db565b6113b3610231565b806113bd816104d2565b0390f35b610237565b60018060a01b031690565b6113e19060086113e69302610664565b6113c6565b90565b906113f491546113d1565b90565b6114015f806113e9565b90565b61140d906106c7565b90565b61141990611404565b9052565b9190611430905f60208501940190611410565b565b3461146257611442366004610655565b61145e61144d6113f7565b611455610231565b9182918261141d565b0390f35b610237565b909182601f830112156114a15781359167ffffffffffffffff831161149c57602001926020830284011161149757565b610896565b610892565b61088e565b9190916040818403126114e7576114bf835f830161087f565b92602082013567ffffffffffffffff81116114e2576114de9201611467565b9091565b61023f565b61023b565b3461151b576115056114ff3660046114a6565b91612d01565b61150d610231565b80611517816104d2565b0390f35b610237565b909182601f8301121561155a5781359167ffffffffffffffff8311611555576020019260c0830284011161155057565b610896565b610892565b61088e565b9190916040818403126115a057611578835f830161087f565b92602082013567ffffffffffffffff811161159b576115979201611520565b9091565b61023f565b61023b565b346115d4576115be6115b836600461155f565b91612b6b565b6115c6610231565b806115d0816104d2565b0390f35b610237565b7f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92990565b6116056115d9565b90565b3461163857611618366004610655565b6116346116236115fd565b61162b610231565b918291826105aa565b0390f35b610237565b7f189ab7a9244df0848122154315af71fe140f3db0fe014031783b0946b8c9d2e390565b61166961163d565b90565b3461169c5761167c366004610655565b611698611687611661565b61168f610231565b918291826105aa565b0390f35b610237565b5f80fd5b5f90565b6116b16116a5565b50806116cc6116c6637965db0b60e01b6103fc565b916103fc565b149081156116d9575b5090565b6116e39150611e4e565b5f6116d5565b906116f390610399565b5f5260205260405f2090565b611708906106c7565b90565b90611715906116ff565b5f5260205260405f2090565b5f1c90565b60ff1690565b61173861173d91611721565b611726565b90565b61174a905461172c565b90565b61177c915f611771611777936117616116a5565b508261176b61177f565b016116e9565b0161170b565b611740565b90565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b5f90565b90565b6117b66117bb91611721565b6117a7565b90565b6117c890546117aa565b90565b60016117ec6117f2926117dc6117a3565b505f6117e661177f565b016116e9565b016117be565b90565b906118109161180b611806826117cb565b61182b565b611812565b565b9061181c9161197b565b50565b90611829916117f5565b565b61183d90611837611e41565b9061186f565b565b611848906102ae565b9052565b91602061186d92949361186660408201965f83019061183f565b019061059d565b565b9061188461187e83839061174d565b15610449565b61188c575050565b6118ad611897610231565b92839263e2517d3f60e01b84526004840161184c565b0390fd5b906118cc916118c76118c2826117cb565b61182b565b6118ce565b565b906118d891611a32565b50565b906118e5916118b1565b565b90806119026118fc6118f7611e41565b6102ae565b916102ae565b036119135761191091611a32565b50565b61191b610231565b63334bd91960e11b815280611932600482016104d2565b0390fd5b9061194260ff91611033565b9181191691161790565b61195590610449565b90565b90565b9061197061196b6119779261194c565b611958565b8254611936565b9055565b6119836116a5565b5061198c61177f565b6119a061199a83859061174d565b15610449565b5f14611a2b576119ca906119c55f6119bd816001940186906116e9565b01859061170b565b61195b565b906119d3611e41565b90611a10611a0a611a047f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d95610399565b926116ff565b926116ff565b92611a19610231565b80611a23816104d2565b0390a4600190565b5050505f90565b611a3a6116a5565b50611a4361177f565b611a4e82849061174d565b5f14611ad857611a7790611a725f611a6a8180940186906116e9565b01859061170b565b61195b565b90611a80611e41565b90611abd611ab7611ab17ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b95610399565b926116ff565b926116ff565b92611ac6610231565b80611ad0816104d2565b0390a4600190565b5050505f90565b611af090611aeb611c4c565b611b3e565b90565b90565b611b0a611b05611b0f92611af3565b611033565b610396565b90565b611b3b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc611af6565b90565b50611b47611b12565b90565b611b5a611b556117a3565b611adf565b90565b90611b6f91611b6a611b9e565b611b71565b565b90611b8491611b7f8161264b565b611d31565b565b90611b9091611b5d565b565b611b9b906106c7565b90565b611ba730611b92565b611bd9611bd37f000000000000000000000000eafabd9dcc2a8106ed87a03cd150af08752883806102ae565b916102ae565b148015611c0a575b611be757565b611bef610231565b63703e46dd60e11b815280611c06600482016104d2565b0390fd5b50611c13611ea0565b611c45611c3f7f000000000000000000000000eafabd9dcc2a8106ed87a03cd150af08752883806102ae565b916102ae565b1415611be1565b611c5530611b92565b611c87611c817f000000000000000000000000eafabd9dcc2a8106ed87a03cd150af08752883806102ae565b916102ae565b03611c8e57565b611c96610231565b63703e46dd60e11b815280611cad600482016104d2565b0390fd5b611cba906106ab565b90565b611cc690611cb1565b90565b611cd2906106c7565b90565b5f80fd5b60e01b90565b90505190611cec8261055c565b565b90602082820312611d0757611d04915f01611cdf565b90565b61023b565b611d14610231565b3d5f823e3d90fd5b9190611d2f905f6020850194019061183f565b565b9190611d5f6020611d49611d4486611cbd565b611cc9565b6352d1902d90611d57610231565b938492611cd9565b82528180611d6f600482016104d2565b03915afa80915f92611e0d575b50155f14611db7575050906001611d9157505b565b611db390611d9d610231565b918291634c9c8ce360e01b835260048301611d1c565b0390fd5b9283611dd2611dcc611dc7611b12565b610396565b91610396565b03611de757611de2929350611ee6565b611d8f565b611e0984611df3610231565b918291632a87526960e21b8352600483016105aa565b0390fd5b611e2f91925060203d8111611e36575b611e278183610265565b810190611cee565b905f611d7c565b503d611e1d565b5f90565b611e49611e3d565b503390565b611e566116a5565b50611e70611e6a6301ffc9a760e01b6103fc565b916103fc565b1490565b60018060a01b031690565b611e8b611e9091611721565b611e74565b90565b611e9d9054611e7f565b90565b611ea8611e3d565b50611ec35f611ebd611eb8611b12565b612192565b01611e93565b90565b5190565b611ede611ed9611ee392611030565b6106a8565b6102dd565b90565b90611ef082611fad565b81611f1b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b916116ff565b90611f24610231565b80611f2e816104d2565b0390a2611f3a81611ec6565b611f4c611f465f611eca565b916102dd565b115f14611f6057611f5c9161208b565b505b565b5050611f6a612009565b611f5e565b90611f8060018060a01b0391611033565b9181191691161790565b90565b90611fa2611f9d611fa9926116ff565b611f8a565b8254611f6f565b9055565b803b611fc1611fbb5f611eca565b916102dd565b14611fe357611fe1905f611fdb611fd6611b12565b612192565b01611f8d565b565b61200590611fef610231565b918291634c9c8ce360e01b835260048301611d1c565b0390fd5b3461201c6120165f611eca565b916102dd565b1161202357565b61202b610231565b63b398979f60e01b815280612042600482016104d2565b0390fd5b606090565b9061205d61205883610b24565b61028e565b918252565b3d5f1461207d576120723d61204b565b903d5f602084013e5b565b612085612046565b9061207b565b5f806120b793612099612046565b508390602081019051915af4906120ae612062565b909190916120ba565b90565b906120ce906120c7612046565b5015610449565b5f146120da5750612145565b6120e382611ec6565b6120f56120ef5f611eca565b916102dd565b148061212a575b612104575090565b61212690612110610231565b918291639996b31560e01b835260048301611d1c565b0390fd5b50803b61213f6121395f611eca565b916102dd565b146120fc565b61214e81611ec6565b61216061215a5f611eca565b916102dd565b115f1461216f57805190602001fd5b612177610231565b630a12f52160e11b81528061218e600482016104d2565b0390fd5b90565b60401c90565b6121a76121ac91612195565b611726565b90565b6121b9905461219b565b90565b67ffffffffffffffff1690565b6121d56121da91611721565b6121bc565b90565b6121e790546121c9565b90565b67ffffffffffffffff1690565b61220b61220661221092611030565b6106a8565b6121ea565b90565b90565b61222a61222561222f92612213565b6106a8565b6121ea565b90565b61223b906106c7565b90565b9061225167ffffffffffffffff91611033565b9181191691161790565b61226f61226a612274926121ea565b6106a8565b6121ea565b90565b90565b9061228f61228a6122969261225b565b612277565b825461223e565b9055565b60401b90565b906122b468ff00000000000000009161229a565b9181191691161790565b906122d36122ce6122da9261194c565b611958565b82546122a0565b9055565b6122e790612216565b9052565b91906122fe905f602085019401906122de565b565b612308612525565b9061231d6123175f84016121af565b15610449565b906123295f84016121dd565b8061233c6123365f6121f7565b916121ea565b148061245d575b906123576123516001612216565b916121ea565b1480612435575b612369909115610449565b9081612424575b50612401576123999061238e6123866001612216565b5f860161227a565b826123ef575b612464565b6123a1575b50565b6123ae905f8091016122be565b60016123e67fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2916123dd610231565b918291826122eb565b0390a15f61239e565b6123fc60015f86016122be565b612394565b612409610231565b63f92ee8a960e01b815280612420600482016104d2565b0390fd5b61242f915015610449565b5f612370565b5061236961244230612232565b3b61245561244f5f611eca565b916102dd565b14905061235e565b5082612343565b6124ab906124706124c3565b612478612553565b61248a612483611054565b829061197b565b5061249d61249661163d565b829061197b565b506124a66115d9565b61197b565b50565b6124b790612300565b565b6124c16124cd565b565b6124cb6124b9565b565b6124de6124d8612507565b15610449565b6124e457565b6124ec610231565b631afcd79f60e31b815280612503600482016104d2565b0390fd5b61250f6116a5565b506125225f61251c612525565b016121af565b90565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0090565b6125516124cd565b565b61255b612549565b565b60207f7067726164657200000000000000000000000000000000000000000000000000917f4d6f7270686f48656c7065723a2043616c6c6572206973206e6f7420616e20755f8201520152565b6125b760276040926111cf565b6125c08161255d565b0190565b6125d99060208101905f8183039101526125aa565b90565b156125e357565b6125eb610231565b62461bcd60e51b815280612601600482016125c4565b0390fd5b50612631612611611e41565b61262361261c61163d565b829061174d565b908115612633575b506125dc565b565b6126459150612640611054565b61174d565b5f61262b565b61265490612605565b565b61268a90612685612665611e41565b61267761267061163d565b829061174d565b90811561268c575b506125dc565b6126eb565b565b61269e9150612699611054565b61174d565b5f61267f565b6126ad906106ab565b90565b6126b9906126a4565b90565b6126c5906126a4565b90565b90565b906126e06126db6126e7926126bc565b6126c8565b8254611f6f565b9055565b6126f76126fd916126b0565b5f6126cb565b565b61270890612656565b565b61273e90612739612719611e41565b61272b61272461163d565b829061174d565b908115612740575b506125dc565b61279f565b565b612752915061274d611054565b61174d565b5f612733565b612761906106ab565b90565b61276d90612758565b90565b61277990612758565b90565b90565b9061279461278f61279b92612770565b61277c565b8254611f6f565b9055565b6127ab6127b291612764565b600161277f565b565b6127bd9061270a565b565b906127f4916127ef6127cf611e41565b6127e16127da61163d565b829061174d565b9081156127f6575b506125dc565b61280e565b565b6128089150612803611054565b61174d565b5f6127e9565b905f1461282a57612826906128216115d9565b61197b565b505b565b61283b906128366115d9565b611a32565b50612828565b9061284b916127bf565b565b60207f70657261746f7200000000000000000000000000000000000000000000000000917f4d6f7270686f48656c7065723a2043616c6c6572206973206e6f7420616e206f5f8201520152565b6128a760276040926111cf565b6128b08161284d565b0190565b6128c99060208101905f81830391015261289a565b90565b156128d357565b6128db610231565b62461bcd60e51b8152806128f1600482016128b4565b0390fd5b9061292b9291612926612906611e41565b6129186129116115d9565b829061174d565b90811561292d575b506128cc565b612ae2565b565b61293f915061293a611054565b61174d565b5f612920565b61294e906106c7565b90565b5f91031261295b57565b61023b565b60209181520190565b90565b5090565b5061297f9060208101906102ce565b90565b61298b906102ae565b9052565b5061299e9060208101906102f4565b90565b906080612a1a612a22936129c36129ba5f830183612970565b5f860190612982565b6129dd6129d36020830183612970565b6020860190612982565b6129f76129ed6040830183612970565b6040860190612982565b612a11612a076060830183612970565b6060860190612982565b8281019061298f565b910190610777565b565b9060a0612a4f612a5793612a46612a3d5f83018361296c565b5f8601906129a1565b8281019061298f565b910190610777565b565b90612a668160c093612a24565b0190565b5090565b60c00190565b91612a8282612a8892612960565b92612969565b90815f905b828210612a9b575050505090565b90919293612abd612ab7600192612ab28886612a6a565b612a59565b95612a6e565b920190929192612a8d565b9091612adf9260208301925f818503910152612a74565b90565b612aeb90612945565b91637299aa31919092803b15612b6657612b185f8094612b23612b0c610231565b97889687958694611cd9565b845260048401612ac8565b03925af18015612b6157612b35575b50565b612b54905f3d8111612b5a575b612b4c8183610265565b810190612951565b5f612b32565b503d612b42565b611d0c565b611cd5565b90612b7692916128f5565b565b90612bae9291612ba9612b89611e41565b612b9b612b946115d9565b829061174d565b908115612bb0575b506128cc565b612c78565b565b612bc29150612bbd611054565b61174d565b5f612ba3565b60209181520190565b90565b612bdd90610399565b9052565b90612bee81602093612bd4565b0190565b50612c0190602081019061074a565b90565b60200190565b91612c1882612c1e92612bc8565b92612bd1565b90815f905b828210612c31575050505090565b90919293612c53612c4d600192612c488886612bf2565b612be1565b95612c04565b920190929192612c23565b9091612c759260208301925f818503910152612c0a565b90565b612c8190612945565b91632acc56f9919092803b15612cfc57612cae5f8094612cb9612ca2610231565b97889687958694611cd9565b845260048401612c5e565b03925af18015612cf757612ccb575b50565b612cea905f3d8111612cf0575b612ce28183610265565b810190612951565b5f612cc8565b503d612cd8565b611d0c565b611cd5565b90612d0c9291612b78565b565b90612d449291612d3f612d1f611e41565b612d31612d2a6115d9565b829061174d565b908115612d46575b506128cc565b612dbd565b565b612d589150612d53611054565b61174d565b5f612d39565b60209181520190565b5f80fd5b9037565b909182612d7b91612d5e565b9160018060fb1b038111612d9e5782916020612d9a9202938491612d6b565b0190565b612d67565b9091612dba9260208301925f818503910152612d6f565b90565b612dc690612945565b916341b67833919092803b15612e4157612df35f8094612dfe612de7610231565b97889687958694611cd9565b845260048401612da3565b03925af18015612e3c57612e10575b50565b612e2f905f3d8111612e35575b612e278183610265565b810190612951565b5f612e0d565b503d612e1d565b611d0c565b611cd5565b90612e519291612d0e565b565b5f90565b612e63612e6891611721565b6113c6565b90565b612e759054612e57565b90565b90612e9f91612e85612e53565b50612e99612e925f612e6b565b9291612945565b91612ea2565b90565b90612ed090612eca612ede94612eb6612e53565b50612ec083612ee5565b9085919091613aa2565b9261334e565b505091909190919091612f85565b90565b5f90565b60a090612ef0612ee1565b502090565b612f09612f04612f0e92612213565b6106a8565b6102dd565b90565b612f1b6001612ef5565b90565b634e487b7160e01b5f52601160045260245ffd5b612f41612f47919392936102dd565b926102dd565b8201809211612f5257565b612f1e565b90565b612f6e612f69612f7392612f57565b6106a8565b6102dd565b90565b612f82620f4240612f5a565b90565b91612fb7612fa8612fbd94612f98612e53565b5093612fa2612f11565b90612f32565b91612fb1612f76565b90612f32565b9161302b565b90565b612fcf612fd5919392936102dd565b926102dd565b91612fe18382026102dd565b928184041490151715612ff057565b612f1e565b634e487b7160e01b5f52601260045260245ffd5b61301561301b916102dd565b916102dd565b908115613026570490565b612ff5565b61304792916130429161303c612e53565b50612fc0565b613009565b90565b6fffffffffffffffffffffffffffffffff1690565b6130688161304a565b0361306f57565b5f80fd5b905051906130808261305f565b565b919060c083820312613104576130fd9061309c60c061028e565b936130a9825f8301613073565b5f8601526130ba8260208301613073565b60208601526130cc8260408301613073565b60408601526130de8260608301613073565b60608601526130f08260808301613073565b608086015260a001613073565b60a0830152565b610243565b9060c0828203126131225761311f915f01613082565b90565b61023b565b613131905161304a565b90565b61314861314361314d9261304a565b6106a8565b6102dd565b90565b61315f613165919392936102dd565b926102dd565b820391821161317057565b612f1e565b61318961318461318e92611030565b6106a8565b61304a565b90565b61319b90516102ae565b90565b6131b26131ad6131b792611030565b6106a8565b6102a3565b90565b6131c39061319e565b90565b6131cf906106ab565b90565b6131db906131c6565b90565b6131e7906106c7565b90565b905051906131f7826102e0565b565b906020828203126132125761320f915f016131ea565b90565b61023b565b9060808061326f9361322f5f8201515f860190612982565b61324160208201516020860190612982565b61325360408201516040860190612982565b61326560608201516060860190612982565b0151910190610777565b565b61327a9061304a565b9052565b9060a0806132e8936132965f8201515f860190613271565b6132a860208201516020860190613271565b6132ba60408201516040860190613271565b6132cc60608201516060860190613271565b6132de60808201516080860190613271565b0151910190613271565b565b9160a061330c9294936133056101608201965f830190613217565b019061327e565b565b61331a6133209161304a565b9161304a565b01906fffffffffffffffffffffffffffffffff821161333b57565b612f1e565b9061334a9061304a565b9052565b60c06133b19161335c612e53565b50613365612e53565b5061336e612e53565b50613377612e53565b5061338a61338485612ee5565b91611404565b6133a6635c60e39a61339a610231565b95869485938493611cd9565b8352600483016103b2565b03915afa90811561369c575f9161366e575b50906133e3426133dd6133d860808601613127565b613134565b90613150565b806133f66133f05f611eca565b916102dd565b141580613648575b8061361a575b613462575b50506134165f8201613127565b61342260208301613127565b9261345f61345961345361344d613447606061344060408a01613127565b9801613127565b95613134565b96613134565b94613134565b92613134565b90565b602061348061347b61347660608601613191565b6131d2565b6131de565b638c00bf6b93906134a386956134ae613497610231565b97889586948594611cd9565b8452600484016132ea565b03915afa918215613615576134ea926134e4915f916135e7575b50916134de6134d960408701613127565b613134565b92613732565b906136d4565b6135126134f682613884565b61350c604085019161350783613127565b61330e565b90613340565b61353961351e82613884565b6135335f85019161352e83613127565b61330e565b90613340565b61354560a08301613127565b6135576135515f613175565b9161304a565b03613563575b80613409565b6135c56135c061358a6135e19361358461357f60a08801613127565b613134565b906136d4565b6135a6816135a161359c5f8901613127565b613134565b613150565b6135ba6135b560208801613127565b613134565b916137a5565b613884565b6135db60208401916135d683613127565b61330e565b90613340565b5f61355d565b613608915060203d811161360e575b6136008183610265565b8101906131f9565b5f6134c8565b503d6135f6565b611d0c565b5061362760608301613191565b61364161363b6136365f6131ba565b6102ae565b916102ae565b1415613404565b5061365560408401613127565b6136676136615f613175565b9161304a565b14156133fe565b61368f915060c03d8111613695575b6136878183610265565b810190613109565b5f6133c3565b503d61367d565b611d0c565b90565b6136b86136b36136bd926136a1565b6106a8565b6102dd565b90565b6136d1670de0b6b3a76400006136a4565b90565b906136f1916136e1612e53565b50906136eb6136c0565b9161302b565b90565b90565b61370b613706613710926136f4565b6106a8565b6102dd565b90565b90565b61372a61372561372f92613713565b6106a8565b6102dd565b90565b6137a29161374891613742612e53565b50612fc0565b61379d613771828361376b60026137666137606136c0565b916136f7565b612fc0565b9161302b565b6137978184613791600361378c6137866136c0565b91613716565b612fc0565b9161302b565b92612f32565b612f32565b90565b906137d86137c96137de94936137b9612e53565b50936137c3612f76565b90612f32565b916137d2612f11565b90612f32565b9161302b565b90565b5f90565b5f7f6d61782075696e74313238206578636565646564000000000000000000000000910152565b6138166014611153565b90613823602083016137e5565b565b61382d61380c565b90565b613838613825565b90565b156138435750565b6138649061384f610231565b91829162461bcd60e51b83526004830161122c565b0390fd5b61387c613877613881926102dd565b6106a8565b61304a565b90565b6138cc906138906137e1565b506138c7816138b76138b16fffffffffffffffffffffffffffffffff613134565b916102dd565b11156138c1613830565b9061383b565b613868565b90565b67ffffffffffffffff81116138e75760208091020190565b610251565b909291926139016138fc826138cf565b61028e565b938185526020808601920283019281841161393e57915b8383106139255750505050565b602080916139338486611cdf565b815201920191613918565b610896565b9080601f830112156139615781602061395e935191016138ec565b90565b61088e565b90602082820312613996575f82015167ffffffffffffffff81116139915761398e9201613943565b90565b61023f565b61023b565b5190565b60200190565b6139ae90610396565b9052565b906139bf816020936139a5565b0190565b60200190565b906139e66139e06139d98461399b565b8093612bc8565b9261399f565b905f5b8181106139f65750505090565b909192613a0f613a0960019286516139b2565b946139c3565b91019190916139e9565b613a2e9160208201915f8184039101526139c9565b90565b634e487b7160e01b5f52603260045260245ffd5b90613a4f8261399b565b811015613a60576020809102010190565b613a31565b613a6f9051610396565b90565b613a86613a81613a8b926102dd565b6106a8565b6102dd565b90565b613a9a613a9f91611721565b613a72565b90565b613aca613ac4613abf613af1955f95613ab9612e53565b50613c3f565b613ba7565b91611404565b613ae6637784c685613ada610231565b95869485938493611cd9565b835260048301613a19565b03915afa8015613b4c57613b1d613b2291613b27935f91613b2a575b50613b175f611eca565b90613a45565b613a65565b613a8e565b90565b613b4691503d805f833e613b3e8183610265565b810190613966565b5f613b0d565b611d0c565b606090565b90613b68613b63836138cf565b61028e565b918252565b369037565b90613b97613b7f83613b56565b92602080613b8d86936138cf565b9201910390613b6d565b565b90613ba390610396565b9052565b613baf613b51565b50613bde613bc5613bc06001612ef5565b613b72565b91613bd983613bd35f611eca565b90613a45565b613b99565b90565b613beb60026136f7565b90565b916020613c0f929493613c0860408201965f8301906103a5565b01906112a6565b565b60200190565b613c205f611eca565b90565b613c37613c32613c3c926102dd565b611033565b610396565b90565b613cdb613ce991613cc3613cee94613c556117a3565b5091613c89613c62613be1565b91613c7a613c6e610231565b93849260208401613bee565b60208201810382520382610265565b613c9b613c9582611ec6565b91613c11565b2091613cb4613ca8610231565b9384926020840161184c565b60208201810382520382610265565b613cd5613ccf82611ec6565b91613c11565b20613a8e565b613ce3613c17565b90612f32565b613c23565b90565b90613d28939291613d23613d03611e41565b613d15613d0e6115d9565b829061174d565b908115613d2a575b506128cc565b614004565b565b613d3c9150613d37611054565b61174d565b5f613d1d565b67ffffffffffffffff8111613d5a5760208091020190565b610251565b90613d71613d6c83613d42565b61028e565b918252565b613d80604061028e565b90565b613d8d60a061028e565b90565b5f90565b5f90565b613da0613d83565b9060208080808086613db0613d90565b815201613dbb613d90565b815201613dc6613d90565b815201613dd1613d90565b815201613ddc613d94565b81525050565b613dea613d98565b90565b613df5613d76565b9060208083613e02613de2565b815201613e0d613d94565b81525050565b613e1b613ded565b90565b5f5b828110613e2c57505050565b602090613e37613e13565b8184015201613e20565b90613e66613e4e83613d5f565b92602080613e5c8693613d42565b9201910390613e1e565b565b613e7c613e77613e8192611030565b6106a8565b610d8b565b90565b613e98613e93613e9d92610d8b565b6106a8565b6102dd565b90565b613ea990610d8b565b600160ff1b8114613eb9575f0390565b612f1e565b613ec8604061028e565b90565b52565b90613ed8906102dd565b9052565b5190565b90613eea82613edc565b811015613efb576020809102010190565b613a31565b60200190565b90608080613f5e93613f1e5f8201515f860190612982565b613f3060208201516020860190612982565b613f4260408201516040860190612982565b613f5460608201516060860190612982565b0151910190610777565b565b9060a06020613f8393613f795f8201515f860190613f06565b0151910190610777565b565b90613f928160c093613f60565b0190565b60200190565b90613fb9613fb3613fac84613edc565b8093612960565b92613f00565b905f5b818110613fc95750505090565b909192613fe2613fdc6001928651613f85565b94613f96565b9101919091613fbc565b6140019160208201915f818403910152613f9c565b90565b90614106926140b56140ff9261402261401d60026136f7565b613e41565b9661402e868390612e78565b614036612e53565b508161404a6140445f613e68565b91610d8b565b125f14614185576140909161406a6140656140709392613ea0565b613e84565b90612f32565b915b9161408761407e613ebe565b935f8501613ecb565b60208301613ece565b6140af87915f906140a96140a383611eca565b85613ee0565b52611eca565b90613ee0565b51506140d95f196140d06140c7613ebe565b935f8501613ecb565b60208301613ece565b6140f985916001906140f36140ed83612ef5565b85613ee0565b52612ef5565b90613ee0565b5150612945565b90637299aa3190823b156141805761413d926141325f8094614126610231565b96879586948593611cd9565b835260048301613fec565b03925af1801561417b5761414f575b50565b61416e905f3d8111614174575b6141668183610265565b810190612951565b5f61414c565b503d61415c565b611d0c565b611cd5565b61418e82613e84565b6141a061419a836102dd565b916102dd565b11155f146141c657614090916141b96141bf9291613e84565b90613150565b5b91614072565b50506140906141d45f611eca565b6141c0565b906141e5939291613cf1565b565b9061421e9392916142196141f9611e41565b61420b6142046115d9565b829061174d565b908115614220575b506128cc565b6142da565b565b614232915061422d611054565b61174d565b5f614213565b90505190614245826102ba565b565b919060a0838203126142b7576142b09061426160a061028e565b9361426e825f8301614238565b5f86015261427f8260208301614238565b60208601526142918260408301614238565b60408601526142a38260608301614238565b60608601526080016131ea565b6080830152565b610243565b9060a0828203126142d5576142d2915f01614247565b90565b61023b565b9160a061431a94926142f36142ee5f612e6b565b611404565b61430f632c3c9157614303610231565b98899485938493611cd9565b8352600483016103b2565b03915afa9081156143f25761436c945f926143c0575b5060a0906143456143405f612e6b565b611404565b614361632c3c9157614355610231565b98899485938493611cd9565b8352600483016103b2565b03915afa9182156143bb57614389945f9361438b575b50926141d9565b565b6143ad91935060a03d81116143b4575b6143a58183610265565b8101906142bc565b915f614382565b503d61439b565b611d0c565b60a09192506143e490823d81116143eb575b6143dc8183610265565b8101906142bc565b9190614330565b503d6143d2565b611d0c565b906144039392916141e7565b565b9061443c939291614437614417611e41565b6144296144226115d9565b829061174d565b90811561443e575b506128cc565b614527565b565b614450915061444b611054565b61174d565b5f614431565b67ffffffffffffffff811161446e5760208091020190565b610251565b919060c0838203126144ad576144a69061448d604061028e565b9361449a825f8301610303565b5f86015260a001610da2565b6020830152565b610243565b909291926144c76144c282614456565b61028e565b9381855260c060208601920283019281841161450657915b8383106144ec5750505050565b602060c0916144fb8486614473565b8152019201916144df565b610896565b6145169136916144b2565b90565b614524903690610303565b90565b61453a614546946145409294909361450b565b91614519565b916148ca565b565b90614554939291614405565b565b9061458d939291614588614568611e41565b61457a6145736115d9565b829061174d565b90811561458f575b506128cc565b6146d8565b565b6145a1915061459c611054565b61174d565b5f614582565b5090565b906145bd6145b883614456565b61028e565b918252565b6145cc604061028e565b90565b5f90565b6145db6145c2565b90602080836145e8613de2565b8152016145f36145cf565b81525050565b6146016145d3565b90565b5f5b82811061461257505050565b60209061461d6145f9565b8184015201614606565b9061464c614634836145ab565b926020806146428693614456565b9201910390614604565b565b614657906102dd565b5f1981146146655760010190565b612f1e565b919081101561467a576040020190565b613a31565b3561468981610736565b90565b3561469681610d8e565b90565b6146a3604061028e565b90565b906146b090610d8b565b9052565b5190565b906146c2826146b4565b8110156146d3576020809102010190565b613a31565b9290936146ee6146e98685906145a7565b614627565b916146f85f611eca565b5b8061471661471061470b8a89906145a7565b6102dd565b916102dd565b1015614816576147729060a08861473461472f5f612e6b565b611404565b6147676147525f61474c632c3c9157958d899161466a565b0161467f565b9261475b610231565b96879485938493611cd9565b8352600483016103b2565b03915afa918215614811576147de926147d7915f916147e3575b506147c46147a760206147a18d8c889161466a565b0161468c565b6147bb6147b2614699565b935f8501613ecb565b602083016146a6565b8683916147d183836146b8565b526146b8565b515061464e565b6146f9565b614804915060a03d811161480a575b6147fc8183610265565b8101906142bc565b5f61478c565b503d6147f2565b611d0c565b50919250935060a061485c9392916148356148305f612e6b565b611404565b614851632c3c9157614845610231565b97889485938493611cd9565b8352600483016103b2565b03915afa9182156148aa57614878935f9361487a575b506148ca565b565b61489c91935060a03d81116148a3575b6148948183610265565b8101906142bc565b915f614872565b503d61488a565b611d0c565b906148bb939291614556565b565b6148c79051610d8b565b90565b9290926148f16148ec6148dc866146b4565b6148e66001612ef5565b90612f32565b613e41565b916148fb5f611eca565b5b8061491761491161490c896146b4565b6102dd565b916102dd565b1015614a76576149f49061493a845f6149318a85906146b8565b51015190612e78565b614942612e53565b508761495b60206149548386906146b8565b51016148bd565b61496d6149675f613e68565b91610d8b565b125f146149f9576149a9906149a361499e61499960206149926149ed979589906146b8565b51016148bd565b613ea0565b613e84565b90612f32565b5b6149da5f6149b98b86906146b8565b510151916149d16149c8613ebe565b935f8501613ecb565b60208301613ece565b8683916149e78383613ee0565b52613ee0565b515061464e565b6148fc565b614a136020614a0c614a189386906146b8565b51016148bd565b613e84565b614a2a614a24836102dd565b916102dd565b11155f14614a6457614a5e6149ed91614a58614a536020614a4c8d88906146b8565b51016148bd565b613e84565b90613150565b5b6149aa565b506149ed614a715f611eca565b614a5f565b5093614abf90614ac6939490614aa45f19614a9b614a92613ebe565b945f8601613ecb565b60208401613ece565b614aae86916146b4565b91614ab98383613ee0565b52613ee0565b5150612945565b90637299aa3190823b15614b4057614afd92614af25f8094614ae6610231565b96879586948593611cd9565b835260048301613fec565b03925af18015614b3b57614b0f575b50565b614b2e905f3d8111614b34575b614b268183610265565b810190612951565b5f614b0c565b503d614b1c565b611d0c565b611cd5565b90614b7b9291614b76614b56611e41565b614b68614b616115d9565b829061174d565b908115614b7d575b506128cc565b614ce8565b565b614b8f9150614b8a611054565b61174d565b5f614b70565b614ba1614ba691611721565b610668565b90565b614bb39054614b95565b90565b60209181520190565b90565b5090565b90503590614bd38261305f565b565b50614be4906020810190614bc6565b90565b906020614c12614c1a93614c09614c005f830183614bd5565b5f860190613271565b82810190614bd5565b910190613271565b565b906020614c47614c4f93614c3e614c355f830183612bf2565b5f860190612bd4565b82810190614bc2565b910190614be7565b565b90614c5e81606093614c1c565b0190565b5090565b60600190565b91614c7a82614c8092614bb6565b92614bbf565b90815f905b828210614c93575050505090565b90919293614cb5614caf600192614caa8886614c62565b614c51565b95614c66565b920190929192614c85565b91614ce5939192614cd860408201945f83019061183f565b6020818503910152614c6c565b90565b90614cfb614cf66001614ba9565b6106d3565b614d0963f461804693612945565b919392813b15614d7f575f614d3191614d3c8296614d25610231565b98899788968795611cd9565b855260048501614cc0565b03925af18015614d7a57614d4e575b50565b614d6d905f3d8111614d73575b614d658183610265565b810190612951565b5f614d4b565b503d614d5b565b611d0c565b611cd5565b90614d8f9291614b45565b565b90614dc691614dc1614da1611e41565b614db3614dac6115d9565b829061174d565b908115614dc8575b506128cc565b614e03565b565b614dda9150614dd5611054565b61174d565b5f614dbb565b916020614e01929493614dfa60408201965f83019061183f565b01906112a6565b565b614e15614e106001614ba9565b6106d3565b9163e55156b5919092803b15614e9057614e425f8094614e4d614e36610231565b97889687958694611cd9565b845260048401614de0565b03925af18015614e8b57614e5f575b50565b614e7e905f3d8111614e84575b614e768183610265565b810190612951565b5f614e5c565b503d614e6c565b611d0c565b611cd5565b90614e9f91614d91565b565b90614ed691614ed1614eb1611e41565b614ec3614ebc6115d9565b829061174d565b908115614ed8575b506128cc565b614f20565b565b614eea9150614ee5611054565b61174d565b5f614ecb565b614ef9906110a0565b9052565b916020614f1e929493614f1760408201965f83019061183f565b0190614ef0565b565b614f32614f2d6001614ba9565b6106d3565b91630e4eecf8919092803b15614fad57614f5f5f8094614f6a614f53610231565b97889687958694611cd9565b845260048401614efd565b03925af18015614fa857614f7c575b50565b614f9b905f3d8111614fa1575b614f938183610265565b810190612951565b5f614f79565b503d614f89565b611d0c565b611cd5565b90614fbc91614ea1565b565b90614ff391614fee614fce611e41565b614fe0614fd961163d565b829061174d565b908115614ff5575b506125dc565b615030565b565b6150079150615002611054565b61174d565b5f614fe8565b91602061502e92949361502760408201965f83019061183f565b019061183f565b565b61504261503d6001614ba9565b6106d3565b9163c55b6bb7919092803b156150bd5761506f5f809461507a615063610231565b97889687958694611cd9565b84526004840161500d565b03925af180156150b85761508c575b50565b6150ab905f3d81116150b1575b6150a38183610265565b810190612951565b5f615089565b503d615099565b611d0c565b611cd5565b906150cc91614fbe565b565b6150e0906150da612ee1565b50612ee5565b90565b6150ee61010061028e565b90565b6150f96150e3565b906020808080808080808961510c613d94565b815201615117613d94565b815201615122613d94565b81520161512d613d94565b815201615138613d94565b815201615143613d94565b81520161514e613d94565b815201615159613d94565b81525050565b6151676150f1565b90565b90565b61518161517c6151869261516a565b6106a8565b6102dd565b90565b61519390516102dd565b90565b6151aa6151a56151af926136a1565b6106a8565b61304a565b90565b6151be6151c49161304a565b9161304a565b9003906fffffffffffffffffffffffffffffffff82116151e057565b612f1e565b906151ee61515f565b9161522f60c06152056152005f612e6b565b611404565b635c60e39a906152248592615218610231565b95869485938493611cd9565b8352600483016103b2565b03915afa908115615536575f91615508575b509061528360a06152596152545f612e6b565b611404565b632c3c915790615278859261526c610231565b95869485938493611cd9565b8352600483016103b2565b03915afa90811561550357615301916152f8915f916154d5575b50926152ea6152e46152b86152b15f612e6b565b879061334e565b9093916152de8d5f8101966152d860208301956060604085019401613ece565b90613ece565b90613ece565b90613ece565b6152f35f612e6b565b6155e4565b60808601613ece565b61531661530d5f611eca565b60e08601613ece565b61532260608201613191565b61533c6153366153315f6131ba565b6102ae565b916102ae565b0361540d575b506153da6153c86153e3926153585f8701615189565b61536a6153645f611eca565b916102dd565b145f146153e55761538761537d5f611eca565b5b60a08801613ece565b6153c26153bd61539960e08901615189565b926153b86153b260a0670de0b6b3a76400009301613127565b91615196565b6151b2565b613134565b906136d4565b6153d460a08601615189565b906136d4565b60c08401613ece565b565b6153876154086153f760408901615189565b6154025f8a01615189565b9061553b565b61537e565b602061542b61542661542160608501613191565b6131d2565b6131de565b638c00bf6b929061544e8594615459615442610231565b96879586948594611cd9565b8452600484016132ea565b03915afa9081156154d0576153e39261549a6154916153da946153c8945f916154a2575b5061548b6301e1338061516d565b90613732565b60e08801613ece565b925050615342565b6154c3915060203d81116154c9575b6154bb8183610265565b8101906131f9565b5f61547d565b503d6154b1565b611d0c565b6154f6915060a03d81116154fc575b6154ee8183610265565b8101906142bc565b5f61529d565b503d6154e4565b611d0c565b615529915060c03d811161552f575b6155218183610265565b810190613109565b5f615241565b503d615517565b611d0c565b9061555991615548612e53565b50906155526136c0565b909161555c565b90565b615576615595939261559092615570612e53565b50612fc0565b61558a836155846001612ef5565b90613150565b90612f32565b613009565b90565b90565b60ff1690565b6155b56155b06155ba92615598565b6106a8565b61559b565b90565b6155dc906155d66155d06155e19461559b565b91610396565b90610664565b610396565b90565b5f9061560c615606615601615633956155fb612e53565b506156c1565b613ba7565b91611404565b615628637784c68561561c610231565b95869485938493611cd9565b835260048301613a19565b03915afa9081156156a25761566861566361567d93615678935f91615680575b5061565d5f611eca565b90613a45565b613a65565b61567260806155a1565b906155bd565b613a8e565b90565b61569c91503d805f833e6156948183610265565b810190613966565b5f615653565b611d0c565b6156b16003613716565b90565b6156be60026136f7565b90565b61572c61571e615731926156d36117a3565b506157066156df6156a7565b916156f76156eb610231565b93849260208401613bee565b60208201810382520382610265565b61571861571282611ec6565b91613c11565b20613a8e565b6157266156b4565b90612f32565b613c23565b90565b61573f61010061028e565b90565b61574a615734565b906020808080808080808961575d613d94565b815201615768613d94565b815201615773613d94565b81520161577e613d94565b815201615789613d94565b815201615794613d94565b81520161579f613d94565b8152016157aa613d94565b81525050565b6157b8615742565b90565b919060608382031261580757615800906157d5606061028e565b936157e2825f83016131ea565b5f8601526157f38260208301613073565b6020860152604001613073565b6040830152565b610243565b9060608282031261582557615822915f016157bb565b90565b61023b565b91602061584b92949361584460408201965f8301906103a5565b019061183f565b565b615856906106ab565b90565b6158629061584d565b90565b61586e906106c7565b90565b90565b61588861588361588d92615871565b6106a8565b6102dd565b90565b6158a86ec097ce7bc90715b34b9f1000000000615874565b90565b91906158b56157b0565b926158f660a06158cc6158c75f612e6b565b611404565b632c3c9157906158eb85926158df610231565b95869485938493611cd9565b8352600483016103b2565b03915afa908115615c52575f91615c24575b5090606061591d6159185f612e6b565b611404565b6393c520629290615940869461594b615934610231565b96879586948594611cd9565b84526004840161582a565b03915afa908115615c1f575f91615bf1575b5061596a60408301613191565b61598461597e6159795f6131ba565b6102ae565b916102ae565b145f14615b41576080615ab6615ac394615a61615a595f615abd96615a538c6020615a4c8c6159b287611eca565b5b996159d36159cb6159c660408a01613127565b613134565b8e8701613ece565b6159fc6159f36159e48f8801615189565b8d6159ed615890565b9161302b565b60a08701613ece565b615a1c615a13615a0b8a612e6b565b848491615c78565b60608701613ece565b615a3b615a32615a2d868a01613127565b613134565b60408701613ece565b615a4488612e6b565b919091612ea2565b9101613ece565b01615189565b5f8a01613ece565b615a6d60a08901615189565b615a7f615a795f611eca565b916102dd565b145f14615b1857615a9c615a925f611eca565b5b60c08a01613ece565b615aa7838901615189565b90615ab0615890565b9161302b565b9201615189565b906136d4565b615acf60608401615189565b615ae1615adb5f611eca565b916102dd565b145f14615afa5750615af85f195b60e08401613ece565b565b615b13615af891615b0d60608601615189565b90615c57565b615aef565b615a9c615b3c615b2a60608b01615189565b615b3660a08c01615189565b9061553b565b615a93565b615b786020615b62615b5d615b5860408701613191565b615859565b615865565b63a035b1fe90615b70610231565b938492611cd9565b82528180615b88600482016104d2565b03915afa8015615bec57615ac394615a61615a595f615abd96615a538c6020615a4c8c615ab69a60809c8891615bbf575b506159b3565b615bdf9150843d8111615be5575b615bd78183610265565b8101906131f9565b5f615bb9565b503d615bcd565b611d0c565b615c12915060603d8111615c18575b615c0a8183610265565b81019061580c565b5f61595d565b503d615c00565b611d0c565b615c45915060a03d8111615c4b575b615c3d8183610265565b8101906142bc565b5f615908565b503d615c33565b611d0c565b90615c7591615c64612e53565b5090615c6e6136c0565b909161302b565b90565b90615ca690615ca0615cb594615c8c612e53565b50615c9683612ee5565b9085919091615cf3565b9261334e565b93925090509190919091615cb8565b90565b91615cea615cdb615cf094615ccb612e53565b5093615cd5612f11565b90612f32565b91615ce4612f76565b90612f32565b9161555c565b90565b615d1b615d15615d10615d42955f95615d0a612e53565b50615dbf565b613ba7565b91611404565b615d37637784c685615d2b610231565b95869485938493611cd9565b835260048301613a19565b03915afa8015615dad57615d7e615d79615d74615d8393615d88955f91615d8b575b50615d6e5f611eca565b90613a45565b613a65565b613a8e565b613868565b613134565b90565b615da791503d805f833e615d9f8183610265565b810190613966565b5f615d64565b611d0c565b615dbc6001612ef5565b90565b615e5b615e6991615e43615e6e94615dd56117a3565b5091615e09615de2613be1565b91615dfa615dee610231565b93849260208401613bee565b60208201810382520382610265565b615e1b615e1582611ec6565b91613c11565b2091615e34615e28610231565b9384926020840161184c565b60208201810382520382610265565b615e55615e4f82611ec6565b91613c11565b20613a8e565b615e63615db2565b90612f32565b613c23565b9056fea2646970667358221220a22232bfdc3a9e0decdaa178b9a6155dd02be7b15e95d1b327ebda4fda5a702e64736f6c63430008150033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.