ETH Price: $3,124.08 (-5.55%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Flow Caps217139222025-01-27 5:59:117 hrs ago1737957551IN
Morpho: Public Allocator
0 ETH0.00029477.07505064
Set Flow Caps217139192025-01-27 5:58:357 hrs ago1737957515IN
Morpho: Public Allocator
0 ETH0.000272727.02622976
Set Flow Caps217067592025-01-26 5:59:3531 hrs ago1737871175IN
Morpho: Public Allocator
0 ETH0.00013433.23190085
Set Flow Caps217067582025-01-26 5:59:2331 hrs ago1737871163IN
Morpho: Public Allocator
0 ETH0.000121852.93234797
Set Flow Caps217067572025-01-26 5:59:1131 hrs ago1737871151IN
Morpho: Public Allocator
0 ETH0.000127933.07427303
Set Flow Caps217067562025-01-26 5:58:5931 hrs ago1737871139IN
Morpho: Public Allocator
0 ETH0.000129363.11319522
Set Flow Caps217067552025-01-26 5:58:4731 hrs ago1737871127IN
Morpho: Public Allocator
0 ETH0.000129393.11381979
Set Flow Caps217067512025-01-26 5:57:5931 hrs ago1737871079IN
Morpho: Public Allocator
0 ETH0.000125073.00470063
Set Flow Caps216995842025-01-25 5:58:472 days ago1737784727IN
Morpho: Public Allocator
0 ETH0.000240235.77277344
Set Flow Caps216995832025-01-25 5:58:352 days ago1737784715IN
Morpho: Public Allocator
0 ETH0.000256746.17838072
Set Flow Caps216924212025-01-24 5:58:473 days ago1737698327IN
Morpho: Public Allocator
0 ETH0.000255666.14364848
Set Flow Caps216924202025-01-24 5:58:353 days ago1737698315IN
Morpho: Public Allocator
0 ETH0.00023645.68908242
Set Flow Caps216883402025-01-23 16:18:593 days ago1737649139IN
Morpho: Public Allocator
0 ETH0.0013597123.11897731
Set Flow Caps216883372025-01-23 16:18:233 days ago1737649103IN
Morpho: Public Allocator
0 ETH0.0014236124.21031589
Set Flow Caps216883372025-01-23 16:18:233 days ago1737649103IN
Morpho: Public Allocator
0 ETH0.0014265624.25561589
Set Flow Caps216883362025-01-23 16:18:113 days ago1737649091IN
Morpho: Public Allocator
0 ETH0.0013035422.16393067
Set Flow Caps216883292025-01-23 16:16:473 days ago1737649007IN
Morpho: Public Allocator
0 ETH0.0016997228.9
Set Flow Caps216852542025-01-23 5:59:114 days ago1737611951IN
Morpho: Public Allocator
0 ETH0.000226485.45026436
Set Flow Caps216852532025-01-23 5:58:594 days ago1737611939IN
Morpho: Public Allocator
0 ETH0.000232555.59625822
Set Flow Caps216852522025-01-23 5:58:474 days ago1737611927IN
Morpho: Public Allocator
0 ETH0.000233495.61078716
Set Flow Caps216852512025-01-23 5:58:354 days ago1737611915IN
Morpho: Public Allocator
0 ETH0.000223215.37144529
Set Flow Caps216805972025-01-22 14:22:114 days ago1737555731IN
Morpho: Public Allocator
0 ETH0.0007309117.58910819
Set Flow Caps216805962025-01-22 14:21:594 days ago1737555719IN
Morpho: Public Allocator
0 ETH0.0007354817.67363441
Set Flow Caps216805952025-01-22 14:21:474 days ago1737555707IN
Morpho: Public Allocator
0 ETH0.0007712718.56032915
Set Flow Caps216805942025-01-22 14:21:354 days ago1737555695IN
Morpho: Public Allocator
0 ETH0.0007493218.03214596
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
210570342024-10-27 12:42:2392 days ago1730032943
Morpho: Public Allocator
0.023 ETH
209585432024-10-13 18:48:35105 days ago1728845315
Morpho: Public Allocator
0.0005 ETH
209577242024-10-13 16:04:35105 days ago1728835475
Morpho: Public Allocator
0.0005 ETH
209566002024-10-13 12:18:23106 days ago1728821903
Morpho: Public Allocator
0.0005 ETH
209544762024-10-13 5:07:35106 days ago1728796055
Morpho: Public Allocator
0.0005 ETH
209519332024-10-12 20:33:35106 days ago1728765215
Morpho: Public Allocator
0.0005 ETH
209518972024-10-12 20:26:11106 days ago1728764771
Morpho: Public Allocator
0.0005 ETH
209518442024-10-12 20:15:35106 days ago1728764135
Morpho: Public Allocator
0.0005 ETH
209518252024-10-12 20:11:35106 days ago1728763895
Morpho: Public Allocator
0.0005 ETH
209518022024-10-12 20:06:47106 days ago1728763607
Morpho: Public Allocator
0.0005 ETH
208741352024-10-02 0:09:59117 days ago1727827799
Morpho: Public Allocator
0.0005 ETH
208584052024-09-29 19:31:35119 days ago1727638295
Morpho: Public Allocator
0.0005 ETH
208205532024-09-24 12:47:47125 days ago1727182067
Morpho: Public Allocator
0.0005 ETH
208197972024-09-24 10:16:11125 days ago1727172971
Morpho: Public Allocator
0.0005 ETH
208171262024-09-24 1:20:35125 days ago1727140835
Morpho: Public Allocator
0.0005 ETH
208163612024-09-23 22:47:11125 days ago1727131631
Morpho: Public Allocator
0.0005 ETH
208155212024-09-23 19:58:11125 days ago1727121491
Morpho: Public Allocator
0.0005 ETH
208139122024-09-23 14:34:47125 days ago1727102087
Morpho: Public Allocator
0.0005 ETH
208092652024-09-22 23:00:35126 days ago1727046035
Morpho: Public Allocator
0.0005 ETH
208081452024-09-22 19:15:11126 days ago1727032511
Morpho: Public Allocator
0.0005 ETH
208060682024-09-22 12:18:35127 days ago1727007515
Morpho: Public Allocator
0.0005 ETH
208036892024-09-22 4:20:47127 days ago1726978847
Morpho: Public Allocator
0.0005 ETH
208027242024-09-22 1:07:11127 days ago1726967231
Morpho: Public Allocator
0.0005 ETH
208014912024-09-21 20:58:47127 days ago1726952327
Morpho: Public Allocator
0.0005 ETH
207640482024-09-16 15:24:11132 days ago1726500251
Morpho: Public Allocator
0.0005 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PublicAllocator

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 999999 runs

Other Settings:
paris EvmVersion
File 1 of 20 : PublicAllocator.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.24;

import {
    FlowCaps,
    FlowCapsConfig,
    Withdrawal,
    MAX_SETTABLE_FLOW_CAP,
    IPublicAllocatorStaticTyping,
    IPublicAllocatorBase
} from "./interfaces/IPublicAllocator.sol";
import {
    Id, IMorpho, IMetaMorpho, MarketAllocation, MarketParams
} from "../lib/metamorpho/src/interfaces/IMetaMorpho.sol";
import {Market} from "../lib/metamorpho/lib/morpho-blue/src/interfaces/IMorpho.sol";

import {ErrorsLib} from "./libraries/ErrorsLib.sol";
import {EventsLib} from "./libraries/EventsLib.sol";
import {UtilsLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/UtilsLib.sol";
import {MarketParamsLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {MorphoBalancesLib} from "../lib/metamorpho/lib/morpho-blue/src/libraries/periphery/MorphoBalancesLib.sol";

/// @title PublicAllocator
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Publicly callable allocator for MetaMorpho vaults.
contract PublicAllocator is IPublicAllocatorStaticTyping {
    using MorphoBalancesLib for IMorpho;
    using MarketParamsLib for MarketParams;
    using UtilsLib for uint256;

    /* CONSTANTS */

    /// @inheritdoc IPublicAllocatorBase
    IMorpho public immutable MORPHO;

    /* STORAGE */

    /// @inheritdoc IPublicAllocatorBase
    mapping(address => address) public admin;
    /// @inheritdoc IPublicAllocatorBase
    mapping(address => uint256) public fee;
    /// @inheritdoc IPublicAllocatorBase
    mapping(address => uint256) public accruedFee;
    /// @inheritdoc IPublicAllocatorStaticTyping
    mapping(address => mapping(Id => FlowCaps)) public flowCaps;

    /* MODIFIER */

    /// @dev Reverts if the caller is not the admin nor the owner of this vault.
    modifier onlyAdminOrVaultOwner(address vault) {
        if (msg.sender != admin[vault] && msg.sender != IMetaMorpho(vault).owner()) {
            revert ErrorsLib.NotAdminNorVaultOwner();
        }
        _;
    }

    /* CONSTRUCTOR */

    /// @dev Initializes the contract.
    constructor(address morpho) {
        MORPHO = IMorpho(morpho);
    }

    /* ADMIN OR VAULT OWNER ONLY */

    /// @inheritdoc IPublicAllocatorBase
    function setAdmin(address vault, address newAdmin) external onlyAdminOrVaultOwner(vault) {
        if (admin[vault] == newAdmin) revert ErrorsLib.AlreadySet();
        admin[vault] = newAdmin;
        emit EventsLib.SetAdmin(msg.sender, vault, newAdmin);
    }

    /// @inheritdoc IPublicAllocatorBase
    function setFee(address vault, uint256 newFee) external onlyAdminOrVaultOwner(vault) {
        if (fee[vault] == newFee) revert ErrorsLib.AlreadySet();
        fee[vault] = newFee;
        emit EventsLib.SetFee(msg.sender, vault, newFee);
    }

    /// @inheritdoc IPublicAllocatorBase
    function setFlowCaps(address vault, FlowCapsConfig[] calldata config) external onlyAdminOrVaultOwner(vault) {
        for (uint256 i = 0; i < config.length; i++) {
            Id id = config[i].id;
            if (!IMetaMorpho(vault).config(id).enabled && (config[i].caps.maxIn > 0 || config[i].caps.maxOut > 0)) {
                revert ErrorsLib.MarketNotEnabled(id);
            }
            if (config[i].caps.maxIn > MAX_SETTABLE_FLOW_CAP || config[i].caps.maxOut > MAX_SETTABLE_FLOW_CAP) {
                revert ErrorsLib.MaxSettableFlowCapExceeded();
            }
            flowCaps[vault][id] = config[i].caps;
        }

        emit EventsLib.SetFlowCaps(msg.sender, vault, config);
    }

    /// @inheritdoc IPublicAllocatorBase
    function transferFee(address vault, address payable feeRecipient) external onlyAdminOrVaultOwner(vault) {
        uint256 claimed = accruedFee[vault];
        accruedFee[vault] = 0;
        feeRecipient.transfer(claimed);
        emit EventsLib.TransferFee(msg.sender, vault, claimed, feeRecipient);
    }

    /* PUBLIC */

    /// @inheritdoc IPublicAllocatorBase
    function reallocateTo(address vault, Withdrawal[] calldata withdrawals, MarketParams calldata supplyMarketParams)
        external
        payable
    {
        if (msg.value != fee[vault]) revert ErrorsLib.IncorrectFee();
        if (msg.value > 0) accruedFee[vault] += msg.value;

        if (withdrawals.length == 0) revert ErrorsLib.EmptyWithdrawals();

        Id supplyMarketId = supplyMarketParams.id();
        if (!IMetaMorpho(vault).config(supplyMarketId).enabled) revert ErrorsLib.MarketNotEnabled(supplyMarketId);

        MarketAllocation[] memory allocations = new MarketAllocation[](withdrawals.length + 1);
        uint128 totalWithdrawn;

        Id id;
        Id prevId;
        for (uint256 i = 0; i < withdrawals.length; i++) {
            prevId = id;
            id = withdrawals[i].marketParams.id();
            if (!IMetaMorpho(vault).config(id).enabled) revert ErrorsLib.MarketNotEnabled(id);
            uint128 withdrawnAssets = withdrawals[i].amount;
            if (withdrawnAssets == 0) revert ErrorsLib.WithdrawZero(id);

            if (Id.unwrap(id) <= Id.unwrap(prevId)) revert ErrorsLib.InconsistentWithdrawals();
            if (Id.unwrap(id) == Id.unwrap(supplyMarketId)) revert ErrorsLib.DepositMarketInWithdrawals();

            MORPHO.accrueInterest(withdrawals[i].marketParams);
            uint256 assets = MORPHO.expectedSupplyAssets(withdrawals[i].marketParams, address(vault));

            if (flowCaps[vault][id].maxOut < withdrawnAssets) revert ErrorsLib.MaxOutflowExceeded(id);
            if (assets < withdrawnAssets) revert ErrorsLib.NotEnoughSupply(id);

            flowCaps[vault][id].maxIn += withdrawnAssets;
            flowCaps[vault][id].maxOut -= withdrawnAssets;
            allocations[i].marketParams = withdrawals[i].marketParams;
            allocations[i].assets = assets - withdrawnAssets;

            totalWithdrawn += withdrawnAssets;

            emit EventsLib.PublicWithdrawal(msg.sender, vault, id, withdrawnAssets);
        }

        if (flowCaps[vault][supplyMarketId].maxIn < totalWithdrawn) revert ErrorsLib.MaxInflowExceeded(supplyMarketId);

        flowCaps[vault][supplyMarketId].maxIn -= totalWithdrawn;
        flowCaps[vault][supplyMarketId].maxOut += totalWithdrawn;
        allocations[withdrawals.length].marketParams = supplyMarketParams;
        allocations[withdrawals.length].assets = type(uint256).max;

        IMetaMorpho(vault).reallocate(allocations);

        emit EventsLib.PublicReallocateTo(msg.sender, vault, supplyMarketId, totalWithdrawn);
    }
}

File 2 of 20 : IPublicAllocator.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {
    IMetaMorpho,
    IMorpho,
    MarketAllocation,
    Id,
    MarketParams
} from "../../lib/metamorpho/src/interfaces/IMetaMorpho.sol";

/// @dev Max settable flow cap, such that caps can always be stored on 128 bits.
/// @dev The actual max possible flow cap is type(uint128).max-1.
/// @dev Equals to 170141183460469231731687303715884105727;
uint128 constant MAX_SETTABLE_FLOW_CAP = type(uint128).max / 2;

struct FlowCaps {
    /// @notice The maximum allowed inflow in a market.
    uint128 maxIn;
    /// @notice The maximum allowed outflow in a market.
    uint128 maxOut;
}

struct FlowCapsConfig {
    /// @notice Market for which to change flow caps.
    Id id;
    /// @notice New flow caps for this market.
    FlowCaps caps;
}

struct Withdrawal {
    /// @notice The market from which to withdraw.
    MarketParams marketParams;
    /// @notice The amount to withdraw.
    uint128 amount;
}

/// @dev This interface is used for factorizing IPublicAllocatorStaticTyping and IPublicAllocator.
/// @dev Consider using the IPublicAllocator interface instead of this one.
interface IPublicAllocatorBase {
    /// @notice The Morpho contract.
    function MORPHO() external view returns (IMorpho);

    /// @notice The admin for a given vault.
    function admin(address vault) external view returns (address);

    /// @notice The current ETH fee for a given vault.
    function fee(address vault) external view returns (uint256);

    /// @notice The accrued ETH fee for a given vault.
    function accruedFee(address vault) external view returns (uint256);

    /// @notice Reallocates from a list of markets to one market.
    /// @param vault The MetaMorpho vault to reallocate.
    /// @param withdrawals The markets to withdraw from,and the amounts to withdraw.
    /// @param supplyMarketParams The market receiving total withdrawn to.
    /// @dev Will call MetaMorpho's `reallocate`.
    /// @dev Checks that the flow caps are respected.
    /// @dev Will revert when `withdrawals` contains a duplicate or is not sorted.
    /// @dev Will revert if `withdrawals` contains the supply market.
    /// @dev Will revert if a withdrawal amount is larger than available liquidity.
    function reallocateTo(address vault, Withdrawal[] calldata withdrawals, MarketParams calldata supplyMarketParams)
        external
        payable;

    /// @notice Sets the admin for a given vault.
    function setAdmin(address vault, address newAdmin) external;

    /// @notice Sets the fee for a given vault.
    function setFee(address vault, uint256 newFee) external;

    /// @notice Transfers the current balance to `feeRecipient` for a given vault.
    function transferFee(address vault, address payable feeRecipient) external;

    /// @notice Sets the maximum inflow and outflow through public allocation for some markets for a given vault.
    /// @dev Max allowed inflow/outflow is MAX_SETTABLE_FLOW_CAP.
    /// @dev Doesn't revert if it doesn't change the storage at all.
    function setFlowCaps(address vault, FlowCapsConfig[] calldata config) external;
}

/// @dev This interface is inherited by PublicAllocator so that function signatures are checked by the compiler.
/// @dev Consider using the IPublicAllocator interface instead of this one.
interface IPublicAllocatorStaticTyping is IPublicAllocatorBase {
    /// @notice Returns (maximum inflow, maximum outflow) through public allocation of a given market for a given vault.
    function flowCaps(address vault, Id) external view returns (uint128, uint128);
}

/// @title IPublicAllocator
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for PublicAllocator to have access to all the functions with the appropriate function
/// signatures.
interface IPublicAllocator is IPublicAllocatorBase {
    /// @notice Returns the maximum inflow and maximum outflow through public allocation of a given market for a given
    /// vault.
    function flowCaps(address vault, Id) external view returns (FlowCaps memory);
}

File 3 of 20 : IMetaMorpho.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {IMorpho, Id, MarketParams} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IERC4626} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";

import {MarketConfig, PendingUint192, PendingAddress} from "../libraries/PendingLib.sol";

struct MarketAllocation {
    /// @notice The market to allocate.
    MarketParams marketParams;
    /// @notice The amount of assets to allocate.
    uint256 assets;
}

interface IMulticall {
    function multicall(bytes[] calldata) external returns (bytes[] memory);
}

interface IOwnable {
    function owner() external view returns (address);
    function transferOwnership(address) external;
    function renounceOwnership() external;
    function acceptOwnership() external;
    function pendingOwner() external view returns (address);
}

/// @dev This interface is used for factorizing IMetaMorphoStaticTyping and IMetaMorpho.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoBase {
    /// @notice The address of the Morpho contract.
    function MORPHO() external view returns (IMorpho);
    function DECIMALS_OFFSET() external view returns (uint8);

    /// @notice The address of the curator.
    function curator() external view returns (address);

    /// @notice Stores whether an address is an allocator or not.
    function isAllocator(address target) external view returns (bool);

    /// @notice The current guardian. Can be set even without the timelock set.
    function guardian() external view returns (address);

    /// @notice The current fee.
    function fee() external view returns (uint96);

    /// @notice The fee recipient.
    function feeRecipient() external view returns (address);

    /// @notice The skim recipient.
    function skimRecipient() external view returns (address);

    /// @notice The current timelock.
    function timelock() external view returns (uint256);

    /// @dev Stores the order of markets on which liquidity is supplied upon deposit.
    /// @dev Can contain any market. A market is skipped as soon as its supply cap is reached.
    function supplyQueue(uint256) external view returns (Id);

    /// @notice Returns the length of the supply queue.
    function supplyQueueLength() external view returns (uint256);

    /// @dev Stores the order of markets from which liquidity is withdrawn upon withdrawal.
    /// @dev Always contain all non-zero cap markets as well as all markets on which the vault supplies liquidity,
    /// without duplicate.
    function withdrawQueue(uint256) external view returns (Id);

    /// @notice Returns the length of the withdraw queue.
    function withdrawQueueLength() external view returns (uint256);

    /// @notice Stores the total assets managed by this vault when the fee was last accrued.
    /// @dev May be greater than `totalAssets()` due to removal of markets with non-zero supply or socialized bad debt.
    /// This difference will decrease the fee accrued until one of the functions updating `lastTotalAssets` is
    /// triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
    function lastTotalAssets() external view returns (uint256);

    /// @notice Submits a `newTimelock`.
    /// @dev Warning: Reverts if a timelock is already pending. Revoke the pending timelock to overwrite it.
    /// @dev In case the new timelock is higher than the current one, the timelock is set immediately.
    function submitTimelock(uint256 newTimelock) external;

    /// @notice Accepts the pending timelock.
    function acceptTimelock() external;

    /// @notice Revokes the pending timelock.
    /// @dev Does not revert if there is no pending timelock.
    function revokePendingTimelock() external;

    /// @notice Submits a `newSupplyCap` for the market defined by `marketParams`.
    /// @dev Warning: Reverts if a cap is already pending. Revoke the pending cap to overwrite it.
    /// @dev Warning: Reverts if a market removal is pending.
    /// @dev In case the new cap is lower than the current one, the cap is set immediately.
    function submitCap(MarketParams memory marketParams, uint256 newSupplyCap) external;

    /// @notice Accepts the pending cap of the market defined by `marketParams`.
    function acceptCap(MarketParams memory marketParams) external;

    /// @notice Revokes the pending cap of the market defined by `id`.
    /// @dev Does not revert if there is no pending cap.
    function revokePendingCap(Id id) external;

    /// @notice Submits a forced market removal from the vault, eventually losing all funds supplied to the market.
    /// @notice Funds can be recovered by enabling this market again and withdrawing from it (using `reallocate`),
    /// but funds will be distributed pro-rata to the shares at the time of withdrawal, not at the time of removal.
    /// @notice This forced removal is expected to be used as an emergency process in case a market constantly reverts.
    /// To softly remove a sane market, the curator role is expected to bundle a reallocation that empties the market
    /// first (using `reallocate`), followed by the removal of the market (using `updateWithdrawQueue`).
    /// @dev Warning: Removing a market with non-zero supply will instantly impact the vault's price per share.
    /// @dev Warning: Reverts for non-zero cap or if there is a pending cap. Successfully submitting a zero cap will
    /// prevent such reverts.
    function submitMarketRemoval(MarketParams memory marketParams) external;

    /// @notice Revokes the pending removal of the market defined by `id`.
    /// @dev Does not revert if there is no pending market removal.
    function revokePendingMarketRemoval(Id id) external;

    /// @notice Submits a `newGuardian`.
    /// @notice Warning: a malicious guardian could disrupt the vault's operation, and would have the power to revoke
    /// any pending guardian.
    /// @dev In case there is no guardian, the gardian is set immediately.
    /// @dev Warning: Submitting a gardian will overwrite the current pending gardian.
    function submitGuardian(address newGuardian) external;

    /// @notice Accepts the pending guardian.
    function acceptGuardian() external;

    /// @notice Revokes the pending guardian.
    function revokePendingGuardian() external;

    /// @notice Skims the vault `token` balance to `skimRecipient`.
    function skim(address) external;

    /// @notice Sets `newAllocator` as an allocator or not (`newIsAllocator`).
    function setIsAllocator(address newAllocator, bool newIsAllocator) external;

    /// @notice Sets `curator` to `newCurator`.
    function setCurator(address newCurator) external;

    /// @notice Sets the `fee` to `newFee`.
    function setFee(uint256 newFee) external;

    /// @notice Sets `feeRecipient` to `newFeeRecipient`.
    function setFeeRecipient(address newFeeRecipient) external;

    /// @notice Sets `skimRecipient` to `newSkimRecipient`.
    function setSkimRecipient(address newSkimRecipient) external;

    /// @notice Sets `supplyQueue` to `newSupplyQueue`.
    /// @param newSupplyQueue is an array of enabled markets, and can contain duplicate markets, but it would only
    /// increase the cost of depositing to the vault.
    function setSupplyQueue(Id[] calldata newSupplyQueue) external;

    /// @notice Updates the withdraw queue. Some markets can be removed, but no market can be added.
    /// @notice Removing a market requires the vault to have 0 supply on it, or to have previously submitted a removal
    /// for this market (with the function `submitMarketRemoval`).
    /// @notice Warning: Anyone can supply on behalf of the vault so the call to `updateWithdrawQueue` that expects a
    /// market to be empty can be griefed by a front-run. To circumvent this, the allocator can simply bundle a
    /// reallocation that withdraws max from this market with a call to `updateWithdrawQueue`.
    /// @dev Warning: Removing a market with supply will decrease the fee accrued until one of the functions updating
    /// `lastTotalAssets` is triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
    /// @dev Warning: `updateWithdrawQueue` is not idempotent. Submitting twice the same tx will change the queue twice.
    /// @param indexes The indexes of each market in the previous withdraw queue, in the new withdraw queue's order.
    function updateWithdrawQueue(uint256[] calldata indexes) external;

    /// @notice Reallocates the vault's liquidity so as to reach a given allocation of assets on each given market.
    /// @notice The allocator can withdraw from any market, even if it's not in the withdraw queue, as long as the loan
    /// token of the market is the same as the vault's asset.
    /// @dev The behavior of the reallocation can be altered by state changes, including:
    /// - Deposits on the vault that supplies to markets that are expected to be supplied to during reallocation.
    /// - Withdrawals from the vault that withdraws from markets that are expected to be withdrawn from during
    /// reallocation.
    /// - Donations to the vault on markets that are expected to be supplied to during reallocation.
    /// - Withdrawals from markets that are expected to be withdrawn from during reallocation.
    /// @dev Sender is expected to pass `assets = type(uint256).max` with the last MarketAllocation of `allocations` to
    /// supply all the remaining withdrawn liquidity, which would ensure that `totalWithdrawn` = `totalSupplied`.
    function reallocate(MarketAllocation[] calldata allocations) external;
}

/// @dev This interface is inherited by MetaMorpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoStaticTyping is IMetaMorphoBase {
    /// @notice Returns the current configuration of each market.
    function config(Id) external view returns (uint184 cap, bool enabled, uint64 removableAt);

    /// @notice Returns the pending guardian.
    function pendingGuardian() external view returns (address guardian, uint64 validAt);

    /// @notice Returns the pending cap for each market.
    function pendingCap(Id) external view returns (uint192 value, uint64 validAt);

    /// @notice Returns the pending timelock.
    function pendingTimelock() external view returns (uint192 value, uint64 validAt);
}

/// @title IMetaMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for MetaMorpho to have access to all the functions with the appropriate function signatures.
interface IMetaMorpho is IMetaMorphoBase, IERC4626, IERC20Permit, IOwnable, IMulticall {
    /// @notice Returns the current configuration of each market.
    function config(Id) external view returns (MarketConfig memory);

    /// @notice Returns the pending guardian.
    function pendingGuardian() external view returns (PendingAddress memory);

    /// @notice Returns the pending cap for each market.
    function pendingCap(Id) external view returns (PendingUint192 memory);

    /// @notice Returns the pending timelock.
    function pendingTimelock() external view returns (PendingUint192 memory);
}

File 4 of 20 : IMorpho.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

type Id is bytes32;

struct MarketParams {
    address loanToken;
    address collateralToken;
    address oracle;
    address irm;
    uint256 lltv;
}

/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
    uint256 supplyShares;
    uint128 borrowShares;
    uint128 collateral;
}

/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
    uint128 totalSupplyAssets;
    uint128 totalSupplyShares;
    uint128 totalBorrowAssets;
    uint128 totalBorrowShares;
    uint128 lastUpdate;
    uint128 fee;
}

struct Authorization {
    address authorizer;
    address authorized;
    bool isAuthorized;
    uint256 nonce;
    uint256 deadline;
}

struct Signature {
    uint8 v;
    bytes32 r;
    bytes32 s;
}

/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
    /// @notice The EIP-712 domain separator.
    /// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing
    /// the same chain id because the domain separator would be the same.
    function DOMAIN_SEPARATOR() external view returns (bytes32);

    /// @notice The owner of the contract.
    /// @dev It has the power to change the owner.
    /// @dev It has the power to set fees on markets and set the fee recipient.
    /// @dev It has the power to enable but not disable IRMs and LLTVs.
    function owner() external view returns (address);

    /// @notice The fee recipient of all markets.
    /// @dev The recipient receives the fees of a given market through a supply position on that market.
    function feeRecipient() external view returns (address);

    /// @notice Whether the `irm` is enabled.
    function isIrmEnabled(address irm) external view returns (bool);

    /// @notice Whether the `lltv` is enabled.
    function isLltvEnabled(uint256 lltv) external view returns (bool);

    /// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
    /// @dev Anyone is authorized to modify their own positions, regardless of this variable.
    function isAuthorized(address authorizer, address authorized) external view returns (bool);

    /// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
    function nonce(address authorizer) external view returns (uint256);

    /// @notice Sets `newOwner` as `owner` of the contract.
    /// @dev Warning: No two-step transfer ownership.
    /// @dev Warning: The owner can be set to the zero address.
    function setOwner(address newOwner) external;

    /// @notice Enables `irm` as a possible IRM for market creation.
    /// @dev Warning: It is not possible to disable an IRM.
    function enableIrm(address irm) external;

    /// @notice Enables `lltv` as a possible LLTV for market creation.
    /// @dev Warning: It is not possible to disable a LLTV.
    function enableLltv(uint256 lltv) external;

    /// @notice Sets the `newFee` for the given market `marketParams`.
    /// @param newFee The new fee, scaled by WAD.
    /// @dev Warning: The recipient can be the zero address.
    function setFee(MarketParams memory marketParams, uint256 newFee) external;

    /// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
    /// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
    /// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
    /// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
    function setFeeRecipient(address newFeeRecipient) external;

    /// @notice Creates the market `marketParams`.
    /// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
    /// Morpho behaves as expected:
    /// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
    /// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
    /// burn functions are not supported.
    /// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
    /// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
    /// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
    /// - The IRM should not re-enter Morpho.
    /// - The oracle should return a price with the correct scaling.
    /// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties
    /// (funds could get stuck):
    /// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.
    /// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and
    /// `toSharesDown` overflow.
    /// - The IRM can revert on `borrowRate`.
    /// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`
    /// overflow.
    /// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and
    /// `liquidate` from being used under certain market conditions.
    /// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or
    /// the computation of `assetsRepaid` in `liquidate` overflow.
    /// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
    /// the point where `totalBorrowShares` is very large and borrowing overflows.
    function createMarket(MarketParams memory marketParams) external;

    /// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoSupply` function with the given `data`.
    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
    /// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
    /// amount of shares is given for full compatibility and precision.
    /// @dev Supplying a large amount can revert for overflow.
    /// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
    /// Consider using the `assets` parameter to avoid this.
    /// @param marketParams The market to supply assets to.
    /// @param assets The amount of assets to supply.
    /// @param shares The amount of shares to mint.
    /// @param onBehalf The address that will own the increased supply position.
    /// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
    /// @return assetsSupplied The amount of assets supplied.
    /// @return sharesSupplied The amount of shares minted.
    function supply(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        bytes memory data
    ) external returns (uint256 assetsSupplied, uint256 sharesSupplied);

    /// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
    /// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
    /// conversion roundings between shares and assets.
    /// @param marketParams The market to withdraw assets from.
    /// @param assets The amount of assets to withdraw.
    /// @param shares The amount of shares to burn.
    /// @param onBehalf The address of the owner of the supply position.
    /// @param receiver The address that will receive the withdrawn assets.
    /// @return assetsWithdrawn The amount of assets withdrawn.
    /// @return sharesWithdrawn The amount of shares burned.
    function withdraw(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        address receiver
    ) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);

    /// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
    /// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
    /// given for full compatibility and precision.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Borrowing a large amount can revert for overflow.
    /// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
    /// Consider using the `assets` parameter to avoid this.
    /// @param marketParams The market to borrow assets from.
    /// @param assets The amount of assets to borrow.
    /// @param shares The amount of shares to mint.
    /// @param onBehalf The address that will own the increased borrow position.
    /// @param receiver The address that will receive the borrowed assets.
    /// @return assetsBorrowed The amount of assets borrowed.
    /// @return sharesBorrowed The amount of shares minted.
    function borrow(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        address receiver
    ) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);

    /// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoReplay` function with the given `data`.
    /// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
    /// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
    /// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
    /// roundings between shares and assets.
    /// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
    /// @param marketParams The market to repay assets to.
    /// @param assets The amount of assets to repay.
    /// @param shares The amount of shares to burn.
    /// @param onBehalf The address of the owner of the debt position.
    /// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
    /// @return assetsRepaid The amount of assets repaid.
    /// @return sharesRepaid The amount of shares burned.
    function repay(
        MarketParams memory marketParams,
        uint256 assets,
        uint256 shares,
        address onBehalf,
        bytes memory data
    ) external returns (uint256 assetsRepaid, uint256 sharesRepaid);

    /// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
    /// `onMorphoSupplyCollateral` function with the given `data`.
    /// @dev Interest are not accrued since it's not required and it saves gas.
    /// @dev Supplying a large amount can revert for overflow.
    /// @param marketParams The market to supply collateral to.
    /// @param assets The amount of collateral to supply.
    /// @param onBehalf The address that will own the increased collateral position.
    /// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
    function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
        external;

    /// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
    /// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
    /// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
    /// @param marketParams The market to withdraw collateral from.
    /// @param assets The amount of collateral to withdraw.
    /// @param onBehalf The address of the owner of the collateral position.
    /// @param receiver The address that will receive the collateral assets.
    function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
        external;

    /// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
    /// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
    /// `onMorphoLiquidate` function with the given `data`.
    /// @dev Either `seizedAssets` or `repaidShares` should be zero.
    /// @dev Seizing more than the collateral balance will underflow and revert without any error message.
    /// @dev Repaying more than the borrow balance will underflow and revert without any error message.
    /// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
    /// @param marketParams The market of the position.
    /// @param borrower The owner of the position.
    /// @param seizedAssets The amount of collateral to seize.
    /// @param repaidShares The amount of shares to repay.
    /// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
    /// @return The amount of assets seized.
    /// @return The amount of assets repaid.
    function liquidate(
        MarketParams memory marketParams,
        address borrower,
        uint256 seizedAssets,
        uint256 repaidShares,
        bytes memory data
    ) external returns (uint256, uint256);

    /// @notice Executes a flash loan.
    /// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
    /// markets combined, plus donations).
    /// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
    /// - `flashFee` is zero.
    /// - `maxFlashLoan` is the token's balance of this contract.
    /// - The receiver of `assets` is the caller.
    /// @param token The token to flash loan.
    /// @param assets The amount of assets to flash loan.
    /// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
    function flashLoan(address token, uint256 assets, bytes calldata data) external;

    /// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
    /// @param authorized The authorized address.
    /// @param newIsAuthorized The new authorization status.
    function setAuthorization(address authorized, bool newIsAuthorized) external;

    /// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
    /// @dev Warning: Reverts if the signature has already been submitted.
    /// @dev The signature is malleable, but it has no impact on the security here.
    /// @dev The nonce is passed as argument to be able to revert with a different error message.
    /// @param authorization The `Authorization` struct.
    /// @param signature The signature.
    function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;

    /// @notice Accrues interest for the given market `marketParams`.
    function accrueInterest(MarketParams memory marketParams) external;

    /// @notice Returns the data stored on the different `slots`.
    function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}

/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
    /// @notice The state of the position of `user` on the market corresponding to `id`.
    /// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
    /// accrual.
    function position(Id id, address user)
        external
        view
        returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);

    /// @notice The state of the market corresponding to `id`.
    /// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
    /// accrual.
    function market(Id id)
        external
        view
        returns (
            uint128 totalSupplyAssets,
            uint128 totalSupplyShares,
            uint128 totalBorrowAssets,
            uint128 totalBorrowShares,
            uint128 lastUpdate,
            uint128 fee
        );

    /// @notice The market params corresponding to `id`.
    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
    function idToMarketParams(Id id)
        external
        view
        returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}

/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
    /// @notice The state of the position of `user` on the market corresponding to `id`.
    /// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
    /// accrual.
    function position(Id id, address user) external view returns (Position memory p);

    /// @notice The state of the market corresponding to `id`.
    /// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
    /// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
    /// interest accrual.
    function market(Id id) external view returns (Market memory m);

    /// @notice The market params corresponding to `id`.
    /// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
    /// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
    function idToMarketParams(Id id) external view returns (MarketParams memory);
}

File 5 of 20 : ErrorsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Id} from "../../lib/metamorpho/src/interfaces/IMetaMorpho.sol";

/// @title ErrorsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library exposing error messages.
library ErrorsLib {
    /// @notice Thrown when the `msg.sender` is not the admin nor the owner of the vault.
    error NotAdminNorVaultOwner();

    /// @notice Thrown when the reallocation fee given is wrong.
    error IncorrectFee();

    /// @notice Thrown when the value is already set.
    error AlreadySet();

    /// @notice Thrown when `withdrawals` is empty.
    error EmptyWithdrawals();

    /// @notice Thrown when `withdrawals` contains a duplicate or is not sorted.
    error InconsistentWithdrawals();

    /// @notice Thrown when the deposit market is in `withdrawals`.
    error DepositMarketInWithdrawals();

    /// @notice Thrown when attempting to reallocate or set flows to non-zero values for a non-enabled market.
    error MarketNotEnabled(Id id);

    /// @notice Thrown when attempting to withdraw zero of a market.
    error WithdrawZero(Id id);

    /// @notice Thrown when attempting to set max inflow/outflow above the MAX_SETTABLE_FLOW_CAP.
    error MaxSettableFlowCapExceeded();

    /// @notice Thrown when attempting to withdraw more than the available supply of a market.
    error NotEnoughSupply(Id id);

    /// @notice Thrown when attempting to withdraw more than the max outflow of a market.
    error MaxOutflowExceeded(Id id);

    /// @notice Thrown when attempting to supply more than the max inflow of a market.
    error MaxInflowExceeded(Id id);
}

File 6 of 20 : EventsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {FlowCapsConfig, Id} from "../interfaces/IPublicAllocator.sol";

/// @title EventsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library exposing events.
library EventsLib {
    /// @notice Emitted during a public reallocation for each withdrawn-from market.
    event PublicWithdrawal(address indexed sender, address indexed vault, Id indexed id, uint256 withdrawnAssets);

    /// @notice Emitted at the end of a public reallocation.
    event PublicReallocateTo(
        address indexed sender, address indexed vault, Id indexed supplyMarketId, uint256 suppliedAssets
    );

    /// @notice Emitted when the admin is set for a vault.
    event SetAdmin(address indexed sender, address indexed vault, address admin);

    /// @notice Emitted when the fee is set for a vault.
    event SetFee(address indexed sender, address indexed vault, uint256 fee);

    /// @notice Emitted when the fee is transfered for a vault.
    event TransferFee(address indexed sender, address indexed vault, uint256 amount, address indexed feeRecipient);

    /// @notice Emitted when the flow caps are set for a vault.
    event SetFlowCaps(address indexed sender, address indexed vault, FlowCapsConfig[] config);
}

File 7 of 20 : UtilsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

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

/// @title UtilsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library exposing helpers.
/// @dev Inspired by https://github.com/morpho-org/morpho-utils.
library UtilsLib {
    /// @dev Returns true if there is exactly one zero among `x` and `y`.
    function exactlyOneZero(uint256 x, uint256 y) internal pure returns (bool z) {
        assembly {
            z := xor(iszero(x), iszero(y))
        }
    }

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

    /// @dev Returns `x` safely cast to uint128.
    function toUint128(uint256 x) internal pure returns (uint128) {
        require(x <= type(uint128).max, ErrorsLib.MAX_UINT128_EXCEEDED);
        return uint128(x);
    }

    /// @dev Returns max(0, x - y).
    function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }
}

File 8 of 20 : MarketParamsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Id, MarketParams} from "../interfaces/IMorpho.sol";

/// @title MarketParamsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to convert a market to its id.
library MarketParamsLib {
    /// @notice The length of the data used to compute the id of a market.
    /// @dev The length is 5 * 32 because `MarketParams` has 5 variables of 32 bytes each.
    uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;

    /// @notice Returns the id of the market `marketParams`.
    function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) {
        assembly ("memory-safe") {
            marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH)
        }
    }
}

File 9 of 20 : MorphoBalancesLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Id, MarketParams, Market, IMorpho} from "../../interfaces/IMorpho.sol";
import {IIrm} from "../../interfaces/IIrm.sol";

import {MathLib} from "../MathLib.sol";
import {UtilsLib} from "../UtilsLib.sol";
import {MorphoLib} from "./MorphoLib.sol";
import {SharesMathLib} from "../SharesMathLib.sol";
import {MarketParamsLib} from "../MarketParamsLib.sol";

/// @title MorphoBalancesLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library exposing getters with the expected value after interest accrual.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
/// @dev The getter to retrieve the expected total borrow shares is not exposed because interest accrual does not apply
/// to it. The value can be queried directly on Morpho using `totalBorrowShares`.
library MorphoBalancesLib {
    using MathLib for uint256;
    using MathLib for uint128;
    using UtilsLib for uint256;
    using MorphoLib for IMorpho;
    using SharesMathLib for uint256;
    using MarketParamsLib for MarketParams;

    /// @notice Returns the expected market balances of a market after having accrued interest.
    /// @return The expected total supply assets.
    /// @return The expected total supply shares.
    /// @return The expected total borrow assets.
    /// @return The expected total borrow shares.
    function expectedMarketBalances(IMorpho morpho, MarketParams memory marketParams)
        internal
        view
        returns (uint256, uint256, uint256, uint256)
    {
        Id id = marketParams.id();
        Market memory market = morpho.market(id);

        uint256 elapsed = block.timestamp - market.lastUpdate;

        // Skipped if elapsed == 0 or totalBorrowAssets == 0 because interest would be null, or if irm == address(0).
        if (elapsed != 0 && market.totalBorrowAssets != 0 && marketParams.irm != address(0)) {
            uint256 borrowRate = IIrm(marketParams.irm).borrowRateView(marketParams, market);
            uint256 interest = market.totalBorrowAssets.wMulDown(borrowRate.wTaylorCompounded(elapsed));
            market.totalBorrowAssets += interest.toUint128();
            market.totalSupplyAssets += interest.toUint128();

            if (market.fee != 0) {
                uint256 feeAmount = interest.wMulDown(market.fee);
                // The fee amount is subtracted from the total supply in this calculation to compensate for the fact
                // that total supply is already updated.
                uint256 feeShares =
                    feeAmount.toSharesDown(market.totalSupplyAssets - feeAmount, market.totalSupplyShares);
                market.totalSupplyShares += feeShares.toUint128();
            }
        }

        return (market.totalSupplyAssets, market.totalSupplyShares, market.totalBorrowAssets, market.totalBorrowShares);
    }

    /// @notice Returns the expected total supply assets of a market after having accrued interest.
    function expectedTotalSupplyAssets(IMorpho morpho, MarketParams memory marketParams)
        internal
        view
        returns (uint256 totalSupplyAssets)
    {
        (totalSupplyAssets,,,) = expectedMarketBalances(morpho, marketParams);
    }

    /// @notice Returns the expected total borrow assets of a market after having accrued interest.
    function expectedTotalBorrowAssets(IMorpho morpho, MarketParams memory marketParams)
        internal
        view
        returns (uint256 totalBorrowAssets)
    {
        (,, totalBorrowAssets,) = expectedMarketBalances(morpho, marketParams);
    }

    /// @notice Returns the expected total supply shares of a market after having accrued interest.
    function expectedTotalSupplyShares(IMorpho morpho, MarketParams memory marketParams)
        internal
        view
        returns (uint256 totalSupplyShares)
    {
        (, totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);
    }

    /// @notice Returns the expected supply assets balance of `user` on a market after having accrued interest.
    /// @dev Warning: Wrong for `feeRecipient` because their supply shares increase is not taken into account.
    /// @dev Warning: Withdrawing using the expected supply assets can lead to a revert due to conversion roundings from
    /// assets to shares.
    function expectedSupplyAssets(IMorpho morpho, MarketParams memory marketParams, address user)
        internal
        view
        returns (uint256)
    {
        Id id = marketParams.id();
        uint256 supplyShares = morpho.supplyShares(id, user);
        (uint256 totalSupplyAssets, uint256 totalSupplyShares,,) = expectedMarketBalances(morpho, marketParams);

        return supplyShares.toAssetsDown(totalSupplyAssets, totalSupplyShares);
    }

    /// @notice Returns the expected borrow assets balance of `user` on a market after having accrued interest.
    /// @dev Warning: The expected balance is rounded up, so it may be greater than the market's expected total borrow
    /// assets.
    function expectedBorrowAssets(IMorpho morpho, MarketParams memory marketParams, address user)
        internal
        view
        returns (uint256)
    {
        Id id = marketParams.id();
        uint256 borrowShares = morpho.borrowShares(id, user);
        (,, uint256 totalBorrowAssets, uint256 totalBorrowShares) = expectedMarketBalances(morpho, marketParams);

        return borrowShares.toAssetsUp(totalBorrowAssets, totalBorrowShares);
    }
}

File 10 of 20 : IERC4626.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
 */
interface IERC4626 is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}

File 11 of 20 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 12 of 20 : PendingLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

struct MarketConfig {
    /// @notice The maximum amount of assets that can be allocated to the market.
    uint184 cap;
    /// @notice Whether the market is in the withdraw queue.
    bool enabled;
    /// @notice The timestamp at which the market can be instantly removed from the withdraw queue.
    uint64 removableAt;
}

struct PendingUint192 {
    /// @notice The pending value to set.
    uint192 value;
    /// @notice The timestamp at which the pending value becomes valid.
    uint64 validAt;
}

struct PendingAddress {
    /// @notice The pending value to set.
    address value;
    /// @notice The timestamp at which the pending value becomes valid.
    uint64 validAt;
}

/// @title PendingLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to manage pending values and their validity timestamp.
library PendingLib {
    /// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
    /// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
    function update(PendingUint192 storage pending, uint184 newValue, uint256 timelock) internal {
        pending.value = newValue;
        // Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
        pending.validAt = uint64(block.timestamp + timelock);
    }

    /// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
    /// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
    function update(PendingAddress storage pending, address newValue, uint256 timelock) internal {
        pending.value = newValue;
        // Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
        pending.validAt = uint64(block.timestamp + timelock);
    }
}

File 13 of 20 : ErrorsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @title ErrorsLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library exposing error messages.
library ErrorsLib {
    /// @notice Thrown when the caller is not the owner.
    string internal constant NOT_OWNER = "not owner";

    /// @notice Thrown when the LLTV to enable exceeds the maximum LLTV.
    string internal constant MAX_LLTV_EXCEEDED = "max LLTV exceeded";

    /// @notice Thrown when the fee to set exceeds the maximum fee.
    string internal constant MAX_FEE_EXCEEDED = "max fee exceeded";

    /// @notice Thrown when the value is already set.
    string internal constant ALREADY_SET = "already set";

    /// @notice Thrown when the IRM is not enabled at market creation.
    string internal constant IRM_NOT_ENABLED = "IRM not enabled";

    /// @notice Thrown when the LLTV is not enabled at market creation.
    string internal constant LLTV_NOT_ENABLED = "LLTV not enabled";

    /// @notice Thrown when the market is already created.
    string internal constant MARKET_ALREADY_CREATED = "market already created";

    /// @notice Thrown when a token to transfer doesn't have code.
    string internal constant NO_CODE = "no code";

    /// @notice Thrown when the market is not created.
    string internal constant MARKET_NOT_CREATED = "market not created";

    /// @notice Thrown when not exactly one of the input amount is zero.
    string internal constant INCONSISTENT_INPUT = "inconsistent input";

    /// @notice Thrown when zero assets is passed as input.
    string internal constant ZERO_ASSETS = "zero assets";

    /// @notice Thrown when a zero address is passed as input.
    string internal constant ZERO_ADDRESS = "zero address";

    /// @notice Thrown when the caller is not authorized to conduct an action.
    string internal constant UNAUTHORIZED = "unauthorized";

    /// @notice Thrown when the collateral is insufficient to `borrow` or `withdrawCollateral`.
    string internal constant INSUFFICIENT_COLLATERAL = "insufficient collateral";

    /// @notice Thrown when the liquidity is insufficient to `withdraw` or `borrow`.
    string internal constant INSUFFICIENT_LIQUIDITY = "insufficient liquidity";

    /// @notice Thrown when the position to liquidate is healthy.
    string internal constant HEALTHY_POSITION = "position is healthy";

    /// @notice Thrown when the authorization signature is invalid.
    string internal constant INVALID_SIGNATURE = "invalid signature";

    /// @notice Thrown when the authorization signature is expired.
    string internal constant SIGNATURE_EXPIRED = "signature expired";

    /// @notice Thrown when the nonce is invalid.
    string internal constant INVALID_NONCE = "invalid nonce";

    /// @notice Thrown when a token transfer reverted.
    string internal constant TRANSFER_REVERTED = "transfer reverted";

    /// @notice Thrown when a token transfer returned false.
    string internal constant TRANSFER_RETURNED_FALSE = "transfer returned false";

    /// @notice Thrown when a token transferFrom reverted.
    string internal constant TRANSFER_FROM_REVERTED = "transferFrom reverted";

    /// @notice Thrown when a token transferFrom returned false
    string internal constant TRANSFER_FROM_RETURNED_FALSE = "transferFrom returned false";

    /// @notice Thrown when the maximum uint128 is exceeded.
    string internal constant MAX_UINT128_EXCEEDED = "max uint128 exceeded";
}

File 14 of 20 : IIrm.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

import {MarketParams, Market} from "./IMorpho.sol";

/// @title IIrm
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Interface that Interest Rate Models (IRMs) used by Morpho must implement.
interface IIrm {
    /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams`.
    /// @dev Assumes that `market` corresponds to `marketParams`.
    function borrowRate(MarketParams memory marketParams, Market memory market) external returns (uint256);

    /// @notice Returns the borrow rate per second (scaled by WAD) of the market `marketParams` without modifying any
    /// storage.
    /// @dev Assumes that `market` corresponds to `marketParams`.
    function borrowRateView(MarketParams memory marketParams, Market memory market) external view returns (uint256);
}

File 15 of 20 : MathLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

uint256 constant WAD = 1e18;

/// @title MathLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to manage fixed-point arithmetic.
library MathLib {
    /// @dev Returns (`x` * `y`) / `WAD` rounded down.
    function wMulDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD);
    }

    /// @dev Returns (`x` * `WAD`) / `y` rounded down.
    function wDivDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y);
    }

    /// @dev Returns (`x` * `WAD`) / `y` rounded up.
    function wDivUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y);
    }

    /// @dev Returns (`x` * `y`) / `d` rounded down.
    function mulDivDown(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
        return (x * y) / d;
    }

    /// @dev Returns (`x` * `y`) / `d` rounded up.
    function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256) {
        return (x * y + (d - 1)) / d;
    }

    /// @dev Returns the sum of the first three non-zero terms of a Taylor expansion of e^(nx) - 1, to approximate a
    /// continuous compound interest rate.
    function wTaylorCompounded(uint256 x, uint256 n) internal pure returns (uint256) {
        uint256 firstTerm = x * n;
        uint256 secondTerm = mulDivDown(firstTerm, firstTerm, 2 * WAD);
        uint256 thirdTerm = mulDivDown(secondTerm, firstTerm, 3 * WAD);

        return firstTerm + secondTerm + thirdTerm;
    }
}

File 16 of 20 : MorphoLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {IMorpho, Id} from "../../interfaces/IMorpho.sol";
import {MorphoStorageLib} from "./MorphoStorageLib.sol";

/// @title MorphoLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library to access Morpho storage variables.
/// @dev Warning: Supply and borrow getters may return outdated values that do not include accrued interest.
library MorphoLib {
    function supplyShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.positionSupplySharesSlot(id, user));
        return uint256(morpho.extSloads(slot)[0]);
    }

    function borrowShares(IMorpho morpho, Id id, address user) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
        return uint128(uint256(morpho.extSloads(slot)[0]));
    }

    function collateral(IMorpho morpho, Id id, address user) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.positionBorrowSharesAndCollateralSlot(id, user));
        return uint256(morpho.extSloads(slot)[0] >> 128);
    }

    function totalSupplyAssets(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
        return uint128(uint256(morpho.extSloads(slot)[0]));
    }

    function totalSupplyShares(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketTotalSupplyAssetsAndSharesSlot(id));
        return uint256(morpho.extSloads(slot)[0] >> 128);
    }

    function totalBorrowAssets(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
        return uint128(uint256(morpho.extSloads(slot)[0]));
    }

    function totalBorrowShares(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketTotalBorrowAssetsAndSharesSlot(id));
        return uint256(morpho.extSloads(slot)[0] >> 128);
    }

    function lastUpdate(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
        return uint128(uint256(morpho.extSloads(slot)[0]));
    }

    function fee(IMorpho morpho, Id id) internal view returns (uint256) {
        bytes32[] memory slot = _array(MorphoStorageLib.marketLastUpdateAndFeeSlot(id));
        return uint256(morpho.extSloads(slot)[0] >> 128);
    }

    function _array(bytes32 x) private pure returns (bytes32[] memory) {
        bytes32[] memory res = new bytes32[](1);
        res[0] = x;
        return res;
    }
}

File 17 of 20 : SharesMathLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

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

/// @title SharesMathLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Shares management library.
/// @dev This implementation mitigates share price manipulations, using OpenZeppelin's method of virtual shares:
/// https://docs.openzeppelin.com/contracts/4.x/erc4626#inflation-attack.
library SharesMathLib {
    using MathLib for uint256;

    /// @dev The number of virtual shares has been chosen low enough to prevent overflows, and high enough to ensure
    /// high precision computations.
    /// @dev Virtual shares can never be redeemed for the assets they are entitled to, but it is assumed the share price
    /// stays low enough not to inflate these assets to a significant value.
    /// @dev Warning: The assets to which virtual borrow shares are entitled behave like unrealizable bad debt.
    uint256 internal constant VIRTUAL_SHARES = 1e6;

    /// @dev A number of virtual assets of 1 enforces a conversion rate between shares and assets when a market is
    /// empty.
    uint256 internal constant VIRTUAL_ASSETS = 1;

    /// @dev Calculates the value of `assets` quoted in shares, rounding down.
    function toSharesDown(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
        return assets.mulDivDown(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
    }

    /// @dev Calculates the value of `shares` quoted in assets, rounding down.
    function toAssetsDown(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
        return shares.mulDivDown(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
    }

    /// @dev Calculates the value of `assets` quoted in shares, rounding up.
    function toSharesUp(uint256 assets, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
        return assets.mulDivUp(totalShares + VIRTUAL_SHARES, totalAssets + VIRTUAL_ASSETS);
    }

    /// @dev Calculates the value of `shares` quoted in assets, rounding up.
    function toAssetsUp(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
        return shares.mulDivUp(totalAssets + VIRTUAL_ASSETS, totalShares + VIRTUAL_SHARES);
    }
}

File 18 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 19 of 20 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 20 of 20 : MorphoStorageLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {Id} from "../../interfaces/IMorpho.sol";

/// @title MorphoStorageLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Helper library exposing getters to access Morpho storage variables' slot.
/// @dev This library is not used in Morpho itself and is intended to be used by integrators.
library MorphoStorageLib {
    /* SLOTS */

    uint256 internal constant OWNER_SLOT = 0;
    uint256 internal constant FEE_RECIPIENT_SLOT = 1;
    uint256 internal constant POSITION_SLOT = 2;
    uint256 internal constant MARKET_SLOT = 3;
    uint256 internal constant IS_IRM_ENABLED_SLOT = 4;
    uint256 internal constant IS_LLTV_ENABLED_SLOT = 5;
    uint256 internal constant IS_AUTHORIZED_SLOT = 6;
    uint256 internal constant NONCE_SLOT = 7;
    uint256 internal constant ID_TO_MARKET_PARAMS_SLOT = 8;

    /* SLOT OFFSETS */

    uint256 internal constant LOAN_TOKEN_OFFSET = 0;
    uint256 internal constant COLLATERAL_TOKEN_OFFSET = 1;
    uint256 internal constant ORACLE_OFFSET = 2;
    uint256 internal constant IRM_OFFSET = 3;
    uint256 internal constant LLTV_OFFSET = 4;

    uint256 internal constant SUPPLY_SHARES_OFFSET = 0;
    uint256 internal constant BORROW_SHARES_AND_COLLATERAL_OFFSET = 1;

    uint256 internal constant TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET = 0;
    uint256 internal constant TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET = 1;
    uint256 internal constant LAST_UPDATE_AND_FEE_OFFSET = 2;

    /* GETTERS */

    function ownerSlot() internal pure returns (bytes32) {
        return bytes32(OWNER_SLOT);
    }

    function feeRecipientSlot() internal pure returns (bytes32) {
        return bytes32(FEE_RECIPIENT_SLOT);
    }

    function positionSupplySharesSlot(Id id, address user) internal pure returns (bytes32) {
        return bytes32(
            uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT))))) + SUPPLY_SHARES_OFFSET
        );
    }

    function positionBorrowSharesAndCollateralSlot(Id id, address user) internal pure returns (bytes32) {
        return bytes32(
            uint256(keccak256(abi.encode(user, keccak256(abi.encode(id, POSITION_SLOT)))))
                + BORROW_SHARES_AND_COLLATERAL_OFFSET
        );
    }

    function marketTotalSupplyAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_SUPPLY_ASSETS_AND_SHARES_OFFSET);
    }

    function marketTotalBorrowAssetsAndSharesSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + TOTAL_BORROW_ASSETS_AND_SHARES_OFFSET);
    }

    function marketLastUpdateAndFeeSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, MARKET_SLOT))) + LAST_UPDATE_AND_FEE_OFFSET);
    }

    function isIrmEnabledSlot(address irm) internal pure returns (bytes32) {
        return keccak256(abi.encode(irm, IS_IRM_ENABLED_SLOT));
    }

    function isLltvEnabledSlot(uint256 lltv) internal pure returns (bytes32) {
        return keccak256(abi.encode(lltv, IS_LLTV_ENABLED_SLOT));
    }

    function isAuthorizedSlot(address authorizer, address authorizee) internal pure returns (bytes32) {
        return keccak256(abi.encode(authorizee, keccak256(abi.encode(authorizer, IS_AUTHORIZED_SLOT))));
    }

    function nonceSlot(address authorizer) internal pure returns (bytes32) {
        return keccak256(abi.encode(authorizer, NONCE_SLOT));
    }

    function idToLoanTokenSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LOAN_TOKEN_OFFSET);
    }

    function idToCollateralTokenSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + COLLATERAL_TOKEN_OFFSET);
    }

    function idToOracleSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + ORACLE_OFFSET);
    }

    function idToIrmSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + IRM_OFFSET);
    }

    function idToLltvSlot(Id id) internal pure returns (bytes32) {
        return bytes32(uint256(keccak256(abi.encode(id, ID_TO_MARKET_PARAMS_SLOT))) + LLTV_OFFSET);
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/metamorpho/lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/metamorpho/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/metamorpho/lib/erc4626-tests/",
    "forge-std/=lib/metamorpho/lib/forge-std/src/",
    "metamorpho/=lib/metamorpho/",
    "morpho-blue-irm/=lib/metamorpho/lib/morpho-blue-irm/src/",
    "morpho-blue/=lib/metamorpho/lib/morpho-blue/",
    "openzeppelin-contracts/=lib/metamorpho/lib/openzeppelin-contracts/",
    "solmate/=lib/metamorpho/lib/morpho-blue-irm/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 999999
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"morpho","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadySet","type":"error"},{"inputs":[],"name":"DepositMarketInWithdrawals","type":"error"},{"inputs":[],"name":"EmptyWithdrawals","type":"error"},{"inputs":[],"name":"InconsistentWithdrawals","type":"error"},{"inputs":[],"name":"IncorrectFee","type":"error"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"MarketNotEnabled","type":"error"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"MaxInflowExceeded","type":"error"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"MaxOutflowExceeded","type":"error"},{"inputs":[],"name":"MaxSettableFlowCapExceeded","type":"error"},{"inputs":[],"name":"NotAdminNorVaultOwner","type":"error"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"NotEnoughSupply","type":"error"},{"inputs":[{"internalType":"Id","name":"id","type":"bytes32"}],"name":"WithdrawZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"Id","name":"supplyMarketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"suppliedAssets","type":"uint256"}],"name":"PublicReallocateTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"Id","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"withdrawnAssets","type":"uint256"}],"name":"PublicWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"Id","name":"id","type":"bytes32"},{"components":[{"internalType":"uint128","name":"maxIn","type":"uint128"},{"internalType":"uint128","name":"maxOut","type":"uint128"}],"internalType":"struct FlowCaps","name":"caps","type":"tuple"}],"indexed":false,"internalType":"struct FlowCapsConfig[]","name":"config","type":"tuple[]"}],"name":"SetFlowCaps","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"TransferFee","type":"event"},{"inputs":[],"name":"MORPHO","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accruedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"Id","name":"","type":"bytes32"}],"name":"flowCaps","outputs":[{"internalType":"uint128","name":"maxIn","type":"uint128"},{"internalType":"uint128","name":"maxOut","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"components":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint128","name":"amount","type":"uint128"}],"internalType":"struct Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"supplyMarketParams","type":"tuple"}],"name":"reallocateTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"Id","name":"id","type":"bytes32"},{"components":[{"internalType":"uint128","name":"maxIn","type":"uint128"},{"internalType":"uint128","name":"maxOut","type":"uint128"}],"internalType":"struct FlowCaps","name":"caps","type":"tuple"}],"internalType":"struct FlowCapsConfig[]","name":"config","type":"tuple[]"}],"name":"setFlowCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address payable","name":"feeRecipient","type":"address"}],"name":"transferFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a03461008857601f6122f738819003918201601f19168301916001600160401b0383118484101761008d5780849260209460405283398101031261008857516001600160a01b038116908190036100885760805260405161225390816100a48239608051818181610e1801528181610f2501528181611053015281816110dd0152611baa0152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b60003560e01c9081630e4eecf814611bce575080633acb562414611b5f57806363a846f814611af95780636fcca69b14611a94578063833947fd1461089757806391b114b2146108325780639dbcd5b9146107a6578063c55b6bb71461064b578063e55156b5146104f55763f46180461461008d57600080fd5b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f0576100c4611d1b565b6024906024359067ffffffffffffffff8083116104f057366023840112156104f05782600401359081116104f0576024830192606090602436918385020101116104f05773ffffffffffffffffffffffffffffffffffffffff80931694856000526020936000855280604060002054163314159081610479575b5061044f576000939291935b8281106101e95750506040519281838501848652526040840194926000905b83821061019a5787337f709e1cb4b0ac458eb1c1a9c708e841ee963b229247afbf1437bd39e01ae4aa14888a0389a3005b90919293958380600192893581526fffffffffffffffffffffffffffffffff806101c5878d016120ac565b16868301526101d660408c016120ac565b1660408201520197019493920190610169565b6101f88184889795969761209c565b356040517fcc718f76000000000000000000000000000000000000000000000000000000008152816004820152848185818c5afa8015610443578791600091610416575b50015115806103c8575b610398576fffffffffffffffffffffffffffffffff91906f7fffffffffffffffffffffffffffffff80846102858a61027f878c8f61209c565b0161200b565b1611908484898c8515610378575b505050505061034e576001926103046040610344936102b3868b8e61209c565b908d60005260038c5282600020906000528b5281600020936102d68c830161200b565b167fffffffffffffffffffffffffffffffff000000000000000000000000000000008554161784550161200b565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b019392919361014a565b60046040517fb9860d64000000000000000000000000000000000000000000000000000000008152fd5b61038c939495509161027f9160409361209c565b1611388484898c610293565b9050604051907f6113d8c70000000000000000000000000000000000000000000000000000000082526004820152fd5b506fffffffffffffffffffffffffffffffff806103ea8861027f868a8d61209c565b1615908115916103fb575b50610246565b905061040d604061027f85898c61209c565b161515386103f5565b6104369150863d881161043c575b61042e8183611dc7565b810190611f3b565b3861023c565b503d610424565b6040513d6000823e3d90fd5b60046040517f26d3a7bf000000000000000000000000000000000000000000000000000000008152fd5b90506040517f8da5cb5b00000000000000000000000000000000000000000000000000000000815285816004818b5afa908115610443576000916104c3575b50163314153861013e565b6104e39150863d88116104e9575b6104db8183611dc7565b810190611e08565b386104b8565b503d6104d1565b600080fd5b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05761052c611d1b565b60243573ffffffffffffffffffffffffffffffffffffffff809216918260005260209060008252806040600020541633141590816105e4575b5061044f57826000526001815281604060002054146105ba577f44a6d70a601a6f8a85c075467e9d7245897140cbf6dd505c9d9d764459f5fb64908360005260018152826040600020556040519283523392a3005b60046040517fa741a045000000000000000000000000000000000000000000000000000000008152fd5b90506040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481885afa9081156104435760009161062e575b501633141584610565565b6106459150833d85116104e9576104db8183611dc7565b85610623565b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057610682611d1b565b60243573ffffffffffffffffffffffffffffffffffffffff918282168092036104f0578216918260005260209060008252806040600020541633141580610740575b61044f578290846000526000835260406000205416146105ba577fc51248b3e510a1244e01043dffdc0132d10194bd4506382cbcf83d05f6ec57ef9083600052600081526040600020837fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790556040519283523392a3005b506040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481885afa8015610443578291600091610789575b50163314156106c4565b6107a09150843d86116104e9576104db8183611dc7565b8661077f565b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff6107f2611d1b565b1660005260036020526040600020602435600052602052604080600020548151906fffffffffffffffffffffffffffffffff8116825260801c6020820152f35b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff61087e611d1b565b1660005260026020526020604060002054604051908152f35b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f0576108c9611d1b565b60243567ffffffffffffffff81116104f057366023820112156104f05767ffffffffffffffff8160040135116104f05736602460c0836004013502830101116104f05760a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126104f05773ffffffffffffffffffffffffffffffffffffffff821660005260016020526040600020543403611a6a5734611a34575b806004013515611a0a5760a061097c36611e41565b20916040517fcc718f7600000000000000000000000000000000000000000000000000000000815283600482015260608160248173ffffffffffffffffffffffffffffffffffffffff86165afa8015610443576020916000916119eb575b5001511561194d57600482013560018101919082106113c7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610a36610a2084611fb4565b93610a2e6040519586611dc7565b808552611fb4565b0160005b81811061199d5750506000926000805b82600401358210610d2c57505073ffffffffffffffffffffffffffffffffffffffff821660005260036020526040600020856000526020526fffffffffffffffffffffffffffffffff93846040600020541694808216809610610cfb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92610b74602093610b989373ffffffffffffffffffffffffffffffffffffffff88166000526003865260406000208b60005286526040600020907fffffffffffffffffffffffffffffffff00000000000000000000000000000000825491610b328582851661204c565b16911617905573ffffffffffffffffffffffffffffffffffffffff87166000526003855260406000208a6000528552610304604060002091825460801c612028565b610b8281600401358761207b565b51610b8c36611e41565b9052600401358561207b565b51015273ffffffffffffffffffffffffffffffffffffffff81163b156104f05760405180927f7299aa310000000000000000000000000000000000000000000000000000000082526024820160206004840152815180915260206044840192019060005b818110610c8957505050908060009203818373ffffffffffffffffffffffffffffffffffffffff86165af19182156104435773ffffffffffffffffffffffffffffffffffffffff92610c7a575b5060405192835216907ff8ae80b0854dfc3c73d3eb4b6160df1996a5859e6c1d11d10f3980a7f469199160203392a4005b610c8390611d97565b84610c49565b91935091602060c0600192828751610ce68382516080809173ffffffffffffffffffffffffffffffffffffffff80825116855280602083015116602086015280604083015116604086015260608201511660608501520151910152565b015160a0820152019401910191859392610bfc565b602487604051907f2e581b4e0000000000000000000000000000000000000000000000000000000082526004820152fd5b949060a0610d4b36610d4684876004013560248901611fcc565b611ed9565b20916040517fcc718f7600000000000000000000000000000000000000000000000000000000815283600482015260608160248173ffffffffffffffffffffffffffffffffffffffff8a165afa80156104435760209160009161197e575b5001511561194d57610dc860a061027f84876004013560248901611fcc565b966fffffffffffffffffffffffffffffffff88161561191c578311156118f2578783146118c857610e0182856004013560248701611fcc565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163b156104f0576080604051917f151c1ade00000000000000000000000000000000000000000000000000000000835273ffffffffffffffffffffffffffffffffffffffff610e8582611d3e565b16600484015273ffffffffffffffffffffffffffffffffffffffff610eac60208301611d3e565b16602484015273ffffffffffffffffffffffffffffffffffffffff610ed360408301611d3e565b16604484015273ffffffffffffffffffffffffffffffffffffffff610efa60608301611d3e565b1660648401520135608482015260008160a4818373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af18015610443576118b9575b50610f6936610d4684876004013560248901611fcc565b60a08120604051602081019182526002604082015260408152610f8b81611dab565b519020604051602081019173ffffffffffffffffffffffffffffffffffffffff89168352604082015260408152610fc181611dab565b519020604051610fd081611d5f565b6001815260208101916020368437610fe78261206e565b526040519182917f7784c685000000000000000000000000000000000000000000000000000000008352602483019060206004850152518091526044830191906000905b80821061189d575050509080600092038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa8015610443576000906117f1575b61108d915061206e565b519060a0812090604051917f5c60e39a000000000000000000000000000000000000000000000000000000008352600483015260c08260248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9182156104435760009261170b575b5060808201906111316fffffffffffffffffffffffffffffffff8351164261208f565b90811515806116ec575b806116c9575b6113f6575b5050506fffffffffffffffffffffffffffffffff602081835116920151166001820182116113c757620f4240810181116113c757611196926001620f424061119193019301906120e6565b6121e4565b73ffffffffffffffffffffffffffffffffffffffff861660005260036020526040600020846000526020526fffffffffffffffffffffffffffffffff881660406000205460801c10611396576fffffffffffffffffffffffffffffffff88168110611365576113078884936112f387948b6112d86112cf896112c98f9c8f73ffffffffffffffffffffffffffffffffffffffff60019f8e828216600052600360205260406000209060005260205260406000208d7fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff61128a845493828516612028565b16911617905516600052600360205260406000208d6000526020526112bb60406000206103048d825460801c61204c565b602481600401359101611fcc565b9361207b565b51913690611ed9565b90526fffffffffffffffffffffffffffffffff84169061208f565b60206112ff878d61207b565b510152612028565b976fffffffffffffffffffffffffffffffff6040519116815273ffffffffffffffffffffffffffffffffffffffff8716907f6218cdb9e8efb3d0e8136d32c91d9446eaf19e2e486bc67dfcb3d574ca60d50460203392a40190610a4a565b602484604051907f8c4bfb140000000000000000000000000000000000000000000000000000000082526004820152fd5b602484604051907fad5f61d30000000000000000000000000000000000000000000000000000000082526004820152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6114a46101648273ffffffffffffffffffffffffffffffffffffffff60606020950151166fffffffffffffffffffffffffffffffff60405197889586947f8c00bf6b00000000000000000000000000000000000000000000000000000000865260048601906080809173ffffffffffffffffffffffffffffffffffffffff80825116855280602083015116602086015280604083015116604086015260608201511660608501520151910152565b818a511660a485015281878b01511660c48501528160408b01511660e48501528160608b01511661010485015251166101248301526fffffffffffffffffffffffffffffffff60a0890151166101448301525afa91821561044357600092611693575b509061157a61153061156f936fffffffffffffffffffffffffffffffff604087015116936120e6565b91611574671bc16d674ec8000061154785806120e6565b0493670de0b6b3a764000095856729a2241af62c0000611568848a996120e6565b0492611e34565b611e34565b906120e6565b046fffffffffffffffffffffffffffffffff6115a4611598836120f9565b82604087015116612028565b1660408401526fffffffffffffffffffffffffffffffff6115d06115c7836120f9565b82865116612028565b1683526fffffffffffffffffffffffffffffffff60a0840151168015611146576115f9916120e6565b04611617816fffffffffffffffffffffffffffffffff84511661208f565b6fffffffffffffffffffffffffffffffff60208401511690620f4240820182116113c7576001810181116113c757611674611685926111916fffffffffffffffffffffffffffffffff95620f4240600161167996019301906120e6565b6120f9565b82602085015116612028565b1660208201528a8080611146565b91506020823d6020116116c1575b816116ae60209383611dc7565b810103126104f05790519061157a611507565b3d91506116a1565b5073ffffffffffffffffffffffffffffffffffffffff6060820151161515611141565b506fffffffffffffffffffffffffffffffff604085015116151561113b565b90915060c0813d60c0116117e9575b8161172760c09383611dc7565b810103126104f057604051908160c081011067ffffffffffffffff60c0840111176117ba5760a06117ae9160c08401604052611762816120c9565b8452611770602082016120c9565b6020850152611781604082016120c9565b6040850152611792606082016120c9565b60608501526117a3608082016120c9565b6080850152016120c9565b60a0820152908b61110e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b3d915061171a565b503d90816000823e6118038282611dc7565b60208183810103126104f05780519167ffffffffffffffff83116104f057808201601f8484010112156104f057828201519161183e83611fb4565b9361184c6040519586611dc7565b8385526020850192820160208560051b8385010101116104f057602081830101925b60208560051b8385010101841061188d57505050505061108d90611083565b835181526020938401930161186e565b919350916020806001928651815201940192018493929161102b565b6118c290611d97565b88610f52565b60046040517f898ca719000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc9527748000000000000000000000000000000000000000000000000000000008152fd5b602484604051907f9565ed900000000000000000000000000000000000000000000000000000000082526004820152fd5b602483604051907f6113d8c70000000000000000000000000000000000000000000000000000000082526004820152fd5b611997915060603d60601161043c5761042e8183611dc7565b8a610da9565b6020906040516119ac81611d5f565b6040516119b881611d7b565b60008152600084820152600060408201526000606082015260006080820152815260008382015282828701015201610a3a565b611a04915060603d60601161043c5761042e8183611dc7565b856109da565b60046040517f76da5945000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff821660005260026020526040600020611a63348254611e34565b9055610967565b60046040517fcd3cb2bb000000000000000000000000000000000000000000000000000000008152fd5b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff611ae0611d1b565b1660005260016020526020604060002054604051908152f35b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057602073ffffffffffffffffffffffffffffffffffffffff80611b48611d1b565b166000526000825260406000205416604051908152f35b346104f05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057611c05611d1b565b906024359173ffffffffffffffffffffffffffffffffffffffff908184168094036104f057811691826000526020916000835280604060002054163314159182611cb5575b505061044f578160005260028152604060002090600082549255600082858115611cab575b600092839283928392f115610443577f6ab9f885fa0bfd2af57586f4cdde83bbfc79294d0cd2d61d4b31e9a3d1be6e2c906040519283523392a4005b6108fc9250611c6f565b9091507f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481875afa90811561044357600091611cfe575b50163314158480611c4a565b611d159150833d85116104e9576104db8183611dc7565b85611cf2565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036104f057565b359073ffffffffffffffffffffffffffffffffffffffff821682036104f057565b6040810190811067ffffffffffffffff8211176117ba57604052565b60a0810190811067ffffffffffffffff8211176117ba57604052565b67ffffffffffffffff81116117ba57604052565b6060810190811067ffffffffffffffff8211176117ba57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117ba57604052565b908160209103126104f0575173ffffffffffffffffffffffffffffffffffffffff811681036104f05790565b919082018092116113c757565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc60a09101126104f05760405190611e7882611d7b565b8173ffffffffffffffffffffffffffffffffffffffff60443581811681036104f057825260643581811681036104f057602083015260843581811681036104f057604083015260a43590811681036104f0576060820152608060c435910152565b91908260a09103126104f057604051611ef181611d7b565b6080808294611eff81611d3e565b8452611f0d60208201611d3e565b6020850152611f1e60408201611d3e565b6040850152611f2f60608201611d3e565b60608501520135910152565b908160609103126104f0576040519067ffffffffffffffff9060608301828111848210176117ba57604052805176ffffffffffffffffffffffffffffffffffffffffffffff811681036104f057835260208101519081151582036104f0576040916020850152015190811681036104f057604082015290565b67ffffffffffffffff81116117ba5760051b60200190565b9190811015611fdc5760c0020190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b356fffffffffffffffffffffffffffffffff811681036104f05790565b9190916fffffffffffffffffffffffffffffffff808094169116019182116113c757565b6fffffffffffffffffffffffffffffffff91821690821603919082116113c757565b805115611fdc5760200190565b8051821015611fdc5760209160051b010190565b919082039182116113c757565b9190811015611fdc576060020190565b35906fffffffffffffffffffffffffffffffff821682036104f057565b51906fffffffffffffffffffffffffffffffff821682036104f057565b818102929181159184041417156113c757565b6fffffffffffffffffffffffffffffffff9060405161211781611d5f565b601481526020907f6d61782075696e7431323820657863656564656400000000000000000000000060208201528383116121515750501690565b60405180927f08c379a00000000000000000000000000000000000000000000000000000000082526020600483015282519283602484015260005b8481106121cd575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b81810183015186820160440152859350820161218c565b81156121ee570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220f28f85a78415b835820c74ee6024f92207b1f2686716124647e59802a3f4164164736f6c63430008180033000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c9081630e4eecf814611bce575080633acb562414611b5f57806363a846f814611af95780636fcca69b14611a94578063833947fd1461089757806391b114b2146108325780639dbcd5b9146107a6578063c55b6bb71461064b578063e55156b5146104f55763f46180461461008d57600080fd5b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f0576100c4611d1b565b6024906024359067ffffffffffffffff8083116104f057366023840112156104f05782600401359081116104f0576024830192606090602436918385020101116104f05773ffffffffffffffffffffffffffffffffffffffff80931694856000526020936000855280604060002054163314159081610479575b5061044f576000939291935b8281106101e95750506040519281838501848652526040840194926000905b83821061019a5787337f709e1cb4b0ac458eb1c1a9c708e841ee963b229247afbf1437bd39e01ae4aa14888a0389a3005b90919293958380600192893581526fffffffffffffffffffffffffffffffff806101c5878d016120ac565b16868301526101d660408c016120ac565b1660408201520197019493920190610169565b6101f88184889795969761209c565b356040517fcc718f76000000000000000000000000000000000000000000000000000000008152816004820152848185818c5afa8015610443578791600091610416575b50015115806103c8575b610398576fffffffffffffffffffffffffffffffff91906f7fffffffffffffffffffffffffffffff80846102858a61027f878c8f61209c565b0161200b565b1611908484898c8515610378575b505050505061034e576001926103046040610344936102b3868b8e61209c565b908d60005260038c5282600020906000528b5281600020936102d68c830161200b565b167fffffffffffffffffffffffffffffffff000000000000000000000000000000008554161784550161200b565b6fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b019392919361014a565b60046040517fb9860d64000000000000000000000000000000000000000000000000000000008152fd5b61038c939495509161027f9160409361209c565b1611388484898c610293565b9050604051907f6113d8c70000000000000000000000000000000000000000000000000000000082526004820152fd5b506fffffffffffffffffffffffffffffffff806103ea8861027f868a8d61209c565b1615908115916103fb575b50610246565b905061040d604061027f85898c61209c565b161515386103f5565b6104369150863d881161043c575b61042e8183611dc7565b810190611f3b565b3861023c565b503d610424565b6040513d6000823e3d90fd5b60046040517f26d3a7bf000000000000000000000000000000000000000000000000000000008152fd5b90506040517f8da5cb5b00000000000000000000000000000000000000000000000000000000815285816004818b5afa908115610443576000916104c3575b50163314153861013e565b6104e39150863d88116104e9575b6104db8183611dc7565b810190611e08565b386104b8565b503d6104d1565b600080fd5b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05761052c611d1b565b60243573ffffffffffffffffffffffffffffffffffffffff809216918260005260209060008252806040600020541633141590816105e4575b5061044f57826000526001815281604060002054146105ba577f44a6d70a601a6f8a85c075467e9d7245897140cbf6dd505c9d9d764459f5fb64908360005260018152826040600020556040519283523392a3005b60046040517fa741a045000000000000000000000000000000000000000000000000000000008152fd5b90506040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481885afa9081156104435760009161062e575b501633141584610565565b6106459150833d85116104e9576104db8183611dc7565b85610623565b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057610682611d1b565b60243573ffffffffffffffffffffffffffffffffffffffff918282168092036104f0578216918260005260209060008252806040600020541633141580610740575b61044f578290846000526000835260406000205416146105ba577fc51248b3e510a1244e01043dffdc0132d10194bd4506382cbcf83d05f6ec57ef9083600052600081526040600020837fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790556040519283523392a3005b506040517f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481885afa8015610443578291600091610789575b50163314156106c4565b6107a09150843d86116104e9576104db8183611dc7565b8661077f565b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff6107f2611d1b565b1660005260036020526040600020602435600052602052604080600020548151906fffffffffffffffffffffffffffffffff8116825260801c6020820152f35b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff61087e611d1b565b1660005260026020526020604060002054604051908152f35b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f0576108c9611d1b565b60243567ffffffffffffffff81116104f057366023820112156104f05767ffffffffffffffff8160040135116104f05736602460c0836004013502830101116104f05760a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126104f05773ffffffffffffffffffffffffffffffffffffffff821660005260016020526040600020543403611a6a5734611a34575b806004013515611a0a5760a061097c36611e41565b20916040517fcc718f7600000000000000000000000000000000000000000000000000000000815283600482015260608160248173ffffffffffffffffffffffffffffffffffffffff86165afa8015610443576020916000916119eb575b5001511561194d57600482013560018101919082106113c7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610a36610a2084611fb4565b93610a2e6040519586611dc7565b808552611fb4565b0160005b81811061199d5750506000926000805b82600401358210610d2c57505073ffffffffffffffffffffffffffffffffffffffff821660005260036020526040600020856000526020526fffffffffffffffffffffffffffffffff93846040600020541694808216809610610cfb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92610b74602093610b989373ffffffffffffffffffffffffffffffffffffffff88166000526003865260406000208b60005286526040600020907fffffffffffffffffffffffffffffffff00000000000000000000000000000000825491610b328582851661204c565b16911617905573ffffffffffffffffffffffffffffffffffffffff87166000526003855260406000208a6000528552610304604060002091825460801c612028565b610b8281600401358761207b565b51610b8c36611e41565b9052600401358561207b565b51015273ffffffffffffffffffffffffffffffffffffffff81163b156104f05760405180927f7299aa310000000000000000000000000000000000000000000000000000000082526024820160206004840152815180915260206044840192019060005b818110610c8957505050908060009203818373ffffffffffffffffffffffffffffffffffffffff86165af19182156104435773ffffffffffffffffffffffffffffffffffffffff92610c7a575b5060405192835216907ff8ae80b0854dfc3c73d3eb4b6160df1996a5859e6c1d11d10f3980a7f469199160203392a4005b610c8390611d97565b84610c49565b91935091602060c0600192828751610ce68382516080809173ffffffffffffffffffffffffffffffffffffffff80825116855280602083015116602086015280604083015116604086015260608201511660608501520151910152565b015160a0820152019401910191859392610bfc565b602487604051907f2e581b4e0000000000000000000000000000000000000000000000000000000082526004820152fd5b949060a0610d4b36610d4684876004013560248901611fcc565b611ed9565b20916040517fcc718f7600000000000000000000000000000000000000000000000000000000815283600482015260608160248173ffffffffffffffffffffffffffffffffffffffff8a165afa80156104435760209160009161197e575b5001511561194d57610dc860a061027f84876004013560248901611fcc565b966fffffffffffffffffffffffffffffffff88161561191c578311156118f2578783146118c857610e0182856004013560248701611fcc565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb163b156104f0576080604051917f151c1ade00000000000000000000000000000000000000000000000000000000835273ffffffffffffffffffffffffffffffffffffffff610e8582611d3e565b16600484015273ffffffffffffffffffffffffffffffffffffffff610eac60208301611d3e565b16602484015273ffffffffffffffffffffffffffffffffffffffff610ed360408301611d3e565b16604484015273ffffffffffffffffffffffffffffffffffffffff610efa60608301611d3e565b1660648401520135608482015260008160a4818373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb165af18015610443576118b9575b50610f6936610d4684876004013560248901611fcc565b60a08120604051602081019182526002604082015260408152610f8b81611dab565b519020604051602081019173ffffffffffffffffffffffffffffffffffffffff89168352604082015260408152610fc181611dab565b519020604051610fd081611d5f565b6001815260208101916020368437610fe78261206e565b526040519182917f7784c685000000000000000000000000000000000000000000000000000000008352602483019060206004850152518091526044830191906000905b80821061189d575050509080600092038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb165afa8015610443576000906117f1575b61108d915061206e565b519060a0812090604051917f5c60e39a000000000000000000000000000000000000000000000000000000008352600483015260c08260248173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb165afa9182156104435760009261170b575b5060808201906111316fffffffffffffffffffffffffffffffff8351164261208f565b90811515806116ec575b806116c9575b6113f6575b5050506fffffffffffffffffffffffffffffffff602081835116920151166001820182116113c757620f4240810181116113c757611196926001620f424061119193019301906120e6565b6121e4565b73ffffffffffffffffffffffffffffffffffffffff861660005260036020526040600020846000526020526fffffffffffffffffffffffffffffffff881660406000205460801c10611396576fffffffffffffffffffffffffffffffff88168110611365576113078884936112f387948b6112d86112cf896112c98f9c8f73ffffffffffffffffffffffffffffffffffffffff60019f8e828216600052600360205260406000209060005260205260406000208d7fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff61128a845493828516612028565b16911617905516600052600360205260406000208d6000526020526112bb60406000206103048d825460801c61204c565b602481600401359101611fcc565b9361207b565b51913690611ed9565b90526fffffffffffffffffffffffffffffffff84169061208f565b60206112ff878d61207b565b510152612028565b976fffffffffffffffffffffffffffffffff6040519116815273ffffffffffffffffffffffffffffffffffffffff8716907f6218cdb9e8efb3d0e8136d32c91d9446eaf19e2e486bc67dfcb3d574ca60d50460203392a40190610a4a565b602484604051907f8c4bfb140000000000000000000000000000000000000000000000000000000082526004820152fd5b602484604051907fad5f61d30000000000000000000000000000000000000000000000000000000082526004820152fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6114a46101648273ffffffffffffffffffffffffffffffffffffffff60606020950151166fffffffffffffffffffffffffffffffff60405197889586947f8c00bf6b00000000000000000000000000000000000000000000000000000000865260048601906080809173ffffffffffffffffffffffffffffffffffffffff80825116855280602083015116602086015280604083015116604086015260608201511660608501520151910152565b818a511660a485015281878b01511660c48501528160408b01511660e48501528160608b01511661010485015251166101248301526fffffffffffffffffffffffffffffffff60a0890151166101448301525afa91821561044357600092611693575b509061157a61153061156f936fffffffffffffffffffffffffffffffff604087015116936120e6565b91611574671bc16d674ec8000061154785806120e6565b0493670de0b6b3a764000095856729a2241af62c0000611568848a996120e6565b0492611e34565b611e34565b906120e6565b046fffffffffffffffffffffffffffffffff6115a4611598836120f9565b82604087015116612028565b1660408401526fffffffffffffffffffffffffffffffff6115d06115c7836120f9565b82865116612028565b1683526fffffffffffffffffffffffffffffffff60a0840151168015611146576115f9916120e6565b04611617816fffffffffffffffffffffffffffffffff84511661208f565b6fffffffffffffffffffffffffffffffff60208401511690620f4240820182116113c7576001810181116113c757611674611685926111916fffffffffffffffffffffffffffffffff95620f4240600161167996019301906120e6565b6120f9565b82602085015116612028565b1660208201528a8080611146565b91506020823d6020116116c1575b816116ae60209383611dc7565b810103126104f05790519061157a611507565b3d91506116a1565b5073ffffffffffffffffffffffffffffffffffffffff6060820151161515611141565b506fffffffffffffffffffffffffffffffff604085015116151561113b565b90915060c0813d60c0116117e9575b8161172760c09383611dc7565b810103126104f057604051908160c081011067ffffffffffffffff60c0840111176117ba5760a06117ae9160c08401604052611762816120c9565b8452611770602082016120c9565b6020850152611781604082016120c9565b6040850152611792606082016120c9565b60608501526117a3608082016120c9565b6080850152016120c9565b60a0820152908b61110e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b3d915061171a565b503d90816000823e6118038282611dc7565b60208183810103126104f05780519167ffffffffffffffff83116104f057808201601f8484010112156104f057828201519161183e83611fb4565b9361184c6040519586611dc7565b8385526020850192820160208560051b8385010101116104f057602081830101925b60208560051b8385010101841061188d57505050505061108d90611083565b835181526020938401930161186e565b919350916020806001928651815201940192018493929161102b565b6118c290611d97565b88610f52565b60046040517f898ca719000000000000000000000000000000000000000000000000000000008152fd5b60046040517fc9527748000000000000000000000000000000000000000000000000000000008152fd5b602484604051907f9565ed900000000000000000000000000000000000000000000000000000000082526004820152fd5b602483604051907f6113d8c70000000000000000000000000000000000000000000000000000000082526004820152fd5b611997915060603d60601161043c5761042e8183611dc7565b8a610da9565b6020906040516119ac81611d5f565b6040516119b881611d7b565b60008152600084820152600060408201526000606082015260006080820152815260008382015282828701015201610a3a565b611a04915060603d60601161043c5761042e8183611dc7565b856109da565b60046040517f76da5945000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff821660005260026020526040600020611a63348254611e34565b9055610967565b60046040517fcd3cb2bb000000000000000000000000000000000000000000000000000000008152fd5b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f05773ffffffffffffffffffffffffffffffffffffffff611ae0611d1b565b1660005260016020526020604060002054604051908152f35b346104f05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057602073ffffffffffffffffffffffffffffffffffffffff80611b48611d1b565b166000526000825260406000205416604051908152f35b346104f05760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb168152f35b346104f05760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104f057611c05611d1b565b906024359173ffffffffffffffffffffffffffffffffffffffff908184168094036104f057811691826000526020916000835280604060002054163314159182611cb5575b505061044f578160005260028152604060002090600082549255600082858115611cab575b600092839283928392f115610443577f6ab9f885fa0bfd2af57586f4cdde83bbfc79294d0cd2d61d4b31e9a3d1be6e2c906040519283523392a4005b6108fc9250611c6f565b9091507f8da5cb5b0000000000000000000000000000000000000000000000000000000081528281600481875afa90811561044357600091611cfe575b50163314158480611c4a565b611d159150833d85116104e9576104db8183611dc7565b85611cf2565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036104f057565b359073ffffffffffffffffffffffffffffffffffffffff821682036104f057565b6040810190811067ffffffffffffffff8211176117ba57604052565b60a0810190811067ffffffffffffffff8211176117ba57604052565b67ffffffffffffffff81116117ba57604052565b6060810190811067ffffffffffffffff8211176117ba57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176117ba57604052565b908160209103126104f0575173ffffffffffffffffffffffffffffffffffffffff811681036104f05790565b919082018092116113c757565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc60a09101126104f05760405190611e7882611d7b565b8173ffffffffffffffffffffffffffffffffffffffff60443581811681036104f057825260643581811681036104f057602083015260843581811681036104f057604083015260a43590811681036104f0576060820152608060c435910152565b91908260a09103126104f057604051611ef181611d7b565b6080808294611eff81611d3e565b8452611f0d60208201611d3e565b6020850152611f1e60408201611d3e565b6040850152611f2f60608201611d3e565b60608501520135910152565b908160609103126104f0576040519067ffffffffffffffff9060608301828111848210176117ba57604052805176ffffffffffffffffffffffffffffffffffffffffffffff811681036104f057835260208101519081151582036104f0576040916020850152015190811681036104f057604082015290565b67ffffffffffffffff81116117ba5760051b60200190565b9190811015611fdc5760c0020190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b356fffffffffffffffffffffffffffffffff811681036104f05790565b9190916fffffffffffffffffffffffffffffffff808094169116019182116113c757565b6fffffffffffffffffffffffffffffffff91821690821603919082116113c757565b805115611fdc5760200190565b8051821015611fdc5760209160051b010190565b919082039182116113c757565b9190811015611fdc576060020190565b35906fffffffffffffffffffffffffffffffff821682036104f057565b51906fffffffffffffffffffffffffffffffff821682036104f057565b818102929181159184041417156113c757565b6fffffffffffffffffffffffffffffffff9060405161211781611d5f565b601481526020907f6d61782075696e7431323820657863656564656400000000000000000000000060208201528383116121515750501690565b60405180927f08c379a00000000000000000000000000000000000000000000000000000000082526020600483015282519283602484015260005b8481106121cd575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b81810183015186820160440152859350820161218c565b81156121ee570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fdfea2646970667358221220f28f85a78415b835820c74ee6024f92207b1f2686716124647e59802a3f4164164736f6c63430008180033

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

000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb

-----Decoded View---------------
Arg [0] : morpho (address): 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb


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
Loading...
Loading
[ Download: CSV Export  ]
[ 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.