ETH Price: $2,938.74 (-0.31%)
 

Overview

Max Total Supply

4.785410403377700393 ERC20 ***

Holders

99

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
0.000101048214978289 ERC20 ***

Value
$0.00
0x087ca5bacf37f23d4b346a8e36c1b45352b37359
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
TheoDepositVault

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {ShareMath} from "./lib/ShareMath.sol";
import {Vault} from "./lib/Vault.sol";
import {IWETH} from "../interfaces/IWETH.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {MerkleProofLib} from "solady/src/utils/MerkleProofLib.sol";

/**
 * @title TheoDepositVault
 * @notice A vault that allows users to deposit and withdraw from an off-chain managed Theo strategy
 * @notice Users receive shares for their deposits, which can be redeemed for assets
 * @notice The vault is managed by a keeper, who is responsible for rolling to the next round
 * @notice The rounds will be rolled over on a weekly basis
 */
contract TheoDepositVault is ReentrancyGuard, ERC20, Ownable2Step {
    using SafeERC20 for IERC20;
    using ShareMath for Vault.DepositReceipt;
    using MerkleProofLib for bytes32[];

    /************************************************
     *  STATE
     ***********************************************/
    /// @notice Stores the user's pending deposit for the round
    mapping(address => Vault.DepositReceipt) public depositReceipts;

    /// @notice On every round's close, the pricePerShare value of an vault token is stored
    /// This is used to determine the number of shares to be returned
    /// to a user with their DepositReceipt.depositAmount
    mapping(uint256 => uint256) public roundPricePerShare;

    /// @notice Stores pending user withdrawals
    mapping(address => Vault.Withdrawal) public withdrawals;

    /// @notice Vault's parameters like cap, decimals
    Vault.VaultParams public vaultParams;

    /// @notice Vault's lifecycle state like round and locked amounts
    Vault.VaultState public vaultState;

    /// @notice The amount of 'asset' that was queued for withdrawal in the last round
    uint256 public lastQueuedWithdrawAmount;

    /// @notice The amount of shares that are queued for withdrawal in the current round
    uint256 public currentQueuedWithdrawShares;

    /// @notice role in charge of weekly vault operations such as rollToNextRound
    // no access to critical vault changes
    address public keeper;

    /// @notice weth address
    address public immutable WETH;

    /// @notice private or public
    bool public isPublic;

    /// @notice merkle root for private whitelist
    bytes32 public merkleRoot;

    /************************************************
     *  EVENTS
     ***********************************************/
    event Deposit(address indexed account, uint256 amount, uint256 round);

    event InitiateWithdraw(address indexed account, uint256 shares, uint256 round);
    event Withdraw(address indexed account, uint256 amount, uint256 shares);

    event Redeem(address indexed account, uint256 share, uint256 round);

    event CapSet(uint256 oldCap, uint256 newCap);

    event InstantWithdraw(address indexed account, uint256 amount, uint256 round);

    event RollRound(uint256 round, uint256 pricePerShare, uint256 lockedAmount);

    /************************************************
     *  MODIFIERS
     ***********************************************/

    /**
     * @dev Throws if called by any account other than the keeper.
     */
    modifier onlyKeeper() {
        require(msg.sender == keeper, "!keeper");
        _;
    }

    /************************************************
     *  CONSTRUCTOR & INITIALIZATION
     ***********************************************/

    /**
     * @notice Initializes the contract with immutable variables
     * @param _weth is the Wrapped Native token contract
     * @param _keeper is the role that will handle funds and advancing rounds
     * @param _tokenName is the token name of the share ERC-20
     * @param _tokenSymbol is the token symbol of the share ERC-20
     * @param _vaultParams is the `VaultParams` struct with general vault data
     */
    constructor(
        address _weth,
        address _keeper,
        string memory _tokenName,
        string memory _tokenSymbol,
        Vault.VaultParams memory _vaultParams
    ) ReentrancyGuard() Ownable(msg.sender) ERC20(_tokenName, _tokenSymbol) {
        require(_weth != address(0), "!_weth");
        require(_keeper != address(0), "!_keeper");
        require(_vaultParams.cap > 0, "!_cap");
        require(_vaultParams.asset != address(0), "!_asset");

        WETH = _weth;
        keeper = _keeper;
        vaultParams = _vaultParams;

        vaultState.round = 1;
    }

    /************************************************
     *  PUBLIC DEPOSITS
     ***********************************************/

    /**
     * @notice Deposits the native asset from msg.sender.
     */
    function depositETH() external payable nonReentrant {
        require(isPublic, "!public");
        require(vaultParams.asset == WETH, "!WETH");
        require(msg.value > 0, "!value");

        _depositFor(msg.value, msg.sender);

        IWETH(WETH).deposit{value: msg.value}();
    }

    /**
     * @notice Deposits the `asset` from msg.sender.
     * @param amount is the amount of `asset` to deposit
     */
    function deposit(uint256 amount) external nonReentrant {
        require(isPublic, "!public");
        require(amount > 0, "!amount");

        _depositFor(amount, msg.sender);

        // An approve() by the msg.sender is required beforehand
        IERC20(vaultParams.asset).safeTransferFrom(msg.sender, address(this), amount);
    }

    /**
     * @notice Deposits the `asset` from msg.sender added to `creditor`'s deposit.
     * @notice Used for vault -> vault deposits on the user's behalf
     * @param amount is the amount of `asset` to deposit
     * @param creditor is the address that can claim/withdraw deposited amount
     */
    function depositFor(uint256 amount, address creditor) external nonReentrant {
        require(isPublic, "!public");
        require(amount > 0, "!amount");
        require(creditor != address(0), "!creditor");

        _depositFor(amount, creditor);

        // An approve() by the msg.sender is required beforehand
        IERC20(vaultParams.asset).safeTransferFrom(msg.sender, address(this), amount);
    }

    /**
     * @notice Deposits the native asset  from msg.sender added to `creditor`'s deposit.
     * @notice Used for vault -> vault deposits on the user's behalf
     * @param creditor is the address that can claim/withdraw deposited amount
     */
    function depositETHFor(address creditor) external payable nonReentrant {
        require(isPublic, "!public");
        require(vaultParams.asset == WETH, "!WETH");
        require(msg.value > 0, "!value");
        require(creditor != address(0), "!creditor");

        _depositFor(msg.value, creditor);

        IWETH(WETH).deposit{value: msg.value}();
    }

    /**
     * @notice Manages the deposit receipts for a depositer
     * @param amount is the amount of `asset` deposited
     * @param creditor is the address to receieve the deposit
     */
    function _depositFor(uint256 amount, address creditor) private {
        uint256 currentRound = vaultState.round;
        uint256 totalWithDepositedAmount = totalBalance() + amount;

        require(totalWithDepositedAmount <= vaultParams.cap, "Exceed cap");
        require(totalWithDepositedAmount >= vaultParams.minimumSupply, "Insufficient balance");

        emit Deposit(creditor, amount, currentRound);

        Vault.DepositReceipt memory depositReceipt = depositReceipts[creditor];

        // If we have an unprocessed pending deposit from the previous rounds, we have to process it.
        uint256 unredeemedShares = depositReceipt.getSharesFromReceipt(currentRound, roundPricePerShare[depositReceipt.round], vaultParams.decimals);

        uint256 depositAmount = amount;

        // If we have a pending deposit in the current round, we add on to the pending deposit
        if (currentRound == depositReceipt.round) {
            uint256 newAmount = uint256(depositReceipt.amount) + amount;
            depositAmount = newAmount;
        }

        ShareMath.assertUint104(depositAmount);

        depositReceipts[creditor] = Vault.DepositReceipt({round: uint16(currentRound), amount: uint104(depositAmount), unredeemedShares: uint128(unredeemedShares)});

        uint256 newTotalPending = uint256(vaultState.totalPending) + amount;
        ShareMath.assertUint128(newTotalPending);

        vaultState.totalPending = uint128(newTotalPending);
    }

    /************************************************
     *  PRIVATE DEPOSITS
     ***********************************************/

    /**
     * @notice Deposits the native asset from msg.sender.
     * @notice msg.sender must be whitelisted
     * @param proof is the merkle proof
     */
    function privateDepositETH(bytes32[] memory proof) external payable nonReentrant {
        if (!isPublic) {
            require(proof.verify(merkleRoot, keccak256(abi.encodePacked(msg.sender))), "Invalid proof");
        }
        require(vaultParams.asset == WETH, "!WETH");
        require(msg.value > 0, "!value");

        _depositFor(msg.value, msg.sender);

        IWETH(WETH).deposit{value: msg.value}();
    }

    /**
     * @notice Deposits the `asset` from msg.sender.
     * @notice msg.sender must be whitelisted
     * @param amount is the amount of `asset` to deposit
     * @param proof is the merkle proof
     */
    function privateDeposit(uint256 amount, bytes32[] memory proof) external nonReentrant {
        if (!isPublic) {
            require(proof.verify(merkleRoot, keccak256(abi.encodePacked(msg.sender))), "Invalid proof");
        }

        require(amount > 0, "!amount");

        _depositFor(amount, msg.sender);

        // An approve() by the msg.sender is required beforehand
        IERC20(vaultParams.asset).safeTransferFrom(msg.sender, address(this), amount);
    }

    /************************************************
     *  WITHDRAWALS
     ***********************************************/

    /**
     * @notice Withdraws the assets on the vault using the outstanding `DepositReceipt.amount`
     * @param amount is the amount to withdraw
     */
    function withdrawInstantly(uint256 amount) external nonReentrant {
        Vault.DepositReceipt storage depositReceipt = depositReceipts[msg.sender];

        uint256 currentRound = vaultState.round;
        require(amount > 0, "!amount");
        require(depositReceipt.round == currentRound, "Invalid round");

        uint256 receiptAmount = depositReceipt.amount;
        require(receiptAmount >= amount, "Exceed amount");

        // Subtraction underflow checks already ensure it is smaller than uint104
        depositReceipt.amount = uint104(receiptAmount - amount);
        vaultState.totalPending = uint128(uint256(vaultState.totalPending) - amount);

        emit InstantWithdraw(msg.sender, amount, currentRound);

        _transferAsset(msg.sender, amount);
    }

    /**
     * @notice Initiates a withdrawal that can be processed once the round completes
     * @param numShares is the number of shares to withdraw
     */
    function initiateWithdraw(uint256 numShares) external nonReentrant {
        require(numShares > 0, "!numShares");

        // We do a max redeem before initiating a withdrawal
        // But we check if they must first have unredeemed shares
        if (depositReceipts[msg.sender].amount > 0 || depositReceipts[msg.sender].unredeemedShares > 0) {
            _redeem(0, true);
        }

        // This caches the `round` variable used in shareBalances
        uint256 currentRound = vaultState.round;
        Vault.Withdrawal memory withdrawal = withdrawals[msg.sender];

        bool withdrawalIsSameRound = withdrawal.round == currentRound;

        emit InitiateWithdraw(msg.sender, numShares, currentRound);

        uint256 existingShares = uint256(withdrawal.shares);

        uint256 withdrawalShares;
        if (withdrawalIsSameRound) {
            withdrawalShares = existingShares + numShares;
        } else {
            require(existingShares == 0, "Existing withdraw");
            withdrawalShares = numShares;
            withdrawals[msg.sender].round = uint16(currentRound);
        }

        ShareMath.assertUint128(withdrawalShares);
        withdrawals[msg.sender].shares = uint128(withdrawalShares);

        _transfer(msg.sender, address(this), numShares);

        currentQueuedWithdrawShares = currentQueuedWithdrawShares + numShares;
    }

    /**
     * @notice Completes a scheduled withdrawal from a past round. Uses finalized pps for the round
     */
    function completeWithdraw() external nonReentrant {
        Vault.Withdrawal storage withdrawal = withdrawals[msg.sender];

        uint256 withdrawalShares = withdrawal.shares;
        uint256 withdrawalRound = withdrawal.round;

        // This checks if there is a withdrawal
        require(withdrawalShares > 0, "Not initiated");

        require(withdrawalRound < vaultState.round, "Round not closed");

        // We leave the round number as non-zero to save on gas for subsequent writes
        withdrawals[msg.sender].shares = 0;
        vaultState.queuedWithdrawShares = uint128(uint256(vaultState.queuedWithdrawShares) - withdrawalShares);

        uint256 withdrawAmount = ShareMath.sharesToAsset(withdrawalShares, roundPricePerShare[withdrawalRound], vaultParams.decimals);

        emit Withdraw(msg.sender, withdrawAmount, withdrawalShares);

        _burn(address(this), withdrawalShares);

        require(withdrawAmount > 0, "!withdrawAmount");
        _transferAsset(msg.sender, withdrawAmount);

        lastQueuedWithdrawAmount = uint256(uint256(lastQueuedWithdrawAmount) - withdrawAmount);
    }

    /************************************************
     *  REDEMPTIONS
     ***********************************************/

    /**
     * @notice Redeems shares that are owed to the account
     * @param numShares is the number of shares to redeem
     */
    function redeem(uint256 numShares) external nonReentrant {
        require(numShares > 0, "!numShares");
        _redeem(numShares, false);
    }

    /**
     * @notice Redeems the entire unredeemedShares balance that is owed to the account
     */
    function maxRedeem() external nonReentrant {
        _redeem(0, true);
    }

    /**
     * @notice Redeems shares that are owed to the account
     * @param numShares is the number of shares to redeem, could be 0 when isMax=true
     * @param isMax is flag for when callers do a max redemption
     */
    function _redeem(uint256 numShares, bool isMax) internal {
        Vault.DepositReceipt memory depositReceipt = depositReceipts[msg.sender];

        // This handles the null case when depositReceipt.round = 0
        // Because we start with round = 1 at `initialize`
        uint256 currentRound = vaultState.round;

        uint256 unredeemedShares = depositReceipt.getSharesFromReceipt(currentRound, roundPricePerShare[depositReceipt.round], vaultParams.decimals);

        numShares = isMax ? unredeemedShares : numShares;
        if (numShares == 0) {
            return;
        }
        require(numShares <= unredeemedShares, "Exceeds available");

        // If we have a depositReceipt on the same round, BUT we have some unredeemed shares
        // we debit from the unredeemedShares, but leave the amount field intact
        // If the round has past, with no new deposits, we just zero it out for new deposits.
        if (depositReceipt.round < currentRound) {
            depositReceipts[msg.sender].amount = 0;
        }

        ShareMath.assertUint128(numShares);
        depositReceipts[msg.sender].unredeemedShares = uint128(unredeemedShares - numShares);

        emit Redeem(msg.sender, numShares, depositReceipt.round);

        _transfer(address(this), msg.sender, numShares);
    }

    /************************************************
     *  VAULT OPERATIONS
     ***********************************************/

    /**
     * @notice Rolls to the next round, finalizing prev round pricePerShare and minting new shares
     * @notice Keeper only deposits enough to fulfill withdraws and passes the true amount as 'currentBalance'
     * @notice Keeper should be a contract so currentBalance and the call to the func happens atomically
     * @param currentBalance is the amount of `asset` that is currently being used for strategy 
              + the amount in the contract right before the roll

     */
    function rollToNextRound(uint256 currentBalance) external onlyKeeper nonReentrant {
        require(currentBalance >= uint256(vaultParams.minimumSupply), "Insufficient balance");
        Vault.VaultState memory state = vaultState;
        uint256 currentRound = state.round;

        uint256 newPricePerShare = ShareMath.pricePerShare(totalSupply() - state.queuedWithdrawShares, currentBalance - lastQueuedWithdrawAmount, state.totalPending, vaultParams.decimals);

        roundPricePerShare[currentRound] = newPricePerShare;

        emit RollRound(currentRound, newPricePerShare, currentBalance);

        vaultState.totalPending = 0;
        vaultState.round = uint16(currentRound + 1);

        uint256 mintShares = ShareMath.assetToShares(state.totalPending, newPricePerShare, vaultParams.decimals);

        _mint(address(this), mintShares);

        uint256 queuedWithdrawAmount = lastQueuedWithdrawAmount + ShareMath.sharesToAsset(currentQueuedWithdrawShares, newPricePerShare, vaultParams.decimals);

        lastQueuedWithdrawAmount = queuedWithdrawAmount;

        uint256 newQueuedWithdrawShares = uint256(state.queuedWithdrawShares) + currentQueuedWithdrawShares;

        ShareMath.assertUint128(newQueuedWithdrawShares);
        vaultState.queuedWithdrawShares = uint128(newQueuedWithdrawShares);

        currentQueuedWithdrawShares = 0;

        vaultState.lastLockedAmount = state.lockedAmount;

        uint256 lockedBalance = currentBalance - queuedWithdrawAmount;

        ShareMath.assertUint104(lockedBalance);

        vaultState.lockedAmount = uint104(lockedBalance);

        IERC20(vaultParams.asset).safeTransfer(keeper, IERC20(vaultParams.asset).balanceOf(address(this)) - queuedWithdrawAmount);
    }

    /**
     * @notice Helper function to make either an ETH transfer or ERC20 transfer
     * @param recipient is the receiving address
     * @param amount is the transfer amount
     */
    function _transferAsset(address recipient, uint256 amount) internal {
        address asset = vaultParams.asset;
        if (asset == WETH) {
            IWETH(WETH).withdraw(amount);
            (bool success, ) = recipient.call{value: amount}("");
            require(success, "Transfer failed");
            return;
        }
        IERC20(asset).safeTransfer(recipient, amount);
    }

    /************************************************
     *  SETTERS
     ***********************************************/

    /**
     * @notice Sets the vault to public or private
     * @param _isPublic is the new public state
     */
    function setPublic(bool _isPublic) external onlyOwner {
        isPublic = _isPublic;
    }

    /**
     * @notice Sets the merkle root for the private whitelist
     * @param _merkleRoot is the new merkle root
     */
    function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        merkleRoot = _merkleRoot;
    }

    /**
     * @notice Sets the new keeper
     * @param newKeeper is the address of the new keeper
     */
    function setNewKeeper(address newKeeper) external onlyOwner {
        require(newKeeper != address(0), "!newKeeper");
        keeper = newKeeper;
    }

    /**
     * @notice Sets a new cap for deposits
     * @param newCap is the new cap for deposits
     */
    function setCap(uint256 newCap) external onlyOwner {
        require(newCap > 0, "!newCap");
        ShareMath.assertUint104(newCap);
        emit CapSet(vaultParams.cap, newCap);
        vaultParams.cap = uint104(newCap);
    }

    /**
     * @notice Sets the new vault parameters
     */
    function setVaultParams(Vault.VaultParams memory newVaultParams) external onlyOwner {
        require(newVaultParams.cap > 0, "!newCap");
        require(newVaultParams.asset != address(0), "!newAsset");
        vaultParams = newVaultParams;
    }

    /************************************************
     *  GETTERS
     ***********************************************/

    /** 
    * @notice Returns the current amount of `asset` that is queued for withdrawal in the current round
    * @param currentBalance is the amount of `asset` that is currently being used for strategy 
            + the amount in the contract right now
    * @return the amount of `asset` that is queued for withdrawal in the current round
    */
    function getCurrQueuedWithdrawAmount(uint256 currentBalance) public view returns (uint256) {
        Vault.VaultState memory state = vaultState;
        uint256 newPricePerShare = ShareMath.pricePerShare(totalSupply() - state.queuedWithdrawShares, currentBalance - lastQueuedWithdrawAmount, state.totalPending, vaultParams.decimals);
        return (lastQueuedWithdrawAmount + ShareMath.sharesToAsset(currentQueuedWithdrawShares, newPricePerShare, vaultParams.decimals));
    }

    /**
     * @notice Returns the vault's total balance, including the amounts locked into a position
     * @return total balance of the vault, including the amounts locked in third party protocols
     */
    function totalBalance() public view returns (uint256) {
        return uint256(vaultState.lockedAmount) + IERC20(vaultParams.asset).balanceOf(address(this));
    }

    /**
     * @notice Returns the asset balance held on the vault for the account not
               accounting for current round deposits
     * @param account is the address to lookup balance for
     * @return the amount of `asset` custodied by the vault for the user
     */
    function accountVaultBalance(address account) external view returns (uint256) {
        uint256 _decimals = vaultParams.decimals;
        uint256 assetPerShare = ShareMath.pricePerShare(totalSupply(), totalBalance(), vaultState.totalPending, _decimals);
        return ShareMath.sharesToAsset(shares(account), assetPerShare, _decimals);
    }

    /**
     * @notice Getter for returning the account's share balance including unredeemed shares
     * @param account is the account to lookup share balance for
     * @return the share balance
     */
    function shares(address account) public view returns (uint256) {
        (uint256 heldByAccount, uint256 heldByVault) = shareBalances(account);
        return heldByAccount + heldByVault;
    }

    /**
     * @notice Getter for returning the account's share balance split between account and vault holdings
     * @param account is the account to lookup share balance for
     * @return heldByAccount is the shares held by account
     * @return heldByVault is the shares held on the vault (unredeemedShares)
     */
    function shareBalances(address account) public view returns (uint256 heldByAccount, uint256 heldByVault) {
        Vault.DepositReceipt memory depositReceipt = depositReceipts[account];

        if (depositReceipt.round < ShareMath.PLACEHOLDER_UINT) {
            return (balanceOf(account), 0);
        }

        uint256 unredeemedShares = depositReceipt.getSharesFromReceipt(vaultState.round, roundPricePerShare[depositReceipt.round], vaultParams.decimals);

        return (balanceOf(account), unredeemedShares);
    }

    /**
     * @notice The price of a unit of share denominated in the `asset`
     */
    function pricePerShare() external view returns (uint256) {
        return ShareMath.pricePerShare(totalSupply(), totalBalance(), vaultState.totalPending, vaultParams.decimals);
    }

    /**
     * @notice returns if account can deposit
     * @param account is the account to check
     * @param proof is the merkle proof
     */
    function canDeposit(address account, bytes32[] memory proof) external view returns (bool) {
        return isPublic || proof.verify(merkleRoot, keccak256(abi.encodePacked(account)));
    }

    /**
     * @notice Returns the token decimals
     */
    function decimals() public view override returns (uint8) {
        return vaultParams.decimals;
    }

    function cap() external view returns (uint256) {
        return vaultParams.cap;
    }

    function totalPending() external view returns (uint256) {
        return vaultState.totalPending;
    }

    function round() external view returns (uint256) {
        return vaultState.round;
    }

    receive() external payable {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This extension of the {Ownable} contract includes a two-step mechanism to transfer
 * ownership, where the new owner must call {acceptOwnership} in order to replace the
 * old one. This can help prevent common mistakes, such as transfers of ownership to
 * incorrect accounts, or to contracts that are unable to interact with the
 * permission system.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC-20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC-721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC-1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

// 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 6 of 20 : 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 7 of 20 : 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";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC-20
 * applications.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Skips emitting an {Approval} event indicating an allowance update. This is not
     * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     *
     * ```solidity
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// 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);
}

// 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);
}

// 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 {
    using Address for address;

    /**
     * @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).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            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 silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

// 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 14 of 20 : 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.
 */
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();
}

// 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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity =0.8.20;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256) external;

    function balanceOf(address account) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    function decimals() external view returns (uint256);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

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

library ShareMath {
    uint256 internal constant PLACEHOLDER_UINT = 1;

    function assetToShares(uint256 assetAmount, uint256 assetPerShare, uint256 decimals) internal pure returns (uint256) {
        // If this throws, it means that vault's roundPricePerShare[currentRound] has not been set yet
        // which should never happen.
        // Has to be larger than 1 because `1` is used in `initRoundPricePerShares` to prevent cold writes.
        require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare");

        return (assetAmount * (10 ** decimals)) / assetPerShare;
    }

    function sharesToAsset(uint256 shares, uint256 assetPerShare, uint256 decimals) internal pure returns (uint256) {
        // If this throws, it means that vault's roundPricePerShare[currentRound] has not been set yet
        // which should never happen.
        // Has to be larger than 1 because `1` is used in `initRoundPricePerShares` to prevent cold writes.
        require(assetPerShare > PLACEHOLDER_UINT, "Invalid assetPerShare");

        return (shares * assetPerShare) / (10 ** decimals);
    }

    /**
     * @notice Returns the shares unredeemed by the user given their DepositReceipt
     * @param depositReceipt is the user's deposit receipt
     * @param currentRound is the `round` stored on the vault
     * @param assetPerShare is the price in asset per share
     * @param decimals is the number of decimals the asset/shares use
     * @return unredeemedShares is the user's virtual balance of shares that are owed
     */
    function getSharesFromReceipt(Vault.DepositReceipt memory depositReceipt, uint256 currentRound, uint256 assetPerShare, uint256 decimals) internal pure returns (uint256 unredeemedShares) {
        if (depositReceipt.round > 0 && depositReceipt.round < currentRound) {
            uint256 sharesFromRound = assetToShares(depositReceipt.amount, assetPerShare, decimals);

            return uint256(depositReceipt.unredeemedShares) + sharesFromRound;
        }
        return depositReceipt.unredeemedShares;
    }

    function pricePerShare(uint256 totalSupply, uint256 totalBalance, uint256 pendingAmount, uint256 decimals) internal pure returns (uint256) {
        uint256 singleShare = 10 ** decimals;
        return totalSupply > 0 ? (singleShare * (totalBalance - pendingAmount)) / totalSupply : singleShare;
    }

    /************************************************
     *  HELPERS
     ***********************************************/

    function assertUint104(uint256 num) internal pure {
        require(num <= type(uint104).max, "Overflow uint104");
    }

    function assertUint128(uint256 num) internal pure {
        require(num <= type(uint128).max, "Overflow uint128");
    }
}

File 19 of 20 : Vault.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/*
 * @title Vault
 * @dev Vault Data Type library for Theo Vaults
 */
library Vault {
    struct VaultParams {
        // Token decimals for vault shares
        uint8 decimals;
        // Asset used in Theo Vault
        address asset;
        // Minimum supply of the vault shares issued, for ETH it's 10**10
        uint56 minimumSupply;
        // Vault cap
        uint104 cap;
    }

    struct VaultState {
        // 32 byte slot 1
        //  Current round number. `round` represents the number of `period`s elapsed.
        uint16 round;
        // Amount that is currently locked for executing strategy
        uint104 lockedAmount;
        // Amount that was locked for executing strategy in the previous round
        // used for calculating performance fee deduction
        uint104 lastLockedAmount;
        // 32 byte slot 2
        // Stores the total tally of how much of `asset` there is
        // to be used to mint vault tokens
        uint128 totalPending;
        // Total amount of queued withdrawal shares from previous rounds (doesn't include the current round)
        uint128 queuedWithdrawShares;
    }

    struct DepositReceipt {
        // Maximum of 65535 rounds. Assuming 1 round is 7 days, maximum is 1256 years.
        uint16 round;
        // Deposit amount, max 20,282,409,603,651 or 20 trillion ETH deposit
        uint104 amount;
        // Unredeemed shares balance
        uint128 unredeemedShares;
    }

    struct Withdrawal {
        // Maximum of 65535 rounds. Assuming 1 round is 7 days, maximum is 1256 years.
        uint16 round;
        // Number of shares withdrawn
        uint128 shares;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
library MerkleProofLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            MERKLE PROOF VERIFICATION OPERATIONS            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf)
        internal
        pure
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            if mload(proof) {
                // Initialize `offset` to the offset of `proof` elements in memory.
                let offset := add(proof, 0x20)
                // Left shift by 5 is equivalent to multiplying by 0x20.
                let end := add(offset, shl(5, mload(proof)))
                // Iterate over proof elements to compute root hash.
                for {} 1 {} {
                    // Slot of `leaf` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(leaf, mload(offset)))
                    // Store elements to hash contiguously in scratch space.
                    // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
                    mstore(scratch, leaf)
                    mstore(xor(scratch, 0x20), mload(offset))
                    // Reuse `leaf` to store the hash to reduce stack operations.
                    leaf := keccak256(0x00, 0x40)
                    offset := add(offset, 0x20)
                    if iszero(lt(offset, end)) { break }
                }
            }
            isValid := eq(leaf, root)
        }
    }

    /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf)
        internal
        pure
        returns (bool isValid)
    {
        /// @solidity memory-safe-assembly
        assembly {
            if proof.length {
                // Left shift by 5 is equivalent to multiplying by 0x20.
                let end := add(proof.offset, shl(5, proof.length))
                // Initialize `offset` to the offset of `proof` in the calldata.
                let offset := proof.offset
                // Iterate over proof elements to compute root hash.
                for {} 1 {} {
                    // Slot of `leaf` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(leaf, calldataload(offset)))
                    // Store elements to hash contiguously in scratch space.
                    // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
                    mstore(scratch, leaf)
                    mstore(xor(scratch, 0x20), calldataload(offset))
                    // Reuse `leaf` to store the hash to reduce stack operations.
                    leaf := keccak256(0x00, 0x40)
                    offset := add(offset, 0x20)
                    if iszero(lt(offset, end)) { break }
                }
            }
            isValid := eq(leaf, root)
        }
    }

    /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
    /// given `proof` and `flags`.
    ///
    /// Note:
    /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
    ///   will always return false.
    /// - The sum of the lengths of `proof` and `leaves` must never overflow.
    /// - Any non-zero word in the `flags` array is treated as true.
    /// - The memory offset of `proof` must be non-zero
    ///   (i.e. `proof` is not pointing to the scratch space).
    function verifyMultiProof(
        bytes32[] memory proof,
        bytes32 root,
        bytes32[] memory leaves,
        bool[] memory flags
    ) internal pure returns (bool isValid) {
        // Rebuilds the root by consuming and producing values on a queue.
        // The queue starts with the `leaves` array, and goes into a `hashes` array.
        // After the process, the last element on the queue is verified
        // to be equal to the `root`.
        //
        // The `flags` array denotes whether the sibling
        // should be popped from the queue (`flag == true`), or
        // should be popped from the `proof` (`flag == false`).
        /// @solidity memory-safe-assembly
        assembly {
            // Cache the lengths of the arrays.
            let leavesLength := mload(leaves)
            let proofLength := mload(proof)
            let flagsLength := mload(flags)

            // Advance the pointers of the arrays to point to the data.
            leaves := add(0x20, leaves)
            proof := add(0x20, proof)
            flags := add(0x20, flags)

            // If the number of flags is correct.
            for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} {
                // For the case where `proof.length + leaves.length == 1`.
                if iszero(flagsLength) {
                    // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
                    isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root)
                    break
                }

                // The required final proof offset if `flagsLength` is not zero, otherwise zero.
                let proofEnd := add(proof, shl(5, proofLength))
                // We can use the free memory space for the queue.
                // We don't need to allocate, since the queue is temporary.
                let hashesFront := mload(0x40)
                // Copy the leaves into the hashes.
                // Sometimes, a little memory expansion costs less than branching.
                // Should cost less, even with a high free memory offset of 0x7d00.
                leavesLength := shl(5, leavesLength)
                for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } {
                    mstore(add(hashesFront, i), mload(add(leaves, i)))
                }
                // Compute the back of the hashes.
                let hashesBack := add(hashesFront, leavesLength)
                // This is the end of the memory for the queue.
                // We recycle `flagsLength` to save on stack variables (sometimes save gas).
                flagsLength := add(hashesBack, shl(5, flagsLength))

                for {} 1 {} {
                    // Pop from `hashes`.
                    let a := mload(hashesFront)
                    // Pop from `hashes`.
                    let b := mload(add(hashesFront, 0x20))
                    hashesFront := add(hashesFront, 0x40)

                    // If the flag is false, load the next proof,
                    // else, pops from the queue.
                    if iszero(mload(flags)) {
                        // Loads the next proof.
                        b := mload(proof)
                        proof := add(proof, 0x20)
                        // Unpop from `hashes`.
                        hashesFront := sub(hashesFront, 0x20)
                    }

                    // Advance to the next flag.
                    flags := add(flags, 0x20)

                    // Slot of `a` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(a, b))
                    // Hash the scratch space and push the result onto the queue.
                    mstore(scratch, a)
                    mstore(xor(scratch, 0x20), b)
                    mstore(hashesBack, keccak256(0x00, 0x40))
                    hashesBack := add(hashesBack, 0x20)
                    if iszero(lt(hashesBack, flagsLength)) { break }
                }
                isValid :=
                    and(
                        // Checks if the last value in the queue is same as the root.
                        eq(mload(sub(hashesBack, 0x20)), root),
                        // And whether all the proofs are used, if required.
                        eq(proofEnd, proof)
                    )
                break
            }
        }
    }

    /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`,
    /// given `proof` and `flags`.
    ///
    /// Note:
    /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length`
    ///   will always return false.
    /// - Any non-zero word in the `flags` array is treated as true.
    /// - The calldata offset of `proof` must be non-zero
    ///   (i.e. `proof` is from a regular Solidity function with a 4-byte selector).
    function verifyMultiProofCalldata(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32[] calldata leaves,
        bool[] calldata flags
    ) internal pure returns (bool isValid) {
        // Rebuilds the root by consuming and producing values on a queue.
        // The queue starts with the `leaves` array, and goes into a `hashes` array.
        // After the process, the last element on the queue is verified
        // to be equal to the `root`.
        //
        // The `flags` array denotes whether the sibling
        // should be popped from the queue (`flag == true`), or
        // should be popped from the `proof` (`flag == false`).
        /// @solidity memory-safe-assembly
        assembly {
            // If the number of flags is correct.
            for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} {
                // For the case where `proof.length + leaves.length == 1`.
                if iszero(flags.length) {
                    // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`.
                    // forgefmt: disable-next-item
                    isValid := eq(
                        calldataload(
                            xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length))
                        ),
                        root
                    )
                    break
                }

                // The required final proof offset if `flagsLength` is not zero, otherwise zero.
                let proofEnd := add(proof.offset, shl(5, proof.length))
                // We can use the free memory space for the queue.
                // We don't need to allocate, since the queue is temporary.
                let hashesFront := mload(0x40)
                // Copy the leaves into the hashes.
                // Sometimes, a little memory expansion costs less than branching.
                // Should cost less, even with a high free memory offset of 0x7d00.
                calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length))
                // Compute the back of the hashes.
                let hashesBack := add(hashesFront, shl(5, leaves.length))
                // This is the end of the memory for the queue.
                // We recycle `flagsLength` to save on stack variables (sometimes save gas).
                flags.length := add(hashesBack, shl(5, flags.length))

                // We don't need to make a copy of `proof.offset` or `flags.offset`,
                // as they are pass-by-value (this trick may not always save gas).

                for {} 1 {} {
                    // Pop from `hashes`.
                    let a := mload(hashesFront)
                    // Pop from `hashes`.
                    let b := mload(add(hashesFront, 0x20))
                    hashesFront := add(hashesFront, 0x40)

                    // If the flag is false, load the next proof,
                    // else, pops from the queue.
                    if iszero(calldataload(flags.offset)) {
                        // Loads the next proof.
                        b := calldataload(proof.offset)
                        proof.offset := add(proof.offset, 0x20)
                        // Unpop from `hashes`.
                        hashesFront := sub(hashesFront, 0x20)
                    }

                    // Advance to the next flag offset.
                    flags.offset := add(flags.offset, 0x20)

                    // Slot of `a` in scratch space.
                    // If the condition is true: 0x20, otherwise: 0x00.
                    let scratch := shl(5, gt(a, b))
                    // Hash the scratch space and push the result onto the queue.
                    mstore(scratch, a)
                    mstore(xor(scratch, 0x20), b)
                    mstore(hashesBack, keccak256(0x00, 0x40))
                    hashesBack := add(hashesBack, 0x20)
                    if iszero(lt(hashesBack, flags.length)) { break }
                }
                isValid :=
                    and(
                        // Checks if the last value in the queue is same as the root.
                        eq(mload(sub(hashesBack, 0x20)), root),
                        // And whether all the proofs are used, if required.
                        eq(proofEnd, proof.offset)
                    )
                break
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes32 array.
    function emptyProof() internal pure returns (bytes32[] calldata proof) {
        /// @solidity memory-safe-assembly
        assembly {
            proof.length := 0
        }
    }

    /// @dev Returns an empty calldata bytes32 array.
    function emptyLeaves() internal pure returns (bytes32[] calldata leaves) {
        /// @solidity memory-safe-assembly
        assembly {
            leaves.length := 0
        }
    }

    /// @dev Returns an empty calldata bool array.
    function emptyFlags() internal pure returns (bool[] calldata flags) {
        /// @solidity memory-safe-assembly
        assembly {
            flags.length := 0
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"string","name":"_tokenName","type":"string"},{"internalType":"string","name":"_tokenSymbol","type":"string"},{"components":[{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint56","name":"minimumSupply","type":"uint56"},{"internalType":"uint104","name":"cap","type":"uint104"}],"internalType":"struct Vault.VaultParams","name":"_vaultParams","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","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":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"CapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InitiateWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"InstantWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"share","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"round","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pricePerShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockedAmount","type":"uint256"}],"name":"RollRound","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountVaultBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"canDeposit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"completeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentQueuedWithdrawShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"creditor","type":"address"}],"name":"depositETHFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"creditor","type":"address"}],"name":"depositFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositReceipts","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint104","name":"amount","type":"uint104"},{"internalType":"uint128","name":"unredeemedShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"currentBalance","type":"uint256"}],"name":"getCurrQueuedWithdrawAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"initiateWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastQueuedWithdrawAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"privateDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"privateDepositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"currentBalance","type":"uint256"}],"name":"rollToNextRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"round","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundPricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCap","type":"uint256"}],"name":"setCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newKeeper","type":"address"}],"name":"setNewKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPublic","type":"bool"}],"name":"setPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint56","name":"minimumSupply","type":"uint56"},{"internalType":"uint104","name":"cap","type":"uint104"}],"internalType":"struct Vault.VaultParams","name":"newVaultParams","type":"tuple"}],"name":"setVaultParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"shareBalances","outputs":[{"internalType":"uint256","name":"heldByAccount","type":"uint256"},{"internalType":"uint256","name":"heldByVault","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"shares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPending","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultParams","outputs":[{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint56","name":"minimumSupply","type":"uint56"},{"internalType":"uint104","name":"cap","type":"uint104"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultState","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint104","name":"lockedAmount","type":"uint104"},{"internalType":"uint104","name":"lastLockedAmount","type":"uint104"},{"internalType":"uint128","name":"totalPending","type":"uint128"},{"internalType":"uint128","name":"queuedWithdrawShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawInstantly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawals","outputs":[{"internalType":"uint16","name":"round","type":"uint16"},{"internalType":"uint128","name":"shares","type":"uint128"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040523480156200001157600080fd5b5060405162003c8138038062003c818339810160408190526200003491620003ec565b600160005533838360046200004a83826200059c565b5060056200005982826200059c565b5050506001600160a01b0381166200008c57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b62000097816200025e565b506001600160a01b038516620000d95760405162461bcd60e51b8152602060048201526006602482015265042beeecae8d60d31b604482015260640162000083565b6001600160a01b0384166200011c5760405162461bcd60e51b815260206004820152600860248201526710afb5b2b2b832b960c11b604482015260640162000083565b600081606001516001600160681b031611620001635760405162461bcd60e51b81526020600482015260056024820152640215f6361760dc1b604482015260640162000083565b60208101516001600160a01b0316620001a95760405162461bcd60e51b81526020600482015260076024820152660857d85cdcd95d60ca1b604482015260640162000083565b6001600160a01b03948516608052601180546001600160a01b0319169486169490941790935550508051600b80546020840151604085015160ff9094166001600160a81b03199092169190911761010091909516029390931766ffffffffffffff60a81b1916600160a81b66ffffffffffffff909216919091021790915560600151600c80546001600160681b0319166001600160681b03909216919091179055600d805461ffff1916600117905562000668565b600780546001600160a01b031916905562000279816200027c565b50565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b80516001600160a01b0381168114620002e657600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715620003265762000326620002eb565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620003575762000357620002eb565b604052919050565b600082601f8301126200037157600080fd5b81516001600160401b038111156200038d576200038d620002eb565b6020620003a3601f8301601f191682016200032c565b8281528582848701011115620003b857600080fd5b60005b83811015620003d8578581018301518282018401528201620003bb565b506000928101909101919091529392505050565b60008060008060008587036101008112156200040757600080fd5b6200041287620002ce565b95506200042260208801620002ce565b60408801519095506001600160401b03808211156200044057600080fd5b6200044e8a838b016200035f565b955060608901519150808211156200046557600080fd5b506200047489828a016200035f565b9350506080607f19820112156200048a57600080fd5b506200049562000301565b608087015160ff81168114620004aa57600080fd5b8152620004ba60a08801620002ce565b602082015260c087015166ffffffffffffff81168114620004da57600080fd5b604082015260e08701516001600160681b0381168114620004fa57600080fd5b6060820152949793965091945092919050565b600181811c908216806200052257607f821691505b6020821081036200054357634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200059757600081815260208120601f850160051c81016020861015620005725750805b601f850160051c820191505b8181101562000593578281556001016200057e565b5050505b505050565b81516001600160401b03811115620005b857620005b8620002eb565b620005d081620005c984546200050d565b8462000549565b602080601f831160018114620006085760008415620005ef5750858301515b600019600386901b1c1916600185901b17855562000593565b600085815260208120601f198616915b82811015620006395788860151825594840194600190910190840162000618565b5085821015620006585787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6080516135cc620006b5600039600081816108fa01528181611a2d01528181611aa701528181611ce601528181611dd601528181611e50015281816122b801526122f401526135cc6000f3fe6080604052600436106103035760003560e01c80637cb6475911610190578063ce7c2ac2116100dc578063eae1f26511610095578063f6203e351161006f578063f6203e3514610aa9578063f6326fb314610abc578063f656ba5114610ac4578063f756fa2114610af957600080fd5b8063eae1f26514610a56578063f0b2c7e614610a69578063f2fde38b14610a8957600080fd5b8063ce7c2ac214610971578063d164cc1514610991578063db006a75146109b1578063dc9a1535146109d1578063dd62ed3e146109f2578063e30c397814610a3857600080fd5b80639fcc2d7511610149578063ad5c464811610123578063ad5c4648146108e8578063ad7a672f1461091c578063b6b55f2514610931578063c0ce93f11461095157600080fd5b80639fcc2d751461081d578063a9059cbb146108a8578063aced1661146108c857600080fd5b80637cb64759146107545780637e108d521461077457806387153eb1146107945780638da5cb5b146107c157806395d89b41146107f357806399530b061461080857600080fd5b80633aa03f171161024f5780635cbcec4e1161020857806370a08231116101e257806370a0823114610690578063715018a6146106c657806379ba5097146106db5780637a9262a2146106f057600080fd5b80635cbcec4e146105d75780636719b2ee146105f75780636f31ab341461067b57600080fd5b80633aa03f171461052d5780633f23bb731461054d5780633f90916a1461056d57806347786d371461058b5780634b2431d9146105ab578063503c70aa146105c157600080fd5b80632775d01c116102bc5780633340d73c116102965780633340d73c146104af578063355274ea146104cf57806336efd16f146104ed57806338bca7261461050d57600080fd5b80632775d01c146104555780632eb4a7ab14610477578063313ce5671461048d57600080fd5b806306fdde031461030f578063095ea7b31461033a578063146ca5311461036a57806318160ddd1461038d57806323b872dd146103a25780632728f333146103c257600080fd5b3661030a57005b600080fd5b34801561031b57600080fd5b50610324610b0e565b6040516103319190612fb4565b60405180910390f35b34801561034657600080fd5b5061035a610355366004613003565b610ba0565b6040519015158152602001610331565b34801561037657600080fd5b50600d5461ffff165b604051908152602001610331565b34801561039957600080fd5b5060035461037f565b3480156103ae57600080fd5b5061035a6103bd36600461302d565b610bba565b3480156103ce57600080fd5b50600d54600e546104109161ffff8116916001600160681b03620100008304811692600160781b900416906001600160801b0380821691600160801b90041685565b6040805161ffff90961686526001600160681b03948516602087015293909216928401929092526001600160801b03918216606084015216608082015260a001610331565b34801561046157600080fd5b50610475610470366004613069565b610be0565b005b34801561048357600080fd5b5061037f60125481565b34801561049957600080fd5b50600b5460405160ff9091168152602001610331565b3480156104bb57600080fd5b506104756104ca366004613133565b610d73565b3480156104db57600080fd5b50600c546001600160681b031661037f565b3480156104f957600080fd5b5061047561050836600461317a565b610e65565b34801561051957600080fd5b50610475610528366004613069565b610f02565b34801561053957600080fd5b5061037f610548366004613069565b611298565b34801561055957600080fd5b5061037f6105683660046131a6565b611366565b34801561057957600080fd5b50600e546001600160801b031661037f565b34801561059757600080fd5b506104756105a6366004613069565b6113ab565b3480156105b757600080fd5b5061037f60105481565b3480156105cd57600080fd5b5061037f600f5481565b3480156105e357600080fd5b506104756105f23660046131cf565b611464565b34801561060357600080fd5b5061064a6106123660046131a6565b60086020526000908152604090205461ffff8116906201000081046001600160681b031690600160781b90046001600160801b031683565b6040805161ffff90941684526001600160681b0390921660208401526001600160801b031690820152606001610331565b34801561068757600080fd5b5061047561148a565b34801561069c57600080fd5b5061037f6106ab3660046131a6565b6001600160a01b031660009081526001602052604090205490565b3480156106d257600080fd5b506104756114aa565b3480156106e757600080fd5b506104756114bc565b3480156106fc57600080fd5b5061073261070b3660046131a6565b600a6020526000908152604090205461ffff8116906201000090046001600160801b031682565b6040805161ffff90931683526001600160801b03909116602083015201610331565b34801561076057600080fd5b5061047561076f366004613069565b6114fd565b34801561078057600080fd5b5061047561078f366004613069565b61150a565b3480156107a057600080fd5b5061037f6107af366004613069565b60096020526000908152604090205481565b3480156107cd57600080fd5b506006546001600160a01b03165b6040516001600160a01b039091168152602001610331565b3480156107ff57600080fd5b50610324611713565b34801561081457600080fd5b5061037f611722565b34801561082957600080fd5b50600b54600c546108659160ff81169161010082046001600160a01b031691600160a81b900466ffffffffffffff16906001600160681b031684565b6040805160ff90951685526001600160a01b03909316602085015266ffffffffffffff909116918301919091526001600160681b03166060820152608001610331565b3480156108b457600080fd5b5061035a6108c3366004613003565b611757565b3480156108d457600080fd5b506011546107db906001600160a01b031681565b3480156108f457600080fd5b506107db7f000000000000000000000000000000000000000000000000000000000000000081565b34801561092857600080fd5b5061037f611765565b34801561093d57600080fd5b5061047561094c366004613069565b6117f3565b34801561095d57600080fd5b5061035a61096c3660046131ec565b611875565b34801561097d57600080fd5b5061037f61098c3660046131a6565b6118d3565b34801561099d57600080fd5b506104756109ac3660046131a6565b6118f0565b3480156109bd57600080fd5b506104756109cc366004613069565b61195d565b3480156109dd57600080fd5b5060115461035a90600160a01b900460ff1681565b3480156109fe57600080fd5b5061037f610a0d366004613224565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b348015610a4457600080fd5b506007546001600160a01b03166107db565b610475610a6436600461324e565b6119ad565b348015610a7557600080fd5b50610475610a84366004613283565b611b23565b348015610a9557600080fd5b50610475610aa43660046131a6565b611c3f565b610475610ab73660046131a6565b611cb0565b610475611da0565b348015610ad057600080fd5b50610ae4610adf3660046131a6565b611ecc565b60408051928352602083019190915201610331565b348015610b0557600080fd5b50610475611faa565b606060048054610b1d90613324565b80601f0160208091040260200160405190810160405280929190818152602001828054610b4990613324565b8015610b965780601f10610b6b57610100808354040283529160200191610b96565b820191906000526020600020905b815481529060010190602001808311610b7957829003601f168201915b5050505050905090565b600033610bae818585612189565b60019150505b92915050565b600033610bc885828561219b565b610bd3858585612219565b60019150505b9392505050565b610be8612278565b336000908152600860205260409020600d5461ffff1682610c245760405162461bcd60e51b8152600401610c1b9061335e565b60405180910390fd5b815461ffff168114610c685760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081c9bdd5b99609a1b6044820152606401610c1b565b81546201000090046001600160681b031683811015610cb95760405162461bcd60e51b815260206004820152600d60248201526c115e18d9595908185b5bdd5b9d609a1b6044820152606401610c1b565b610cc38482613395565b83546001600160681b0391909116620100000262010000600160781b0319909116178355600e54610cfe9085906001600160801b0316613395565b600e80546001600160801b0319166001600160801b0392909216919091179055604080518581526020810184905233917fab2daf3c146ca6416cbccd2a86ed2ba995e171ef6319df14a38aef01403a9c96910160405180910390a2610d6333856122a2565b505050610d706001600055565b50565b610d7b612278565b601154600160a01b900460ff16610e10576012546040516001600160601b03193360601b166020820152610dd491906034015b60405160208183030381529060405280519060200120836124089092919063ffffffff16565b610e105760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610c1b565b60008211610e305760405162461bcd60e51b8152600401610c1b9061335e565b610e3a823361244a565b600b54610e579061010090046001600160a01b03163330856126d8565b610e616001600055565b5050565b610e6d612278565b601154600160a01b900460ff16610e965760405162461bcd60e51b8152600401610c1b906133a8565b60008211610eb65760405162461bcd60e51b8152600401610c1b9061335e565b6001600160a01b038116610ef85760405162461bcd60e51b815260206004820152600960248201526810b1b932b234ba37b960b91b6044820152606401610c1b565b610e3a828261244a565b6011546001600160a01b03163314610f465760405162461bcd60e51b815260206004820152600760248201526610b5b2b2b832b960c91b6044820152606401610c1b565b610f4e612278565b600b54600160a81b900466ffffffffffffff16811015610fa75760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c1b565b6040805160a081018252600d5461ffff81168083526001600160681b0362010000830481166020850152600160781b90920490911692820192909252600e546001600160801b038082166060840152600160801b909104166080820181905290919060009061104c9061101960035490565b6110239190613395565b600f546110309087613395565b6060860151600b546001600160801b039091169060ff1661273f565b60008381526009602090815260409182902083905581518581529081018390529081018690529091507f509ab3a60bcf0e5158f6bdabea90d540867b8a80428adae5bad92fe0a7e604d19060600160405180910390a1600e80546001600160801b03191690556110bd8260016133c9565b600d805461ffff191661ffff929092169190911790556060830151600b546000916110f8916001600160801b0390911690849060ff16612786565b905061110430826127f0565b601054600b5460009161111b91859060ff16612826565b600f5461112891906133c9565b905080600f81905550600060105486608001516001600160801b031661114e91906133c9565b905061115981612885565b600e80546001600160801b03808416600160801b029116179055600060108190556020870151600d80546001600160681b03909216600160781b026cffffffffffffffffffffffffff60781b199092169190911790556111b98389613395565b90506111c4816128cf565b600d805462010000600160781b031916620100006001600160681b03841602179055601154600b546040516370a0823160e01b8152306004820152611287926001600160a01b03908116928792610100909104909116906370a0823190602401602060405180830381865afa158015611241573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126591906133dc565b61126f9190613395565b600b5461010090046001600160a01b03169190612919565b50505050505050610d706001600055565b6040805160a081018252600d5461ffff811682526001600160681b0362010000820481166020840152600160781b9091041691810191909152600e546001600160801b038082166060840152600160801b909104166080820181905260009190829061133a9061130760035490565b6113119190613395565b600f5461131e9087613395565b6060850151600b546001600160801b039091169060ff1661273f565b601054600b5491925061135191839060ff16612826565b600f5461135e91906133c9565b949350505050565b600b5460009060ff168161139661137c60035490565b611384611765565b600e546001600160801b03168561273f565b905061135e6113a4856118d3565b8284612826565b6113b361294a565b600081116113ed5760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b6044820152606401610c1b565b6113f6816128cf565b600c54604080516001600160681b039092168252602082018390527f5f86edbb9d92228a9edc3f0ebc0f001bda1ea345ac7335e0eeef3504b31d1a1c910160405180910390a1600c80546cffffffffffffffffffffffffff19166001600160681b0392909216919091179055565b61146c61294a565b60118054911515600160a01b0260ff60a01b19909216919091179055565b611492612278565b61149e60006001612977565b6114a86001600055565b565b6114b261294a565b6114a86000612b24565b60075433906001600160a01b031681146114f45760405163118cdaa760e01b81526001600160a01b0382166004820152602401610c1b565b610d7081612b24565b61150561294a565b601255565b611512612278565b6000811161154f5760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b6044820152606401610c1b565b336000908152600860205260409020546201000090046001600160681b0316151580611599575033600090815260086020526040902054600160781b90046001600160801b031615155b156115aa576115aa60006001612977565b600d54336000818152600a602090815260409182902082518084018452905461ffff808216808452620100009092046001600160801b0316838501528451888152961692860183905291949093918514927f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a260208201516001600160801b03166000821561164d5761164686836133c9565b90506116b0565b811561168f5760405162461bcd60e51b81526020600482015260116024820152704578697374696e6720776974686472617760781b6044820152606401610c1b565b50336000908152600a60205260409020805461ffff191661ffff8616179055845b6116b981612885565b336000818152600a60205260409020805462010000600160901b031916620100006001600160801b038516021790556116f3903088612219565b8560105461170191906133c9565b60105550610d70935061240192505050565b606060058054610b1d90613324565b600061175261173060035490565b611738611765565b600e54600b546001600160801b039091169060ff1661273f565b905090565b600033610bae818585612219565b600b546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa1580156117b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d791906133dc565b600d5461175291906201000090046001600160681b03166133c9565b6117fb612278565b601154600160a01b900460ff166118245760405162461bcd60e51b8152600401610c1b906133a8565b600081116118445760405162461bcd60e51b8152600401610c1b9061335e565b61184e813361244a565b600b5461186b9061010090046001600160a01b03163330846126d8565b610d706001600055565b601154600090600160a01b900460ff1680610bd957506012546040516001600160601b0319606086901b166020820152610bd9919060340160405160208183030381529060405280519060200120846124089092919063ffffffff16565b60008060006118e184611ecc565b909250905061135e81836133c9565b6118f861294a565b6001600160a01b03811661193b5760405162461bcd60e51b815260206004820152600a60248201526910b732bba5b2b2b832b960b11b6044820152606401610c1b565b601180546001600160a01b0319166001600160a01b0392909216919091179055565b611965612278565b600081116119a25760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b6044820152606401610c1b565b61186b816000612977565b6119b5612278565b601154600160a01b900460ff16611a28576012546040516001600160601b03193360601b1660208201526119ec9190603401610dae565b611a285760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610c1b565b600b547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166101009092041614611a7b5760405162461bcd60e51b8152600401610c1b906133f5565b60003411611a9b5760405162461bcd60e51b8152600401610c1b90613414565b611aa5343361244a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0057600080fd5b505af1158015611b14573d6000803e3d6000fd5b5050505050610d706001600055565b611b2b61294a565b600081606001516001600160681b031611611b725760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b6044820152606401610c1b565b60208101516001600160a01b0316611bb85760405162461bcd60e51b8152602060048201526009602482015268085b995dd05cdcd95d60ba1b6044820152606401610c1b565b8051600b80546020840151604085015166ffffffffffffff16600160a81b0266ffffffffffffff60a81b196001600160a01b03909216610100026001600160a81b031990931660ff90951694909417919091171691909117905560600151600c80546001600160681b039092166cffffffffffffffffffffffffff19909216919091179055565b611c4761294a565b600780546001600160a01b0383166001600160a01b03199091168117909155611c786006546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611cb8612278565b601154600160a01b900460ff16611ce15760405162461bcd60e51b8152600401610c1b906133a8565b600b547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166101009092041614611d345760405162461bcd60e51b8152600401610c1b906133f5565b60003411611d545760405162461bcd60e51b8152600401610c1b90613414565b6001600160a01b038116611d965760405162461bcd60e51b815260206004820152600960248201526810b1b932b234ba37b960b91b6044820152606401610c1b565b611aa5348261244a565b611da8612278565b601154600160a01b900460ff16611dd15760405162461bcd60e51b8152600401610c1b906133a8565b600b547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166101009092041614611e245760405162461bcd60e51b8152600401610c1b906133f5565b60003411611e445760405162461bcd60e51b8152600401610c1b90613414565b611e4e343361244a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611ea957600080fd5b505af1158015611ebd573d6000803e3d6000fd5b50505050506114a86001600055565b6001600160a01b03811660009081526008602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031694830194909452600160781b90046001600160801b031691810191909152829160011115611f4e575050506001600160a01b031660009081526001602052604081205491565b600d54815161ffff908116600090815260096020526040812054600b549193611f7f9386939116919060ff16612b3d565b9050611fa0856001600160a01b031660009081526001602052604090205490565b9590945092505050565b611fb2612278565b336000908152600a6020526040902080546001600160801b03620100008204169061ffff16816120145760405162461bcd60e51b815260206004820152600d60248201526c139bdd081a5b9a5d1a585d1959609a1b6044820152606401610c1b565b600d5461ffff16811061205c5760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b6044820152606401610c1b565b336000908152600a60205260409020805462010000600160901b0319169055600e54612099908390600160801b90046001600160801b0316613395565b600e80546001600160801b03928316600160801b029216919091179055600081815260096020526040812054600b546120d691859160ff16612826565b604080518281526020810186905291925033917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a261211e3084612bae565b600081116121605760405162461bcd60e51b815260206004820152600f60248201526e085dda5d1a191c985dd05b5bdd5b9d608a1b6044820152606401610c1b565b61216a33826122a2565b80600f546121789190613395565b600f55506114a89250612401915050565b6121968383836001612be4565b505050565b6001600160a01b038381166000908152600260209081526040808320938616835292905220546000198114612213578181101561220457604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610c1b565b61221384848484036000612be4565b50505050565b6001600160a01b03831661224357604051634b637e8f60e11b815260006004820152602401610c1b565b6001600160a01b03821661226d5760405163ec442f0560e01b815260006004820152602401610c1b565b612196838383612cb9565b60026000540361229b57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b600b546001600160a01b036101009091048116907f00000000000000000000000000000000000000000000000000000000000000001681036123ed57604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50509050806122135760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610c1b565b6121966001600160a01b0382168484612919565b6001600055565b60008351156124435760208401845160051b81015b8151841160051b93845281516020948518526040600020939091019080821061241d5750505b5014919050565b600d5461ffff1660008361245c611765565b61246691906133c9565b600c549091506001600160681b03168111156124b15760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b6044820152606401610c1b565b600b54600160a81b900466ffffffffffffff1681101561250a5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c1b565b60408051858152602081018490526001600160a01b038516917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a26001600160a01b03831660009081526008602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031683860152600160781b9091046001600160801b03168284015284526009909252822054600b549192916125c491849187919060ff16612b3d565b8251909150869061ffff1685036125f45760008784602001516001600160681b03166125f091906133c9565b9150505b6125fd816128cf565b6040805160608101825261ffff80881682526001600160681b0380851660208085019182526001600160801b038089168688019081526001600160a01b038e166000908152600890935296822095518654935197518216600160781b02600160781b600160f81b03199890951662010000026effffffffffffffffffffffffffffff19909416951694909417919091179490941617909155600e546126a4918a91166133c9565b90506126af81612885565b600e80546001600160801b0319166001600160801b039290921691909117905550505050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526122139186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612de3565b60008061274d83600a613518565b90506000861161275d578061277c565b856127688587613395565b6127729083613524565b61277c919061353b565b9695505050505050565b6000600183116127d05760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610c1b565b826127dc83600a613518565b6127e69086613524565b61135e919061353b565b6001600160a01b03821661281a5760405163ec442f0560e01b815260006004820152602401610c1b565b610e6160008383612cb9565b6000600183116128705760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610c1b565b61287b82600a613518565b6127e68486613524565b6001600160801b03811115610d705760405162461bcd60e51b815260206004820152601060248201526f09eeccae4ccd8deee40ead2dce86264760831b6044820152606401610c1b565b6001600160681b03811115610d705760405162461bcd60e51b815260206004820152601060248201526f13dd995c999b1bddc81d5a5b9d0c4c0d60821b6044820152606401610c1b565b6040516001600160a01b0383811660248301526044820183905261219691859182169063a9059cbb9060640161270d565b6006546001600160a01b031633146114a85760405163118cdaa760e01b8152336004820152602401610c1b565b3360009081526008602090815260408083208151606081018352905461ffff8082168084526201000083046001600160681b031684870152600160781b9092046001600160801b031683850152600d54918652600990945291842054600b54919492909316926129ed918591859160ff16612b3d565b9050836129fa57846129fc565b805b945084600003612a0d575050505050565b80851115612a515760405162461bcd60e51b81526020600482015260116024820152704578636565647320617661696c61626c6560781b6044820152606401610c1b565b825161ffff16821115612a7e57336000908152600860205260409020805462010000600160781b03191690555b612a8785612885565b612a918582613395565b336000818152600860205260409081902080546001600160801b0394909416600160781b02600160781b600160f81b0319909416939093179092558451915190917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92991612b0a9189825261ffff16602082015260400190565b60405180910390a2612b1d303387612219565b5050505050565b600780546001600160a01b0319169055610d7081612e46565b835160009061ffff1615801590612b585750845161ffff1684115b15612b9a576000612b7786602001516001600160681b03168585612786565b90508086604001516001600160801b0316612b9291906133c9565b91505061135e565b50505050604001516001600160801b031690565b6001600160a01b038216612bd857604051634b637e8f60e11b815260006004820152602401610c1b565b610e6182600083612cb9565b6001600160a01b038416612c0e5760405163e602df0560e01b815260006004820152602401610c1b565b6001600160a01b038316612c3857604051634a1406b160e11b815260006004820152602401610c1b565b6001600160a01b038085166000908152600260209081526040808320938716835292905220829055801561221357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051612cab91815260200190565b60405180910390a350505050565b6001600160a01b038316612ce4578060036000828254612cd991906133c9565b90915550612d569050565b6001600160a01b03831660009081526001602052604090205481811015612d375760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610c1b565b6001600160a01b03841660009081526001602052604090209082900390555b6001600160a01b038216612d7257600380548290039055612d91565b6001600160a01b03821660009081526001602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612dd691815260200190565b60405180910390a3505050565b6000612df86001600160a01b03841683612e98565b90508051600014158015612e1d575080806020019051810190612e1b919061355d565b155b1561219657604051635274afe760e01b81526001600160a01b0384166004820152602401610c1b565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060610bd98383600084600080856001600160a01b03168486604051612ebe919061357a565b60006040518083038185875af1925050503d8060008114612efb576040519150601f19603f3d011682016040523d82523d6000602084013e612f00565b606091505b509150915061277c868383606082612f2057612f1b82612f67565b610bd9565b8151158015612f3757506001600160a01b0384163b155b15612f6057604051639996b31560e01b81526001600160a01b0385166004820152602401610c1b565b5080610bd9565b805115612f775780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b60005b83811015612fab578181015183820152602001612f93565b50506000910152565b6020815260008251806020840152612fd3816040850160208701612f90565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114612ffe57600080fd5b919050565b6000806040838503121561301657600080fd5b61301f83612fe7565b946020939093013593505050565b60008060006060848603121561304257600080fd5b61304b84612fe7565b925061305960208501612fe7565b9150604084013590509250925092565b60006020828403121561307b57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126130a957600080fd5b8135602067ffffffffffffffff808311156130c6576130c6613082565b8260051b604051601f19603f830116810181811084821117156130eb576130eb613082565b60405293845285810183019383810192508785111561310957600080fd5b83870191505b848210156131285781358352918301919083019061310f565b979650505050505050565b6000806040838503121561314657600080fd5b82359150602083013567ffffffffffffffff81111561316457600080fd5b61317085828601613098565b9150509250929050565b6000806040838503121561318d57600080fd5b8235915061319d60208401612fe7565b90509250929050565b6000602082840312156131b857600080fd5b610bd982612fe7565b8015158114610d7057600080fd5b6000602082840312156131e157600080fd5b8135610bd9816131c1565b600080604083850312156131ff57600080fd5b61320883612fe7565b9150602083013567ffffffffffffffff81111561316457600080fd5b6000806040838503121561323757600080fd5b61324083612fe7565b915061319d60208401612fe7565b60006020828403121561326057600080fd5b813567ffffffffffffffff81111561327757600080fd5b61135e84828501613098565b60006080828403121561329557600080fd5b6040516080810181811067ffffffffffffffff821117156132b8576132b8613082565b604052823560ff811681146132cc57600080fd5b81526132da60208401612fe7565b6020820152604083013566ffffffffffffff811681146132f957600080fd5b604082015260608301356001600160681b038116811461331857600080fd5b60608201529392505050565b600181811c9082168061333857607f821691505b60208210810361335857634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526007908201526608585b5bdd5b9d60ca1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bb457610bb461337f565b602080825260079082015266217075626c696360c81b604082015260600190565b80820180821115610bb457610bb461337f565b6000602082840312156133ee57600080fd5b5051919050565b602080825260059082015264042ae8aa8960db1b604082015260600190565b6020808252600690820152652176616c756560d01b604082015260600190565b600181815b8085111561346f5781600019048211156134555761345561337f565b8085161561346257918102915b93841c9390800290613439565b509250929050565b60008261348657506001610bb4565b8161349357506000610bb4565b81600181146134a957600281146134b3576134cf565b6001915050610bb4565b60ff8411156134c4576134c461337f565b50506001821b610bb4565b5060208310610133831016604e8410600b84101617156134f2575081810a610bb4565b6134fc8383613434565b80600019048211156135105761351061337f565b029392505050565b6000610bd98383613477565b8082028115828204841417610bb457610bb461337f565b60008261355857634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561356f57600080fd5b8151610bd9816131c1565b6000825161358c818460208701612f90565b919091019291505056fea264697066735822122034e09cf2404bf3252671f6001b4992c9b7bedde936154d87fa666a3afc41bdd864736f6c63430008140033000000000000000000000000420000000000000000000000000000000000000600000000000000000000000058abe9162e77a2bff179182cebefb9dda3135fe0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000012000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000000000000000000000105468656f4554485368617265383435330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085445544838343533000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106103035760003560e01c80637cb6475911610190578063ce7c2ac2116100dc578063eae1f26511610095578063f6203e351161006f578063f6203e3514610aa9578063f6326fb314610abc578063f656ba5114610ac4578063f756fa2114610af957600080fd5b8063eae1f26514610a56578063f0b2c7e614610a69578063f2fde38b14610a8957600080fd5b8063ce7c2ac214610971578063d164cc1514610991578063db006a75146109b1578063dc9a1535146109d1578063dd62ed3e146109f2578063e30c397814610a3857600080fd5b80639fcc2d7511610149578063ad5c464811610123578063ad5c4648146108e8578063ad7a672f1461091c578063b6b55f2514610931578063c0ce93f11461095157600080fd5b80639fcc2d751461081d578063a9059cbb146108a8578063aced1661146108c857600080fd5b80637cb64759146107545780637e108d521461077457806387153eb1146107945780638da5cb5b146107c157806395d89b41146107f357806399530b061461080857600080fd5b80633aa03f171161024f5780635cbcec4e1161020857806370a08231116101e257806370a0823114610690578063715018a6146106c657806379ba5097146106db5780637a9262a2146106f057600080fd5b80635cbcec4e146105d75780636719b2ee146105f75780636f31ab341461067b57600080fd5b80633aa03f171461052d5780633f23bb731461054d5780633f90916a1461056d57806347786d371461058b5780634b2431d9146105ab578063503c70aa146105c157600080fd5b80632775d01c116102bc5780633340d73c116102965780633340d73c146104af578063355274ea146104cf57806336efd16f146104ed57806338bca7261461050d57600080fd5b80632775d01c146104555780632eb4a7ab14610477578063313ce5671461048d57600080fd5b806306fdde031461030f578063095ea7b31461033a578063146ca5311461036a57806318160ddd1461038d57806323b872dd146103a25780632728f333146103c257600080fd5b3661030a57005b600080fd5b34801561031b57600080fd5b50610324610b0e565b6040516103319190612fb4565b60405180910390f35b34801561034657600080fd5b5061035a610355366004613003565b610ba0565b6040519015158152602001610331565b34801561037657600080fd5b50600d5461ffff165b604051908152602001610331565b34801561039957600080fd5b5060035461037f565b3480156103ae57600080fd5b5061035a6103bd36600461302d565b610bba565b3480156103ce57600080fd5b50600d54600e546104109161ffff8116916001600160681b03620100008304811692600160781b900416906001600160801b0380821691600160801b90041685565b6040805161ffff90961686526001600160681b03948516602087015293909216928401929092526001600160801b03918216606084015216608082015260a001610331565b34801561046157600080fd5b50610475610470366004613069565b610be0565b005b34801561048357600080fd5b5061037f60125481565b34801561049957600080fd5b50600b5460405160ff9091168152602001610331565b3480156104bb57600080fd5b506104756104ca366004613133565b610d73565b3480156104db57600080fd5b50600c546001600160681b031661037f565b3480156104f957600080fd5b5061047561050836600461317a565b610e65565b34801561051957600080fd5b50610475610528366004613069565b610f02565b34801561053957600080fd5b5061037f610548366004613069565b611298565b34801561055957600080fd5b5061037f6105683660046131a6565b611366565b34801561057957600080fd5b50600e546001600160801b031661037f565b34801561059757600080fd5b506104756105a6366004613069565b6113ab565b3480156105b757600080fd5b5061037f60105481565b3480156105cd57600080fd5b5061037f600f5481565b3480156105e357600080fd5b506104756105f23660046131cf565b611464565b34801561060357600080fd5b5061064a6106123660046131a6565b60086020526000908152604090205461ffff8116906201000081046001600160681b031690600160781b90046001600160801b031683565b6040805161ffff90941684526001600160681b0390921660208401526001600160801b031690820152606001610331565b34801561068757600080fd5b5061047561148a565b34801561069c57600080fd5b5061037f6106ab3660046131a6565b6001600160a01b031660009081526001602052604090205490565b3480156106d257600080fd5b506104756114aa565b3480156106e757600080fd5b506104756114bc565b3480156106fc57600080fd5b5061073261070b3660046131a6565b600a6020526000908152604090205461ffff8116906201000090046001600160801b031682565b6040805161ffff90931683526001600160801b03909116602083015201610331565b34801561076057600080fd5b5061047561076f366004613069565b6114fd565b34801561078057600080fd5b5061047561078f366004613069565b61150a565b3480156107a057600080fd5b5061037f6107af366004613069565b60096020526000908152604090205481565b3480156107cd57600080fd5b506006546001600160a01b03165b6040516001600160a01b039091168152602001610331565b3480156107ff57600080fd5b50610324611713565b34801561081457600080fd5b5061037f611722565b34801561082957600080fd5b50600b54600c546108659160ff81169161010082046001600160a01b031691600160a81b900466ffffffffffffff16906001600160681b031684565b6040805160ff90951685526001600160a01b03909316602085015266ffffffffffffff909116918301919091526001600160681b03166060820152608001610331565b3480156108b457600080fd5b5061035a6108c3366004613003565b611757565b3480156108d457600080fd5b506011546107db906001600160a01b031681565b3480156108f457600080fd5b506107db7f000000000000000000000000420000000000000000000000000000000000000681565b34801561092857600080fd5b5061037f611765565b34801561093d57600080fd5b5061047561094c366004613069565b6117f3565b34801561095d57600080fd5b5061035a61096c3660046131ec565b611875565b34801561097d57600080fd5b5061037f61098c3660046131a6565b6118d3565b34801561099d57600080fd5b506104756109ac3660046131a6565b6118f0565b3480156109bd57600080fd5b506104756109cc366004613069565b61195d565b3480156109dd57600080fd5b5060115461035a90600160a01b900460ff1681565b3480156109fe57600080fd5b5061037f610a0d366004613224565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b348015610a4457600080fd5b506007546001600160a01b03166107db565b610475610a6436600461324e565b6119ad565b348015610a7557600080fd5b50610475610a84366004613283565b611b23565b348015610a9557600080fd5b50610475610aa43660046131a6565b611c3f565b610475610ab73660046131a6565b611cb0565b610475611da0565b348015610ad057600080fd5b50610ae4610adf3660046131a6565b611ecc565b60408051928352602083019190915201610331565b348015610b0557600080fd5b50610475611faa565b606060048054610b1d90613324565b80601f0160208091040260200160405190810160405280929190818152602001828054610b4990613324565b8015610b965780601f10610b6b57610100808354040283529160200191610b96565b820191906000526020600020905b815481529060010190602001808311610b7957829003601f168201915b5050505050905090565b600033610bae818585612189565b60019150505b92915050565b600033610bc885828561219b565b610bd3858585612219565b60019150505b9392505050565b610be8612278565b336000908152600860205260409020600d5461ffff1682610c245760405162461bcd60e51b8152600401610c1b9061335e565b60405180910390fd5b815461ffff168114610c685760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081c9bdd5b99609a1b6044820152606401610c1b565b81546201000090046001600160681b031683811015610cb95760405162461bcd60e51b815260206004820152600d60248201526c115e18d9595908185b5bdd5b9d609a1b6044820152606401610c1b565b610cc38482613395565b83546001600160681b0391909116620100000262010000600160781b0319909116178355600e54610cfe9085906001600160801b0316613395565b600e80546001600160801b0319166001600160801b0392909216919091179055604080518581526020810184905233917fab2daf3c146ca6416cbccd2a86ed2ba995e171ef6319df14a38aef01403a9c96910160405180910390a2610d6333856122a2565b505050610d706001600055565b50565b610d7b612278565b601154600160a01b900460ff16610e10576012546040516001600160601b03193360601b166020820152610dd491906034015b60405160208183030381529060405280519060200120836124089092919063ffffffff16565b610e105760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610c1b565b60008211610e305760405162461bcd60e51b8152600401610c1b9061335e565b610e3a823361244a565b600b54610e579061010090046001600160a01b03163330856126d8565b610e616001600055565b5050565b610e6d612278565b601154600160a01b900460ff16610e965760405162461bcd60e51b8152600401610c1b906133a8565b60008211610eb65760405162461bcd60e51b8152600401610c1b9061335e565b6001600160a01b038116610ef85760405162461bcd60e51b815260206004820152600960248201526810b1b932b234ba37b960b91b6044820152606401610c1b565b610e3a828261244a565b6011546001600160a01b03163314610f465760405162461bcd60e51b815260206004820152600760248201526610b5b2b2b832b960c91b6044820152606401610c1b565b610f4e612278565b600b54600160a81b900466ffffffffffffff16811015610fa75760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c1b565b6040805160a081018252600d5461ffff81168083526001600160681b0362010000830481166020850152600160781b90920490911692820192909252600e546001600160801b038082166060840152600160801b909104166080820181905290919060009061104c9061101960035490565b6110239190613395565b600f546110309087613395565b6060860151600b546001600160801b039091169060ff1661273f565b60008381526009602090815260409182902083905581518581529081018390529081018690529091507f509ab3a60bcf0e5158f6bdabea90d540867b8a80428adae5bad92fe0a7e604d19060600160405180910390a1600e80546001600160801b03191690556110bd8260016133c9565b600d805461ffff191661ffff929092169190911790556060830151600b546000916110f8916001600160801b0390911690849060ff16612786565b905061110430826127f0565b601054600b5460009161111b91859060ff16612826565b600f5461112891906133c9565b905080600f81905550600060105486608001516001600160801b031661114e91906133c9565b905061115981612885565b600e80546001600160801b03808416600160801b029116179055600060108190556020870151600d80546001600160681b03909216600160781b026cffffffffffffffffffffffffff60781b199092169190911790556111b98389613395565b90506111c4816128cf565b600d805462010000600160781b031916620100006001600160681b03841602179055601154600b546040516370a0823160e01b8152306004820152611287926001600160a01b03908116928792610100909104909116906370a0823190602401602060405180830381865afa158015611241573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126591906133dc565b61126f9190613395565b600b5461010090046001600160a01b03169190612919565b50505050505050610d706001600055565b6040805160a081018252600d5461ffff811682526001600160681b0362010000820481166020840152600160781b9091041691810191909152600e546001600160801b038082166060840152600160801b909104166080820181905260009190829061133a9061130760035490565b6113119190613395565b600f5461131e9087613395565b6060850151600b546001600160801b039091169060ff1661273f565b601054600b5491925061135191839060ff16612826565b600f5461135e91906133c9565b949350505050565b600b5460009060ff168161139661137c60035490565b611384611765565b600e546001600160801b03168561273f565b905061135e6113a4856118d3565b8284612826565b6113b361294a565b600081116113ed5760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b6044820152606401610c1b565b6113f6816128cf565b600c54604080516001600160681b039092168252602082018390527f5f86edbb9d92228a9edc3f0ebc0f001bda1ea345ac7335e0eeef3504b31d1a1c910160405180910390a1600c80546cffffffffffffffffffffffffff19166001600160681b0392909216919091179055565b61146c61294a565b60118054911515600160a01b0260ff60a01b19909216919091179055565b611492612278565b61149e60006001612977565b6114a86001600055565b565b6114b261294a565b6114a86000612b24565b60075433906001600160a01b031681146114f45760405163118cdaa760e01b81526001600160a01b0382166004820152602401610c1b565b610d7081612b24565b61150561294a565b601255565b611512612278565b6000811161154f5760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b6044820152606401610c1b565b336000908152600860205260409020546201000090046001600160681b0316151580611599575033600090815260086020526040902054600160781b90046001600160801b031615155b156115aa576115aa60006001612977565b600d54336000818152600a602090815260409182902082518084018452905461ffff808216808452620100009092046001600160801b0316838501528451888152961692860183905291949093918514927f0c53c82ad07e2d592d88ece3b066777dd60f1118e2a081b380efc4358f0d9e2a910160405180910390a260208201516001600160801b03166000821561164d5761164686836133c9565b90506116b0565b811561168f5760405162461bcd60e51b81526020600482015260116024820152704578697374696e6720776974686472617760781b6044820152606401610c1b565b50336000908152600a60205260409020805461ffff191661ffff8616179055845b6116b981612885565b336000818152600a60205260409020805462010000600160901b031916620100006001600160801b038516021790556116f3903088612219565b8560105461170191906133c9565b60105550610d70935061240192505050565b606060058054610b1d90613324565b600061175261173060035490565b611738611765565b600e54600b546001600160801b039091169060ff1661273f565b905090565b600033610bae818585612219565b600b546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa1580156117b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d791906133dc565b600d5461175291906201000090046001600160681b03166133c9565b6117fb612278565b601154600160a01b900460ff166118245760405162461bcd60e51b8152600401610c1b906133a8565b600081116118445760405162461bcd60e51b8152600401610c1b9061335e565b61184e813361244a565b600b5461186b9061010090046001600160a01b03163330846126d8565b610d706001600055565b601154600090600160a01b900460ff1680610bd957506012546040516001600160601b0319606086901b166020820152610bd9919060340160405160208183030381529060405280519060200120846124089092919063ffffffff16565b60008060006118e184611ecc565b909250905061135e81836133c9565b6118f861294a565b6001600160a01b03811661193b5760405162461bcd60e51b815260206004820152600a60248201526910b732bba5b2b2b832b960b11b6044820152606401610c1b565b601180546001600160a01b0319166001600160a01b0392909216919091179055565b611965612278565b600081116119a25760405162461bcd60e51b815260206004820152600a602482015269216e756d53686172657360b01b6044820152606401610c1b565b61186b816000612977565b6119b5612278565b601154600160a01b900460ff16611a28576012546040516001600160601b03193360601b1660208201526119ec9190603401610dae565b611a285760405162461bcd60e51b815260206004820152600d60248201526c24b73b30b634b210383937b7b360991b6044820152606401610c1b565b600b547f00000000000000000000000042000000000000000000000000000000000000066001600160a01b039081166101009092041614611a7b5760405162461bcd60e51b8152600401610c1b906133f5565b60003411611a9b5760405162461bcd60e51b8152600401610c1b90613414565b611aa5343361244a565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b0057600080fd5b505af1158015611b14573d6000803e3d6000fd5b5050505050610d706001600055565b611b2b61294a565b600081606001516001600160681b031611611b725760405162461bcd60e51b81526020600482015260076024820152660216e65774361760cc1b6044820152606401610c1b565b60208101516001600160a01b0316611bb85760405162461bcd60e51b8152602060048201526009602482015268085b995dd05cdcd95d60ba1b6044820152606401610c1b565b8051600b80546020840151604085015166ffffffffffffff16600160a81b0266ffffffffffffff60a81b196001600160a01b03909216610100026001600160a81b031990931660ff90951694909417919091171691909117905560600151600c80546001600160681b039092166cffffffffffffffffffffffffff19909216919091179055565b611c4761294a565b600780546001600160a01b0383166001600160a01b03199091168117909155611c786006546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611cb8612278565b601154600160a01b900460ff16611ce15760405162461bcd60e51b8152600401610c1b906133a8565b600b547f00000000000000000000000042000000000000000000000000000000000000066001600160a01b039081166101009092041614611d345760405162461bcd60e51b8152600401610c1b906133f5565b60003411611d545760405162461bcd60e51b8152600401610c1b90613414565b6001600160a01b038116611d965760405162461bcd60e51b815260206004820152600960248201526810b1b932b234ba37b960b91b6044820152606401610c1b565b611aa5348261244a565b611da8612278565b601154600160a01b900460ff16611dd15760405162461bcd60e51b8152600401610c1b906133a8565b600b547f00000000000000000000000042000000000000000000000000000000000000066001600160a01b039081166101009092041614611e245760405162461bcd60e51b8152600401610c1b906133f5565b60003411611e445760405162461bcd60e51b8152600401610c1b90613414565b611e4e343361244a565b7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015611ea957600080fd5b505af1158015611ebd573d6000803e3d6000fd5b50505050506114a86001600055565b6001600160a01b03811660009081526008602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031694830194909452600160781b90046001600160801b031691810191909152829160011115611f4e575050506001600160a01b031660009081526001602052604081205491565b600d54815161ffff908116600090815260096020526040812054600b549193611f7f9386939116919060ff16612b3d565b9050611fa0856001600160a01b031660009081526001602052604090205490565b9590945092505050565b611fb2612278565b336000908152600a6020526040902080546001600160801b03620100008204169061ffff16816120145760405162461bcd60e51b815260206004820152600d60248201526c139bdd081a5b9a5d1a585d1959609a1b6044820152606401610c1b565b600d5461ffff16811061205c5760405162461bcd60e51b815260206004820152601060248201526f149bdd5b99081b9bdd0818db1bdcd95960821b6044820152606401610c1b565b336000908152600a60205260409020805462010000600160901b0319169055600e54612099908390600160801b90046001600160801b0316613395565b600e80546001600160801b03928316600160801b029216919091179055600081815260096020526040812054600b546120d691859160ff16612826565b604080518281526020810186905291925033917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a261211e3084612bae565b600081116121605760405162461bcd60e51b815260206004820152600f60248201526e085dda5d1a191c985dd05b5bdd5b9d608a1b6044820152606401610c1b565b61216a33826122a2565b80600f546121789190613395565b600f55506114a89250612401915050565b6121968383836001612be4565b505050565b6001600160a01b038381166000908152600260209081526040808320938616835292905220546000198114612213578181101561220457604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610c1b565b61221384848484036000612be4565b50505050565b6001600160a01b03831661224357604051634b637e8f60e11b815260006004820152602401610c1b565b6001600160a01b03821661226d5760405163ec442f0560e01b815260006004820152602401610c1b565b612196838383612cb9565b60026000540361229b57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b600b546001600160a01b036101009091048116907f00000000000000000000000042000000000000000000000000000000000000061681036123ed57604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000042000000000000000000000000000000000000066001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561234057600080fd5b505af1158015612354573d6000803e3d6000fd5b505050506000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146123a5576040519150601f19603f3d011682016040523d82523d6000602084013e6123aa565b606091505b50509050806122135760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b6044820152606401610c1b565b6121966001600160a01b0382168484612919565b6001600055565b60008351156124435760208401845160051b81015b8151841160051b93845281516020948518526040600020939091019080821061241d5750505b5014919050565b600d5461ffff1660008361245c611765565b61246691906133c9565b600c549091506001600160681b03168111156124b15760405162461bcd60e51b815260206004820152600a6024820152690457863656564206361760b41b6044820152606401610c1b565b600b54600160a81b900466ffffffffffffff1681101561250a5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610c1b565b60408051858152602081018490526001600160a01b038516917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a26001600160a01b03831660009081526008602090815260408083208151606081018352905461ffff81168083526201000082046001600160681b031683860152600160781b9091046001600160801b03168284015284526009909252822054600b549192916125c491849187919060ff16612b3d565b8251909150869061ffff1685036125f45760008784602001516001600160681b03166125f091906133c9565b9150505b6125fd816128cf565b6040805160608101825261ffff80881682526001600160681b0380851660208085019182526001600160801b038089168688019081526001600160a01b038e166000908152600890935296822095518654935197518216600160781b02600160781b600160f81b03199890951662010000026effffffffffffffffffffffffffffff19909416951694909417919091179490941617909155600e546126a4918a91166133c9565b90506126af81612885565b600e80546001600160801b0319166001600160801b039290921691909117905550505050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526122139186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612de3565b60008061274d83600a613518565b90506000861161275d578061277c565b856127688587613395565b6127729083613524565b61277c919061353b565b9695505050505050565b6000600183116127d05760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610c1b565b826127dc83600a613518565b6127e69086613524565b61135e919061353b565b6001600160a01b03821661281a5760405163ec442f0560e01b815260006004820152602401610c1b565b610e6160008383612cb9565b6000600183116128705760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206173736574506572536861726560581b6044820152606401610c1b565b61287b82600a613518565b6127e68486613524565b6001600160801b03811115610d705760405162461bcd60e51b815260206004820152601060248201526f09eeccae4ccd8deee40ead2dce86264760831b6044820152606401610c1b565b6001600160681b03811115610d705760405162461bcd60e51b815260206004820152601060248201526f13dd995c999b1bddc81d5a5b9d0c4c0d60821b6044820152606401610c1b565b6040516001600160a01b0383811660248301526044820183905261219691859182169063a9059cbb9060640161270d565b6006546001600160a01b031633146114a85760405163118cdaa760e01b8152336004820152602401610c1b565b3360009081526008602090815260408083208151606081018352905461ffff8082168084526201000083046001600160681b031684870152600160781b9092046001600160801b031683850152600d54918652600990945291842054600b54919492909316926129ed918591859160ff16612b3d565b9050836129fa57846129fc565b805b945084600003612a0d575050505050565b80851115612a515760405162461bcd60e51b81526020600482015260116024820152704578636565647320617661696c61626c6560781b6044820152606401610c1b565b825161ffff16821115612a7e57336000908152600860205260409020805462010000600160781b03191690555b612a8785612885565b612a918582613395565b336000818152600860205260409081902080546001600160801b0394909416600160781b02600160781b600160f81b0319909416939093179092558451915190917fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a92991612b0a9189825261ffff16602082015260400190565b60405180910390a2612b1d303387612219565b5050505050565b600780546001600160a01b0319169055610d7081612e46565b835160009061ffff1615801590612b585750845161ffff1684115b15612b9a576000612b7786602001516001600160681b03168585612786565b90508086604001516001600160801b0316612b9291906133c9565b91505061135e565b50505050604001516001600160801b031690565b6001600160a01b038216612bd857604051634b637e8f60e11b815260006004820152602401610c1b565b610e6182600083612cb9565b6001600160a01b038416612c0e5760405163e602df0560e01b815260006004820152602401610c1b565b6001600160a01b038316612c3857604051634a1406b160e11b815260006004820152602401610c1b565b6001600160a01b038085166000908152600260209081526040808320938716835292905220829055801561221357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051612cab91815260200190565b60405180910390a350505050565b6001600160a01b038316612ce4578060036000828254612cd991906133c9565b90915550612d569050565b6001600160a01b03831660009081526001602052604090205481811015612d375760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610c1b565b6001600160a01b03841660009081526001602052604090209082900390555b6001600160a01b038216612d7257600380548290039055612d91565b6001600160a01b03821660009081526001602052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612dd691815260200190565b60405180910390a3505050565b6000612df86001600160a01b03841683612e98565b90508051600014158015612e1d575080806020019051810190612e1b919061355d565b155b1561219657604051635274afe760e01b81526001600160a01b0384166004820152602401610c1b565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6060610bd98383600084600080856001600160a01b03168486604051612ebe919061357a565b60006040518083038185875af1925050503d8060008114612efb576040519150601f19603f3d011682016040523d82523d6000602084013e612f00565b606091505b509150915061277c868383606082612f2057612f1b82612f67565b610bd9565b8151158015612f3757506001600160a01b0384163b155b15612f6057604051639996b31560e01b81526001600160a01b0385166004820152602401610c1b565b5080610bd9565b805115612f775780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b60005b83811015612fab578181015183820152602001612f93565b50506000910152565b6020815260008251806020840152612fd3816040850160208701612f90565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114612ffe57600080fd5b919050565b6000806040838503121561301657600080fd5b61301f83612fe7565b946020939093013593505050565b60008060006060848603121561304257600080fd5b61304b84612fe7565b925061305960208501612fe7565b9150604084013590509250925092565b60006020828403121561307b57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126130a957600080fd5b8135602067ffffffffffffffff808311156130c6576130c6613082565b8260051b604051601f19603f830116810181811084821117156130eb576130eb613082565b60405293845285810183019383810192508785111561310957600080fd5b83870191505b848210156131285781358352918301919083019061310f565b979650505050505050565b6000806040838503121561314657600080fd5b82359150602083013567ffffffffffffffff81111561316457600080fd5b61317085828601613098565b9150509250929050565b6000806040838503121561318d57600080fd5b8235915061319d60208401612fe7565b90509250929050565b6000602082840312156131b857600080fd5b610bd982612fe7565b8015158114610d7057600080fd5b6000602082840312156131e157600080fd5b8135610bd9816131c1565b600080604083850312156131ff57600080fd5b61320883612fe7565b9150602083013567ffffffffffffffff81111561316457600080fd5b6000806040838503121561323757600080fd5b61324083612fe7565b915061319d60208401612fe7565b60006020828403121561326057600080fd5b813567ffffffffffffffff81111561327757600080fd5b61135e84828501613098565b60006080828403121561329557600080fd5b6040516080810181811067ffffffffffffffff821117156132b8576132b8613082565b604052823560ff811681146132cc57600080fd5b81526132da60208401612fe7565b6020820152604083013566ffffffffffffff811681146132f957600080fd5b604082015260608301356001600160681b038116811461331857600080fd5b60608201529392505050565b600181811c9082168061333857607f821691505b60208210810361335857634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526007908201526608585b5bdd5b9d60ca1b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610bb457610bb461337f565b602080825260079082015266217075626c696360c81b604082015260600190565b80820180821115610bb457610bb461337f565b6000602082840312156133ee57600080fd5b5051919050565b602080825260059082015264042ae8aa8960db1b604082015260600190565b6020808252600690820152652176616c756560d01b604082015260600190565b600181815b8085111561346f5781600019048211156134555761345561337f565b8085161561346257918102915b93841c9390800290613439565b509250929050565b60008261348657506001610bb4565b8161349357506000610bb4565b81600181146134a957600281146134b3576134cf565b6001915050610bb4565b60ff8411156134c4576134c461337f565b50506001821b610bb4565b5060208310610133831016604e8410600b84101617156134f2575081810a610bb4565b6134fc8383613434565b80600019048211156135105761351061337f565b029392505050565b6000610bd98383613477565b8082028115828204841417610bb457610bb461337f565b60008261355857634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561356f57600080fd5b8151610bd9816131c1565b6000825161358c818460208701612f90565b919091019291505056fea264697066735822122034e09cf2404bf3252671f6001b4992c9b7bedde936154d87fa666a3afc41bdd864736f6c63430008140033

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

000000000000000000000000420000000000000000000000000000000000000600000000000000000000000058abe9162e77a2bff179182cebefb9dda3135fe0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000012000000000000000000000000420000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000002540be40000000000000000000000000000000000000000000000006c6b935b8bbd40000000000000000000000000000000000000000000000000000000000000000000105468656f4554485368617265383435330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085445544838343533000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _weth (address): 0x4200000000000000000000000000000000000006
Arg [1] : _keeper (address): 0x58ABE9162e77a2BFf179182CeBEFb9DDa3135FE0
Arg [2] : _tokenName (string): TheoETHShare8453
Arg [3] : _tokenSymbol (string): TETH8453
Arg [4] : _vaultParams (tuple):
Arg [1] : decimals (uint8): 18
Arg [2] : asset (address): 0x4200000000000000000000000000000000000006
Arg [3] : minimumSupply (uint56): 10000000000
Arg [4] : cap (uint104): 2000000000000000000000


-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [1] : 00000000000000000000000058abe9162e77a2bff179182cebefb9dda3135fe0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [5] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [6] : 00000000000000000000000000000000000000000000000000000002540be400
Arg [7] : 00000000000000000000000000000000000000000000006c6b935b8bbd400000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [9] : 5468656f45544853686172653834353300000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [11] : 5445544838343533000000000000000000000000000000000000000000000000


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.