ETH Price: $4,516.25 (+1.49%)

Contract

0x89202AC5577E4Cadee1A327A0b9C1dABbbD07e5E

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
130966292025-10-07 12:17:2034 hrs ago1759839440  Contract Creation0 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VaultV2

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 100000 runs

Other Settings:
cancun EvmVersion
File 1 of 13 : VaultV2.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity 0.8.28;

import {IVaultV2, IERC20, Caps} from "./interfaces/IVaultV2.sol";
import {IAdapter} from "./interfaces/IAdapter.sol";
import {IAdapterRegistry} from "./interfaces/IAdapterRegistry.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import "./libraries/ConstantsLib.sol";
import {MathLib} from "./libraries/MathLib.sol";
import {SafeERC20Lib} from "./libraries/SafeERC20Lib.sol";
import {IReceiveSharesGate, ISendSharesGate, IReceiveAssetsGate, ISendAssetsGate} from "./interfaces/IGate.sol";

/// ERC4626
/// @dev The vault is compliant with ERC-4626 and with ERC-2612 (permit extension). Though the vault has a
/// non-conventional behaviour on max functions: they always return zero.
/// @dev totalSupply is not updated to include shares minted to fee recipients. One can call accrueInterestView to
/// compute the updated totalSupply.
///
/// TOTAL ASSETS
/// @dev Adapters are responsible for reporting to the vault how much their investments are worth at any time, so that
/// the vault can accrue interest or realize losses.
/// @dev _totalAssets stores the last recorded total assets. Use totalAssets() for the updated total assets.
/// @dev Upon interest accrual, the vault loops through adapters' realAssets(). If there are too many adapters and/or
/// they consume too much gas on realAssets(), it could cause issues such as expensive interactions, even DOS.
///
/// LOSS REALIZATION
/// @dev Loss realization occurs in accrueInterest and decreases the total assets, causing shares to lose value.
/// @dev Vault shares should not be loanable to prevent shares shorting on loss realization. Shares can be flashloanable
/// because flashloan-based shorting is prevented as interests and losses are only accounted once per transaction.
///
/// SHARE PRICE
/// @dev The share price can go down if the vault incurs some losses. Users might want to perform slippage checks upon
/// withdraw/redeem via an other contract.
/// @dev Interest/loss are accounted only once per transaction (at the first interaction with the vault).
/// @dev Donations increase the share price but not faster than the maxRate.
/// @dev The vault has 1 virtual asset and a decimal offset of max(0, 18 - assetDecimals). In order to protect against
/// inflation attacks, the vault might need to be seeded with an initial deposit. See
/// https://docs.openzeppelin.com/contracts/5.x/erc4626#inflation-attack
/// @dev If they make the rate increase by a large factor, donations and forceDeallocate penalties can be in part stolen
/// by opportunistic depositors. Setting a low maxRate prevents that by making the donation/penalty distributed over a
/// long period.
///
/// CAPS
/// @dev Ids have an asset allocation, and can be absolutely capped and/or relatively capped.
/// @dev The allocation is not always up to date, because interest and losses are accounted only when (de)allocating in
/// the corresponding markets.
/// @dev The caps are checked on allocate (where allocations can increase) for the ids returned by the adapter.
/// @dev Relative caps are "soft" in the sense that they are not checked on exit.
/// @dev Caps can be exceeded because of interest.
/// @dev The relative cap is relative to firstTotalAssets, not realAssets.
/// @dev The relative cap unit is WAD.
/// @dev To track allocations using events, use the Allocate and Deallocate events only.
///
/// FIRST TOTAL ASSETS
/// @dev The variable firstTotalAssets tracks the total assets after the first interest accrual of the transaction.
/// @dev Used to implement a mechanism that prevents bypassing relative caps with flashloans. This mechanism makes the
/// caps conservative and can generate false positives, notably for big deposits that go through the liquidity adapter.
/// @dev Also used to accrue interest only once per transaction (see the "share price" section).
/// @dev Relative caps can still be manipulated by allocators (with short-term deposits), but it requires capital.
/// @dev The behavior of firstTotalAssets is different when the vault has totalAssets=0, but it does not matter
/// internally because in this case there are no investments to cap.
///
/// ADAPTERS
/// @dev Loose specification of adapters:
/// - They must enforce that only the vault can call allocate/deallocate.
/// - They must enter/exit markets only in allocate/deallocate.
/// - They must return the right ids on allocate/deallocate. Returned ids must not repeat.
/// - After a call to deallocate, the vault must have an approval to transfer at least `assets` from the adapter.
/// - They must make it possible to make deallocate possible (for in-kind redemptions).
/// - The totalAssets() calculation ignores markets for which the vault has no allocation.
/// - They must not re-enter (directly or indirectly) the vault. They might not statically prevent it, but the curator
/// must not interact with markets that can re-enter the vault.
/// - After an update, the sum of the changes returned after interactions with a given market must be exactly the
/// current estimated position.
/// @dev Ids being reused are useful to cap multiple investments that have a common property.
/// @dev Allocating is prevented if one of the ids' absolute cap is zero and deallocating is prevented if the id's
/// allocation is zero. This prevents interactions with zero assets with unknown markets. For markets that share all
/// their ids, it will be impossible to "disable" them (preventing any interaction) without disabling the others using
/// the same ids.
/// @dev On allocate or deallocate, the adapters might lose some assets (total realAssets decreases), for instance due
/// to roundings or entry/exit fees. This loss should stay negligible compared to gas. Adapters might not statically
/// ensure this, but the curators should not interact with markets that can create big entry/exit losses.
/// @dev Except particular scenarios, adapters should be removed only if they have no assets. In order to ensure no
/// allocator can allocate some assets in an adapter being removed, there should be an id exclusive to the adapter with
/// its cap set to zero.
///
/// ADAPTER REGISTRY
/// @dev An adapter registry can be added to restrict the adapters. This is useful to commit to using only a certain
/// type of adapters for example.
/// @dev If adapterRegistry is set to address(0), the vault can have any adapters.
/// @dev When an adapterRegistry is set, it retroactively checks already added adapters.
/// @dev If the adapterRegistry now returns false for an already added adapter, it doesn't impact the vault's
/// functioning.
/// @dev The invariant that adapters of the vault are all in the registry holds only if the registry cannot remove
/// adapters (is "add only").
///
/// LIQUIDITY ADAPTER
/// @dev Liquidity is allocated to the liquidityAdapter on deposit/mint, and deallocated from the liquidityAdapter on
/// withdraw/redeem if idle assets don't cover the withdrawal.
/// @dev The liquidity adapter is useful on exit, so that exit liquidity is available in addition to the idle assets. But
/// the same adapter/data is used for both entry and exit to have the property that in the general case looping
/// supply-withdraw or withdraw-supply should not change the allocation.
/// @dev If a cap (absolute or relative) associated with the ids returned by the liquidity adapter on the liquidity data
/// is reached, deposit/mint will revert. In particular, when the vault is empty or almost empty, the relative cap check
/// is likely to make deposits revert.
///
/// TOKEN REQUIREMENTS
/// @dev List of assumptions on the token that guarantees that the vault behaves as expected:
/// - It should be ERC-20 compliant, except that it can omit return values on transfer and transferFrom.
/// - The balance of the vault should only decrease on transfer and transferFrom.
/// - It should not re-enter the vault on transfer or transferFrom.
/// - The 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.
///
/// LIVENESS REQUIREMENTS
/// @dev List of assumptions that guarantees the vault's liveness properties:
/// - Adapters should not revert on realAssets.
/// - The token should not revert on transfer and transferFrom if balances and approvals are right.
/// - The token should not revert on transfer to self.
/// - totalAssets and totalSupply must stay below ~10^35. Initially there are min(1, 10^(18-decimals)) shares per asset.
/// - The vault is pinged at least every 10 years.
/// - Adapters must not revert on deallocate if the underlying markets are liquid.
///
/// TIMELOCKS
/// @dev The timelock duration of decreaseTimelock is the timelock duration of the function whose timelock is being
/// decreased (e.g. the timelock of decreaseTimelock(addAdapter, ...) is timelock[addAdapter]).
/// @dev Multiple clashing data can be pending, for example increaseCap and decreaseCap, which can make so accepted
/// timelocked data can potentially be changed shortly afterwards.
/// @dev If a function is abdicated, it cannot be called no matter its timelock and what executableAt[data] contains.
/// Otherwise, the minimum time in which a function can be called is the following:
/// min(
///     timelock[selector],
///     executableAt[selector::_],
///     executableAt[decreaseTimelock::selector::newTimelock] + newTimelock
/// ).
/// @dev Nothing is checked on the timelocked data, so it could be not executable (function does not exist, argument
/// encoding is wrong, function' conditions are not met, etc.).
///
/// ABDICATION
/// @dev When a timelocked function is abdicated, it can't be called anymore.
/// @dev It is still possible to submit data for it or change its timelock, but it will not be executable / effective.
///
/// GATES
/// @dev Set to 0 to disable a gate.
/// @dev Gates must never revert, nor consume too much gas.
/// @dev receiveSharesGate:
///     - Gates receiving shares.
///     - Can lock users out of getting back their shares deposited on an other contract.
/// @dev sendSharesGate:
///     - Gates sending shares.
///     - Can lock users out of exiting the vault.
/// @dev receiveAssetsGate:
///     - Gates withdrawing assets from the vault.
///     - The vault itself (address(this)) is always allowed to receive assets, regardless of the gate configuration.
///     - Can lock users out of exiting the vault.
/// @dev sendAssetsGate:
///     - Gates depositing assets to the vault.
///     - This gate is not critical (cannot block users' funds), while still being able to gate supplies.
///
/// FEES
/// @dev Fees unit is WAD.
/// @dev This invariant holds for both fees: fee != 0 => recipient != address(0).
///
/// ROLES
/// @dev The owner cannot do actions that can directly hurt depositors. Though it can set the curator and sentinels.
/// @dev The curator cannot do actions that can directly hurt depositors without going through a timelock.
/// @dev Allocators can move funds between markets in the boundaries set by caps without going through timelocks. They
/// can also set the liquidity adapter and data, which can prevent deposits and/or withdrawals (it cannot prevent
/// "in-kind redemptions" with forceDeallocate though). Allocators also set the maxRate.
/// @dev Warning: if setIsAllocator is timelocked, removing an allocator will take time.
/// @dev Roles are not "two-step", so anyone can give a role to anyone, but it does not mean that they will exercise it.
///
/// MISC
/// @dev Zero checks are not systematically performed.
/// @dev No-ops are allowed.
/// @dev NatSpec comments are included only when they bring clarity.
/// @dev The contract uses transient storage.
/// @dev At creation, all settings are set to their default values. Notably, timelocks are zero which is useful to set
/// up the vault quickly. Also, there are no gates so anybody can interact with the vault. To prevent that, the gates
/// configuration can be batched with the vault creation.
contract VaultV2 is IVaultV2 {
    using MathLib for uint256;
    using MathLib for uint128;
    using MathLib for int256;

    /* IMMUTABLE */

    address public immutable asset;
    uint8 public immutable decimals;
    uint256 public immutable virtualShares;

    /* ROLES STORAGE */

    address public owner;
    address public curator;
    address public receiveSharesGate;
    address public sendSharesGate;
    address public receiveAssetsGate;
    address public sendAssetsGate;
    address public adapterRegistry;
    mapping(address account => bool) public isSentinel;
    mapping(address account => bool) public isAllocator;

    /* TOKEN STORAGE */

    string public name;
    string public symbol;
    uint256 public totalSupply;
    mapping(address account => uint256) public balanceOf;
    mapping(address owner => mapping(address spender => uint256)) public allowance;
    mapping(address account => uint256) public nonces;

    /* INTEREST STORAGE */

    uint256 public transient firstTotalAssets;
    uint128 public _totalAssets;
    uint64 public lastUpdate;
    uint64 public maxRate;

    /* CURATION STORAGE */

    mapping(address account => bool) public isAdapter;
    address[] public adapters;
    mapping(bytes32 id => Caps) internal caps;
    mapping(address adapter => uint256) public forceDeallocatePenalty;

    /* LIQUIDITY ADAPTER STORAGE */

    address public liquidityAdapter;
    bytes public liquidityData;

    /* TIMELOCKS STORAGE */

    mapping(bytes4 selector => uint256) public timelock;
    mapping(bytes4 selector => bool) public abdicated;
    mapping(bytes data => uint256) public executableAt;

    /* FEES STORAGE */

    uint96 public performanceFee;
    address public performanceFeeRecipient;
    uint96 public managementFee;
    address public managementFeeRecipient;

    /* GETTERS */

    function adaptersLength() external view returns (uint256) {
        return adapters.length;
    }

    function totalAssets() external view returns (uint256) {
        (uint256 newTotalAssets,,) = accrueInterestView();
        return newTotalAssets;
    }

    function DOMAIN_SEPARATOR() public view returns (bytes32) {
        return keccak256(abi.encode(DOMAIN_TYPEHASH, block.chainid, address(this)));
    }

    function absoluteCap(bytes32 id) external view returns (uint256) {
        return caps[id].absoluteCap;
    }

    function relativeCap(bytes32 id) external view returns (uint256) {
        return caps[id].relativeCap;
    }

    function allocation(bytes32 id) external view returns (uint256) {
        return caps[id].allocation;
    }

    /* MULTICALL */

    /// @dev Useful for EOAs to batch admin calls.
    /// @dev Does not return anything, because accounts who would use the return data would be contracts, which can do
    /// the multicall themselves.
    function multicall(bytes[] calldata data) external {
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory returnData) = address(this).delegatecall(data[i]);
            if (!success) {
                assembly ("memory-safe") {
                    revert(add(32, returnData), mload(returnData))
                }
            }
        }
    }

    /* CONSTRUCTOR */

    constructor(address _owner, address _asset) {
        asset = _asset;
        owner = _owner;
        lastUpdate = uint64(block.timestamp);
        uint256 assetDecimals = IERC20(_asset).decimals();
        uint256 decimalOffset = uint256(18).zeroFloorSub(assetDecimals);
        decimals = uint8(assetDecimals + decimalOffset);
        virtualShares = 10 ** decimalOffset;
        emit EventsLib.Constructor(_owner, _asset);
    }

    /* OWNER FUNCTIONS */

    function setOwner(address newOwner) external {
        require(msg.sender == owner, ErrorsLib.Unauthorized());
        owner = newOwner;
        emit EventsLib.SetOwner(newOwner);
    }

    function setCurator(address newCurator) external {
        require(msg.sender == owner, ErrorsLib.Unauthorized());
        curator = newCurator;
        emit EventsLib.SetCurator(newCurator);
    }

    function setIsSentinel(address account, bool newIsSentinel) external {
        require(msg.sender == owner, ErrorsLib.Unauthorized());
        isSentinel[account] = newIsSentinel;
        emit EventsLib.SetIsSentinel(account, newIsSentinel);
    }

    function setName(string memory newName) external {
        require(msg.sender == owner, ErrorsLib.Unauthorized());
        name = newName;
        emit EventsLib.SetName(newName);
    }

    function setSymbol(string memory newSymbol) external {
        require(msg.sender == owner, ErrorsLib.Unauthorized());
        symbol = newSymbol;
        emit EventsLib.SetSymbol(newSymbol);
    }

    /* TIMELOCKS FOR CURATOR FUNCTIONS */

    /// @dev Will revert if the timelock value is type(uint256).max or any value that overflows when added to the block
    /// timestamp.
    function submit(bytes calldata data) external {
        require(msg.sender == curator, ErrorsLib.Unauthorized());
        require(executableAt[data] == 0, ErrorsLib.DataAlreadyPending());

        bytes4 selector = bytes4(data);
        uint256 _timelock =
            selector == IVaultV2.decreaseTimelock.selector ? timelock[bytes4(data[4:8])] : timelock[selector];
        executableAt[data] = block.timestamp + _timelock;
        emit EventsLib.Submit(selector, data, executableAt[data]);
    }

    function timelocked() internal {
        bytes4 selector = bytes4(msg.data);
        require(executableAt[msg.data] != 0, ErrorsLib.DataNotTimelocked());
        require(block.timestamp >= executableAt[msg.data], ErrorsLib.TimelockNotExpired());
        require(!abdicated[selector], ErrorsLib.Abdicated());
        executableAt[msg.data] = 0;
        emit EventsLib.Accept(selector, msg.data);
    }

    function revoke(bytes calldata data) external {
        require(msg.sender == curator || isSentinel[msg.sender], ErrorsLib.Unauthorized());
        require(executableAt[data] != 0, ErrorsLib.DataNotTimelocked());
        executableAt[data] = 0;
        bytes4 selector = bytes4(data);
        emit EventsLib.Revoke(msg.sender, selector, data);
    }

    /* CURATOR FUNCTIONS */

    function setIsAllocator(address account, bool newIsAllocator) external {
        timelocked();
        isAllocator[account] = newIsAllocator;
        emit EventsLib.SetIsAllocator(account, newIsAllocator);
    }

    function setReceiveSharesGate(address newReceiveSharesGate) external {
        timelocked();
        receiveSharesGate = newReceiveSharesGate;
        emit EventsLib.SetReceiveSharesGate(newReceiveSharesGate);
    }

    function setSendSharesGate(address newSendSharesGate) external {
        timelocked();
        sendSharesGate = newSendSharesGate;
        emit EventsLib.SetSendSharesGate(newSendSharesGate);
    }

    function setReceiveAssetsGate(address newReceiveAssetsGate) external {
        timelocked();
        receiveAssetsGate = newReceiveAssetsGate;
        emit EventsLib.SetReceiveAssetsGate(newReceiveAssetsGate);
    }

    function setSendAssetsGate(address newSendAssetsGate) external {
        timelocked();
        sendAssetsGate = newSendAssetsGate;
        emit EventsLib.SetSendAssetsGate(newSendAssetsGate);
    }

    /// @dev The no-op will revert if the registry now returns false for an already added adapter.
    function setAdapterRegistry(address newAdapterRegistry) external {
        timelocked();

        if (newAdapterRegistry != address(0)) {
            for (uint256 i = 0; i < adapters.length; i++) {
                require(
                    IAdapterRegistry(newAdapterRegistry).isInRegistry(adapters[i]), ErrorsLib.NotInAdapterRegistry()
                );
            }
        }

        adapterRegistry = newAdapterRegistry;
        emit EventsLib.SetAdapterRegistry(newAdapterRegistry);
    }

    function addAdapter(address account) external {
        timelocked();
        require(
            adapterRegistry == address(0) || IAdapterRegistry(adapterRegistry).isInRegistry(account),
            ErrorsLib.NotInAdapterRegistry()
        );
        if (!isAdapter[account]) {
            adapters.push(account);
            isAdapter[account] = true;
        }
        emit EventsLib.AddAdapter(account);
    }

    function removeAdapter(address account) external {
        timelocked();
        if (isAdapter[account]) {
            for (uint256 i = 0; i < adapters.length; i++) {
                if (adapters[i] == account) {
                    adapters[i] = adapters[adapters.length - 1];
                    adapters.pop();
                    break;
                }
            }
            isAdapter[account] = false;
        }
        emit EventsLib.RemoveAdapter(account);
    }

    /// @dev This function requires great caution because it can irreversibly disable submit for a selector.
    /// @dev Existing pending operations submitted before increasing a timelock can still be executed at the initial
    /// executableAt.
    function increaseTimelock(bytes4 selector, uint256 newDuration) external {
        timelocked();
        require(selector != IVaultV2.decreaseTimelock.selector, ErrorsLib.AutomaticallyTimelocked());
        require(newDuration >= timelock[selector], ErrorsLib.TimelockNotIncreasing());

        timelock[selector] = newDuration;
        emit EventsLib.IncreaseTimelock(selector, newDuration);
    }

    function decreaseTimelock(bytes4 selector, uint256 newDuration) external {
        timelocked();
        require(selector != IVaultV2.decreaseTimelock.selector, ErrorsLib.AutomaticallyTimelocked());
        require(newDuration <= timelock[selector], ErrorsLib.TimelockNotDecreasing());

        timelock[selector] = newDuration;
        emit EventsLib.DecreaseTimelock(selector, newDuration);
    }

    function abdicate(bytes4 selector) external {
        timelocked();
        abdicated[selector] = true;
        emit EventsLib.Abdicate(selector);
    }

    function setPerformanceFee(uint256 newPerformanceFee) external {
        timelocked();
        require(newPerformanceFee <= MAX_PERFORMANCE_FEE, ErrorsLib.FeeTooHigh());
        require(performanceFeeRecipient != address(0) || newPerformanceFee == 0, ErrorsLib.FeeInvariantBroken());

        accrueInterest();

        // Safe because 2**96 > MAX_PERFORMANCE_FEE.
        performanceFee = uint96(newPerformanceFee);
        emit EventsLib.SetPerformanceFee(newPerformanceFee);
    }

    function setManagementFee(uint256 newManagementFee) external {
        timelocked();
        require(newManagementFee <= MAX_MANAGEMENT_FEE, ErrorsLib.FeeTooHigh());
        require(managementFeeRecipient != address(0) || newManagementFee == 0, ErrorsLib.FeeInvariantBroken());

        accrueInterest();

        // Safe because 2**96 > MAX_MANAGEMENT_FEE.
        managementFee = uint96(newManagementFee);
        emit EventsLib.SetManagementFee(newManagementFee);
    }

    function setPerformanceFeeRecipient(address newPerformanceFeeRecipient) external {
        timelocked();
        require(newPerformanceFeeRecipient != address(0) || performanceFee == 0, ErrorsLib.FeeInvariantBroken());

        accrueInterest();

        performanceFeeRecipient = newPerformanceFeeRecipient;
        emit EventsLib.SetPerformanceFeeRecipient(newPerformanceFeeRecipient);
    }

    function setManagementFeeRecipient(address newManagementFeeRecipient) external {
        timelocked();
        require(newManagementFeeRecipient != address(0) || managementFee == 0, ErrorsLib.FeeInvariantBroken());

        accrueInterest();

        managementFeeRecipient = newManagementFeeRecipient;
        emit EventsLib.SetManagementFeeRecipient(newManagementFeeRecipient);
    }

    function increaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external {
        timelocked();
        bytes32 id = keccak256(idData);
        require(newAbsoluteCap >= caps[id].absoluteCap, ErrorsLib.AbsoluteCapNotIncreasing());

        caps[id].absoluteCap = newAbsoluteCap.toUint128();
        emit EventsLib.IncreaseAbsoluteCap(id, idData, newAbsoluteCap);
    }

    function decreaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external {
        bytes32 id = keccak256(idData);
        require(msg.sender == curator || isSentinel[msg.sender], ErrorsLib.Unauthorized());
        require(newAbsoluteCap <= caps[id].absoluteCap, ErrorsLib.AbsoluteCapNotDecreasing());

        // Safe because newAbsoluteCap <= absoluteCap < 2**128.
        caps[id].absoluteCap = uint128(newAbsoluteCap);
        emit EventsLib.DecreaseAbsoluteCap(msg.sender, id, idData, newAbsoluteCap);
    }

    function increaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external {
        timelocked();
        bytes32 id = keccak256(idData);
        require(newRelativeCap <= WAD, ErrorsLib.RelativeCapAboveOne());
        require(newRelativeCap >= caps[id].relativeCap, ErrorsLib.RelativeCapNotIncreasing());

        // Safe because WAD < 2**128.
        caps[id].relativeCap = uint128(newRelativeCap);
        emit EventsLib.IncreaseRelativeCap(id, idData, newRelativeCap);
    }

    function decreaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external {
        bytes32 id = keccak256(idData);
        require(msg.sender == curator || isSentinel[msg.sender], ErrorsLib.Unauthorized());
        require(newRelativeCap <= caps[id].relativeCap, ErrorsLib.RelativeCapNotDecreasing());

        // Safe because WAD < 2**128.
        caps[id].relativeCap = uint128(newRelativeCap);
        emit EventsLib.DecreaseRelativeCap(msg.sender, id, idData, newRelativeCap);
    }

    function setForceDeallocatePenalty(address adapter, uint256 newForceDeallocatePenalty) external {
        timelocked();
        require(newForceDeallocatePenalty <= MAX_FORCE_DEALLOCATE_PENALTY, ErrorsLib.PenaltyTooHigh());
        forceDeallocatePenalty[adapter] = newForceDeallocatePenalty;
        emit EventsLib.SetForceDeallocatePenalty(adapter, newForceDeallocatePenalty);
    }

    /* ALLOCATOR FUNCTIONS */

    function allocate(address adapter, bytes memory data, uint256 assets) external {
        require(isAllocator[msg.sender], ErrorsLib.Unauthorized());
        allocateInternal(adapter, data, assets);
    }

    function allocateInternal(address adapter, bytes memory data, uint256 assets) internal {
        require(isAdapter[adapter], ErrorsLib.NotAdapter());

        accrueInterest();

        SafeERC20Lib.safeTransfer(asset, adapter, assets);
        (bytes32[] memory ids, int256 change) = IAdapter(adapter).allocate(data, assets, msg.sig, msg.sender);

        for (uint256 i; i < ids.length; i++) {
            Caps storage _caps = caps[ids[i]];
            _caps.allocation = (int256(_caps.allocation) + change).toUint256();

            require(_caps.absoluteCap > 0, ErrorsLib.ZeroAbsoluteCap());
            require(_caps.allocation <= _caps.absoluteCap, ErrorsLib.AbsoluteCapExceeded());
            require(
                _caps.relativeCap == WAD || _caps.allocation <= firstTotalAssets.mulDivDown(_caps.relativeCap, WAD),
                ErrorsLib.RelativeCapExceeded()
            );
        }
        emit EventsLib.Allocate(msg.sender, adapter, assets, ids, change);
    }

    function deallocate(address adapter, bytes memory data, uint256 assets) external {
        require(isAllocator[msg.sender] || isSentinel[msg.sender], ErrorsLib.Unauthorized());
        deallocateInternal(adapter, data, assets);
    }

    function deallocateInternal(address adapter, bytes memory data, uint256 assets)
        internal
        returns (bytes32[] memory)
    {
        require(isAdapter[adapter], ErrorsLib.NotAdapter());

        (bytes32[] memory ids, int256 change) = IAdapter(adapter).deallocate(data, assets, msg.sig, msg.sender);

        for (uint256 i; i < ids.length; i++) {
            Caps storage _caps = caps[ids[i]];
            require(_caps.allocation > 0, ErrorsLib.ZeroAllocation());
            _caps.allocation = (int256(_caps.allocation) + change).toUint256();
        }

        SafeERC20Lib.safeTransferFrom(asset, adapter, address(this), assets);
        emit EventsLib.Deallocate(msg.sender, adapter, assets, ids, change);
        return ids;
    }

    /// @dev Whether newLiquidityAdapter is an adapter is checked in allocate/deallocate.
    function setLiquidityAdapterAndData(address newLiquidityAdapter, bytes memory newLiquidityData) external {
        require(isAllocator[msg.sender], ErrorsLib.Unauthorized());
        liquidityAdapter = newLiquidityAdapter;
        liquidityData = newLiquidityData;
        emit EventsLib.SetLiquidityAdapterAndData(msg.sender, newLiquidityAdapter, newLiquidityData);
    }

    function setMaxRate(uint256 newMaxRate) external {
        require(isAllocator[msg.sender], ErrorsLib.Unauthorized());
        require(newMaxRate <= MAX_MAX_RATE, ErrorsLib.MaxRateTooHigh());

        accrueInterest();

        // Safe because newMaxRate <= MAX_MAX_RATE < 2**64-1.
        maxRate = uint64(newMaxRate);
        emit EventsLib.SetMaxRate(newMaxRate);
    }

    /* EXCHANGE RATE FUNCTIONS */

    function accrueInterest() public {
        (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares) = accrueInterestView();
        emit EventsLib.AccrueInterest(_totalAssets, newTotalAssets, performanceFeeShares, managementFeeShares);
        _totalAssets = newTotalAssets.toUint128();
        if (firstTotalAssets == 0) firstTotalAssets = newTotalAssets;
        if (performanceFeeShares != 0) createShares(performanceFeeRecipient, performanceFeeShares);
        if (managementFeeShares != 0) createShares(managementFeeRecipient, managementFeeShares);
        lastUpdate = uint64(block.timestamp);
    }

    /// @dev Returns newTotalAssets, performanceFeeShares, managementFeeShares.
    /// @dev The management fee is not bound to the interest, so it can make the share price go down.
    /// @dev The management fees is taken even if the vault incurs some losses.
    /// @dev Both fees are rounded down, so fee recipients could receive less than expected.
    /// @dev The performance fee is taken on the "distributed interest" (which differs from the "real interest" because
    /// of the max rate).
    function accrueInterestView() public view returns (uint256, uint256, uint256) {
        if (firstTotalAssets != 0) return (_totalAssets, 0, 0);
        uint256 elapsed = block.timestamp - lastUpdate;
        uint256 realAssets = IERC20(asset).balanceOf(address(this));
        for (uint256 i = 0; i < adapters.length; i++) {
            realAssets += IAdapter(adapters[i]).realAssets();
        }
        uint256 maxTotalAssets = _totalAssets + (_totalAssets * elapsed).mulDivDown(maxRate, WAD);
        uint256 newTotalAssets = MathLib.min(realAssets, maxTotalAssets);
        uint256 interest = newTotalAssets.zeroFloorSub(_totalAssets);

        // The performance fee assets may be rounded down to 0 if interest * fee < WAD.
        uint256 performanceFeeAssets = interest > 0 && performanceFee > 0 && canReceiveShares(performanceFeeRecipient)
            ? interest.mulDivDown(performanceFee, WAD)
            : 0;
        // The management fee is taken on newTotalAssets to make all approximations consistent (interacting less
        // increases fees).
        uint256 managementFeeAssets = elapsed > 0 && managementFee > 0 && canReceiveShares(managementFeeRecipient)
            ? (newTotalAssets * elapsed).mulDivDown(managementFee, WAD)
            : 0;

        // Interest should be accrued at least every 10 years to avoid fees exceeding total assets.
        uint256 newTotalAssetsWithoutFees = newTotalAssets - performanceFeeAssets - managementFeeAssets;
        uint256 performanceFeeShares =
            performanceFeeAssets.mulDivDown(totalSupply + virtualShares, newTotalAssetsWithoutFees + 1);
        uint256 managementFeeShares =
            managementFeeAssets.mulDivDown(totalSupply + virtualShares, newTotalAssetsWithoutFees + 1);

        return (newTotalAssets, performanceFeeShares, managementFeeShares);
    }

    /// @dev Returns previewed minted shares.
    function previewDeposit(uint256 assets) public view returns (uint256) {
        (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares) = accrueInterestView();
        uint256 newTotalSupply = totalSupply + performanceFeeShares + managementFeeShares;
        return assets.mulDivDown(newTotalSupply + virtualShares, newTotalAssets + 1);
    }

    /// @dev Returns previewed deposited assets.
    function previewMint(uint256 shares) public view returns (uint256) {
        (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares) = accrueInterestView();
        uint256 newTotalSupply = totalSupply + performanceFeeShares + managementFeeShares;
        return shares.mulDivUp(newTotalAssets + 1, newTotalSupply + virtualShares);
    }

    /// @dev Returns previewed redeemed shares.
    function previewWithdraw(uint256 assets) public view returns (uint256) {
        (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares) = accrueInterestView();
        uint256 newTotalSupply = totalSupply + performanceFeeShares + managementFeeShares;
        return assets.mulDivUp(newTotalSupply + virtualShares, newTotalAssets + 1);
    }

    /// @dev Returns previewed withdrawn assets.
    function previewRedeem(uint256 shares) public view returns (uint256) {
        (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares) = accrueInterestView();
        uint256 newTotalSupply = totalSupply + performanceFeeShares + managementFeeShares;
        return shares.mulDivDown(newTotalAssets + 1, newTotalSupply + virtualShares);
    }

    /// @dev Returns corresponding shares (rounded down).
    /// @dev Takes into account performance and management fees.
    function convertToShares(uint256 assets) external view returns (uint256) {
        return previewDeposit(assets);
    }

    /// @dev Returns corresponding assets (rounded down).
    /// @dev Takes into account performance and management fees.
    function convertToAssets(uint256 shares) external view returns (uint256) {
        return previewRedeem(shares);
    }

    /* MAX FUNCTIONS */

    /// @dev Gross underestimation because being revert-free cannot be guaranteed when calling the gate.
    function maxDeposit(address) external pure returns (uint256) {
        return 0;
    }

    /// @dev Gross underestimation because being revert-free cannot be guaranteed when calling the gate.
    function maxMint(address) external pure returns (uint256) {
        return 0;
    }

    /// @dev Gross underestimation because being revert-free cannot be guaranteed when calling the gate.
    function maxWithdraw(address) external pure returns (uint256) {
        return 0;
    }

    /// @dev Gross underestimation because being revert-free cannot be guaranteed when calling the gate.
    function maxRedeem(address) external pure returns (uint256) {
        return 0;
    }

    /* USER MAIN FUNCTIONS */

    /// @dev Returns minted shares.
    function deposit(uint256 assets, address onBehalf) external returns (uint256) {
        accrueInterest();
        uint256 shares = previewDeposit(assets);
        enter(assets, shares, onBehalf);
        return shares;
    }

    /// @dev Returns deposited assets.
    function mint(uint256 shares, address onBehalf) external returns (uint256) {
        accrueInterest();
        uint256 assets = previewMint(shares);
        enter(assets, shares, onBehalf);
        return assets;
    }

    /// @dev Internal function for deposit and mint.
    function enter(uint256 assets, uint256 shares, address onBehalf) internal {
        require(canReceiveShares(onBehalf), ErrorsLib.CannotReceiveShares());
        require(canSendAssets(msg.sender), ErrorsLib.CannotSendAssets());

        SafeERC20Lib.safeTransferFrom(asset, msg.sender, address(this), assets);
        createShares(onBehalf, shares);
        _totalAssets += assets.toUint128();
        emit EventsLib.Deposit(msg.sender, onBehalf, assets, shares);

        if (liquidityAdapter != address(0)) allocateInternal(liquidityAdapter, liquidityData, assets);
    }

    /// @dev Returns redeemed shares.
    function withdraw(uint256 assets, address receiver, address onBehalf) public returns (uint256) {
        accrueInterest();
        uint256 shares = previewWithdraw(assets);
        exit(assets, shares, receiver, onBehalf);
        return shares;
    }

    /// @dev Returns withdrawn assets.
    function redeem(uint256 shares, address receiver, address onBehalf) external returns (uint256) {
        accrueInterest();
        uint256 assets = previewRedeem(shares);
        exit(assets, shares, receiver, onBehalf);
        return assets;
    }

    /// @dev Internal function for withdraw and redeem.
    function exit(uint256 assets, uint256 shares, address receiver, address onBehalf) internal {
        require(canSendShares(onBehalf), ErrorsLib.CannotSendShares());
        require(canReceiveAssets(receiver), ErrorsLib.CannotReceiveAssets());

        uint256 idleAssets = IERC20(asset).balanceOf(address(this));
        if (assets > idleAssets && liquidityAdapter != address(0)) {
            deallocateInternal(liquidityAdapter, liquidityData, assets - idleAssets);
        }

        if (msg.sender != onBehalf) {
            uint256 _allowance = allowance[onBehalf][msg.sender];
            if (_allowance != type(uint256).max) allowance[onBehalf][msg.sender] = _allowance - shares;
        }

        deleteShares(onBehalf, shares);
        _totalAssets -= assets.toUint128();
        SafeERC20Lib.safeTransfer(asset, receiver, assets);
        emit EventsLib.Withdraw(msg.sender, receiver, onBehalf, assets, shares);
    }

    /// @dev Returns shares withdrawn as penalty.
    /// @dev When calling this function, a penalty is taken from onBehalf, in order to discourage allocation
    /// manipulations.
    /// @dev The penalty is taken as a withdrawal for which assets are returned to the vault. In consequence,
    /// totalAssets is decreased normally along with totalSupply (the share price doesn't change except because of
    /// rounding errors), but the amount of assets actually controlled by the vault is not decreased.
    /// @dev If a user has A assets in the vault, and that the vault is already fully illiquid, the optimal amount to
    /// force deallocate in order to exit the vault is min(liquidity_of_market, A / (1 + penalty)).
    /// This ensures that either the market is empty or that it leaves no shares nor liquidity after exiting.
    function forceDeallocate(address adapter, bytes memory data, uint256 assets, address onBehalf)
        external
        returns (uint256)
    {
        bytes32[] memory ids = deallocateInternal(adapter, data, assets);
        uint256 penaltyAssets = assets.mulDivUp(forceDeallocatePenalty[adapter], WAD);
        uint256 penaltyShares = withdraw(penaltyAssets, address(this), onBehalf);
        emit EventsLib.ForceDeallocate(msg.sender, adapter, assets, onBehalf, ids, penaltyAssets);
        return penaltyShares;
    }

    /* ERC20 FUNCTIONS */

    /// @dev Returns success (always true because reverts on failure).
    function transfer(address to, uint256 shares) external returns (bool) {
        require(to != address(0), ErrorsLib.ZeroAddress());

        require(canSendShares(msg.sender), ErrorsLib.CannotSendShares());
        require(canReceiveShares(to), ErrorsLib.CannotReceiveShares());

        balanceOf[msg.sender] -= shares;
        balanceOf[to] += shares;
        emit EventsLib.Transfer(msg.sender, to, shares);
        return true;
    }

    /// @dev Returns success (always true because reverts on failure).
    function transferFrom(address from, address to, uint256 shares) external returns (bool) {
        require(from != address(0), ErrorsLib.ZeroAddress());
        require(to != address(0), ErrorsLib.ZeroAddress());

        require(canSendShares(from), ErrorsLib.CannotSendShares());
        require(canReceiveShares(to), ErrorsLib.CannotReceiveShares());

        if (msg.sender != from) {
            uint256 _allowance = allowance[from][msg.sender];
            if (_allowance != type(uint256).max) {
                allowance[from][msg.sender] = _allowance - shares;
                emit EventsLib.AllowanceUpdatedByTransferFrom(from, msg.sender, _allowance - shares);
            }
        }

        balanceOf[from] -= shares;
        balanceOf[to] += shares;
        emit EventsLib.Transfer(from, to, shares);
        return true;
    }

    /// @dev Returns success (always true because reverts on failure).
    function approve(address spender, uint256 shares) external returns (bool) {
        allowance[msg.sender][spender] = shares;
        emit EventsLib.Approval(msg.sender, spender, shares);
        return true;
    }

    /// @dev Signature malleability is not explicitly prevented but it is not a problem thanks to the nonce.
    function permit(address _owner, address spender, uint256 shares, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external
    {
        require(deadline >= block.timestamp, ErrorsLib.PermitDeadlineExpired());

        uint256 nonce = nonces[_owner]++;
        bytes32 hashStruct = keccak256(abi.encode(PERMIT_TYPEHASH, _owner, spender, shares, nonce, deadline));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), hashStruct));
        address recoveredAddress = ecrecover(digest, v, r, s);
        require(recoveredAddress != address(0) && recoveredAddress == _owner, ErrorsLib.InvalidSigner());

        allowance[_owner][spender] = shares;
        emit EventsLib.Approval(_owner, spender, shares);
        emit EventsLib.Permit(_owner, spender, shares, nonce, deadline);
    }

    function createShares(address to, uint256 shares) internal {
        require(to != address(0), ErrorsLib.ZeroAddress());
        balanceOf[to] += shares;
        totalSupply += shares;
        emit EventsLib.Transfer(address(0), to, shares);
    }

    function deleteShares(address from, uint256 shares) internal {
        require(from != address(0), ErrorsLib.ZeroAddress());
        balanceOf[from] -= shares;
        totalSupply -= shares;
        emit EventsLib.Transfer(from, address(0), shares);
    }

    /* PERMISSIONED TOKEN FUNCTIONS */

    function canReceiveShares(address account) public view returns (bool) {
        return receiveSharesGate == address(0) || IReceiveSharesGate(receiveSharesGate).canReceiveShares(account);
    }

    function canSendShares(address account) public view returns (bool) {
        return sendSharesGate == address(0) || ISendSharesGate(sendSharesGate).canSendShares(account);
    }

    function canReceiveAssets(address account) public view returns (bool) {
        return account == address(this) || receiveAssetsGate == address(0)
            || IReceiveAssetsGate(receiveAssetsGate).canReceiveAssets(account);
    }

    function canSendAssets(address account) public view returns (bool) {
        return sendAssetsGate == address(0) || ISendAssetsGate(sendAssetsGate).canSendAssets(account);
    }
}

File 2 of 13 : IVaultV2.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

import {IERC20} from "./IERC20.sol";
import {IERC4626} from "./IERC4626.sol";
import {IERC2612} from "./IERC2612.sol";

struct Caps {
    uint256 allocation;
    uint128 absoluteCap;
    uint128 relativeCap;
}

interface IVaultV2 is IERC4626, IERC2612 {
    // State variables
    function virtualShares() external view returns (uint256);
    function owner() external view returns (address);
    function curator() external view returns (address);
    function receiveSharesGate() external view returns (address);
    function sendSharesGate() external view returns (address);
    function receiveAssetsGate() external view returns (address);
    function sendAssetsGate() external view returns (address);
    function adapterRegistry() external view returns (address);
    function isSentinel(address account) external view returns (bool);
    function isAllocator(address account) external view returns (bool);
    function firstTotalAssets() external view returns (uint256);
    function _totalAssets() external view returns (uint128);
    function lastUpdate() external view returns (uint64);
    function maxRate() external view returns (uint64);
    function adapters(uint256 index) external view returns (address);
    function adaptersLength() external view returns (uint256);
    function isAdapter(address account) external view returns (bool);
    function allocation(bytes32 id) external view returns (uint256);
    function absoluteCap(bytes32 id) external view returns (uint256);
    function relativeCap(bytes32 id) external view returns (uint256);
    function forceDeallocatePenalty(address adapter) external view returns (uint256);
    function liquidityAdapter() external view returns (address);
    function liquidityData() external view returns (bytes memory);
    function timelock(bytes4 selector) external view returns (uint256);
    function abdicated(bytes4 selector) external view returns (bool);
    function executableAt(bytes memory data) external view returns (uint256);
    function performanceFee() external view returns (uint96);
    function performanceFeeRecipient() external view returns (address);
    function managementFee() external view returns (uint96);
    function managementFeeRecipient() external view returns (address);

    // Gating
    function canSendShares(address account) external view returns (bool);
    function canReceiveShares(address account) external view returns (bool);
    function canSendAssets(address account) external view returns (bool);
    function canReceiveAssets(address account) external view returns (bool);

    // Multicall
    function multicall(bytes[] memory data) external;

    // Owner functions
    function setOwner(address newOwner) external;
    function setCurator(address newCurator) external;
    function setIsSentinel(address account, bool isSentinel) external;
    function setName(string memory newName) external;
    function setSymbol(string memory newSymbol) external;

    // Timelocks for curator functions
    function submit(bytes memory data) external;
    function revoke(bytes memory data) external;

    // Curator functions
    function setIsAllocator(address account, bool newIsAllocator) external;
    function setReceiveSharesGate(address newReceiveSharesGate) external;
    function setSendSharesGate(address newSendSharesGate) external;
    function setReceiveAssetsGate(address newReceiveAssetsGate) external;
    function setSendAssetsGate(address newSendAssetsGate) external;
    function setAdapterRegistry(address newAdapterRegistry) external;
    function addAdapter(address account) external;
    function removeAdapter(address account) external;
    function increaseTimelock(bytes4 selector, uint256 newDuration) external;
    function decreaseTimelock(bytes4 selector, uint256 newDuration) external;
    function abdicate(bytes4 selector) external;
    function setPerformanceFee(uint256 newPerformanceFee) external;
    function setManagementFee(uint256 newManagementFee) external;
    function setPerformanceFeeRecipient(address newPerformanceFeeRecipient) external;
    function setManagementFeeRecipient(address newManagementFeeRecipient) external;
    function increaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
    function decreaseAbsoluteCap(bytes memory idData, uint256 newAbsoluteCap) external;
    function increaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
    function decreaseRelativeCap(bytes memory idData, uint256 newRelativeCap) external;
    function setMaxRate(uint256 newMaxRate) external;
    function setForceDeallocatePenalty(address adapter, uint256 newForceDeallocatePenalty) external;

    // Allocator functions
    function allocate(address adapter, bytes memory data, uint256 assets) external;
    function deallocate(address adapter, bytes memory data, uint256 assets) external;
    function setLiquidityAdapterAndData(address newLiquidityAdapter, bytes memory newLiquidityData) external;

    // Exchange rate
    function accrueInterest() external;
    function accrueInterestView()
        external
        view
        returns (uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares);

    // Force deallocate
    function forceDeallocate(address adapter, bytes memory data, uint256 assets, address onBehalf)
        external
        returns (uint256 penaltyShares);
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

/// @dev See VaultV2 NatSpec comments for more details on adapter's spec.
interface IAdapter {
    /// @dev Returns the market' ids and the change in assets on this market.
    function allocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
        external
        returns (bytes32[] memory ids, int256 change);

    /// @dev Returns the market' ids and the change in assets on this market.
    function deallocate(bytes memory data, uint256 assets, bytes4 selector, address sender)
        external
        returns (bytes32[] memory ids, int256 change);

    /// @dev Returns the current value of the investments of the adapter (in underlying asset).
    function realAssets() external view returns (uint256 assets);
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IAdapterRegistry {
    function isInRegistry(address account) external view returns (bool);
}

File 5 of 13 : ErrorsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

library ErrorsLib {
    error Abdicated();
    error AbsoluteCapExceeded();
    error AbsoluteCapNotDecreasing();
    error AbsoluteCapNotIncreasing();
    error ApproveReturnedFalse();
    error ApproveReverted();
    error CannotReceiveShares();
    error CannotReceiveAssets();
    error CannotSendShares();
    error CannotSendAssets();
    error CapExceeded();
    error CastOverflow();
    error DataAlreadyPending();
    error DataNotTimelocked();
    error FeeInvariantBroken();
    error FeeTooHigh();
    error InvalidSigner();
    error MaxRateTooHigh();
    error NoCode();
    error NotAdapter();
    error NotInAdapterRegistry();
    error PenaltyTooHigh();
    error PermitDeadlineExpired();
    error RelativeCapAboveOne();
    error RelativeCapExceeded();
    error RelativeCapNotDecreasing();
    error RelativeCapNotIncreasing();
    error AutomaticallyTimelocked();
    error TimelockNotDecreasing();
    error TimelockNotExpired();
    error TimelockNotIncreasing();
    error TransferFromReturnedFalse();
    error TransferFromReverted();
    error TransferReturnedFalse();
    error TransferReverted();
    error Unauthorized();
    error ZeroAbsoluteCap();
    error ZeroAddress();
    error ZeroAllocation();
}

File 6 of 13 : EventsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

library EventsLib {
    // ERC20 events
    event Approval(address indexed owner, address indexed spender, uint256 shares);
    event Transfer(address indexed from, address indexed to, uint256 shares);
    /// @dev Emitted when the allowance is updated by transferFrom (not when it is updated by permit, approve, withdraw,
    /// redeem because their respective events allow to track the allowance).
    event AllowanceUpdatedByTransferFrom(address indexed owner, address indexed spender, uint256 shares);
    event Permit(address indexed owner, address indexed spender, uint256 shares, uint256 nonce, uint256 deadline);

    // ERC4626 events
    event Deposit(address indexed sender, address indexed onBehalf, uint256 assets, uint256 shares);
    event Withdraw(
        address indexed sender, address indexed receiver, address indexed onBehalf, uint256 assets, uint256 shares
    );

    // Vault creation events
    event Constructor(address indexed owner, address indexed asset);

    // Allocation events
    event Allocate(address indexed sender, address indexed adapter, uint256 assets, bytes32[] ids, int256 change);
    event Deallocate(address indexed sender, address indexed adapter, uint256 assets, bytes32[] ids, int256 change);
    event ForceDeallocate(
        address indexed sender,
        address adapter,
        uint256 assets,
        address indexed onBehalf,
        bytes32[] ids,
        uint256 penaltyAssets
    );

    // Fee and interest events
    event AccrueInterest(
        uint256 previousTotalAssets, uint256 newTotalAssets, uint256 performanceFeeShares, uint256 managementFeeShares
    );

    // Timelock events
    event Revoke(address indexed sender, bytes4 indexed selector, bytes data);
    event Submit(bytes4 indexed selector, bytes data, uint256 executableAt);
    event Accept(bytes4 indexed selector, bytes data);

    // Configuration events
    event SetOwner(address indexed newOwner);
    event SetCurator(address indexed newCurator);
    event SetIsSentinel(address indexed account, bool newIsSentinel);
    event SetName(string newName);
    event SetSymbol(string newSymbol);
    event SetIsAllocator(address indexed account, bool newIsAllocator);
    event SetReceiveSharesGate(address indexed newReceiveSharesGate);
    event SetSendSharesGate(address indexed newSendSharesGate);
    event SetReceiveAssetsGate(address indexed newReceiveAssetsGate);
    event SetSendAssetsGate(address indexed newSendAssetsGate);
    event SetAdapterRegistry(address indexed newAdapterRegistry);
    event AddAdapter(address indexed account);
    event RemoveAdapter(address indexed account);
    event DecreaseTimelock(bytes4 indexed selector, uint256 newDuration);
    event IncreaseTimelock(bytes4 indexed selector, uint256 newDuration);
    event Abdicate(bytes4 indexed selector);
    event SetLiquidityAdapterAndData(
        address indexed sender, address indexed newLiquidityAdapter, bytes indexed newLiquidityData
    );
    event SetPerformanceFee(uint256 newPerformanceFee);
    event SetPerformanceFeeRecipient(address indexed newPerformanceFeeRecipient);
    event SetManagementFee(uint256 newManagementFee);
    event SetManagementFeeRecipient(address indexed newManagementFeeRecipient);
    event DecreaseAbsoluteCap(address indexed sender, bytes32 indexed id, bytes idData, uint256 newAbsoluteCap);
    event IncreaseAbsoluteCap(bytes32 indexed id, bytes idData, uint256 newAbsoluteCap);
    event DecreaseRelativeCap(address indexed sender, bytes32 indexed id, bytes idData, uint256 newRelativeCap);
    event IncreaseRelativeCap(bytes32 indexed id, bytes idData, uint256 newRelativeCap);
    event SetMaxRate(uint256 newMaxRate);
    event SetForceDeallocatePenalty(address indexed adapter, uint256 forceDeallocatePenalty);
}

File 7 of 13 : ConstantsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

uint256 constant WAD = 1e18;
bytes32 constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
bytes32 constant PERMIT_TYPEHASH =
    keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
uint256 constant MAX_MAX_RATE = 200e16 / uint256(365 days); // 200% APR
uint256 constant MAX_PERFORMANCE_FEE = 0.5e18; // 50%
uint256 constant MAX_MANAGEMENT_FEE = 0.05e18 / uint256(365 days); // 5%
uint256 constant MAX_FORCE_DEALLOCATE_PENALTY = 0.02e18; // 2%

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

import {ErrorsLib} from "./ErrorsLib.sol";

library MathLib {
    /// @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 max(0, x - y).
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Casts from uint256 to uint128, reverting if input number is too large.
    function toUint128(uint256 x) internal pure returns (uint128) {
        require(x <= type(uint128).max, ErrorsLib.CastOverflow());
        return uint128(x);
    }

    /// @dev Casts from int256 to uint256, reverting if input number is negative.
    function toUint256(int256 x) internal pure returns (uint256) {
        require(x >= 0, ErrorsLib.CastOverflow());
        return uint256(x);
    }

    /// @dev Returns min(x, y).
    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            z := xor(x, mul(xor(x, y), lt(y, x)))
        }
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity ^0.8.0;

import {IERC20} from "../interfaces/IERC20.sol";
import {ErrorsLib} from "./ErrorsLib.sol";

library SafeERC20Lib {
    function safeTransfer(address token, address to, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transfer, (to, value)));
        require(success, ErrorsLib.TransferReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferReturnedFalse());
    }

    function safeTransferFrom(address token, address from, address to, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.transferFrom, (from, to, value)));
        require(success, ErrorsLib.TransferFromReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.TransferFromReturnedFalse());
    }

    function safeApprove(address token, address spender, uint256 value) internal {
        require(token.code.length > 0, ErrorsLib.NoCode());

        (bool success, bytes memory returndata) = token.call(abi.encodeCall(IERC20.approve, (spender, value)));
        require(success, ErrorsLib.ApproveReverted());
        require(returndata.length == 0 || abi.decode(returndata, (bool)), ErrorsLib.ApproveReturnedFalse());
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IReceiveSharesGate {
    function canReceiveShares(address account) external view returns (bool);
}

interface ISendSharesGate {
    function canSendShares(address account) external view returns (bool);
}

interface IReceiveAssetsGate {
    function canReceiveAssets(address account) external view returns (bool);
}

interface ISendAssetsGate {
    function canSendAssets(address account) external view returns (bool);
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IERC20 {
    function decimals() external view returns (uint8);
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 shares) external returns (bool success);
    function transferFrom(address from, address to, uint256 shares) external returns (bool success);
    function approve(address spender, uint256 shares) external returns (bool success);
    function allowance(address owner, address spender) external view returns (uint256);
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

import {IERC20} from "./IERC20.sol";

interface IERC4626 is IERC20 {
    function asset() external view returns (address);
    function totalAssets() external view returns (uint256);
    function convertToAssets(uint256 shares) external view returns (uint256 assets);
    function convertToShares(uint256 assets) external view returns (uint256 shares);
    function deposit(uint256 assets, address onBehalf) external returns (uint256 shares);
    function mint(uint256 shares, address onBehalf) external returns (uint256 assets);
    function withdraw(uint256 assets, address onBehalf, address receiver) external returns (uint256 shares);
    function redeem(uint256 shares, address onBehalf, address receiver) external returns (uint256 assets);
    function previewDeposit(uint256 assets) external view returns (uint256 shares);
    function previewMint(uint256 shares) external view returns (uint256 assets);
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);
    function previewRedeem(uint256 shares) external view returns (uint256 assets);
    function maxDeposit(address onBehalf) external view returns (uint256 assets);
    function maxMint(address onBehalf) external view returns (uint256 shares);
    function maxWithdraw(address onBehalf) external view returns (uint256 assets);
    function maxRedeem(address onBehalf) external view returns (uint256 shares);
}

// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IERC2612 {
    function permit(address owner, address spender, uint256 shares, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
        external;
    function nonces(address owner) external view returns (uint256);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

Settings
{
  "remappings": [
    "solmate/=lib/bundler3/lib/permit2/lib/solmate/",
    "@openzeppelin/contracts/=lib/metamorpho-1.1/lib/openzeppelin-contracts/contracts/",
    "bundler3/=lib/bundler3/",
    "ds-test/=lib/metamorpho-1.1/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/metamorpho-1.1/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/bundler3/lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/morpho-blue/lib/halmos-cheatcodes/src/",
    "metamorpho-1.1/=lib/metamorpho-1.1/",
    "metamorpho-v1.1/=lib/vault-v2/lib/metamorpho-v1.1/",
    "metamorpho/=lib/vault-v2/lib/metamorpho/",
    "morpho-blue-irm/=lib/morpho-blue-irm/src/",
    "morpho-blue-oracles/=lib/morpho-blue-oracles/src/",
    "morpho-blue/=lib/morpho-blue/",
    "murky/=lib/universal-rewards-distributor/lib/murky/src/",
    "openzeppelin-contracts/=lib/metamorpho-1.1/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/universal-rewards-distributor/lib/openzeppelin-contracts/contracts/",
    "permit2/=lib/bundler3/lib/permit2/",
    "pre-liquidation/=lib/pre-liquidation/src/",
    "public-allocator/=lib/public-allocator/src/",
    "safe-smart-account/=lib/safe-smart-account/",
    "universal-rewards-distributor/=lib/universal-rewards-distributor/src/",
    "vault-v2-adapter-registries/=lib/vault-v2-adapter-registries/src/",
    "vault-v2/=lib/vault-v2/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_asset","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Abdicated","type":"error"},{"inputs":[],"name":"AbsoluteCapExceeded","type":"error"},{"inputs":[],"name":"AbsoluteCapNotDecreasing","type":"error"},{"inputs":[],"name":"AbsoluteCapNotIncreasing","type":"error"},{"inputs":[],"name":"AutomaticallyTimelocked","type":"error"},{"inputs":[],"name":"CannotReceiveAssets","type":"error"},{"inputs":[],"name":"CannotReceiveShares","type":"error"},{"inputs":[],"name":"CannotSendAssets","type":"error"},{"inputs":[],"name":"CannotSendShares","type":"error"},{"inputs":[],"name":"CastOverflow","type":"error"},{"inputs":[],"name":"DataAlreadyPending","type":"error"},{"inputs":[],"name":"DataNotTimelocked","type":"error"},{"inputs":[],"name":"FeeInvariantBroken","type":"error"},{"inputs":[],"name":"FeeTooHigh","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"MaxRateTooHigh","type":"error"},{"inputs":[],"name":"NoCode","type":"error"},{"inputs":[],"name":"NotAdapter","type":"error"},{"inputs":[],"name":"NotInAdapterRegistry","type":"error"},{"inputs":[],"name":"PenaltyTooHigh","type":"error"},{"inputs":[],"name":"PermitDeadlineExpired","type":"error"},{"inputs":[],"name":"RelativeCapAboveOne","type":"error"},{"inputs":[],"name":"RelativeCapExceeded","type":"error"},{"inputs":[],"name":"RelativeCapNotDecreasing","type":"error"},{"inputs":[],"name":"RelativeCapNotIncreasing","type":"error"},{"inputs":[],"name":"TimelockNotDecreasing","type":"error"},{"inputs":[],"name":"TimelockNotExpired","type":"error"},{"inputs":[],"name":"TimelockNotIncreasing","type":"error"},{"inputs":[],"name":"TransferFromReturnedFalse","type":"error"},{"inputs":[],"name":"TransferFromReverted","type":"error"},{"inputs":[],"name":"TransferReturnedFalse","type":"error"},{"inputs":[],"name":"TransferReverted","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAbsoluteCap","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAllocation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"Abdicate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Accept","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousTotalAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotalAssets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"performanceFeeShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"managementFeeShares","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"AddAdapter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"adapter","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"ids","type":"bytes32[]"},{"indexed":false,"internalType":"int256","name":"change","type":"int256"}],"name":"Allocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"AllowanceUpdatedByTransferFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"Constructor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"adapter","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"ids","type":"bytes32[]"},{"indexed":false,"internalType":"int256","name":"change","type":"int256"}],"name":"Deallocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"idData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"newAbsoluteCap","type":"uint256"}],"name":"DecreaseAbsoluteCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"idData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"newRelativeCap","type":"uint256"}],"name":"DecreaseRelativeCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"DecreaseTimelock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalf","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"adapter","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":true,"internalType":"address","name":"onBehalf","type":"address"},{"indexed":false,"internalType":"bytes32[]","name":"ids","type":"bytes32[]"},{"indexed":false,"internalType":"uint256","name":"penaltyAssets","type":"uint256"}],"name":"ForceDeallocate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"idData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"newAbsoluteCap","type":"uint256"}],"name":"IncreaseAbsoluteCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"idData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"newRelativeCap","type":"uint256"}],"name":"IncreaseRelativeCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"IncreaseTimelock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"Permit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RemoveAdapter","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"Revoke","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdapterRegistry","type":"address"}],"name":"SetAdapterRegistry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newCurator","type":"address"}],"name":"SetCurator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"adapter","type":"address"},{"indexed":false,"internalType":"uint256","name":"forceDeallocatePenalty","type":"uint256"}],"name":"SetForceDeallocatePenalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"newIsAllocator","type":"bool"}],"name":"SetIsAllocator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"newIsSentinel","type":"bool"}],"name":"SetIsSentinel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"newLiquidityAdapter","type":"address"},{"indexed":true,"internalType":"bytes","name":"newLiquidityData","type":"bytes"}],"name":"SetLiquidityAdapterAndData","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newManagementFee","type":"uint256"}],"name":"SetManagementFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newManagementFeeRecipient","type":"address"}],"name":"SetManagementFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxRate","type":"uint256"}],"name":"SetMaxRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newName","type":"string"}],"name":"SetName","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"SetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPerformanceFee","type":"uint256"}],"name":"SetPerformanceFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPerformanceFeeRecipient","type":"address"}],"name":"SetPerformanceFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newReceiveAssetsGate","type":"address"}],"name":"SetReceiveAssetsGate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newReceiveSharesGate","type":"address"}],"name":"SetReceiveSharesGate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSendAssetsGate","type":"address"}],"name":"SetSendAssetsGate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSendSharesGate","type":"address"}],"name":"SetSendSharesGate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newSymbol","type":"string"}],"name":"SetSymbol","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"executableAt","type":"uint256"}],"name":"Submit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalf","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_totalAssets","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"abdicate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"abdicated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"absoluteCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrueInterestView","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adapterRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"adapters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adaptersLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addAdapter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"allocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canReceiveAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canReceiveShares","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canSendAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"canSendShares","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"deallocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"idData","type":"bytes"},{"internalType":"uint256","name":"newAbsoluteCap","type":"uint256"}],"name":"decreaseAbsoluteCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"idData","type":"bytes"},{"internalType":"uint256","name":"newRelativeCap","type":"uint256"}],"name":"decreaseRelativeCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"decreaseTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"executableAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"}],"name":"forceDeallocate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"}],"name":"forceDeallocatePenalty","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"idData","type":"bytes"},{"internalType":"uint256","name":"newAbsoluteCap","type":"uint256"}],"name":"increaseAbsoluteCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"idData","type":"bytes"},{"internalType":"uint256","name":"newRelativeCap","type":"uint256"}],"name":"increaseRelativeCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"increaseTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isAdapter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isAllocator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSentinel","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdate","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAdapter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementFee","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"maxRate","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFee","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiveAssetsGate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiveSharesGate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"onBehalf","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"relativeCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"removeAdapter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"revoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendAssetsGate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sendSharesGate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdapterRegistry","type":"address"}],"name":"setAdapterRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCurator","type":"address"}],"name":"setCurator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adapter","type":"address"},{"internalType":"uint256","name":"newForceDeallocatePenalty","type":"uint256"}],"name":"setForceDeallocatePenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"newIsAllocator","type":"bool"}],"name":"setIsAllocator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"newIsSentinel","type":"bool"}],"name":"setIsSentinel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLiquidityAdapter","type":"address"},{"internalType":"bytes","name":"newLiquidityData","type":"bytes"}],"name":"setLiquidityAdapterAndData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newManagementFee","type":"uint256"}],"name":"setManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManagementFeeRecipient","type":"address"}],"name":"setManagementFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxRate","type":"uint256"}],"name":"setMaxRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newName","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPerformanceFee","type":"uint256"}],"name":"setPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPerformanceFeeRecipient","type":"address"}],"name":"setPerformanceFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newReceiveAssetsGate","type":"address"}],"name":"setReceiveAssetsGate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newReceiveSharesGate","type":"address"}],"name":"setReceiveSharesGate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSendAssetsGate","type":"address"}],"name":"setSendAssetsGate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSendSharesGate","type":"address"}],"name":"setSendSharesGate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newSymbol","type":"string"}],"name":"setSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"submit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"timelock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"virtualShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"onBehalf","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

60e080604052346101b657604081615749803803809161001f82856101cd565b8339810103126101b65761003e602061003783610204565b9201610204565b60808181525f80546001600160a01b0319166001600160a01b03948516908117909155600f8054600160801b600160c01b0319164290931b600160801b600160c01b03169290921790915560405163313ce56760e01b8152909290911690602081600481855afa80156101c2575f90610181575b60ff9150168060120381601211029081810180911161016d5760ff1660a052604d811161016d57600a0a60c052604051917f612d665a88b3ae6bc3e53207bfc2db673e2e05e2aa4a68043b618cc81295a27d5f80a361553090816102198239608051818181612fd301528181613fe501528181614ac701528181614b9501528181614dc7015261500d015260a0518161302a015260c051818181610ebc01528181613c5801528181613f380152818161410901526145ab0152f35b634e487b7160e01b5f52601160045260245ffd5b506020813d6020116101ba575b8161019b602093836101cd565b810103126101b6575160ff811681036101b65760ff906100b2565b5f80fd5b3d915061018e565b6040513d5f823e3d90fd5b601f909101601f19168101906001600160401b038211908210176101f057604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101b65756fe60806040526004361015610011575f80fd5b5f3560e01c806301e1d1141461374b57806304dbf0ce146136c457806306fdde031461361f57806307a2d13a14612daf578063095ea7b31461359a5780630a28a4771461357c5780630b467b9b146134705780630d326b181461344d57806313af4035146133b057806318160ddd1461339357806320fe8d581461337057806323b872dd146132055780632438525b146130ef5780632cb19f98146130695780632e0292281461304e578063313ce567146130115780633644e51514612ff757806338d52e0f14612fa75780633e9d2ac714612efb578063402d267d14610bd55780634796629114612e175780634b219d1614612dcd5780634cdad50614612daf5780634dedf20e14612d655780634ef501ac14612d1757806350b5c16a14612ce457806354cde13e14612cb15780635797527014612b9a578063585cd34b146129c55780635aa22bc8146129a85780635b34b823146128735780635c1a1a4f146127675780635c9ce04d1461273a57806360a38ac11461270257806360d54d411461251957806368c18beb146124cf5780636a5f1aa2146124055780636d9a3010146123e55780636e553f65146123ac57806370897b23146122f857806370a08231146122b35780637e729ac4146122805780637ecebe001461223b5780637fb6caad14611fe85780638639fb0714611f92578063871c979c14611f0b5780638778878214611ee05780638c54519b14611dbe5780638da5cb5b14611d8c5780638e511e4d14611d695780638eede80114611d36578063920ed70614611c8f57806393ab2ab714611c5c57806394bf804d14611c2357806395d89b4114611b3757806398c9b49c14611b0a57806399e9918314611ac55780639faae464146119fb578063a68bafa3146119cb578063a6afed95146119b3578063a6f7f5d614611988578063a9059cbb14611851578063aa4abe7f14611777578063ac9650d814611686578063ad468d1114611653578063b192a84a146115b7578063b2e3284814611519578063b3d7f6b9146114fb578063b460af94146114cc578063b84c8246146112c4578063ba03a75f1461127a578063ba0876521461124b578063bc0dd3741461120c578063c0463711146111e2578063c21ad0281461115b578063c47f002714610f09578063c63d75b614610bd5578063c69507dd14610edf578063c6e6f5921461065b578063c719946c14610ea5578063ce04bebb14610e76578063ce96cb7714610bd5578063d505accf14610bda578063d905777e14610bd5578063dd62ed3e14610b67578063e470b8bc14610b11578063e4d38cd8146109b9578063e66f53b714610986578063e78ab14e14610935578063e90956cf14610898578063ece1d6e514610878578063ed27f7c914610858578063ef7fa71b14610681578063ef8b30f71461065b578063f6f98fd514610564578063f73f8f31146105485763fe56e23214610444575f80fd5b3461054457602060031936011261054457600435610460614633565b635e80a6bf811161051c57601a5460601c15801590610514575b156104ec5760207fd87632b1c6ebfa21acbca0e3279b3cf6385a377cb8fda51e5b866baa6e6012ab916104ab6143f2565b6bffffffffffffffffffffffff81167fffffffffffffffffffffffffffffffffffffffff000000000000000000000000601a541617601a55604051908152a1005b7fda9e0fa0000000000000000000000000000000000000000000000000000000005f5260045ffd5b50801561047a565b7fcd4e6167000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b34610544575f6003193601126105445760205f5c604051908152f35b346105445761057236613969565b9061057b614633565b8051602082012091825f5260126020526fffffffffffffffffffffffffffffffff600160405f200154168110610633577f7368d59ed82f6a538f6deef9baa54623fe3699ce07b19031f762f740c8c34b03916105d682614f21565b845f5260126020526fffffffffffffffffffffffffffffffff600160405f200191167fffffffffffffffffffffffffffffffff0000000000000000000000000000000082541617905561062e60405192839283613ea9565b0390a2005b7fa844d937000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544576020600319360112610544576020610679600435614609565b604051908152f35b346105445761068f3661388a565b73ffffffffffffffffffffffffffffffffffffffff6001541633036108305760405181838237602081838101601881520301902054610808577fffffffff000000000000000000000000000000000000000000000000000000006106f38284613c91565b16917f5c1a1a4f0000000000000000000000000000000000000000000000000000000083036107d15781600811610544577f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb917fffffffff000000000000000000000000000000000000000000000000000000006004830135165f52601660205261078360405f20545b42613c28565b60405182848237602081848101601881520301902055604051818382376020818381016018815203019020546107c6604051938493604085526040850191613cf7565b9060208301520390a2005b7f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb91835f52601660205261078360405f205461077d565b7fd91ff208000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f60031936011261054457602060195460601c604051908152f35b34610544575f600319360112610544576020600f5460c01c604051908152f35b34610544576020600319360112610544576108b161376f565b73ffffffffffffffffffffffffffffffffffffffff5f541633036108305773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001557fbd0a63c12948fbc9194a5839019f99c9d71db924e5c70018265bc778b8f1a5065f80a2005b34610544576020600319360112610544577fffffffff0000000000000000000000000000000000000000000000000000000061096f613a94565b165f526016602052602060405f2054604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b34610544576080600319360112610544576109d261376f565b60243567ffffffffffffffff8111610544576109f290369060040161394b565b604435906064359173ffffffffffffffffffffffffffffffffffffffff83169182840361054457610a398273ffffffffffffffffffffffffffffffffffffffff928761495a565b941693845f526013602052610a5260405f205483613f68565b94670de0b6b3a763ffff8601809611610ae457610ad07fb98216be0267fa550428a584fe6ac1ef0f39788e0198372100e813444afecd2992670de0b6b3a76400006020980494610aa06143f2565b610ab5610aac87613c35565b98308a89614fbf565b604051938452888401526080604084015260808301906145d6565b9260608201528033930390a3604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610544576020600319360112610544577fffffffff00000000000000000000000000000000000000000000000000000000610b4b613a94565b165f526017602052602060ff60405f2054166040519015158152f35b3461054457604060031936011261054457610b8061376f565b73ffffffffffffffffffffffffffffffffffffffff610b9d613792565b91165f52600d60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b613a70565b346105445760e060031936011261054457610bf361376f565b610bfb613792565b9060443590606435906084359060ff821680920361054457428310610e4e5773ffffffffffffffffffffffffffffffffffffffff1692835f52600e60205260405f208054927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8414610ae45760805f916020936001870190556040519873ffffffffffffffffffffffffffffffffffffffff858b01917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60408d015216998a606082015286848201528760a08201528860c082015260c08152610ce260e082613806565b519020610ced613ec5565b9060405190868201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152610d32606282613806565b519020906040519182528482015260a435604082015260c435606082015282805260015afa15610e435773ffffffffffffffffffffffffffffffffffffffff5f5116848115159182610e39575b505015610e1157610e0c7f40336af4b170f3dad5ddfb59897a8289adc3bed01417ca7e2bd77f85bc52641393855f52600d60205260405f20875f526020528260405f205586867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020604051878152a3604051938493846040919493926060820195825260208201520152565b0390a3005b7f815e1d64000000000000000000000000000000000000000000000000000000005f5260045ffd5b1490508487610d7f565b6040513d5f823e3d90fd5b7f05787bdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f6003193601126105445760206fffffffffffffffffffffffffffffffff600f5416604051908152f35b34610544575f6003193601126105445760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610544576020600319360112610544576004355f526012602052602060405f2054604051908152f35b3461054457610f1736613bec565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361083057805167ffffffffffffffff811161112e57610f516009546137b5565b601f81116110d5575b506020601f8211600114610ff35791610fcb82610fe3937f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02955f91610fe8575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b6009555b604051918291602083526020830190613847565b0390a1005b905083015186610f9a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169060095f527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af915f5b8181106110bd5750927f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02949260019282610fe39610611086575b5050811b01600955610fcf565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580611079565b9192602060018192868901518155019401920161103f565b60095f5261111e907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c81019160208510611124575b601f0160051c01906142cc565b82610f5a565b9091508190611111565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61118961376f565b611191614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003557f43a3573cf238e4b97d4ffec8e9b8a69cd276b47cf68230dbdbec3a7a98b287235f80a2005b34610544575f60031936011261054457602067ffffffffffffffff600f5460801c16604051908152f35b34610544576020600319360112610544576004355f52601260205260206fffffffffffffffffffffffffffffffff600160405f20015416604051908152f35b3461054457602061067961125e36613b98565b9061126a9392936143f2565b61127384613f11565b9384614fbf565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6112a861376f565b165f526007602052602060ff60405f2054166040519015158152f35b34610544576112d236613bec565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361083057805167ffffffffffffffff811161112e5761130c600a546137b5565b601f811161147e575b506020601f821160011461139c579161138582610fe3937fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6955f91610fe857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b600a55604051918291602083526020830190613847565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821690600a5f527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8915f5b8181106114665750927fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6949260019282610fe3961061142f575b5050811b01600a55610fcf565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580611422565b919260206001819286890151815501940192016113e8565b600a5f526114c6907fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601f840160051c8101916020851061112457601f0160051c01906142cc565b82611315565b346105445760206106796114df36613b98565b906114eb9392936143f2565b6114f484613c35565b8094614fbf565b34610544576020600319360112610544576020610679600435614587565b34610544576020600319360112610544577fffffffff00000000000000000000000000000000000000000000000000000000611553613a94565b61155b614633565b16805f52601760205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557fa8480b135a28741e8c059528bf8f82de70278485fb86bfc816a183801f0a85705f80a2005b346105445773ffffffffffffffffffffffffffffffffffffffff7f74dc60cbc81a9472d04ad1d20e151d369c41104d655ed3f2f3091166a502cd8d60206115fd36613b5c565b9390611607614633565b1692835f52600882526116488160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a2005b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60145416604051908152f35b346105445760206003193601126105445760043567ffffffffffffffff8111610544573660238201121561054457806004013567ffffffffffffffff8111610544573660248260051b8401011161054457905f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd81360301915b838110156117755760248160051b830101358381121561054457820160248101359067ffffffffffffffff821161054457604401813603811361054457815f92918392604051928392833781018381520390305af461175e614558565b901561176d5750600101611701565b805190602001fd5b005b3461054457602060031936011261054457600435335f52600860205260ff60405f2054161561083057640ec41a0ddf81116118295760207f75fef0e2a5e934789b0723129a0d1bbfd4a50f39c5af9919626e4f3603aef5ff916117d86143f2565b600f5477ffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffff0000000000000000000000000000000000000000000000008360c01b16911617600f55604051908152a1005b7f0d54247f000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760406003193601126105445761186a61376f565b60243573ffffffffffffffffffffffffffffffffffffffff821691821561196057611894336142e2565b15611938576118a29061436a565b1561191057335f52600c60205260405f206118be828254613e9c565b9055815f52600c60205260405f206118d7828254613c28565b90556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3602060405160018152f35b7f861a96d6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f876736d1000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f6003193601126105445760206bffffffffffffffffffffffff601a5416604051908152f35b34610544575f600319360112610544576117756143f2565b34610544576020600319360112610544576004355f5260126020526020600160405f20015460801c604051908152f35b3461054457602060031936011261054457611a1461376f565b611a1c614633565b73ffffffffffffffffffffffffffffffffffffffff8116908115801590611aad575b156104ec57611a4b6143f2565b6bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000601a549260601b16911617601a557f7f1dd9b78dfeeb8c452333915b2f077f4920fefc4ec7f146767e9ba40303ef1f5f80a2005b506bffffffffffffffffffffffff601a541615611a3e565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff611af361376f565b165f526013602052602060405f2054604051908152f35b34610544576020600319360112610544576020611b2d611b2861376f565b61436a565b6040519015158152f35b34610544575f600319360112610544576040515f600a54611b57816137b5565b8084529060018116908115611be15750600114611b83575b611b7f83610fcf81850382613806565b0390f35b600a5f9081527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8939250905b808210611bc757509091508101602001610fcf611b6f565b919260018160209254838588010152019101909291611baf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b84019091019150610fcf9050611b6f565b34610544576040600319360112610544576020600435610679611c44613792565b611c4c6143f2565b611c5583614587565b9283614da2565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b3461054457611c9d36613b5c565b9073ffffffffffffffffffffffffffffffffffffffff5f5416330361083057602073ffffffffffffffffffffffffffffffffffffffff7f8da69db4003c01b5c7be66a7bb5953423222e5118b6af0aadf54e75feef5bc50921692835f52600782526116488160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610544576020600319360112610544576020611b2d611d8761376f565b6142e2565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b3461054457611dcc36613969565b90805160208201209173ffffffffffffffffffffffffffffffffffffffff6001541633148015611eca575b1561083057825f5260126020526fffffffffffffffffffffffffffffffff600160405f200154168111611ea257610e0c7fbc2ffe81312f53db4f327eca188ebdc13df66a8ce25f7dec6f5b4495fe27b37191845f526012602052600160405f20016fffffffffffffffffffffffffffffffff808316167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055604051918291339583613ea9565b7fbdeafe07000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f205416611df7565b34610544575f6003193601126105445760206bffffffffffffffffffffffff60195416604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff611f3961376f565b611f41614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060055416176005557f34c1885f043c6c77736fbc402c63a383472347b85868dab73d42b69596a98e945f80a2005b346105445760206003193601126105445760043567ffffffffffffffff811161054457602080611fc78193369060040161394b565b604051928184925191829101835e8101601881520301902054604051908152f35b346105445760406003193601126105445761200161376f565b60243567ffffffffffffffff81116105445761202190369060040161394b565b90335f52600860205260ff60405f205416156108305773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000601454161760145581519167ffffffffffffffff831161112e576120946015546137b5565b601f81116121ed575b50602092601f811160011461212e57806120ec91602094955f91610fe857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b6015555b604051918183925191829101835e81015f815203902090337f9deb43d71422af41853c3921fb364b7647f9a9b136e46d66d45c1bf707af706c5f80a4005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0811660155f527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475905f5b8181106121d55750906020949583600194931061219e575b5050811b016015556120f0565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580612191565b84870151835560209687019660019093019201612179565b60155f52612235907f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475601f860160051c8101916020871061112457601f0160051c01906142cc565b8361209d565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61226961376f565b165f52600e602052602060405f2054604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6122e161376f565b165f52600c602052602060405f2054604051908152f35b3461054457602060031936011261054457600435612314614633565b6706f05b59d3b20000811161051c5760195460601c158015906123a4575b156104ec5760207f8b940a95968ad5b511f89b01075446a4fe9f614f2dc5fbb9e9a6b227d6d4fd70916123636143f2565b6bffffffffffffffffffffffff81167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006019541617601955604051908152a1005b508015612332565b346105445760406003193601126105445760206004356106796123cd613792565b6123d56143f2565b6123de83614609565b8093614da2565b34610544575f600319360112610544576020601a5460601c604051908152f35b346105445760206003193601126105445761241e61376f565b612426614633565b73ffffffffffffffffffffffffffffffffffffffff81169081158015906124b7575b156104ec576124556143f2565b6bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006019549260601b169116176019557fe59cc3d47f72dbd81f7d5fc40b9b05d9c4374a54addea771648ae24943c26e765f80a2005b506bffffffffffffffffffffffff6019541615612448565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6124fd61376f565b165f526010602052602060ff60405f2054166040519015158152f35b346105445760206003193601126105445761253261376f565b61253a614633565b73ffffffffffffffffffffffffffffffffffffffff60065416801590811561266f575b50156126475773ffffffffffffffffffffffffffffffffffffffff811690815f52601060205260ff60405f205416156125b8575b507f8f125a24838c4c23e893904b255b5c672d43d4cb8af7e3d15841eaeabc1e68aa5f80a2005b601154906801000000000000000082101561112e576125e082600161260c9401601155613b17565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b805f52601060205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905581612591565b7f133c5cc8000000000000000000000000000000000000000000000000000000005f5260045ffd5b60249150602090604051928380927fe4bb26f200000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff871660048301525afa908115610e43575f916126d3575b508261255d565b6126f5915060203d6020116126fb575b6126ed8183613806565b810190613d35565b826126cc565b503d6126e3565b34610544575f60031936011261054457611b7f61271d613f7b565b604080519384526020840192909252908201529081906060820190565b346105445761274836613ac3565b90335f52600860205260ff60405f205416156108305761177592614b52565b3461054457604060031936011261054457612780613a94565b7fffffffff00000000000000000000000000000000000000000000000000000000602435916127ad614633565b16907f5c1a1a4f00000000000000000000000000000000000000000000000000000000821461284b57815f52601660205260405f205481116128235760207f488e0bfafe0a9580c2271bee1f563a47d309f0105ca950ea525d909b43b36daf91835f52601682528060405f2055604051908152a2005b7f17e0a21c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f07e895b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6128a161376f565b6128a9614633565b1680612900575b807fffffffffffffffffffffffff000000000000000000000000000000000000000060065416176006557f7c5f71ef3a94efd2804ad9a6eb74b723dae0d26ef7d2a031f7986c96ae55afda5f80a2005b6011545f5b8181106129135750506128b0565b73ffffffffffffffffffffffffffffffffffffffff61293182613b17565b90549060031b1c16604051907fe4bb26f20000000000000000000000000000000000000000000000000000000082526004820152602081602481875afa908115610e43575f9161298a575b501561264757600101612905565b6129a2915060203d81116126fb576126ed8183613806565b8461297c565b34610544575f600319360112610544576020601154604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6129f361376f565b6129fb614633565b16805f52601060205260ff60405f205416612a37575b7f34f33faa2592bc1f615ec3e91b55b7784665ce46461403c294824d85f9f664585f80a2005b5f5b6011549081811015612b93578273ffffffffffffffffffffffffffffffffffffffff612a6483613b17565b90549060031b1c1614612a7b576001915001612a39565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610ae4576125e073ffffffffffffffffffffffffffffffffffffffff612ac9612ad794613b17565b90549060031b1c1691613b17565b6011548015612b66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612b0b81613b17565b73ffffffffffffffffffffffffffffffffffffffff82549160031b1b191690556011555b805f52601060205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055612a11565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5050612b2f565b3461054457612ba836613969565b90805160208201209173ffffffffffffffffffffffffffffffffffffffff6001541633148015612c9b575b1561083057825f526012602052600160405f20015460801c8111612c73575f83815260126020526040902060010180546fffffffffffffffffffffffffffffffff16608083901b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000161790557fcedce6ffe8b7f89de49bd4f955667ca0a963a8059264196807b240ed470b25ce90610e0c90604051918291339583613ea9565b7f04c27fbf000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f205416612bd3565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60045416604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b34610544576020600319360112610544576004356011548110156105445773ffffffffffffffffffffffffffffffffffffffff612d55602092613b17565b90549060031b1c16604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff612d9361376f565b165f526008602052602060ff60405f2054166040519015158152f35b34610544576020600319360112610544576020610679600435613f11565b3461054457612ddb36613ac3565b90335f52600860205260ff60405f2054168015612e01575b15610830576117759261495a565b50335f52600760205260ff60405f205416612df3565b3461054457604060031936011261054457612e30613a94565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591612e5d614633565b16907f5c1a1a4f00000000000000000000000000000000000000000000000000000000821461284b57815f52601660205260405f20548110612ed35760207fed380a7a1f0afc99b313ac7d9f1e52e44430d32b4639c7993bd0021974e30c0e91835f52601682528060405f2055604051908152a2005b7f470f70c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461054457604060031936011261054457612f1461376f565b60243590612f20614633565b66470de4df8200008211612f7f57602073ffffffffffffffffffffffffffffffffffffffff7f1e29a0bf54cf1e929f17cc97a198ff5cf7f8da1df1cb8ff67f7184ce380f3924921692835f52601382528060405f2055604051908152a2005b7f516e7f38000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f60031936011261054457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610544575f600319360112610544576020610679613ec5565b34610544575f60031936011261054457602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610544575f60031936011261054457611b7f610fcf61399b565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61309761376f565b61309f614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002557e4237ebb79833e3e0bc633281452dc9e5c76b92b603140b2a53b0bceb441cae5f80a2005b34610544576130fd36613969565b90613106614633565b8051602082012091670de0b6b3a764000081116131dd57825f526012602052600160405f20015460801c81106131b5575f83815260126020526040902060010180546fffffffffffffffffffffffffffffffff16608083901b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000161790557f2a343b9a1ceba40853d01c6adeea53f5c0e4b95b4eb870ed4af309a0ead7e3999161062e60405192839283613ea9565b7f8433449d000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f0d6108b6000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760606003193601126105445761321e61376f565b613226613792565b60443573ffffffffffffffffffffffffffffffffffffffff83169182156119605773ffffffffffffffffffffffffffffffffffffffff81169384156119605761326e906142e2565b156119385761327c9061436a565b156119105760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef918333036132ef575b835f52600c825260405f206132c3828254613e9c565b9055845f52600c825260405f206132db828254613c28565b9055604051908152a3602060405160018152f35b5f848152600d8352604080822033835284529020548160018201613315575b50506132ad565b816133238261333d94613e9c565b5f888152600d875260408082203383528852902055613e9c565b604051908152847fc1886047cf852ffdaeda16dafd86e28507781ffba1faafef1d536d4abaa260b0843393a3858161330e565b34610544576020600319360112610544576020611b2d61338e61376f565b613e14565b34610544575f600319360112610544576020600b54604051908152f35b34610544576020600319360112610544576133c961376f565b5f5473ffffffffffffffffffffffffffffffffffffffff811633036108305773ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f557f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb55f80a2005b34610544576020600319360112610544576020611b2d61346b61376f565b613d4d565b346105445761347e3661388a565b73ffffffffffffffffffffffffffffffffffffffff6001541633148015613566575b1561083057604051818382376020818381016018815203019020541561353e575f604051828482376020818481016018815203019020557f70521cf6a7c2458c5ad406081ad7b3bc4afd31b01b586a157a9780fcee6a77cb610e0c7fffffffff000000000000000000000000000000000000000000000000000000006135268486613c91565b16936040519182916020835233956020840191613cf7565b7f1ea942a8000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f2054166134a0565b34610544576020600319360112610544576020610679600435613c35565b34610544576040600319360112610544576135b361376f565b73ffffffffffffffffffffffffffffffffffffffff60243591335f52600d60205260405f208282165f526020528260405f205560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610544575f600319360112610544576040515f60095461363f816137b5565b8084529060018116908115611be1575060011461366657611b7f83610fcf81850382613806565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106136aa57509091508101602001610fcf611b6f565b919260018160209254838588010152019101909291613692565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6136f261376f565b6136fa614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060045416176004557f6b530281a3f54e1c3e430297307183ba1bafca3cdf775404395c208e6cf3e15f5f80a2005b34610544575f600319360112610544576020613765613f7b565b5050604051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361054457565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361054457565b90600182811c921680156137fc575b60208310146137cf57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916137c4565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761112e57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9060206003198301126105445760043567ffffffffffffffff811161054457826023820112156105445780600401359267ffffffffffffffff84116105445760248483010111610544576024019190565b67ffffffffffffffff811161112e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b929192613921826138db565b9161392f6040519384613806565b829481845281830111610544578281602093845f960137010152565b9080601f830112156105445781602061396693359101613915565b90565b6040600319820112610544576004359067ffffffffffffffff8211610544576139949160040161394b565b9060243590565b604051905f82601554916139ae836137b5565b8083529260018116908115613a3357506001146139d4575b6139d292500383613806565b565b5060155f90815290917f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec4755b818310613a175750509060206139d2928201016139c6565b60209193508060019154838589010152019101909184926139ff565b602092506139d29491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b8201016139c6565b3461054457602060031936011261054457613a8961376f565b5060206040515f8152f35b600435907fffffffff000000000000000000000000000000000000000000000000000000008216820361054457565b9060606003198301126105445760043573ffffffffffffffffffffffffffffffffffffffff8116810361054457916024359067ffffffffffffffff821161054457613b109160040161394b565b9060443590565b601154811015613b2f5760115f5260205f2001905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60031960409101126105445760043573ffffffffffffffffffffffffffffffffffffffff81168103610544579060243580151581036105445790565b6003196060910112610544576004359060243573ffffffffffffffffffffffffffffffffffffffff81168103610544579060443573ffffffffffffffffffffffffffffffffffffffff811681036105445790565b6020600319820112610544576004359067ffffffffffffffff821161054457806023830112156105445781602461396693600401359101613915565b91908201809211610ae457565b613c51613c7d613c56613c46613f7b565b919490600b54613c28565b613c28565b7f000000000000000000000000000000000000000000000000000000000000000090613c28565b60018201809211610ae457613966926147dd565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110613cc5575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610544575180151581036105445790565b73ffffffffffffffffffffffffffffffffffffffff16308114908115613df3575b8115613d78575090565b9050602073ffffffffffffffffffffffffffffffffffffffff60045416916024604051809481937f0d326b1800000000000000000000000000000000000000000000000000000000835260048301525afa908115610e43575f91613dda575090565b613966915060203d6020116126fb576126ed8183613806565b60045473ffffffffffffffffffffffffffffffffffffffff16159150613d6e565b73ffffffffffffffffffffffffffffffffffffffff600554168015918215613e3b57505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f20fe8d580000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b91908203918211610ae457565b929190613ec0602091604086526040860190613847565b930152565b60405160208101907f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218825246604082015230606082015260608152613f0b608082613806565b51902090565b613c5190613f20613c46613f7b565b60018301809311610ae45761396692613f5d613f63927f000000000000000000000000000000000000000000000000000000000000000090613c28565b92613f68565b614521565b81810292918115918404141715610ae457565b5f5c6142b057600f54613f9b67ffffffffffffffff8260801c1642613e9c565b916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115610e43575f9161427e575b505f6011545b8082106141d1575050614062670de0b6b3a764000061405b6fffffffffffffffffffffffffffffffff8616956140518888613f68565b9060c01c90613f68565b0484613c28565b81811090821802189180830390831102801515806141b8575b806141a4575b1561419c576140aa670de0b6b3a7640000916bffffffffffffffffffffffff6019541690613f68565b04925b80151580614183575b8061416f575b15614168576140ee6140d7670de0b6b3a76400009285613f68565b6bffffffffffffffffffffffff601a541690613f68565b045b614103816140fe8686613e9c565b613e9c565b600b54947f0000000000000000000000000000000000000000000000000000000000000000926141338488613c28565b60018401809411610ae4576141629461415685613f6361415c94613f6397613f68565b98613c28565b90613f68565b91929190565b505f6140f0565b5061417e601a5460601c61436a565b6140bc565b506bffffffffffffffffffffffff601a541615156140b6565b505f926140ad565b506141b360195460601c61436a565b614081565b506bffffffffffffffffffffffff60195416151561407b565b90916004602073ffffffffffffffffffffffffffffffffffffffff6141f586613b17565b90549060031b1c16604051928380927f56c075730000000000000000000000000000000000000000000000000000000082525afa908115610e43575f9161424c575b5061424490600192613c28565b92019061401b565b90506020813d8211614276575b8161426660209383613806565b8101031261054457516001614237565b3d9150614259565b90506020813d6020116142a8575b8161429960209383613806565b8101031261054457515f614015565b3d915061428c565b6fffffffffffffffffffffffffffffffff600f5416905f905f90565b8181106142d7575050565b5f81556001016142cc565b73ffffffffffffffffffffffffffffffffffffffff60035416801591821561430957505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f8e511e4d0000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b73ffffffffffffffffffffffffffffffffffffffff60025416801591821561439157505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f98c9b49c0000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b6143fa613f7b565b91600f547f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc0460806040516fffffffffffffffffffffffffffffffff84168152846020820152856040820152866060820152a17fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff61448784614f21565b16911617600f555f5c15614519575b5080614504575b50806144ef575b50600f547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff000000000000000000000000000000004260801b16911617600f55565b6144fe90601a5460601c614f4d565b5f6144a4565b6145139060195460601c614f4d565b5f61449d565b5f5d5f614496565b811561452b570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b3d15614582573d90614569826138db565b916145776040519384613806565b82523d5f602084013e565b606090565b613c5190614596613c46613f7b565b9160018101809111610ae4576145d0613966937f000000000000000000000000000000000000000000000000000000000000000090613c28565b916147dd565b90602080835192838152019201905f5b8181106145f35750505090565b82518452602093840193909201916001016145e6565b613c5161461a613c56613c46613f7b565b9160018201809211610ae45761396692613f6391613f68565b5f357fffffffff00000000000000000000000000000000000000000000000000000000811690600436106147a9575b50604051365f82376020813681016018815203019020541561353e57604051365f82376020813681016018815203019020544210614781577fffffffff0000000000000000000000000000000000000000000000000000000016805f52601760205260ff60405f205416614759575f604051368282376020813681016018815203019020557f29aa42fc192ff77ef42105abba283197ac841341e196e417a7fc2784cdc4e5fb60405160208152366020820152365f60408301375f602080368401010152602081817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f360116820101030190a2565b7f281df4aa000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f621e25c3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fffffffff000000000000000000000000000000000000000000000000000000008092503660040360031b1b16165f614662565b906147e791613f68565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810191818311610ae45761396692613f6391613c28565b919060408382031261054457825167ffffffffffffffff81116105445783019080601f830112156105445781519167ffffffffffffffff831161112e578260051b90604051936148736020840186613806565b845260208085019282010192831161054457602001905b82821061489d5750505060209092015190565b815181526020918201910161488a565b92937fffffffff0000000000000000000000000000000000000000000000000000000060609396956148fc73ffffffffffffffffffffffffffffffffffffffff94608088526080880190613847565b97602087015216604085015216910152565b8051821015613b2f5760209160051b010190565b9190915f8382019384129112908015821691151617610ae457565b939291613ec09060409286526060602087015260608601906145d6565b919273ffffffffffffffffffffffffffffffffffffffff8316805f52601060205260ff60405f20541615614b2a575f6149e893604051809581927f4e45f1ff00000000000000000000000000000000000000000000000000000000835233908a7fffffffff0000000000000000000000000000000000000000000000000000000087351691600486016148ad565b038183855af1948515610e43575f935f96614b00575b505f5b8451811015614a9457614a14818661490e565b515f52601260205260405f209081548015614a6c5788614a3391614922565b5f8112614a44576001925501614a01565b7fe58d4718000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fba0d87b5000000000000000000000000000000000000000000000000000000005f5260045ffd5b509194614afa90614aeb847fd602b36fb24934aef1bc2a658de029b486fa4c664a6e45de1f48e3fd1be25dd994969730907f00000000000000000000000000000000000000000000000000000000000000006152fd565b6040519182918733968461493d565b0390a390565b909550614b209193503d805f833e614b188183613806565b810190614820565b929092945f6149fe565b7ff521d159000000000000000000000000000000000000000000000000000000005f5260045ffd5b919273ffffffffffffffffffffffffffffffffffffffff831692835f52601060205260ff60405f20541615614b2a57614c1492614bb9865f93614b936143f2565b7f0000000000000000000000000000000000000000000000000000000000000000615427565b604051809481927f1eadd7780000000000000000000000000000000000000000000000000000000083523390897fffffffff0000000000000000000000000000000000000000000000000000000087351691600486016148ad565b038183875af1928315610e43575f925f94614d80575b505f5b8351811015614d4457614c40818561490e565b515f52601260205260405f20614c57868254614922565b905f8212614a4457818155600101546fffffffffffffffffffffffffffffffff81168015614d1c578211614cf45760801c90670de0b6b3a76400008214918215614cd3575b505015614cab57600101614c2d565b7f44e1772c000000000000000000000000000000000000000000000000000000005f5260045ffd5b670de0b6b3a7640000919250614cea905f5c613f68565b0410155f80614c9c565b7f4616e4af000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fbb1a23b9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50927f2bc7948a96a066968d2a58aaf46eb0b305aa166b1d1951d2f7ef0919746b8c2a919492614d7b60405192839233968461493d565b0390a3565b909350614d989192503d805f833e614b188183613806565b919091925f614c2a565b91614dac8161436a565b1561191057614dba33613e14565b15614ef957614deb8330337f00000000000000000000000000000000000000000000000000000000000000006152fd565b614df58282614f4d565b614dfe83614f21565b906fffffffffffffffffffffffffffffffff600f5492166fffffffffffffffffffffffffffffffff831601916fffffffffffffffffffffffffffffffff8311610ae4577fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9416911617600f5560405192848452602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a373ffffffffffffffffffffffffffffffffffffffff601454169081614ee7575050565b6139d291614ef361399b565b90614b52565b7f515b7cd9000000000000000000000000000000000000000000000000000000005f5260045ffd5b6fffffffffffffffffffffffffffffffff8111614a44576fffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16908115611960577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205f92848452600c825260408420614fa5828254613c28565b9055614fb381600b54613c28565b600b55604051908152a3565b91929092614fcc826142e2565b1561193857614fda81613d4d565b156152d5576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000009260208260248173ffffffffffffffffffffffffffffffffffffffff88165afa8015610e43575f9061528f575b73ffffffffffffffffffffffffffffffffffffffff925080861180615282575b615259575b5016938433036151bf575b841561196057845f52600c60205260405f206150a6828254613e9c565b90556150b481600b54613e9c565b600b555f857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020604051858152a36150ec84614f21565b926fffffffffffffffffffffffffffffffff600f5494166fffffffffffffffffffffffffffffffff851603936fffffffffffffffffffffffffffffffff8511610ae4578361518a9287927fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9916911617600f55615427565b604051938452602084015216907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4565b845f52600d60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f2054817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361521c575b5050615089565b61522591613e9c565b855f52600d60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20555f81615215565b61527b9061526c84601454169188613e9c565b9061527561399b565b9061495a565b505f61507e565b5082601454161515615079565b506020823d6020116152cd575b816152a960209383613806565b810103126105445773ffffffffffffffffffffffffffffffffffffffff9151615059565b3d915061529c565b7f8181c5ea000000000000000000000000000000000000000000000000000000005f5260045ffd5b90813b156153ff575f809493819473ffffffffffffffffffffffffffffffffffffffff604051928160208501967f23b872dd00000000000000000000000000000000000000000000000000000000885216602485015216604483015260648201526064815261536d608482613806565b51925af1615379614558565b90156153d75780519081159182156153bd575b50501561539557565b7f1eded19c000000000000000000000000000000000000000000000000000000005f5260045ffd5b6153d09250602080918301019101613d35565b5f8061538c565b7fe65b7a77000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff046a714000000000000000000000000000000000000000000000000000000005f5260045ffd5b919091803b156153ff575f928380936040519073ffffffffffffffffffffffffffffffffffffffff60208301947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024830152604482015260448152615491606482613806565b51925af161549d614558565b90156154fb5780519081159182156154e1575b5050156154b957565b7f2f0470fc000000000000000000000000000000000000000000000000000000005f5260045ffd5b6154f49250602080918301019101613d35565b5f806154b0565b7face2a47e000000000000000000000000000000000000000000000000000000005f5260045ffdfea164736f6c634300081c000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c806301e1d1141461374b57806304dbf0ce146136c457806306fdde031461361f57806307a2d13a14612daf578063095ea7b31461359a5780630a28a4771461357c5780630b467b9b146134705780630d326b181461344d57806313af4035146133b057806318160ddd1461339357806320fe8d581461337057806323b872dd146132055780632438525b146130ef5780632cb19f98146130695780632e0292281461304e578063313ce567146130115780633644e51514612ff757806338d52e0f14612fa75780633e9d2ac714612efb578063402d267d14610bd55780634796629114612e175780634b219d1614612dcd5780634cdad50614612daf5780634dedf20e14612d655780634ef501ac14612d1757806350b5c16a14612ce457806354cde13e14612cb15780635797527014612b9a578063585cd34b146129c55780635aa22bc8146129a85780635b34b823146128735780635c1a1a4f146127675780635c9ce04d1461273a57806360a38ac11461270257806360d54d411461251957806368c18beb146124cf5780636a5f1aa2146124055780636d9a3010146123e55780636e553f65146123ac57806370897b23146122f857806370a08231146122b35780637e729ac4146122805780637ecebe001461223b5780637fb6caad14611fe85780638639fb0714611f92578063871c979c14611f0b5780638778878214611ee05780638c54519b14611dbe5780638da5cb5b14611d8c5780638e511e4d14611d695780638eede80114611d36578063920ed70614611c8f57806393ab2ab714611c5c57806394bf804d14611c2357806395d89b4114611b3757806398c9b49c14611b0a57806399e9918314611ac55780639faae464146119fb578063a68bafa3146119cb578063a6afed95146119b3578063a6f7f5d614611988578063a9059cbb14611851578063aa4abe7f14611777578063ac9650d814611686578063ad468d1114611653578063b192a84a146115b7578063b2e3284814611519578063b3d7f6b9146114fb578063b460af94146114cc578063b84c8246146112c4578063ba03a75f1461127a578063ba0876521461124b578063bc0dd3741461120c578063c0463711146111e2578063c21ad0281461115b578063c47f002714610f09578063c63d75b614610bd5578063c69507dd14610edf578063c6e6f5921461065b578063c719946c14610ea5578063ce04bebb14610e76578063ce96cb7714610bd5578063d505accf14610bda578063d905777e14610bd5578063dd62ed3e14610b67578063e470b8bc14610b11578063e4d38cd8146109b9578063e66f53b714610986578063e78ab14e14610935578063e90956cf14610898578063ece1d6e514610878578063ed27f7c914610858578063ef7fa71b14610681578063ef8b30f71461065b578063f6f98fd514610564578063f73f8f31146105485763fe56e23214610444575f80fd5b3461054457602060031936011261054457600435610460614633565b635e80a6bf811161051c57601a5460601c15801590610514575b156104ec5760207fd87632b1c6ebfa21acbca0e3279b3cf6385a377cb8fda51e5b866baa6e6012ab916104ab6143f2565b6bffffffffffffffffffffffff81167fffffffffffffffffffffffffffffffffffffffff000000000000000000000000601a541617601a55604051908152a1005b7fda9e0fa0000000000000000000000000000000000000000000000000000000005f5260045ffd5b50801561047a565b7fcd4e6167000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f80fd5b34610544575f6003193601126105445760205f5c604051908152f35b346105445761057236613969565b9061057b614633565b8051602082012091825f5260126020526fffffffffffffffffffffffffffffffff600160405f200154168110610633577f7368d59ed82f6a538f6deef9baa54623fe3699ce07b19031f762f740c8c34b03916105d682614f21565b845f5260126020526fffffffffffffffffffffffffffffffff600160405f200191167fffffffffffffffffffffffffffffffff0000000000000000000000000000000082541617905561062e60405192839283613ea9565b0390a2005b7fa844d937000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544576020600319360112610544576020610679600435614609565b604051908152f35b346105445761068f3661388a565b73ffffffffffffffffffffffffffffffffffffffff6001541633036108305760405181838237602081838101601881520301902054610808577fffffffff000000000000000000000000000000000000000000000000000000006106f38284613c91565b16917f5c1a1a4f0000000000000000000000000000000000000000000000000000000083036107d15781600811610544577f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb917fffffffff000000000000000000000000000000000000000000000000000000006004830135165f52601660205261078360405f20545b42613c28565b60405182848237602081848101601881520301902055604051818382376020818381016018815203019020546107c6604051938493604085526040850191613cf7565b9060208301520390a2005b7f8b18afeb361b83b025999ed5b42f1d90c68aaa5a0fd49c015f04c3b8b81e80eb91835f52601660205261078360405f205461077d565b7fd91ff208000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f60031936011261054457602060195460601c604051908152f35b34610544575f600319360112610544576020600f5460c01c604051908152f35b34610544576020600319360112610544576108b161376f565b73ffffffffffffffffffffffffffffffffffffffff5f541633036108305773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001557fbd0a63c12948fbc9194a5839019f99c9d71db924e5c70018265bc778b8f1a5065f80a2005b34610544576020600319360112610544577fffffffff0000000000000000000000000000000000000000000000000000000061096f613a94565b165f526016602052602060405f2054604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b34610544576080600319360112610544576109d261376f565b60243567ffffffffffffffff8111610544576109f290369060040161394b565b604435906064359173ffffffffffffffffffffffffffffffffffffffff83169182840361054457610a398273ffffffffffffffffffffffffffffffffffffffff928761495a565b941693845f526013602052610a5260405f205483613f68565b94670de0b6b3a763ffff8601809611610ae457610ad07fb98216be0267fa550428a584fe6ac1ef0f39788e0198372100e813444afecd2992670de0b6b3a76400006020980494610aa06143f2565b610ab5610aac87613c35565b98308a89614fbf565b604051938452888401526080604084015260808301906145d6565b9260608201528033930390a3604051908152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b34610544576020600319360112610544577fffffffff00000000000000000000000000000000000000000000000000000000610b4b613a94565b165f526017602052602060ff60405f2054166040519015158152f35b3461054457604060031936011261054457610b8061376f565b73ffffffffffffffffffffffffffffffffffffffff610b9d613792565b91165f52600d60205273ffffffffffffffffffffffffffffffffffffffff60405f2091165f52602052602060405f2054604051908152f35b613a70565b346105445760e060031936011261054457610bf361376f565b610bfb613792565b9060443590606435906084359060ff821680920361054457428310610e4e5773ffffffffffffffffffffffffffffffffffffffff1692835f52600e60205260405f208054927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8414610ae45760805f916020936001870190556040519873ffffffffffffffffffffffffffffffffffffffff858b01917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528a60408d015216998a606082015286848201528760a08201528860c082015260c08152610ce260e082613806565b519020610ced613ec5565b9060405190868201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152610d32606282613806565b519020906040519182528482015260a435604082015260c435606082015282805260015afa15610e435773ffffffffffffffffffffffffffffffffffffffff5f5116848115159182610e39575b505015610e1157610e0c7f40336af4b170f3dad5ddfb59897a8289adc3bed01417ca7e2bd77f85bc52641393855f52600d60205260405f20875f526020528260405f205586867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9256020604051878152a3604051938493846040919493926060820195825260208201520152565b0390a3005b7f815e1d64000000000000000000000000000000000000000000000000000000005f5260045ffd5b1490508487610d7f565b6040513d5f823e3d90fd5b7f05787bdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f6003193601126105445760206fffffffffffffffffffffffffffffffff600f5416604051908152f35b34610544575f6003193601126105445760206040517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b34610544576020600319360112610544576004355f526012602052602060405f2054604051908152f35b3461054457610f1736613bec565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361083057805167ffffffffffffffff811161112e57610f516009546137b5565b601f81116110d5575b506020601f8211600114610ff35791610fcb82610fe3937f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02955f91610fe8575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b6009555b604051918291602083526020830190613847565b0390a1005b905083015186610f9a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082169060095f527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af915f5b8181106110bd5750927f4df9dcd34ae35f40f2c756fd8ac83210ed0b76d065543ee73d868aec7c7fcf02949260019282610fe39610611086575b5050811b01600955610fcf565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580611079565b9192602060018192868901518155019401920161103f565b60095f5261111e907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c81019160208510611124575b601f0160051c01906142cc565b82610f5a565b9091508190611111565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61118961376f565b611191614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060035416176003557f43a3573cf238e4b97d4ffec8e9b8a69cd276b47cf68230dbdbec3a7a98b287235f80a2005b34610544575f60031936011261054457602067ffffffffffffffff600f5460801c16604051908152f35b34610544576020600319360112610544576004355f52601260205260206fffffffffffffffffffffffffffffffff600160405f20015416604051908152f35b3461054457602061067961125e36613b98565b9061126a9392936143f2565b61127384613f11565b9384614fbf565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6112a861376f565b165f526007602052602060ff60405f2054166040519015158152f35b34610544576112d236613bec565b73ffffffffffffffffffffffffffffffffffffffff5f5416330361083057805167ffffffffffffffff811161112e5761130c600a546137b5565b601f811161147e575b506020601f821160011461139c579161138582610fe3937fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6955f91610fe857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b600a55604051918291602083526020830190613847565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0821690600a5f527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8915f5b8181106114665750927fadf3ae8bd543b3007d464f15cb8ea1db3f44e84d41d203164f40b95e27558ac6949260019282610fe3961061142f575b5050811b01600a55610fcf565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580611422565b919260206001819286890151815501940192016113e8565b600a5f526114c6907fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601f840160051c8101916020851061112457601f0160051c01906142cc565b82611315565b346105445760206106796114df36613b98565b906114eb9392936143f2565b6114f484613c35565b8094614fbf565b34610544576020600319360112610544576020610679600435614587565b34610544576020600319360112610544577fffffffff00000000000000000000000000000000000000000000000000000000611553613a94565b61155b614633565b16805f52601760205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557fa8480b135a28741e8c059528bf8f82de70278485fb86bfc816a183801f0a85705f80a2005b346105445773ffffffffffffffffffffffffffffffffffffffff7f74dc60cbc81a9472d04ad1d20e151d369c41104d655ed3f2f3091166a502cd8d60206115fd36613b5c565b9390611607614633565b1692835f52600882526116488160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a2005b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60145416604051908152f35b346105445760206003193601126105445760043567ffffffffffffffff8111610544573660238201121561054457806004013567ffffffffffffffff8111610544573660248260051b8401011161054457905f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd81360301915b838110156117755760248160051b830101358381121561054457820160248101359067ffffffffffffffff821161054457604401813603811361054457815f92918392604051928392833781018381520390305af461175e614558565b901561176d5750600101611701565b805190602001fd5b005b3461054457602060031936011261054457600435335f52600860205260ff60405f2054161561083057640ec41a0ddf81116118295760207f75fef0e2a5e934789b0723129a0d1bbfd4a50f39c5af9919626e4f3603aef5ff916117d86143f2565b600f5477ffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffff0000000000000000000000000000000000000000000000008360c01b16911617600f55604051908152a1005b7f0d54247f000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760406003193601126105445761186a61376f565b60243573ffffffffffffffffffffffffffffffffffffffff821691821561196057611894336142e2565b15611938576118a29061436a565b1561191057335f52600c60205260405f206118be828254613e9c565b9055815f52600c60205260405f206118d7828254613c28565b90556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3602060405160018152f35b7f861a96d6000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f876736d1000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd92e233d000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f6003193601126105445760206bffffffffffffffffffffffff601a5416604051908152f35b34610544575f600319360112610544576117756143f2565b34610544576020600319360112610544576004355f5260126020526020600160405f20015460801c604051908152f35b3461054457602060031936011261054457611a1461376f565b611a1c614633565b73ffffffffffffffffffffffffffffffffffffffff8116908115801590611aad575b156104ec57611a4b6143f2565b6bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000601a549260601b16911617601a557f7f1dd9b78dfeeb8c452333915b2f077f4920fefc4ec7f146767e9ba40303ef1f5f80a2005b506bffffffffffffffffffffffff601a541615611a3e565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff611af361376f565b165f526013602052602060405f2054604051908152f35b34610544576020600319360112610544576020611b2d611b2861376f565b61436a565b6040519015158152f35b34610544575f600319360112610544576040515f600a54611b57816137b5565b8084529060018116908115611be15750600114611b83575b611b7f83610fcf81850382613806565b0390f35b600a5f9081527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8939250905b808210611bc757509091508101602001610fcf611b6f565b919260018160209254838588010152019101909291611baf565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b84019091019150610fcf9050611b6f565b34610544576040600319360112610544576020600435610679611c44613792565b611c4c6143f2565b611c5583614587565b9283614da2565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60035416604051908152f35b3461054457611c9d36613b5c565b9073ffffffffffffffffffffffffffffffffffffffff5f5416330361083057602073ffffffffffffffffffffffffffffffffffffffff7f8da69db4003c01b5c7be66a7bb5953423222e5118b6af0aadf54e75feef5bc50921692835f52600782526116488160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b34610544576020600319360112610544576020611b2d611d8761376f565b6142e2565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b3461054457611dcc36613969565b90805160208201209173ffffffffffffffffffffffffffffffffffffffff6001541633148015611eca575b1561083057825f5260126020526fffffffffffffffffffffffffffffffff600160405f200154168111611ea257610e0c7fbc2ffe81312f53db4f327eca188ebdc13df66a8ce25f7dec6f5b4495fe27b37191845f526012602052600160405f20016fffffffffffffffffffffffffffffffff808316167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055604051918291339583613ea9565b7fbdeafe07000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f205416611df7565b34610544575f6003193601126105445760206bffffffffffffffffffffffff60195416604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff611f3961376f565b611f41614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060055416176005557f34c1885f043c6c77736fbc402c63a383472347b85868dab73d42b69596a98e945f80a2005b346105445760206003193601126105445760043567ffffffffffffffff811161054457602080611fc78193369060040161394b565b604051928184925191829101835e8101601881520301902054604051908152f35b346105445760406003193601126105445761200161376f565b60243567ffffffffffffffff81116105445761202190369060040161394b565b90335f52600860205260ff60405f205416156108305773ffffffffffffffffffffffffffffffffffffffff16807fffffffffffffffffffffffff0000000000000000000000000000000000000000601454161760145581519167ffffffffffffffff831161112e576120946015546137b5565b601f81116121ed575b50602092601f811160011461212e57806120ec91602094955f91610fe857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c19161790565b6015555b604051918183925191829101835e81015f815203902090337f9deb43d71422af41853c3921fb364b7647f9a9b136e46d66d45c1bf707af706c5f80a4005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0811660155f527f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475905f5b8181106121d55750906020949583600194931061219e575b5050811b016015556120f0565b8401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690558580612191565b84870151835560209687019660019093019201612179565b60155f52612235907f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475601f860160051c8101916020871061112457601f0160051c01906142cc565b8361209d565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61226961376f565b165f52600e602052602060405f2054604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60025416604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6122e161376f565b165f52600c602052602060405f2054604051908152f35b3461054457602060031936011261054457600435612314614633565b6706f05b59d3b20000811161051c5760195460601c158015906123a4575b156104ec5760207f8b940a95968ad5b511f89b01075446a4fe9f614f2dc5fbb9e9a6b227d6d4fd70916123636143f2565b6bffffffffffffffffffffffff81167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006019541617601955604051908152a1005b508015612332565b346105445760406003193601126105445760206004356106796123cd613792565b6123d56143f2565b6123de83614609565b8093614da2565b34610544575f600319360112610544576020601a5460601c604051908152f35b346105445760206003193601126105445761241e61376f565b612426614633565b73ffffffffffffffffffffffffffffffffffffffff81169081158015906124b7575b156104ec576124556143f2565b6bffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006019549260601b169116176019557fe59cc3d47f72dbd81f7d5fc40b9b05d9c4374a54addea771648ae24943c26e765f80a2005b506bffffffffffffffffffffffff6019541615612448565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6124fd61376f565b165f526010602052602060ff60405f2054166040519015158152f35b346105445760206003193601126105445761253261376f565b61253a614633565b73ffffffffffffffffffffffffffffffffffffffff60065416801590811561266f575b50156126475773ffffffffffffffffffffffffffffffffffffffff811690815f52601060205260ff60405f205416156125b8575b507f8f125a24838c4c23e893904b255b5c672d43d4cb8af7e3d15841eaeabc1e68aa5f80a2005b601154906801000000000000000082101561112e576125e082600161260c9401601155613b17565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b805f52601060205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082541617905581612591565b7f133c5cc8000000000000000000000000000000000000000000000000000000005f5260045ffd5b60249150602090604051928380927fe4bb26f200000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff871660048301525afa908115610e43575f916126d3575b508261255d565b6126f5915060203d6020116126fb575b6126ed8183613806565b810190613d35565b826126cc565b503d6126e3565b34610544575f60031936011261054457611b7f61271d613f7b565b604080519384526020840192909252908201529081906060820190565b346105445761274836613ac3565b90335f52600860205260ff60405f205416156108305761177592614b52565b3461054457604060031936011261054457612780613a94565b7fffffffff00000000000000000000000000000000000000000000000000000000602435916127ad614633565b16907f5c1a1a4f00000000000000000000000000000000000000000000000000000000821461284b57815f52601660205260405f205481116128235760207f488e0bfafe0a9580c2271bee1f563a47d309f0105ca950ea525d909b43b36daf91835f52601682528060405f2055604051908152a2005b7f17e0a21c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f07e895b1000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6128a161376f565b6128a9614633565b1680612900575b807fffffffffffffffffffffffff000000000000000000000000000000000000000060065416176006557f7c5f71ef3a94efd2804ad9a6eb74b723dae0d26ef7d2a031f7986c96ae55afda5f80a2005b6011545f5b8181106129135750506128b0565b73ffffffffffffffffffffffffffffffffffffffff61293182613b17565b90549060031b1c16604051907fe4bb26f20000000000000000000000000000000000000000000000000000000082526004820152602081602481875afa908115610e43575f9161298a575b501561264757600101612905565b6129a2915060203d81116126fb576126ed8183613806565b8461297c565b34610544575f600319360112610544576020601154604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6129f361376f565b6129fb614633565b16805f52601060205260ff60405f205416612a37575b7f34f33faa2592bc1f615ec3e91b55b7784665ce46461403c294824d85f9f664585f80a2005b5f5b6011549081811015612b93578273ffffffffffffffffffffffffffffffffffffffff612a6483613b17565b90549060031b1c1614612a7b576001915001612a39565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610ae4576125e073ffffffffffffffffffffffffffffffffffffffff612ac9612ad794613b17565b90549060031b1c1691613b17565b6011548015612b66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01612b0b81613b17565b73ffffffffffffffffffffffffffffffffffffffff82549160031b1b191690556011555b805f52601060205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055612a11565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5050612b2f565b3461054457612ba836613969565b90805160208201209173ffffffffffffffffffffffffffffffffffffffff6001541633148015612c9b575b1561083057825f526012602052600160405f20015460801c8111612c73575f83815260126020526040902060010180546fffffffffffffffffffffffffffffffff16608083901b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000161790557fcedce6ffe8b7f89de49bd4f955667ca0a963a8059264196807b240ed470b25ce90610e0c90604051918291339583613ea9565b7f04c27fbf000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f205416612bd3565b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60045416604051908152f35b34610544575f60031936011261054457602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b34610544576020600319360112610544576004356011548110156105445773ffffffffffffffffffffffffffffffffffffffff612d55602092613b17565b90549060031b1c16604051908152f35b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff612d9361376f565b165f526008602052602060ff60405f2054166040519015158152f35b34610544576020600319360112610544576020610679600435613f11565b3461054457612ddb36613ac3565b90335f52600860205260ff60405f2054168015612e01575b15610830576117759261495a565b50335f52600760205260ff60405f205416612df3565b3461054457604060031936011261054457612e30613a94565b7fffffffff0000000000000000000000000000000000000000000000000000000060243591612e5d614633565b16907f5c1a1a4f00000000000000000000000000000000000000000000000000000000821461284b57815f52601660205260405f20548110612ed35760207fed380a7a1f0afc99b313ac7d9f1e52e44430d32b4639c7993bd0021974e30c0e91835f52601682528060405f2055604051908152a2005b7f470f70c2000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461054457604060031936011261054457612f1461376f565b60243590612f20614633565b66470de4df8200008211612f7f57602073ffffffffffffffffffffffffffffffffffffffff7f1e29a0bf54cf1e929f17cc97a198ff5cf7f8da1df1cb8ff67f7184ce380f3924921692835f52601382528060405f2055604051908152a2005b7f516e7f38000000000000000000000000000000000000000000000000000000005f5260045ffd5b34610544575f60031936011261054457602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f168152f35b34610544575f600319360112610544576020610679613ec5565b34610544575f60031936011261054457602060405160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b34610544575f60031936011261054457611b7f610fcf61399b565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff61309761376f565b61309f614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060025416176002557e4237ebb79833e3e0bc633281452dc9e5c76b92b603140b2a53b0bceb441cae5f80a2005b34610544576130fd36613969565b90613106614633565b8051602082012091670de0b6b3a764000081116131dd57825f526012602052600160405f20015460801c81106131b5575f83815260126020526040902060010180546fffffffffffffffffffffffffffffffff16608083901b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000161790557f2a343b9a1ceba40853d01c6adeea53f5c0e4b95b4eb870ed4af309a0ead7e3999161062e60405192839283613ea9565b7f8433449d000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f0d6108b6000000000000000000000000000000000000000000000000000000005f5260045ffd5b346105445760606003193601126105445761321e61376f565b613226613792565b60443573ffffffffffffffffffffffffffffffffffffffff83169182156119605773ffffffffffffffffffffffffffffffffffffffff81169384156119605761326e906142e2565b156119385761327c9061436a565b156119105760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef918333036132ef575b835f52600c825260405f206132c3828254613e9c565b9055845f52600c825260405f206132db828254613c28565b9055604051908152a3602060405160018152f35b5f848152600d8352604080822033835284529020548160018201613315575b50506132ad565b816133238261333d94613e9c565b5f888152600d875260408082203383528852902055613e9c565b604051908152847fc1886047cf852ffdaeda16dafd86e28507781ffba1faafef1d536d4abaa260b0843393a3858161330e565b34610544576020600319360112610544576020611b2d61338e61376f565b613e14565b34610544575f600319360112610544576020600b54604051908152f35b34610544576020600319360112610544576133c961376f565b5f5473ffffffffffffffffffffffffffffffffffffffff811633036108305773ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f557f167d3e9c1016ab80e58802ca9da10ce5c6a0f4debc46a2e7a2cd9e56899a4fb55f80a2005b34610544576020600319360112610544576020611b2d61346b61376f565b613d4d565b346105445761347e3661388a565b73ffffffffffffffffffffffffffffffffffffffff6001541633148015613566575b1561083057604051818382376020818381016018815203019020541561353e575f604051828482376020818481016018815203019020557f70521cf6a7c2458c5ad406081ad7b3bc4afd31b01b586a157a9780fcee6a77cb610e0c7fffffffff000000000000000000000000000000000000000000000000000000006135268486613c91565b16936040519182916020835233956020840191613cf7565b7f1ea942a8000000000000000000000000000000000000000000000000000000005f5260045ffd5b50335f52600760205260ff60405f2054166134a0565b34610544576020600319360112610544576020610679600435613c35565b34610544576040600319360112610544576135b361376f565b73ffffffffffffffffffffffffffffffffffffffff60243591335f52600d60205260405f208282165f526020528260405f205560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b34610544575f600319360112610544576040515f60095461363f816137b5565b8084529060018116908115611be1575060011461366657611b7f83610fcf81850382613806565b60095f9081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106136aa57509091508101602001610fcf611b6f565b919260018160209254838588010152019101909291613692565b346105445760206003193601126105445773ffffffffffffffffffffffffffffffffffffffff6136f261376f565b6136fa614633565b16807fffffffffffffffffffffffff000000000000000000000000000000000000000060045416176004557f6b530281a3f54e1c3e430297307183ba1bafca3cdf775404395c208e6cf3e15f5f80a2005b34610544575f600319360112610544576020613765613f7b565b5050604051908152f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361054457565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361054457565b90600182811c921680156137fc575b60208310146137cf57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916137c4565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761112e57604052565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b9060206003198301126105445760043567ffffffffffffffff811161054457826023820112156105445780600401359267ffffffffffffffff84116105445760248483010111610544576024019190565b67ffffffffffffffff811161112e57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b929192613921826138db565b9161392f6040519384613806565b829481845281830111610544578281602093845f960137010152565b9080601f830112156105445781602061396693359101613915565b90565b6040600319820112610544576004359067ffffffffffffffff8211610544576139949160040161394b565b9060243590565b604051905f82601554916139ae836137b5565b8083529260018116908115613a3357506001146139d4575b6139d292500383613806565b565b5060155f90815290917f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec4755b818310613a175750509060206139d2928201016139c6565b60209193508060019154838589010152019101909184926139ff565b602092506139d29491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b8201016139c6565b3461054457602060031936011261054457613a8961376f565b5060206040515f8152f35b600435907fffffffff000000000000000000000000000000000000000000000000000000008216820361054457565b9060606003198301126105445760043573ffffffffffffffffffffffffffffffffffffffff8116810361054457916024359067ffffffffffffffff821161054457613b109160040161394b565b9060443590565b601154811015613b2f5760115f5260205f2001905f90565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60031960409101126105445760043573ffffffffffffffffffffffffffffffffffffffff81168103610544579060243580151581036105445790565b6003196060910112610544576004359060243573ffffffffffffffffffffffffffffffffffffffff81168103610544579060443573ffffffffffffffffffffffffffffffffffffffff811681036105445790565b6020600319820112610544576004359067ffffffffffffffff821161054457806023830112156105445781602461396693600401359101613915565b91908201809211610ae457565b613c51613c7d613c56613c46613f7b565b919490600b54613c28565b613c28565b7f0000000000000000000000000000000000000000000000000de0b6b3a764000090613c28565b60018201809211610ae457613966926147dd565b919091357fffffffff0000000000000000000000000000000000000000000000000000000081169260048110613cc5575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610544575180151581036105445790565b73ffffffffffffffffffffffffffffffffffffffff16308114908115613df3575b8115613d78575090565b9050602073ffffffffffffffffffffffffffffffffffffffff60045416916024604051809481937f0d326b1800000000000000000000000000000000000000000000000000000000835260048301525afa908115610e43575f91613dda575090565b613966915060203d6020116126fb576126ed8183613806565b60045473ffffffffffffffffffffffffffffffffffffffff16159150613d6e565b73ffffffffffffffffffffffffffffffffffffffff600554168015918215613e3b57505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f20fe8d580000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b91908203918211610ae457565b929190613ec0602091604086526040860190613847565b930152565b60405160208101907f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218825246604082015230606082015260608152613f0b608082613806565b51902090565b613c5190613f20613c46613f7b565b60018301809311610ae45761396692613f5d613f63927f0000000000000000000000000000000000000000000000000de0b6b3a764000090613c28565b92613f68565b614521565b81810292918115918404141715610ae457565b5f5c6142b057600f54613f9b67ffffffffffffffff8260801c1642613e9c565b916040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f165afa908115610e43575f9161427e575b505f6011545b8082106141d1575050614062670de0b6b3a764000061405b6fffffffffffffffffffffffffffffffff8616956140518888613f68565b9060c01c90613f68565b0484613c28565b81811090821802189180830390831102801515806141b8575b806141a4575b1561419c576140aa670de0b6b3a7640000916bffffffffffffffffffffffff6019541690613f68565b04925b80151580614183575b8061416f575b15614168576140ee6140d7670de0b6b3a76400009285613f68565b6bffffffffffffffffffffffff601a541690613f68565b045b614103816140fe8686613e9c565b613e9c565b600b54947f0000000000000000000000000000000000000000000000000de0b6b3a7640000926141338488613c28565b60018401809411610ae4576141629461415685613f6361415c94613f6397613f68565b98613c28565b90613f68565b91929190565b505f6140f0565b5061417e601a5460601c61436a565b6140bc565b506bffffffffffffffffffffffff601a541615156140b6565b505f926140ad565b506141b360195460601c61436a565b614081565b506bffffffffffffffffffffffff60195416151561407b565b90916004602073ffffffffffffffffffffffffffffffffffffffff6141f586613b17565b90549060031b1c16604051928380927f56c075730000000000000000000000000000000000000000000000000000000082525afa908115610e43575f9161424c575b5061424490600192613c28565b92019061401b565b90506020813d8211614276575b8161426660209383613806565b8101031261054457516001614237565b3d9150614259565b90506020813d6020116142a8575b8161429960209383613806565b8101031261054457515f614015565b3d915061428c565b6fffffffffffffffffffffffffffffffff600f5416905f905f90565b8181106142d7575050565b5f81556001016142cc565b73ffffffffffffffffffffffffffffffffffffffff60035416801591821561430957505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f8e511e4d0000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b73ffffffffffffffffffffffffffffffffffffffff60025416801591821561439157505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f98c9b49c0000000000000000000000000000000000000000000000000000000084521660048301525afa908115610e43575f91613dda575090565b6143fa613f7b565b91600f547f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc0460806040516fffffffffffffffffffffffffffffffff84168152846020820152856040820152866060820152a17fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff61448784614f21565b16911617600f555f5c15614519575b5080614504575b50806144ef575b50600f547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff77ffffffffffffffff000000000000000000000000000000004260801b16911617600f55565b6144fe90601a5460601c614f4d565b5f6144a4565b6145139060195460601c614f4d565b5f61449d565b5f5d5f614496565b811561452b570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b3d15614582573d90614569826138db565b916145776040519384613806565b82523d5f602084013e565b606090565b613c5190614596613c46613f7b565b9160018101809111610ae4576145d0613966937f0000000000000000000000000000000000000000000000000de0b6b3a764000090613c28565b916147dd565b90602080835192838152019201905f5b8181106145f35750505090565b82518452602093840193909201916001016145e6565b613c5161461a613c56613c46613f7b565b9160018201809211610ae45761396692613f6391613f68565b5f357fffffffff00000000000000000000000000000000000000000000000000000000811690600436106147a9575b50604051365f82376020813681016018815203019020541561353e57604051365f82376020813681016018815203019020544210614781577fffffffff0000000000000000000000000000000000000000000000000000000016805f52601760205260ff60405f205416614759575f604051368282376020813681016018815203019020557f29aa42fc192ff77ef42105abba283197ac841341e196e417a7fc2784cdc4e5fb60405160208152366020820152365f60408301375f602080368401010152602081817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f360116820101030190a2565b7f281df4aa000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f621e25c3000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fffffffff000000000000000000000000000000000000000000000000000000008092503660040360031b1b16165f614662565b906147e791613f68565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810191818311610ae45761396692613f6391613c28565b919060408382031261054457825167ffffffffffffffff81116105445783019080601f830112156105445781519167ffffffffffffffff831161112e578260051b90604051936148736020840186613806565b845260208085019282010192831161054457602001905b82821061489d5750505060209092015190565b815181526020918201910161488a565b92937fffffffff0000000000000000000000000000000000000000000000000000000060609396956148fc73ffffffffffffffffffffffffffffffffffffffff94608088526080880190613847565b97602087015216604085015216910152565b8051821015613b2f5760209160051b010190565b9190915f8382019384129112908015821691151617610ae457565b939291613ec09060409286526060602087015260608601906145d6565b919273ffffffffffffffffffffffffffffffffffffffff8316805f52601060205260ff60405f20541615614b2a575f6149e893604051809581927f4e45f1ff00000000000000000000000000000000000000000000000000000000835233908a7fffffffff0000000000000000000000000000000000000000000000000000000087351691600486016148ad565b038183855af1948515610e43575f935f96614b00575b505f5b8451811015614a9457614a14818661490e565b515f52601260205260405f209081548015614a6c5788614a3391614922565b5f8112614a44576001925501614a01565b7fe58d4718000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fba0d87b5000000000000000000000000000000000000000000000000000000005f5260045ffd5b509194614afa90614aeb847fd602b36fb24934aef1bc2a658de029b486fa4c664a6e45de1f48e3fd1be25dd994969730907f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f6152fd565b6040519182918733968461493d565b0390a390565b909550614b209193503d805f833e614b188183613806565b810190614820565b929092945f6149fe565b7ff521d159000000000000000000000000000000000000000000000000000000005f5260045ffd5b919273ffffffffffffffffffffffffffffffffffffffff831692835f52601060205260ff60405f20541615614b2a57614c1492614bb9865f93614b936143f2565b7f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f615427565b604051809481927f1eadd7780000000000000000000000000000000000000000000000000000000083523390897fffffffff0000000000000000000000000000000000000000000000000000000087351691600486016148ad565b038183875af1928315610e43575f925f94614d80575b505f5b8351811015614d4457614c40818561490e565b515f52601260205260405f20614c57868254614922565b905f8212614a4457818155600101546fffffffffffffffffffffffffffffffff81168015614d1c578211614cf45760801c90670de0b6b3a76400008214918215614cd3575b505015614cab57600101614c2d565b7f44e1772c000000000000000000000000000000000000000000000000000000005f5260045ffd5b670de0b6b3a7640000919250614cea905f5c613f68565b0410155f80614c9c565b7f4616e4af000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fbb1a23b9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50927f2bc7948a96a066968d2a58aaf46eb0b305aa166b1d1951d2f7ef0919746b8c2a919492614d7b60405192839233968461493d565b0390a3565b909350614d989192503d805f833e614b188183613806565b919091925f614c2a565b91614dac8161436a565b1561191057614dba33613e14565b15614ef957614deb8330337f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f6152fd565b614df58282614f4d565b614dfe83614f21565b906fffffffffffffffffffffffffffffffff600f5492166fffffffffffffffffffffffffffffffff831601916fffffffffffffffffffffffffffffffff8311610ae4577fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9416911617600f5560405192848452602084015216907fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d760403392a373ffffffffffffffffffffffffffffffffffffffff601454169081614ee7575050565b6139d291614ef361399b565b90614b52565b7f515b7cd9000000000000000000000000000000000000000000000000000000005f5260045ffd5b6fffffffffffffffffffffffffffffffff8111614a44576fffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16908115611960577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60205f92848452600c825260408420614fa5828254613c28565b9055614fb381600b54613c28565b600b55604051908152a3565b91929092614fcc826142e2565b1561193857614fda81613d4d565b156152d5576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f9260208260248173ffffffffffffffffffffffffffffffffffffffff88165afa8015610e43575f9061528f575b73ffffffffffffffffffffffffffffffffffffffff925080861180615282575b615259575b5016938433036151bf575b841561196057845f52600c60205260405f206150a6828254613e9c565b90556150b481600b54613e9c565b600b555f857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020604051858152a36150ec84614f21565b926fffffffffffffffffffffffffffffffff600f5494166fffffffffffffffffffffffffffffffff851603936fffffffffffffffffffffffffffffffff8511610ae4578361518a9287927fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9916911617600f55615427565b604051938452602084015216907ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db60403392a4565b845f52600d60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f2054817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361521c575b5050615089565b61522591613e9c565b855f52600d60205260405f2073ffffffffffffffffffffffffffffffffffffffff33165f5260205260405f20555f81615215565b61527b9061526c84601454169188613e9c565b9061527561399b565b9061495a565b505f61507e565b5082601454161515615079565b506020823d6020116152cd575b816152a960209383613806565b810103126105445773ffffffffffffffffffffffffffffffffffffffff9151615059565b3d915061529c565b7f8181c5ea000000000000000000000000000000000000000000000000000000005f5260045ffd5b90813b156153ff575f809493819473ffffffffffffffffffffffffffffffffffffffff604051928160208501967f23b872dd00000000000000000000000000000000000000000000000000000000885216602485015216604483015260648201526064815261536d608482613806565b51925af1615379614558565b90156153d75780519081159182156153bd575b50501561539557565b7f1eded19c000000000000000000000000000000000000000000000000000000005f5260045ffd5b6153d09250602080918301019101613d35565b5f8061538c565b7fe65b7a77000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff046a714000000000000000000000000000000000000000000000000000000005f5260045ffd5b919091803b156153ff575f928380936040519073ffffffffffffffffffffffffffffffffffffffff60208301947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024830152604482015260448152615491606482613806565b51925af161549d614558565b90156154fb5780519081159182156154e1575b5050156154b957565b7f2f0470fc000000000000000000000000000000000000000000000000000000005f5260045ffd5b6154f49250602080918301019101613d35565b5f806154b0565b7face2a47e000000000000000000000000000000000000000000000000000000005f5260045ffdfea164736f6c634300081c000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f

-----Decoded View---------------
Arg [0] : _owner (address): 0x0000000000000000000000000000000000000000
Arg [1] : _asset (address): 0xe1E289900F526C52642A92eb65Af73C4B7ab885F

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 000000000000000000000000e1e289900f526c52642a92eb65af73c4b7ab885f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x89202AC5577E4Cadee1A327A0b9C1dABbbD07e5E
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.