ETH Price: $1,801.45 (+9.61%)

Contract

0x30fa9A3cF56931ACEea42E28D35519a97D90aA67

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction and > 10 Token Transfers found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
102734942025-02-18 12:43:4764 days ago1739882627  Contract Creation0 ETH

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GeneralAdapter1

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 999999 runs

Other Settings:
cancun EvmVersion
File 1 of 33 : GeneralAdapter1.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity 0.8.28;

import {IWNative} from "../interfaces/IWNative.sol";
import {IERC4626} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {MarketParams, IMorpho} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {CoreAdapter, ErrorsLib, IERC20, SafeERC20, Address} from "./CoreAdapter.sol";
import {MathRayLib} from "../libraries/MathRayLib.sol";
import {SafeCast160} from "../../lib/permit2/src/libraries/SafeCast160.sol";
import {Permit2Lib} from "../../lib/permit2/src/libraries/Permit2Lib.sol";
import {MorphoBalancesLib} from "../../lib/morpho-blue/src/libraries/periphery/MorphoBalancesLib.sol";
import {MarketParamsLib} from "../../lib/morpho-blue/src/libraries/MarketParamsLib.sol";
import {MorphoLib} from "../../lib/morpho-blue/src/libraries/periphery/MorphoLib.sol";

/// @custom:security-contact [email protected]
/// @notice Chain agnostic adapter contract n°1.
contract GeneralAdapter1 is CoreAdapter {
    using SafeCast160 for uint256;
    using MarketParamsLib for MarketParams;
    using MathRayLib for uint256;

    /* IMMUTABLES */

    /// @notice The address of the Morpho contract.
    IMorpho public immutable MORPHO;

    /// @dev The address of the wrapped native token.
    IWNative public immutable WRAPPED_NATIVE;

    /* CONSTRUCTOR */

    /// @param bundler3 The address of the Bundler3 contract.
    /// @param morpho The address of the Morpho protocol.
    /// @param wNative The address of the canonical native token wrapper.
    constructor(address bundler3, address morpho, address wNative) CoreAdapter(bundler3) {
        require(morpho != address(0), ErrorsLib.ZeroAddress());
        require(wNative != address(0), ErrorsLib.ZeroAddress());

        MORPHO = IMorpho(morpho);
        WRAPPED_NATIVE = IWNative(wNative);
    }

    /* ERC4626 ACTIONS */

    /// @notice Mints shares of an ERC4626 vault.
    /// @dev Underlying tokens must have been previously sent to the adapter.
    /// @dev Assumes the given vault implements EIP-4626.
    /// @param vault The address of the vault.
    /// @param shares The amount of vault shares to mint.
    /// @param maxSharePriceE27 The maximum amount of assets to pay to get 1 share, scaled by 1e27.
    /// @param receiver The address to which shares will be minted.
    function erc4626Mint(address vault, uint256 shares, uint256 maxSharePriceE27, address receiver)
        external
        onlyBundler3
    {
        require(receiver != address(0), ErrorsLib.ZeroAddress());
        require(shares != 0, ErrorsLib.ZeroShares());

        IERC20 underlyingToken = IERC20(IERC4626(vault).asset());
        SafeERC20.forceApprove(underlyingToken, vault, type(uint256).max);

        uint256 assets = IERC4626(vault).mint(shares, receiver);

        SafeERC20.forceApprove(underlyingToken, vault, 0);

        require(assets.rDivUp(shares) <= maxSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Deposits underlying token in an ERC4626 vault.
    /// @dev Underlying tokens must have been previously sent to the adapter.
    /// @dev Assumes the given vault implements EIP-4626.
    /// @param vault The address of the vault.
    /// @param assets The amount of underlying token to deposit. Pass `type(uint).max` to deposit the adapter's balance.
    /// @param maxSharePriceE27 The maximum amount of assets to pay to get 1 share, scaled by 1e27.
    /// @param receiver The address to which shares will be minted.
    function erc4626Deposit(address vault, uint256 assets, uint256 maxSharePriceE27, address receiver)
        external
        onlyBundler3
    {
        require(receiver != address(0), ErrorsLib.ZeroAddress());

        IERC20 underlyingToken = IERC20(IERC4626(vault).asset());
        if (assets == type(uint256).max) assets = underlyingToken.balanceOf(address(this));

        require(assets != 0, ErrorsLib.ZeroAmount());

        SafeERC20.forceApprove(underlyingToken, vault, type(uint256).max);

        uint256 shares = IERC4626(vault).deposit(assets, receiver);

        SafeERC20.forceApprove(underlyingToken, vault, 0);

        require(assets.rDivUp(shares) <= maxSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Withdraws underlying token from an ERC4626 vault.
    /// @dev Assumes the given `vault` implements EIP-4626.
    /// @dev If `owner` is the initiator, they must have previously approved the adapter to spend their vault shares.
    /// Otherwise, vault shares must have been previously sent to the adapter.
    /// @param vault The address of the vault.
    /// @param assets The amount of underlying token to withdraw.
    /// @param minSharePriceE27 The minimum number of assets to receive per share, scaled by 1e27.
    /// @param receiver The address that will receive the withdrawn assets.
    /// @param owner The address on behalf of which the assets are withdrawn. Can only be the adapter or the initiator.
    function erc4626Withdraw(address vault, uint256 assets, uint256 minSharePriceE27, address receiver, address owner)
        external
        onlyBundler3
    {
        require(receiver != address(0), ErrorsLib.ZeroAddress());
        require(owner == address(this) || owner == initiator(), ErrorsLib.UnexpectedOwner());
        require(assets != 0, ErrorsLib.ZeroAmount());

        uint256 shares = IERC4626(vault).withdraw(assets, receiver, owner);
        require(assets.rDivDown(shares) >= minSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Redeems shares of an ERC4626 vault.
    /// @dev Assumes the given `vault` implements EIP-4626.
    /// @dev If `owner` is the initiator, they must have previously approved the adapter to spend their vault shares.
    /// Otherwise, vault shares must have been previously sent to the adapter.
    /// @param vault The address of the vault.
    /// @param shares The amount of vault shares to redeem. Pass `type(uint).max` to redeem the owner's shares.
    /// @param minSharePriceE27 The minimum number of assets to receive per share, scaled by 1e27.
    /// @param receiver The address that will receive the withdrawn assets.
    /// @param owner The address on behalf of which the shares are redeemed. Can only be the adapter or the initiator.
    function erc4626Redeem(address vault, uint256 shares, uint256 minSharePriceE27, address receiver, address owner)
        external
        onlyBundler3
    {
        require(receiver != address(0), ErrorsLib.ZeroAddress());
        require(owner == address(this) || owner == initiator(), ErrorsLib.UnexpectedOwner());

        if (shares == type(uint256).max) shares = IERC4626(vault).balanceOf(owner);

        require(shares != 0, ErrorsLib.ZeroShares());

        uint256 assets = IERC4626(vault).redeem(shares, receiver, owner);
        require(assets.rDivDown(shares) >= minSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /* MORPHO CALLBACKS */

    /// @notice Receives supply callback from the Morpho contract.
    /// @param data Bytes containing an abi-encoded Call[].
    function onMorphoSupply(uint256, bytes calldata data) external {
        morphoCallback(data);
    }

    /// @notice Receives supply collateral callback from the Morpho contract.
    /// @param data Bytes containing an abi-encoded Call[].
    function onMorphoSupplyCollateral(uint256, bytes calldata data) external {
        morphoCallback(data);
    }

    /// @notice Receives repay callback from the Morpho contract.
    /// @param data Bytes containing an abi-encoded Call[].
    function onMorphoRepay(uint256, bytes calldata data) external {
        morphoCallback(data);
    }

    /// @notice Receives flashloan callback from the Morpho contract.
    /// @param data Bytes containing an abi-encoded Call[].
    function onMorphoFlashLoan(uint256, bytes calldata data) external {
        morphoCallback(data);
    }

    /* MORPHO ACTIONS */

    /// @notice Supplies loan asset on Morpho.
    /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the
    /// adapter is guaranteed to have `assets` tokens pulled from its balance, but the possibility to mint a specific
    /// amount of shares is given for full compatibility and precision.
    /// @dev Loan tokens must have been previously sent to the adapter.
    /// @param marketParams The Morpho market to supply assets to.
    /// @param assets The amount of assets to supply. Pass `type(uint).max` to supply the adapter's loan asset balance.
    /// @param shares The amount of shares to mint.
    /// @param maxSharePriceE27 The maximum amount of assets supplied per minted share, scaled by 1e27.
    /// @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.
    function morphoSupply(
        MarketParams calldata marketParams,
        uint256 assets,
        uint256 shares,
        uint256 maxSharePriceE27,
        address onBehalf,
        bytes calldata data
    ) external onlyBundler3 {
        // Do not check `onBehalf` against the zero address as it's done in Morpho.
        require(onBehalf != address(this), ErrorsLib.AdapterAddress());

        if (assets == type(uint256).max) {
            assets = IERC20(marketParams.loanToken).balanceOf(address(this));
            require(assets != 0, ErrorsLib.ZeroAmount());
        }

        // Morpho's allowance is not reset as it is trusted.
        SafeERC20.forceApprove(IERC20(marketParams.loanToken), address(MORPHO), type(uint256).max);

        (uint256 suppliedAssets, uint256 suppliedShares) = MORPHO.supply(marketParams, assets, shares, onBehalf, data);

        require(suppliedAssets.rDivUp(suppliedShares) <= maxSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Supplies collateral on Morpho.
    /// @dev Collateral tokens must have been previously sent to the adapter.
    /// @param marketParams The Morpho market to supply collateral to.
    /// @param assets The amount of collateral to supply. Pass `type(uint).max` to supply the adapter's collateral
    /// balance.
    /// @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 morphoSupplyCollateral(
        MarketParams calldata marketParams,
        uint256 assets,
        address onBehalf,
        bytes calldata data
    ) external onlyBundler3 {
        // Do not check `onBehalf` against the zero address as it's done at Morpho's level.
        require(onBehalf != address(this), ErrorsLib.AdapterAddress());

        if (assets == type(uint256).max) assets = IERC20(marketParams.collateralToken).balanceOf(address(this));

        require(assets != 0, ErrorsLib.ZeroAmount());

        // Morpho's allowance is not reset as it is trusted.
        SafeERC20.forceApprove(IERC20(marketParams.collateralToken), address(MORPHO), type(uint256).max);

        MORPHO.supplyCollateral(marketParams, assets, onBehalf, data);
    }

    /// @notice Borrows assets on Morpho.
    /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the
    /// initiator is guaranteed to borrow `assets` tokens, but the possibility to mint a specific amount of shares is
    /// given for full compatibility and precision.
    /// @dev Initiator must have previously authorized the adapter to act on their behalf on Morpho.
    /// @param marketParams The Morpho market to borrow assets from.
    /// @param assets The amount of assets to borrow.
    /// @param shares The amount of shares to mint.
    /// @param minSharePriceE27 The minimum amount of assets borrowed per borrow share minted, scaled by 1e27.
    /// @param receiver The address that will receive the borrowed assets.
    function morphoBorrow(
        MarketParams calldata marketParams,
        uint256 assets,
        uint256 shares,
        uint256 minSharePriceE27,
        address receiver
    ) external onlyBundler3 {
        (uint256 borrowedAssets, uint256 borrowedShares) =
            MORPHO.borrow(marketParams, assets, shares, initiator(), receiver);

        require(borrowedAssets.rDivDown(borrowedShares) >= minSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Repays assets on Morpho.
    /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the
    /// adapter is guaranteed to have `assets` tokens pulled from its balance, but the possibility to burn a specific
    /// amount of shares is given for full compatibility and precision.
    /// @dev Loan tokens must have been previously sent to the adapter.
    /// @param marketParams The Morpho market to repay assets to.
    /// @param assets The amount of assets to repay. Pass `type(uint).max` to repay the adapter's loan asset balance.
    /// @param shares The amount of shares to burn. Pass `type(uint).max` to repay the initiator's entire debt.
    /// @param maxSharePriceE27 The maximum amount of assets repaid per borrow share burned, scaled by 1e27.
    /// @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.
    function morphoRepay(
        MarketParams calldata marketParams,
        uint256 assets,
        uint256 shares,
        uint256 maxSharePriceE27,
        address onBehalf,
        bytes calldata data
    ) external onlyBundler3 {
        // Do not check `onBehalf` against the zero address as it's done at Morpho's level.
        require(onBehalf != address(this), ErrorsLib.AdapterAddress());

        if (assets == type(uint256).max) {
            assets = IERC20(marketParams.loanToken).balanceOf(address(this));
            require(assets != 0, ErrorsLib.ZeroAmount());
        }

        if (shares == type(uint256).max) {
            shares = MorphoLib.borrowShares(MORPHO, marketParams.id(), onBehalf);
            require(shares != 0, ErrorsLib.ZeroAmount());
        }

        // Morpho's allowance is not reset as it is trusted.
        SafeERC20.forceApprove(IERC20(marketParams.loanToken), address(MORPHO), type(uint256).max);

        (uint256 repaidAssets, uint256 repaidShares) = MORPHO.repay(marketParams, assets, shares, onBehalf, data);

        require(repaidAssets.rDivUp(repaidShares) <= maxSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Withdraws assets on Morpho.
    /// @dev Either `assets` or `shares` should be zero. Most usecases should rely on `assets` as an input so the
    /// initiator is guaranteed to withdraw `assets` tokens, but the possibility to burn a specific amount of shares is
    /// given for full compatibility and precision.
    /// @dev Initiator must have previously authorized the maodule to act on their behalf on Morpho.
    /// @param marketParams The Morpho market to withdraw assets from.
    /// @param assets The amount of assets to withdraw.
    /// @param shares The amount of shares to burn. Pass `type(uint).max` to burn all the initiator's supply shares.
    /// @param minSharePriceE27 The minimum amount of assets withdraw per burn share, scaled by 1e27.
    /// @param receiver The address that will receive the withdrawn assets.
    function morphoWithdraw(
        MarketParams calldata marketParams,
        uint256 assets,
        uint256 shares,
        uint256 minSharePriceE27,
        address receiver
    ) external onlyBundler3 {
        if (shares == type(uint256).max) {
            shares = MorphoLib.supplyShares(MORPHO, marketParams.id(), initiator());
            require(shares != 0, ErrorsLib.ZeroAmount());
        }

        (uint256 withdrawnAssets, uint256 withdrawnShares) =
            MORPHO.withdraw(marketParams, assets, shares, initiator(), receiver);

        require(withdrawnAssets.rDivDown(withdrawnShares) >= minSharePriceE27, ErrorsLib.SlippageExceeded());
    }

    /// @notice Withdraws collateral from Morpho.
    /// @dev Initiator must have previously authorized the adapter to act on their behalf on Morpho.
    /// @param marketParams The Morpho market to withdraw collateral from.
    /// @param assets The amount of collateral to withdraw. Pass `type(uint).max` to withdraw the initiator's collateral
    /// balance.
    /// @param receiver The address that will receive the collateral assets.
    function morphoWithdrawCollateral(MarketParams calldata marketParams, uint256 assets, address receiver)
        external
        onlyBundler3
    {
        if (assets == type(uint256).max) assets = MorphoLib.collateral(MORPHO, marketParams.id(), initiator());
        require(assets != 0, ErrorsLib.ZeroAmount());

        MORPHO.withdrawCollateral(marketParams, assets, initiator(), receiver);
    }

    /// @notice Triggers a flash loan on Morpho.
    /// @param token The address of 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 morphoFlashLoan(address token, uint256 assets, bytes calldata data) external onlyBundler3 {
        require(assets != 0, ErrorsLib.ZeroAmount());
        // Morpho's allowance is not reset as it is trusted.
        SafeERC20.forceApprove(IERC20(token), address(MORPHO), type(uint256).max);

        MORPHO.flashLoan(token, assets, data);
    }

    /* PERMIT2 ACTIONS */

    /// @notice Transfers with Permit2.
    /// @param token The address of the ERC20 token to transfer.
    /// @param receiver The address that will receive the tokens.
    /// @param amount The amount of token to transfer. Pass `type(uint).max` to transfer the initiator's balance.
    function permit2TransferFrom(address token, address receiver, uint256 amount) external onlyBundler3 {
        require(receiver != address(0), ErrorsLib.ZeroAddress());

        address initiator = initiator();
        if (amount == type(uint256).max) amount = IERC20(token).balanceOf(initiator);

        require(amount != 0, ErrorsLib.ZeroAmount());

        Permit2Lib.PERMIT2.transferFrom(initiator, receiver, amount.toUint160(), token);
    }

    /* TRANSFER ACTIONS */

    /// @notice Transfers ERC20 tokens from the initiator.
    /// @notice Initiator must have given sufficient allowance to the Adapter to spend their tokens.
    /// @param token The address of the ERC20 token to transfer.
    /// @param receiver The address that will receive the tokens.
    /// @param amount The amount of token to transfer. Pass `type(uint).max` to transfer the initiator's balance.
    function erc20TransferFrom(address token, address receiver, uint256 amount) external onlyBundler3 {
        require(receiver != address(0), ErrorsLib.ZeroAddress());

        address initiator = initiator();
        if (amount == type(uint256).max) amount = IERC20(token).balanceOf(initiator);

        require(amount != 0, ErrorsLib.ZeroAmount());

        SafeERC20.safeTransferFrom(IERC20(token), initiator, receiver, amount);
    }

    /* WRAPPED NATIVE TOKEN ACTIONS */

    /// @notice Wraps native tokens to wNative.
    /// @dev Native tokens must have been previously sent to the adapter.
    /// @param amount The amount of native token to wrap. Pass `type(uint).max` to wrap the adapter's balance.
    /// @param receiver The account receiving the wrapped native tokens.
    function wrapNative(uint256 amount, address receiver) external onlyBundler3 {
        if (amount == type(uint256).max) amount = address(this).balance;

        require(amount != 0, ErrorsLib.ZeroAmount());

        WRAPPED_NATIVE.deposit{value: amount}();
        if (receiver != address(this)) SafeERC20.safeTransfer(IERC20(address(WRAPPED_NATIVE)), receiver, amount);
    }

    /// @notice Unwraps wNative tokens to the native token.
    /// @dev Wrapped native tokens must have been previously sent to the adapter.
    /// @param amount The amount of wrapped native token to unwrap. Pass `type(uint).max` to unwrap the adapter's
    /// balance.
    /// @param receiver The account receiving the native tokens.
    function unwrapNative(uint256 amount, address receiver) external onlyBundler3 {
        if (amount == type(uint256).max) amount = WRAPPED_NATIVE.balanceOf(address(this));

        require(amount != 0, ErrorsLib.ZeroAmount());

        WRAPPED_NATIVE.withdraw(amount);
        if (receiver != address(this)) Address.sendValue(payable(receiver), amount);
    }

    /* INTERNAL FUNCTIONS */

    /// @dev Triggers `_multicall` logic during a callback.
    function morphoCallback(bytes calldata data) internal {
        require(msg.sender == address(MORPHO), ErrorsLib.UnauthorizedSender());
        // No need to approve Morpho to pull tokens because it should already be approved max.

        reenterBundler3(data);
    }
}

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

interface IWNative {
    function deposit() external payable;
    function withdraw(uint256 wad) external;
    function approve(address guy, uint256 wad) external returns (bool);
    function transferFrom(address src, address dst, uint256 wad) external returns (bool);
    function transfer(address dst, uint256 wad) external returns (bool);
    function balanceOf(address guy) external returns (uint256);
}

File 3 of 33 : 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 ERC-4626 "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 4 of 33 : 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 33 : CoreAdapter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

import {ErrorsLib} from "../libraries/ErrorsLib.sol";
import {SafeERC20, IERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "../../lib/openzeppelin-contracts/contracts/utils/Address.sol";
import {IBundler3} from "../interfaces/IBundler3.sol";
import {UtilsLib} from "../libraries/UtilsLib.sol";

/// @custom:security-contact [email protected]
/// @notice Common contract to all Bundler3 adapters.
abstract contract CoreAdapter {
    /* IMMUTABLES */

    /// @notice The address of the Bundler3 contract.
    address public immutable BUNDLER3;

    /* CONSTRUCTOR */

    /// @param bundler3 The address of the Bundler3 contract.
    constructor(address bundler3) {
        require(bundler3 != address(0), ErrorsLib.ZeroAddress());

        BUNDLER3 = bundler3;
    }

    /* MODIFIERS */

    /// @dev Prevents a function from being called outside of a bundle context.
    /// @dev Ensures the value of initiator() is correct.
    modifier onlyBundler3() {
        require(msg.sender == BUNDLER3, ErrorsLib.UnauthorizedSender());
        _;
    }

    /* FALLBACKS */

    /// @notice Native tokens are received by the adapter and should be used afterwards.
    /// @dev Allows the wrapped native contract to transfer native tokens to the adapter.
    receive() external payable virtual {}

    /* ACTIONS */

    /// @notice Transfers native assets.
    /// @param receiver The address that will receive the native tokens.
    /// @param amount The amount of native tokens to transfer. Pass `type(uint).max` to transfer the adapter's balance
    /// (this allows 0 value transfers).
    function nativeTransfer(address receiver, uint256 amount) external onlyBundler3 {
        require(receiver != address(0), ErrorsLib.ZeroAddress());
        require(receiver != address(this), ErrorsLib.AdapterAddress());

        if (amount == type(uint256).max) amount = address(this).balance;
        else require(amount != 0, ErrorsLib.ZeroAmount());

        if (amount > 0) Address.sendValue(payable(receiver), amount);
    }

    /// @notice Transfers ERC20 tokens.
    /// @param token The address of the ERC20 token to transfer.
    /// @param receiver The address that will receive the tokens.
    /// @param amount The amount of token to transfer. Pass `type(uint).max` to transfer the adapter's balance (this
    /// allows 0 value transfers).
    function erc20Transfer(address token, address receiver, uint256 amount) external onlyBundler3 {
        require(receiver != address(0), ErrorsLib.ZeroAddress());
        require(receiver != address(this), ErrorsLib.AdapterAddress());

        if (amount == type(uint256).max) amount = IERC20(token).balanceOf(address(this));
        else require(amount != 0, ErrorsLib.ZeroAmount());

        if (amount > 0) SafeERC20.safeTransfer(IERC20(token), receiver, amount);
    }

    /* INTERNAL */

    /// @notice Returns the current initiator stored in the adapter.
    /// @dev The initiator value being non-zero indicates that a bundle is being processed.
    function initiator() internal view returns (address) {
        return IBundler3(BUNDLER3).initiator();
    }

    /// @notice Calls bundler3.reenter with an already encoded Call array.
    /// @dev Useful to skip an ABI decode-encode step when transmitting callback data.
    /// @param data An abi-encoded Call[].
    function reenterBundler3(bytes calldata data) internal {
        (bool success, bytes memory returnData) = BUNDLER3.call(bytes.concat(IBundler3.reenter.selector, data));
        if (!success) UtilsLib.lowLevelRevert(returnData);
    }
}

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

uint256 constant RAY = 1e27;

/// @custom:security-contact [email protected]
/// @notice Library to manage high-precision fixed-point arithmetic.
library MathRayLib {
    /// @dev Returns (`x` * `RAY`) / `y` rounded down.
    function rDivDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return (x * RAY) / y;
    }

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

File 7 of 33 : SafeCast160.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

library SafeCast160 {
    /// @notice Thrown when a valude greater than type(uint160).max is cast to uint160
    error UnsafeCast();

    /// @notice Safely casts uint256 to uint160
    /// @param value The uint256 to be cast
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) revert UnsafeCast();
        return uint160(value);
    }
}

File 8 of 33 : Permit2Lib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {ERC20} from "solmate/src/tokens/ERC20.sol";

import {IDAIPermit} from "../interfaces/IDAIPermit.sol";
import {IAllowanceTransfer} from "../interfaces/IAllowanceTransfer.sol";
import {SafeCast160} from "./SafeCast160.sol";

/// @title Permit2Lib
/// @notice Enables efficient transfers and EIP-2612/DAI
/// permits for any token by falling back to Permit2.
library Permit2Lib {
    using SafeCast160 for uint256;
    /*//////////////////////////////////////////////////////////////
                                CONSTANTS
    //////////////////////////////////////////////////////////////*/

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR = 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet, encoded as a bytes32.
    bytes32 internal constant WETH9_ADDRESS = 0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2;

    /// @dev The address of the Permit2 contract the library will use.
    IAllowanceTransfer internal constant PERMIT2 =
        IAllowanceTransfer(address(0x000000000022D473030F116dDEE9F6B43aC78BA3));

    /// @notice Transfer a given amount of tokens from one user to another.
    /// @param token The token to transfer.
    /// @param from The user to transfer from.
    /// @param to The user to transfer to.
    /// @param amount The amount to transfer.
    function transferFrom2(ERC20 token, address from, address to, uint256 amount) internal {
        // Generate calldata for a standard transferFrom call.
        bytes memory inputData = abi.encodeCall(ERC20.transferFrom, (from, to, amount));

        bool success; // Call the token contract as normal, capturing whether it succeeded.
        assembly {
            success :=
                and(
                    // Set success to whether the call reverted, if not we check it either
                    // returned exactly 1 (can't just be non-zero data), or had no return data.
                    or(eq(mload(0), 1), iszero(returndatasize())),
                    // Counterintuitively, this call() must be positioned after the or() in the
                    // surrounding and() because and() evaluates its arguments from right to left.
                    // We use 0 and 32 to copy up to 32 bytes of return data into the first slot of scratch space.
                    call(gas(), token, 0, add(inputData, 32), mload(inputData), 0, 32)
                )
        }

        // We'll fall back to using Permit2 if calling transferFrom on the token directly reverted.
        if (!success) PERMIT2.transferFrom(from, to, amount.toUint160(), address(token));
    }

    /*//////////////////////////////////////////////////////////////
                              PERMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    /// @param token The token to permit spending.
    /// @param owner The user to permit spending from.
    /// @param spender The user to permit spending to.
    /// @param amount The amount to permit spending.
    /// @param deadline  The timestamp after which the signature is no longer valid.
    /// @param v Must produce valid secp256k1 signature from the owner along with r and s.
    /// @param r Must produce valid secp256k1 signature from the owner along with v and s.
    /// @param s Must produce valid secp256k1 signature from the owner along with r and v.
    function permit2(
        ERC20 token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        // Generate calldata for a call to DOMAIN_SEPARATOR on the token.
        bytes memory inputData = abi.encodeWithSelector(ERC20.DOMAIN_SEPARATOR.selector);

        bool success; // Call the token contract as normal, capturing whether it succeeded.
        bytes32 domainSeparator; // If the call succeeded, we'll capture the return value here.

        assembly {
            // If the token is WETH9, we know it doesn't have a DOMAIN_SEPARATOR, and we'll skip this step.
            // We make sure to mask the token address as its higher order bits aren't guaranteed to be clean.
            if iszero(eq(and(token, 0xffffffffffffffffffffffffffffffffffffffff), WETH9_ADDRESS)) {
                success :=
                    and(
                        // Should resolve false if its not 32 bytes or its first word is 0.
                        and(iszero(iszero(mload(0))), eq(returndatasize(), 32)),
                        // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                        // Counterintuitively, this call must be positioned second to the and() call in the
                        // surrounding and() call or else returndatasize() will be zero during the computation.
                        // We send a maximum of 5000 gas to prevent tokens with fallbacks from using a ton of gas.
                        // which should be plenty to allow tokens to fetch their DOMAIN_SEPARATOR from storage, etc.
                        staticcall(5000, token, add(inputData, 32), mload(inputData), 0, 32)
                    )

                domainSeparator := mload(0) // Copy the return value into the domainSeparator variable.
            }
        }

        // If the call to DOMAIN_SEPARATOR succeeded, try using permit on the token.
        if (success) {
            // We'll use DAI's special permit if it's DOMAIN_SEPARATOR matches,
            // otherwise we'll just encode a call to the standard permit function.
            inputData = domainSeparator == DAI_DOMAIN_SEPARATOR
                ? abi.encodeCall(IDAIPermit.permit, (owner, spender, token.nonces(owner), deadline, true, v, r, s))
                : abi.encodeCall(ERC20.permit, (owner, spender, amount, deadline, v, r, s));

            assembly {
                success := call(gas(), token, 0, add(inputData, 32), mload(inputData), 0, 0)
            }
        }

        if (!success) {
            // If the initial DOMAIN_SEPARATOR call on the token failed or a
            // subsequent call to permit failed, fall back to using Permit2.
            simplePermit2(token, owner, spender, amount, deadline, v, r, s);
        }
    }

    /// @notice Simple unlimited permit on the Permit2 contract.
    /// @param token The token to permit spending.
    /// @param owner The user to permit spending from.
    /// @param spender The user to permit spending to.
    /// @param amount The amount to permit spending.
    /// @param deadline  The timestamp after which the signature is no longer valid.
    /// @param v Must produce valid secp256k1 signature from the owner along with r and s.
    /// @param r Must produce valid secp256k1 signature from the owner along with v and s.
    /// @param s Must produce valid secp256k1 signature from the owner along with r and v.
    function simplePermit2(
        ERC20 token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        (,, uint48 nonce) = PERMIT2.allowance(owner, address(token), spender);

        PERMIT2.permit(
            owner,
            IAllowanceTransfer.PermitSingle({
                details: IAllowanceTransfer.PermitDetails({
                    token: address(token),
                    amount: amount.toUint160(),
                    // Use an unlimited expiration because it most
                    // closely mimics how a standard approval works.
                    expiration: type(uint48).max,
                    nonce: nonce
                }),
                spender: spender,
                sigDeadline: deadline
            }),
            bytes.concat(r, s, bytes1(v))
        );
    }
}

File 9 of 33 : 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 33 : 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 11 of 33 : 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 12 of 33 : 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 ERC-20 standard as defined in the ERC.
 */
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 13 of 33 : 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 ERC-20 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 14 of 33 : ErrorsLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;

/// @custom:security-contact [email protected]
/// @notice Library exposing error messages.
library ErrorsLib {
    /* STANDARD ADAPTERS */

    /// @dev Thrown when a multicall is attempted while a bundle is already initiated.
    error AlreadyInitiated();

    /// @dev Thrown when a call is attempted from an unauthorized sender.
    error UnauthorizedSender();

    /// @dev Thrown when a reenter is attempted but the concatenation of the sender and bundle does not hash to the
    /// pre-recorded `reenterHash`.
    error IncorrectReenterHash();

    /// @dev Thrown when a multicall is attempted with an empty bundle.
    error EmptyBundle();

    /// @dev Thrown when a reenter was expected but did not happen.
    error MissingExpectedReenter();

    /// @dev Thrown when a call is attempted with a zero address as input.
    error ZeroAddress();

    /// @dev Thrown when a call is attempted with the adapter address as input.
    error AdapterAddress();

    /// @dev Thrown when a call is attempted with a zero amount as input.
    error ZeroAmount();

    /// @dev Thrown when a call is attempted with a zero shares as input.
    error ZeroShares();

    /// @dev Thrown when the given owner is unexpected.
    error UnexpectedOwner();

    /// @dev Thrown when an action ends up minting/burning more shares than a given slippage.
    error SlippageExceeded();

    /// @dev Thrown when a call to depositFor fails.
    error DepositFailed();

    /// @dev Thrown when a call to withdrawTo fails.
    error WithdrawFailed();

    /* MIGRATION ADAPTERS */

    /// @dev Thrown when repaying a CompoundV2 debt returns an error code.
    error RepayError();

    /// @dev Thrown when redeeming CompoundV2 cTokens returns an error code.
    error RedeemError();

    /// @dev Thrown when trying to repay ETH on CompoundV2 with the wrong function.
    error CTokenIsCETH();

    /* PARASWAP ADAPTER */

    /// @dev Thrown when the contract used to trade is not deemed valid by Paraswap's Augustus registry.
    error InvalidAugustus();

    /// @dev Thrown when a data offset is invalid.
    error InvalidOffset();

    /// @dev Thrown when a swap has spent too many source tokens.
    error SellAmountTooHigh();

    /// @dev Thrown when a swap has not bought enough destination tokens.
    error BuyAmountTooLow();
}

File 15 of 33 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

File 16 of 33 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert Errors.FailedCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

File 17 of 33 : IBundler3.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

/// @notice Struct containing all the data needed to make a call.
/// @notice The call target is `to`, the calldata is `data` with value `value`.
/// @notice If `skipRevert` is true, other planned calls will continue executing even if this call reverts. `skipRevert`
/// will ignore all reverts. Use with caution.
/// @notice If the call will trigger a reenter, the callbackHash should be set to the hash of the reenter bundle data.
struct Call {
    address to;
    bytes data;
    uint256 value;
    bool skipRevert;
    bytes32 callbackHash;
}

/// @custom:security-contact [email protected]
interface IBundler3 {
    function multicall(Call[] calldata) external payable;
    function reenter(Call[] calldata) external;
    function reenterHash() external view returns (bytes32);
    function initiator() external view returns (address);
}

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

import {SafeERC20, IERC20} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

/// @custom:security-contact [email protected]
/// @notice Utils library.
library UtilsLib {
    /// @dev Bubbles up the revert reason / custom error encoded in `returnData`.
    /// @dev Assumes `returnData` is the return data of any kind of failing CALL to a contract.
    function lowLevelRevert(bytes memory returnData) internal pure {
        assembly ("memory-safe") {
            revert(add(32, returnData), mload(returnData))
        }
    }
}

File 19 of 33 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 20 of 33 : IDAIPermit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IDAIPermit {
    /// @param holder The address of the token owner.
    /// @param spender The address of the token spender.
    /// @param nonce The owner's nonce, increases at each call to permit.
    /// @param expiry The timestamp at which the permit is no longer valid.
    /// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0.
    /// @param v Must produce valid secp256k1 signature from the owner along with r and s.
    /// @param r Must produce valid secp256k1 signature from the owner along with v and s.
    /// @param s Must produce valid secp256k1 signature from the owner along with r and v.
    function permit(
        address holder,
        address spender,
        uint256 nonce,
        uint256 expiry,
        bool allowed,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 21 of 33 : IAllowanceTransfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

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

/// @title AllowanceTransfer
/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 contract
interface IAllowanceTransfer is IEIP712 {
    /// @notice Thrown when an allowance on a token has expired.
    /// @param deadline The timestamp at which the allowed amount is no longer valid
    error AllowanceExpired(uint256 deadline);

    /// @notice Thrown when an allowance on a token has been depleted.
    /// @param amount The maximum amount allowed
    error InsufficientAllowance(uint256 amount);

    /// @notice Thrown when too many nonces are invalidated.
    error ExcessiveInvalidation();

    /// @notice Emits an event when the owner successfully invalidates an ordered nonce.
    event NonceInvalidation(
        address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce
    );

    /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.
    event Approval(
        address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration
    );

    /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.
    event Permit(
        address indexed owner,
        address indexed token,
        address indexed spender,
        uint160 amount,
        uint48 expiration,
        uint48 nonce
    );

    /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.
    event Lockdown(address indexed owner, address token, address spender);

    /// @notice The permit data for a token
    struct PermitDetails {
        // ERC20 token address
        address token;
        // the maximum amount allowed to spend
        uint160 amount;
        // timestamp at which a spender's token allowances become invalid
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice The permit message signed for a single token allownce
    struct PermitSingle {
        // the permit data for a single token alownce
        PermitDetails details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The permit message signed for multiple token allowances
    struct PermitBatch {
        // the permit data for multiple token allowances
        PermitDetails[] details;
        // address permissioned on the allowed tokens
        address spender;
        // deadline on the permit signature
        uint256 sigDeadline;
    }

    /// @notice The saved permissions
    /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    struct PackedAllowance {
        // amount allowed
        uint160 amount;
        // permission expiry
        uint48 expiration;
        // an incrementing value indexed per owner,token,and spender for each signature
        uint48 nonce;
    }

    /// @notice A token spender pair.
    struct TokenSpenderPair {
        // the token the spender is approved
        address token;
        // the spender address
        address spender;
    }

    /// @notice Details for a token transfer.
    struct AllowanceTransferDetails {
        // the owner of the token
        address from;
        // the recipient of the token
        address to;
        // the amount of the token
        uint160 amount;
        // the token to be transferred
        address token;
    }

    /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.
    /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]
    /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.
    function allowance(address user, address token, address spender)
        external
        view
        returns (uint160 amount, uint48 expiration, uint48 nonce);

    /// @notice Approves the spender to use up to amount of the specified token up until the expiration
    /// @param token The token to approve
    /// @param spender The spender address to approve
    /// @param amount The approved amount of the token
    /// @param expiration The timestamp at which the approval is no longer valid
    /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve
    /// @dev Setting amount to type(uint160).max sets an unlimited approval
    function approve(address token, address spender, uint160 amount, uint48 expiration) external;

    /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitSingle Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;

    /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature
    /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce
    /// @param owner The owner of the tokens being approved
    /// @param permitBatch Data signed over by the owner specifying the terms of approval
    /// @param signature The owner's signature over the permit data
    function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;

    /// @notice Transfer approved tokens from one address to another
    /// @param from The address to transfer from
    /// @param to The address of the recipient
    /// @param amount The amount of the token to transfer
    /// @param token The token address to transfer
    /// @dev Requires the from address to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(address from, address to, uint160 amount, address token) external;

    /// @notice Transfer approved tokens in a batch
    /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers
    /// @dev Requires the from addresses to have approved at least the desired amount
    /// of tokens to msg.sender.
    function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;

    /// @notice Enables performing a "lockdown" of the sender's Permit2 identity
    /// by batch revoking approvals
    /// @param approvals Array of approvals to revoke.
    function lockdown(TokenSpenderPair[] calldata approvals) external;

    /// @notice Invalidate nonces for a given (token, spender) pair
    /// @param token The token to invalidate nonces for
    /// @param spender The spender to invalidate nonces for
    /// @param newNonce The new nonce to set. Invalidates all nonces less than it.
    /// @dev Can't invalidate more than 2**16 nonces per transaction.
    function invalidateNonces(address token, address spender, uint48 newNonce) external;
}

File 22 of 33 : 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 23 of 33 : 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 24 of 33 : 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 25 of 33 : 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 26 of 33 : 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);
    }
}

File 27 of 33 : IERC1363.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

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

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 28 of 33 : Errors.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

File 29 of 33 : IEIP712.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IEIP712 {
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 30 of 33 : 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 31 of 33 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

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

File 32 of 33 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 33 of 33 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"bundler3","type":"address"},{"internalType":"address","name":"morpho","type":"address"},{"internalType":"address","name":"wNative","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdapterAddress","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"UnauthorizedSender","type":"error"},{"inputs":[],"name":"UnexpectedOwner","type":"error"},{"inputs":[],"name":"UnsafeCast","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroShares","type":"error"},{"inputs":[],"name":"BUNDLER3","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MORPHO","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WRAPPED_NATIVE","outputs":[{"internalType":"contract IWNative","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"erc20Transfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"erc20TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"maxSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"erc4626Deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"maxSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"erc4626Mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"minSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"erc4626Redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"minSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"erc4626Withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"minSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"morphoBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"morphoFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"maxSharePriceE27","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"morphoRepay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"maxSharePriceE27","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"morphoSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"onBehalf","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"morphoSupplyCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"minSharePriceE27","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"morphoWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"morphoWithdrawCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"nativeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoRepay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoSupplyCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"permit2TransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"unwrapNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"wrapNative","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e0346101b257601f6137e538819003918201601f19168301916001600160401b038311848410176101b6578084926060946040528339810103126101b257610047816101ca565b906100606040610059602084016101ca565b92016101ca565b916001600160a01b038116156101a3576080526001600160a01b03169081156101a3576001600160a01b03169081156101a35760a05260c05260405161360690816101df823960805181818161017f015281816103290152818161052901528181610798015281816109c301528181610c4201528181610e50015281816111270152818161117501528181611456015281816116b40152818161197b01528181611a1101528181611cae0152818161203201528181612214015281816123ec0152818161255c015281816128ef0152612fe4015260a05181818161038701528181610847015281816112200152818161138f01528181611abf01528181611d8501528181611e2001528181611fe4015281816125c7015281816127570152612855015260c0518181816104dd01528181610cae01528181610dae01526124570152f35b63d92e233d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101b25756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f5f3560e01c806305b4591c14610e225780631af3bbc6146125025780632075be0314610e2257806331f5707214610e225780633244c12c146123995780633790767d146121ed57806339029ab6146120085780633acb562414611f995780634d5fcf6814611c815780635b866db6146119e457806362577ad01461194f5780636ef5eeae1461168b578063827fcfcc1461142c57806384d287ef1461114b578063a317e4b5146110dc578063a7f6e60614610e27578063b1022fdf14610e22578063b172af6d14610bf0578063c95657061461099a578063ca4636731461071b578063d96ca0b914610501578063d999984d14610492578063e2975912146102b55763f2522bcd1461012d575061000e565b346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b25761016461296e565b6024359073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361028a5773ffffffffffffffffffffffffffffffffffffffff16908082156102625730831461023a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810361020d575050475b806101fe578280f35b61020791613486565b5f808280f35b6101f5575b6004837f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004847fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b6004847fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004837f08094908000000000000000000000000000000000000000000000000000000008152fd5b80fd5b50346102b25760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b2576102ed61296e565b60243560443567ffffffffffffffff811161048e576103109036906004016127c1565b909273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361046657821561043e579073ffffffffffffffffffffffffffffffffffffffff859392169173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906103b28285613192565b813b1561043a57848094610407604051988996879586947fe0232b4200000000000000000000000000000000000000000000000000000000865260048601526024850152606060448501526064840191612ed1565b03925af1801561042d576104185780f35b61042191612c68565b805f126102b2575f8180f35b50604051903d90823e3d90fd5b8480fd5b6004857f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004857f08094908000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102b257610510366129b2565b919073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036106f35773ffffffffffffffffffffffffffffffffffffffff83911680156106cb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610596612fa1565b9414610612575b811561043e579173ffffffffffffffffffffffffffffffffffffffff9161060f949383604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601526044850152606484015260648352610609608484612c68565b16613572565b80f35b90506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa9081156106c057859161068a575b509061059d565b90506020813d6020116106b8575b816106a560209383612c68565b810103126106b457515f610683565b5f80fd5b3d9150610698565b6040513d87823e3d90fd5b6004857fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004847f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b2577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161010081126109965760a0136102b25760a43561075f612928565b60e43567ffffffffffffffff811161048e5761077f9036906004016127c1565b909273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610466579173ffffffffffffffffffffffffffffffffffffffff168230821461096e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146108d1575b821561043e579084929173ffffffffffffffffffffffffffffffffffffffff61082b612e77565b169061086e73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168093613192565b813b1561043a57848094610407604051988996879586947f238d65790000000000000000000000000000000000000000000000000000000086526108b460048701612d0b565b60a486015260c485015261010060e4850152610104840191612ed1565b91506024602073ffffffffffffffffffffffffffffffffffffffff6108f4612e77565b16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156106c057859161093c575b5091610804565b90506020813d602011610966575b8161095760209383612c68565b810103126106b457515f610935565b3d915061094a565b6004867fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b5080fd5b50346102b2576109a936612b88565b91939073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610bc85773ffffffffffffffffffffffffffffffffffffffff811615610ba05773ffffffffffffffffffffffffffffffffffffffff8316308114908115610b79575b5015610b51578315610b29576040517fb460af940000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff91821660248201529281166044840152919291602091849160649183918991165af1918215610b1e578492610ae8575b5090610ab3610ab892613311565b61336a565b10610ac05780f35b807f8199f5f30000000000000000000000000000000000000000000000000000000060049252fd5b91506020823d602011610b16575b81610b0360209383612c68565b810103126106b457905190610ab3610aa5565b3d9150610af6565b6040513d86823e3d90fd5b6004867f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004867fd459cda8000000000000000000000000000000000000000000000000000000008152fd5b905073ffffffffffffffffffffffffffffffffffffffff610b98612fa1565b16145f610a27565b6004867fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004867f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257600435610c2b61294b565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361028a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214610d62575b8115610212578273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b15610996578180916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015610d5757610d3b575b505073ffffffffffffffffffffffffffffffffffffffff16903082036101fe578280f35b90610d4591612c68565b825f12610d5357825f610d17565b8280fd5b6040513d84823e3d90fd5b90506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020816024818673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1908115610e17578391610de5575b5090610c90565b90506020813d602011610e0f575b81610e0060209383612c68565b810103126106b457515f610dde565b3d9150610df3565b6040513d85823e3d90fd5b6127ef565b50346102b257610e3636612b88565b91939073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610bc8578373ffffffffffffffffffffffffffffffffffffffff8216156110b45773ffffffffffffffffffffffffffffffffffffffff841690308214801561108e575b15611066577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610fc5575b508315610f9d576040517fba0876520000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff91821660248201529281166044840152919291602091849160649183918991165af1918215610b1e578492610f67575b50610ab3610ab892613311565b91506020823d602011610f95575b81610f8260209383612c68565b810103126106b457905190610ab3610f5a565b3d9150610f75565b6004867f9811e0c7000000000000000000000000000000000000000000000000000000008152fd5b909350604051907f70a08231000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa90811561105b578691611029575b50925f610ee1565b90506020813d602011611053575b8161104460209383612c68565b810103126106b457515f611021565b3d9150611037565b6040513d88823e3d90fd5b6004887fd459cda8000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff6110ac612fa1565b168214610eb5565b6004877fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102b25761115a36612b23565b73ffffffffffffffffffffffffffffffffffffffff949391947f0000000000000000000000000000000000000000000000000000000000000000163303610bc8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8314611293575b92611206604093946111d3612fa1565b855196879586957f5c2bea4900000000000000000000000000000000000000000000000000000000875260048701612f5a565b03818673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af18015610e1757610ab8918490859261125f575b50610ab390613311565b610ab39250611286915060403d60401161128c575b61127e8183612c68565b810190612ebb565b91611255565b503d611274565b91506113765f61134360a06112a83688612ca9565b2061130f61133b6112b7612fa1565b926040516020810191825260026040820152604081526112d8606082612c68565b5190206040519283916020830195866020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c68565b51902061354b565b604051809381927f7784c685000000000000000000000000000000000000000000000000000000008352600483016130b6565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa8015611421576113c8915f916113ff575b506130ef565b519283156113d75792916111c3565b7f1f2a2005000000000000000000000000000000000000000000000000000000005f5260045ffd5b61141b91503d805f833e6114138183612c68565b810190613030565b5f6113c2565b6040513d5f823e3d90fd5b50346102b25761143b366129b2565b9073ffffffffffffffffffffffffffffffffffffffff9392937f000000000000000000000000000000000000000000000000000000000000000016330361028a5773ffffffffffffffffffffffffffffffffffffffff829116938415610262577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6114c4612fa1565b93146115e1575b81156115b95773ffffffffffffffffffffffffffffffffffffffff82116115915783946e22d473030f116ddee9f6b43ac78ba33b1561043a5773ffffffffffffffffffffffffffffffffffffffff92839182604051967f36c7851600000000000000000000000000000000000000000000000000000000885216600487015260248601521660448401521660648201528181608481836e22d473030f116ddee9f6b43ac78ba35af18015610d57576115805750f35b8161158a91612c68565b6102b25780f35b6004847fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b6004847f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b90506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa908115610b1e578491611659575b50906114cb565b90506020813d602011611683575b8161167460209383612c68565b810103126106b457515f611652565b3d9150611667565b50346102b25761169a36612a24565b90929173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361046657809173ffffffffffffffffffffffffffffffffffffffff811615610ba05773ffffffffffffffffffffffffffffffffffffffff8416906040517f38d52e0f000000000000000000000000000000000000000000000000000000008152602081600481865afa908115611944577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff918a91611915575b5016931461188c575b83156118645761180183926020926117a8888b9897613192565b6040519687809481937f6e553f65000000000000000000000000000000000000000000000000000000008352896004840190929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b03925af192831561105b57869361182e575b5061182693611821916132b1565b6133a1565b11610ac05780f35b9092506020813d60201161185c575b8161184a60209383612c68565b810103126106b4575191611826611813565b3d915061183d565b6004877f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b92506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa90811561190a5787916118d8575b509261178e565b90506020813d602011611902575b816118f360209383612c68565b810103126106b457515f6118d1565b3d91506118e6565b6040513d89823e3d90fd5b611937915060203d60201161193d575b61192f8183612c68565b810190612e4b565b5f611785565b503d611925565b6040513d8a823e3d90fd5b50346102b25761195e36612b23565b73ffffffffffffffffffffffffffffffffffffffff9491949392937f0000000000000000000000000000000000000000000000000000000000000000163303610bc85790611206604093926119b1612fa1565b855196879586957f50d8cd4b00000000000000000000000000000000000000000000000000000000875260048701612f5a565b50346102b2576119f336612a9a565b93929573ffffffffffffffffffffffffffffffffffffffff959192957f0000000000000000000000000000000000000000000000000000000000000000163303611c5957813073ffffffffffffffffffffffffffffffffffffffff881614611c3157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff899214611b5a575b611b1b60409673ffffffffffffffffffffffffffffffffffffffff611aa384612e9a565b1695611ae673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168098613192565b8851998a98899788967fa99aad8900000000000000000000000000000000000000000000000000000000885260048801612f0f565b03925af18015610e17576118269184908592611b38575b506133a1565b9050611b53915060403d60401161128c5761127e8183612c68565b905f611b32565b9150506024919293602073ffffffffffffffffffffffffffffffffffffffff611b8284612e9a565b16604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315611944578893611bfd575b508215611bd557939291908790611a7f565b6004887f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011611c29575b81611c1960209383612c68565b810103126106b45751915f611bc3565b3d9150611c0c565b6004897fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b6004887f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b257611c9036612a9a565b93929573ffffffffffffffffffffffffffffffffffffffff959192957f0000000000000000000000000000000000000000000000000000000000000000163303611c595783823073ffffffffffffffffffffffffffffffffffffffff891614611f7157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a939214611e93575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611de1575b611b1b60409673ffffffffffffffffffffffffffffffffffffffff611d6984612e9a565b1695611dac73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168098613192565b8851998a98899788967f20b76e8100000000000000000000000000000000000000000000000000000000885260048801612f0f565b91929350611e0790611343611e028860a0611dfc3688612ca9565b20613513565b61354b565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611944576fffffffffffffffffffffffffffffffff91611e6b918a91611e7f57506130ef565b5116938415611bd557939291908790611d45565b61141b91503d808c833e6114138183612c68565b90915060249250602073ffffffffffffffffffffffffffffffffffffffff611eba84612e9a565b16604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315611f66578993611f32575b508215611f0a57908891611d1e565b6004897f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011611f5e575b81611f4e60209383612c68565b810103126106b45751915f611efb565b3d9150611f41565b6040513d8b823e3d90fd5b60048a7fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346102b25761201736612a24565b73ffffffffffffffffffffffffffffffffffffffff939291937f00000000000000000000000000000000000000000000000000000000000000001633036104665773ffffffffffffffffffffffffffffffffffffffff8116156106cb5781156121c557849073ffffffffffffffffffffffffffffffffffffffff8416604051907f38d52e0f000000000000000000000000000000000000000000000000000000008252602082600481845afa908115610b1e5773ffffffffffffffffffffffffffffffffffffffff6121539260209487916121a8575b5016936120fa8886613192565b6040519586809481937f94bf804d0000000000000000000000000000000000000000000000000000000083528a6004840190929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b03925af191821561105b578692612172575061182693611821916132b1565b9091506020813d6020116121a0575b8161218e60209383612c68565b810103126106b4575190611826611813565b3d9150612181565b6121bf9150853d871161193d5761192f8183612c68565b5f6120ed565b6004857f9811e0c7000000000000000000000000000000000000000000000000000000008152fd5b50346102b2576121fc366129b2565b9073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036106f3578173ffffffffffffffffffffffffffffffffffffffff82168015610ba0573014612371577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103612345575090506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa908115610b1e578491612313575b50905b816122ed578380f35b73ffffffffffffffffffffffffffffffffffffffff61230c9316613129565b5f80808380f35b90506020813d60201161233d575b8161232e60209383612c68565b810103126106b457515f6122e1565b3d9150612321565b6122e4576004847f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004857fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b50346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b2576004356123d461294b565b9073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361028a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146124fb575b80156102125773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b1561048e57836040517fd0e30db0000000000000000000000000000000000000000000000000000000008152818160048187895af18015610d57576124e6575b50503073ffffffffffffffffffffffffffffffffffffffff8216036124dd578380f35b61230c92613129565b816124f091612c68565b61048e57835f6124ba565b504761243a565b50346106b4577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360160e081126106b45760a0136106b45760a435612545612928565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303612799577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214612679575b81156113d75773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166125ef612fa1565b90803b156106b45773ffffffffffffffffffffffffffffffffffffffff935f6101049286829660405198899788967f8720316d00000000000000000000000000000000000000000000000000000000885261264c60048901612d0b565b60a48801521660c48601521660e48401525af180156114215761266d575080f35b61001891505f90612c68565b905060405161268781612c1f565b60043573ffffffffffffffffffffffffffffffffffffffff811681036106b457815260243573ffffffffffffffffffffffffffffffffffffffff811681036106b457602082015260443573ffffffffffffffffffffffffffffffffffffffff811681036106b45760408201526064359073ffffffffffffffffffffffffffffffffffffffff821682036106b457611343611e0260a08361273e9560605f960152608435608082015220612738612fa1565b90613513565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa80156114215761278f915f916113ff57506130ef565b5160801c906125aa565b7f08094908000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f840112156106b45782359167ffffffffffffffff83116106b457602083818601950101116106b457565b346106b45760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b45760243567ffffffffffffffff81116106b45761283e9036906004016127c1565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303612799575f9182916128ea602460405183819460208301967f803a7fba000000000000000000000000000000000000000000000000000000008852848401378101868382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c68565b5190827f00000000000000000000000000000000000000000000000000000000000000005af1612918613429565b901561292057005b805190602001fd5b60c4359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060243573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060443590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790602435906044359060643573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820161014081126106b45760a0136106b45760049160a4359160c4359160e435916101043573ffffffffffffffffffffffffffffffffffffffff811681036106b45791610124359067ffffffffffffffff82116106b457612b1f916004016127c1565b9091565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0161012081126106b45760a0136106b45760049060a4359060c4359060e435906101043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790602435906044359060643573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060843573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b60a0810190811067ffffffffffffffff821117612c3b57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612c3b57604052565b91908260a09103126106b457604051612cc181612c1f565b6080808294612ccf81612991565b8452612cdd60208201612991565b6020850152612cee60408201612991565b6040850152612cff60608201612991565b60608501520135910152565b60043573ffffffffffffffffffffffffffffffffffffffff81168091036106b457815260243573ffffffffffffffffffffffffffffffffffffffff81168091036106b457602082015260443573ffffffffffffffffffffffffffffffffffffffff81168091036106b457604082015260643573ffffffffffffffffffffffffffffffffffffffff81168091036106b45760608201526080608435910152565b6080809173ffffffffffffffffffffffffffffffffffffffff612dcc82612991565b16845273ffffffffffffffffffffffffffffffffffffffff612df060208301612991565b16602085015273ffffffffffffffffffffffffffffffffffffffff612e1760408301612991565b16604085015273ffffffffffffffffffffffffffffffffffffffff612e3e60608301612991565b1660608501520135910152565b908160209103126106b4575173ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b60243573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b3573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b91908260409103126106b4576020825192015190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b919361012093612f579795612f398573ffffffffffffffffffffffffffffffffffffffff95612daa565b60a085015260c08401521660e0820152816101008201520191612ed1565b90565b9373ffffffffffffffffffffffffffffffffffffffff929061010094849298979398612f8b8861012081019b612daa565b60a088015260c08701521660e085015216910152565b6040517f5c39fcc100000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115611421575f91613017575090565b612f57915060203d60201161193d5761192f8183612c68565b6020818303126106b45780519067ffffffffffffffff82116106b457019080601f830112156106b45781519167ffffffffffffffff8311612c3b578260051b9060208201936130826040519586612c68565b84526020808501928201019283116106b457602001905b8282106130a65750505090565b8151815260209182019101613099565b60206040818301928281528451809452019201905f5b8181106130d95750505090565b82518452602093840193909201916001016130cc565b8051156130fc5760200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044808301939093529181526131909161318b606483612c68565b613572565b565b6040519060205f73ffffffffffffffffffffffffffffffffffffffff828501957f095ea7b300000000000000000000000000000000000000000000000000000000875216948560248601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604486015260448552613212606486612c68565b84519082855af15f513d8261327f575b50501561322e57505050565b61318b61319093604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152613279606482612c68565b82613572565b9091506132a9575073ffffffffffffffffffffffffffffffffffffffff81163b15155b5f80613222565b6001146132a2565b6040519060205f73ffffffffffffffffffffffffffffffffffffffff828501957f095ea7b3000000000000000000000000000000000000000000000000000000008752169485602486015281604486015260448552613212606486612c68565b906b033b2e3c9fd0803ce80000008202918083046b033b2e3c9fd0803ce8000000149015171561333d57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8115613374570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b906b033b2e3c9fd0803ce80000008202918083046b033b2e3c9fd0803ce8000000149015171561333d57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161333d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183010180921161333d57612f579161336a565b3d15613481573d9067ffffffffffffffff8211612c3b576040519161347660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184612c68565b82523d5f602084013e565b606090565b8147106134e3575f80809373ffffffffffffffffffffffffffffffffffffffff8294165af16134b3613429565b50156134bb57565b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b50477fcf479181000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b61353a61130f916040516020810191825260026040820152604081526112d8606082612c68565b5190206001810180911161333d5790565b6040519061355a604083612c68565b600182526020368184013761356e826130ef565b5290565b905f602091828151910182855af115611421575f513d6135f0575073ffffffffffffffffffffffffffffffffffffffff81163b155b6135ae5750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b600114156135a756fea164736f6c634300081c000a0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af4320000000000000000000000004200000000000000000000000000000000000006

Deployed Bytecode

0x6080604052600436101561001a575b3615610018575f80fd5b005b5f5f3560e01c806305b4591c14610e225780631af3bbc6146125025780632075be0314610e2257806331f5707214610e225780633244c12c146123995780633790767d146121ed57806339029ab6146120085780633acb562414611f995780634d5fcf6814611c815780635b866db6146119e457806362577ad01461194f5780636ef5eeae1461168b578063827fcfcc1461142c57806384d287ef1461114b578063a317e4b5146110dc578063a7f6e60614610e27578063b1022fdf14610e22578063b172af6d14610bf0578063c95657061461099a578063ca4636731461071b578063d96ca0b914610501578063d999984d14610492578063e2975912146102b55763f2522bcd1461012d575061000e565b346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b25761016461296e565b6024359073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361028a5773ffffffffffffffffffffffffffffffffffffffff16908082156102625730831461023a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810361020d575050475b806101fe578280f35b61020791613486565b5f808280f35b6101f5575b6004837f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004847fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b6004847fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004837f08094908000000000000000000000000000000000000000000000000000000008152fd5b80fd5b50346102b25760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b2576102ed61296e565b60243560443567ffffffffffffffff811161048e576103109036906004016127c1565b909273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361046657821561043e579073ffffffffffffffffffffffffffffffffffffffff859392169173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af43216906103b28285613192565b813b1561043a57848094610407604051988996879586947fe0232b4200000000000000000000000000000000000000000000000000000000865260048601526024850152606060448501526064840191612ed1565b03925af1801561042d576104185780f35b61042191612c68565b805f126102b2575f8180f35b50604051903d90823e3d90fd5b8480fd5b6004857f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004857f08094908000000000000000000000000000000000000000000000000000000008152fd5b8380fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004200000000000000000000000000000000000006168152f35b50346102b257610510366129b2565b919073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a4481633036106f35773ffffffffffffffffffffffffffffffffffffffff83911680156106cb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610596612fa1565b9414610612575b811561043e579173ffffffffffffffffffffffffffffffffffffffff9161060f949383604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601526044850152606484015260648352610609608484612c68565b16613572565b80f35b90506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa9081156106c057859161068a575b509061059d565b90506020813d6020116106b8575b816106a560209383612c68565b810103126106b457515f610683565b5f80fd5b3d9150610698565b6040513d87823e3d90fd5b6004857fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004847f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b2577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161010081126109965760a0136102b25760a43561075f612928565b60e43567ffffffffffffffff811161048e5761077f9036906004016127c1565b909273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303610466579173ffffffffffffffffffffffffffffffffffffffff168230821461096e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146108d1575b821561043e579084929173ffffffffffffffffffffffffffffffffffffffff61082b612e77565b169061086e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432168093613192565b813b1561043a57848094610407604051988996879586947f238d65790000000000000000000000000000000000000000000000000000000086526108b460048701612d0b565b60a486015260c485015261010060e4850152610104840191612ed1565b91506024602073ffffffffffffffffffffffffffffffffffffffff6108f4612e77565b16604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156106c057859161093c575b5091610804565b90506020813d602011610966575b8161095760209383612c68565b810103126106b457515f610935565b3d915061094a565b6004867fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b5080fd5b50346102b2576109a936612b88565b91939073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303610bc85773ffffffffffffffffffffffffffffffffffffffff811615610ba05773ffffffffffffffffffffffffffffffffffffffff8316308114908115610b79575b5015610b51578315610b29576040517fb460af940000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff91821660248201529281166044840152919291602091849160649183918991165af1918215610b1e578492610ae8575b5090610ab3610ab892613311565b61336a565b10610ac05780f35b807f8199f5f30000000000000000000000000000000000000000000000000000000060049252fd5b91506020823d602011610b16575b81610b0360209383612c68565b810103126106b457905190610ab3610aa5565b3d9150610af6565b6040513d86823e3d90fd5b6004867f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004867fd459cda8000000000000000000000000000000000000000000000000000000008152fd5b905073ffffffffffffffffffffffffffffffffffffffff610b98612fa1565b16145f610a27565b6004867fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b6004867f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257600435610c2b61294b565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361028a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214610d62575b8115610212578273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000420000000000000000000000000000000000000616803b15610996578180916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528960048401525af18015610d5757610d3b575b505073ffffffffffffffffffffffffffffffffffffffff16903082036101fe578280f35b90610d4591612c68565b825f12610d5357825f610d17565b8280fd5b6040513d84823e3d90fd5b90506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526020816024818673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004200000000000000000000000000000000000006165af1908115610e17578391610de5575b5090610c90565b90506020813d602011610e0f575b81610e0060209383612c68565b810103126106b457515f610dde565b3d9150610df3565b6040513d85823e3d90fd5b6127ef565b50346102b257610e3636612b88565b91939073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303610bc8578373ffffffffffffffffffffffffffffffffffffffff8216156110b45773ffffffffffffffffffffffffffffffffffffffff841690308214801561108e575b15611066577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14610fc5575b508315610f9d576040517fba0876520000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff91821660248201529281166044840152919291602091849160649183918991165af1918215610b1e578492610f67575b50610ab3610ab892613311565b91506020823d602011610f95575b81610f8260209383612c68565b810103126106b457905190610ab3610f5a565b3d9150610f75565b6004867f9811e0c7000000000000000000000000000000000000000000000000000000008152fd5b909350604051907f70a08231000000000000000000000000000000000000000000000000000000008252600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa90811561105b578691611029575b50925f610ee1565b90506020813d602011611053575b8161104460209383612c68565b810103126106b457515f611021565b3d9150611037565b6040513d88823e3d90fd5b6004887fd459cda8000000000000000000000000000000000000000000000000000000008152fd5b5073ffffffffffffffffffffffffffffffffffffffff6110ac612fa1565b168214610eb5565b6004877fd92e233d000000000000000000000000000000000000000000000000000000008152fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448168152f35b50346102b25761115a36612b23565b73ffffffffffffffffffffffffffffffffffffffff949391947f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303610bc8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8314611293575b92611206604093946111d3612fa1565b855196879586957f5c2bea4900000000000000000000000000000000000000000000000000000000875260048701612f5a565b03818673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432165af18015610e1757610ab8918490859261125f575b50610ab390613311565b610ab39250611286915060403d60401161128c575b61127e8183612c68565b810190612ebb565b91611255565b503d611274565b91506113765f61134360a06112a83688612ca9565b2061130f61133b6112b7612fa1565b926040516020810191825260026040820152604081526112d8606082612c68565b5190206040519283916020830195866020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c68565b51902061354b565b604051809381927f7784c685000000000000000000000000000000000000000000000000000000008352600483016130b6565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432165afa8015611421576113c8915f916113ff575b506130ef565b519283156113d75792916111c3565b7f1f2a2005000000000000000000000000000000000000000000000000000000005f5260045ffd5b61141b91503d805f833e6114138183612c68565b810190613030565b5f6113c2565b6040513d5f823e3d90fd5b50346102b25761143b366129b2565b9073ffffffffffffffffffffffffffffffffffffffff9392937f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361028a5773ffffffffffffffffffffffffffffffffffffffff829116938415610262577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6114c4612fa1565b93146115e1575b81156115b95773ffffffffffffffffffffffffffffffffffffffff82116115915783946e22d473030f116ddee9f6b43ac78ba33b1561043a5773ffffffffffffffffffffffffffffffffffffffff92839182604051967f36c7851600000000000000000000000000000000000000000000000000000000885216600487015260248601521660448401521660648201528181608481836e22d473030f116ddee9f6b43ac78ba35af18015610d57576115805750f35b8161158a91612c68565b6102b25780f35b6004847fc4bd89a9000000000000000000000000000000000000000000000000000000008152fd5b6004847f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b90506040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260208160248173ffffffffffffffffffffffffffffffffffffffff86165afa908115610b1e578491611659575b50906114cb565b90506020813d602011611683575b8161167460209383612c68565b810103126106b457515f611652565b3d9150611667565b50346102b25761169a36612a24565b90929173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361046657809173ffffffffffffffffffffffffffffffffffffffff811615610ba05773ffffffffffffffffffffffffffffffffffffffff8416906040517f38d52e0f000000000000000000000000000000000000000000000000000000008152602081600481865afa908115611944577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff918a91611915575b5016931461188c575b83156118645761180183926020926117a8888b9897613192565b6040519687809481937f6e553f65000000000000000000000000000000000000000000000000000000008352896004840190929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b03925af192831561105b57869361182e575b5061182693611821916132b1565b6133a1565b11610ac05780f35b9092506020813d60201161185c575b8161184a60209383612c68565b810103126106b4575191611826611813565b3d915061183d565b6004877f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b92506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa90811561190a5787916118d8575b509261178e565b90506020813d602011611902575b816118f360209383612c68565b810103126106b457515f6118d1565b3d91506118e6565b6040513d89823e3d90fd5b611937915060203d60201161193d575b61192f8183612c68565b810190612e4b565b5f611785565b503d611925565b6040513d8a823e3d90fd5b50346102b25761195e36612b23565b73ffffffffffffffffffffffffffffffffffffffff9491949392937f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303610bc85790611206604093926119b1612fa1565b855196879586957f50d8cd4b00000000000000000000000000000000000000000000000000000000875260048701612f5a565b50346102b2576119f336612a9a565b93929573ffffffffffffffffffffffffffffffffffffffff959192957f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303611c5957813073ffffffffffffffffffffffffffffffffffffffff881614611c3157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff899214611b5a575b611b1b60409673ffffffffffffffffffffffffffffffffffffffff611aa384612e9a565b1695611ae673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432168098613192565b8851998a98899788967fa99aad8900000000000000000000000000000000000000000000000000000000885260048801612f0f565b03925af18015610e17576118269184908592611b38575b506133a1565b9050611b53915060403d60401161128c5761127e8183612c68565b905f611b32565b9150506024919293602073ffffffffffffffffffffffffffffffffffffffff611b8284612e9a565b16604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315611944578893611bfd575b508215611bd557939291908790611a7f565b6004887f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011611c29575b81611c1960209383612c68565b810103126106b45751915f611bc3565b3d9150611c0c565b6004897fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b6004887f08094908000000000000000000000000000000000000000000000000000000008152fd5b50346102b257611c9036612a9a565b93929573ffffffffffffffffffffffffffffffffffffffff959192957f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303611c595783823073ffffffffffffffffffffffffffffffffffffffff891614611f7157907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a939214611e93575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611de1575b611b1b60409673ffffffffffffffffffffffffffffffffffffffff611d6984612e9a565b1695611dac73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432168098613192565b8851998a98899788967f20b76e8100000000000000000000000000000000000000000000000000000000885260048801612f0f565b91929350611e0790611343611e028860a0611dfc3688612ca9565b20613513565b61354b565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432165afa908115611944576fffffffffffffffffffffffffffffffff91611e6b918a91611e7f57506130ef565b5116938415611bd557939291908790611d45565b61141b91503d808c833e6114138183612c68565b90915060249250602073ffffffffffffffffffffffffffffffffffffffff611eba84612e9a565b16604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315611f66578993611f32575b508215611f0a57908891611d1e565b6004897f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b9092506020813d602011611f5e575b81611f4e60209383612c68565b810103126106b45751915f611efb565b3d9150611f41565b6040513d8b823e3d90fd5b60048a7fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b50346102b257807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b257602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432168152f35b50346102b25761201736612a24565b73ffffffffffffffffffffffffffffffffffffffff939291937f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a4481633036104665773ffffffffffffffffffffffffffffffffffffffff8116156106cb5781156121c557849073ffffffffffffffffffffffffffffffffffffffff8416604051907f38d52e0f000000000000000000000000000000000000000000000000000000008252602082600481845afa908115610b1e5773ffffffffffffffffffffffffffffffffffffffff6121539260209487916121a8575b5016936120fa8886613192565b6040519586809481937f94bf804d0000000000000000000000000000000000000000000000000000000083528a6004840190929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b03925af191821561105b578692612172575061182693611821916132b1565b9091506020813d6020116121a0575b8161218e60209383612c68565b810103126106b4575190611826611813565b3d9150612181565b6121bf9150853d871161193d5761192f8183612c68565b5f6120ed565b6004857f9811e0c7000000000000000000000000000000000000000000000000000000008152fd5b50346102b2576121fc366129b2565b9073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a4481633036106f3578173ffffffffffffffffffffffffffffffffffffffff82168015610ba0573014612371577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8103612345575090506040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260208160248173ffffffffffffffffffffffffffffffffffffffff87165afa908115610b1e578491612313575b50905b816122ed578380f35b73ffffffffffffffffffffffffffffffffffffffff61230c9316613129565b5f80808380f35b90506020813d60201161233d575b8161232e60209383612c68565b810103126106b457515f6122e1565b3d9150612321565b6122e4576004847f1f2a2005000000000000000000000000000000000000000000000000000000008152fd5b6004857fde8b5909000000000000000000000000000000000000000000000000000000008152fd5b50346102b25760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102b2576004356123d461294b565b9073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a44816330361028a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146124fb575b80156102125773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000042000000000000000000000000000000000000061691823b1561048e57836040517fd0e30db0000000000000000000000000000000000000000000000000000000008152818160048187895af18015610d57576124e6575b50503073ffffffffffffffffffffffffffffffffffffffff8216036124dd578380f35b61230c92613129565b816124f091612c68565b61048e57835f6124ba565b504761243a565b50346106b4577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360160e081126106b45760a0136106b45760a435612545612928565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448163303612799577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214612679575b81156113d75773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432166125ef612fa1565b90803b156106b45773ffffffffffffffffffffffffffffffffffffffff935f6101049286829660405198899788967f8720316d00000000000000000000000000000000000000000000000000000000885261264c60048901612d0b565b60a48801521660c48601521660e48401525af180156114215761266d575080f35b61001891505f90612c68565b905060405161268781612c1f565b60043573ffffffffffffffffffffffffffffffffffffffff811681036106b457815260243573ffffffffffffffffffffffffffffffffffffffff811681036106b457602082015260443573ffffffffffffffffffffffffffffffffffffffff811681036106b45760408201526064359073ffffffffffffffffffffffffffffffffffffffff821682036106b457611343611e0260a08361273e9560605f960152608435608082015220612738612fa1565b90613513565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432165afa80156114215761278f915f916113ff57506130ef565b5160801c906125aa565b7f08094908000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f840112156106b45782359167ffffffffffffffff83116106b457602083818601950101116106b457565b346106b45760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b45760243567ffffffffffffffff81116106b45761283e9036906004016127c1565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432163303612799575f9182916128ea602460405183819460208301967f803a7fba000000000000000000000000000000000000000000000000000000008852848401378101868382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c68565b5190827f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a4485af1612918613429565b901561292057005b805190602001fd5b60c4359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b359073ffffffffffffffffffffffffffffffffffffffff821682036106b457565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060243573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060443590565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60809101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790602435906044359060643573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820161014081126106b45760a0136106b45760049160a4359160c4359160e435916101043573ffffffffffffffffffffffffffffffffffffffff811681036106b45791610124359067ffffffffffffffff82116106b457612b1f916004016127c1565b9091565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0161012081126106b45760a0136106b45760049060a4359060c4359060e435906101043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60a09101126106b45760043573ffffffffffffffffffffffffffffffffffffffff811681036106b45790602435906044359060643573ffffffffffffffffffffffffffffffffffffffff811681036106b4579060843573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b60a0810190811067ffffffffffffffff821117612c3b57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612c3b57604052565b91908260a09103126106b457604051612cc181612c1f565b6080808294612ccf81612991565b8452612cdd60208201612991565b6020850152612cee60408201612991565b6040850152612cff60608201612991565b60608501520135910152565b60043573ffffffffffffffffffffffffffffffffffffffff81168091036106b457815260243573ffffffffffffffffffffffffffffffffffffffff81168091036106b457602082015260443573ffffffffffffffffffffffffffffffffffffffff81168091036106b457604082015260643573ffffffffffffffffffffffffffffffffffffffff81168091036106b45760608201526080608435910152565b6080809173ffffffffffffffffffffffffffffffffffffffff612dcc82612991565b16845273ffffffffffffffffffffffffffffffffffffffff612df060208301612991565b16602085015273ffffffffffffffffffffffffffffffffffffffff612e1760408301612991565b16604085015273ffffffffffffffffffffffffffffffffffffffff612e3e60608301612991565b1660608501520135910152565b908160209103126106b4575173ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b60243573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b3573ffffffffffffffffffffffffffffffffffffffff811681036106b45790565b91908260409103126106b4576020825192015190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b919361012093612f579795612f398573ffffffffffffffffffffffffffffffffffffffff95612daa565b60a085015260c08401521660e0820152816101008201520191612ed1565b90565b9373ffffffffffffffffffffffffffffffffffffffff929061010094849298979398612f8b8861012081019b612daa565b60a088015260c08701521660e085015216910152565b6040517f5c39fcc100000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448165afa908115611421575f91613017575090565b612f57915060203d60201161193d5761192f8183612c68565b6020818303126106b45780519067ffffffffffffffff82116106b457019080601f830112156106b45781519167ffffffffffffffff8311612c3b578260051b9060208201936130826040519586612c68565b84526020808501928201019283116106b457602001905b8282106130a65750505090565b8151815260209182019101613099565b60206040818301928281528451809452019201905f5b8181106130d95750505090565b82518452602093840193909201916001016130cc565b8051156130fc5760200190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044808301939093529181526131909161318b606483612c68565b613572565b565b6040519060205f73ffffffffffffffffffffffffffffffffffffffff828501957f095ea7b300000000000000000000000000000000000000000000000000000000875216948560248601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff604486015260448552613212606486612c68565b84519082855af15f513d8261327f575b50501561322e57505050565b61318b61319093604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152613279606482612c68565b82613572565b9091506132a9575073ffffffffffffffffffffffffffffffffffffffff81163b15155b5f80613222565b6001146132a2565b6040519060205f73ffffffffffffffffffffffffffffffffffffffff828501957f095ea7b3000000000000000000000000000000000000000000000000000000008752169485602486015281604486015260448552613212606486612c68565b906b033b2e3c9fd0803ce80000008202918083046b033b2e3c9fd0803ce8000000149015171561333d57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8115613374570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b906b033b2e3c9fd0803ce80000008202918083046b033b2e3c9fd0803ce8000000149015171561333d57807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81011161333d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183010180921161333d57612f579161336a565b3d15613481573d9067ffffffffffffffff8211612c3b576040519161347660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184612c68565b82523d5f602084013e565b606090565b8147106134e3575f80809373ffffffffffffffffffffffffffffffffffffffff8294165af16134b3613429565b50156134bb57565b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b50477fcf479181000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b61353a61130f916040516020810191825260026040820152604081526112d8606082612c68565b5190206001810180911161333d5790565b6040519061355a604083612c68565b600182526020368184013761356e826130ef565b5290565b905f602091828151910182855af115611421575f513d6135f0575073ffffffffffffffffffffffffffffffffffffffff81163b155b6135ae5750565b73ffffffffffffffffffffffffffffffffffffffff907f5274afe7000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b600114156135a756fea164736f6c634300081c000a

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

0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af4320000000000000000000000004200000000000000000000000000000000000006

-----Decoded View---------------
Arg [0] : bundler3 (address): 0x3D07BF2FFb23248034bF704F3a4786F1ffE2a448
Arg [1] : morpho (address): 0xE741BC7c34758b4caE05062794E8Ae24978AF432
Arg [2] : wNative (address): 0x4200000000000000000000000000000000000006

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000003d07bf2ffb23248034bf704f3a4786f1ffe2a448
Arg [1] : 000000000000000000000000e741bc7c34758b4cae05062794e8ae24978af432
Arg [2] : 0000000000000000000000004200000000000000000000000000000000000006


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
[ 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.