{
  "language": "Solidity",
  "sources": {
    "contracts/FSushi.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushi is Ownable, ERC20, IFSushi {\n    using DateUtils for uint256;\n\n    bytes32 private constant _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n    address private immutable _CACHED_THIS;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n\n    uint256 public immutable override startWeek;\n\n    mapping(address => bool) public override isMinter;\n    bool public override mintersLocked;\n\n    mapping(address => uint256) public override nonces;\n    /**\n     * @return minimum number of minted total supply during the whole week (only available >= startWeek)\n     */\n    mapping(uint256 => uint256) public override totalSupplyDuring;\n    /**\n     * @notice totalSupplyDuring is guaranteed to be correct before this week (exclusive)\n     */\n    uint256 public override lastCheckpoint;\n\n    modifier onlyMinter() {\n        if (!isMinter[msg.sender]) revert Forbidden();\n        _;\n    }\n\n    constructor() ERC20(\"Flash Sushi Token\", \"fSUSHI\") {\n        uint256 nextWeek = block.timestamp.toWeekNumber() + 1;\n        startWeek = nextWeek;\n        lastCheckpoint = nextWeek;\n\n        bytes32 hashedName = keccak256(bytes(\"Flash Sushi Token\"));\n        bytes32 hashedVersion = keccak256(bytes(\"1\"));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _CACHED_THIS = address(this);\n        _TYPE_HASH = typeHash;\n    }\n\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    function setMinter(address account, bool _isMinter) external override onlyOwner {\n        if (mintersLocked) revert MintersLocked();\n\n        isMinter[account] = _isMinter;\n\n        emit SetMinter(account, _isMinter);\n    }\n\n    function lockMinters() external onlyOwner {\n        mintersLocked = true;\n\n        emit LockMinters();\n    }\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external override {\n        if (block.timestamp > deadline) revert Expired();\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        if (signer != owner) revert InvalidSignature();\n\n        _approve(owner, spender, value);\n    }\n\n    function mint(address to, uint256 amount) external onlyMinter {\n        _mint(to, amount);\n\n        checkpoint();\n    }\n\n    function checkpointedTotalSupplyDuring(uint256 week) external override returns (uint256) {\n        checkpoint();\n        return totalSupplyDuring[week];\n    }\n\n    /**\n     * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n     */\n    function checkpoint() public {\n        uint256 from = lastCheckpoint;\n        uint256 until = block.timestamp.toWeekNumber();\n        if (until < from) return;\n\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            uint256 old = totalSupplyDuring[week];\n            if (week == until) {\n                uint256 current = totalSupply();\n                if (current > old) {\n                    totalSupplyDuring[week] = current;\n                }\n                break;\n            } else if (startWeek < week && old == 0) {\n                totalSupplyDuring[week] = totalSupplyDuring[week - 1];\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        lastCheckpoint = until;\n\n        emit Checkpoint(until);\n    }\n}\n"
    },
    "contracts/interfaces/IFSushi.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IFSushi is IERC20Metadata {\n    error Forbidden();\n    error Expired();\n    error MintersLocked();\n    error InvalidSignature();\n\n    event SetMinter(address indexed account, bool indexed isMinter);\n    event LockMinters();\n    event Checkpoint(uint256 lastCheckpoint);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function startWeek() external view returns (uint256);\n\n    function isMinter(address account) external view returns (bool);\n\n    function mintersLocked() external view returns (bool);\n\n    function nonces(address account) external view returns (uint256);\n\n    function totalSupplyDuring(uint256 time) external view returns (uint256);\n\n    function lastCheckpoint() external view returns (uint256);\n\n    function setMinter(address account, bool _isMinter) external;\n\n    function lockMinters() external;\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    function mint(address to, uint256 amount) external;\n\n    function checkpointedTotalSupplyDuring(uint256 week) external returns (uint256);\n\n    function checkpoint() external;\n}\n"
    },
    "contracts/libraries/DateUtils.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nuint256 constant WEEK = 1 weeks;\n\nlibrary DateUtils {\n    function toWeekNumber(uint256 timestamp) internal pure returns (uint256) {\n        return timestamp / WEEK;\n    }\n\n    function toTimestamp(uint256 weekNumber) internal pure returns (uint256) {\n        return weekNumber * WEEK;\n    }\n}\n"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV // Deprecated in v4.8\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/Math.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10**64) {\n                value /= 10**64;\n                result += 64;\n            }\n            if (value >= 10**32) {\n                value /= 10**32;\n                result += 32;\n            }\n            if (value >= 10**16) {\n                value /= 10**16;\n                result += 16;\n            }\n            if (value >= 10**8) {\n                value /= 10**8;\n                result += 8;\n            }\n            if (value >= 10**4) {\n                value /= 10**4;\n                result += 4;\n            }\n            if (value >= 10**2) {\n                value /= 10**2;\n                result += 2;\n            }\n            if (value >= 10**1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/cryptography/EIP712.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n    /* solhint-disable var-name-mixedcase */\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n    // invalidate the cached domain separator if the chain id changes.\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n    address private immutable _CACHED_THIS;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n\n    /* solhint-enable var-name-mixedcase */\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    constructor(string memory name, string memory version) {\n        bytes32 hashedName = keccak256(bytes(name));\n        bytes32 hashedVersion = keccak256(bytes(version));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _CACHED_THIS = address(this);\n        _TYPE_HASH = typeHash;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./draft-IERC20Permit.sol\";\nimport \"../ERC20.sol\";\nimport \"../../../utils/cryptography/ECDSA.sol\";\nimport \"../../../utils/cryptography/EIP712.sol\";\nimport \"../../../utils/Counters.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private constant _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n    /**\n     * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\n     * However, to ensure consistency with the upgradeable transpiler, we will continue\n     * to reserve a slot.\n     * @custom:oz-renamed-from _PERMIT_TYPEHASH\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    constructor(string memory name) EIP712(name, \"1\") {}\n\n    /**\n     * @dev See {IERC20Permit-permit}.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @dev See {IERC20Permit-nonces}.\n     */\n    function nonces(address owner) public view virtual override returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(address owner) internal virtual returns (uint256 current) {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Counters.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n    struct Counter {\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\n        uint256 _value; // default: 0\n    }\n\n    function current(Counter storage counter) internal view returns (uint256) {\n        return counter._value;\n    }\n\n    function increment(Counter storage counter) internal {\n        unchecked {\n            counter._value += 1;\n        }\n    }\n\n    function decrement(Counter storage counter) internal {\n        uint256 value = counter._value;\n        require(value > 0, \"Counter: decrement overflow\");\n        unchecked {\n            counter._value = value - 1;\n        }\n    }\n\n    function reset(Counter storage counter) internal {\n        counter._value = 0;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20Permit token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../utils/SafeERC20.sol\";\nimport \"../../../interfaces/IERC4626.sol\";\nimport \"../../../utils/math/Math.sol\";\n\n/**\n * @dev Implementation of the ERC4626 \"Tokenized Vault Standard\" as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].\n *\n * This extension allows the minting and burning of \"shares\" (represented using the ERC20 inheritance) in exchange for\n * underlying \"assets\" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends\n * the ERC20 standard. Any additional extensions included along it would affect the \"shares\" token represented by this\n * contract and not the \"assets\" token which is an independent contract.\n *\n * CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of\n * shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as\n * https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].\n *\n * _Available since v4.7._\n */\nabstract contract ERC4626 is ERC20, IERC4626 {\n    using Math for uint256;\n\n    IERC20 private immutable _asset;\n    uint8 private immutable _decimals;\n\n    /**\n     * @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).\n     */\n    constructor(IERC20 asset_) {\n        (bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);\n        _decimals = success ? assetDecimals : super.decimals();\n        _asset = asset_;\n    }\n\n    /**\n     * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.\n     */\n    function _tryGetAssetDecimals(IERC20 asset_) private returns (bool, uint8) {\n        (bool success, bytes memory encodedDecimals) = address(asset_).call(\n            abi.encodeWithSelector(IERC20Metadata.decimals.selector)\n        );\n        if (success && encodedDecimals.length >= 32) {\n            uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));\n            if (returnedDecimals <= type(uint8).max) {\n                return (true, uint8(returnedDecimals));\n            }\n        }\n        return (false, 0);\n    }\n\n    /**\n     * @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset\n     * has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on\n     * inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value.\n     * See {IERC20Metadata-decimals}.\n     */\n    function decimals() public view virtual override(IERC20Metadata, ERC20) returns (uint8) {\n        return _decimals;\n    }\n\n    /** @dev See {IERC4626-asset}. */\n    function asset() public view virtual override returns (address) {\n        return address(_asset);\n    }\n\n    /** @dev See {IERC4626-totalAssets}. */\n    function totalAssets() public view virtual override returns (uint256) {\n        return _asset.balanceOf(address(this));\n    }\n\n    /** @dev See {IERC4626-convertToShares}. */\n    function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {\n        return _convertToShares(assets, Math.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-convertToAssets}. */\n    function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {\n        return _convertToAssets(shares, Math.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-maxDeposit}. */\n    function maxDeposit(address) public view virtual override returns (uint256) {\n        return _isVaultCollateralized() ? type(uint256).max : 0;\n    }\n\n    /** @dev See {IERC4626-maxMint}. */\n    function maxMint(address) public view virtual override returns (uint256) {\n        return type(uint256).max;\n    }\n\n    /** @dev See {IERC4626-maxWithdraw}. */\n    function maxWithdraw(address owner) public view virtual override returns (uint256) {\n        return _convertToAssets(balanceOf(owner), Math.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-maxRedeem}. */\n    function maxRedeem(address owner) public view virtual override returns (uint256) {\n        return balanceOf(owner);\n    }\n\n    /** @dev See {IERC4626-previewDeposit}. */\n    function previewDeposit(uint256 assets) public view virtual override returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-previewMint}. */\n    function previewMint(uint256 shares) public view virtual override returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Up);\n    }\n\n    /** @dev See {IERC4626-previewWithdraw}. */\n    function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {\n        return _convertToShares(assets, Math.Rounding.Up);\n    }\n\n    /** @dev See {IERC4626-previewRedeem}. */\n    function previewRedeem(uint256 shares) public view virtual override returns (uint256) {\n        return _convertToAssets(shares, Math.Rounding.Down);\n    }\n\n    /** @dev See {IERC4626-deposit}. */\n    function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {\n        require(assets <= maxDeposit(receiver), \"ERC4626: deposit more than max\");\n\n        uint256 shares = previewDeposit(assets);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-mint}. */\n    function mint(uint256 shares, address receiver) public virtual override returns (uint256) {\n        require(shares <= maxMint(receiver), \"ERC4626: mint more than max\");\n\n        uint256 assets = previewMint(shares);\n        _deposit(_msgSender(), receiver, assets, shares);\n\n        return assets;\n    }\n\n    /** @dev See {IERC4626-withdraw}. */\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) public virtual override returns (uint256) {\n        require(assets <= maxWithdraw(owner), \"ERC4626: withdraw more than max\");\n\n        uint256 shares = previewWithdraw(assets);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return shares;\n    }\n\n    /** @dev See {IERC4626-redeem}. */\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) public virtual override returns (uint256) {\n        require(shares <= maxRedeem(owner), \"ERC4626: redeem more than max\");\n\n        uint256 assets = previewRedeem(shares);\n        _withdraw(_msgSender(), receiver, owner, assets, shares);\n\n        return assets;\n    }\n\n    /**\n     * @dev Internal conversion function (from assets to shares) with support for rounding direction.\n     *\n     * Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset\n     * would represent an infinite amount of shares.\n     */\n    function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256 shares) {\n        uint256 supply = totalSupply();\n        return\n            (assets == 0 || supply == 0)\n                ? _initialConvertToShares(assets, rounding)\n                : assets.mulDiv(supply, totalAssets(), rounding);\n    }\n\n    /**\n     * @dev Internal conversion function (from assets to shares) to apply when the vault is empty.\n     *\n     * NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.\n     */\n    function _initialConvertToShares(\n        uint256 assets,\n        Math.Rounding /*rounding*/\n    ) internal view virtual returns (uint256 shares) {\n        return assets;\n    }\n\n    /**\n     * @dev Internal conversion function (from shares to assets) with support for rounding direction.\n     */\n    function _convertToAssets(uint256 shares, Math.Rounding rounding) internal view virtual returns (uint256 assets) {\n        uint256 supply = totalSupply();\n        return\n            (supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);\n    }\n\n    /**\n     * @dev Internal conversion function (from shares to assets) to apply when the vault is empty.\n     *\n     * NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.\n     */\n    function _initialConvertToAssets(\n        uint256 shares,\n        Math.Rounding /*rounding*/\n    ) internal view virtual returns (uint256 assets) {\n        return shares;\n    }\n\n    /**\n     * @dev Deposit/mint common workflow.\n     */\n    function _deposit(\n        address caller,\n        address receiver,\n        uint256 assets,\n        uint256 shares\n    ) internal virtual {\n        // If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the\n        // `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the\n        // assets are transferred and before the shares are minted, which is a valid state.\n        // slither-disable-next-line reentrancy-no-eth\n        SafeERC20.safeTransferFrom(_asset, caller, address(this), assets);\n        _mint(receiver, shares);\n\n        emit Deposit(caller, receiver, assets, shares);\n    }\n\n    /**\n     * @dev Withdraw/redeem common workflow.\n     */\n    function _withdraw(\n        address caller,\n        address receiver,\n        address owner,\n        uint256 assets,\n        uint256 shares\n    ) internal virtual {\n        if (caller != owner) {\n            _spendAllowance(owner, caller, shares);\n        }\n\n        // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the\n        // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,\n        // calls the vault, which is assumed not malicious.\n        //\n        // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the\n        // shares are burned and after the assets are transferred, which is a valid state.\n        _burn(owner, shares);\n        SafeERC20.safeTransfer(_asset, receiver, assets);\n\n        emit Withdraw(caller, receiver, owner, assets, shares);\n    }\n\n    function _isVaultCollateralized() private view returns (bool) {\n        return totalAssets() > 0 || totalSupply() == 0;\n    }\n}\n"
    },
    "@openzeppelin/contracts/interfaces/IERC4626.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../token/ERC20/IERC20.sol\";\nimport \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n *\n * _Available since v4.7._\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(\n        uint256 assets,\n        address receiver,\n        address owner\n    ) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(\n        uint256 shares,\n        address receiver,\n        address owner\n    ) external returns (uint256 assets);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/ERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n    using Address for address;\n    using Strings for uint256;\n\n    // Token name\n    string private _name;\n\n    // Token symbol\n    string private _symbol;\n\n    // Mapping from token ID to owner address\n    mapping(uint256 => address) private _owners;\n\n    // Mapping owner address to token count\n    mapping(address => uint256) private _balances;\n\n    // Mapping from token ID to approved address\n    mapping(uint256 => address) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n        return\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function balanceOf(address owner) public view virtual override returns (uint256) {\n        require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n        return _balances[owner];\n    }\n\n    /**\n     * @dev See {IERC721-ownerOf}.\n     */\n    function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n        address owner = _ownerOf(tokenId);\n        require(owner != address(0), \"ERC721: invalid token ID\");\n        return owner;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-name}.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-symbol}.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        _requireMinted(tokenId);\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return \"\";\n    }\n\n    /**\n     * @dev See {IERC721-approve}.\n     */\n    function approve(address to, uint256 tokenId) public virtual override {\n        address owner = ERC721.ownerOf(tokenId);\n        require(to != owner, \"ERC721: approval to current owner\");\n\n        require(\n            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n            \"ERC721: approve caller is not token owner or approved for all\"\n        );\n\n        _approve(to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-getApproved}.\n     */\n    function getApproved(uint256 tokenId) public view virtual override returns (address) {\n        _requireMinted(tokenId);\n\n        return _tokenApprovals[tokenId];\n    }\n\n    /**\n     * @dev See {IERC721-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual override {\n        _setApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @dev See {IERC721-isApprovedForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n        return _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev See {IERC721-transferFrom}.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        //solhint-disable-next-line max-line-length\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n\n        _transfer(from, to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) public virtual override {\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner or approved\");\n        _safeTransfer(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * `data` is additional data, it has no specified format and it is sent in call to `to`.\n     *\n     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n     * implement alternative mechanisms to perform token transfer, such as signature-based.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeTransfer(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        _transfer(from, to, tokenId);\n        require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n    }\n\n    /**\n     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist\n     */\n    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {\n        return _owners[tokenId];\n    }\n\n    /**\n     * @dev Returns whether `tokenId` exists.\n     *\n     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n     *\n     * Tokens start existing when they are minted (`_mint`),\n     * and stop existing when they are burned (`_burn`).\n     */\n    function _exists(uint256 tokenId) internal view virtual returns (bool) {\n        return _ownerOf(tokenId) != address(0);\n    }\n\n    /**\n     * @dev Returns whether `spender` is allowed to manage `tokenId`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n        address owner = ERC721.ownerOf(tokenId);\n        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n    }\n\n    /**\n     * @dev Safely mints `tokenId` and transfers it to `to`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMint(address to, uint256 tokenId) internal virtual {\n        _safeMint(to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeMint(\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        _mint(to, tokenId);\n        require(\n            _checkOnERC721Received(address(0), to, tokenId, data),\n            \"ERC721: transfer to non ERC721Receiver implementer\"\n        );\n    }\n\n    /**\n     * @dev Mints `tokenId` and transfers it to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - `to` cannot be the zero address.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _mint(address to, uint256 tokenId) internal virtual {\n        require(to != address(0), \"ERC721: mint to the zero address\");\n        require(!_exists(tokenId), \"ERC721: token already minted\");\n\n        _beforeTokenTransfer(address(0), to, tokenId, 1);\n\n        // Check that tokenId was not minted by `_beforeTokenTransfer` hook\n        require(!_exists(tokenId), \"ERC721: token already minted\");\n\n        unchecked {\n            // Will not overflow unless all 2**256 token ids are minted to the same owner.\n            // Given that tokens are minted one by one, it is impossible in practice that\n            // this ever happens. Might change if we allow batch minting.\n            // The ERC fails to describe this case.\n            _balances[to] += 1;\n        }\n\n        _owners[tokenId] = to;\n\n        emit Transfer(address(0), to, tokenId);\n\n        _afterTokenTransfer(address(0), to, tokenId, 1);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     * This is an internal function that does not check if the sender is authorized to operate on the token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId) internal virtual {\n        address owner = ERC721.ownerOf(tokenId);\n\n        _beforeTokenTransfer(owner, address(0), tokenId, 1);\n\n        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook\n        owner = ERC721.ownerOf(tokenId);\n\n        // Clear approvals\n        delete _tokenApprovals[tokenId];\n\n        unchecked {\n            // Cannot overflow, as that would require more tokens to be burned/transferred\n            // out than the owner initially received through minting and transferring in.\n            _balances[owner] -= 1;\n        }\n        delete _owners[tokenId];\n\n        emit Transfer(owner, address(0), tokenId);\n\n        _afterTokenTransfer(owner, address(0), tokenId, 1);\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {\n        require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n        require(to != address(0), \"ERC721: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, tokenId, 1);\n\n        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook\n        require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n\n        // Clear approvals from the previous owner\n        delete _tokenApprovals[tokenId];\n\n        unchecked {\n            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:\n            // `from`'s balance is the number of token held, which is at least one before the current\n            // transfer.\n            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require\n            // all 2**256 token ids to be minted, which in practice is impossible.\n            _balances[from] -= 1;\n            _balances[to] += 1;\n        }\n        _owners[tokenId] = to;\n\n        emit Transfer(from, to, tokenId);\n\n        _afterTokenTransfer(from, to, tokenId, 1);\n    }\n\n    /**\n     * @dev Approve `to` to operate on `tokenId`\n     *\n     * Emits an {Approval} event.\n     */\n    function _approve(address to, uint256 tokenId) internal virtual {\n        _tokenApprovals[tokenId] = to;\n        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n    }\n\n    /**\n     * @dev Approve `operator` to operate on all of `owner` tokens\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function _setApprovalForAll(\n        address owner,\n        address operator,\n        bool approved\n    ) internal virtual {\n        require(owner != operator, \"ERC721: approve to caller\");\n        _operatorApprovals[owner][operator] = approved;\n        emit ApprovalForAll(owner, operator, approved);\n    }\n\n    /**\n     * @dev Reverts if the `tokenId` has not been minted yet.\n     */\n    function _requireMinted(uint256 tokenId) internal view virtual {\n        require(_exists(tokenId), \"ERC721: invalid token ID\");\n    }\n\n    /**\n     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n     * The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param data bytes optional data to send along with the call\n     * @return bool whether the call correctly returned the expected magic value\n     */\n    function _checkOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) private returns (bool) {\n        if (to.isContract()) {\n            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n                return retval == IERC721Receiver.onERC721Received.selector;\n            } catch (bytes memory reason) {\n                if (reason.length == 0) {\n                    revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n                } else {\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.\n     * - When `from` is zero, the tokens will be minted for `to`.\n     * - When `to` is zero, ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     * - `batchSize` is non-zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256, /* firstTokenId */\n        uint256 batchSize\n    ) internal virtual {\n        if (batchSize > 1) {\n            if (from != address(0)) {\n                _balances[from] -= batchSize;\n            }\n            if (to != address(0)) {\n                _balances[to] += batchSize;\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is\n     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.\n     * - When `from` is zero, the tokens were minted for `to`.\n     * - When `to` is zero, ``from``'s tokens were burned.\n     * - `from` and `to` are never both zero.\n     * - `batchSize` is non-zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 firstTokenId,\n        uint256 batchSize\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721.sol\";\n\n/**\n * @dev ERC721 token with storage based token URI management.\n */\nabstract contract ERC721URIStorage is ERC721 {\n    using Strings for uint256;\n\n    // Optional mapping for token URIs\n    mapping(uint256 => string) private _tokenURIs;\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        _requireMinted(tokenId);\n\n        string memory _tokenURI = _tokenURIs[tokenId];\n        string memory base = _baseURI();\n\n        // If there is no base URI, return the token URI.\n        if (bytes(base).length == 0) {\n            return _tokenURI;\n        }\n        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).\n        if (bytes(_tokenURI).length > 0) {\n            return string(abi.encodePacked(base, _tokenURI));\n        }\n\n        return super.tokenURI(tokenId);\n    }\n\n    /**\n     * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {\n        require(_exists(tokenId), \"ERC721URIStorage: URI set of nonexistent token\");\n        _tokenURIs[tokenId] = _tokenURI;\n    }\n\n    /**\n     * @dev See {ERC721-_burn}. This override additionally checks to see if a\n     * token-specific URI was set for the token, and if so, it deletes the token URI from\n     * the storage mapping.\n     */\n    function _burn(uint256 tokenId) internal virtual override {\n        super._burn(tokenId);\n\n        if (bytes(_tokenURIs[tokenId]).length != 0) {\n            delete _tokenURIs[tokenId];\n        }\n    }\n}\n"
    },
    "contracts/mocks/FlashNFT.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";\nimport \"@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract FlashNFT is ERC721URIStorage, Ownable {\n    using Counters for Counters.Counter;\n    Counters.Counter private tokenIds;\n\n    constructor() ERC721(\"Flashstake NFT\", \"FLASHNFT\") {}\n\n    function contractURI() public pure returns (string memory) {\n        return \"https://nft.flashstake.io/metadata\";\n    }\n\n    function _baseURI() internal pure virtual override returns (string memory) {\n        return \"https://nft.flashstake.io/\";\n    }\n\n    function exists(uint256 _tokenId) public view returns (bool) {\n        return _exists(_tokenId);\n    }\n\n    // Only the FlashV3 protocol (owner) can burn\n    function burn(uint256 _tokenId) public onlyOwner returns (bool) {\n        _burn(_tokenId);\n        return true;\n    }\n\n    // Only the FlashV3 protocol (owner) can mint\n    function mint(address _recipientAddress) public onlyOwner returns (uint256) {\n        tokenIds.increment();\n        _mint(_recipientAddress, tokenIds.current());\n\n        return tokenIds.current();\n    }\n\n    function totalSupply() public view returns (uint256) {\n        return tokenIds.current();\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\nabstract contract ERC20Burnable is Context, ERC20 {\n    /**\n     * @dev Destroys `amount` tokens from the caller.\n     *\n     * See {ERC20-_burn}.\n     */\n    function burn(uint256 amount) public virtual {\n        _burn(_msgSender(), amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, deducting from the caller's\n     * allowance.\n     *\n     * See {ERC20-_burn} and {ERC20-allowance}.\n     *\n     * Requirements:\n     *\n     * - the caller must have allowance for ``accounts``'s tokens of at least\n     * `amount`.\n     */\n    function burnFrom(address account, uint256 amount) public virtual {\n        _spendAllowance(account, _msgSender(), amount);\n        _burn(account, amount);\n    }\n}\n"
    },
    "contracts/FarmingLPToken.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol\";\nimport \"./interfaces/IFarmingLPToken.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./interfaces/IFarmingLPTokenMigrator.sol\";\nimport \"./interfaces/IMasterChef.sol\";\nimport \"./libraries/UniswapV2Utils.sol\";\nimport \"./base/BaseERC20.sol\";\n\ncontract FarmingLPToken is BaseERC20, ReentrancyGuard, IFarmingLPToken {\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n    using SafeCast for int256;\n\n    uint128 internal constant POINTS_MULTIPLIER = type(uint128).max;\n\n    address public override factory;\n    address public override router;\n    address public override masterChef;\n    uint256 public override pid;\n    address public override sushi;\n    address public override lpToken;\n    address public override token0;\n    address public override token1;\n\n    uint256 public override withdrawableTotalLPs;\n    uint256 internal _pointsPerShare;\n    mapping(address => int256) internal _pointsCorrection;\n    mapping(address => uint256) internal _withdrawnVaultBalanceOf;\n\n    function initialize(\n        address _router,\n        address _masterChef,\n        uint256 _pid\n    ) external override initializer {\n        if (_router == address(0)) return;\n\n        factory = msg.sender;\n        (address _lpToken, , , ) = IMasterChef(_masterChef).poolInfo(_pid);\n        address _token0 = IUniswapV2Pair(_lpToken).token0();\n        address _token1 = IUniswapV2Pair(_lpToken).token1();\n        router = _router;\n        masterChef = _masterChef;\n        pid = _pid;\n        sushi = IMasterChef(_masterChef).sushi();\n        lpToken = _lpToken;\n        token0 = _token0;\n        token1 = _token1;\n\n        BaseERC20_initialize(\n            string.concat(\n                \"Farming LP Token (\",\n                IERC20Metadata(_token0).name(),\n                \"-\",\n                IERC20Metadata(_token1).name(),\n                \")\"\n            ),\n            string.concat(\"fLP:\", IERC20Metadata(_token0).symbol(), \"-\", IERC20Metadata(_token1).symbol()),\n            \"1\"\n        );\n        approveMax();\n    }\n\n    function withdrawableLPsOf(address account) external view override returns (uint256) {\n        uint256 total = totalShares();\n        if (total == 0) return 0;\n        return (sharesOf(account) * withdrawableTotalLPs) / total;\n    }\n\n    /**\n     * @return Sum of (shares in SUSHI) + (withdrawable total SUSHI)\n     */\n    function totalSupply() public view override(BaseERC20, IERC20) returns (uint256) {\n        return totalShares() + withdrawableTotalYield();\n    }\n\n    /**\n     * @return Sum of (shares in SUSHI by depositd account) + (SUSHI withdrawable by account)\n     */\n    function balanceOf(address account) public view override(BaseERC20, IERC20) returns (uint256) {\n        return sharesOf(account) + withdrawableYieldOf(account);\n    }\n\n    /**\n     * @return total shares in SUSHI currently being depositd\n     */\n    function totalShares() public view override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @return shares in SUSHI currently being depositd by account\n     */\n    function sharesOf(address account) public view override returns (uint256) {\n        return _balanceOf[account];\n    }\n\n    /**\n     * @dev Returns the total amount of SUSHI if every holder wants to withdraw at once\n     * @return A uint256 representing the total SUSHI\n     */\n    function withdrawableTotalYield() public view override returns (uint256) {\n        address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n        uint256 pendingSushi = IMasterChef(masterChef).pendingSushi(pid, address(this));\n        return pendingSushi + IERC4626(yieldVault).maxWithdraw(address(this));\n    }\n\n    /**\n     * @dev Returns the amount of SUSHI a given address is able to withdraw.\n     * @param account Address of a reward recipient\n     * @return A uint256 representing the SUSHI `account` can withdraw\n     */\n    function withdrawableYieldOf(address account) public view override returns (uint256) {\n        address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n        return IERC4626(yieldVault).convertToAssets((_withdrawableVaultBalanceOf(account, true)));\n    }\n\n    /**\n     * @dev Vault balance is used to record reward debt for account.\n     * @param account Address of a reward recipient\n     * @param preview if true, it adds the amount of MasterChef.pendingSushi()\n     * @return A uint256 representing the SUSHI `account` can withdraw\n     */\n    function _withdrawableVaultBalanceOf(address account, bool preview) internal view returns (uint256) {\n        return _cumulativeVaultBalanceOf(account, preview) - _withdrawnVaultBalanceOf[account];\n    }\n\n    /**\n     * @notice View the amount of vault balance that an address has earned in total.\n     * @dev cumulativeVaultBalanceOf(account) = withdrawableVaultBalanceOf(account) + withdrawnVaultBalanceOf(account)\n     *  = (pointsPerShare * sharesOf(account) + pointsCorrection[account]) / POINTS_MULTIPLIER\n     * @param account The address of a token holder.\n     * @param preview if true, it adds the amount of MasterChef.pendingSushi()\n     * @return The amount of SUSHI that `account` has earned in total.\n     */\n    function _cumulativeVaultBalanceOf(address account, bool preview) internal view returns (uint256) {\n        uint256 pointsPerShare = _pointsPerShare;\n        if (preview) {\n            uint256 total = totalShares();\n            if (total > 0) {\n                address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n                uint256 pendingSushi = IMasterChef(masterChef).pendingSushi(pid, address(this));\n                pointsPerShare += (IERC4626(yieldVault).previewDeposit(pendingSushi) * POINTS_MULTIPLIER) / total;\n            }\n        }\n        return\n            ((pointsPerShare * sharesOf(account)).toInt256() + _pointsCorrection[account]).toUint256() /\n            POINTS_MULTIPLIER;\n    }\n\n    function approveMax() public override {\n        IERC20(lpToken).approve(masterChef, type(uint256).max);\n        IERC20(sushi).approve(IFarmingLPTokenFactory(factory).yieldVault(), type(uint256).max);\n        IERC20(sushi).approve(router, type(uint256).max);\n        IERC20(token0).approve(router, type(uint256).max);\n        IERC20(token1).approve(router, type(uint256).max);\n    }\n\n    /**\n     * @dev amount of sushi that LPs converted to is added to sharesOf(account) and aLP is minted\n     *  user signature is needed for IUniswapV2Pair.permit()\n     */\n    function depositSigned(\n        uint256 amountLP,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountMin,\n        address beneficiary,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external override nonReentrant {\n        IUniswapV2Pair(lpToken).permit(msg.sender, address(this), amountLP, deadline, v, r, s);\n        _deposit(amountLP, path0, path1, amountMin, beneficiary);\n    }\n\n    /**\n     * @dev amount of sushi that LPs converted to is added to sharesOf(account) and aLP is minted\n     */\n    function deposit(\n        uint256 amountLP,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountMin,\n        address beneficiary,\n        uint256 deadline\n    ) external override nonReentrant {\n        if (block.timestamp > deadline) revert Expired();\n        _deposit(amountLP, path0, path1, amountMin, beneficiary);\n    }\n\n    function _deposit(\n        uint256 amountLP,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountMin,\n        address beneficiary\n    ) internal {\n        if (path0[0] != token0 || path0[path0.length - 1] != sushi) revert InvalidPath();\n        if (path1[0] != token1 || path1[path1.length - 1] != sushi) revert InvalidPath();\n\n        IERC20(lpToken).safeTransferFrom(msg.sender, address(this), amountLP);\n\n        uint256 total = IUniswapV2Pair(lpToken).totalSupply();\n        (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(lpToken).getReserves();\n        uint256 amount = UniswapV2Utils.quote(router, (reserve0 * amountLP) / total, path0) +\n            UniswapV2Utils.quote(router, (reserve1 * amountLP) / total, path1);\n\n        if (amount < amountMin) revert InsufficientAmount();\n\n        IMasterChef(masterChef).deposit(pid, amountLP);\n        _depositSushi();\n\n        _mint(beneficiary, amount);\n        withdrawableTotalLPs += amountLP;\n\n        emit Deposit(amount, amountLP, beneficiary);\n    }\n\n    /**\n     * @dev amount is added to sharesOf(account) and same amount of aLP is minted\n     *  provided SUSHI is swapped then added as liquidity which results in LP tokens depositd\n     */\n    function depositWithSushi(\n        uint256 amount,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountLPMin,\n        address beneficiary,\n        uint256 deadline\n    ) external override {\n        if (path0[0] != sushi || path0[path0.length - 1] != token0) revert InvalidPath();\n        if (path1[0] != sushi || path1[path1.length - 1] != token1) revert InvalidPath();\n\n        IERC20(sushi).safeTransferFrom(msg.sender, address(this), amount);\n        uint256 amountLP = UniswapV2Utils.addLiquidityWithSingleToken(router, amount, path0, path1, deadline);\n        if (amountLP < amountLPMin) revert InsufficientAmount();\n\n        IMasterChef(masterChef).deposit(pid, amountLP);\n        _depositSushi();\n\n        _mint(beneficiary, amount);\n        withdrawableTotalLPs += amountLP;\n\n        emit Deposit(amount, amountLP, beneficiary);\n    }\n\n    /**\n     * @dev when unstaking, the user's share of LP tokens are returned and pro-rata SUSHI yield is return as well\n     */\n    function withdraw(uint256 shares, address beneficiary) external override nonReentrant {\n        uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n        IMasterChef(masterChef).withdraw(pid, amountLP);\n\n        _claimSushi(shares, beneficiary);\n\n        IERC20(lpToken).safeTransfer(beneficiary, amountLP);\n\n        _burn(msg.sender, shares);\n        withdrawableTotalLPs -= amountLP;\n\n        emit Withdraw(shares, amountLP, beneficiary);\n    }\n\n    function _claimSushi(uint256 shares, address beneficiary) internal {\n        _depositSushi();\n\n        uint256 sharesMax = sharesOf(msg.sender);\n        if (shares > sharesMax) revert InsufficientAmount();\n\n        address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n        uint256 withdrawable = _withdrawableVaultBalanceOf(msg.sender, false);\n        if (withdrawable == 0) revert InsufficientYield();\n\n        uint256 yieldShares = (withdrawable * shares) / sharesMax;\n        _withdrawnVaultBalanceOf[msg.sender] += yieldShares;\n\n        uint256 yield = IERC4626(yieldVault).redeem(yieldShares, beneficiary, address(this));\n\n        emit ClaimSushi(shares, yield, beneficiary);\n    }\n\n    /**\n     * @dev withdraw without caring about rewards. EMERGENCY ONLY\n     */\n    function emergencyWithdraw(address beneficiary) external override nonReentrant {\n        uint256 shares = sharesOf(msg.sender);\n        uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n        IMasterChef(masterChef).withdraw(pid, amountLP);\n\n        IERC20(lpToken).safeTransfer(beneficiary, amountLP);\n\n        _burn(msg.sender, shares);\n        withdrawableTotalLPs -= amountLP;\n\n        emit EmergencyWithdraw(shares, amountLP, beneficiary);\n    }\n\n    /**\n     * @dev migrate to a new version of fLP\n     */\n    function migrate(address beneficiary, bytes calldata params) external nonReentrant {\n        address migrator = IFarmingLPTokenFactory(factory).migrator();\n        if (migrator == address(0)) revert NoMigratorSet();\n\n        uint256 shares = sharesOf(msg.sender);\n        uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n        IMasterChef(masterChef).withdraw(pid, amountLP);\n\n        _claimSushi(shares, beneficiary);\n\n        _burn(msg.sender, shares);\n        withdrawableTotalLPs -= amountLP;\n\n        address _lpToken = lpToken;\n        IERC20(_lpToken).approve(migrator, amountLP);\n        IFarmingLPTokenMigrator(migrator).onMigrate(msg.sender, pid, _lpToken, shares, amountLP, beneficiary, params);\n\n        emit Migrate(shares, amountLP, beneficiary);\n    }\n\n    /**\n     * @dev migrate to a new version of fLP without caring about rewards. EMERGENCY ONLY\n     */\n    function emergencyMigrate(address beneficiary, bytes calldata params) external nonReentrant {\n        address migrator = IFarmingLPTokenFactory(factory).migrator();\n        if (migrator == address(0)) revert NoMigratorSet();\n\n        uint256 shares = sharesOf(msg.sender);\n        uint256 amountLP = (shares * withdrawableTotalLPs) / totalShares();\n        IMasterChef(masterChef).withdraw(pid, amountLP);\n\n        _burn(msg.sender, shares);\n        withdrawableTotalLPs -= amountLP;\n\n        address _lpToken = lpToken;\n        IERC20(_lpToken).approve(migrator, amountLP);\n        IFarmingLPTokenMigrator(migrator).onMigrate(msg.sender, pid, _lpToken, shares, amountLP, beneficiary, params);\n\n        emit EmergencyMigrate(shares, amountLP, beneficiary);\n    }\n\n    /**\n     * @dev withdraws pending SUSHI from MasterChef and add it to the balance\n     */\n    function checkpoint() external override nonReentrant {\n        uint256 balance = IERC20(lpToken).balanceOf(address(this));\n        if (balance > withdrawableTotalLPs) {\n            withdrawableTotalLPs = balance;\n        }\n\n        IMasterChef(masterChef).deposit(pid, 0);\n        _depositSushi();\n    }\n\n    function _depositSushi() internal {\n        uint256 balance = IERC20(sushi).balanceOf(address(this));\n        if (balance > 0) {\n            address yieldVault = IFarmingLPTokenFactory(factory).yieldVault();\n            uint256 yieldBalance = IERC4626(yieldVault).deposit(balance, address(this));\n\n            uint256 total = totalShares();\n            if (total > 0) {\n                _pointsPerShare += (yieldBalance * POINTS_MULTIPLIER) / total;\n            }\n        }\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal override returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n        uint256 balance = balanceOf(from);\n        uint256 shares = balance == 0 ? 0 : (amount * sharesOf(from)) / balance;\n\n        (balanceOfFrom, balanceOfTo) = super._transfer(from, to, shares);\n\n        int256 _magCorrection = (_pointsPerShare * shares).toInt256();\n        _pointsCorrection[from] += _magCorrection;\n        _pointsCorrection[to] += _magCorrection;\n    }\n\n    function _mint(address account, uint256 shares) internal override {\n        super._mint(account, shares);\n\n        _correctPoints(account, -int256(shares));\n    }\n\n    function _burn(address account, uint256 shares) internal override {\n        super._burn(account, shares);\n\n        _correctPoints(account, int256(shares));\n    }\n\n    function _correctPoints(address account, int256 amount) internal {\n        _pointsCorrection[account] += amount * int256(_pointsPerShare);\n    }\n}\n"
    },
    "contracts/interfaces/IFarmingLPToken.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IFarmingLPToken is IERC20 {\n    error InvalidPath();\n    error InsufficientYield();\n    error InsufficientAmount();\n    error NoMigratorSet();\n\n    event Deposit(uint256 shares, uint256 amountLP, address indexed beneficiary);\n    event Withdraw(uint256 shares, uint256 amountLP, address indexed beneficiary);\n    event EmergencyWithdraw(uint256 shares, uint256 amountLP, address indexed beneficiary);\n    event ClaimSushi(uint256 shares, uint256 yield, address indexed beneficiary);\n    event Migrate(uint256 shares, uint256 amountLP, address indexed beneficiary);\n    event EmergencyMigrate(uint256 shares, uint256 amountLP, address indexed beneficiary);\n\n    function initialize(\n        address _router,\n        address _masterChef,\n        uint256 _pid\n    ) external;\n\n    function factory() external view returns (address);\n\n    function router() external view returns (address);\n\n    function masterChef() external view returns (address);\n\n    function sushi() external view returns (address);\n\n    function pid() external view returns (uint256);\n\n    function lpToken() external view returns (address);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function withdrawableTotalLPs() external view returns (uint256);\n\n    function withdrawableLPsOf(address account) external view returns (uint256);\n\n    function withdrawableTotalYield() external view returns (uint256);\n\n    function withdrawableYieldOf(address account) external view returns (uint256);\n\n    function totalShares() external view returns (uint256);\n\n    function sharesOf(address account) external view returns (uint256);\n\n    function approveMax() external;\n\n    function depositSigned(\n        uint256 amountLP,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountMin,\n        address beneficiary,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    function deposit(\n        uint256 amountLP,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountMin,\n        address beneficiary,\n        uint256 deadline\n    ) external;\n\n    function depositWithSushi(\n        uint256 amount,\n        address[] calldata path0,\n        address[] calldata path1,\n        uint256 amountLPMin,\n        address beneficiary,\n        uint256 deadline\n    ) external;\n\n    function withdraw(uint256 shares, address beneficiary) external;\n\n    function emergencyWithdraw(address beneficiary) external;\n\n    function migrate(address beneficiary, bytes calldata params) external;\n\n    function emergencyMigrate(address beneficiary, bytes calldata params) external;\n\n    function checkpoint() external;\n}\n"
    },
    "contracts/interfaces/IFarmingLPTokenFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFarmingLPTokenFactory {\n    error InvalidAddress();\n    error MigratorSet();\n    error TokenCreated();\n\n    event UpdateVault(address indexed vault);\n    event UpdateMigrator(address indexed migrator);\n    event CreateFarmingLPToken(uint256 indexed pid, address indexed token);\n\n    function router() external view returns (address);\n\n    function masterChef() external view returns (address);\n\n    function yieldVault() external view returns (address);\n\n    function migrator() external view returns (address);\n\n    function getFarmingLPToken(uint256 pid) external view returns (address);\n\n    function predictFarmingLPTokenAddress(uint256 pid) external view returns (address token);\n\n    function updateYieldVault(address vault) external;\n\n    function updateMigrator(address vault) external;\n\n    function createFarmingLPToken(uint256 pid) external returns (address token);\n}\n"
    },
    "contracts/interfaces/IFarmingLPTokenMigrator.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFarmingLPTokenMigrator {\n    /**\n     * @dev address of legacy FarmingLPTokenFactory\n     */\n    function factoryLegacy() external view returns (address);\n\n    /**\n     * @dev msg.sender MUST be factoryLegacy.getFarmingLPToken(lpToken)\n     */\n    function onMigrate(\n        address account,\n        uint256 pid,\n        address lpToken,\n        uint256 shares,\n        uint256 amountLP,\n        address beneficiary,\n        bytes calldata params\n    ) external;\n}\n"
    },
    "contracts/interfaces/IMasterChef.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IMasterChef {\n    function sushi() external view returns (address);\n\n    function poolInfo(uint256 _pid)\n        external\n        view\n        returns (\n            address lpToken,\n            uint256 allocPoint,\n            uint256 lastRewardBlock,\n            uint256 accSushiPerShare\n        );\n\n    function userInfo(uint256 _pid, address user) external view returns (uint256 amount, uint256 rewardDebt);\n\n    function pendingSushi(uint256 _pid, address _user) external view returns (uint256);\n\n    function deposit(uint256 _pid, uint256 _amount) external;\n\n    function withdraw(uint256 _pid, uint256 _amount) external;\n}\n"
    },
    "contracts/libraries/UniswapV2Utils.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol\";\n\nlibrary UniswapV2Utils {\n    using SafeERC20 for IERC20;\n\n    error InsufficientAmountLP();\n\n    function quote(\n        address router,\n        uint256 amountIn,\n        address[] memory path\n    ) internal view returns (uint256 amountOut) {\n        if (path.length < 2) return amountIn;\n\n        uint256[] memory amountsOut = IUniswapV2Router02(router).getAmountsOut(amountIn, path);\n        return amountsOut[amountsOut.length - 1];\n    }\n\n    function addLiquidityWithSingleToken(\n        address router,\n        uint256 amount,\n        address[] memory path0,\n        address[] memory path1,\n        uint256 deadline\n    ) internal returns (uint256 amountLP) {\n        uint256 amountOut0 = swap(router, amount / 2, path0, deadline);\n        uint256 amountOut1 = swap(router, amount / 2, path1, deadline);\n\n        (address token0, address token1) = (path0[path0.length - 1], path1[path1.length - 1]);\n        (, , uint256 _amountLP) = IUniswapV2Router02(router).addLiquidity(\n            token0,\n            token1,\n            amountOut0,\n            amountOut1,\n            0,\n            0,\n            address(this),\n            deadline\n        );\n\n        uint256 balance0 = IERC20(token0).balanceOf(address(this));\n        if (balance0 > 0) {\n            IERC20(token0).safeTransfer(msg.sender, balance0);\n        }\n        uint256 balance1 = IERC20(token1).balanceOf(address(this));\n        if (balance1 > 0) {\n            IERC20(token1).safeTransfer(msg.sender, balance1);\n        }\n\n        return _amountLP;\n    }\n\n    function swap(\n        address router,\n        uint256 amountIn,\n        address[] memory path,\n        uint256 deadline\n    ) internal returns (uint256 amountOut) {\n        if (path.length < 2) return amountIn;\n\n        uint256[] memory amountsOut = IUniswapV2Router02(router).swapExactTokensForTokens(\n            amountIn,\n            0,\n            path,\n            address(this),\n            deadline\n        );\n        return amountsOut[amountsOut.length - 1];\n    }\n}\n"
    },
    "contracts/base/BaseERC20.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nabstract contract BaseERC20 is Initializable, IERC20Metadata {\n    error Expired();\n    error InvalidSignature();\n    error InvalidAccount();\n    error InvalidSender();\n    error InvalidReceiver();\n    error InvalidOwner();\n    error InvalidSpender();\n    error NotEnoughBalance();\n\n    uint8 public constant override decimals = 18;\n    bytes32 private _CACHED_DOMAIN_SEPARATOR;\n    uint256 private _CACHED_CHAIN_ID;\n    address private _CACHED_THIS;\n\n    bytes32 private _HASHED_NAME;\n    bytes32 private _HASHED_VERSION;\n    bytes32 private _TYPE_HASH;\n\n    string public override name;\n    string public override symbol;\n\n    uint256 internal _totalSupply;\n    mapping(address => uint256) internal _balanceOf;\n    mapping(address => mapping(address => uint256)) internal _allowance;\n    mapping(address => uint256) public nonces;\n\n    bytes32 private constant _PERMIT_TYPEHASH =\n        keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n    function BaseERC20_initialize(\n        string memory _name,\n        string memory _symbol,\n        string memory _version\n    ) internal onlyInitializing {\n        name = _name;\n        symbol = _symbol;\n\n        bytes32 hashedName = keccak256(bytes(_name));\n        bytes32 hashedVersion = keccak256(bytes(_version));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _CACHED_THIS = address(this);\n        _TYPE_HASH = typeHash;\n    }\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    function totalSupply() external view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    function balanceOf(address account) external view virtual returns (uint256) {\n        return _balanceOf[account];\n    }\n\n    function allowance(address owner, address spender) external view virtual returns (uint256) {\n        return _allowance[owner][spender];\n    }\n\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual {\n        if (block.timestamp > deadline) revert Expired();\n\n        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline));\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        if (signer != owner) revert InvalidSignature();\n\n        _approve(owner, spender, value);\n    }\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool) {\n        if (_allowance[from][msg.sender] != type(uint256).max) {\n            _allowance[from][msg.sender] -= amount;\n        }\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    function transfer(address to, uint256 amount) external override returns (bool) {\n        _transfer(msg.sender, to, amount);\n        return true;\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n        if (from == address(0)) revert InvalidSender();\n        if (to == address(0)) revert InvalidReceiver();\n\n        uint256 balance = _balanceOf[from];\n        if (balance < amount) revert NotEnoughBalance();\n        unchecked {\n            balanceOfFrom = balance - amount;\n            balanceOfTo = _balanceOf[to] + amount;\n            _balanceOf[from] = balanceOfFrom;\n            _balanceOf[to] = balanceOfTo;\n        }\n\n        emit Transfer(from, to, amount);\n    }\n\n    function approve(address spender, uint256 amount) external override returns (bool) {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        if (owner == address(0)) revert InvalidOwner();\n        if (spender == address(0)) revert InvalidSpender();\n\n        _allowance[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    function _mint(address account, uint256 amount) internal virtual {\n        if (account == address(0)) revert InvalidAccount();\n\n        _totalSupply += amount;\n        unchecked {\n            _balanceOf[account] += amount;\n        }\n\n        emit Transfer(address(0), account, amount);\n    }\n\n    function _burn(address account, uint256 amount) internal virtual {\n        if (account == address(0)) revert InvalidAccount();\n\n        uint256 balance = _balanceOf[account];\n        if (balance < amount) revert NotEnoughBalance();\n        unchecked {\n            _balanceOf[account] = balance - amount;\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n    }\n}\n"
    },
    "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/SafeCast.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint248 from uint256, reverting on\n     * overflow (when the input is greater than largest uint248).\n     *\n     * Counterpart to Solidity's `uint248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint248(uint256 value) internal pure returns (uint248) {\n        require(value <= type(uint248).max, \"SafeCast: value doesn't fit in 248 bits\");\n        return uint248(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint240 from uint256, reverting on\n     * overflow (when the input is greater than largest uint240).\n     *\n     * Counterpart to Solidity's `uint240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint240(uint256 value) internal pure returns (uint240) {\n        require(value <= type(uint240).max, \"SafeCast: value doesn't fit in 240 bits\");\n        return uint240(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint232 from uint256, reverting on\n     * overflow (when the input is greater than largest uint232).\n     *\n     * Counterpart to Solidity's `uint232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint232(uint256 value) internal pure returns (uint232) {\n        require(value <= type(uint232).max, \"SafeCast: value doesn't fit in 232 bits\");\n        return uint232(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint216 from uint256, reverting on\n     * overflow (when the input is greater than largest uint216).\n     *\n     * Counterpart to Solidity's `uint216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint216(uint256 value) internal pure returns (uint216) {\n        require(value <= type(uint216).max, \"SafeCast: value doesn't fit in 216 bits\");\n        return uint216(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint208 from uint256, reverting on\n     * overflow (when the input is greater than largest uint208).\n     *\n     * Counterpart to Solidity's `uint208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint208(uint256 value) internal pure returns (uint208) {\n        require(value <= type(uint208).max, \"SafeCast: value doesn't fit in 208 bits\");\n        return uint208(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint200 from uint256, reverting on\n     * overflow (when the input is greater than largest uint200).\n     *\n     * Counterpart to Solidity's `uint200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint200(uint256 value) internal pure returns (uint200) {\n        require(value <= type(uint200).max, \"SafeCast: value doesn't fit in 200 bits\");\n        return uint200(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint192 from uint256, reverting on\n     * overflow (when the input is greater than largest uint192).\n     *\n     * Counterpart to Solidity's `uint192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint192(uint256 value) internal pure returns (uint192) {\n        require(value <= type(uint192).max, \"SafeCast: value doesn't fit in 192 bits\");\n        return uint192(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint184 from uint256, reverting on\n     * overflow (when the input is greater than largest uint184).\n     *\n     * Counterpart to Solidity's `uint184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint184(uint256 value) internal pure returns (uint184) {\n        require(value <= type(uint184).max, \"SafeCast: value doesn't fit in 184 bits\");\n        return uint184(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint176 from uint256, reverting on\n     * overflow (when the input is greater than largest uint176).\n     *\n     * Counterpart to Solidity's `uint176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint176(uint256 value) internal pure returns (uint176) {\n        require(value <= type(uint176).max, \"SafeCast: value doesn't fit in 176 bits\");\n        return uint176(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint168 from uint256, reverting on\n     * overflow (when the input is greater than largest uint168).\n     *\n     * Counterpart to Solidity's `uint168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint168(uint256 value) internal pure returns (uint168) {\n        require(value <= type(uint168).max, \"SafeCast: value doesn't fit in 168 bits\");\n        return uint168(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint160 from uint256, reverting on\n     * overflow (when the input is greater than largest uint160).\n     *\n     * Counterpart to Solidity's `uint160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint160(uint256 value) internal pure returns (uint160) {\n        require(value <= type(uint160).max, \"SafeCast: value doesn't fit in 160 bits\");\n        return uint160(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint152 from uint256, reverting on\n     * overflow (when the input is greater than largest uint152).\n     *\n     * Counterpart to Solidity's `uint152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint152(uint256 value) internal pure returns (uint152) {\n        require(value <= type(uint152).max, \"SafeCast: value doesn't fit in 152 bits\");\n        return uint152(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint144 from uint256, reverting on\n     * overflow (when the input is greater than largest uint144).\n     *\n     * Counterpart to Solidity's `uint144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint144(uint256 value) internal pure returns (uint144) {\n        require(value <= type(uint144).max, \"SafeCast: value doesn't fit in 144 bits\");\n        return uint144(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint136 from uint256, reverting on\n     * overflow (when the input is greater than largest uint136).\n     *\n     * Counterpart to Solidity's `uint136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint136(uint256 value) internal pure returns (uint136) {\n        require(value <= type(uint136).max, \"SafeCast: value doesn't fit in 136 bits\");\n        return uint136(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint120 from uint256, reverting on\n     * overflow (when the input is greater than largest uint120).\n     *\n     * Counterpart to Solidity's `uint120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint120(uint256 value) internal pure returns (uint120) {\n        require(value <= type(uint120).max, \"SafeCast: value doesn't fit in 120 bits\");\n        return uint120(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint112 from uint256, reverting on\n     * overflow (when the input is greater than largest uint112).\n     *\n     * Counterpart to Solidity's `uint112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint112(uint256 value) internal pure returns (uint112) {\n        require(value <= type(uint112).max, \"SafeCast: value doesn't fit in 112 bits\");\n        return uint112(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint104 from uint256, reverting on\n     * overflow (when the input is greater than largest uint104).\n     *\n     * Counterpart to Solidity's `uint104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint104(uint256 value) internal pure returns (uint104) {\n        require(value <= type(uint104).max, \"SafeCast: value doesn't fit in 104 bits\");\n        return uint104(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.2._\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint88 from uint256, reverting on\n     * overflow (when the input is greater than largest uint88).\n     *\n     * Counterpart to Solidity's `uint88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint88(uint256 value) internal pure returns (uint88) {\n        require(value <= type(uint88).max, \"SafeCast: value doesn't fit in 88 bits\");\n        return uint88(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint80 from uint256, reverting on\n     * overflow (when the input is greater than largest uint80).\n     *\n     * Counterpart to Solidity's `uint80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint80(uint256 value) internal pure returns (uint80) {\n        require(value <= type(uint80).max, \"SafeCast: value doesn't fit in 80 bits\");\n        return uint80(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint72 from uint256, reverting on\n     * overflow (when the input is greater than largest uint72).\n     *\n     * Counterpart to Solidity's `uint72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint72(uint256 value) internal pure returns (uint72) {\n        require(value <= type(uint72).max, \"SafeCast: value doesn't fit in 72 bits\");\n        return uint72(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint56 from uint256, reverting on\n     * overflow (when the input is greater than largest uint56).\n     *\n     * Counterpart to Solidity's `uint56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint56(uint256 value) internal pure returns (uint56) {\n        require(value <= type(uint56).max, \"SafeCast: value doesn't fit in 56 bits\");\n        return uint56(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint48 from uint256, reverting on\n     * overflow (when the input is greater than largest uint48).\n     *\n     * Counterpart to Solidity's `uint48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint48(uint256 value) internal pure returns (uint48) {\n        require(value <= type(uint48).max, \"SafeCast: value doesn't fit in 48 bits\");\n        return uint48(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint40 from uint256, reverting on\n     * overflow (when the input is greater than largest uint40).\n     *\n     * Counterpart to Solidity's `uint40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint40(uint256 value) internal pure returns (uint40) {\n        require(value <= type(uint40).max, \"SafeCast: value doesn't fit in 40 bits\");\n        return uint40(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint24 from uint256, reverting on\n     * overflow (when the input is greater than largest uint24).\n     *\n     * Counterpart to Solidity's `uint24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toUint24(uint256 value) internal pure returns (uint24) {\n        require(value <= type(uint24).max, \"SafeCast: value doesn't fit in 24 bits\");\n        return uint24(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v2.5._\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     *\n     * _Available since v3.0._\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int248 from int256, reverting on\n     * overflow (when the input is less than smallest int248 or\n     * greater than largest int248).\n     *\n     * Counterpart to Solidity's `int248` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 248 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt248(int256 value) internal pure returns (int248 downcasted) {\n        downcasted = int248(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 248 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int240 from int256, reverting on\n     * overflow (when the input is less than smallest int240 or\n     * greater than largest int240).\n     *\n     * Counterpart to Solidity's `int240` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 240 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt240(int256 value) internal pure returns (int240 downcasted) {\n        downcasted = int240(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 240 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int232 from int256, reverting on\n     * overflow (when the input is less than smallest int232 or\n     * greater than largest int232).\n     *\n     * Counterpart to Solidity's `int232` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 232 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt232(int256 value) internal pure returns (int232 downcasted) {\n        downcasted = int232(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 232 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int224 from int256, reverting on\n     * overflow (when the input is less than smallest int224 or\n     * greater than largest int224).\n     *\n     * Counterpart to Solidity's `int224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt224(int256 value) internal pure returns (int224 downcasted) {\n        downcasted = int224(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 224 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int216 from int256, reverting on\n     * overflow (when the input is less than smallest int216 or\n     * greater than largest int216).\n     *\n     * Counterpart to Solidity's `int216` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 216 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt216(int256 value) internal pure returns (int216 downcasted) {\n        downcasted = int216(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 216 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int208 from int256, reverting on\n     * overflow (when the input is less than smallest int208 or\n     * greater than largest int208).\n     *\n     * Counterpart to Solidity's `int208` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 208 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt208(int256 value) internal pure returns (int208 downcasted) {\n        downcasted = int208(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 208 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int200 from int256, reverting on\n     * overflow (when the input is less than smallest int200 or\n     * greater than largest int200).\n     *\n     * Counterpart to Solidity's `int200` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 200 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt200(int256 value) internal pure returns (int200 downcasted) {\n        downcasted = int200(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 200 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int192 from int256, reverting on\n     * overflow (when the input is less than smallest int192 or\n     * greater than largest int192).\n     *\n     * Counterpart to Solidity's `int192` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 192 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt192(int256 value) internal pure returns (int192 downcasted) {\n        downcasted = int192(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 192 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int184 from int256, reverting on\n     * overflow (when the input is less than smallest int184 or\n     * greater than largest int184).\n     *\n     * Counterpart to Solidity's `int184` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 184 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt184(int256 value) internal pure returns (int184 downcasted) {\n        downcasted = int184(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 184 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int176 from int256, reverting on\n     * overflow (when the input is less than smallest int176 or\n     * greater than largest int176).\n     *\n     * Counterpart to Solidity's `int176` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 176 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt176(int256 value) internal pure returns (int176 downcasted) {\n        downcasted = int176(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 176 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int168 from int256, reverting on\n     * overflow (when the input is less than smallest int168 or\n     * greater than largest int168).\n     *\n     * Counterpart to Solidity's `int168` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 168 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt168(int256 value) internal pure returns (int168 downcasted) {\n        downcasted = int168(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 168 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int160 from int256, reverting on\n     * overflow (when the input is less than smallest int160 or\n     * greater than largest int160).\n     *\n     * Counterpart to Solidity's `int160` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 160 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt160(int256 value) internal pure returns (int160 downcasted) {\n        downcasted = int160(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 160 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int152 from int256, reverting on\n     * overflow (when the input is less than smallest int152 or\n     * greater than largest int152).\n     *\n     * Counterpart to Solidity's `int152` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 152 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt152(int256 value) internal pure returns (int152 downcasted) {\n        downcasted = int152(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 152 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int144 from int256, reverting on\n     * overflow (when the input is less than smallest int144 or\n     * greater than largest int144).\n     *\n     * Counterpart to Solidity's `int144` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 144 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt144(int256 value) internal pure returns (int144 downcasted) {\n        downcasted = int144(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 144 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int136 from int256, reverting on\n     * overflow (when the input is less than smallest int136 or\n     * greater than largest int136).\n     *\n     * Counterpart to Solidity's `int136` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 136 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt136(int256 value) internal pure returns (int136 downcasted) {\n        downcasted = int136(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 136 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128 downcasted) {\n        downcasted = int128(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 128 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int120 from int256, reverting on\n     * overflow (when the input is less than smallest int120 or\n     * greater than largest int120).\n     *\n     * Counterpart to Solidity's `int120` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 120 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt120(int256 value) internal pure returns (int120 downcasted) {\n        downcasted = int120(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 120 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int112 from int256, reverting on\n     * overflow (when the input is less than smallest int112 or\n     * greater than largest int112).\n     *\n     * Counterpart to Solidity's `int112` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 112 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt112(int256 value) internal pure returns (int112 downcasted) {\n        downcasted = int112(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 112 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int104 from int256, reverting on\n     * overflow (when the input is less than smallest int104 or\n     * greater than largest int104).\n     *\n     * Counterpart to Solidity's `int104` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 104 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt104(int256 value) internal pure returns (int104 downcasted) {\n        downcasted = int104(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 104 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int96 from int256, reverting on\n     * overflow (when the input is less than smallest int96 or\n     * greater than largest int96).\n     *\n     * Counterpart to Solidity's `int96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt96(int256 value) internal pure returns (int96 downcasted) {\n        downcasted = int96(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 96 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int88 from int256, reverting on\n     * overflow (when the input is less than smallest int88 or\n     * greater than largest int88).\n     *\n     * Counterpart to Solidity's `int88` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 88 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt88(int256 value) internal pure returns (int88 downcasted) {\n        downcasted = int88(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 88 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int80 from int256, reverting on\n     * overflow (when the input is less than smallest int80 or\n     * greater than largest int80).\n     *\n     * Counterpart to Solidity's `int80` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 80 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt80(int256 value) internal pure returns (int80 downcasted) {\n        downcasted = int80(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 80 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int72 from int256, reverting on\n     * overflow (when the input is less than smallest int72 or\n     * greater than largest int72).\n     *\n     * Counterpart to Solidity's `int72` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 72 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt72(int256 value) internal pure returns (int72 downcasted) {\n        downcasted = int72(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 72 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64 downcasted) {\n        downcasted = int64(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 64 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int56 from int256, reverting on\n     * overflow (when the input is less than smallest int56 or\n     * greater than largest int56).\n     *\n     * Counterpart to Solidity's `int56` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 56 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt56(int256 value) internal pure returns (int56 downcasted) {\n        downcasted = int56(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 56 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int48 from int256, reverting on\n     * overflow (when the input is less than smallest int48 or\n     * greater than largest int48).\n     *\n     * Counterpart to Solidity's `int48` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 48 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt48(int256 value) internal pure returns (int48 downcasted) {\n        downcasted = int48(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 48 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int40 from int256, reverting on\n     * overflow (when the input is less than smallest int40 or\n     * greater than largest int40).\n     *\n     * Counterpart to Solidity's `int40` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 40 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt40(int256 value) internal pure returns (int40 downcasted) {\n        downcasted = int40(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 40 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32 downcasted) {\n        downcasted = int32(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 32 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int24 from int256, reverting on\n     * overflow (when the input is less than smallest int24 or\n     * greater than largest int24).\n     *\n     * Counterpart to Solidity's `int24` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 24 bits\n     *\n     * _Available since v4.7._\n     */\n    function toInt24(int256 value) internal pure returns (int24 downcasted) {\n        downcasted = int24(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 24 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16 downcasted) {\n        downcasted = int16(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 16 bits\");\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8 downcasted) {\n        downcasted = int8(value);\n        require(downcasted == value, \"SafeCast: value doesn't fit in 8 bits\");\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     *\n     * _Available since v3.0._\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
    },
    "@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Pair.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n    event Approval(address indexed owner, address indexed spender, uint value);\n    event Transfer(address indexed from, address indexed to, uint value);\n\n    function name() external pure returns (string memory);\n    function symbol() external pure returns (string memory);\n    function decimals() external pure returns (uint8);\n    function totalSupply() external view returns (uint);\n    function balanceOf(address owner) external view returns (uint);\n    function allowance(address owner, address spender) external view returns (uint);\n\n    function approve(address spender, uint value) external returns (bool);\n    function transfer(address to, uint value) external returns (bool);\n    function transferFrom(address from, address to, uint value) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n    function nonces(address owner) external view returns (uint);\n\n    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;\n\n    event Mint(address indexed sender, uint amount0, uint amount1);\n    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);\n    event Swap(\n        address indexed sender,\n        uint amount0In,\n        uint amount1In,\n        uint amount0Out,\n        uint amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint);\n    function factory() external view returns (address);\n    function token0() external view returns (address);\n    function token1() external view returns (address);\n    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\n    function price0CumulativeLast() external view returns (uint);\n    function price1CumulativeLast() external view returns (uint);\n    function kLast() external view returns (uint);\n\n    function mint(address to) external returns (uint liquidity);\n    function burn(address to) external returns (uint amount0, uint amount1);\n    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;\n    function skim(address to) external;\n    function sync() external;\n\n    function initialize(address, address) external;\n}"
    },
    "@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router02.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\nimport './IUniswapV2Router01.sol';\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountETH);\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external payable;\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external;\n}"
    },
    "@sushiswap/core/contracts/uniswapv2/interfaces/IUniswapV2Router01.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint amountADesired,\n        uint amountBDesired,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB, uint liquidity);\n    function addLiquidityETH(\n        address token,\n        uint amountTokenDesired,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETH(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline\n    ) external returns (uint amountToken, uint amountETH);\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint liquidity,\n        uint amountAMin,\n        uint amountBMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountA, uint amountB);\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint liquidity,\n        uint amountTokenMin,\n        uint amountETHMin,\n        address to,\n        uint deadline,\n        bool approveMax, uint8 v, bytes32 r, bytes32 s\n    ) external returns (uint amountToken, uint amountETH);\n    function swapExactTokensForTokens(\n        uint amountIn,\n        uint amountOutMin,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapTokensForExactTokens(\n        uint amountOut,\n        uint amountInMax,\n        address[] calldata path,\n        address to,\n        uint deadline\n    ) external returns (uint[] memory amounts);\n    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)\n        external\n        returns (uint[] memory amounts);\n    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)\n        external\n        payable\n        returns (uint[] memory amounts);\n\n    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);\n    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);\n    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);\n    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);\n    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);\n}"
    },
    "@openzeppelin/contracts/proxy/utils/Initializable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized < type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Internal function that returns the initialized version. Returns `_initialized`\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Internal function that returns the initialized version. Returns `_initializing`\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
    },
    "contracts/FarmingLPTokenFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./FarmingLPToken.sol\";\n\ncontract FarmingLPTokenFactory is Ownable, IFarmingLPTokenFactory {\n    address public immutable override router;\n    address public immutable override masterChef;\n    address internal immutable _implementation;\n\n    address public override yieldVault;\n    address public override migrator;\n    mapping(uint256 => address) public override getFarmingLPToken;\n\n    constructor(\n        address _router,\n        address _masterChef,\n        address _yieldVault\n    ) {\n        router = _router;\n        masterChef = _masterChef;\n        yieldVault = _yieldVault;\n        FarmingLPToken token = new FarmingLPToken();\n        token.initialize(address(0), address(0), 0);\n        _implementation = address(token);\n    }\n\n    function predictFarmingLPTokenAddress(uint256 pid) external view override returns (address token) {\n        token = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n    }\n\n    function updateYieldVault(address vault) external override onlyOwner {\n        if (vault == address(0)) revert InvalidAddress();\n        yieldVault = vault;\n\n        emit UpdateVault(vault);\n    }\n\n    function updateMigrator(address _migrator) external override onlyOwner {\n        if (_migrator != address(0)) revert MigratorSet();\n        migrator = _migrator;\n\n        emit UpdateMigrator(_migrator);\n    }\n\n    function createFarmingLPToken(uint256 pid) external override returns (address token) {\n        if (getFarmingLPToken[pid] != address(0)) revert TokenCreated();\n\n        token = Clones.cloneDeterministic(_implementation, bytes32(pid));\n        FarmingLPToken(token).initialize(router, masterChef, pid);\n\n        getFarmingLPToken[pid] = token;\n\n        emit CreateFarmingLPToken(pid, token);\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/Clones.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n *\n * _Available since v3.4._\n */\nlibrary Clones {\n    /**\n     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n     *\n     * This function uses the create opcode, which should never revert.\n     */\n    function clone(address implementation) internal returns (address instance) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n            // of the `implementation` address with the bytecode before the address.\n            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n            instance := create(0, 0x09, 0x37)\n        }\n        require(instance != address(0), \"ERC1167: create failed\");\n    }\n\n    /**\n     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.\n     *\n     * This function uses the create2 opcode and a `salt` to deterministically deploy\n     * the clone. Using the same `implementation` and `salt` multiple time will revert, since\n     * the clones cannot be deployed twice at the same address.\n     */\n    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n            // of the `implementation` address with the bytecode before the address.\n            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n            instance := create2(0, 0x09, 0x37, salt)\n        }\n        require(instance != address(0), \"ERC1167: create2 failed\");\n    }\n\n    /**\n     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n     */\n    function predictDeterministicAddress(\n        address implementation,\n        bytes32 salt,\n        address deployer\n    ) internal pure returns (address predicted) {\n        /// @solidity memory-safe-assembly\n        assembly {\n            let ptr := mload(0x40)\n            mstore(add(ptr, 0x38), deployer)\n            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)\n            mstore(add(ptr, 0x14), implementation)\n            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)\n            mstore(add(ptr, 0x58), salt)\n            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))\n            predicted := keccak256(add(ptr, 0x43), 0x55)\n        }\n    }\n\n    /**\n     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n     */\n    function predictDeterministicAddress(address implementation, bytes32 salt)\n        internal\n        view\n        returns (address predicted)\n    {\n        return predictDeterministicAddress(implementation, salt, address(this));\n    }\n}\n"
    },
    "contracts/SousChef.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"./interfaces/ISousChef.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./interfaces/IFSushiRestaurant.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./interfaces/IFlashStrategySushiSwap.sol\";\nimport \"./FSushiBill.sol\";\n\ncontract SousChef is Ownable, ISousChef {\n    using SafeERC20 for IERC20;\n    using SafeCast for uint256;\n    using SafeCast for int256;\n    using DateUtils for uint256;\n\n    uint256 internal constant BONUS_MULTIPLIER = 10;\n    uint256 internal constant REWARDS_PER_WEEK = 3000e18;\n    uint256 internal constant REWARDS_FOR_INITIAL_WEEKS = BONUS_MULTIPLIER * REWARDS_PER_WEEK;\n\n    address public immutable override fSushi;\n    address public immutable override flashStrategyFactory;\n    uint256 public immutable override startWeek;\n\n    address internal immutable _implementation;\n\n    /**\n     * @notice address of IFSushiRestaurant\n     */\n    address public override restaurant;\n\n    /**\n     * @notice address of IFSushiKitchen\n     */\n    address public override kitchen;\n\n    mapping(uint256 => address) public override getBill;\n    /**\n     * @notice how much rewards to be minted at the week\n     */\n    mapping(uint256 => uint256) public override weeklyRewards; // week => amount\n    /**\n     * @notice weeklyRewards is guaranteed to be correct before this week (exclusive)\n     */\n    uint256 public override lastCheckpoint; // week\n\n    constructor(\n        address _fSushi,\n        address _restaurant,\n        address _kitchen,\n        address _flashStrategyFactory\n    ) {\n        fSushi = _fSushi;\n        restaurant = _restaurant;\n        kitchen = _kitchen;\n        flashStrategyFactory = _flashStrategyFactory;\n        uint256 thisWeek = block.timestamp.toWeekNumber();\n        startWeek = thisWeek;\n        lastCheckpoint = thisWeek + 1;\n        weeklyRewards[thisWeek] = REWARDS_FOR_INITIAL_WEEKS;\n\n        FSushiBill bill = new FSushiBill();\n        bill.initialize(0, address(0));\n        _implementation = address(bill);\n    }\n\n    function predictBillAddress(uint256 pid) external view override returns (address bill) {\n        bill = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n    }\n\n    function updateRestaurant(address _restaurant) external override onlyOwner {\n        if (_restaurant == address(0)) revert InvalidRestaurant();\n\n        restaurant = _restaurant;\n\n        emit UpdateRestaurant(_restaurant);\n    }\n\n    function updateKitchen(address _kitchen) external override onlyOwner {\n        if (_kitchen == address(0)) revert InvalidKitchen();\n\n        kitchen = _kitchen;\n\n        emit UpdateKitchen(_kitchen);\n    }\n\n    function createBill(uint256 pid) external override returns (address bill) {\n        if (getBill[pid] != address(0)) revert BillCreated();\n\n        address strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).getFlashStrategySushiSwap(pid);\n        if (strategy == address(0))\n            strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).createFlashStrategySushiSwap(pid);\n\n        bill = Clones.cloneDeterministic(_implementation, bytes32(pid));\n        FSushiBill(bill).initialize(pid, IFlashStrategySushiSwap(strategy).fToken());\n\n        getBill[pid] = bill;\n\n        emit CreateBill(pid, bill);\n    }\n\n    /**\n     * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n     */\n    function checkpoint() external override {\n        uint256 from = lastCheckpoint;\n        uint256 until = block.timestamp.toWeekNumber() + 1;\n        if (until <= from) return;\n\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            if (until <= week) break;\n            weeklyRewards[week] = _rewards(week);\n\n            unchecked {\n                ++i;\n            }\n        }\n        lastCheckpoint = until;\n    }\n\n    function _rewards(uint256 week) internal returns (uint256) {\n        if (week < startWeek + 2) return REWARDS_FOR_INITIAL_WEEKS;\n        if (week == startWeek + 2) return REWARDS_PER_WEEK;\n\n        uint256 totalSupply = IFSushi(fSushi).checkpointedTotalSupplyDuring(week - 1);\n        uint256 lockedAssets = IFSushiRestaurant(restaurant).checkpointedTotalAssetsDuring(week - 1);\n\n        uint256 rewards = (totalSupply == 0 || totalSupply < lockedAssets)\n            ? 0\n            : (REWARDS_PER_WEEK * (totalSupply - lockedAssets)) / totalSupply;\n\n        // emission rate decreases 1% every week from week 3\n        if (week - startWeek > 2) {\n            rewards = (rewards * 99) / 100;\n        }\n        return rewards;\n    }\n\n    function mintFSushi(\n        uint256 pid,\n        address to,\n        uint256 amount\n    ) external override {\n        if (getBill[pid] != msg.sender) revert Forbidden();\n\n        IFSushi(fSushi).mint(to, amount);\n    }\n}\n"
    },
    "contracts/interfaces/ISousChef.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface ISousChef {\n    error BillCreated();\n    error InvalidRestaurant();\n    error InvalidKitchen();\n    error Forbidden();\n\n    event UpdateRestaurant(address indexed restaurant);\n    event UpdateKitchen(address indexed kitchen);\n    event CreateBill(uint256 indexed pid, address indexed bill);\n    event Checkpoint();\n\n    function fSushi() external view returns (address);\n\n    function flashStrategyFactory() external view returns (address);\n\n    function startWeek() external view returns (uint256);\n\n    function restaurant() external view returns (address);\n\n    function kitchen() external view returns (address);\n\n    function getBill(uint256 pid) external view returns (address);\n\n    function weeklyRewards(uint256 week) external view returns (uint256);\n\n    function lastCheckpoint() external view returns (uint256);\n\n    function predictBillAddress(uint256 pid) external view returns (address bill);\n\n    function updateRestaurant(address _restaurant) external;\n\n    function updateKitchen(address _kitchen) external;\n\n    function createBill(uint256 pid) external returns (address strategy);\n\n    function checkpoint() external;\n\n    function mintFSushi(\n        uint256 pid,\n        address to,\n        uint256 amount\n    ) external;\n}\n"
    },
    "contracts/interfaces/IFSushiRestaurant.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFSushiRestaurant {\n    function startWeek() external view returns (uint256);\n\n    function totalAssets() external view returns (uint256);\n\n    function totalAssetsDuring(uint256 week) external view returns (uint256);\n\n    function lastCheckpoint() external view returns (uint256);\n\n    function checkpointedTotalAssets() external returns (uint256);\n\n    function checkpointedTotalAssetsDuring(uint256 week) external returns (uint256);\n\n    function checkpoint() external;\n}\n"
    },
    "contracts/interfaces/IFlashStrategySushiSwapFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFlashStrategySushiSwapFactory {\n    error InvalidFee();\n    error InvalidFeeRecipient();\n    error FlashStrategySushiSwapCreated();\n\n    event UpdateStakeFeeBPS(uint256 fee);\n    event UpdateFlashStakeFeeBPS(uint256 fee);\n    event UpdateFeeRecipient(address feeRecipient);\n    event CreateFlashStrategySushiSwap(uint256 pid, address strategy);\n\n    function flashProtocol() external view returns (address);\n\n    function flpTokenFactory() external view returns (address);\n\n    function feeRecipient() external view returns (address);\n\n    function getFlashStrategySushiSwap(uint256 pid) external view returns (address);\n\n    function predictFlashStrategySushiSwapAddress(uint256 pid) external view returns (address strategy);\n\n    function updateFeeRecipient(address _feeRecipient) external;\n\n    function createFlashStrategySushiSwap(uint256 pid) external returns (address strategy);\n}\n"
    },
    "contracts/interfaces/IFlashStrategySushiSwap.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"./IFlashStrategy.sol\";\n\ninterface IFlashStrategySushiSwap is IFlashStrategy {\n    error Forbidden();\n    error InvalidVault();\n    error AmountTooLow();\n    error InsufficientYield();\n    error InsufficientTotalSupply();\n\n    function factory() external view returns (address);\n\n    function flashProtocol() external view returns (address);\n\n    function fToken() external view returns (address);\n\n    function sushi() external view returns (address);\n\n    function flpToken() external view returns (address);\n\n    function initialize(address _flashProtocol, address _flpToken) external;\n}\n"
    },
    "contracts/FSushiBill.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./base/BaseERC20.sol\";\nimport \"./interfaces/IFSushiBill.sol\";\nimport \"./interfaces/ISousChef.sol\";\nimport \"./interfaces/IFSushiKitchen.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushiBill is BaseERC20, IFSushiBill {\n    using SafeERC20 for IERC20;\n    using DateUtils for uint256;\n\n    address public override sousChef;\n    uint256 public override pid;\n    address public override fToken;\n\n    /**\n     * @notice points = ∫W(t)dt, where W(t) is the total supply at the week\n     */\n    mapping(uint256 => uint256) public override points; // week => points\n    /**\n     * @notice points are guaranteed to be correct before this time's week start\n     */\n    uint256 public override lastCheckpoint; // timestamp\n\n    /**\n     * @notice userPoints = ∫w(t)dt, where a(t) is the balance of account at the week\n     */\n    mapping(address => mapping(uint256 => uint256)) public override userPoints; // account => week => points\n    /**\n     * @notice userPoints of account is guaranteed to be correct before this week\n     */\n    mapping(address => uint256) public override userLastCheckpoint; // account => timestamp\n    /**\n     * @notice how much rewards were claimed in total for account\n     */\n    mapping(address => uint256) public override claimedRewards; // account => amount\n    /**\n     * @notice in the next claim, rewards will be accumulated from this week\n     */\n    mapping(address => uint256) public override nextClaimableWeek; // account => week\n\n    function initialize(uint256 _pid, address _fToken) external override initializer {\n        if (_fToken == address(0)) return;\n\n        BaseERC20_initialize(\n            string.concat(\"Flash Sushi Bill for \", IERC20Metadata(_fToken).name()),\n            string.concat(\"x\", IERC20Metadata(_fToken).symbol()),\n            \"1\"\n        );\n\n        sousChef = msg.sender;\n        pid = _pid;\n        fToken = _fToken;\n    }\n\n    function deposit(uint256 amount, address beneficiary) external override {\n        userCheckpoint(msg.sender);\n\n        if (amount > 0) {\n            IERC20(fToken).safeTransferFrom(msg.sender, address(this), amount);\n\n            uint256 balance = _balanceOf[msg.sender] + amount;\n            _balanceOf[msg.sender] = balance;\n            uint256 totalSupply = _totalSupply + amount;\n            _totalSupply = totalSupply;\n\n            _mint(beneficiary, amount);\n        }\n\n        emit Deposit(msg.sender, amount, beneficiary);\n    }\n\n    function withdraw(uint256 amount, address beneficiary) external override {\n        userCheckpoint(msg.sender);\n\n        if (amount > 0) {\n            uint256 balance = _balanceOf[msg.sender] - amount;\n            _balanceOf[msg.sender] = balance;\n            uint256 totalSupply = _totalSupply - amount;\n            _totalSupply = totalSupply;\n\n            _burn(msg.sender, amount);\n\n            IERC20(fToken).safeTransfer(beneficiary, amount);\n        }\n\n        emit Withdraw(msg.sender, amount, beneficiary);\n    }\n\n    /**\n     * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n     */\n    function checkpoint() public override {\n        ISousChef(sousChef).checkpoint();\n\n        uint256 prevCheckpoint = lastCheckpoint;\n        _updatePoints(points, _totalSupply, prevCheckpoint);\n        if (prevCheckpoint < block.timestamp) {\n            lastCheckpoint = block.timestamp;\n        }\n\n        emit Checkpoint();\n    }\n\n    function userCheckpoint(address account) public override {\n        checkpoint();\n\n        uint256 prevCheckpoint = userLastCheckpoint[account];\n        _updatePoints(userPoints[account], _balanceOf[account], prevCheckpoint);\n        if (prevCheckpoint < block.timestamp) {\n            userLastCheckpoint[account] = block.timestamp;\n        }\n\n        emit UserCheckpoint(account);\n    }\n\n    function _updatePoints(\n        mapping(uint256 => uint256) storage _points,\n        uint256 balance,\n        uint256 lastTime\n    ) internal {\n        if (balance == 0) return;\n\n        if (lastTime == 0) {\n            uint256 startWeek = ISousChef(sousChef).startWeek();\n            lastTime = startWeek.toTimestamp();\n        }\n\n        uint256 from = lastTime.toWeekNumber();\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            uint256 weekStart = week.toTimestamp();\n            uint256 weekEnd = weekStart + WEEK;\n            if (block.timestamp <= weekStart) break;\n            if (block.timestamp < weekEnd) {\n                _points[week] += balance * (block.timestamp - Math.max(lastTime, weekStart));\n                break;\n            }\n            if (i == 0) {\n                _points[week] += balance * (weekEnd - lastTime);\n            } else {\n                _points[week] += balance * WEEK;\n            }\n\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    function claimRewards(address beneficiary) external {\n        userCheckpoint(msg.sender);\n\n        uint256 from = nextClaimableWeek[msg.sender];\n        if (from == block.timestamp.toWeekNumber()) return;\n        if (from == 0) {\n            from = ISousChef(sousChef).startWeek();\n        }\n\n        (address _sousChef, uint256 _pid) = (sousChef, pid);\n        address kitchen = ISousChef(_sousChef).kitchen();\n        IFSushiKitchen(kitchen).checkpoint(_pid);\n\n        // add week-by-week rewards until the last week\n        uint256 totalRewards;\n        uint256 to = block.timestamp.toWeekNumber(); // exclusive last index\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            if (to <= week) break;\n            uint256 weeklyRewards = ISousChef(_sousChef).weeklyRewards(week);\n            uint256 weight = IFSushiKitchen(kitchen).relativeWeightAt(_pid, (week + 1).toTimestamp());\n            uint256 rewards = points[week] == 0\n                ? 0\n                : (weeklyRewards * weight * userPoints[msg.sender][week]) / points[week] / 1e18;\n            totalRewards += rewards;\n\n            unchecked {\n                ++i;\n            }\n        }\n        nextClaimableWeek[msg.sender] = to;\n\n        if (totalRewards > 0) {\n            claimedRewards[msg.sender] += totalRewards;\n\n            ISousChef(sousChef).mintFSushi(_pid, beneficiary, totalRewards);\n\n            emit ClaimRewards(msg.sender, beneficiary, totalRewards);\n        }\n    }\n\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal override returns (uint256 balanceOfFrom, uint256 balanceOfTo) {\n        userCheckpoint(from);\n        userCheckpoint(to);\n\n        return super._transfer(from, to, amount);\n    }\n}\n"
    },
    "contracts/interfaces/IFlashStrategy.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashStrategy {\n    event BurnedFToken(address indexed _address, uint256 _tokenAmount, uint256 _yieldReturned);\n\n    // This is how principal will be deposited into the contract\n    // The Flash protocol allows the strategy to specify how much\n    // should be registered. This allows the strategy to manipulate (eg take fee)\n    // on the principal if the strategy requires\n    function depositPrincipal(uint256 _tokenAmount) external returns (uint256);\n\n    // This is how principal will be returned from the contract\n    function withdrawPrincipal(uint256 _tokenAmount) external;\n\n    // Responsible for instant upfront yield. Takes fERC20 tokens specific to this\n    // strategy. The strategy is responsible for returning some amount of principal tokens\n    function burnFToken(\n        uint256 _tokenAmount,\n        uint256 _minimumReturned,\n        address _yieldTo\n    ) external returns (uint256);\n\n    // This should return the current total of all principal within the contract\n    function getPrincipalBalance() external view returns (uint256);\n\n    // This should return the current total of all yield generated to date (including bootstrapped tokens)\n    function getYieldBalance() external view returns (uint256);\n\n    // This should return the principal token address (eg DAI)\n    function getPrincipalAddress() external view returns (address);\n\n    // View function which quotes how many principal tokens would be returned if x\n    // fERC20 tokens are burned\n    function quoteMintFToken(uint256 _tokenAmount, uint256 duration) external view returns (uint256);\n\n    // View function which quotes how many principal tokens would be returned if x\n    // fERC20 tokens are burned\n    // IMPORTANT NOTE: This should utilise bootstrap tokens if they exist\n    // bootstrapped tokens are any principal tokens that exist within the smart contract\n    function quoteBurnFToken(uint256 _tokenAmount) external view returns (uint256);\n\n    // The function to set the fERC20 address within the strategy\n    function setFTokenAddress(address _fTokenAddress) external;\n\n    // This should return what the maximum stake duration is\n    function getMaxStakeDuration() external view returns (uint256);\n}\n"
    },
    "contracts/interfaces/IFSushiBill.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\ninterface IFSushiBill is IERC20Metadata {\n    error NoClaimableRewards();\n\n    event Deposit(address indexed account, uint256 amount, address indexed beneficiary);\n    event Withdraw(address indexed account, uint256 amount, address indexed beneficiary);\n    event Checkpoint();\n    event UserCheckpoint(address indexed account);\n    event ClaimRewards(address indexed account, address indexed beneficiary, uint256 amount);\n\n    function sousChef() external view returns (address);\n\n    function pid() external view returns (uint256);\n\n    function fToken() external view returns (address);\n\n    function points(uint256 week) external view returns (uint256);\n\n    function lastCheckpoint() external view returns (uint256 timestamp);\n\n    function userPoints(address account, uint256 week) external view returns (uint256);\n\n    function userLastCheckpoint(address account) external view returns (uint256 timestamp);\n\n    function claimedRewards(address account) external view returns (uint256);\n\n    function nextClaimableWeek(address account) external view returns (uint256);\n\n    function initialize(uint256 _pid, address _fToken) external;\n\n    function deposit(uint256 amount, address beneficiary) external;\n\n    function withdraw(uint256 amount, address beneficiary) external;\n\n    function claimRewards(address beneficiary) external;\n\n    function checkpoint() external;\n\n    function userCheckpoint(address account) external;\n}\n"
    },
    "contracts/interfaces/IFSushiKitchen.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IFSushiKitchen {\n    error InvalidPid();\n\n    event AddPool(uint256 indexed pid);\n    event UpdateWeight(uint256 indexed pid, uint256 weightPoints, uint256 totalWeightPoints);\n\n    function flashStrategyFactory() external view returns (address);\n\n    function totalWeightPointsLength() external view returns (uint256);\n\n    function weightPointsLength(uint256 pid) external view returns (uint256);\n\n    function totalWeightPoints() external view returns (uint256);\n\n    function weightPoints(uint256 pid) external view returns (uint256);\n\n    function totalWeightPointsAt(uint256 timestamp) external view returns (uint256);\n\n    function weightPointsAt(uint256 pid, uint256 timestamp) external view returns (uint256);\n\n    function relativeWeight(uint256 pid) external view returns (uint256);\n\n    function relativeWeightAt(uint256 pid, uint256 timestamp) external view returns (uint256);\n\n    function addPool(uint256 pid) external;\n\n    function updateWeight(uint256 pid, uint256 points) external;\n\n    function checkpoint(uint256 pid) external;\n}\n"
    },
    "contracts/FSushiBar.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"./interfaces/IFSushiBar.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/FSushiBarPriorityQueue.sol\";\nimport \"./libraries/DateUtils.sol\";\n\n/**\n * @notice FSushiBar is an extension of ERC4626 with the addition of vesting period for locks\n */\ncontract FSushiBar is IFSushiBar {\n    using FSushiBarPriorityQueue for FSushiBarPriorityQueue.Heap;\n    using SafeERC20 for IERC20;\n    using Math for uint256;\n    using DateUtils for uint256;\n\n    uint8 public constant decimals = 18;\n    string public constant name = \"Flash SushiBar\";\n    string public constant symbol = \"xfSUSHI\";\n    uint256 internal constant MINIMUM_WEEKS = 1;\n    uint256 internal constant MAXIMUM_WEEKS = 104; // almost 2 years\n\n    address public immutable override asset;\n    uint256 public immutable override startWeek;\n\n    mapping(address => uint256) public override balanceOf;\n    uint256 public override totalSupply;\n\n    mapping(address => FSushiBarPriorityQueue.Heap) internal _locks;\n\n    uint256 public override totalAssets;\n    /**\n     * @dev this is guaranteed to be correct up until the last week\n     * @return minimum number of staked total assets during the whole week\n     */\n    mapping(uint256 => uint256) public override totalAssetsDuring;\n    /**\n     * @notice totalAssetsDuring is guaranteed to be correct before this week\n     */\n    uint256 public override lastCheckpoint; // week\n\n    uint256 internal _totalPower;\n    uint256 internal _totalYield;\n\n    modifier validWeeks(uint256 _weeks) {\n        if (_weeks < MINIMUM_WEEKS || _weeks > MAXIMUM_WEEKS) revert InvalidDuration();\n        _;\n    }\n\n    constructor(address fSushi) {\n        asset = fSushi;\n\n        uint256 thisWeek = block.timestamp.toWeekNumber();\n        startWeek = thisWeek;\n        lastCheckpoint = thisWeek;\n    }\n\n    function previewDeposit(uint256 assets, uint256 _weeks)\n        public\n        view\n        override\n        validWeeks(_weeks)\n        returns (uint256 shares)\n    {\n        return _toShares(_toPower(assets, _weeks), _totalPower);\n    }\n\n    function previewWithdraw(address owner)\n        public\n        view\n        override\n        returns (\n            uint256 shares,\n            uint256 assets,\n            uint256 yield\n        )\n    {\n        (assets, , shares) = _locks[owner].enqueued(block.timestamp);\n        yield = _getYield(shares);\n    }\n\n    function _toShares(uint256 power, uint256 totalPower) internal view returns (uint256 shares) {\n        uint256 supply = totalSupply;\n        shares = (power == 0 || supply == 0) ? power : power.mulDiv(supply, totalPower, Math.Rounding.Down);\n    }\n\n    function _toPower(uint256 assets, uint256 _weeks) internal pure returns (uint256) {\n        return assets.mulDiv(_weeks, MAXIMUM_WEEKS, Math.Rounding.Up);\n    }\n\n    function _getYield(uint256 shares) internal view returns (uint256 yield) {\n        uint256 _totalSupply = totalSupply;\n        if (_totalSupply == 0) return 0;\n\n        return _totalYield.mulDiv(shares, _totalSupply, Math.Rounding.Down);\n    }\n\n    function depositSigned(\n        uint256 assets,\n        uint256 _weeks,\n        address beneficiary,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public override returns (uint256) {\n        IFSushi(asset).permit(msg.sender, address(this), assets, deadline, v, r, s);\n\n        return deposit(assets, _weeks, beneficiary);\n    }\n\n    function deposit(\n        uint256 assets,\n        uint256 _weeks,\n        address beneficiary\n    ) public override validWeeks(_weeks) returns (uint256) {\n        checkpoint();\n\n        uint256 max = (totalAssets > 0 || totalSupply == 0) ? type(uint256).max : 0;\n        if (assets > max) revert Bankrupt();\n\n        uint256 totalPower = _totalPower;\n        uint256 power = _toPower(assets, _weeks);\n        uint256 shares = _toShares(power, totalPower);\n\n        IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);\n        _mint(beneficiary, shares);\n\n        _locks[msg.sender].enqueue(block.timestamp + _weeks * (1 weeks), assets, power, shares);\n\n        totalAssets += assets;\n        totalAssetsDuring[block.timestamp.toWeekNumber()] += assets;\n        _totalPower = totalPower + power;\n\n        emit Deposit(msg.sender, beneficiary, shares, assets);\n\n        return shares;\n    }\n\n    function withdraw(address beneficiary)\n        public\n        override\n        returns (\n            uint256 shares,\n            uint256 assets,\n            uint256 yield\n        )\n    {\n        checkpoint();\n\n        uint256 power;\n        (assets, power, shares) = _locks[msg.sender].drain(block.timestamp);\n        if (shares == 0) revert WithdrawalDenied();\n\n        yield = _getYield(shares);\n        totalAssets -= (assets + yield);\n        totalAssetsDuring[block.timestamp.toWeekNumber()] -= (assets + yield);\n        _totalPower -= power;\n        _totalYield -= yield;\n\n        _burn(msg.sender, shares);\n        IERC20(asset).safeTransfer(beneficiary, assets + yield);\n\n        emit Withdraw(msg.sender, beneficiary, shares, assets, yield);\n    }\n\n    function checkpointedTotalAssets() external override returns (uint256) {\n        checkpoint();\n        return totalAssets;\n    }\n\n    function checkpointedTotalAssetsDuring(uint256 week) external override returns (uint256) {\n        checkpoint();\n        return totalAssetsDuring[week];\n    }\n\n    /**\n     * @dev if this function doesn't get called for 512 weeks (around 9.8 years) this contract breaks\n     */\n    function checkpoint() public override {\n        uint256 oldTotalAssets = totalAssets;\n        uint256 newTotalAssets = IERC20(asset).balanceOf(address(this));\n        if (newTotalAssets > oldTotalAssets) {\n            totalAssets = newTotalAssets;\n            totalAssetsDuring[block.timestamp.toWeekNumber()] = newTotalAssets;\n            _totalPower += newTotalAssets - oldTotalAssets;\n            _totalYield += newTotalAssets - oldTotalAssets;\n        }\n\n        uint256 from = lastCheckpoint;\n        uint256 until = block.timestamp.toWeekNumber();\n        if (until <= from) return;\n\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            if (until <= week) break;\n\n            totalAssetsDuring[week + 1] = totalAssetsDuring[week];\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        lastCheckpoint = until;\n    }\n\n    function _mint(address account, uint256 amount) internal {\n        if (account == address(0)) revert InvalidAccount();\n\n        totalSupply += amount;\n        unchecked {\n            balanceOf[account] += amount;\n        }\n\n        emit Transfer(address(0), account, amount);\n    }\n\n    function _burn(address account, uint256 amount) internal {\n        if (account == address(0)) revert InvalidAccount();\n\n        uint256 balance = balanceOf[account];\n        if (balance < amount) revert NotEnoughBalance();\n        unchecked {\n            balanceOf[account] = balance - amount;\n            totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n    }\n}\n"
    },
    "contracts/interfaces/IFSushiBar.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\nimport \"./IFSushiRestaurant.sol\";\n\ninterface IFSushiBar is IFSushiRestaurant {\n    error Bankrupt();\n    error InvalidDuration();\n    error InvalidAccount();\n    error NotEnoughBalance();\n    error WithdrawalDenied();\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Deposit(address indexed sender, address indexed beneficiary, uint256 shares, uint256 assets);\n    event Withdraw(address indexed owner, address indexed beneficiary, uint256 shares, uint256 assets, uint256 yield);\n\n    function asset() external view returns (address);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address account) external view returns (uint256);\n\n    function previewDeposit(uint256 assets, uint256 _weeks) external view returns (uint256 shares);\n\n    function previewWithdraw(address owner)\n        external\n        view\n        returns (\n            uint256 shares,\n            uint256 assets,\n            uint256 yield\n        );\n\n    function depositSigned(\n        uint256 assets,\n        uint256 _weeks,\n        address receiver,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256);\n\n    function deposit(\n        uint256 assets,\n        uint256 _weeks,\n        address receiver\n    ) external returns (uint256);\n\n    function withdraw(address beneficiary)\n        external\n        returns (\n            uint256 shares,\n            uint256 assets,\n            uint256 yield\n        );\n}\n"
    },
    "contracts/libraries/FSushiBarPriorityQueue.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\n// modified https://github.com/MihanixA/SummingPriorityQueue/blob/master/contracts/SummingPriorityQueue.sol\nlibrary FSushiBarPriorityQueue {\n    error QueueEmpty();\n\n    struct Snapshot {\n        uint256 assets;\n        uint256 power;\n        uint256 shares;\n    }\n\n    struct Heap {\n        uint256[] timestamps;\n        mapping(uint256 => Snapshot) snapshots;\n    }\n\n    modifier notEmpty(Heap storage self) {\n        if (self.timestamps.length == 1) revert QueueEmpty();\n        _;\n    }\n\n    function top(Heap storage self) internal view notEmpty(self) returns (uint256) {\n        return self.timestamps[1];\n    }\n\n    /**\n     * @dev average time complexity: O(log n), worst-case time complexity: O(n)\n     */\n    function enqueued(Heap storage self, uint256 timestamp)\n        internal\n        view\n        returns (\n            uint256 assets,\n            uint256 power,\n            uint256 shares\n        )\n    {\n        return _dfs(self, timestamp, 1);\n    }\n\n    function _dfs(\n        Heap storage self,\n        uint256 timestamp,\n        uint256 i\n    )\n        private\n        view\n        returns (\n            uint256 assets,\n            uint256 power,\n            uint256 shares\n        )\n    {\n        if (i >= self.timestamps.length) return (0, 0, 0);\n        if (self.timestamps[i] > timestamp) return (0, 0, 0);\n\n        Snapshot memory snapshot = self.snapshots[self.timestamps[i]];\n        assets = snapshot.assets;\n        power = snapshot.power;\n        shares = snapshot.shares;\n\n        (uint256 assetsLeft, uint256 powerLeft, uint256 sharesLeft) = _dfs(self, timestamp, i * 2);\n        (uint256 assetsRight, uint256 powerRight, uint256 sharesRight) = _dfs(self, timestamp, i * 2 + 1);\n        return (assets + assetsLeft + assetsRight, power + powerLeft + powerRight, shares + sharesLeft + sharesRight);\n    }\n\n    function enqueue(\n        Heap storage self,\n        uint256 timestamp,\n        uint256 assets,\n        uint256 power,\n        uint256 shares\n    ) internal {\n        if (self.timestamps.length == 0) self.timestamps.push(0); // initialize\n\n        self.timestamps.push(timestamp);\n        uint256 i = self.timestamps.length - 1;\n\n        while (i > 1 && self.timestamps[i / 2] > self.timestamps[i]) {\n            (self.timestamps[i / 2], self.timestamps[i]) = (timestamp, self.timestamps[i / 2]);\n            i /= 2;\n        }\n\n        self.snapshots[timestamp] = Snapshot(assets, power, shares);\n    }\n\n    function dequeue(Heap storage self)\n        internal\n        notEmpty(self)\n        returns (\n            uint256 timestamp,\n            uint256 assets,\n            uint256 power,\n            uint256 shares\n        )\n    {\n        if (self.timestamps.length == 1) revert QueueEmpty();\n\n        timestamp = top(self);\n        self.timestamps[1] = self.timestamps[self.timestamps.length - 1];\n        self.timestamps.pop();\n\n        uint256 i = 1;\n\n        while (i * 2 < self.timestamps.length) {\n            uint256 j = i * 2;\n\n            if (j + 1 < self.timestamps.length)\n                if (self.timestamps[j] > self.timestamps[j + 1]) j++;\n\n            if (self.timestamps[i] < self.timestamps[j]) break;\n\n            (self.timestamps[i], self.timestamps[j]) = (self.timestamps[j], self.timestamps[i]);\n            i = j;\n        }\n\n        Snapshot memory snapshot = self.snapshots[timestamp];\n        delete self.snapshots[timestamp];\n\n        return (timestamp, snapshot.assets, snapshot.power, snapshot.shares);\n    }\n\n    function drain(Heap storage self, uint256 timestamp)\n        internal\n        returns (\n            uint256 assetsDequeued,\n            uint256 powerDequeued,\n            uint256 sharesDequeued\n        )\n    {\n        while (self.timestamps.length > 1 && top(self) < timestamp) {\n            (, uint256 assets, uint256 power, uint256 shares) = dequeue(self);\n            assetsDequeued += assets;\n            powerDequeued += power;\n            sharesDequeued += shares;\n        }\n    }\n}\n"
    },
    "contracts/FSushiAirdropsVotingEscrow.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"./interfaces/IVotingEscrow.sol\";\nimport \"./interfaces/IFSushi.sol\";\nimport \"./libraries/DateUtils.sol\";\n\ncontract FSushiAirdropsVotingEscrow {\n    using DateUtils for uint256;\n\n    uint256 private constant INITIAL_SUPPLY_PER_WEEK = 5000e18;\n\n    address public immutable votingEscrow;\n    address public immutable fSushi;\n    uint256 public immutable startWeek;\n    uint256 public immutable votingEscrowInterval;\n\n    uint256 public lastCheckpoint;\n    mapping(address => uint256) public lastCheckpointOf;\n    mapping(uint256 => uint256) public votingEscrowTotalSupply;\n\n    error Expired();\n    error Claimed();\n\n    event Claim(\n        address indexed account,\n        uint256 amount,\n        address indexed beneficiary,\n        uint256 fromWeek,\n        uint256 untilWeek\n    );\n\n    constructor(address _votingEscrow, address _fSushi) {\n        votingEscrow = _votingEscrow;\n        fSushi = _fSushi;\n        startWeek = block.timestamp.toWeekNumber();\n        votingEscrowInterval = IVotingEscrow(_votingEscrow).interval();\n    }\n\n    function claim(address beneficiary) external returns (uint256 amount) {\n        IVotingEscrow(votingEscrow).checkpoint();\n\n        uint256 from = lastCheckpointOf[msg.sender];\n        if (from == 0) {\n            from = startWeek;\n        }\n        uint256 until = block.timestamp.toWeekNumber() + 1;\n\n        for (uint256 i; i < 512; ) {\n            uint256 week = from + i;\n            if (week >= until) break;\n\n            uint256 weekStart = week.toTimestamp();\n            uint256 balance = _votingEscrowBalanceOf(msg.sender, weekStart);\n            uint256 totalSupply = _votingEscrowTotalSupply(weekStart);\n\n            amount += ((INITIAL_SUPPLY_PER_WEEK >> (week - startWeek)) * balance) / totalSupply;\n\n            unchecked {\n                ++i;\n            }\n        }\n\n        lastCheckpointOf[msg.sender] = until;\n\n        if (amount > 0) {\n            IFSushi(fSushi).mint(beneficiary, amount);\n\n            emit Claim(msg.sender, amount, beneficiary, from, until);\n        }\n    }\n\n    function _votingEscrowBalanceOf(address account, uint256 timestamp) internal view returns (uint256) {\n        uint256 epoch = IVotingEscrow(votingEscrow).userPointEpoch(account);\n        if (epoch == 0) return 0;\n        else {\n            (int128 bias, int128 slope, uint256 ts, ) = IVotingEscrow(votingEscrow).userPointHistory(account, epoch);\n            unchecked {\n                bias -= slope * int128(int256(timestamp - ts));\n            }\n            if (bias < 0) bias = 0;\n            return uint256(uint128(bias));\n        }\n    }\n\n    function _votingEscrowTotalSupply(uint256 timestamp) internal returns (uint256) {\n        uint256 week = timestamp.toWeekNumber();\n        if (week < lastCheckpoint) return votingEscrowTotalSupply[week];\n\n        lastCheckpoint = timestamp.toWeekNumber() + 1;\n\n        uint256 epoch = IVotingEscrow(votingEscrow).epoch();\n        (int128 bias, int128 slope, uint256 ts, ) = IVotingEscrow(votingEscrow).pointHistory(epoch);\n        uint256 t_i = (ts / votingEscrowInterval) * votingEscrowInterval;\n        for (uint256 i; i < 255; i++) {\n            t_i += votingEscrowInterval;\n            int128 d_slope;\n            if (t_i > timestamp) t_i = timestamp;\n            else d_slope = IVotingEscrow(votingEscrow).slopeChanges(t_i);\n            unchecked {\n                bias -= slope * int128(int256(t_i - ts));\n            }\n            if (t_i == timestamp) break;\n            slope += d_slope;\n            ts = t_i;\n        }\n\n        if (bias < 0) bias = 0;\n        uint256 totalSupply = uint256(uint128(bias));\n        votingEscrowTotalSupply[week] = totalSupply;\n        return totalSupply;\n    }\n}\n"
    },
    "contracts/interfaces/IVotingEscrow.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IVotingEscrow {\n    error Forbidden();\n    error Expired();\n    error Existent();\n    error NonExistent();\n    error TooLate();\n    error TooEarly();\n    error InvalidAmount();\n    error InvalidPath();\n    error OutOfRange();\n    error DiscountTooHigh();\n    error Discounted();\n    error NotExpired();\n    error NotPastBlock();\n\n    event SetDelegate(address indexed account, bool isDelegate);\n    event Deposit(\n        address indexed provider,\n        uint256 value,\n        uint256 discount,\n        uint256 indexed unlockTime,\n        int128 indexed _type,\n        uint256 ts\n    );\n    event Withdraw(address indexed provider, uint256 value, uint256 discount, uint256 ts);\n    event Supply(uint256 prevSupply, uint256 supply);\n\n    function interval() external view returns (uint256);\n\n    function maxDuration() external view returns (uint256);\n\n    function token() external view returns (address);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function isDelegate(address account) external view returns (bool);\n\n    function supply() external view returns (uint256);\n\n    function delegateAt(address account, uint256 index) external view returns (address);\n\n    function locked(address account)\n        external\n        view\n        returns (\n            int128 amount,\n            int128 discount,\n            uint256 start,\n            uint256 end\n        );\n\n    function epoch() external view returns (uint256);\n\n    function pointHistory(uint256 epoch)\n        external\n        view\n        returns (\n            int128 bias,\n            int128 slope,\n            uint256 ts,\n            uint256 blk\n        );\n\n    function userPointHistory(address account, uint256 epoch)\n        external\n        view\n        returns (\n            int128 bias,\n            int128 slope,\n            uint256 ts,\n            uint256 blk\n        );\n\n    function userPointEpoch(address account) external view returns (uint256);\n\n    function slopeChanges(uint256 epoch) external view returns (int128);\n\n    function delegateLength(address addr) external view returns (uint256);\n\n    function getLastUserSlope(address addr) external view returns (int128);\n\n    function getCheckpointTime(address _addr, uint256 _idx) external view returns (uint256);\n\n    function unlockTime(address _addr) external view returns (uint256);\n\n    function setDelegate(address account, bool _isDelegate) external;\n\n    function checkpoint() external;\n\n    function depositFor(address _addr, uint256 _value) external;\n\n    function createLockFor(\n        address _addr,\n        uint256 _value,\n        uint256 _discount,\n        uint256 _duration\n    ) external;\n\n    function createLock(uint256 _value, uint256 _duration) external;\n\n    function increaseAmountFor(\n        address _addr,\n        uint256 _value,\n        uint256 _discount\n    ) external;\n\n    function increaseAmount(uint256 _value) external;\n\n    function increaseUnlockTime(uint256 _duration) external;\n\n    function withdraw() external;\n\n    function balanceOf(address addr) external view returns (uint256);\n\n    function balanceOf(address addr, uint256 _t) external view returns (uint256);\n\n    function balanceOfAt(address addr, uint256 _block) external view returns (uint256);\n\n    function totalSupply() external view returns (uint256);\n\n    function totalSupply(uint256 t) external view returns (uint256);\n\n    function totalSupplyAt(uint256 _block) external view returns (uint256);\n}\n"
    },
    "contracts/FSushiAirdrops.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"./interfaces/IFSushi.sol\";\n\ncontract FSushiAirdrops is Ownable {\n    bytes32 private constant CLAIM_TYPEHASH =\n        keccak256(\"Claim(uint256 chainId,address contract,uint256 id,address account,uint256 amount)\");\n\n    address public immutable fSushi;\n    address public signer;\n    string[] public airdrops;\n    mapping(uint256 => mapping(address => bool)) public hasClaimed;\n\n    error NotEOA();\n    error InvalidName();\n    error InvalidId();\n    error InvalidSignature();\n    error Expired();\n    error Claimed();\n\n    event UpdateSigner(address indexed signer);\n    event AddAirdrop(uint256 indexed id, string name);\n    event Claim(uint256 indexed id, string name, address indexed account, uint256 amount, address indexed beneficiary);\n\n    constructor(address _fSushi) {\n        fSushi = _fSushi;\n    }\n\n    function updateSigner(address _signer) external onlyOwner {\n        if (_signer.code.length > 0) revert NotEOA();\n\n        signer = _signer;\n\n        emit UpdateSigner(_signer);\n    }\n\n    function addAirdrop(string memory name) external onlyOwner {\n        if (bytes(name).length == 0) revert InvalidName();\n\n        uint256 id = airdrops.length;\n        airdrops.push(name);\n\n        emit AddAirdrop(id, name);\n    }\n\n    function claim(\n        uint256 id,\n        uint256 amount,\n        address beneficiary,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        if (block.timestamp > deadline) revert Expired();\n\n        string memory name = airdrops[id];\n        if (bytes(name).length == 0) revert InvalidId();\n\n        if (hasClaimed[id][msg.sender]) revert Claimed();\n        hasClaimed[id][msg.sender] = true;\n\n        bytes32 hash = keccak256(\n            abi.encodePacked(block.chainid, address(this), id, msg.sender, amount, beneficiary, deadline)\n        );\n        address _signer = ECDSA.recover(ECDSA.toEthSignedMessageHash(hash), v, r, s);\n        if (_signer != signer) revert InvalidSignature();\n\n        IFSushi(fSushi).mint(beneficiary, amount);\n\n        emit Claim(id, name, msg.sender, amount, beneficiary);\n    }\n}\n"
    },
    "contracts/FSushiKitchen.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/IFSushiKitchen.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./libraries/Snapshots.sol\";\n\ncontract FSushiKitchen is Ownable, IFSushiKitchen {\n    using Snapshots for Snapshots.Snapshot[];\n\n    uint256 internal constant BASE = 1e18;\n\n    address public immutable override flashStrategyFactory;\n\n    Snapshots.Snapshot[] internal _totalWeightPoints;\n    mapping(uint256 => Snapshots.Snapshot[]) internal _weightPoints; // pid -> snapshots\n\n    constructor(address _flashStrategyFactory) {\n        flashStrategyFactory = _flashStrategyFactory;\n    }\n\n    function totalWeightPointsLength() external view override returns (uint256) {\n        return _totalWeightPoints.size();\n    }\n\n    function weightPointsLength(uint256 pid) external view override returns (uint256) {\n        return _weightPoints[pid].size();\n    }\n\n    function totalWeightPoints() external view override returns (uint256) {\n        return _totalWeightPoints.lastValue();\n    }\n\n    function weightPoints(uint256 pid) external view override returns (uint256) {\n        return _weightPoints[pid].lastValue();\n    }\n\n    function totalWeightPointsAt(uint256 timestamp) external view override returns (uint256) {\n        return _totalWeightPoints.valueAt(timestamp);\n    }\n\n    function weightPointsAt(uint256 pid, uint256 timestamp) external view override returns (uint256) {\n        return _weightPoints[pid].valueAt(timestamp);\n    }\n\n    function relativeWeight(uint256 pid) external view override returns (uint256) {\n        uint256 totalPoints = _totalWeightPoints.lastValue();\n        if (totalPoints == 0) return 0;\n\n        uint256 points = _weightPoints[pid].lastValue();\n        return (points * BASE) / totalPoints;\n    }\n\n    function relativeWeightAt(uint256 pid, uint256 timestamp) external view override returns (uint256) {\n        uint256 totalPoints = _totalWeightPoints.valueAt(timestamp);\n        if (totalPoints == 0) return 0;\n\n        uint256 points = _weightPoints[pid].valueAt(timestamp);\n        return (points * BASE) / totalPoints;\n    }\n\n    function addPool(uint256 pid) external override {\n        address strategy = IFlashStrategySushiSwapFactory(flashStrategyFactory).getFlashStrategySushiSwap(pid);\n        if (strategy == address(0)) revert InvalidPid();\n\n        emit AddPool(pid);\n\n        _updateWeight(pid, 100e18);\n    }\n\n    function updateWeight(uint256 pid, uint256 points) external override onlyOwner {\n        if (_weightPoints[pid].size() == 0) revert InvalidPid();\n\n        _updateWeight(pid, points);\n    }\n\n    function _updateWeight(uint256 pid, uint256 points) internal {\n        uint256 prev = _weightPoints[pid].lastValue();\n        _weightPoints[pid].append(points);\n        uint256 totalPoints = _totalWeightPoints.lastValue() + points - prev;\n        _totalWeightPoints.append(totalPoints);\n\n        emit UpdateWeight(pid, points, totalPoints);\n    }\n\n    function checkpoint(uint256) external override {\n        // Empty: for future compatibility\n    }\n}\n"
    },
    "contracts/libraries/Snapshots.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nlibrary Snapshots {\n    error InvalidTimestamp();\n\n    struct Snapshot {\n        uint256 value;\n        uint256 timestamp;\n    }\n\n    function size(Snapshot[] storage snapshots) internal view returns (uint256) {\n        return snapshots.length;\n    }\n\n    function lastValue(Snapshot[] storage snapshots) internal view returns (uint256) {\n        uint256 _length = snapshots.length;\n        return _length > 0 ? snapshots[_length - 1].value : 0;\n    }\n\n    function valueAt(Snapshot[] storage snapshots, uint256 timestamp) internal view returns (uint256) {\n        uint256 _now = block.timestamp;\n        if (_now < timestamp) revert InvalidTimestamp();\n\n        uint256 _length = snapshots.length;\n        if (_length == 0) {\n            return 0;\n        }\n\n        // First check most recent balance\n        if (snapshots[_length - 1].timestamp <= timestamp) {\n            return snapshots[_length - 1].value;\n        }\n\n        // Next check implicit zero balance\n        if (timestamp < snapshots[0].timestamp) {\n            return 0;\n        }\n\n        unchecked {\n            uint256 lower = 0;\n            uint256 upper = _length - 1;\n            while (upper > lower) {\n                uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n                Snapshot memory snapshot = snapshots[center];\n                if (snapshot.timestamp == _now) {\n                    return snapshot.value;\n                } else if (snapshot.timestamp < _now) {\n                    lower = center;\n                } else {\n                    upper = center - 1;\n                }\n            }\n            return snapshots[lower].value;\n        }\n    }\n\n    function append(Snapshot[] storage snapshots, uint256 value) internal {\n        snapshots.push(Snapshot(value, block.timestamp));\n    }\n}\n"
    },
    "contracts/FlashStrategySushiSwapFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/Clones.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./interfaces/IFarmingLPTokenFactory.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./FlashStrategySushiSwap.sol\";\n\ninterface IFlashProtocol {\n    function registerStrategy(\n        address _strategyAddress,\n        address _principalTokenAddress,\n        string calldata _fTokenName,\n        string calldata _fTokenSymbol\n    ) external;\n}\n\ncontract FlashStrategySushiSwapFactory is Ownable, IFlashStrategySushiSwapFactory {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n\n    /**\n     * @notice address of FlashProtocol\n     */\n    address public immutable override flashProtocol;\n    /**\n     * @notice address of FarmingLPTokenFactory\n     */\n    address public immutable override flpTokenFactory;\n\n    address internal immutable _implementation;\n\n    /**\n     * @notice fee recipient\n     */\n    address public override feeRecipient;\n\n    mapping(uint256 => address) public override getFlashStrategySushiSwap;\n\n    constructor(\n        address _flashProtocol,\n        address _flpTokenFactory,\n        address _feeRecipient\n    ) {\n        flashProtocol = _flashProtocol;\n        flpTokenFactory = _flpTokenFactory;\n        updateFeeRecipient(_feeRecipient);\n\n        FlashStrategySushiSwap strategy = new FlashStrategySushiSwap();\n        strategy.initialize(address(0), address(0));\n        _implementation = address(strategy);\n    }\n\n    function predictFlashStrategySushiSwapAddress(uint256 pid) external view override returns (address token) {\n        token = Clones.predictDeterministicAddress(_implementation, bytes32(pid));\n    }\n\n    function updateFeeRecipient(address _feeRecipient) public override onlyOwner {\n        if (_feeRecipient == address(0)) revert InvalidFeeRecipient();\n\n        feeRecipient = _feeRecipient;\n\n        emit UpdateFeeRecipient(_feeRecipient);\n    }\n\n    function createFlashStrategySushiSwap(uint256 pid) external override returns (address strategy) {\n        if (getFlashStrategySushiSwap[pid] != address(0)) revert FlashStrategySushiSwapCreated();\n\n        address flpToken = IFarmingLPTokenFactory(flpTokenFactory).getFarmingLPToken(pid);\n        if (flpToken == address(0)) flpToken = IFarmingLPTokenFactory(flpTokenFactory).createFarmingLPToken(pid);\n\n        strategy = Clones.cloneDeterministic(_implementation, bytes32(pid));\n        FlashStrategySushiSwap(strategy).initialize(flashProtocol, flpToken);\n\n        getFlashStrategySushiSwap[pid] = strategy;\n\n        string memory name = string.concat(\"fToken for \", IERC20Metadata(flpToken).name());\n        string memory symbol = string.concat(\n            \"f\",\n            IERC20Metadata(flpToken).symbol(),\n            \"-\",\n            _toHexString(uint160(flpToken) >> 144, 4)\n        );\n        IFlashProtocol(flashProtocol).registerStrategy(strategy, flpToken, name, symbol);\n\n        emit CreateFlashStrategySushiSwap(pid, strategy);\n    }\n\n    function _toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(length);\n        for (uint256 i = 0; i < length; ) {\n            buffer[length - i - 1] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n            unchecked {\n                ++i;\n            }\n        }\n        return string(buffer);\n    }\n}\n"
    },
    "contracts/FlashStrategySushiSwap.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"./interfaces/IFlashStrategySushiSwap.sol\";\nimport \"./interfaces/IFlashStrategySushiSwapFactory.sol\";\nimport \"./interfaces/IFlashFToken.sol\";\nimport \"./interfaces/IFarmingLPToken.sol\";\nimport \"./interfaces/IERC20Receiver.sol\";\n\ncontract FlashStrategySushiSwap is Initializable, ReentrancyGuard, IFlashStrategySushiSwap {\n    using SafeERC20 for IERC20;\n\n    address public override factory;\n\n    /**\n     * @notice address of FlashProtocol\n     */\n    address public override flashProtocol;\n\n    /**\n     * @notice address of SUSHI token\n     */\n    address public override sushi;\n    /**\n     * @notice address of FarmingLPToken\n     */\n    address public override flpToken;\n\n    uint256 internal _balancePrincipal;\n\n    /**\n     * @notice address of fERC20 for this strategy\n     */\n    address public override fToken;\n\n    function initialize(address _flashProtocol, address _flpToken) external override initializer {\n        if (_flashProtocol == address(0)) return;\n\n        factory = msg.sender;\n        flashProtocol = _flashProtocol;\n        sushi = IFarmingLPToken(_flpToken).sushi();\n        flpToken = _flpToken;\n    }\n\n    modifier onlyAuthorised() {\n        if (msg.sender != flashProtocol && msg.sender != address(this)) revert Forbidden();\n        _;\n    }\n\n    /**\n     * @return amount of principal tokens that are currently deposited\n     */\n    function getPrincipalBalance() external view override returns (uint256) {\n        return _balancePrincipal;\n    }\n\n    /**\n     * @return amount of yield tokens that can be rewarded in SUSHI\n     */\n    function getYieldBalance() public view override returns (uint256) {\n        return IFarmingLPToken(flpToken).withdrawableYieldOf(address(this));\n    }\n\n    /**\n     * @return address of LP Token\n     */\n    function getPrincipalAddress() external view override returns (address) {\n        return flpToken;\n    }\n\n    /**\n     * @dev called by flashProtocol\n     * @return amountFToken how many fTokens should be minted for a given _amount and _duration (in seconds)\n     */\n    function quoteMintFToken(uint256 _amount, uint256 _duration) external pure override returns (uint256 amountFToken) {\n        // 1 fToken per 1 year\n        uint256 amountToMint = (_amount * _duration) / 365 days;\n\n        if (amountToMint == 0) revert AmountTooLow();\n\n        return amountToMint;\n    }\n\n    /**\n     * @return how many aLP rewards should be returned if _amount fERC20 tokens are burned\n     */\n    function quoteBurnFToken(uint256 _amount) public view override returns (uint256) {\n        uint256 totalSupply = IERC20(fToken).totalSupply();\n        if (totalSupply == 0) revert InsufficientTotalSupply();\n\n        if (_amount > totalSupply) {\n            _amount = totalSupply;\n        }\n\n        return (getYieldBalance() * _amount) / totalSupply;\n    }\n\n    function getMaxStakeDuration() public pure override returns (uint256) {\n        return 104 weeks; // almost 2 years\n    }\n\n    /**\n     * @dev called by flashProtocol\n     */\n    function setFTokenAddress(address _fTokenAddress) external override {\n        if (msg.sender != flashProtocol) revert Forbidden();\n        fToken = _fTokenAddress;\n    }\n\n    /**\n     * @notice This function will be called whenever a user stakes via the Flash Protocol.\n     * @dev The Strategy owner can choose to implement a fee but the resulting \"locked\" principal the user should expect\n     *  after the stake has ended must be returned.\n     */\n    function depositPrincipal(uint256 _amount) external override onlyAuthorised returns (uint256) {\n        uint256 fee = _amount / 400; // charge 0.25%\n        _transferFee(flpToken, fee);\n\n        uint256 amount = _amount - fee;\n        _balancePrincipal += amount;\n\n        return amount;\n    }\n\n    /**\n     * @notice This function should withdraw principal from the underlying strategy.\n     */\n    function withdrawPrincipal(uint256 _amount) external override onlyAuthorised {\n        address _flpToken = flpToken;\n        IFarmingLPToken(_flpToken).checkpoint();\n\n        IERC20(_flpToken).safeTransfer(msg.sender, _amount);\n        _balancePrincipal -= _amount;\n    }\n\n    /**\n     * @notice This is the function the user will be calling when performing a FlashBurn.\n     * @dev It is responsible for burning the fToken supplied by the user and returning yield to the user.\n     */\n    function burnFToken(\n        uint256 _amount,\n        uint256 _minimumReturned,\n        address _yieldTo\n    ) external override nonReentrant returns (uint256) {\n        uint256 yield = quoteBurnFToken(_amount);\n        if (yield == 0 || yield < _minimumReturned) revert InsufficientYield();\n\n        IFlashFToken(fToken).burnFrom(msg.sender, _amount);\n\n        address _flpToken = flpToken;\n        IFarmingLPToken(_flpToken).withdraw(yield, address(this));\n\n        address lpToken = IFarmingLPToken(_flpToken).lpToken();\n        uint256 balanceLPToken = IERC20(lpToken).balanceOf(address(this));\n        _transfer(lpToken, _yieldTo, balanceLPToken);\n\n        address _sushi = sushi;\n        uint256 balanceSushi = IERC20(_sushi).balanceOf(address(this));\n        _transfer(_sushi, _yieldTo, balanceSushi);\n\n        emit BurnedFToken(msg.sender, _amount, yield);\n\n        return yield;\n    }\n\n    function _transfer(\n        address token,\n        address to,\n        uint256 amount\n    ) internal {\n        uint256 fee = amount / 100; // charge 1%\n        IERC20(token).safeTransfer(to, amount - fee);\n        _transferFee(token, fee);\n    }\n\n    function _transferFee(address token, uint256 amount) internal {\n        if (amount > 0) {\n            address feeRecipient = IFlashStrategySushiSwapFactory(factory).feeRecipient();\n            IERC20(token).safeTransfer(feeRecipient, amount);\n            if (feeRecipient.code.length > 0) {\n                try IERC20Receiver(feeRecipient).onReceiveERC20(token, address(this), amount) {} catch {}\n            }\n        }\n    }\n}\n"
    },
    "contracts/interfaces/IFlashFToken.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashFToken {\n    function mint(address account, uint256 amount) external;\n\n    function burnFrom(address from, uint256 amount) external;\n\n    function decimals() external returns (uint8);\n}\n"
    },
    "contracts/interfaces/IERC20Receiver.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\n\ninterface IERC20Receiver {\n    function onReceiveERC20(\n        address token,\n        address from,\n        uint256 amount\n    ) external;\n}\n"
    },
    "contracts/mocks/VotingEscrowMock.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"./libraries/Integers.sol\";\n\n/**\n * @title Voting Escrow\n * @author LevX (team@levx.io)\n * @notice Votes have a weight depending on time, so that users are\n *         committed to the future of (whatever they are voting for)\n * @dev Vote weight decays linearly over time. Lock time cannot be\n *      more than `MAXTIME`.\n * @dev Ported from vyper (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)\n */\n\n// Voting escrow to have time-weighted votes\n// Votes have a weight depending on time, so that users are committed\n// to the future of (whatever they are voting for).\n// The weight in this implementation is linear, and lock cannot be more than maxtime:\n// w ^\n// 1 +        /\n//   |      /\n//   |    /\n//   |  /\n//   |/\n// 0 +--------+------> time\n//       maxtime\n\ncontract VotingEscrowMock is Ownable, ReentrancyGuard {\n    using SafeERC20 for IERC20;\n    using Integers for int128;\n    using Integers for uint256;\n\n    event Deposit(\n        address indexed provider,\n        uint256 value,\n        uint256 discount,\n        uint256 indexed unlockTime,\n        int128 indexed _type,\n        uint256 ts\n    );\n    event Withdraw(address indexed provider, uint256 value, uint256 discount, uint256 ts);\n    event Supply(uint256 prevSupply, uint256 supply);\n\n    struct Point {\n        int128 bias;\n        int128 slope; // - dweight / dt\n        uint256 ts;\n        uint256 blk; // block\n    }\n\n    struct LockedBalance {\n        int128 amount;\n        int128 discount;\n        uint256 start;\n        uint256 end;\n    }\n\n    int128 public constant DEPOSIT_FOR_TYPE = 0;\n    int128 public constant CRETE_LOCK_TYPE = 1;\n    int128 public constant INCREASE_LOCK_AMOUNT = 2;\n    int128 public constant INCREASE_UNLOCK_TIME = 3;\n    uint256 internal constant MULTIPLIER = 1e18;\n\n    uint256 public immutable interval;\n    uint256 public immutable maxDuration;\n    address public immutable token;\n    string public name;\n    string public symbol;\n    uint8 public immutable decimals;\n\n    address public migrator;\n\n    uint256 public supply;\n    mapping(address => bool) public migrated;\n    mapping(address => address[]) public delegateAt;\n    mapping(address => LockedBalance) public locked;\n    uint256 public epoch;\n\n    mapping(uint256 => Point) public pointHistory; // epoch -> unsigned point\n    mapping(address => mapping(uint256 => Point)) public userPointHistory; // user -> Point[user_epoch]\n    mapping(address => uint256) public userPointEpoch;\n    mapping(uint256 => int128) public slopeChanges; // time -> signed slope change\n\n    constructor(\n        address _token,\n        string memory _name,\n        string memory _symbol,\n        uint256 _interval,\n        uint256 _maxDuration\n    ) {\n        token = _token;\n        name = _name;\n        symbol = _symbol;\n        decimals = IERC20Metadata(_token).decimals();\n\n        interval = _interval;\n        maxDuration = (_maxDuration / _interval) * _interval; // rounded down to a multiple of interval\n\n        pointHistory[0].blk = block.number;\n        pointHistory[0].ts = block.timestamp;\n    }\n\n    function delegateLength(address addr) external view returns (uint256) {\n        return delegateAt[addr].length;\n    }\n\n    /**\n     * @notice Get the most recently recorded rate of voting power decrease for `addr`\n     * @param addr Address of the user wallet\n     * @return Value of the slope\n     */\n    function getLastUserSlope(address addr) external view returns (int128) {\n        uint256 uepoch = userPointEpoch[addr];\n        return userPointHistory[addr][uepoch].slope;\n    }\n\n    /**\n     * @notice Get the timestamp for checkpoint `_idx` for `_addr`\n     * @param _addr User wallet address\n     * @param _idx User epoch number\n     * @return Epoch time of the checkpoint\n     */\n    function getCheckpointTime(address _addr, uint256 _idx) external view returns (uint256) {\n        return userPointHistory[_addr][_idx].ts;\n    }\n\n    /**\n     * @notice Get timestamp when `_addr`'s lock finishes\n     * @param _addr User wallet\n     * @return Epoch time of the lock end\n     */\n    function unlockTime(address _addr) external view returns (uint256) {\n        return locked[_addr].end;\n    }\n\n    /**\n     * @notice Record global and per-user data to checkpoint\n     * @param addr User's wallet address. No user checkpoint if 0x0\n     * @param old_locked Pevious locked amount / end lock time for the user\n     * @param new_locked New locked amount / end lock time for the user\n     */\n    function _checkpoint(\n        address addr,\n        LockedBalance memory old_locked,\n        LockedBalance memory new_locked\n    ) internal {\n        Point memory u_old;\n        Point memory u_new;\n        int128 old_dslope;\n        int128 new_dslope;\n        uint256 _epoch = epoch;\n\n        if (addr != address(0)) {\n            // Calculate slopes and biases\n            // Kept at zero when they have to\n            if (old_locked.end > block.timestamp && old_locked.amount > 0) {\n                u_old.slope = old_locked.amount / maxDuration.toInt128();\n                u_old.bias = u_old.slope * (old_locked.end - block.timestamp).toInt128();\n            }\n            if (new_locked.end > block.timestamp && new_locked.amount > 0) {\n                u_new.slope = new_locked.amount / maxDuration.toInt128();\n                u_new.bias = u_new.slope * (new_locked.end - block.timestamp).toInt128();\n            }\n\n            // Read values of scheduled changes in the slope\n            // old_locked.end can be in the past and in the future\n            // new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros\n            old_dslope = slopeChanges[old_locked.end];\n            if (new_locked.end != 0) {\n                if (new_locked.end == old_locked.end) new_dslope = old_dslope;\n                else new_dslope = slopeChanges[new_locked.end];\n            }\n        }\n\n        Point memory last_point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number});\n        if (_epoch > 0) last_point = pointHistory[_epoch];\n        uint256 last_checkpoint = last_point.ts;\n        // initial_last_point is used for extrapolation to calculate block number\n        // (approximately, for *At methods) and save them\n        // as we cannot figure that out exactly from inside the contract\n        Point memory initial_last_point = Point(last_point.bias, last_point.slope, last_point.ts, last_point.blk);\n        uint256 block_slope; // dblock/dt\n        if (block.timestamp > last_point.ts)\n            block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.ts);\n        // If last point is already recorded in this block, slope=0\n        // But that's ok b/c we know the block in such case\n\n        {\n            // Go over weeks to fill history and calculate what the current point is\n            uint256 t_i = (last_checkpoint / interval) * interval;\n            for (uint256 i; i < 255; i++) {\n                // Hopefully it won't happen that this won't get used in 5 years!\n                // If it does, users will be able to withdraw but vote weight will be broken\n                t_i += interval;\n                int128 d_slope;\n                if (t_i > block.timestamp) t_i = block.timestamp;\n                else d_slope = slopeChanges[t_i];\n                last_point.bias -= last_point.slope * (t_i - last_checkpoint).toInt128();\n                last_point.slope += d_slope;\n                if (last_point.bias < 0)\n                    // This can happen\n                    last_point.bias = 0;\n                if (last_point.slope < 0)\n                    // This cannot happen - just in case\n                    last_point.slope = 0;\n                last_checkpoint = t_i;\n                last_point.ts = t_i;\n                last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER;\n                _epoch += 1;\n                if (t_i == block.timestamp) {\n                    last_point.blk = block.number;\n                    break;\n                } else pointHistory[_epoch] = last_point;\n            }\n        }\n\n        epoch = _epoch;\n        // Now point_history is filled until t=now\n\n        if (addr != address(0)) {\n            // If last point was in this block, the slope change has been applied already\n            // But in such case we have 0 slope(s)\n            last_point.slope += (u_new.slope - u_old.slope);\n            last_point.bias += (u_new.bias - u_old.bias);\n            if (last_point.slope < 0) last_point.slope = 0;\n            if (last_point.bias < 0) last_point.bias = 0;\n        }\n\n        // Record the changed point into history\n        pointHistory[_epoch] = last_point;\n\n        if (addr != address(0)) {\n            // Schedule the slope changes (slope is going down)\n            // We subtract new_user_slope from [new_locked.end]\n            // and add old_user_slope to [old_locked.end]\n            if (old_locked.end > block.timestamp) {\n                // old_dslope was <something> - u_old.slope, so we cancel that\n                old_dslope += u_old.slope;\n                if (new_locked.end == old_locked.end) old_dslope -= u_new.slope; // It was a new deposit, not extension\n                slopeChanges[old_locked.end] = old_dslope;\n            }\n\n            if (new_locked.end > block.timestamp) {\n                if (new_locked.end > old_locked.end) {\n                    new_dslope -= u_new.slope; // old slope disappeared at this point\n                    slopeChanges[new_locked.end] = new_dslope;\n                }\n                // else: we recorded it already in old_dslope\n            }\n\n            // Now handle user history\n            uint256 user_epoch = userPointEpoch[addr] + 1;\n\n            userPointEpoch[addr] = user_epoch;\n            u_new.ts = block.timestamp;\n            u_new.blk = block.number;\n            userPointHistory[addr][user_epoch] = u_new;\n        }\n    }\n\n    /**\n     * @notice Deposit and lock tokens for a user\n     * @param _addr User's wallet address\n     * @param _value Amount to deposit\n     * @param _discount Amount to get discounted out of _value\n     * @param unlock_time New time when to unlock the tokens, or 0 if unchanged\n     * @param locked_balance Previous locked amount / timestamp\n     */\n    function _depositFor(\n        address _addr,\n        uint256 _value,\n        uint256 _discount,\n        uint256 unlock_time,\n        LockedBalance memory locked_balance,\n        int128 _type\n    ) internal {\n        LockedBalance memory _locked = locked_balance;\n        uint256 supply_before = supply;\n\n        supply = supply_before + _value;\n        LockedBalance memory old_locked;\n        (old_locked.amount, old_locked.discount, old_locked.start, old_locked.end) = (\n            _locked.amount,\n            _locked.discount,\n            _locked.start,\n            _locked.end\n        );\n        // Adding to existing lock, or if a lock is expired - creating a new one\n        _locked.amount += (_value).toInt128();\n        if (_discount != 0) _locked.discount += _discount.toInt128();\n        if (unlock_time != 0) {\n            if (_locked.start == 0) _locked.start = block.timestamp;\n            _locked.end = unlock_time;\n        }\n        locked[_addr] = _locked;\n\n        // Possibilities:\n        // Both old_locked.end could be current or expired (>/< block.timestamp)\n        // value == 0 (extend lock) or value > 0 (add to lock or extend lock)\n        // _locked.end > block.timestamp (always)\n        _checkpoint(_addr, old_locked, _locked);\n\n        if (_value > _discount) {\n            IERC20(token).safeTransferFrom(_addr, address(this), _value - _discount);\n        }\n\n        emit Deposit(_addr, _value, _discount, _locked.end, _type, block.timestamp);\n        emit Supply(supply_before, supply_before + _value);\n    }\n\n    /**\n     * @notice Record global data to checkpoint\n     */\n    function checkpoint() external {\n        _checkpoint(address(0), LockedBalance(0, 0, 0, 0), LockedBalance(0, 0, 0, 0));\n    }\n\n    /**\n     * @notice Deposit `_value` tokens for `_addr` and add to the lock\n     * @dev Anyone (even a smart contract) can deposit for someone else, but\n     *      cannot extend their locktime and deposit for a brand new user\n     * @param _addr User's wallet address\n     * @param _value Amount to add to user's lock\n     */\n    function depositFor(address _addr, uint256 _value) external nonReentrant {\n        LockedBalance memory _locked = locked[_addr];\n\n        require(_value > 0, \"VE: INVALID_VALUE\");\n        require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n        require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n        _depositFor(_addr, _value, 0, 0, _locked, DEPOSIT_FOR_TYPE);\n    }\n\n    /**\n     * @notice Deposit `_value` tokens with `_discount` for `_addr` and lock for `_duration`\n     * @param _addr User's wallet address\n     * @param _value Amount to add to user's lock\n     * @param _discount Amount to get discounted out of _value\n     * @param _duration Epoch time until tokens unlock from now\n     */\n    function createLockFor(\n        address _addr,\n        uint256 _value,\n        uint256 _discount,\n        uint256 _duration\n    ) external nonReentrant {\n        uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n        LockedBalance memory _locked = locked[_addr];\n\n        require(_value > 0, \"VE: INVALID_VALUE\");\n        require(_value >= _discount, \"VE: DISCOUNT_TOO_HIGH\");\n        require(_locked.amount == 0, \"VE: EXISTING_LOCK_FOUND\");\n        require(unlock_time > block.timestamp, \"VE: UNLOCK_TIME_TOO_EARLY\");\n        require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n        _depositFor(_addr, _value, _discount, unlock_time, _locked, CRETE_LOCK_TYPE);\n    }\n\n    /**\n     * @notice Deposit `_value` tokens for `msg.sender` and lock for `_duration`\n     * @param _value Amount to deposit\n     * @param _duration Epoch time until tokens unlock from now\n     */\n    function createLock(uint256 _value, uint256 _duration) external nonReentrant {\n        uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n        LockedBalance memory _locked = locked[msg.sender];\n\n        require(_value > 0, \"VE: INVALID_VALUE\");\n        require(_locked.amount == 0, \"VE: EXISTING_LOCK_FOUND\");\n        require(unlock_time > block.timestamp, \"VE: UNLOCK_TIME_TOO_EARLY\");\n        require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n        _depositFor(msg.sender, _value, 0, unlock_time, _locked, CRETE_LOCK_TYPE);\n    }\n\n    /**\n     * @notice Deposit `_value` additional tokens for `msg.sender`\n     *          without modifying the unlock time\n     * @param _addr User's wallet address\n     * @param _value Amount of tokens to deposit and add to the lock\n     * @param _discount Amount to get discounted out of _value\n     */\n    function increaseAmountFor(\n        address _addr,\n        uint256 _value,\n        uint256 _discount\n    ) external nonReentrant {\n        LockedBalance memory _locked = locked[_addr];\n\n        require(_value > 0, \"VE: INVALID_VALUE\");\n        require(_value >= _discount, \"VE: DISCOUNT_TOO_HIGH\");\n        require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n        require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n        _depositFor(_addr, _value, _discount, 0, _locked, INCREASE_LOCK_AMOUNT);\n    }\n\n    /**\n     * @notice Deposit `_value` additional tokens for `msg.sender`\n     *          without modifying the unlock time\n     * @param _value Amount of tokens to deposit and add to the lock\n     */\n    function increaseAmount(uint256 _value) external nonReentrant {\n        LockedBalance memory _locked = locked[msg.sender];\n\n        require(_value > 0, \"VE: INVALID_VALUE\");\n        require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n        require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n\n        _depositFor(msg.sender, _value, 0, 0, _locked, INCREASE_LOCK_AMOUNT);\n    }\n\n    /**\n     * @notice Extend the unlock time for `msg.sender` to `_duration`\n     * @param _duration Increased epoch time for unlocking\n     */\n    function increaseUnlockTime(uint256 _duration) external nonReentrant {\n        LockedBalance memory _locked = locked[msg.sender];\n        uint256 unlock_time = ((_locked.end + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\n\n        require(_locked.end > block.timestamp, \"VE: LOCK_EXPIRED\");\n        require(_locked.amount > 0, \"VE: LOCK_NOT_FOUND\");\n        require(_locked.discount == 0, \"VE: LOCK_DISCOUNTED\");\n        require(unlock_time >= _locked.end + interval, \"VE: UNLOCK_TIME_TOO_EARLY\");\n        require(unlock_time <= block.timestamp + maxDuration, \"VE: UNLOCK_TIME_TOO_LATE\");\n\n        _depositFor(msg.sender, 0, 0, unlock_time, _locked, INCREASE_UNLOCK_TIME);\n    }\n\n    /**\n     * @notice Withdraw all tokens for `msg.sender`\n     * @dev Only possible if the lock has expired\n     */\n    function withdraw() external nonReentrant {\n        LockedBalance memory _locked = locked[msg.sender];\n        require(block.timestamp >= _locked.end, \"VE: LOCK_NOT_EXPIRED\");\n\n        uint256 supply_before = _clear(_locked);\n\n        uint256 value = _locked.amount.toUint256();\n        uint256 discount = _locked.discount.toUint256();\n\n        if (value > discount) {\n            IERC20(token).safeTransfer(msg.sender, value - discount);\n        }\n\n        emit Withdraw(msg.sender, value, discount, block.timestamp);\n        emit Supply(supply_before, supply_before - value);\n    }\n\n    function _clear(LockedBalance memory _locked) internal returns (uint256 supply_before) {\n        uint256 value = _locked.amount.toUint256();\n\n        locked[msg.sender] = LockedBalance(0, 0, 0, 0);\n        supply_before = supply;\n        supply = supply_before - value;\n\n        // old_locked can have either expired <= timestamp or zero end\n        // _locked has only 0 end\n        // Both can have >= 0 amount\n        _checkpoint(msg.sender, _locked, LockedBalance(0, 0, 0, 0));\n    }\n\n    // The following ERC20/minime-compatible methods are not real balanceOf and supply!\n    // They measure the weights for the purpose of voting, so they don't represent\n    // real coins.\n\n    /**\n     * @notice Binary search to estimate timestamp for block number\n     * @param _block Block to find\n     * @param max_epoch Don't go beyond this epoch\n     * @return Approximate timestamp for block\n     */\n    function _findBlockEpoch(uint256 _block, uint256 max_epoch) internal view returns (uint256) {\n        uint256 _min;\n        uint256 _max = max_epoch;\n        for (uint256 i; i < 128; i++) {\n            if (_min >= _max) break;\n            uint256 _mid = (_min + _max + 1) / 2;\n            if (pointHistory[_mid].blk <= _block) _min = _mid;\n            else _max = _mid - 1;\n        }\n        return _min;\n    }\n\n    function balanceOf(address addr) public view returns (uint256) {\n        return balanceOf(addr, block.timestamp);\n    }\n\n    /**\n     * @notice Get the current voting power for `msg.sender`\n     * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility\n     * @param addr User wallet address\n     * @param _t Epoch time to return voting power at\n     * @return User voting power\n     */\n    function balanceOf(address addr, uint256 _t) public view returns (uint256) {\n        uint256 _epoch = userPointEpoch[addr];\n        if (_epoch == 0) return 0;\n        else {\n            Point memory last_point = userPointHistory[addr][_epoch];\n            last_point.bias -= last_point.slope * (_t - last_point.ts).toInt128();\n            if (last_point.bias < 0) last_point.bias = 0;\n            return last_point.bias.toUint256();\n        }\n    }\n\n    /**\n     * @notice Measure voting power of `addr` at block height `_block`\n     * @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime\n     * @param addr User's wallet address\n     * @param _block Block to calculate the voting power at\n     * @return Voting power\n     */\n    function balanceOfAt(address addr, uint256 _block) external view returns (uint256) {\n        // Copying and pasting totalSupply code because Vyper cannot pass by\n        // reference yet\n        require(_block <= block.number);\n\n        // Binary search\n        uint256 _min;\n        uint256 _max = userPointEpoch[addr];\n        for (uint256 i; i < 128; i++) {\n            if (_min >= _max) break;\n            uint256 _mid = (_min + _max + 1) / 2;\n            if (userPointHistory[addr][_mid].blk <= _block) _min = _mid;\n            else _max = _mid - 1;\n        }\n\n        Point memory upoint = userPointHistory[addr][_min];\n\n        uint256 max_epoch = epoch;\n        uint256 _epoch = _findBlockEpoch(_block, max_epoch);\n        Point memory point_0 = pointHistory[_epoch];\n        uint256 d_block;\n        uint256 d_t;\n        if (_epoch < max_epoch) {\n            Point memory point_1 = pointHistory[_epoch + 1];\n            d_block = point_1.blk - point_0.blk;\n            d_t = point_1.ts - point_0.ts;\n        } else {\n            d_block = block.number - point_0.blk;\n            d_t = block.timestamp - point_0.ts;\n        }\n        uint256 block_time = point_0.ts;\n        if (d_block != 0) block_time += ((d_t * (_block - point_0.blk)) / d_block);\n\n        upoint.bias -= upoint.slope * (block_time - upoint.ts).toInt128();\n        if (upoint.bias >= 0) return upoint.bias.toUint256();\n        else return 0;\n    }\n\n    /**\n     * @notice Calculate total voting power at some point in the past\n     * @param point The point (bias/slope) to start search from\n     * @param t Time to calculate the total voting power at\n     * @return Total voting power at that time\n     */\n    function _supplyAt(Point memory point, uint256 t) internal view returns (uint256) {\n        Point memory last_point = point;\n        uint256 t_i = (last_point.ts / interval) * interval;\n        for (uint256 i; i < 255; i++) {\n            t_i += interval;\n            int128 d_slope;\n            if (t_i > t) t_i = t;\n            else d_slope = slopeChanges[t_i];\n            last_point.bias -= last_point.slope * (t_i - last_point.ts).toInt128();\n            if (t_i == t) break;\n            last_point.slope += d_slope;\n            last_point.ts = t_i;\n        }\n\n        if (last_point.bias < 0) last_point.bias = 0;\n        return last_point.bias.toUint256();\n    }\n\n    function totalSupply() public view returns (uint256) {\n        return totalSupply(block.timestamp);\n    }\n\n    /**\n     * @notice Calculate total voting power\n     * @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility\n     * @return Total voting power\n     */\n    function totalSupply(uint256 t) public view returns (uint256) {\n        uint256 _epoch = epoch;\n        Point memory last_point = pointHistory[_epoch];\n        return _supplyAt(last_point, t);\n    }\n\n    /**\n     * @notice Calculate total voting power at some point in the past\n     * @param _block Block to calculate the total voting power at\n     * @return Total voting power at `_block`\n     */\n    function totalSupplyAt(uint256 _block) external view returns (uint256) {\n        require(_block <= block.number);\n        uint256 _epoch = epoch;\n        uint256 target_epoch = _findBlockEpoch(_block, _epoch);\n\n        Point memory point = pointHistory[target_epoch];\n        uint256 dt;\n        if (target_epoch < _epoch) {\n            Point memory point_next = pointHistory[target_epoch + 1];\n            if (point.blk != point_next.blk)\n                dt = ((_block - point.blk) * (point_next.ts - point.ts)) / (point_next.blk - point.blk);\n        } else if (point.blk != block.number)\n            dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk);\n        // Now dt contains info on how far are we beyond point\n\n        return _supplyAt(point, point.ts + dt);\n    }\n}\n"
    },
    "contracts/mocks/libraries/Integers.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.17;\n\nlibrary Integers {\n    error OutOfRange();\n\n    function toInt128(uint256 u) internal pure returns (int128) {\n        revertIfOutOfRange(u <= uint256(uint128(type(int128).max)));\n        return int128(int256(u));\n    }\n\n    function toUint192(uint256 u) internal pure returns (uint192) {\n        revertIfOutOfRange(u <= uint256(type(uint192).max));\n        return uint192(u);\n    }\n\n    function toUint256(int128 i) internal pure returns (uint256) {\n        revertIfOutOfRange(i >= 0);\n        return uint256(uint128(i));\n    }\n\n    function revertIfOutOfRange(bool success) internal pure {\n        if (!success) revert OutOfRange();\n    }\n}\n"
    },
    "contracts/mocks/FlashProtocol.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"../interfaces/IFlashStrategy.sol\";\nimport \"../interfaces/IFlashFToken.sol\";\nimport \"../interfaces/IFlashNFT.sol\";\nimport \"../interfaces/IFlashFTokenFactory.sol\";\n\ncontract FlashProtocol is Ownable, ReentrancyGuard {\n    using SafeERC20 for IERC20;\n\n    address public immutable flashNFTAddress;\n    address immutable flashFTokenFactoryAddress;\n\n    // Define the structure for each strategy\n    struct StrategyInformation {\n        address fTokenAddress;\n        address principalTokenAddress;\n    }\n    mapping(address => StrategyInformation) strategies;\n\n    // This will store the NFT ID to StakeID mapping\n    mapping(uint256 => uint256) nftIdMappingsToStakeIds;\n\n    // This will store how many stakes we have\n    uint256 stakeCount = 0;\n\n    // The global fToken mint fee\n    uint96 globalMintFee = 0;\n    address globalMintFeeRecipient = 0x5089722613C2cCEe071C39C59e9889641f435F15;\n\n    // This defines the structure of the Stake information we store\n    struct StakeStruct {\n        address stakerAddress; // Address of staker\n        address strategyAddress; // Address of strategy being used\n        uint256 stakeStartTs; // Unix timestamp of when stake started\n        uint256 stakeDuration; // Time in seconds from start time until stake ends\n        uint256 stakedAmount; // The amount of tokens staked\n        bool active; // Stake has been removed/unstaked\n        uint256 nftId; // NFT id if set\n        uint256 fTokensToUser; // How many fERC20 tokens were minted\n        uint256 fTokensFee; // How many fERC20 tokens were taken as fee\n        uint256 totalFTokenBurned;\n        uint256 totalStakedWithdrawn;\n    }\n    mapping(uint256 => StakeStruct) stakes;\n\n    // Define events\n    event StrategyRegistered(\n        address indexed _strategyAddress,\n        address indexed _principalTokenAddress,\n        address indexed _fTokenAddress\n    );\n    event Staked(uint256 _stakeId);\n    event Unstaked(uint256 _stakeId, uint256 _tokensReturned, uint256 _fTokensBurned, bool _stakeFinished);\n    event NFTIssued(uint256 _stakeId, uint256 nftId);\n\n    constructor(address _flashNFTAddress, address _flashFTokenFactoryAddress) {\n        flashNFTAddress = _flashNFTAddress;\n        flashFTokenFactoryAddress = _flashFTokenFactoryAddress;\n    }\n\n    function registerStrategy(\n        address _strategyAddress,\n        address _principalTokenAddress,\n        string calldata _fTokenName,\n        string calldata _fTokenSymbol\n    ) external {\n        require(\n            strategies[_strategyAddress].principalTokenAddress == address(0) &&\n                _strategyAddress != address(0) &&\n                _principalTokenAddress != address(0)\n        );\n\n        address flashFToken = IFlashFTokenFactory(flashFTokenFactoryAddress).createFToken(_fTokenName, _fTokenSymbol);\n\n        // Store the appropriate information\n        strategies[_strategyAddress].fTokenAddress = flashFToken;\n        strategies[_strategyAddress].principalTokenAddress = _principalTokenAddress;\n\n        IFlashStrategy(_strategyAddress).setFTokenAddress(flashFToken);\n\n        emit StrategyRegistered(_strategyAddress, _principalTokenAddress, flashFToken);\n    }\n\n    function stake(\n        address _strategyAddress,\n        uint256 _tokenAmount,\n        uint256 _stakeDuration,\n        address _fTokensTo,\n        bool _issueNFT\n    ) public nonReentrant returns (StakeStruct memory _stake) {\n        require(strategies[_strategyAddress].principalTokenAddress != address(0));\n        require(\n            _stakeDuration >= 60 && _stakeDuration <= IFlashStrategy(_strategyAddress).getMaxStakeDuration(),\n            \"ISD\"\n        );\n\n        // Transfer the tokens from caller to the strategy contract\n        IERC20(strategies[_strategyAddress].principalTokenAddress).safeTransferFrom(\n            msg.sender,\n            address(_strategyAddress),\n            _tokenAmount\n        );\n\n        // Determine how many fERC20 tokens to mint (ask strategy)\n        uint256 tokensToMint = IFlashStrategy(_strategyAddress).quoteMintFToken(_tokenAmount, _stakeDuration);\n\n        // Deposit into the strategy\n        uint256 principalAfterDeductions = IFlashStrategy(_strategyAddress).depositPrincipal(_tokenAmount);\n\n        // Calculate fee and if this is more than 0, transfer fee\n        uint256 fee = (tokensToMint * globalMintFee) / 10000;\n        if (fee > 0) {\n            IFlashFToken(strategies[_strategyAddress].fTokenAddress).mint(globalMintFeeRecipient, fee);\n        }\n\n        // Mint fERC20 tokens to the user\n        IFlashFToken(strategies[_strategyAddress].fTokenAddress).mint(_fTokensTo, (tokensToMint - fee));\n\n        // Save the stake details\n        stakeCount = stakeCount + 1;\n        stakes[stakeCount] = StakeStruct(\n            msg.sender,\n            _strategyAddress,\n            block.timestamp,\n            _stakeDuration,\n            principalAfterDeductions,\n            true,\n            0,\n            (tokensToMint - fee),\n            fee,\n            0,\n            0\n        );\n\n        // Mint NFT if requested\n        if (_issueNFT) {\n            issueNFT(stakeCount);\n        }\n\n        emit Staked(stakeCount);\n\n        return stakes[stakeCount];\n    }\n\n    function unstake(\n        uint256 _id,\n        bool _isNFT,\n        uint256 _fTokenToBurn\n    ) external nonReentrant returns (uint256 _principalReturned, uint256 _fTokensBurned) {\n        StakeStruct memory p;\n        uint256 stakeId;\n        address returnAddress;\n        if (_isNFT) {\n            stakeId = nftIdMappingsToStakeIds[_id];\n            p = stakes[stakeId];\n            returnAddress = msg.sender;\n            require(p.nftId == _id, \"SNM\");\n            require(IFlashNFT(flashNFTAddress).ownerOf(_id) == msg.sender, \"NNO\");\n        } else {\n            stakeId = _id;\n            p = stakes[stakeId];\n            returnAddress = p.stakerAddress;\n\n            require(p.nftId == 0, \"NTR\");\n            require(p.stakerAddress == msg.sender, \"NSO\");\n        }\n        require(p.active == true, \"SNE\");\n\n        bool stakeFinished;\n        uint256 principalToReturn;\n        uint256 percentageIntoStake = (((block.timestamp - p.stakeStartTs) * (10**18)) / p.stakeDuration);\n\n        if (percentageIntoStake >= (10**18)) {\n            // Stake has ended, simply return principal\n            principalToReturn = p.stakedAmount - p.totalStakedWithdrawn;\n            _fTokenToBurn = 0;\n\n            stakeFinished = true;\n        } else {\n            require(block.timestamp >= (p.stakeStartTs + 3600), \"MIN DUR 1HR\");\n\n            // Stake has not ended yet, user is trying to withdraw early\n            uint256 fTokenBurnForFullUnstake = ((((10**18) - percentageIntoStake) * (p.fTokensToUser + p.fTokensFee)) /\n                (10**18));\n\n            if (p.totalFTokenBurned > fTokenBurnForFullUnstake) {\n                // The total number of fTokens burned is greater than the amount required, no burn required\n                fTokenBurnForFullUnstake = 0;\n            } else {\n                fTokenBurnForFullUnstake = fTokenBurnForFullUnstake - p.totalFTokenBurned;\n            }\n\n            // Ensure the user cannot burn more fTokens than required\n            if (_fTokenToBurn > fTokenBurnForFullUnstake) {\n                _fTokenToBurn = fTokenBurnForFullUnstake;\n            }\n\n            // Is the user trying to withdraw everything early?\n            if (_fTokenToBurn == fTokenBurnForFullUnstake) {\n                // Yes, return all principal\n                principalToReturn = p.stakedAmount - p.totalStakedWithdrawn;\n                stakeFinished = true;\n            } else {\n                // No - only a partial withdraw\n                principalToReturn =\n                    (((_fTokenToBurn * (10**18)) / (p.fTokensToUser + p.fTokensFee)) * p.stakedAmount) /\n                    (10**18);\n            }\n\n            // Burn these fTokens\n            IFlashFToken(strategies[p.strategyAddress].fTokenAddress).burnFrom(msg.sender, _fTokenToBurn);\n\n            // Update stake information\n            stakes[stakeId].totalFTokenBurned = p.totalFTokenBurned + _fTokenToBurn;\n            stakes[stakeId].totalStakedWithdrawn = p.totalStakedWithdrawn + principalToReturn;\n        }\n        require(principalToReturn > 0);\n        require(p.stakedAmount >= stakes[stakeId].totalStakedWithdrawn);\n\n        // if the stake is finished, delete all data related to it (nice to have)\n        if (stakeFinished) {\n            delete stakes[stakeId];\n        }\n        // if the stake finished and it was NFT based, remove the mapping (nice to have)\n        if (stakeFinished && _isNFT) {\n            delete nftIdMappingsToStakeIds[_id];\n        }\n        emit Unstaked(stakeId, principalToReturn, _fTokenToBurn, stakeFinished);\n\n        // Remove tokens from Strategy and transfer to user\n        IFlashStrategy(p.strategyAddress).withdrawPrincipal(principalToReturn);\n        IERC20(strategies[p.strategyAddress].principalTokenAddress).safeTransfer(returnAddress, principalToReturn);\n\n        return (principalToReturn, _fTokenToBurn);\n    }\n\n    function issueNFT(uint256 _stakeId) public returns (uint256 _nftId) {\n        StakeStruct memory p = stakes[_stakeId];\n        require(p.active == true && p.nftId == 0 && p.stakerAddress == msg.sender);\n\n        // Mint the NFT\n        uint256 nftId = IFlashNFT(flashNFTAddress).mint(msg.sender);\n\n        // Store the NFT ID\n        stakes[_stakeId].nftId = nftId;\n\n        // Update the NFT Mapping so we can look it up later\n        nftIdMappingsToStakeIds[nftId] = _stakeId;\n\n        emit NFTIssued(_stakeId, nftId);\n\n        return nftId;\n    }\n\n    function setMintFeeInfo(address _feeRecipient, uint96 _feePercentageBasis) external onlyOwner {\n        require(_feePercentageBasis <= 2000);\n        globalMintFeeRecipient = _feeRecipient;\n        globalMintFee = _feePercentageBasis;\n    }\n\n    function getStakeInfo(uint256 _id, bool _isNFT) external view returns (StakeStruct memory _stake) {\n        uint256 stakeId;\n        if (_isNFT) {\n            stakeId = nftIdMappingsToStakeIds[_id];\n            require(stakes[stakeId].nftId == _id);\n        } else {\n            stakeId = _id;\n        }\n\n        return stakes[stakeId];\n    }\n\n    function flashStake(\n        address _strategyAddress,\n        uint256 _tokenAmount,\n        uint256 _stakeDuration,\n        uint256 _minimumReceived,\n        address _yieldTo,\n        bool _mintNFT\n    ) external {\n        // Stake (re-direct fTokens to this contract)\n        uint256 fTokensToUser = stake(_strategyAddress, _tokenAmount, _stakeDuration, address(this), _mintNFT)\n            .fTokensToUser;\n\n        IERC20 fToken = IERC20(strategies[_strategyAddress].fTokenAddress);\n\n        // Approve, burn and send yield to specified address\n        fToken.approve(_strategyAddress, fTokensToUser);\n        IFlashStrategy(_strategyAddress).burnFToken(fTokensToUser, _minimumReceived, _yieldTo);\n    }\n}\n"
    },
    "contracts/interfaces/IFlashNFT.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashNFT {\n    function mint(address _recipientAddress) external returns (uint256);\n\n    function burn(uint256 _tokenId) external returns (bool);\n\n    function ownerOf(uint256 tokenId) external view returns (address);\n}\n"
    },
    "contracts/interfaces/IFlashFTokenFactory.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\ninterface IFlashFTokenFactory {\n    function createFToken(string calldata _fTokenName, string calldata _fTokenSymbol) external returns (address);\n}\n"
    },
    "contracts/mocks/FlashFTokenFactory.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"../interfaces/IFlashFTokenFactory.sol\";\nimport \"./FlashFToken.sol\";\n\ncontract FlashFTokenFactory is Ownable, IFlashFTokenFactory {\n    event FTokenCreated(address _tokenAddress);\n\n    constructor() {}\n\n    function createFToken(string calldata _fTokenName, string calldata _fTokenSymbol)\n        external\n        onlyOwner\n        returns (address)\n    {\n        FlashFToken flashFToken = new FlashFToken(_fTokenName, _fTokenSymbol);\n        flashFToken.transferOwnership(msg.sender);\n\n        emit FTokenCreated(address(flashFToken));\n        return address(flashFToken);\n    }\n}\n"
    },
    "contracts/mocks/FlashFToken.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\";\n\ncontract FlashFToken is ERC20, ERC20Burnable, ERC20Permit, Ownable {\n    constructor(string memory _tokenName, string memory _tokenSymbol)\n        ERC20(_tokenName, _tokenSymbol)\n        ERC20Permit(_tokenName)\n    {}\n\n    function mint(address to, uint256 amount) public onlyOwner {\n        _mint(to, amount);\n    }\n}\n"
    },
    "contracts/mocks/FeeVault.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"../interfaces/IERC20Receiver.sol\";\n\ncontract FeeVault is IERC20Receiver {\n    using SafeERC20 for IERC20;\n\n    mapping(address => uint256) claimableAmount;\n\n    function onReceiveERC20(\n        address token,\n        address,\n        uint256\n    ) external {\n        claimableAmount[token] = IERC20(token).balanceOf(address(this));\n    }\n\n    function claim(address token) external {\n        uint256 amount = claimableAmount[token];\n        claimableAmount[token] = 0;\n\n        IERC20(token).safeTransfer(msg.sender, amount);\n    }\n}\n"
    },
    "contracts/mocks/MasterChef.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./SushiToken.sol\";\n\ninterface IMigratorChef {\n    // Perform LP token migration from legacy UniswapV2 to SushiSwap.\n    // Take the current LP token address and return the new LP token address.\n    // Migrator should have full access to the caller's LP token.\n    // Return the new LP token address.\n    //\n    // XXX Migrator must have allowance access to UniswapV2 LP tokens.\n    // SushiSwap must mint EXACTLY the same amount of SushiSwap LP tokens or\n    // else something bad will happen. Traditional UniswapV2 does not\n    // do that so be careful!\n    function migrate(IERC20 token) external returns (IERC20);\n}\n\n// MasterChef is the master of Sushi. He can make Sushi and he is a fair guy.\n//\n// Note that it's ownable and the owner wields tremendous power. The ownership\n// will be transferred to a governance smart contract once SUSHI is sufficiently\n// distributed and the community can show to govern itself.\n//\n// Have fun reading it. Hopefully it's bug-free. God bless.\ncontract MasterChef is Ownable {\n    using SafeMath for uint256;\n    using SafeERC20 for IERC20;\n    // Info of each user.\n    struct UserInfo {\n        uint256 amount; // How many LP tokens the user has provided.\n        uint256 rewardDebt; // Reward debt. See explanation below.\n        //\n        // We do some fancy math here. Basically, any point in time, the amount of SUSHIs\n        // entitled to a user but is pending to be distributed is:\n        //\n        //   pending reward = (user.amount * pool.accSushiPerShare) - user.rewardDebt\n        //\n        // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n        //   1. The pool's `accSushiPerShare` (and `lastRewardBlock`) gets updated.\n        //   2. User receives the pending reward sent to his/her address.\n        //   3. User's `amount` gets updated.\n        //   4. User's `rewardDebt` gets updated.\n    }\n    // Info of each pool.\n    struct PoolInfo {\n        IERC20 lpToken; // Address of LP token contract.\n        uint256 allocPoint; // How many allocation points assigned to this pool. SUSHIs to distribute per block.\n        uint256 lastRewardBlock; // Last block number that SUSHIs distribution occurs.\n        uint256 accSushiPerShare; // Accumulated SUSHIs per share, times 1e12. See below.\n    }\n    // The SUSHI TOKEN!\n    SushiToken public sushi;\n    // Dev address.\n    address public devaddr;\n    // Block number when bonus SUSHI period ends.\n    uint256 public bonusEndBlock;\n    // SUSHI tokens created per block.\n    uint256 public sushiPerBlock;\n    // Bonus muliplier for early sushi makers.\n    uint256 public constant BONUS_MULTIPLIER = 10;\n    // The migrator contract. It has a lot of power. Can only be set through governance (owner).\n    IMigratorChef public migrator;\n    // Info of each pool.\n    PoolInfo[] public poolInfo;\n    // Info of each user that stakes LP tokens.\n    mapping(uint256 => mapping(address => UserInfo)) public userInfo;\n    // Total allocation poitns. Must be the sum of all allocation points in all pools.\n    uint256 public totalAllocPoint = 0;\n    // The block number when SUSHI mining starts.\n    uint256 public startBlock;\n    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);\n    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);\n    event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);\n\n    constructor(\n        SushiToken _sushi,\n        address _devaddr,\n        uint256 _sushiPerBlock,\n        uint256 _startBlock,\n        uint256 _bonusEndBlock\n    ) {\n        sushi = _sushi;\n        devaddr = _devaddr;\n        sushiPerBlock = _sushiPerBlock;\n        bonusEndBlock = _bonusEndBlock;\n        startBlock = _startBlock;\n    }\n\n    function poolLength() external view returns (uint256) {\n        return poolInfo.length;\n    }\n\n    // Add a new lp to the pool. Can only be called by the owner.\n    // XXX DO NOT add the same LP token more than once. Rewards will be messed up if you do.\n    function add(\n        uint256 _allocPoint,\n        IERC20 _lpToken,\n        bool _withUpdate\n    ) public onlyOwner {\n        if (_withUpdate) {\n            massUpdatePools();\n        }\n        uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n        totalAllocPoint = totalAllocPoint.add(_allocPoint);\n        poolInfo.push(\n            PoolInfo({\n                lpToken: _lpToken,\n                allocPoint: _allocPoint,\n                lastRewardBlock: lastRewardBlock,\n                accSushiPerShare: 0\n            })\n        );\n    }\n\n    // Update the given pool's SUSHI allocation point. Can only be called by the owner.\n    function set(\n        uint256 _pid,\n        uint256 _allocPoint,\n        bool _withUpdate\n    ) public onlyOwner {\n        if (_withUpdate) {\n            massUpdatePools();\n        }\n        totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);\n        poolInfo[_pid].allocPoint = _allocPoint;\n    }\n\n    // Set the migrator contract. Can only be called by the owner.\n    function setMigrator(IMigratorChef _migrator) public onlyOwner {\n        migrator = _migrator;\n    }\n\n    // Migrate lp token to another lp contract. Can be called by anyone. We trust that migrator contract is good.\n    function migrate(uint256 _pid) public {\n        require(address(migrator) != address(0), \"migrate: no migrator\");\n        PoolInfo storage pool = poolInfo[_pid];\n        IERC20 lpToken = pool.lpToken;\n        uint256 bal = lpToken.balanceOf(address(this));\n        lpToken.safeApprove(address(migrator), bal);\n        IERC20 newLpToken = migrator.migrate(lpToken);\n        require(bal == newLpToken.balanceOf(address(this)), \"migrate: bad\");\n        pool.lpToken = newLpToken;\n    }\n\n    // Return reward multiplier over the given _from to _to block.\n    function getMultiplier(uint256 _from, uint256 _to) public view returns (uint256) {\n        if (_to <= bonusEndBlock) {\n            return _to.sub(_from).mul(BONUS_MULTIPLIER);\n        } else if (_from >= bonusEndBlock) {\n            return _to.sub(_from);\n        } else {\n            return bonusEndBlock.sub(_from).mul(BONUS_MULTIPLIER).add(_to.sub(bonusEndBlock));\n        }\n    }\n\n    // View function to see pending SUSHIs on frontend.\n    function pendingSushi(uint256 _pid, address _user) external view returns (uint256) {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][_user];\n        uint256 accSushiPerShare = pool.accSushiPerShare;\n        uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n        if (block.number > pool.lastRewardBlock && lpSupply != 0) {\n            uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);\n            uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint);\n            accSushiPerShare = accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply));\n        }\n        return user.amount.mul(accSushiPerShare).div(1e12).sub(user.rewardDebt);\n    }\n\n    // Update reward vairables for all pools. Be careful of gas spending!\n    function massUpdatePools() public {\n        uint256 length = poolInfo.length;\n        for (uint256 pid = 0; pid < length; ++pid) {\n            updatePool(pid);\n        }\n    }\n\n    // Update reward variables of the given pool to be up-to-date.\n    function updatePool(uint256 _pid) public {\n        PoolInfo storage pool = poolInfo[_pid];\n        if (block.number <= pool.lastRewardBlock) {\n            return;\n        }\n        uint256 lpSupply = pool.lpToken.balanceOf(address(this));\n        if (lpSupply == 0) {\n            pool.lastRewardBlock = block.number;\n            return;\n        }\n        uint256 multiplier = getMultiplier(pool.lastRewardBlock, block.number);\n        uint256 sushiReward = multiplier.mul(sushiPerBlock).mul(pool.allocPoint).div(totalAllocPoint);\n        sushi.mint(devaddr, sushiReward.div(10));\n        sushi.mint(address(this), sushiReward);\n        pool.accSushiPerShare = pool.accSushiPerShare.add(sushiReward.mul(1e12).div(lpSupply));\n        pool.lastRewardBlock = block.number;\n    }\n\n    // Deposit LP tokens to MasterChef for SUSHI allocation.\n    function deposit(uint256 _pid, uint256 _amount) public {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        updatePool(_pid);\n        if (user.amount > 0) {\n            uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt);\n            safeSushiTransfer(msg.sender, pending);\n        }\n        pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n        user.amount = user.amount.add(_amount);\n        user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);\n        emit Deposit(msg.sender, _pid, _amount);\n    }\n\n    // Withdraw LP tokens from MasterChef.\n    function withdraw(uint256 _pid, uint256 _amount) public {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        require(user.amount >= _amount, \"withdraw: not good\");\n        updatePool(_pid);\n        uint256 pending = user.amount.mul(pool.accSushiPerShare).div(1e12).sub(user.rewardDebt);\n        safeSushiTransfer(msg.sender, pending);\n        user.amount = user.amount.sub(_amount);\n        user.rewardDebt = user.amount.mul(pool.accSushiPerShare).div(1e12);\n        pool.lpToken.safeTransfer(address(msg.sender), _amount);\n        emit Withdraw(msg.sender, _pid, _amount);\n    }\n\n    // Withdraw without caring about rewards. EMERGENCY ONLY.\n    function emergencyWithdraw(uint256 _pid) public {\n        PoolInfo storage pool = poolInfo[_pid];\n        UserInfo storage user = userInfo[_pid][msg.sender];\n        pool.lpToken.safeTransfer(address(msg.sender), user.amount);\n        emit EmergencyWithdraw(msg.sender, _pid, user.amount);\n        user.amount = 0;\n        user.rewardDebt = 0;\n    }\n\n    // Safe sushi transfer function, just in case if rounding error causes pool to not have enough SUSHIs.\n    function safeSushiTransfer(address _to, uint256 _amount) internal {\n        uint256 sushiBal = sushi.balanceOf(address(this));\n        if (_amount > sushiBal) {\n            sushi.transfer(_to, sushiBal);\n        } else {\n            sushi.transfer(_to, _amount);\n        }\n    }\n\n    // Update dev address by the previous dev.\n    function dev(address _devaddr) public {\n        require(msg.sender == devaddr, \"dev: wut?\");\n        devaddr = _devaddr;\n    }\n}\n"
    },
    "contracts/mocks/SushiToken.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeMath.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\n// WARNING: There is a known vuln contained within this contract related to vote delegation,\n// it's NOT recommmended to use this in production.\n\n// SushiToken with Governance.\ncontract SushiToken is ERC20(\"SushiToken\", \"SUSHI\"), Ownable {\n    using SafeMath for uint256;\n\n    /// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).\n    function mint(address _to, uint256 _amount) public onlyOwner {\n        _mint(_to, _amount);\n        _moveDelegates(address(0), _delegates[_to], _amount);\n    }\n\n    // Copied and modified from YAM code:\n    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol\n    // https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol\n    // Which is copied and modified from COMPOUND:\n    // https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol\n\n    /// @notice A record of each accounts delegate\n    mapping(address => address) internal _delegates;\n\n    /// @notice A checkpoint for marking number of votes from a given block\n    struct Checkpoint {\n        uint32 fromBlock;\n        uint256 votes;\n    }\n\n    /// @notice A record of votes checkpoints for each account, by index\n    mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;\n\n    /// @notice The number of checkpoints for each account\n    mapping(address => uint32) public numCheckpoints;\n\n    /// @notice The EIP-712 typehash for the contract's domain\n    bytes32 public constant DOMAIN_TYPEHASH =\n        keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n    /// @notice The EIP-712 typehash for the delegation struct used by the contract\n    bytes32 public constant DELEGATION_TYPEHASH =\n        keccak256(\"Delegation(address delegatee,uint256 nonce,uint256 expiry)\");\n\n    /// @notice A record of states for signing / validating signatures\n    mapping(address => uint256) public nonces;\n\n    /// @notice An event thats emitted when an account changes its delegate\n    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);\n\n    /// @notice An event thats emitted when a delegate account's vote balance changes\n    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);\n\n    /**\n     * @notice Delegate votes from `msg.sender` to `delegatee`\n     * @param delegator The address to get delegatee for\n     */\n    function delegates(address delegator) external view returns (address) {\n        return _delegates[delegator];\n    }\n\n    /**\n     * @notice Delegate votes from `msg.sender` to `delegatee`\n     * @param delegatee The address to delegate votes to\n     */\n    function delegate(address delegatee) external {\n        return _delegate(msg.sender, delegatee);\n    }\n\n    /**\n     * @notice Delegates votes from signatory to `delegatee`\n     * @param delegatee The address to delegate votes to\n     * @param nonce The contract state required to match the signature\n     * @param expiry The time at which to expire the signature\n     * @param v The recovery byte of the signature\n     * @param r Half of the ECDSA signature pair\n     * @param s Half of the ECDSA signature pair\n     */\n    function delegateBySig(\n        address delegatee,\n        uint256 nonce,\n        uint256 expiry,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external {\n        bytes32 domainSeparator = keccak256(\n            abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), getChainId(), address(this))\n        );\n\n        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));\n\n        bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n\n        address signatory = ecrecover(digest, v, r, s);\n        require(signatory != address(0), \"SUSHI::delegateBySig: invalid signature\");\n        require(nonce == nonces[signatory]++, \"SUSHI::delegateBySig: invalid nonce\");\n        require(block.timestamp <= expiry, \"SUSHI::delegateBySig: signature expired\");\n        return _delegate(signatory, delegatee);\n    }\n\n    /**\n     * @notice Gets the current votes balance for `account`\n     * @param account The address to get votes balance\n     * @return The number of current votes for `account`\n     */\n    function getCurrentVotes(address account) external view returns (uint256) {\n        uint32 nCheckpoints = numCheckpoints[account];\n        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;\n    }\n\n    /**\n     * @notice Determine the prior number of votes for an account as of a block number\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\n     * @param account The address of the account to check\n     * @param blockNumber The block number to get the vote balance at\n     * @return The number of votes the account had as of the given block\n     */\n    function getPriorVotes(address account, uint256 blockNumber) external view returns (uint256) {\n        require(blockNumber < block.number, \"SUSHI::getPriorVotes: not yet determined\");\n\n        uint32 nCheckpoints = numCheckpoints[account];\n        if (nCheckpoints == 0) {\n            return 0;\n        }\n\n        // First check most recent balance\n        if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {\n            return checkpoints[account][nCheckpoints - 1].votes;\n        }\n\n        // Next check implicit zero balance\n        if (checkpoints[account][0].fromBlock > blockNumber) {\n            return 0;\n        }\n\n        uint32 lower = 0;\n        uint32 upper = nCheckpoints - 1;\n        while (upper > lower) {\n            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n            Checkpoint memory cp = checkpoints[account][center];\n            if (cp.fromBlock == blockNumber) {\n                return cp.votes;\n            } else if (cp.fromBlock < blockNumber) {\n                lower = center;\n            } else {\n                upper = center - 1;\n            }\n        }\n        return checkpoints[account][lower].votes;\n    }\n\n    function _delegate(address delegator, address delegatee) internal {\n        address currentDelegate = _delegates[delegator];\n        uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SUSHIs (not scaled);\n        _delegates[delegator] = delegatee;\n\n        emit DelegateChanged(delegator, currentDelegate, delegatee);\n\n        _moveDelegates(currentDelegate, delegatee, delegatorBalance);\n    }\n\n    function _moveDelegates(\n        address srcRep,\n        address dstRep,\n        uint256 amount\n    ) internal {\n        if (srcRep != dstRep && amount > 0) {\n            if (srcRep != address(0)) {\n                // decrease old representative\n                uint32 srcRepNum = numCheckpoints[srcRep];\n                uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;\n                uint256 srcRepNew = srcRepOld.sub(amount);\n                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);\n            }\n\n            if (dstRep != address(0)) {\n                // increase new representative\n                uint32 dstRepNum = numCheckpoints[dstRep];\n                uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;\n                uint256 dstRepNew = dstRepOld.add(amount);\n                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);\n            }\n        }\n    }\n\n    function _writeCheckpoint(\n        address delegatee,\n        uint32 nCheckpoints,\n        uint256 oldVotes,\n        uint256 newVotes\n    ) internal {\n        uint32 blockNumber = safe32(block.number, \"SUSHI::_writeCheckpoint: block number exceeds 32 bits\");\n\n        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {\n            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;\n        } else {\n            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);\n            numCheckpoints[delegatee] = nCheckpoints + 1;\n        }\n\n        emit DelegateVotesChanged(delegatee, oldVotes, newVotes);\n    }\n\n    function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n        require(n < 2**32, errorMessage);\n        return uint32(n);\n    }\n\n    function getChainId() internal view returns (uint256) {\n        return block.chainid;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/SafeMath.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator.\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b <= a, errorMessage);\n            return a - b;\n        }\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a / b;\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(\n        uint256 a,\n        uint256 b,\n        string memory errorMessage\n    ) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a % b;\n        }\n    }\n}\n"
    },
    "contracts/interfaces/ISushiBar.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface ISushiBar is IERC20 {\n    function sushi() external view returns (IERC20);\n\n    function enter(uint256 _amount) external;\n\n    function leave(uint256 _share) external;\n}\n"
    },
    "contracts/SushiBarVault.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol\";\nimport \"./interfaces/ISushiBar.sol\";\n\ncontract SushiBarVault is ERC4626 {\n    using SafeERC20 for IERC20;\n\n    address internal immutable _sushi;\n    address internal immutable _sushiBar;\n\n    constructor(address sushi, address sushiBar) ERC4626(IERC20(sushi)) ERC20(\"SushiBar Yield Vault\", \"yxSUSHI\") {\n        _sushi = sushi;\n        _sushiBar = sushiBar;\n\n        approveMax();\n    }\n\n    function totalAssets() public view override returns (uint256) {\n        uint256 total = IERC20(_sushiBar).totalSupply();\n        return\n            total == 0\n                ? 0\n                : (IERC20(_sushi).balanceOf(address(_sushiBar)) * IERC20(_sushiBar).balanceOf(address(this))) / total;\n    }\n\n    function _initialConvertToShares(\n        uint256 assets,\n        Math.Rounding /*rounding*/\n    ) internal view override returns (uint256 shares) {\n        uint256 balance = IERC20(_sushi).balanceOf(address(_sushiBar));\n        return balance == 0 ? assets : (assets * IERC20(_sushiBar).totalSupply()) / balance;\n    }\n\n    function _initialConvertToAssets(\n        uint256 shares,\n        Math.Rounding /*rounding*/\n    ) internal view override returns (uint256 assets) {\n        uint256 total = IERC20(_sushiBar).totalSupply();\n        return total == 0 ? shares : (shares * IERC20(_sushi).balanceOf(address(_sushiBar))) / total;\n    }\n\n    function approveMax() public {\n        IERC20(_sushi).approve(_sushiBar, type(uint256).max);\n    }\n\n    function _deposit(\n        address caller,\n        address receiver,\n        uint256 assets,\n        uint256 shares\n    ) internal override {\n        IERC20(_sushi).safeTransferFrom(msg.sender, address(this), assets);\n        ISushiBar(_sushiBar).enter(assets);\n\n        _mint(receiver, shares);\n\n        emit Deposit(caller, receiver, assets, shares);\n    }\n\n    function _withdraw(\n        address caller,\n        address receiver,\n        address owner,\n        uint256 assets,\n        uint256 shares\n    ) internal override {\n        if (caller != owner) {\n            _spendAllowance(owner, caller, shares);\n        }\n\n        _burn(owner, shares);\n\n        ISushiBar(_sushiBar).leave(shares);\n        IERC20(_sushi).safeTransfer(receiver, assets);\n\n        emit Withdraw(caller, receiver, owner, assets, shares);\n    }\n}\n"
    },
    "contracts/mocks/SushiBar.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"./libraries/SafeMath.sol\";\n\ncontract SushiBar is ERC20(\"SushiBar\", \"xSUSHI\") {\n    using SafeMath for uint256;\n    IERC20 public sushi;\n\n    constructor(IERC20 _sushi) {\n        sushi = _sushi;\n    }\n\n    // Enter the bar. Pay some SUSHIs. Earn some shares.\n    function enter(uint256 _amount) public {\n        uint256 totalSushi = sushi.balanceOf(address(this));\n        uint256 totalShares = totalSupply();\n        if (totalShares == 0 || totalSushi == 0) {\n            _mint(msg.sender, _amount);\n        } else {\n            uint256 what = _amount.mul(totalShares).div(totalSushi);\n            _mint(msg.sender, what);\n        }\n        sushi.transferFrom(msg.sender, address(this), _amount);\n    }\n\n    // Leave the bar. Claim back your SUSHIs.\n    function leave(uint256 _share) public {\n        uint256 totalShares = totalSupply();\n        uint256 what = _share.mul(sushi.balanceOf(address(this))).div(totalShares);\n        _burn(msg.sender, _share);\n        sushi.transfer(msg.sender, what);\n    }\n}\n"
    },
    "contracts/mocks/libraries/SafeMath.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\n// a library for performing overflow-safe math, updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math)\nlibrary SafeMath {\n    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {\n        require((c = a + b) >= b, \"SafeMath: Add Overflow\");\n    }\n\n    function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {\n        require((c = a - b) <= a, \"SafeMath: Underflow\");\n    }\n\n    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {\n        require(b == 0 || (c = a * b) / b == a, \"SafeMath: Mul Overflow\");\n    }\n\n    function div(uint256 a, uint256 b) internal pure returns (uint256 c) {\n        c = a / b;\n    }\n\n    function to128(uint256 a) internal pure returns (uint128 c) {\n        require(a <= type(uint128).max, \"SafeMath: uint128 Overflow\");\n        c = uint128(a);\n    }\n}\n\nlibrary SafeMath128 {\n    function add(uint128 a, uint128 b) internal pure returns (uint128 c) {\n        require((c = a + b) >= b, \"SafeMath: Add Overflow\");\n    }\n\n    function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {\n        require((c = a - b) <= a, \"SafeMath: Underflow\");\n    }\n}\n"
    },
    "contracts/mocks/ERC20Mock.sol": {
      "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.17;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract ERC20Mock is ERC20 {\n    uint8 internal immutable _decimals;\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        uint8 __decimals\n    ) ERC20(name, symbol) {\n        _decimals = __decimals;\n    }\n\n    function decimals() public view override returns (uint8) {\n        return _decimals;\n    }\n\n    function mint(address account, uint256 amount) public {\n        _mint(account, amount);\n    }\n\n    function burn(address account, uint256 amount) public {\n        _burn(account, amount);\n    }\n\n    function transferInternal(\n        address from,\n        address to,\n        uint256 value\n    ) public {\n        _transfer(from, to, value);\n    }\n\n    function approveInternal(\n        address owner,\n        address spender,\n        uint256 value\n    ) public {\n        _approve(owner, spender, value);\n    }\n}\n"
    },
    "contracts/mocks/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IERC20Uniswap {\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IWETH.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IWETH {\n    function deposit() external payable;\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function withdraw(uint256) external;\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2Factory.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Factory {\n    event PairCreated(address indexed token0, address indexed token1, address pair, uint256);\n\n    function feeTo() external view returns (address);\n\n    function feeToSetter() external view returns (address);\n\n    function migrator() external view returns (address);\n\n    function getPair(address tokenA, address tokenB) external view returns (address pair);\n\n    function allPairs(uint256) external view returns (address pair);\n\n    function allPairsLength() external view returns (uint256);\n\n    function createPair(address tokenA, address tokenB) external returns (address pair);\n\n    function setFeeTo(address) external;\n\n    function setFeeToSetter(address) external;\n\n    function setMigrator(address) external;\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2Callee.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Callee {\n    function uniswapV2Call(\n        address sender,\n        uint256 amount0,\n        uint256 amount1,\n        bytes calldata data\n    ) external;\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2Pair.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2Pair {\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external pure returns (string memory);\n\n    function symbol() external pure returns (string memory);\n\n    function decimals() external pure returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n    function nonces(address owner) external view returns (uint256);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    event Mint(address indexed sender, uint256 amount0, uint256 amount1);\n    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);\n    event Swap(\n        address indexed sender,\n        uint256 amount0In,\n        uint256 amount1In,\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address indexed to\n    );\n    event Sync(uint112 reserve0, uint112 reserve1);\n\n    function MINIMUM_LIQUIDITY() external pure returns (uint256);\n\n    function factory() external view returns (address);\n\n    function token0() external view returns (address);\n\n    function token1() external view returns (address);\n\n    function getReserves()\n        external\n        view\n        returns (\n            uint112 reserve0,\n            uint112 reserve1,\n            uint32 blockTimestampLast\n        );\n\n    function price0CumulativeLast() external view returns (uint256);\n\n    function price1CumulativeLast() external view returns (uint256);\n\n    function kLast() external view returns (uint256);\n\n    function mint(address to) external returns (uint256 liquidity);\n\n    function burn(address to) external returns (uint256 amount0, uint256 amount1);\n\n    function swap(\n        uint256 amount0Out,\n        uint256 amount1Out,\n        address to,\n        bytes calldata data\n    ) external;\n\n    function skim(address to) external;\n\n    function sync() external;\n\n    function initialize(address, address) external;\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2Router02.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\nimport \"./IUniswapV2Router01.sol\";\n\ninterface IUniswapV2Router02 is IUniswapV2Router01 {\n    function removeLiquidityETHSupportingFeeOnTransferTokens(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountETH);\n\n    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256 amountETH);\n\n    function swapExactTokensForTokensSupportingFeeOnTransferTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external;\n\n    function swapExactETHForTokensSupportingFeeOnTransferTokens(\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external payable;\n\n    function swapExactTokensForETHSupportingFeeOnTransferTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external;\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2Router01.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.2;\n\ninterface IUniswapV2Router01 {\n    function factory() external pure returns (address);\n\n    function WETH() external pure returns (address);\n\n    function addLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 amountADesired,\n        uint256 amountBDesired,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    )\n        external\n        returns (\n            uint256 amountA,\n            uint256 amountB,\n            uint256 liquidity\n        );\n\n    function addLiquidityETH(\n        address token,\n        uint256 amountTokenDesired,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    )\n        external\n        payable\n        returns (\n            uint256 amountToken,\n            uint256 amountETH,\n            uint256 liquidity\n        );\n\n    function removeLiquidity(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountA, uint256 amountB);\n\n    function removeLiquidityETH(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline\n    ) external returns (uint256 amountToken, uint256 amountETH);\n\n    function removeLiquidityWithPermit(\n        address tokenA,\n        address tokenB,\n        uint256 liquidity,\n        uint256 amountAMin,\n        uint256 amountBMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256 amountA, uint256 amountB);\n\n    function removeLiquidityETHWithPermit(\n        address token,\n        uint256 liquidity,\n        uint256 amountTokenMin,\n        uint256 amountETHMin,\n        address to,\n        uint256 deadline,\n        bool approveMax,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external returns (uint256 amountToken, uint256 amountETH);\n\n    function swapExactTokensForTokens(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    function swapTokensForExactTokens(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    function swapExactETHForTokens(\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256[] memory amounts);\n\n    function swapTokensForExactETH(\n        uint256 amountOut,\n        uint256 amountInMax,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    function swapExactTokensForETH(\n        uint256 amountIn,\n        uint256 amountOutMin,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external returns (uint256[] memory amounts);\n\n    function swapETHForExactTokens(\n        uint256 amountOut,\n        address[] calldata path,\n        address to,\n        uint256 deadline\n    ) external payable returns (uint256[] memory amounts);\n\n    function quote(\n        uint256 amountA,\n        uint256 reserveA,\n        uint256 reserveB\n    ) external pure returns (uint256 amountB);\n\n    function getAmountOut(\n        uint256 amountIn,\n        uint256 reserveIn,\n        uint256 reserveOut\n    ) external pure returns (uint256 amountOut);\n\n    function getAmountIn(\n        uint256 amountOut,\n        uint256 reserveIn,\n        uint256 reserveOut\n    ) external pure returns (uint256 amountIn);\n\n    function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);\n\n    function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);\n}\n"
    },
    "contracts/mocks/uniswapv2/libraries/TransferHelper.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.6.0;\n\n// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false\nlibrary TransferHelper {\n    function safeApprove(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('approve(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: APPROVE_FAILED\");\n    }\n\n    function safeTransfer(\n        address token,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transfer(address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FAILED\");\n    }\n\n    function safeTransferFrom(\n        address token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));\n        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"TransferHelper: TRANSFER_FROM_FAILED\");\n    }\n\n    function safeTransferETH(address to, uint256 value) internal {\n        (bool success, ) = to.call{value: value}(new bytes(0));\n        require(success, \"TransferHelper: ETH_TRANSFER_FAILED\");\n    }\n}\n"
    },
    "contracts/mocks/libraries/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.17;\n\nimport \"../interfaces/IERC20.sol\";\n\nlibrary SafeERC20 {\n    function safeSymbol(IERC20Uniswap token) internal view returns (string memory) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x95d89b41));\n        return success && data.length > 0 ? abi.decode(data, (string)) : \"???\";\n    }\n\n    function safeName(IERC20Uniswap token) internal view returns (string memory) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x06fdde03));\n        return success && data.length > 0 ? abi.decode(data, (string)) : \"???\";\n    }\n\n    function safeDecimals(IERC20Uniswap token) public view returns (uint8) {\n        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(0x313ce567));\n        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;\n    }\n\n    function safeTransfer(\n        IERC20Uniswap token,\n        address to,\n        uint256 amount\n    ) internal {\n        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(0xa9059cbb, to, amount));\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"SafeERC20: Transfer failed\");\n    }\n\n    function safeTransferFrom(\n        IERC20Uniswap token,\n        address from,\n        uint256 amount\n    ) internal {\n        (bool success, bytes memory data) = address(token).call(\n            abi.encodeWithSelector(0x23b872dd, from, address(this), amount)\n        );\n        require(success && (data.length == 0 || abi.decode(data, (bool))), \"SafeERC20: TransferFrom failed\");\n    }\n}\n"
    },
    "contracts/mocks/uniswapv2/interfaces/IUniswapV2ERC20.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.5.0;\n\ninterface IUniswapV2ERC20 {\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    function name() external pure returns (string memory);\n\n    function symbol() external pure returns (string memory);\n\n    function decimals() external pure returns (uint8);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address owner) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    ) external returns (bool);\n\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    function PERMIT_TYPEHASH() external pure returns (bytes32);\n\n    function nonces(address owner) external view returns (uint256);\n\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "viaIR": true,
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates",
          "devdoc",
          "userdoc"
        ],
        "": [
          "ast"
        ]
      }
    },
    "metadata": {
      "useLiteralContent": true
    },
    "libraries": {
      "": {
        "__CACHE_BREAKER__": "0x00000000d41867734bbee4c6863d9255b2b06ac1"
      }
    }
  }
}