Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
MorphoGenericAprOracle
Compiler Version
v0.8.23+commit.f704f362
Contract Source Code (Solidity)
/** *Submitted for verification at KatanaScan.com on 2025-07-25 */ // SPDX-License-Identifier: AGPL-3.0 pragma solidity >=0.4.0 >=0.5.0 >=0.8.18 ^0.8.0 ^0.8.18; // lib/v3-core/contracts/libraries/BitMath.sol /// @title BitMath /// @dev This library provides functionality for computing bit properties of an unsigned integer library BitMath { /// @notice Returns the index of the most significant bit of the number, /// where the least significant bit is at index 0 and the most significant bit is at index 255 /// @dev The function satisfies the property: /// x >= 2**mostSignificantBit(x) and x < 2**(mostSignificantBit(x)+1) /// @param x the value for which to compute the most significant bit, must be greater than 0 /// @return r the index of the most significant bit function mostSignificantBit(uint256 x) internal pure returns (uint8 r) { require(x > 0); unchecked { if (x >= 0x100000000000000000000000000000000) { x >>= 128; r += 128; } if (x >= 0x10000000000000000) { x >>= 64; r += 64; } if (x >= 0x100000000) { x >>= 32; r += 32; } if (x >= 0x10000) { x >>= 16; r += 16; } if (x >= 0x100) { x >>= 8; r += 8; } if (x >= 0x10) { x >>= 4; r += 4; } if (x >= 0x4) { x >>= 2; r += 2; } if (x >= 0x2) r += 1; } } /// @notice Returns the index of the least significant bit of the number, /// where the least significant bit is at index 0 and the most significant bit is at index 255 /// @dev The function satisfies the property: /// (x & 2**leastSignificantBit(x)) != 0 and (x & (2**(leastSignificantBit(x)) - 1)) == 0) /// @param x the value for which to compute the least significant bit, must be greater than 0 /// @return r the index of the least significant bit function leastSignificantBit(uint256 x) internal pure returns (uint8 r) { require(x > 0); unchecked { r = 255; if (x & type(uint128).max > 0) { r -= 128; } else { x >>= 128; } if (x & type(uint64).max > 0) { r -= 64; } else { x >>= 64; } if (x & type(uint32).max > 0) { r -= 32; } else { x >>= 32; } if (x & type(uint16).max > 0) { r -= 16; } else { x >>= 16; } if (x & type(uint8).max > 0) { r -= 8; } else { x >>= 8; } if (x & 0xf > 0) { r -= 4; } else { x >>= 4; } if (x & 0x3 > 0) { r -= 2; } else { x >>= 2; } if (x & 0x1 > 0) r -= 1; } } } // lib/openzeppelin-contracts/contracts/utils/Context.sol // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.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 Context { 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; } } // src/interfaces/Morpho/libraries/ErrorsLib.sol /// @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"; } // lib/v3-core/contracts/libraries/FixedPoint96.sol /// @title FixedPoint96 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) /// @dev Used in SqrtPriceMath.sol library FixedPoint96 { uint8 internal constant RESOLUTION = 96; uint256 internal constant Q96 = 0x1000000000000000000000000; } // lib/v3-core/contracts/libraries/FullMath.sol /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = (0 - denominator) & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } } } // lib/tokenized-strategy-periphery/src/utils/Governance.sol contract Governance { /// @notice Emitted when the governance address is updated. event GovernanceTransferred( address indexed previousGovernance, address indexed newGovernance ); modifier onlyGovernance() { _checkGovernance(); _; } /// @notice Checks if the msg sender is the governance. function _checkGovernance() internal view virtual { require(governance == msg.sender, "!governance"); } /// @notice Address that can set the default base fee and provider address public governance; constructor(address _governance) { governance = _governance; emit GovernanceTransferred(address(0), _governance); } /** * @notice Sets a new address as the governance of the contract. * @dev Throws if the caller is not current governance. * @param _newGovernance The new governance address. */ function transferGovernance( address _newGovernance ) external virtual onlyGovernance { require(_newGovernance != address(0), "ZERO ADDRESS"); address oldGovernance = governance; governance = _newGovernance; emit GovernanceTransferred(oldGovernance, _newGovernance); } } // lib/tokenized-strategy/src/interfaces/IBaseStrategy.sol interface IBaseStrategy { function tokenizedStrategyAddress() external view returns (address); /*////////////////////////////////////////////////////////////// IMMUTABLE FUNCTIONS //////////////////////////////////////////////////////////////*/ function availableDepositLimit( address _owner ) external view returns (uint256); function availableWithdrawLimit( address _owner ) external view returns (uint256); function deployFunds(uint256 _assets) external; function freeFunds(uint256 _amount) external; function harvestAndReport() external returns (uint256); function tendThis(uint256 _totalIdle) external; function shutdownWithdraw(uint256 _amount) external; function tendTrigger() external view returns (bool, bytes memory); } // lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) /** * @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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` 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 amount) external returns (bool); } // lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) /** * @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); } // src/interfaces/Morpho/IMorpho.sol type Id is bytes32; struct MarketParams { address loanToken; address collateralToken; address oracle; address irm; uint256 lltv; } /// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest /// accrual. struct Position { uint256 supplyShares; uint128 borrowShares; uint128 collateral; } /// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last /// interest accrual. struct Market { uint128 totalSupplyAssets; uint128 totalSupplyShares; uint128 totalBorrowAssets; uint128 totalBorrowShares; uint128 lastUpdate; uint128 fee; } struct Authorization { address authorizer; address authorized; bool isAuthorized; uint256 nonce; uint256 deadline; } struct Signature { uint8 v; bytes32 r; bytes32 s; } /// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho. /// @dev Consider using the IMorpho interface instead of this one. interface IMorphoBase { /// @notice The EIP-712 domain separator. /// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing /// the same chain id because the domain separator would be the same. function DOMAIN_SEPARATOR() external view returns (bytes32); /// @notice The owner of the contract. /// @dev It has the power to change the owner. /// @dev It has the power to set fees on markets and set the fee recipient. /// @dev It has the power to enable but not disable IRMs and LLTVs. function owner() external view returns (address); /// @notice The fee recipient of all markets. /// @dev The recipient receives the fees of a given market through a supply position on that market. function feeRecipient() external view returns (address); /// @notice Whether the `irm` is enabled. function isIrmEnabled(address irm) external view returns (bool); /// @notice Whether the `lltv` is enabled. function isLltvEnabled(uint256 lltv) external view returns (bool); /// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets. /// @dev Anyone is authorized to modify their own positions, regardless of this variable. function isAuthorized( address authorizer, address authorized ) external view returns (bool); /// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures. function nonce(address authorizer) external view returns (uint256); /// @notice Sets `newOwner` as `owner` of the contract. /// @dev Warning: No two-step transfer ownership. /// @dev Warning: The owner can be set to the zero address. function setOwner(address newOwner) external; /// @notice Enables `irm` as a possible IRM for market creation. /// @dev Warning: It is not possible to disable an IRM. function enableIrm(address irm) external; /// @notice Enables `lltv` as a possible LLTV for market creation. /// @dev Warning: It is not possible to disable a LLTV. function enableLltv(uint256 lltv) external; /// @notice Sets the `newFee` for the given market `marketParams`. /// @param newFee The new fee, scaled by WAD. /// @dev Warning: The recipient can be the zero address. function setFee(MarketParams memory marketParams, uint256 newFee) external; /// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee. /// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost. /// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To /// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes. function setFeeRecipient(address newFeeRecipient) external; /// @notice Creates the market `marketParams`. /// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees /// Morpho behaves as expected: /// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`. /// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with /// burn functions are not supported. /// - The token should not re-enter Morpho on `transfer` nor `transferFrom`. /// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount /// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported. /// - The IRM should not re-enter Morpho. /// - The oracle should return a price with the correct scaling. /// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties /// (funds could get stuck): /// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue. /// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and /// `toSharesDown` overflow. /// - The IRM can revert on `borrowRate`. /// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest` /// overflow. /// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and /// `liquidate` from being used under certain market conditions. /// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or /// the computation of `assetsRepaid` in `liquidate` overflow. /// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to /// the point where `totalBorrowShares` is very large and borrowing overflows. function createMarket(MarketParams memory marketParams) external; /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's /// `onMorphoSupply` function with the given `data`. /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the /// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific /// amount of shares is given for full compatibility and precision. /// @dev Supplying a large amount can revert for overflow. /// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage. /// Consider using the `assets` parameter to avoid this. /// @param marketParams The market to supply assets to. /// @param assets The amount of assets to supply. /// @param shares The amount of shares to mint. /// @param onBehalf The address that will own the increased supply position. /// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed. /// @return assetsSupplied The amount of assets supplied. /// @return sharesSupplied The amount of shares minted. function supply( MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, bytes memory data ) external returns (uint256 assetsSupplied, uint256 sharesSupplied); /// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`. /// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`. /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions. /// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow. /// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to /// conversion roundings between shares and assets. /// @param marketParams The market to withdraw assets from. /// @param assets The amount of assets to withdraw. /// @param shares The amount of shares to burn. /// @param onBehalf The address of the owner of the supply position. /// @param receiver The address that will receive the withdrawn assets. /// @return assetsWithdrawn The amount of assets withdrawn. /// @return sharesWithdrawn The amount of shares burned. function withdraw( MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver ) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn); /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`. /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the /// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is /// given for full compatibility and precision. /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions. /// @dev Borrowing a large amount can revert for overflow. /// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage. /// Consider using the `assets` parameter to avoid this. /// @param marketParams The market to borrow assets from. /// @param assets The amount of assets to borrow. /// @param shares The amount of shares to mint. /// @param onBehalf The address that will own the increased borrow position. /// @param receiver The address that will receive the borrowed assets. /// @return assetsBorrowed The amount of assets borrowed. /// @return sharesBorrowed The amount of shares minted. function borrow( MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, address receiver ) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed); /// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's /// `onMorphoRepay` function with the given `data`. /// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`. /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow. /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion /// roundings between shares and assets. /// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow. /// @param marketParams The market to repay assets to. /// @param assets The amount of assets to repay. /// @param shares The amount of shares to burn. /// @param onBehalf The address of the owner of the debt position. /// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed. /// @return assetsRepaid The amount of assets repaid. /// @return sharesRepaid The amount of shares burned. function repay( MarketParams memory marketParams, uint256 assets, uint256 shares, address onBehalf, bytes memory data ) external returns (uint256 assetsRepaid, uint256 sharesRepaid); /// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's /// `onMorphoSupplyCollateral` function with the given `data`. /// @dev Interest are not accrued since it's not required and it saves gas. /// @dev Supplying a large amount can revert for overflow. /// @param marketParams The market to supply collateral to. /// @param assets The amount of collateral to supply. /// @param onBehalf The address that will own the increased collateral position. /// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed. function supplyCollateral( MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data ) external; /// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`. /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions. /// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow. /// @param marketParams The market to withdraw collateral from. /// @param assets The amount of collateral to withdraw. /// @param onBehalf The address of the owner of the collateral position. /// @param receiver The address that will receive the collateral assets. function withdrawCollateral( MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver ) external; /// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the /// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's /// `onMorphoLiquidate` function with the given `data`. /// @dev Either `seizedAssets` or `repaidShares` should be zero. /// @dev Seizing more than the collateral balance will underflow and revert without any error message. /// @dev Repaying more than the borrow balance will underflow and revert without any error message. /// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow. /// @param marketParams The market of the position. /// @param borrower The owner of the position. /// @param seizedAssets The amount of collateral to seize. /// @param repaidShares The amount of shares to repay. /// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed. /// @return The amount of assets seized. /// @return The amount of assets repaid. function liquidate( MarketParams memory marketParams, address borrower, uint256 seizedAssets, uint256 repaidShares, bytes memory data ) external returns (uint256, uint256); /// @notice Executes a flash loan. /// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all /// markets combined, plus donations). /// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached: /// - `flashFee` is zero. /// - `maxFlashLoan` is the token's balance of this contract. /// - The receiver of `assets` is the caller. /// @param token The token to flash loan. /// @param assets The amount of assets to flash loan. /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback. function flashLoan( address token, uint256 assets, bytes calldata data ) external; /// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions. /// @param authorized The authorized address. /// @param newIsAuthorized The new authorization status. function setAuthorization( address authorized, bool newIsAuthorized ) external; /// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions. /// @dev Warning: Reverts if the signature has already been submitted. /// @dev The signature is malleable, but it has no impact on the security here. /// @dev The nonce is passed as argument to be able to revert with a different error message. /// @param authorization The `Authorization` struct. /// @param signature The signature. function setAuthorizationWithSig( Authorization calldata authorization, Signature calldata signature ) external; /// @notice Accrues interest for the given market `marketParams`. function accrueInterest(MarketParams memory marketParams) external; /// @notice Returns the data stored on the different `slots`. function extSloads( bytes32[] memory slots ) external view returns (bytes32[] memory); } /// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler. /// @dev Consider using the IMorpho interface instead of this one. interface IMorphoStaticTyping is IMorphoBase { /// @notice The state of the position of `user` on the market corresponding to `id`. /// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest /// accrual. function position( Id id, address user ) external view returns ( uint256 supplyShares, uint128 borrowShares, uint128 collateral ); /// @notice The state of the market corresponding to `id`. /// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest /// accrual. function market( Id id ) external view returns ( uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee ); /// @notice The market params corresponding to `id`. /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`. function idToMarketParams( Id id ) external view returns ( address loanToken, address collateralToken, address oracle, address irm, uint256 lltv ); } /// @title IMorpho /// @author Morpho Labs /// @custom:contact [email protected] /// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures. interface IMorpho is IMorphoBase { /// @notice The state of the position of `user` on the market corresponding to `id`. /// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest /// accrual. function position( Id id, address user ) external view returns (Position memory p); /// @notice The state of the market corresponding to `id`. /// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual. /// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last /// interest accrual. function market(Id id) external view returns (Market memory m); /// @notice The market params corresponding to `id`. /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`. function idToMarketParams( Id id ) external view returns (MarketParams memory); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol /// @title Permissionless pool actions /// @notice Contains pool methods that can be called by anyone interface IUniswapV3PoolActions { /// @notice Sets the initial price for the pool /// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value /// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96 function initialize(uint160 sqrtPriceX96) external; /// @notice Adds liquidity for the given recipient/tickLower/tickUpper position /// @dev The caller of this method receives a callback in the form of IUniswapV3MintCallback#uniswapV3MintCallback /// in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends /// on tickLower, tickUpper, the amount of liquidity, and the current price. /// @param recipient The address for which the liquidity will be created /// @param tickLower The lower tick of the position in which to add liquidity /// @param tickUpper The upper tick of the position in which to add liquidity /// @param amount The amount of liquidity to mint /// @param data Any data that should be passed through to the callback /// @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback /// @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback function mint( address recipient, int24 tickLower, int24 tickUpper, uint128 amount, bytes calldata data ) external returns (uint256 amount0, uint256 amount1); /// @notice Collects tokens owed to a position /// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity. /// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or /// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the /// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity. /// @param recipient The address which should receive the fees collected /// @param tickLower The lower tick of the position for which to collect fees /// @param tickUpper The upper tick of the position for which to collect fees /// @param amount0Requested How much token0 should be withdrawn from the fees owed /// @param amount1Requested How much token1 should be withdrawn from the fees owed /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect( address recipient, int24 tickLower, int24 tickUpper, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); /// @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position /// @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0 /// @dev Fees must be collected separately via a call to #collect /// @param tickLower The lower tick of the position for which to burn liquidity /// @param tickUpper The upper tick of the position for which to burn liquidity /// @param amount How much liquidity to burn /// @return amount0 The amount of token0 sent to the recipient /// @return amount1 The amount of token1 sent to the recipient function burn( int24 tickLower, int24 tickUpper, uint128 amount ) external returns (uint256 amount0, uint256 amount1); /// @notice Swap token0 for token1, or token1 for token0 /// @dev The caller of this method receives a callback in the form of IUniswapV3SwapCallback#uniswapV3SwapCallback /// @param recipient The address to receive the output of the swap /// @param zeroForOne The direction of the swap, true for token0 to token1, false for token1 to token0 /// @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative) /// @param sqrtPriceLimitX96 The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this /// value after the swap. If one for zero, the price cannot be greater than this value after the swap /// @param data Any data to be passed through to the callback /// @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive /// @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive function swap( address recipient, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96, bytes calldata data ) external returns (int256 amount0, int256 amount1); /// @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback /// @dev The caller of this method receives a callback in the form of IUniswapV3FlashCallback#uniswapV3FlashCallback /// @dev Can be used to donate underlying tokens pro-rata to currently in-range liquidity providers by calling /// with 0 amount{0,1} and sending the donation amount(s) from the callback /// @param recipient The address which will receive the token0 and token1 amounts /// @param amount0 The amount of token0 to send /// @param amount1 The amount of token1 to send /// @param data Any data to be passed through to the callback function flash( address recipient, uint256 amount0, uint256 amount1, bytes calldata data ) external; /// @notice Increase the maximum number of price and liquidity observations that this pool will store /// @dev This method is no-op if the pool already has an observationCardinalityNext greater than or equal to /// the input observationCardinalityNext. /// @param observationCardinalityNext The desired minimum number of observations for the pool to store function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external; } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol /// @title Pool state that is not stored /// @notice Contains view functions to provide information about the pool that is computed rather than stored on the /// blockchain. The functions here may have variable gas costs. interface IUniswapV3PoolDerivedState { /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, /// you must call it with secondsAgos = [3600, 0]. /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block /// timestamp function observe(uint32[] calldata secondsAgos) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first /// snapshot is taken and the second snapshot is taken. /// @param tickLower The lower tick of the range /// @param tickUpper The upper tick of the range /// @return tickCumulativeInside The snapshot of the tick accumulator for the range /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range /// @return secondsInside The snapshot of seconds per liquidity for the range function snapshotCumulativesInside(int24 tickLower, int24 tickUpper) external view returns ( int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside ); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolErrors.sol /// @title Errors emitted by a pool /// @notice Contains all events emitted by the pool interface IUniswapV3PoolErrors { error LOK(); error TLU(); error TLM(); error TUM(); error AI(); error M0(); error M1(); error AS(); error IIA(); error L(); error F0(); error F1(); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol /// @title Events emitted by a pool /// @notice Contains all events emitted by the pool interface IUniswapV3PoolEvents { /// @notice Emitted exactly once by a pool when #initialize is first called on the pool /// @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize /// @param sqrtPriceX96 The initial sqrt price of the pool, as a Q64.96 /// @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool event Initialize(uint160 sqrtPriceX96, int24 tick); /// @notice Emitted when liquidity is minted for a given position /// @param sender The address that minted the liquidity /// @param owner The owner of the position and recipient of any minted liquidity /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount The amount of liquidity minted to the position range /// @param amount0 How much token0 was required for the minted liquidity /// @param amount1 How much token1 was required for the minted liquidity event Mint( address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1 ); /// @notice Emitted when fees are collected by the owner of a position /// @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees /// @param owner The owner of the position for which fees are collected /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount0 The amount of token0 fees collected /// @param amount1 The amount of token1 fees collected event Collect( address indexed owner, address recipient, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount0, uint128 amount1 ); /// @notice Emitted when a position's liquidity is removed /// @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect /// @param owner The owner of the position for which liquidity is removed /// @param tickLower The lower tick of the position /// @param tickUpper The upper tick of the position /// @param amount The amount of liquidity to remove /// @param amount0 The amount of token0 withdrawn /// @param amount1 The amount of token1 withdrawn event Burn( address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1 ); /// @notice Emitted by the pool for any swaps between token0 and token1 /// @param sender The address that initiated the swap call, and that received the callback /// @param recipient The address that received the output of the swap /// @param amount0 The delta of the token0 balance of the pool /// @param amount1 The delta of the token1 balance of the pool /// @param sqrtPriceX96 The sqrt(price) of the pool after the swap, as a Q64.96 /// @param liquidity The liquidity of the pool after the swap /// @param tick The log base 1.0001 of price of the pool after the swap event Swap( address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick ); /// @notice Emitted by the pool for any flashes of token0/token1 /// @param sender The address that initiated the swap call, and that received the callback /// @param recipient The address that received the tokens from flash /// @param amount0 The amount of token0 that was flashed /// @param amount1 The amount of token1 that was flashed /// @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee /// @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee event Flash( address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1 ); /// @notice Emitted by the pool for increases to the number of observations that can be stored /// @dev observationCardinalityNext is not the observation cardinality until an observation is written at the index /// just before a mint/swap/burn. /// @param observationCardinalityNextOld The previous value of the next observation cardinality /// @param observationCardinalityNextNew The updated value of the next observation cardinality event IncreaseObservationCardinalityNext( uint16 observationCardinalityNextOld, uint16 observationCardinalityNextNew ); /// @notice Emitted when the protocol fee is changed by the pool /// @param feeProtocol0Old The previous value of the token0 protocol fee /// @param feeProtocol1Old The previous value of the token1 protocol fee /// @param feeProtocol0New The updated value of the token0 protocol fee /// @param feeProtocol1New The updated value of the token1 protocol fee event SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New); /// @notice Emitted when the collected protocol fees are withdrawn by the factory owner /// @param sender The address that collects the protocol fees /// @param recipient The address that receives the collected protocol fees /// @param amount0 The amount of token0 protocol fees that is withdrawn /// @param amount0 The amount of token1 protocol fees that is withdrawn event CollectProtocol(address indexed sender, address indexed recipient, uint128 amount0, uint128 amount1); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values interface IUniswapV3PoolImmutables { /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface /// @return The contract address function factory() external view returns (address); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (address); /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The fee function fee() external view returns (uint24); /// @notice The pool tick spacing /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... /// This value is an int24 to avoid casting even though it is always positive. /// @return The tick spacing function tickSpacing() external view returns (int24); /// @notice The maximum amount of position liquidity that can use any tick in the range /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool /// @return The max amount of liquidity per tick function maxLiquidityPerTick() external view returns (uint128); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol /// @title Permissioned pool actions /// @notice Contains pool methods that may only be called by the factory owner interface IUniswapV3PoolOwnerActions { /// @notice Set the denominator of the protocol's % share of the fees /// @param feeProtocol0 new protocol fee for token0 of the pool /// @param feeProtocol1 new protocol fee for token1 of the pool function setFeeProtocol(uint8 feeProtocol0, uint8 feeProtocol1) external; /// @notice Collect the protocol fee accrued to the pool /// @param recipient The address to which collected protocol fees should be sent /// @param amount0Requested The maximum amount of token0 to send, can be 0 to collect fees in only token1 /// @param amount1Requested The maximum amount of token1 to send, can be 0 to collect fees in only token0 /// @return amount0 The protocol fee collected in token0 /// @return amount1 The protocol fee collected in token1 function collectProtocol( address recipient, uint128 amount0Requested, uint128 amount1Requested ) external returns (uint128 amount0, uint128 amount1); } // lib/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol /// @title Pool state that can change /// @notice These methods compose the pool's state, and can change with any frequency including multiple times /// per transaction interface IUniswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value /// @return tick The current tick of the pool, i.e. according to the last tick transition that was run. /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// @return observationIndex The index of the last oracle observation that was written, /// @return observationCardinality The current maximum number of observations stored in the pool, /// @return observationCardinalityNext The next maximum number of observations, to be updated when the observation. /// @return feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked ); /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal0X128() external view returns (uint256); /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); /// @notice The amounts of token0 and token1 that are owed to the protocol /// @dev Protocol fees will never exceed uint128 max in either token function protocolFees() external view returns (uint128 token0, uint128 token1); /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks /// @return The liquidity at the current price of the pool function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or /// tick upper /// @return liquidityNet how much liquidity changes when the pool price crosses the tick, /// @return feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, /// @return feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, /// @return tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick /// @return secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, /// @return secondsOutside the seconds spent on the other side of the tick from the current tick, /// @return initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in comparison to previous snapshots for /// a specific position. function ticks(int24 tick) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper /// @return liquidity The amount of liquidity in the position, /// @return feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, /// @return feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, /// @return tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, /// @return tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke function positions(bytes32 key) external view returns ( uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Returns data about a specific observation index /// @param index The element of the observations array to fetch /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, /// @return tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, /// @return secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, /// @return initialized whether the observation has been initialized and the values are safe to use function observations(uint256 index) external view returns ( uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized ); } // lib/tokenized-strategy-periphery/src/swappers/interfaces/IUniswapV3Swapper.sol interface IUniswapV3Swapper { function minAmountToSell() external view returns (uint256); function base() external view returns (address); function router() external view returns (address); function uniFees(address, address) external view returns (uint24); } // src/interfaces/Morpho/libraries/MathLib.sol 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; } } // lib/v3-core/contracts/libraries/SafeCast.sol /// @title Safe casting methods /// @notice Contains methods for safely casting between types library SafeCast { /// @notice Cast a uint256 to a uint160, revert on overflow /// @param y The uint256 to be downcasted /// @return z The downcasted integer, now type uint160 function toUint160(uint256 y) internal pure returns (uint160 z) { require((z = uint160(y)) == y); } /// @notice Cast a int256 to a int128, revert on overflow or underflow /// @param y The int256 to be downcasted /// @return z The downcasted integer, now type int128 function toInt128(int256 y) internal pure returns (int128 z) { require((z = int128(y)) == y); } /// @notice Cast a uint256 to a int256, revert on overflow /// @param y The uint256 to be casted /// @return z The casted integer, now type int256 function toInt256(uint256 y) internal pure returns (int256 z) { require(y < 2**255); z = int256(y); } } // lib/v3-core/contracts/libraries/TickMath.sol /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { error T(); error R(); /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { unchecked { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); if (absTick > uint256(int256(MAX_TICK))) revert T(); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { unchecked { // second inequality must be < because the price can never reach the price at the max tick if (!(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO)) revert R(); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } } } // lib/v3-core/contracts/libraries/UnsafeMath.sol /// @title Math functions that do not check inputs or outputs /// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks library UnsafeMath { /// @notice Returns ceil(x / y) /// @dev division by 0 has unspecified behavior, and must be checked externally /// @param x The dividend /// @param y The divisor /// @return z The quotient, ceil(x / y) function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) { assembly { z := add(div(x, y), gt(mod(x, y), 0)) } } } // lib/tokenized-strategy-periphery/src/AprOracle/AprOracleBase.sol abstract contract AprOracleBase is Governance { string public name; constructor( string memory _name, address _governance ) Governance(_governance) { name = _name; } /** * @notice Will return the expected Apr of a strategy post a debt change. * @dev _delta is a signed integer so that it can also represent a debt * decrease. * * _delta will be == 0 to get the current apr. * * This will potentially be called during non-view functions so gas * efficiency should be taken into account. * * @param _strategy The strategy to get the apr for. * @param _delta The difference in debt. * @return . The expected apr for the strategy. */ function aprAfterDebtChange( address _strategy, int256 _delta ) external view virtual returns (uint256); } // lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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); } // src/interfaces/Morpho/IIrm.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); } // src/interfaces/Morpho/libraries/MarketParamsLib.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 ) } } } // src/interfaces/Morpho/libraries/MorphoStorageLib.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 ); } } // src/interfaces/Morpho/libraries/SharesMathLib.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 ); } } // lib/v3-core/contracts/libraries/TickBitmap.sol /// @title Packed tick initialized state library /// @notice Stores a packed mapping of tick index to its initialized state /// @dev The mapping uses int16 for keys since ticks are represented as int24 and there are 256 (2^8) values per word. library TickBitmap { /// @notice Computes the position in the mapping where the initialized bit for a tick lives /// @param tick The tick for which to compute the position /// @return wordPos The key in the mapping containing the word in which the bit is stored /// @return bitPos The bit position in the word where the flag is stored function position(int24 tick) internal pure returns (int16 wordPos, uint8 bitPos) { unchecked { wordPos = int16(tick >> 8); bitPos = uint8(int8(tick % 256)); } } /// @notice Flips the initialized state for a given tick from false to true, or vice versa /// @param self The mapping in which to flip the tick /// @param tick The tick to flip /// @param tickSpacing The spacing between usable ticks function flipTick( mapping(int16 => uint256) storage self, int24 tick, int24 tickSpacing ) internal { unchecked { require(tick % tickSpacing == 0); // ensure that the tick is spaced (int16 wordPos, uint8 bitPos) = position(tick / tickSpacing); uint256 mask = 1 << bitPos; self[wordPos] ^= mask; } } /// @notice Returns the next initialized tick contained in the same word (or adjacent word) as the tick that is either /// to the left (less than or equal to) or right (greater than) of the given tick /// @param self The mapping in which to compute the next initialized tick /// @param tick The starting tick /// @param tickSpacing The spacing between usable ticks /// @param lte Whether to search for the next initialized tick to the left (less than or equal to the starting tick) /// @return next The next initialized or uninitialized tick up to 256 ticks away from the current tick /// @return initialized Whether the next tick is initialized, as the function only searches within up to 256 ticks function nextInitializedTickWithinOneWord( mapping(int16 => uint256) storage self, int24 tick, int24 tickSpacing, bool lte ) internal view returns (int24 next, bool initialized) { unchecked { int24 compressed = tick / tickSpacing; if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity if (lte) { (int16 wordPos, uint8 bitPos) = position(compressed); // all the 1s at or to the right of the current bitPos uint256 mask = (1 << bitPos) - 1 + (1 << bitPos); uint256 masked = self[wordPos] & mask; // if there are no initialized ticks to the right of or at the current tick, return rightmost in the word initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized ? (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * tickSpacing : (compressed - int24(uint24(bitPos))) * tickSpacing; } else { // start from the word of the next tick, since the current tick state doesn't matter (int16 wordPos, uint8 bitPos) = position(compressed + 1); // all the 1s at or to the left of the bitPos uint256 mask = ~((1 << bitPos) - 1); uint256 masked = self[wordPos] & mask; // if there are no initialized ticks to the left of the current tick, return leftmost in the word initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized ? (compressed + 1 + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * tickSpacing : (compressed + 1 + int24(uint24(type(uint8).max - bitPos))) * tickSpacing; } } } } // src/interfaces/Morpho/libraries/UtilsLib.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)) } } } // lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. * * _Available since v4.7._ */ 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); } // src/interfaces/Morpho/libraries/MorphoLib.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; } } // lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} } // src/interfaces/Morpho/IMetaMorpho.sol 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); } } 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 Funds can be recovered by enabling this market again and withdrawing from it (using `reallocate`), /// but funds will be distributed pro-rata to the shares at the time of withdrawal, not at the time of removal. /// @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, 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); } // lib/v3-core/contracts/libraries/SqrtPriceMath.sol /// @title Functions based on Q64.96 sqrt price and liquidity /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas library SqrtPriceMath { using SafeCast for uint256; /// @notice Gets the next sqrt price given a delta of token0 /// @dev Always rounds up, because in the exact output case (increasing price) we need to move the price at least /// far enough to get the desired output amount, and in the exact input case (decreasing price) we need to move the /// price less in order to not send too much output. /// The most precise formula for this is liquidity * sqrtPX96 / (liquidity +- amount * sqrtPX96), /// if this is impossible because of overflow, we calculate liquidity / (liquidity / sqrtPX96 +- amount). /// @param sqrtPX96 The starting price, i.e. before accounting for the token0 delta /// @param liquidity The amount of usable liquidity /// @param amount How much of token0 to add or remove from virtual reserves /// @param add Whether to add or remove the amount of token0 /// @return The price after adding or removing amount, depending on add function getNextSqrtPriceFromAmount0RoundingUp( uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add ) internal pure returns (uint160) { // we short circuit amount == 0 because the result is otherwise not guaranteed to equal the input price if (amount == 0) return sqrtPX96; uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; if (add) { unchecked { uint256 product; if ((product = amount * sqrtPX96) / amount == sqrtPX96) { uint256 denominator = numerator1 + product; if (denominator >= numerator1) // always fits in 160 bits return uint160(FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator)); } } // denominator is checked for overflow return uint160(UnsafeMath.divRoundingUp(numerator1, (numerator1 / sqrtPX96) + amount)); } else { unchecked { uint256 product; // if the product overflows, we know the denominator underflows // in addition, we must check that the denominator does not underflow require((product = amount * sqrtPX96) / amount == sqrtPX96 && numerator1 > product); uint256 denominator = numerator1 - product; return FullMath.mulDivRoundingUp(numerator1, sqrtPX96, denominator).toUint160(); } } } /// @notice Gets the next sqrt price given a delta of token1 /// @dev Always rounds down, because in the exact output case (decreasing price) we need to move the price at least /// far enough to get the desired output amount, and in the exact input case (increasing price) we need to move the /// price less in order to not send too much output. /// The formula we compute is within <1 wei of the lossless version: sqrtPX96 +- amount / liquidity /// @param sqrtPX96 The starting price, i.e., before accounting for the token1 delta /// @param liquidity The amount of usable liquidity /// @param amount How much of token1 to add, or remove, from virtual reserves /// @param add Whether to add, or remove, the amount of token1 /// @return The price after adding or removing `amount` function getNextSqrtPriceFromAmount1RoundingDown( uint160 sqrtPX96, uint128 liquidity, uint256 amount, bool add ) internal pure returns (uint160) { // if we're adding (subtracting), rounding down requires rounding the quotient down (up) // in both cases, avoid a mulDiv for most inputs if (add) { uint256 quotient = ( amount <= type(uint160).max ? (amount << FixedPoint96.RESOLUTION) / liquidity : FullMath.mulDiv(amount, FixedPoint96.Q96, liquidity) ); return (uint256(sqrtPX96) + quotient).toUint160(); } else { uint256 quotient = ( amount <= type(uint160).max ? UnsafeMath.divRoundingUp(amount << FixedPoint96.RESOLUTION, liquidity) : FullMath.mulDivRoundingUp(amount, FixedPoint96.Q96, liquidity) ); require(sqrtPX96 > quotient); // always fits 160 bits unchecked { return uint160(sqrtPX96 - quotient); } } } /// @notice Gets the next sqrt price given an input amount of token0 or token1 /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds /// @param sqrtPX96 The starting price, i.e., before accounting for the input amount /// @param liquidity The amount of usable liquidity /// @param amountIn How much of token0, or token1, is being swapped in /// @param zeroForOne Whether the amount in is token0 or token1 /// @return sqrtQX96 The price after adding the input amount to token0 or token1 function getNextSqrtPriceFromInput( uint160 sqrtPX96, uint128 liquidity, uint256 amountIn, bool zeroForOne ) internal pure returns (uint160 sqrtQX96) { require(sqrtPX96 > 0); require(liquidity > 0); // round to make sure that we don't pass the target price return zeroForOne ? getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountIn, true) : getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountIn, true); } /// @notice Gets the next sqrt price given an output amount of token0 or token1 /// @dev Throws if price or liquidity are 0 or the next price is out of bounds /// @param sqrtPX96 The starting price before accounting for the output amount /// @param liquidity The amount of usable liquidity /// @param amountOut How much of token0, or token1, is being swapped out /// @param zeroForOne Whether the amount out is token0 or token1 /// @return sqrtQX96 The price after removing the output amount of token0 or token1 function getNextSqrtPriceFromOutput( uint160 sqrtPX96, uint128 liquidity, uint256 amountOut, bool zeroForOne ) internal pure returns (uint160 sqrtQX96) { require(sqrtPX96 > 0); require(liquidity > 0); // round to make sure that we pass the target price return zeroForOne ? getNextSqrtPriceFromAmount1RoundingDown(sqrtPX96, liquidity, amountOut, false) : getNextSqrtPriceFromAmount0RoundingUp(sqrtPX96, liquidity, amountOut, false); } /// @notice Gets the amount0 delta between two prices /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper), /// i.e. liquidity * (sqrt(upper) - sqrt(lower)) / (sqrt(upper) * sqrt(lower)) /// @param sqrtRatioAX96 A sqrt price /// @param sqrtRatioBX96 Another sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up or down /// @return amount0 Amount of token0 required to cover a position of size liquidity between the two passed prices function getAmount0Delta( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity, bool roundUp ) internal pure returns (uint256 amount0) { unchecked { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); uint256 numerator1 = uint256(liquidity) << FixedPoint96.RESOLUTION; uint256 numerator2 = sqrtRatioBX96 - sqrtRatioAX96; require(sqrtRatioAX96 > 0); return roundUp ? UnsafeMath.divRoundingUp( FullMath.mulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96), sqrtRatioAX96 ) : FullMath.mulDiv(numerator1, numerator2, sqrtRatioBX96) / sqrtRatioAX96; } } /// @notice Gets the amount1 delta between two prices /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower)) /// @param sqrtRatioAX96 A sqrt price /// @param sqrtRatioBX96 Another sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up, or down /// @return amount1 Amount of token1 required to cover a position of size liquidity between the two passed prices function getAmount1Delta( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity, bool roundUp ) internal pure returns (uint256 amount1) { unchecked { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return roundUp ? FullMath.mulDivRoundingUp(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96) : FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); } } /// @notice Helper that gets signed token0 delta /// @param sqrtRatioAX96 A sqrt price /// @param sqrtRatioBX96 Another sqrt price /// @param liquidity The change in liquidity for which to compute the amount0 delta /// @return amount0 Amount of token0 corresponding to the passed liquidityDelta between the two prices function getAmount0Delta( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, int128 liquidity ) internal pure returns (int256 amount0) { unchecked { return liquidity < 0 ? -getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() : getAmount0Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); } } /// @notice Helper that gets signed token1 delta /// @param sqrtRatioAX96 A sqrt price /// @param sqrtRatioBX96 Another sqrt price /// @param liquidity The change in liquidity for which to compute the amount1 delta /// @return amount1 Amount of token1 corresponding to the passed liquidityDelta between the two prices function getAmount1Delta( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, int128 liquidity ) internal pure returns (int256 amount1) { unchecked { return liquidity < 0 ? -getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(-liquidity), false).toInt256() : getAmount1Delta(sqrtRatioAX96, sqrtRatioBX96, uint128(liquidity), true).toInt256(); } } } // lib/v3-core/contracts/libraries/SwapMath.sol /// @title Computes the result of a swap within ticks /// @notice Contains methods for computing the result of a swap within a single tick price range, i.e., a single tick. library SwapMath { /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive /// @param sqrtRatioCurrentX96 The current sqrt price of the pool /// @param sqrtRatioTargetX96 The price that cannot be exceeded, from which the direction of the swap is inferred /// @param liquidity The usable liquidity /// @param amountRemaining How much input or output amount is remaining to be swapped in/out /// @param feePips The fee taken from the input amount, expressed in hundredths of a bip /// @return sqrtRatioNextX96 The price after swapping the amount in/out, not to exceed the price target /// @return amountIn The amount to be swapped in, of either token0 or token1, based on the direction of the swap /// @return amountOut The amount to be received, of either token0 or token1, based on the direction of the swap /// @return feeAmount The amount of input that will be taken as a fee function computeSwapStep( uint160 sqrtRatioCurrentX96, uint160 sqrtRatioTargetX96, uint128 liquidity, int256 amountRemaining, uint24 feePips ) internal pure returns ( uint160 sqrtRatioNextX96, uint256 amountIn, uint256 amountOut, uint256 feeAmount ) { unchecked { bool zeroForOne = sqrtRatioCurrentX96 >= sqrtRatioTargetX96; bool exactIn = amountRemaining >= 0; if (exactIn) { uint256 amountRemainingLessFee = FullMath.mulDiv(uint256(amountRemaining), 1e6 - feePips, 1e6); amountIn = zeroForOne ? SqrtPriceMath.getAmount0Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true) : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, true); if (amountRemainingLessFee >= amountIn) sqrtRatioNextX96 = sqrtRatioTargetX96; else sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromInput( sqrtRatioCurrentX96, liquidity, amountRemainingLessFee, zeroForOne ); } else { amountOut = zeroForOne ? SqrtPriceMath.getAmount1Delta(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, false) : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioTargetX96, liquidity, false); if (uint256(-amountRemaining) >= amountOut) sqrtRatioNextX96 = sqrtRatioTargetX96; else sqrtRatioNextX96 = SqrtPriceMath.getNextSqrtPriceFromOutput( sqrtRatioCurrentX96, liquidity, uint256(-amountRemaining), zeroForOne ); } bool max = sqrtRatioTargetX96 == sqrtRatioNextX96; // get the input/output amounts if (zeroForOne) { amountIn = max && exactIn ? amountIn : SqrtPriceMath.getAmount0Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, true); amountOut = max && !exactIn ? amountOut : SqrtPriceMath.getAmount1Delta(sqrtRatioNextX96, sqrtRatioCurrentX96, liquidity, false); } else { amountIn = max && exactIn ? amountIn : SqrtPriceMath.getAmount1Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, true); amountOut = max && !exactIn ? amountOut : SqrtPriceMath.getAmount0Delta(sqrtRatioCurrentX96, sqrtRatioNextX96, liquidity, false); } // cap the output amount to not exceed the remaining output amount if (!exactIn && amountOut > uint256(-amountRemaining)) { amountOut = uint256(-amountRemaining); } if (exactIn && sqrtRatioNextX96 != sqrtRatioTargetX96) { // we didn't reach the target, so take the remainder of the maximum input as fee feeAmount = uint256(amountRemaining) - amountIn; } else { feeAmount = FullMath.mulDivRoundingUp(amountIn, feePips, 1e6 - feePips); } } } } // lib/tokenized-strategy/src/interfaces/ITokenizedStrategy.sol // Interface that implements the 4626 standard and the implementation functions interface ITokenizedStrategy is IERC4626, IERC20Permit { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event StrategyShutdown(); event NewTokenizedStrategy( address indexed strategy, address indexed asset, string apiVersion ); event Reported( uint256 profit, uint256 loss, uint256 protocolFees, uint256 performanceFees ); event UpdatePerformanceFeeRecipient( address indexed newPerformanceFeeRecipient ); event UpdateKeeper(address indexed newKeeper); event UpdatePerformanceFee(uint16 newPerformanceFee); event UpdateManagement(address indexed newManagement); event UpdateEmergencyAdmin(address indexed newEmergencyAdmin); event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime); event UpdatePendingManagement(address indexed newPendingManagement); /*////////////////////////////////////////////////////////////// INITIALIZATION //////////////////////////////////////////////////////////////*/ function initialize( address _asset, string memory _name, address _management, address _performanceFeeRecipient, address _keeper ) external; /*////////////////////////////////////////////////////////////// NON-STANDARD 4626 OPTIONS //////////////////////////////////////////////////////////////*/ function withdraw( uint256 assets, address receiver, address owner, uint256 maxLoss ) external returns (uint256); function redeem( uint256 shares, address receiver, address owner, uint256 maxLoss ) external returns (uint256); function maxWithdraw( address owner, uint256 /*maxLoss*/ ) external view returns (uint256); function maxRedeem( address owner, uint256 /*maxLoss*/ ) external view returns (uint256); /*////////////////////////////////////////////////////////////// MODIFIER HELPERS //////////////////////////////////////////////////////////////*/ function requireManagement(address _sender) external view; function requireKeeperOrManagement(address _sender) external view; function requireEmergencyAuthorized(address _sender) external view; /*////////////////////////////////////////////////////////////// KEEPERS FUNCTIONS //////////////////////////////////////////////////////////////*/ function tend() external; function report() external returns (uint256 _profit, uint256 _loss); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ function MAX_FEE() external view returns (uint16); function FACTORY() external view returns (address); /*////////////////////////////////////////////////////////////// GETTERS //////////////////////////////////////////////////////////////*/ function apiVersion() external view returns (string memory); function pricePerShare() external view returns (uint256); function management() external view returns (address); function pendingManagement() external view returns (address); function keeper() external view returns (address); function emergencyAdmin() external view returns (address); function performanceFee() external view returns (uint16); function performanceFeeRecipient() external view returns (address); function fullProfitUnlockDate() external view returns (uint256); function profitUnlockingRate() external view returns (uint256); function profitMaxUnlockTime() external view returns (uint256); function lastReport() external view returns (uint256); function isShutdown() external view returns (bool); function unlockedShares() external view returns (uint256); /*////////////////////////////////////////////////////////////// SETTERS //////////////////////////////////////////////////////////////*/ function setPendingManagement(address) external; function acceptManagement() external; function setKeeper(address _keeper) external; function setEmergencyAdmin(address _emergencyAdmin) external; function setPerformanceFee(uint16 _performanceFee) external; function setPerformanceFeeRecipient( address _performanceFeeRecipient ) external; function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external; function setName(string calldata _newName) external; function shutdownStrategy() external; function emergencyWithdraw(uint256 _amount) external; } // lib/v3-core/contracts/interfaces/IUniswapV3Pool.sol /// @title The interface for a Uniswap V3 Pool /// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform /// to the ERC20 specification /// @dev The pool interface is broken up into many smaller pieces interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState, IUniswapV3PoolActions, IUniswapV3PoolOwnerActions, IUniswapV3PoolErrors, IUniswapV3PoolEvents { } // lib/tokenized-strategy/src/interfaces/IStrategy.sol interface IStrategy is IBaseStrategy, ITokenizedStrategy {} // lib/tokenized-strategy-periphery/src/Bases/HealthCheck/IBaseHealthCheck.sol interface IBaseHealthCheck is IStrategy { function doHealthCheck() external view returns (bool); function profitLimitRatio() external view returns (uint256); function lossLimitRatio() external view returns (uint256); function setProfitLimitRatio(uint256 _newProfitLimitRatio) external; function setLossLimitRatio(uint256 _newLossLimitRatio) external; function setDoHealthCheck(bool _doHealthCheck) external; } // src/interfaces/Morpho/libraries/MorphoBalancesLib.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); } } // lib/tokenized-strategy-periphery/src/Bases/4626Compounder/IBase4626Compounder.sol interface IBase4626Compounder is IBaseHealthCheck { function vault() external view returns (address); function balanceOfAsset() external view returns (uint256); function balanceOfVault() external view returns (uint256); function balanceOfStake() external view returns (uint256); function valueOfVault() external view returns (uint256); function vaultsMaxWithdraw() external view returns (uint256); } // src/interfaces/IStrategyInterface.sol interface IStrategyInterface is IBase4626Compounder {} // src/Strategies/Morpho/interfaces/IMorphoCompounder.sol interface IMorphoCompounder is IStrategyInterface, IUniswapV3Swapper { enum SwapType { NULL, UNISWAP_V3, AUCTION } // State Variables function auction() external view returns (address); function minAmountToSellMapping(address) external view returns (uint256); function swapType(address) external view returns (SwapType); function allRewardTokens(uint256) external view returns (address); // Functions function addRewardToken(address _token, SwapType _swapType) external; function removeRewardToken(address _token) external; function getAllRewardTokens() external view returns (address[] memory); function setAuction(address _auction) external; function setUniFees(address _token0, address _token1, uint24 _fee) external; function setSwapType(address _from, SwapType _swapType) external; function setMinAmountToSellMapping( address _token, uint256 _amount ) external; function kickAuction(address _token) external returns (uint256); } // lib/v3-core/contracts/libraries/Simulate.sol /// @title Library for simulating swaps. /// @notice By fully replicating the swap logic, we can make a static call to get a quote. library Simulate { using SafeCast for uint256; struct Cache { // price at the beginning of the swap uint160 sqrtPriceX96Start; // tick at the beginning of the swap int24 tickStart; // liquidity at the beginning of the swap uint128 liquidityStart; // the lp fee of the pool uint24 fee; // the tick spacing of the pool int24 tickSpacing; } struct State { // the amount remaining to be swapped in/out of the input/output asset int256 amountSpecifiedRemaining; // the amount already swapped out/in of the output/input asset int256 amountCalculated; // current sqrt(price) uint160 sqrtPriceX96; // the tick associated with the current price int24 tick; // the current liquidity in range uint128 liquidity; } // copied from UniswapV3Pool to avoid pragma issues associated with importing it struct StepComputations { // the price at the beginning of the step uint160 sqrtPriceStartX96; // the next tick to swap to from the current tick in the swap direction int24 tickNext; // whether tickNext is initialized or not bool initialized; // sqrt(price) for the next tick (1/0) uint160 sqrtPriceNextX96; // how much is being swapped in in this step uint256 amountIn; // how much is being swapped out uint256 amountOut; // how much fee is being paid in uint256 feeAmount; } function simulateSwap( IUniswapV3Pool pool, bool zeroForOne, int256 amountSpecified, uint160 sqrtPriceLimitX96 ) internal view returns (int256 amount0, int256 amount1) { require(amountSpecified != 0, 'AS'); (uint160 sqrtPriceX96, int24 tick, , , , , ) = pool.slot0(); require( zeroForOne ? sqrtPriceLimitX96 < sqrtPriceX96 && sqrtPriceLimitX96 > TickMath.MIN_SQRT_RATIO : sqrtPriceLimitX96 > sqrtPriceX96 && sqrtPriceLimitX96 < TickMath.MAX_SQRT_RATIO, 'SPL' ); Cache memory cache = Cache({ sqrtPriceX96Start: sqrtPriceX96, tickStart: tick, liquidityStart: pool.liquidity(), fee: pool.fee(), tickSpacing: pool.tickSpacing() }); bool exactInput = amountSpecified > 0; State memory state = State({ amountSpecifiedRemaining: amountSpecified, amountCalculated: 0, sqrtPriceX96: cache.sqrtPriceX96Start, tick: cache.tickStart, liquidity: cache.liquidityStart }); while (state.amountSpecifiedRemaining != 0 && state.sqrtPriceX96 != sqrtPriceLimitX96) { StepComputations memory step; step.sqrtPriceStartX96 = state.sqrtPriceX96; (step.tickNext, step.initialized) = nextInitializedTickWithinOneWord( pool.tickBitmap, state.tick, cache.tickSpacing, zeroForOne ); if (step.tickNext < TickMath.MIN_TICK) { step.tickNext = TickMath.MIN_TICK; } else if (step.tickNext > TickMath.MAX_TICK) { step.tickNext = TickMath.MAX_TICK; } step.sqrtPriceNextX96 = TickMath.getSqrtRatioAtTick(step.tickNext); (state.sqrtPriceX96, step.amountIn, step.amountOut, step.feeAmount) = SwapMath.computeSwapStep( state.sqrtPriceX96, (zeroForOne ? step.sqrtPriceNextX96 < sqrtPriceLimitX96 : step.sqrtPriceNextX96 > sqrtPriceLimitX96) ? sqrtPriceLimitX96 : step.sqrtPriceNextX96, state.liquidity, state.amountSpecifiedRemaining, cache.fee ); if (exactInput) { unchecked { state.amountSpecifiedRemaining -= (step.amountIn + step.feeAmount).toInt256(); } state.amountCalculated -= step.amountOut.toInt256(); } else { unchecked { state.amountSpecifiedRemaining += step.amountOut.toInt256(); } state.amountCalculated += (step.amountIn + step.feeAmount).toInt256(); } if (state.sqrtPriceX96 == step.sqrtPriceNextX96) { if (step.initialized) { (, int128 liquidityNet, , , , , , ) = pool.ticks(step.tickNext); unchecked { if (zeroForOne) liquidityNet = -liquidityNet; } state.liquidity = liquidityNet < 0 ? state.liquidity - uint128(-liquidityNet) : state.liquidity + uint128(liquidityNet); } unchecked { state.tick = zeroForOne ? step.tickNext - 1 : step.tickNext; } } else if (state.sqrtPriceX96 != step.sqrtPriceStartX96) { // recompute unless we're on a lower tick boundary (i.e. already transitioned ticks), and haven't moved state.tick = TickMath.getTickAtSqrtRatio(state.sqrtPriceX96); } } (amount0, amount1) = zeroForOne == exactInput ? (amountSpecified - state.amountSpecifiedRemaining, state.amountCalculated) : (state.amountCalculated, amountSpecified - state.amountSpecifiedRemaining); } // This function replicates TickBitmap, but accepts a function pointer argument. // It's private because it's messy, and shouldn't be re-used. function nextInitializedTickWithinOneWord( function(int16) external view returns (uint256) self, int24 tick, int24 tickSpacing, bool lte ) private view returns (int24 next, bool initialized) { unchecked { int24 compressed = tick / tickSpacing; if (tick < 0 && tick % tickSpacing != 0) compressed--; // round towards negative infinity if (lte) { (int16 wordPos, uint8 bitPos) = TickBitmap.position(compressed); // all the 1s at or to the right of the current bitPos uint256 mask = (1 << bitPos) - 1 + (1 << bitPos); uint256 masked = self(wordPos) & mask; // if there are no initialized ticks to the right of or at the current tick, return rightmost in the word initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized ? (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * tickSpacing : (compressed - int24(uint24(bitPos))) * tickSpacing; } else { // start from the word of the next tick, since the current tick state doesn't matter (int16 wordPos, uint8 bitPos) = TickBitmap.position(compressed + 1); // all the 1s at or to the left of the bitPos uint256 mask = ~((1 << bitPos) - 1); uint256 masked = self(wordPos) & mask; // if there are no initialized ticks to the left of the current tick, return leftmost in the word initialized = masked != 0; // overflow/underflow is possible, but prevented externally by limiting both tickSpacing and tick next = initialized ? (compressed + 1 + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * tickSpacing : (compressed + 1 + int24(uint24(type(uint8).max - bitPos))) * tickSpacing; } } } } // src/periphery/MorphoGenericOracle.sol interface IOracle { function latestAnswer() external view returns (int256); } interface IMorphoGenericOracle { function getRewardsRate(address _vault) external view returns (uint256); } contract MorphoGenericAprOracle is AprOracleBase { using MorphoBalancesLib for IMorpho; constructor() AprOracleBase("Morpho Apr Oracle", msg.sender) {} IMorpho internal constant MORPHO = IMorpho(0xD50F2DffFd62f94Ee4AEd9ca05C61d0753268aBc); uint256 internal constant MAX_BPS = 10_000; uint256 internal constant WAD = 1e18; uint256 internal constant SECONDS_PER_YEAR = 31_556_952; mapping(address => address) public rewardOracles; uint256 public per = 1e8; /** * @notice Will return the expected Apr of a strategy post a debt change. * @dev _delta is a signed integer so that it can also represent a debt * decrease. * * This should return the annual expected return at the current timestamp * represented as 1e18. * * ie. 10% == 1e17 * * _delta will be == 0 to get the current apr. * * This will potentially be called during non-view functions so gas * efficiency should be taken into account. * * @param _strategy The token to get the apr for. * @param _delta The difference in debt. * @return . The expected apr for the strategy represented as 1e18. */ function aprAfterDebtChange( address _strategy, int256 _delta ) external view virtual override returns (uint256) { address _vault = IMorphoCompounder(_strategy).vault(); uint256 underlyingYield = getUnderlyingYield( _vault, _delta ); // Give a buffer for the rewards rate uint256 rewardsRate = (getRewardsRate(_vault) * 9_500) / MAX_BPS; return rewardsRate + underlyingYield; } function getRewardsRate(address _vault) public view virtual returns (uint256) { address _rewardOracle = rewardOracles[_vault]; if (_rewardOracle == address(0)) { return 0; } return IMorphoGenericOracle(_rewardOracle).getRewardsRate(_vault); } function getUnderlyingYield( address _vault, int256 _delta ) public view virtual returns (uint256) { IMetaMorpho metaMorpho = IMetaMorpho(_vault); uint256 queueLength = metaMorpho.withdrawQueueLength(); uint256 totalAssets = metaMorpho.totalAssets(); uint256 rate = 0; for (uint256 i = 0; i < queueLength; i++) { Id id = metaMorpho.withdrawQueue(i); MarketParams memory marketParams = MORPHO.idToMarketParams(id); if (marketParams.irm == address(0)) continue; uint256 suppliedAssets = MORPHO.expectedSupplyAssets( marketParams, _vault ); if (suppliedAssets == 0) continue; int256 marketChange = (int256(suppliedAssets) * _delta) / int256(totalAssets); Market memory market = MORPHO.market(id); // Update the supplied assets uint128 newSupplyAssets = uint128( uint256( int256(uint256(market.totalSupplyAssets)) + marketChange ) ); market.totalSupplyAssets = newSupplyAssets; uint256 borrowRate = IIrm(marketParams.irm).borrowRateView( marketParams, market ); uint256 borrowApy = borrowRate * SECONDS_PER_YEAR; uint256 supplyAPY = (borrowApy * ((market.totalBorrowAssets * WAD) / newSupplyAssets) * (WAD - market.fee)) / WAD / WAD; rate += supplyAPY * uint256(int256(suppliedAssets) + marketChange); } // Account for the fee return ((rate / uint256(int256(totalAssets) + _delta)) * (WAD - IMetaMorpho(_vault).fee())) / WAD; } function setRewardOracles( address[] memory _vaults, address[] memory _rewardOracles ) external virtual onlyGovernance { for (uint256 i = 0; i < _vaults.length; i++) { rewardOracles[_vaults[i]] = _rewardOracles[i]; } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"int256","name":"_delta","type":"int256"}],"name":"aprAfterDebtChange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"getRewardsRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"int256","name":"_delta","type":"int256"}],"name":"getUnderlyingYield","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"per","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardOracles","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_vaults","type":"address[]"},{"internalType":"address[]","name":"_rewardOracles","type":"address[]"}],"name":"setRewardOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526305f5e10060035534801562000018575f80fd5b5060408051808201825260118152704d6f7270686f20417072204f7261636c6560781b60208201525f80546001600160a01b0319163390811782559251919291829182917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce80908290a350600162000090838262000137565b50505062000203565b634e487b7160e01b5f52604160045260245ffd5b600181811c90821680620000c257607f821691505b602082108103620000e157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200013257805f5260205f20601f840160051c810160208510156200010e5750805b601f840160051c820191505b818110156200012f575f81556001016200011a565b50505b505050565b81516001600160401b0381111562000153576200015362000099565b6200016b81620001648454620000ad565b84620000e7565b602080601f831160018114620001a1575f8415620001895750858301515b5f19600386901b1c1916600185901b178555620001fb565b5f85815260208120601f198616915b82811015620001d157888601518255948401946001909101908401620001b0565b5085821015620001ef57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b61155d80620002115f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80636bf164db116100635780636bf164db146101125780637ec9c3b814610125578063a5c648301461012e578063d38bfff414610156578063f7e9d16614610169575f80fd5b8063053270ae1461009457806306fdde03146100a95780632d9e85bd146100c75780635aa6e675146100e8575b5f80fd5b6100a76100a2366004610fcc565b61017c565b005b6100b1610206565b6040516100be919061102c565b60405180910390f35b6100da6100d5366004611078565b610292565b6040519081526020016100be565b5f546100fa906001600160a01b031681565b6040516001600160a01b0390911681526020016100be565b6100da610120366004611078565b61033e565b6100da60035481565b6100fa61013c3660046110a2565b60026020525f90815260409020546001600160a01b031681565b6100a76101643660046110a2565b6107fa565b6100da6101773660046110a2565b61089b565b610184610933565b5f5b8251811015610201578181815181106101a1576101a16110bd565b602002602001015160025f8584815181106101be576101be6110bd565b6020908102919091018101516001600160a01b039081168352908201929092526040015f2080546001600160a01b03191692909116919091179055600101610186565b505050565b60018054610213906110d1565b80601f016020809104026020016040519081016040528092919081815260200182805461023f906110d1565b801561028a5780601f106102615761010080835404028352916020019161028a565b820191905f5260205f20905b81548152906001019060200180831161026d57829003601f168201915b505050505081565b5f80836001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102f49190611109565b90505f610301828561033e565b90505f6127106103108461089b565b61031c9061251c611138565b6103269190611163565b90506103328282611176565b93505050505b92915050565b5f808390505f816001600160a01b03166333f91ebb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610380573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103a49190611189565b90505f826001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104079190611189565b90505f805b8381101561073d576040516362518ddf60e01b8152600481018290525f906001600160a01b038716906362518ddf90602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190611189565b604051632c3c915760e01b8152600481018290529091505f9073d50f2dfffd62f94ee4aed9ca05c61d0753268abc90632c3c91579060240160a060405180830381865afa1580156104d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104f491906111a0565b60608101519091506001600160a01b0316610510575050610735565b5f61053073d50f2dfffd62f94ee4aed9ca05c61d0753268abc838d61097c565b9050805f0361054157505050610735565b5f8661054d8c8461122f565b610557919061125e565b604051632e3071cd60e11b8152600481018690529091505f9073d50f2dfffd62f94ee4aed9ca05c61d0753268abc90635c60e39a9060240160c060405180830381865afa1580156105aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ce91906112a5565b90505f82825f01516001600160801b03166105e99190611342565b6001600160801b03811683526060860151604051638c00bf6b60e01b81529192505f916001600160a01b0390911690638c00bf6b9061062e9089908790600401611369565b602060405180830381865afa158015610649573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066d9190611189565b90505f61067e6301e1855883611138565b90505f670de0b6b3a7640000808660a001516001600160801b0316670de0b6b3a76400006106ac91906113fe565b866001600160801b0316670de0b6b3a764000089604001516001600160801b03166106d79190611138565b6106e19190611163565b6106eb9086611138565b6106f59190611138565b6106ff9190611163565b6107099190611163565b90506107158688611342565b61071f9082611138565b610729908c611176565b9a505050505050505050505b60010161040c565b50670de0b6b3a7640000876001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610783573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107a79190611411565b6107c7906bffffffffffffffffffffffff16670de0b6b3a76400006113fe565b6107d18885611342565b6107db9084611163565b6107e59190611138565b6107ef9190611163565b979650505050505050565b610802610933565b6001600160a01b03811661084c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b60448201526064015b60405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce809190a35050565b6001600160a01b038082165f90815260026020526040812054909116806108c457505f92915050565b604051637bf4e8b360e11b81526001600160a01b03848116600483015282169063f7e9d16690602401602060405180830381865afa158015610908573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092c9190611189565b9392505050565b5f546001600160a01b0316331461097a5760405162461bcd60e51b815260206004820152600b60248201526a21676f7665726e616e636560a81b6044820152606401610843565b565b5f806109898460a0902090565b90505f6109a06001600160a01b03871683866109cd565b90505f806109ae8888610a76565b5091935091506109c19050838383610cf1565b98975050505050505050565b5f806109e16109dc8585610d1d565b610d8f565b604051637784c68560e01b81529091506001600160a01b03861690637784c68590610a1090849060040161143c565b5f60405180830381865afa158015610a2a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a51919081019061147f565b5f81518110610a6257610a626110bd565b60200260200101515f1c9150509392505050565b5f805f805f610a868660a0902090565b604051632e3071cd60e11b8152600481018290529091505f906001600160a01b03891690635c60e39a9060240160c060405180830381865afa158015610ace573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af291906112a5565b90505f81608001516001600160801b031642610b0e91906113fe565b90508015801590610b2b575060408201516001600160801b031615155b8015610b43575060608801516001600160a01b031615155b15610cbd576060880151604051638c00bf6b60e01b81525f916001600160a01b031690638c00bf6b90610b7c908c908790600401611369565b602060405180830381865afa158015610b97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbb9190611189565b90505f610bdf610bcb8385610dd8565b60408601516001600160801b031690610e36565b9050610bea81610e4a565b84604001818151610bfb9190611500565b6001600160801b0316905250610c1081610e4a565b84518590610c1f908390611500565b6001600160801b0390811690915260a086015116159050610cba575f610c5b8560a001516001600160801b031683610e3690919063ffffffff16565b90505f610c8f82875f01516001600160801b0316610c7991906113fe565b60208801518491906001600160801b0316610ea6565b9050610c9a81610e4a565b86602001818151610cab9190611500565b6001600160801b031690525050505b50505b508051602082015160408301516060909301516001600160801b039283169b9183169a509282169850911695509350505050565b5f610d15610d00600185611176565b610d0d620f424085611176565b869190610ec2565b949350505050565b5f8082846002604051602001610d3d929190918252602082015260400190565b60408051601f1981840301815282825280516020918201206001600160a01b0390941690830152810191909152606001604051602081830303815290604052805190602001205f1c61092c9190611176565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110610dc757610dc76110bd565b602090810291909101015292915050565b5f80610de48385611138565b90505f610e048280610dff670de0b6b3a76400006002611138565b610ec2565b90505f610e1f8284610dff670de0b6b3a76400006003611138565b905080610e2c8385611176565b6103329190611176565b5f61092c8383670de0b6b3a7640000610ec2565b6040805180820190915260148152731b585e081d5a5b9d0c4c8e08195e18d95959195960621b60208201525f906001600160801b03831115610e9f5760405162461bcd60e51b8152600401610843919061102c565b5090919050565b5f610d15610eb7620f424084611176565b610d0d600186611176565b5f81610ece8486611138565b610d159190611163565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610f1557610f15610ed8565b604052919050565b5f67ffffffffffffffff821115610f3657610f36610ed8565b5060051b60200190565b6001600160a01b0381168114610f54575f80fd5b50565b5f82601f830112610f66575f80fd5b81356020610f7b610f7683610f1d565b610eec565b8083825260208201915060208460051b870101935086841115610f9c575f80fd5b602086015b84811015610fc1578035610fb481610f40565b8352918301918301610fa1565b509695505050505050565b5f8060408385031215610fdd575f80fd5b823567ffffffffffffffff80821115610ff4575f80fd5b61100086838701610f57565b93506020850135915080821115611015575f80fd5b5061102285828601610f57565b9150509250929050565b5f602080835283518060208501525f5b818110156110585785810183015185820160400152820161103c565b505f604082860101526040601f19601f8301168501019250505092915050565b5f8060408385031215611089575f80fd5b823561109481610f40565b946020939093013593505050565b5f602082840312156110b2575f80fd5b813561092c81610f40565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806110e557607f821691505b60208210810361110357634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611119575f80fd5b815161092c81610f40565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761033857610338611124565b634e487b7160e01b5f52601260045260245ffd5b5f826111715761117161114f565b500490565b8082018082111561033857610338611124565b5f60208284031215611199575f80fd5b5051919050565b5f60a082840312156111b0575f80fd5b60405160a0810181811067ffffffffffffffff821117156111d3576111d3610ed8565b60405282516111e181610f40565b815260208301516111f181610f40565b6020820152604083015161120481610f40565b6040820152606083015161121781610f40565b60608201526080928301519281019290925250919050565b8082025f8212600160ff1b8414161561124a5761124a611124565b818105831482151761033857610338611124565b5f8261126c5761126c61114f565b600160ff1b82145f198414161561128557611285611124565b500590565b80516001600160801b03811681146112a0575f80fd5b919050565b5f60c082840312156112b5575f80fd5b60405160c0810181811067ffffffffffffffff821117156112d8576112d8610ed8565b6040526112e48361128a565b81526112f26020840161128a565b60208201526113036040840161128a565b60408201526113146060840161128a565b60608201526113256080840161128a565b608082015261133660a0840161128a565b60a08201529392505050565b8082018281125f83128015821682158216171561136157611361611124565b505092915050565b82516001600160a01b039081168252602080850151821681840152604080860151831681850152606080870151909316838501526080958601518685015284516001600160801b0390811660a08087019190915292860151811660c086015290850151811660e08501529184015182166101008401529383015181166101208301529190920151166101408201526101600190565b8181038181111561033857610338611124565b5f60208284031215611421575f80fd5b81516bffffffffffffffffffffffff8116811461092c575f80fd5b602080825282518282018190525f9190848201906040850190845b8181101561147357835183529284019291840191600101611457565b50909695505050505050565b5f6020808385031215611490575f80fd5b825167ffffffffffffffff8111156114a6575f80fd5b8301601f810185136114b6575f80fd5b80516114c4610f7682610f1d565b81815260059190911b820183019083810190878311156114e2575f80fd5b928401925b828410156107ef578351825292840192908401906114e7565b6001600160801b0381811683821601908082111561152057611520611124565b509291505056fea2646970667358221220e57e5f3cab9f778849995a83200c232f7391110ff0157563c5567c4fd7650c8e64736f6c63430008170033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610090575f3560e01c80636bf164db116100635780636bf164db146101125780637ec9c3b814610125578063a5c648301461012e578063d38bfff414610156578063f7e9d16614610169575f80fd5b8063053270ae1461009457806306fdde03146100a95780632d9e85bd146100c75780635aa6e675146100e8575b5f80fd5b6100a76100a2366004610fcc565b61017c565b005b6100b1610206565b6040516100be919061102c565b60405180910390f35b6100da6100d5366004611078565b610292565b6040519081526020016100be565b5f546100fa906001600160a01b031681565b6040516001600160a01b0390911681526020016100be565b6100da610120366004611078565b61033e565b6100da60035481565b6100fa61013c3660046110a2565b60026020525f90815260409020546001600160a01b031681565b6100a76101643660046110a2565b6107fa565b6100da6101773660046110a2565b61089b565b610184610933565b5f5b8251811015610201578181815181106101a1576101a16110bd565b602002602001015160025f8584815181106101be576101be6110bd565b6020908102919091018101516001600160a01b039081168352908201929092526040015f2080546001600160a01b03191692909116919091179055600101610186565b505050565b60018054610213906110d1565b80601f016020809104026020016040519081016040528092919081815260200182805461023f906110d1565b801561028a5780601f106102615761010080835404028352916020019161028a565b820191905f5260205f20905b81548152906001019060200180831161026d57829003601f168201915b505050505081565b5f80836001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102f49190611109565b90505f610301828561033e565b90505f6127106103108461089b565b61031c9061251c611138565b6103269190611163565b90506103328282611176565b93505050505b92915050565b5f808390505f816001600160a01b03166333f91ebb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610380573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103a49190611189565b90505f826001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103e3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104079190611189565b90505f805b8381101561073d576040516362518ddf60e01b8152600481018290525f906001600160a01b038716906362518ddf90602401602060405180830381865afa158015610459573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061047d9190611189565b604051632c3c915760e01b8152600481018290529091505f9073d50f2dfffd62f94ee4aed9ca05c61d0753268abc90632c3c91579060240160a060405180830381865afa1580156104d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104f491906111a0565b60608101519091506001600160a01b0316610510575050610735565b5f61053073d50f2dfffd62f94ee4aed9ca05c61d0753268abc838d61097c565b9050805f0361054157505050610735565b5f8661054d8c8461122f565b610557919061125e565b604051632e3071cd60e11b8152600481018690529091505f9073d50f2dfffd62f94ee4aed9ca05c61d0753268abc90635c60e39a9060240160c060405180830381865afa1580156105aa573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ce91906112a5565b90505f82825f01516001600160801b03166105e99190611342565b6001600160801b03811683526060860151604051638c00bf6b60e01b81529192505f916001600160a01b0390911690638c00bf6b9061062e9089908790600401611369565b602060405180830381865afa158015610649573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061066d9190611189565b90505f61067e6301e1855883611138565b90505f670de0b6b3a7640000808660a001516001600160801b0316670de0b6b3a76400006106ac91906113fe565b866001600160801b0316670de0b6b3a764000089604001516001600160801b03166106d79190611138565b6106e19190611163565b6106eb9086611138565b6106f59190611138565b6106ff9190611163565b6107099190611163565b90506107158688611342565b61071f9082611138565b610729908c611176565b9a505050505050505050505b60010161040c565b50670de0b6b3a7640000876001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015610783573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107a79190611411565b6107c7906bffffffffffffffffffffffff16670de0b6b3a76400006113fe565b6107d18885611342565b6107db9084611163565b6107e59190611138565b6107ef9190611163565b979650505050505050565b610802610933565b6001600160a01b03811661084c5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b60448201526064015b60405180910390fd5b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce809190a35050565b6001600160a01b038082165f90815260026020526040812054909116806108c457505f92915050565b604051637bf4e8b360e11b81526001600160a01b03848116600483015282169063f7e9d16690602401602060405180830381865afa158015610908573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061092c9190611189565b9392505050565b5f546001600160a01b0316331461097a5760405162461bcd60e51b815260206004820152600b60248201526a21676f7665726e616e636560a81b6044820152606401610843565b565b5f806109898460a0902090565b90505f6109a06001600160a01b03871683866109cd565b90505f806109ae8888610a76565b5091935091506109c19050838383610cf1565b98975050505050505050565b5f806109e16109dc8585610d1d565b610d8f565b604051637784c68560e01b81529091506001600160a01b03861690637784c68590610a1090849060040161143c565b5f60405180830381865afa158015610a2a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a51919081019061147f565b5f81518110610a6257610a626110bd565b60200260200101515f1c9150509392505050565b5f805f805f610a868660a0902090565b604051632e3071cd60e11b8152600481018290529091505f906001600160a01b03891690635c60e39a9060240160c060405180830381865afa158015610ace573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af291906112a5565b90505f81608001516001600160801b031642610b0e91906113fe565b90508015801590610b2b575060408201516001600160801b031615155b8015610b43575060608801516001600160a01b031615155b15610cbd576060880151604051638c00bf6b60e01b81525f916001600160a01b031690638c00bf6b90610b7c908c908790600401611369565b602060405180830381865afa158015610b97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bbb9190611189565b90505f610bdf610bcb8385610dd8565b60408601516001600160801b031690610e36565b9050610bea81610e4a565b84604001818151610bfb9190611500565b6001600160801b0316905250610c1081610e4a565b84518590610c1f908390611500565b6001600160801b0390811690915260a086015116159050610cba575f610c5b8560a001516001600160801b031683610e3690919063ffffffff16565b90505f610c8f82875f01516001600160801b0316610c7991906113fe565b60208801518491906001600160801b0316610ea6565b9050610c9a81610e4a565b86602001818151610cab9190611500565b6001600160801b031690525050505b50505b508051602082015160408301516060909301516001600160801b039283169b9183169a509282169850911695509350505050565b5f610d15610d00600185611176565b610d0d620f424085611176565b869190610ec2565b949350505050565b5f8082846002604051602001610d3d929190918252602082015260400190565b60408051601f1981840301815282825280516020918201206001600160a01b0390941690830152810191909152606001604051602081830303815290604052805190602001205f1c61092c9190611176565b6040805160018082528183019092526060915f91906020808301908036833701905050905082815f81518110610dc757610dc76110bd565b602090810291909101015292915050565b5f80610de48385611138565b90505f610e048280610dff670de0b6b3a76400006002611138565b610ec2565b90505f610e1f8284610dff670de0b6b3a76400006003611138565b905080610e2c8385611176565b6103329190611176565b5f61092c8383670de0b6b3a7640000610ec2565b6040805180820190915260148152731b585e081d5a5b9d0c4c8e08195e18d95959195960621b60208201525f906001600160801b03831115610e9f5760405162461bcd60e51b8152600401610843919061102c565b5090919050565b5f610d15610eb7620f424084611176565b610d0d600186611176565b5f81610ece8486611138565b610d159190611163565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610f1557610f15610ed8565b604052919050565b5f67ffffffffffffffff821115610f3657610f36610ed8565b5060051b60200190565b6001600160a01b0381168114610f54575f80fd5b50565b5f82601f830112610f66575f80fd5b81356020610f7b610f7683610f1d565b610eec565b8083825260208201915060208460051b870101935086841115610f9c575f80fd5b602086015b84811015610fc1578035610fb481610f40565b8352918301918301610fa1565b509695505050505050565b5f8060408385031215610fdd575f80fd5b823567ffffffffffffffff80821115610ff4575f80fd5b61100086838701610f57565b93506020850135915080821115611015575f80fd5b5061102285828601610f57565b9150509250929050565b5f602080835283518060208501525f5b818110156110585785810183015185820160400152820161103c565b505f604082860101526040601f19601f8301168501019250505092915050565b5f8060408385031215611089575f80fd5b823561109481610f40565b946020939093013593505050565b5f602082840312156110b2575f80fd5b813561092c81610f40565b634e487b7160e01b5f52603260045260245ffd5b600181811c908216806110e557607f821691505b60208210810361110357634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611119575f80fd5b815161092c81610f40565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761033857610338611124565b634e487b7160e01b5f52601260045260245ffd5b5f826111715761117161114f565b500490565b8082018082111561033857610338611124565b5f60208284031215611199575f80fd5b5051919050565b5f60a082840312156111b0575f80fd5b60405160a0810181811067ffffffffffffffff821117156111d3576111d3610ed8565b60405282516111e181610f40565b815260208301516111f181610f40565b6020820152604083015161120481610f40565b6040820152606083015161121781610f40565b60608201526080928301519281019290925250919050565b8082025f8212600160ff1b8414161561124a5761124a611124565b818105831482151761033857610338611124565b5f8261126c5761126c61114f565b600160ff1b82145f198414161561128557611285611124565b500590565b80516001600160801b03811681146112a0575f80fd5b919050565b5f60c082840312156112b5575f80fd5b60405160c0810181811067ffffffffffffffff821117156112d8576112d8610ed8565b6040526112e48361128a565b81526112f26020840161128a565b60208201526113036040840161128a565b60408201526113146060840161128a565b60608201526113256080840161128a565b608082015261133660a0840161128a565b60a08201529392505050565b8082018281125f83128015821682158216171561136157611361611124565b505092915050565b82516001600160a01b039081168252602080850151821681840152604080860151831681850152606080870151909316838501526080958601518685015284516001600160801b0390811660a08087019190915292860151811660c086015290850151811660e08501529184015182166101008401529383015181166101208301529190920151166101408201526101600190565b8181038181111561033857610338611124565b5f60208284031215611421575f80fd5b81516bffffffffffffffffffffffff8116811461092c575f80fd5b602080825282518282018190525f9190848201906040850190845b8181101561147357835183529284019291840191600101611457565b50909695505050505050565b5f6020808385031215611490575f80fd5b825167ffffffffffffffff8111156114a6575f80fd5b8301601f810185136114b6575f80fd5b80516114c4610f7682610f1d565b81815260059190911b820183019083810190878311156114e2575f80fd5b928401925b828410156107ef578351825292840192908401906114e7565b6001600160801b0381811683821601908082111561152057611520611124565b509291505056fea2646970667358221220e57e5f3cab9f778849995a83200c232f7391110ff0157563c5567c4fd7650c8e64736f6c63430008170033
Deployed Bytecode Sourcemap
179912:4233:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;183865:277;;;;;;:::i;:::-;;:::i;:::-;;82274:18;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;181150:489;;;;;;:::i;:::-;;:::i;:::-;;;3116:25:1;;;3104:2;3089:18;181150:489:0;2970:177:1;14504:25:0;;;;;-1:-1:-1;;;;;14504:25:0;;;;;;-1:-1:-1;;;;;3316:32:1;;;3298:51;;3286:2;3271:18;14504:25:0;3152:203:1;181953:1904:0;;;;;;:::i;:::-;;:::i;180400:24::-;;;;;;180343:48;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;180343:48:0;;;14893:325;;;;;;:::i;:::-;;:::i;181647:298::-;;;;;;:::i;:::-;;:::i;183865:277::-;14200:18;:16;:18::i;:::-;184023:9:::1;184018:117;184042:7;:14;184038:1;:18;184018:117;;;184106:14;184121:1;184106:17;;;;;;;;:::i;:::-;;;;;;;184078:13;:25;184092:7;184100:1;184092:10;;;;;;;;:::i;:::-;;::::0;;::::1;::::0;;;;;;;-1:-1:-1;;;;;184078:25:0;;::::1;::::0;;;;::::1;::::0;;;;;;-1:-1:-1;184078:25:0;:45;;-1:-1:-1;;;;;;184078:45:0::1;::::0;;;::::1;::::0;;;::::1;::::0;;-1:-1:-1;184058:3:0::1;184018:117;;;;183865:277:::0;;:::o;82274:18::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;181150:489::-;181277:7;181297:14;181332:9;-1:-1:-1;;;;;181314:34:0;;:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181297:53;;181361:23;181387:71;181420:6;181441;181387:18;:71::i;:::-;181361:97;;181518:19;180223:6;181541:22;181556:6;181541:14;:22::i;:::-;:30;;181566:5;181541:30;:::i;:::-;181540:42;;;;:::i;:::-;181518:64;-1:-1:-1;181602:29:0;181616:15;181518:64;181602:29;:::i;:::-;181595:36;;;;;181150:489;;;;;:::o;181953:1904::-;182066:7;182086:22;182123:6;182086:44;;182141:19;182163:10;-1:-1:-1;;;;;182163:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;182141:54;;182206:19;182228:10;-1:-1:-1;;;;;182228:22:0;;:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;182206:46;;182265:12;182297:9;182292:1386;182316:11;182312:1;:15;182292:1386;;;182357:27;;-1:-1:-1;;;182357:27:0;;;;;3116:25:1;;;182349:5:0;;-1:-1:-1;;;;;182357:24:0;;;;;3089:18:1;;182357:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;182434;;-1:-1:-1;;;182434:27:0;;;;;3116:25:1;;;182349:35:0;;-1:-1:-1;182399:32:0;;180135:42;;182434:23;;3089:18:1;;182434:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;182482:16;;;;182399:62;;-1:-1:-1;;;;;;182482:30:0;182478:44;;182514:8;;;;182478:44;182539:22;182564:98;180135:42;182610:12;182641:6;182564:27;:98::i;:::-;182539:123;;182683:14;182701:1;182683:19;182679:33;;182704:8;;;;;182679:33;182729:19;182811:11;182752:31;182777:6;182759:14;182752:31;:::i;:::-;182751:72;;;;:::i;:::-;182863:17;;-1:-1:-1;;;182863:17:0;;;;;3116:25:1;;;182729:94:0;;-1:-1:-1;182840:20:0;;180135:42;;182863:13;;3089:18:1;;182863:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;182840:40;;182940:23;183066:12;183037:6;:24;;;-1:-1:-1;;;;;183029:33:0;183022:56;;;;:::i;:::-;-1:-1:-1;;;;;183127:42:0;;;;183212:16;;;;183207:108;;-1:-1:-1;;;183207:108:0;;182940:172;;-1:-1:-1;183127:24:0;;-1:-1:-1;;;;;183207:37:0;;;;;;:108;;183212:12;;183127:6;;183207:108;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183186:129;-1:-1:-1;183330:17:0;183350:29;180324:10;183186:129;183350:29;:::i;:::-;183330:49;;183396:17;180268:4;;183525:6;:10;;;-1:-1:-1;;;;;183519:16:0;180268:4;183519:16;;;;:::i;:::-;183482:15;-1:-1:-1;;;;;183447:50:0;180268:4;183448:6;:24;;;-1:-1:-1;;;;;183448:30:0;;;;;:::i;:::-;183447:50;;;;:::i;:::-;183417:81;;:9;:81;:::i;:::-;:119;;;;:::i;:::-;183416:144;;;;:::i;:::-;:167;;;;:::i;:::-;183396:187;-1:-1:-1;183628:37:0;183653:12;183635:14;183628:37;:::i;:::-;183608:58;;:9;:58;:::i;:::-;183600:66;;;;:::i;:::-;;;182334:1344;;;;;;;;;182292:1386;182329:3;;182292:1386;;;;180268:4;183828:6;-1:-1:-1;;;;;183816:23:0;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183810:31;;;;180268:4;183810:31;:::i;:::-;183759:28;183781:6;183766:11;183759:28;:::i;:::-;183744:44;;:4;:44;:::i;:::-;183743:99;;;;:::i;:::-;183742:107;;;;:::i;:::-;183722:127;181953:1904;-1:-1:-1;;;;;;;181953:1904:0:o;14893:325::-;14200:18;:16;:18::i;:::-;-1:-1:-1;;;;;15012:28:0;::::1;15004:53;;;::::0;-1:-1:-1;;;15004:53:0;;10157:2:1;15004:53:0::1;::::0;::::1;10139:21:1::0;10196:2;10176:18;;;10169:30;-1:-1:-1;;;10215:18:1;;;10208:42;10267:18;;15004:53:0::1;;;;;;;;;15068:21;15092:10:::0;;-1:-1:-1;;;;;15113:27:0;;::::1;-1:-1:-1::0;;;;;;15113:27:0;::::1;::::0;::::1;::::0;;15158:52:::1;::::0;15092:10;;;::::1;::::0;;;15158:52:::1;::::0;15068:21;15158:52:::1;14993:225;14893:325:::0;:::o;181647:298::-;-1:-1:-1;;;;;181760:21:0;;;181716:7;181760:21;;;:13;:21;;;;;;181716:7;;181760:21;;181792:68;;-1:-1:-1;181847:1:0;;181647:298;-1:-1:-1;;181647:298:0:o;181792:68::-;181879:58;;-1:-1:-1;;;181879:58:0;;-1:-1:-1;;;;;3316:32:1;;;181879:58:0;;;3298:51:1;181879:50:0;;;;;3271:18:1;;181879:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;181872:65;181647:298;-1:-1:-1;;;181647:298:0:o;14307:117::-;14376:10;;-1:-1:-1;;;;;14376:10:0;14390;14376:24;14368:48;;;;-1:-1:-1;;;14368:48:0;;10498:2:1;14368:48:0;;;10480:21:1;10537:2;10517:18;;;10510:30;-1:-1:-1;;;10556:18:1;;;10549:41;10607:18;;14368:48:0;10296:335:1;14368:48:0;14307:117::o;168334:517::-;168485:7;168505:5;168513:17;:12;85480:26;85421:100;;;85248:291;168513:17;168505:25;-1:-1:-1;168541:20:0;168564:29;-1:-1:-1;;;;;168564:19:0;;168505:25;168588:4;168564:19;:29::i;:::-;168541:52;;168619:25;168659;168716:44;168739:6;168747:12;168716:22;:44::i;:::-;-1:-1:-1;168604:156:0;;-1:-1:-1;168604:156:0;-1:-1:-1;168780:63:0;;-1:-1:-1;168780:12:0;168604:156;;168780:25;:63::i;:::-;168773:70;168334:517;-1:-1:-1;;;;;;;;168334:517:0:o;112199:303::-;112315:7;112335:21;112359:83;112380:51;112422:2;112426:4;112380:41;:51::i;:::-;112359:6;:83::i;:::-;112468:22;;-1:-1:-1;;;112468:22:0;;112335:107;;-1:-1:-1;;;;;;112468:16:0;;;;;:22;;112335:107;;112468:22;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;112468:22:0;;;;;;;;;;;;:::i;:::-;112491:1;112468:25;;;;;;;;:::i;:::-;;;;;;;112460:34;;112453:41;;;112199:303;;;;;:::o;165010:1751::-;165140:7;165149;165158;165167;165187:5;165195:17;:12;85480:26;85421:100;;;85248:291;165195:17;165246;;-1:-1:-1;;;165246:17:0;;;;;3116:25:1;;;165187::0;;-1:-1:-1;165223:20:0;;-1:-1:-1;;;;;165246:13:0;;;;;3089:18:1;;165246:17:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165223:40;;165276:15;165312:6;:17;;;-1:-1:-1;;;;;165294:35:0;:15;:35;;;;:::i;:::-;165276:53;-1:-1:-1;165479:12:0;;;;;:58;;-1:-1:-1;165508:24:0;;;;-1:-1:-1;;;;;165508:29:0;;;165479:58;:105;;;;-1:-1:-1;165554:16:0;;;;-1:-1:-1;;;;;165554:30:0;;;165479:105;165461:1106;;;165637:16;;;;165632:108;;-1:-1:-1;;;165632:108:0;;165611:18;;-1:-1:-1;;;;;165632:37:0;;;;:108;;165637:12;;165719:6;;165632:108;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;165611:129;-1:-1:-1;165755:16:0;165774:104;165826:37;165611:129;165855:7;165826:28;:37::i;:::-;165774:24;;;;-1:-1:-1;;;;;165774:33:0;;;:104::i;:::-;165755:123;;165921:20;:8;:18;:20::i;:::-;165893:6;:24;;:48;;;;;;;:::i;:::-;-1:-1:-1;;;;;165893:48:0;;;-1:-1:-1;165984:20:0;:8;:18;:20::i;:::-;165956:48;;:6;;:48;;;;;:::i;:::-;-1:-1:-1;;;;;165956:48:0;;;;;;166025:10;;;;:15;;;-1:-1:-1;166021:535:0;;166061:17;166081:29;166099:6;:10;;;-1:-1:-1;;;;;166081:29:0;:8;:17;;:29;;;;:::i;:::-;166061:49;;166305:17;166325:147;166397:9;166370:6;:24;;;-1:-1:-1;;;;;166370:36:0;;;;;:::i;:::-;166429:24;;;;166325:9;;:147;-1:-1:-1;;;;;166325:147:0;:22;:147::i;:::-;166305:167;;166519:21;:9;:19;:21::i;:::-;166491:6;:24;;:49;;;;;;;:::i;:::-;-1:-1:-1;;;;;166491:49:0;;;-1:-1:-1;;;166021:535:0;165596:971;;165461:1106;-1:-1:-1;166601:24:0;;166640;;;;166679;;;;166718;;;;;-1:-1:-1;;;;;166579:174:0;;;;;;;;-1:-1:-1;166579:174:0;;;;-1:-1:-1;166579:174:0;;;-1:-1:-1;165010:1751:0;-1:-1:-1;;;;165010:1751:0:o;92812:311::-;92949:7;92989:126;93025:28;92323:1;93025:11;:28;:::i;:::-;93072;92136:3;93072:11;:28;:::i;:::-;92989:6;;:126;:17;:126::i;:::-;92969:146;92812:311;-1:-1:-1;;;;92812:311:0:o;87290:466::-;87393:7;86747:1;87566:4;87622:2;86077:1;87611:29;;;;;;;;12557:25:1;;;12613:2;12598:18;;12591:34;12545:2;12530:18;;12361:270;87611:29:0;;;;-1:-1:-1;;87611:29:0;;;;;;;;;87601:40;;87611:29;87601:40;;;;-1:-1:-1;;;;;12828:32:1;;;87525:143:0;;;12810:51:1;12877:18;;12870:34;;;;12783:18;;87525:143:0;;;;;;;;;;;;87489:202;;;;;;87459:251;;:274;;;;:::i;114923:167::-;115024:16;;;115038:1;115024:16;;;;;;;;;114972;;115001:20;;115024:16;;;;;;;;;;;;-1:-1:-1;115024:16:0;115001:39;;115060:1;115051:3;115055:1;115051:6;;;;;;;;:::i;:::-;;;;;;;;;;:10;115079:3;114923:167;-1:-1:-1;;114923:167:0:o;70468:350::-;70565:7;;70605:5;70609:1;70605;:5;:::i;:::-;70585:25;-1:-1:-1;70621:18:0;70642:41;70585:25;;70675:7;69148:4;70675:1;:7;:::i;:::-;70642:10;:41::i;:::-;70621:62;-1:-1:-1;70694:17:0;70714:42;70621:62;70737:9;70748:7;69148:4;70748:1;:7;:::i;70714:42::-;70694:62;-1:-1:-1;70694:62:0;70776:22;70788:10;70776:9;:22;:::i;:::-;:34;;;;:::i;69377:119::-;69440:7;69467:21;69478:1;69481;69148:4;69467:10;:21::i;99129:172::-;99234:30;;;;;;;;;;;;-1:-1:-1;;;99234:30:0;;;;99182:7;;-1:-1:-1;;;;;99210:22:0;;;99202:63;;;;-1:-1:-1;;;99202:63:0;;;;;;;;:::i;:::-;-1:-1:-1;99291:1:0;;99129:172;-1:-1:-1;99129:172:0:o;92413:311::-;92550:7;92590:126;92626:28;92136:3;92626:11;:28;:::i;:::-;92673;92323:1;92673:11;:28;:::i;69918:156::-;70028:7;70065:1;70056:5;70060:1;70056;:5;:::i;:::-;70055:11;;;;:::i;14:127:1:-;75:10;70:3;66:20;63:1;56:31;106:4;103:1;96:15;130:4;127:1;120:15;146:275;217:2;211:9;282:2;263:13;;-1:-1:-1;;259:27:1;247:40;;317:18;302:34;;338:22;;;299:62;296:88;;;364:18;;:::i;:::-;400:2;393:22;146:275;;-1:-1:-1;146:275:1:o;426:183::-;486:4;519:18;511:6;508:30;505:56;;;541:18;;:::i;:::-;-1:-1:-1;586:1:1;582:14;598:4;578:25;;426:183::o;614:131::-;-1:-1:-1;;;;;689:31:1;;679:42;;669:70;;735:1;732;725:12;669:70;614:131;:::o;750:743::-;804:5;857:3;850:4;842:6;838:17;834:27;824:55;;875:1;872;865:12;824:55;911:6;898:20;937:4;961:60;977:43;1017:2;977:43;:::i;:::-;961:60;:::i;:::-;1043:3;1067:2;1062:3;1055:15;1095:4;1090:3;1086:14;1079:21;;1152:4;1146:2;1143:1;1139:10;1131:6;1127:23;1123:34;1109:48;;1180:3;1172:6;1169:15;1166:35;;;1197:1;1194;1187:12;1166:35;1233:4;1225:6;1221:17;1247:217;1263:6;1258:3;1255:15;1247:217;;;1343:3;1330:17;1360:31;1385:5;1360:31;:::i;:::-;1404:18;;1442:12;;;;1280;;1247:217;;;-1:-1:-1;1482:5:1;750:743;-1:-1:-1;;;;;;750:743:1:o;1498:595::-;1616:6;1624;1677:2;1665:9;1656:7;1652:23;1648:32;1645:52;;;1693:1;1690;1683:12;1645:52;1733:9;1720:23;1762:18;1803:2;1795:6;1792:14;1789:34;;;1819:1;1816;1809:12;1789:34;1842:61;1895:7;1886:6;1875:9;1871:22;1842:61;:::i;:::-;1832:71;;1956:2;1945:9;1941:18;1928:32;1912:48;;1985:2;1975:8;1972:16;1969:36;;;2001:1;1998;1991:12;1969:36;;2024:63;2079:7;2068:8;2057:9;2053:24;2024:63;:::i;:::-;2014:73;;;1498:595;;;;;:::o;2098:548::-;2210:4;2239:2;2268;2257:9;2250:21;2300:6;2294:13;2343:6;2338:2;2327:9;2323:18;2316:34;2368:1;2378:140;2392:6;2389:1;2386:13;2378:140;;;2487:14;;;2483:23;;2477:30;2453:17;;;2472:2;2449:26;2442:66;2407:10;;2378:140;;;2382:3;2567:1;2562:2;2553:6;2542:9;2538:22;2534:31;2527:42;2637:2;2630;2626:7;2621:2;2613:6;2609:15;2605:29;2594:9;2590:45;2586:54;2578:62;;;;2098:548;;;;:::o;2651:314::-;2718:6;2726;2779:2;2767:9;2758:7;2754:23;2750:32;2747:52;;;2795:1;2792;2785:12;2747:52;2834:9;2821:23;2853:31;2878:5;2853:31;:::i;:::-;2903:5;2955:2;2940:18;;;;2927:32;;-1:-1:-1;;;2651:314:1:o;3360:247::-;3419:6;3472:2;3460:9;3451:7;3447:23;3443:32;3440:52;;;3488:1;3485;3478:12;3440:52;3527:9;3514:23;3546:31;3571:5;3546:31;:::i;3612:127::-;3673:10;3668:3;3664:20;3661:1;3654:31;3704:4;3701:1;3694:15;3728:4;3725:1;3718:15;3744:380;3823:1;3819:12;;;;3866;;;3887:61;;3941:4;3933:6;3929:17;3919:27;;3887:61;3994:2;3986:6;3983:14;3963:18;3960:38;3957:161;;4040:10;4035:3;4031:20;4028:1;4021:31;4075:4;4072:1;4065:15;4103:4;4100:1;4093:15;3957:161;;3744:380;;;:::o;4129:251::-;4199:6;4252:2;4240:9;4231:7;4227:23;4223:32;4220:52;;;4268:1;4265;4258:12;4220:52;4300:9;4294:16;4319:31;4344:5;4319:31;:::i;4385:127::-;4446:10;4441:3;4437:20;4434:1;4427:31;4477:4;4474:1;4467:15;4501:4;4498:1;4491:15;4517:168;4590:9;;;4621;;4638:15;;;4632:22;;4618:37;4608:71;;4659:18;;:::i;4690:127::-;4751:10;4746:3;4742:20;4739:1;4732:31;4782:4;4779:1;4772:15;4806:4;4803:1;4796:15;4822:120;4862:1;4888;4878:35;;4893:18;;:::i;:::-;-1:-1:-1;4927:9:1;;4822:120::o;4947:125::-;5012:9;;;5033:10;;;5030:36;;;5046:18;;:::i;5077:184::-;5147:6;5200:2;5188:9;5179:7;5175:23;5171:32;5168:52;;;5216:1;5213;5206:12;5168:52;-1:-1:-1;5239:16:1;;5077:184;-1:-1:-1;5077:184:1:o;5681:972::-;5780:6;5833:3;5821:9;5812:7;5808:23;5804:33;5801:53;;;5850:1;5847;5840:12;5801:53;5883:2;5877:9;5925:3;5917:6;5913:16;5995:6;5983:10;5980:22;5959:18;5947:10;5944:34;5941:62;5938:88;;;6006:18;;:::i;:::-;6042:2;6035:22;6079:16;;6104:31;6079:16;6104:31;:::i;:::-;6144:21;;6210:2;6195:18;;6189:25;6223:33;6189:25;6223:33;:::i;:::-;6284:2;6272:15;;6265:32;6342:2;6327:18;;6321:25;6355:33;6321:25;6355:33;:::i;:::-;6416:2;6404:15;;6397:32;6474:2;6459:18;;6453:25;6487:33;6453:25;6487:33;:::i;:::-;6548:2;6536:15;;6529:32;6616:3;6601:19;;;6595:26;6577:16;;;6570:52;;;;-1:-1:-1;6540:6:1;5681:972;-1:-1:-1;5681:972:1:o;6658:237::-;6730:9;;;6697:7;6755:9;;-1:-1:-1;;;6766:18:1;;6751:34;6748:60;;;6788:18;;:::i;:::-;6861:1;6852:7;6847:16;6844:1;6841:23;6837:1;6830:9;6827:38;6817:72;;6869:18;;:::i;6900:193::-;6939:1;6965;6955:35;;6970:18;;:::i;:::-;-1:-1:-1;;;7006:18:1;;-1:-1:-1;;7026:13:1;;7002:38;6999:64;;;7043:18;;:::i;:::-;-1:-1:-1;7077:10:1;;6900:193::o;7098:192::-;7177:13;;-1:-1:-1;;;;;7219:46:1;;7209:57;;7199:85;;7280:1;7277;7270:12;7199:85;7098:192;;;:::o;7295:885::-;7388:6;7441:3;7429:9;7420:7;7416:23;7412:33;7409:53;;;7458:1;7455;7448:12;7409:53;7491:2;7485:9;7533:3;7525:6;7521:16;7603:6;7591:10;7588:22;7567:18;7555:10;7552:34;7549:62;7546:88;;;7614:18;;:::i;:::-;7650:2;7643:22;7689:40;7719:9;7689:40;:::i;:::-;7681:6;7674:56;7763:49;7808:2;7797:9;7793:18;7763:49;:::i;:::-;7758:2;7750:6;7746:15;7739:74;7846:49;7891:2;7880:9;7876:18;7846:49;:::i;:::-;7841:2;7833:6;7829:15;7822:74;7929:49;7974:2;7963:9;7959:18;7929:49;:::i;:::-;7924:2;7916:6;7912:15;7905:74;8013:50;8058:3;8047:9;8043:19;8013:50;:::i;:::-;8007:3;7999:6;7995:16;7988:76;8098:50;8143:3;8132:9;8128:19;8098:50;:::i;:::-;8092:3;8080:16;;8073:76;8084:6;7295:885;-1:-1:-1;;;7295:885:1:o;8185:216::-;8249:9;;;8277:11;;;8224:3;8307:9;;8335:10;;8331:19;;8360:10;;8352:19;;8328:44;8325:70;;;8375:18;;:::i;:::-;8325:70;;8185:216;;;;:::o;8406:1110::-;8745:13;;-1:-1:-1;;;;;8741:22:1;;;8723:41;;8824:4;8812:17;;;8806:24;8802:33;;8780:20;;;8773:63;8896:4;8884:17;;;8878:24;8874:33;;8852:20;;;8845:63;8968:4;8956:17;;;8950:24;8946:33;;;8924:20;;;8917:63;9036:4;9024:17;;;9018:24;8996:20;;;8989:54;9137:13;;-1:-1:-1;;;;;9133:22:1;;;8703:3;9112:19;;;9105:51;;;;9203:17;;;9197:24;9193:33;;9187:3;9172:19;;9165:62;9274:17;;;9268:24;9264:33;;9258:3;9243:19;;9236:62;9345:17;;;9339:24;9335:33;;9329:3;9314:19;;9307:62;9416:17;;;9410:24;9406:33;;9400:3;9385:19;;9378:62;9487:16;;;;9481:23;9477:32;9471:3;9456:19;;9449:61;8672:3;8657:19;;8406:1110::o;9521:128::-;9588:9;;;9609:11;;;9606:37;;;9623:18;;:::i;9654:296::-;9723:6;9776:2;9764:9;9755:7;9751:23;9747:32;9744:52;;;9792:1;9789;9782:12;9744:52;9824:9;9818:16;9874:26;9867:5;9863:38;9856:5;9853:49;9843:77;;9916:1;9913;9906:12;10636:632;10807:2;10859:21;;;10929:13;;10832:18;;;10951:22;;;10778:4;;10807:2;11030:15;;;;11004:2;10989:18;;;10778:4;11073:169;11087:6;11084:1;11081:13;11073:169;;;11148:13;;11136:26;;11217:15;;;;11182:12;;;;11109:1;11102:9;11073:169;;;-1:-1:-1;11259:3:1;;10636:632;-1:-1:-1;;;;;;10636:632:1:o;11273:881::-;11368:6;11399:2;11442;11430:9;11421:7;11417:23;11413:32;11410:52;;;11458:1;11455;11448:12;11410:52;11491:9;11485:16;11524:18;11516:6;11513:30;11510:50;;;11556:1;11553;11546:12;11510:50;11579:22;;11632:4;11624:13;;11620:27;-1:-1:-1;11610:55:1;;11661:1;11658;11651:12;11610:55;11690:2;11684:9;11713:60;11729:43;11769:2;11729:43;:::i;11713:60::-;11807:15;;;11889:1;11885:10;;;;11877:19;;11873:28;;;11838:12;;;;11913:19;;;11910:39;;;11945:1;11942;11935:12;11910:39;11969:11;;;;11989:135;12005:6;12000:3;11997:15;11989:135;;;12071:10;;12059:23;;12022:12;;;;12102;;;;11989:135;;12159:197;-1:-1:-1;;;;;12281:10:1;;;12293;;;12277:27;;12316:11;;;12313:37;;;12330:18;;:::i;:::-;12313:37;12159:197;;;;:::o
Swarm Source
ipfs://e57e5f3cab9f778849995a83200c232f7391110ff0157563c5567c4fd7650c8e
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.