Contract 0x85e66216fb0e80f87b54eb39a415c3bbd40e37f9

Contract Overview

Balance:
0 AVAX

AVAX Value:
$0.00

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0xa67186e54b8fce1a58a9a51a9f4654460224cc0c1128b7db4deadd47155afe43Level Up150216542022-05-22 8:13:0010 mins ago0xfb4cf95188bff4161d08e18cc38d4fab74c7bb08 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.004931642857 26.567486718
0x49b56f84cf1d8b3c955df8254ca99950e8a9a1c8031b28431715b7b12ca7f79eLevel Up150216482022-05-22 8:12:4811 mins ago0xfb4cf95188bff4161d08e18cc38d4fab74c7bb08 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.005395774876 26.615965689
0xa42d1701447100d82dc02340c0493ff1741f7268e8f7ea7d6e817b56451dae2fClaim150216362022-05-22 8:12:2311 mins ago0xfb4cf95188bff4161d08e18cc38d4fab74c7bb08 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.003227443423 26.717468051
0x28a4a872a399fa56ffbce90a4f8a4317ae4fef363ab6c94550eb9c973cb5b770Claim150215902022-05-22 8:10:5213 mins ago0xe9ccc645c399597de1ed6d8cfba719bdc65642a1 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0027480235 26.5
0xe8bd606131f19b8f457d409e110e966b03877a4742c05b8401e049735c1dbfd5Claim150213882022-05-22 8:04:0819 mins ago0x0e1005d91e83f41f97e9e633afe728d2ce0fd86f IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0027480235 26.5
0x1c285934c4ef507ef357b2d5b685854dbb6ab64de466decd5fc94733be54a6a0Enter150213552022-05-22 8:03:0220 mins ago0xbd68dee22c7effb1f4bb25217a06b876b10b4052 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.007009621 26.5
0xa5c00c66a76701491feadeb2d1a91ff43a12e5a4ea1c8d75dfcccea21ac8e8a6Level Up150209182022-05-22 7:48:3135 mins ago0x0fc0ebe63b74c3c90731a3cdae03c9a51b084f36 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0019027265 26.5
0x60fc5419be4c13dfae519f103272693632f12eec59193b723bb01138f7ffb797Claim150207132022-05-22 7:41:4142 mins ago0xe8e1f7299ba6cf14cead1acab154cc8c91077625 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.002682892609 26.664406703
0x9d8e5f4c6858d5852157c9c8e001a9a33aaef35da56fc4de908550cedd976429Level Up150198982022-05-22 7:14:261 hr 9 mins ago0x0eb205bf618e02f1bddce00c7d3b468b2e2f72f8 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0046800325 26.5
0x0de1f8b9c4170fe94258e2428c4b190a43971fdd0848637d79832341ffd69353Level Up150198812022-05-22 7:13:531 hr 10 mins ago0xd2ea8868b155420c324b863cdd3d309d39c96041 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.00548380731
0x73e792961cadf12a00c2ea608ba8c445df25277ea42d80563f7628d3e5e4b7ebLevel Up150198742022-05-22 7:13:361 hr 10 mins ago0xd2ea8868b155420c324b863cdd3d309d39c96041 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0058193130
0x7f0bb5138a3bcb6fafc7de2811f0e76877b03639af45fee999c51bdcd34ceebcLevel Up150197392022-05-22 7:09:071 hr 14 mins ago0x1b39f6ffda90ee592e78ef46b68a8caebfe16410 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0046872405 26.5
0x3252df1d33fccd75ec63ec38d811314c4a4758edddbc10ee120932255694e4beLevel Up150197122022-05-22 7:08:141 hr 15 mins ago0x29a9e58c8309dd6020d171cbecd0e409db43f5e8 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0018301165 26.5
0xd39c7e32c68b0db119287fe45ba31bfbb1fbdb0d850421161eacec12a4d1e83bVote150195672022-05-22 7:03:221 hr 20 mins ago0x3adf1154aa908b0252664e4b709cf4e31e5685ac IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0029683975 26.5
0x580e4fbdc8b9e1aa82cb3b1d3f39eff23bea654ea7b42ee763de6b528e27bcdaLevel Up150190252022-05-22 6:45:181 hr 38 mins ago0x3a46b61b78bb572abf33953831d663ce56b27a0d IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0019027265 26.5
0x0629610641412f3b441ddf2d3e908d530290241f41874481dd58348308bb9994Level Up150188872022-05-22 6:40:421 hr 43 mins ago0xcc914544e614d9021893f83971db6902a8ad5693 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0049201225 26.5
0x2b36ed792c5ee999cc5516be39dd48edf887074b3b6affe05fc00f8612af55c6Claim150188172022-05-22 6:38:221 hr 45 mins ago0xeaddaad6500deb6b7aea9af6b0a378cd67557e40 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0035723855 26.5
0x8e1a84e75e515a74d757af8a2dae2649135b661c3277c39eaa67cedb863dde33Level Up150184972022-05-22 6:27:391 hr 56 mins ago0x82f50cce6488f7d61741bc2ba45bc9cbf682bed1 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.00500116854 26.94
0x79ff69b94e5ab96a2edb4ffbe9c886fd5362e687d90bb99da549aba386dc4095Claim150180982022-05-22 6:14:142 hrs 9 mins ago0xabc2411db9ae3b280851aa7cf6c83082eb53ed17 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0027480235 26.5
0x3a12d7608353c8208537b75b8f932979a8fa96f13dc318352d691d90401a6ac8Claim150179162022-05-22 6:08:112 hrs 15 mins ago0x0b5ba8242e8b6350ab50f5ef2c1463b29a31d98d IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0027480235 26.5
0x4ea300ca4b7c1d8fb5cfec32b6f7efdf4dfef0fe5374016da71dd49302f9860eLevel Up150166762022-05-22 5:26:392 hrs 57 mins ago0x58c4eb6882b49167cdd0c205a7474b4edbdaf257 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.00186438226
0xf098dfd44f144d0b562f273152c442e0c4474cd334eb4129f71ac13638f8fae6Claim150166262022-05-22 5:25:042 hrs 58 mins ago0x58c4eb6882b49167cdd0c205a7474b4edbdaf257 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.00269617426
0x359ac250c6e5b97b4270e80c01386ec9fd4719a91d9ae7e3ded314950d5b14c8Level Up150164862022-05-22 5:20:243 hrs 3 mins ago0x58c4eb6882b49167cdd0c205a7474b4edbdaf257 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0048187126
0xfffebfe2d28875bc48f76c9125dcc7349be3bcbfb92b340e39b54b4bf1df1035Level Up150164762022-05-22 5:20:043 hrs 3 mins ago0x58c4eb6882b49167cdd0c205a7474b4edbdaf257 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0048187126
0x1e5f2a6c0fef4ac75f34e950abdd3af6a78aa9cdd4afdcf9780e03d918205029Claim150164442022-05-22 5:18:593 hrs 4 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x85e66216fb0e80f87b54eb39a415c3bbd40e37f90 AVAX0.0027480235 26.5
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Pond

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at snowtrace.io on 2022-03-18
*/

// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.12;

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

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

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

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

    string public name;

    string public symbol;

    uint8 public immutable decimals;

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

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

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

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

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

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

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

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

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

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

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

        return true;
    }

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

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

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

        return true;
    }

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

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

        balanceOf[from] -= amount;

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

        emit Transfer(from, to, amount);

        return true;
    }

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

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

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

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

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

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

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

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

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

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

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

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

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

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

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    event Debug(bool one, bool two, uint256 retsize);

    /*///////////////////////////////////////////////////////////////
                            ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*///////////////////////////////////////////////////////////////
                           ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (not just any non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the addition in the
                // order of operations or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
/// @dev Note that balanceOf does not revert if passed the zero address, in defiance of the ERC.
abstract contract ERC721 {
    /*///////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

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

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

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

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

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*///////////////////////////////////////////////////////////////
                            ERC721 STORAGE                        
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public balanceOf;

    mapping(uint256 => address) public ownerOf;

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

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

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*///////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            balanceOf[from]--;

            balanceOf[to]++;
        }

        ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes memory data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*///////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

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

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            balanceOf[to]++;
        }

        ownerOf[id] = to;

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

    function _burn(uint256 id) internal virtual {
        address owner = ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            balanceOf[owner]--;
        }

        delete ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
interface ERC721TokenReceiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 id,
        bytes calldata data
    ) external returns (bytes4);
}// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)



/**
 * @dev These functions deal with verification of Merkle Trees proofs.
 *
 * The proofs can be generated using the JavaScript library
 * https://github.com/miguelmota/merkletreejs[merkletreejs].
 * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
 *
 * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     *
     * _Available since v4.4._
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];
            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = _efficientHash(computedHash, proofElement);
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = _efficientHash(proofElement, computedHash);
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}
//slither-disable-next-line locked-ether
contract HopperNFT is ERC721 {
    using SafeTransferLib for address;

    address public owner;

    /*///////////////////////////////////////////////////////////////
                            IMMUTABLE STORAGE
    //////////////////////////////////////////////////////////////*/
    uint256 public immutable MAX_PER_ADDRESS;
    uint256 public immutable MAX_SUPPLY;
    uint256 public immutable MINT_COST;
    uint256 public immutable WL_MINT_COST;
    uint256 public immutable LEGENDARY_ID_START;

    /*///////////////////////////////////////////////////////////////
                              SALE DETAILS
    //////////////////////////////////////////////////////////////*/

    uint256 public reserved;
    uint256 public preSaleOpenTime;
    bytes32 public freeMerkleRoot;
    bytes32 public wlMerkleRoot;
    mapping(address => uint256) public freeRedeemed;
    mapping(address => uint256) public wlRedeemed;

    /*///////////////////////////////////////////////////////////////
                                HOPPERS
    //////////////////////////////////////////////////////////////*/

    struct Hopper {
        uint200 level; // capped by zone
        uint16 rebirths;
        uint8 strength;
        uint8 agility;
        uint8 vitality;
        uint8 intelligence;
        uint8 fertility;
    }

    mapping(uint256 => Hopper) public hoppers;
    uint256 public hoppersLength;
    uint256 public hopperMaxAttributeValue;

    mapping(uint256 => uint256) public indexer;

    string public baseURI;
    string public imageURL;

    /*///////////////////////////////////////////////////////////////
                             
    //////////////////////////////////////////////////////////////*/

    // whitelist for leveling up
    mapping(address => bool) public zones;

    // unlabeled data [key -> tokenid -> data] for potential future zones
    mapping(string => mapping(uint256 => bytes32)) public unlabeledData;

    // unlabeled data [key -> data] for potential future zones
    mapping(string => bytes32) public unlabeledGlobalData;

    /*///////////////////////////////////////////////////////////////
                            HOPPER NAMES
    //////////////////////////////////////////////////////////////*/

    uint256 public nameFee;
    mapping(bytes32 => bool) public takenNames;
    mapping(uint256 => string) public hoppersNames;

    /*///////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed newOwner);
    event LevelUp(uint256 tokenId);
    event NameChange(uint256 tokenId);
    event UpdatedNameFee(uint256 namefee);
    event Rebirth(uint256 tokenId);
    event UnlabeledData(string key, uint256 tokenId);

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error MintLimit();
    error InsufficientAmount();
    error Unauthorized();
    error InvalidTokenID();
    error MaxLength25();
    error OnlyEOAAllowed();
    error NameTaken();
    error OnlyLvL100();
    error TooSoon();
    error ReservedAmountInvalid();
    error OnlyAlphanumeric();

    constructor(
        string memory _NFT_NAME,
        string memory _NFT_SYMBOL,
        uint256 _NAME_FEE
    ) ERC721(_NFT_NAME, _NFT_SYMBOL) {
        owner = msg.sender;

        MINT_COST = 1.75 ether;
        WL_MINT_COST = 1.2 ether;
        MAX_SUPPLY = 10_000;
        MAX_PER_ADDRESS = 10;
        LEGENDARY_ID_START = 9968;

        nameFee = _NAME_FEE;
        hopperMaxAttributeValue = 10;

        unchecked {
            preSaleOpenTime = type(uint256).max - 30 minutes;
        }
    }

    /*///////////////////////////////////////////////////////////////
                    CONTRACT MANAGEMENT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    modifier onlyOwner() {
        if (msg.sender != owner) revert Unauthorized();
        _;
    }

    modifier onlyZone() {
        if (!zones[msg.sender]) revert Unauthorized();
        _;
    }

    modifier onlyOwnerOrZone() {
        if (msg.sender != owner && !zones[msg.sender]) revert Unauthorized();
        _;
    }

    function setOwner(address newOwner) external onlyOwner {
        //slither-disable-next-line missing-zero-check
        owner = newOwner;
        emit OwnerUpdated(newOwner);
    }

    function setHopperMaxAttributeValue(uint256 _hopperMaxAttributeValue)
        external
        onlyOwner
    {
        hopperMaxAttributeValue = _hopperMaxAttributeValue;
    }

    function setNameChangeFee(uint256 _nameFee) external onlyOwner {
        nameFee = _nameFee;
        emit UpdatedNameFee(_nameFee);
    }

    function setBaseURI(string calldata _baseURI) external onlyOwner {
        baseURI = _baseURI;
    }

    function setImageURL(string calldata _imageURL) external onlyOwner {
        imageURL = _imageURL;
    }

    function setSaleDetails(
        uint256 _preSaleOpenTime,
        bytes32 _wlMerkleRoot,
        bytes32 _freeMerkleRoot,
        uint256 _reserved
    ) external onlyOwner {
        preSaleOpenTime = _preSaleOpenTime;

        freeMerkleRoot = _freeMerkleRoot;
        wlMerkleRoot = _wlMerkleRoot;

        reserved = _reserved;
    }

    function withdraw() external onlyOwner {
        owner.safeTransferETH(address(this).balance);
    }

    /*///////////////////////////////////////////////////////////////
                    HOPPER VALID ZONES/ADVENTURES
    //////////////////////////////////////////////////////////////*/

    function addZones(address[] calldata _zones) external onlyOwner {
        uint256 length = _zones.length;
        for (uint256 i; i < length; ) {
            zones[_zones[i]] = true;
            unchecked {
                ++i;
            }
        }
    }

    function removeZone(address _zone) external onlyOwner {
        delete zones[_zone];
    }

    /*///////////////////////////////////////////////////////////////
                            Unlabeled Data
    //////////////////////////////////////////////////////////////*/

    function setGlobalData(string calldata _key, bytes32 _data)
        external
        onlyOwnerOrZone
    {
        unlabeledGlobalData[_key] = _data;
    }

    function unsetGlobalData(string calldata _key) external onlyOwnerOrZone {
        delete unlabeledGlobalData[_key];
    }

    function getGlobalData(string calldata _key)
        external
        view
        returns (bytes32)
    {
        return unlabeledGlobalData[_key];
    }

    function setData(
        string calldata _key,
        uint256 _tokenId,
        bytes32 _data
    ) external onlyOwnerOrZone {
        unlabeledData[_key][_tokenId] = _data;

        emit UnlabeledData(_key, _tokenId);
    }

    function unsetData(string calldata _key, uint256 _tokenId)
        external
        onlyOwnerOrZone
    {
        delete unlabeledData[_key][_tokenId];
    }

    function getData(string calldata _key, uint256 _tokenId)
        external
        view
        returns (bytes32)
    {
        return unlabeledData[_key][_tokenId];
    }

    function getHopperWithData(string[] calldata _keys, uint256 _tokenId)
        external
        view
        returns (Hopper memory hopper, bytes32[] memory arrData)
    {
        hopper = hoppers[_tokenId];

        uint256 length = _keys.length;
        arrData = new bytes32[](length);

        for (uint256 i; i < length; ) {
            arrData[i] = unlabeledData[_keys[i]][_tokenId];
            unchecked {
                ++i;
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                        HOPPER LEVEL SYSTEM
    //////////////////////////////////////////////////////////////*/

    function rebirth(uint256 _tokenId) external {
        Hopper memory hopper = hoppers[_tokenId];

        if (ownerOf[_tokenId] != msg.sender) revert Unauthorized();
        if (hopper.level < 100) revert OnlyLvL100();

        uint256 _hopperMaxAttributeValue = hopperMaxAttributeValue;

        unchecked {
            if (hopper.strength < _hopperMaxAttributeValue) {
                hoppers[_tokenId].strength = uint8(hopper.strength + 1);
            }

            if (hopper.intelligence < _hopperMaxAttributeValue) {
                hoppers[_tokenId].intelligence = uint8(hopper.intelligence + 1);
            }

            if (hopper.agility < _hopperMaxAttributeValue) {
                hoppers[_tokenId].agility = uint8(hopper.agility + 1);
            }

            if (hopper.vitality < _hopperMaxAttributeValue) {
                hoppers[_tokenId].vitality = uint8(hopper.vitality + 1);
            }

            if (hopper.fertility < _hopperMaxAttributeValue) {
                hoppers[_tokenId].fertility = uint8(hopper.fertility + 1);
            }

            ++hoppers[_tokenId].rebirths;
        }

        hoppers[_tokenId].level = 1;

        delete unlabeledData["LEVEL_GAUGE_KEY"][_tokenId];

        emit Rebirth(_tokenId);
    }

    function levelUp(uint256 tokenId) external onlyZone {
        // max level is checked on zone
        unchecked {
            ++(hoppers[tokenId].level);
        }
        emit LevelUp(tokenId);
    }

    function changeHopperName(uint256 tokenId, string calldata _newName)
        external
        onlyZone
        returns (uint256)
    {
        bytes memory newName = bytes(_newName);
        uint256 newLength = newName.length;

        if (newLength > 25) revert MaxLength25();

        // Checks it's only alphanumeric characters
        for (uint256 i; i < newLength; ) {
            bytes1 char = newName[i];

            if (
                !(char >= 0x30 && char <= 0x39) && //9-0
                !(char >= 0x41 && char <= 0x5A) && //A-Z
                !(char >= 0x61 && char <= 0x7A) && //a-z
                !(char == 0x2E) //.
            ) {
                revert OnlyAlphanumeric();
            }
            unchecked {
                ++i;
            }
        }

        // Checks new name uniqueness
        bytes32 nameHash = keccak256(newName);
        if (takenNames[nameHash]) revert NameTaken();

        // Free previous name
        takenNames[keccak256(bytes(hoppersNames[tokenId]))] = false;

        // Reserve name
        takenNames[nameHash] = true;
        hoppersNames[tokenId] = _newName;

        emit NameChange(tokenId);

        return nameFee;
    }

    /*///////////////////////////////////////////////////////////////
                          HOPPER GENERATION
    //////////////////////////////////////////////////////////////*/

    function enoughRandom() internal view returns (uint256) {
        return
            uint256(
                keccak256(
                    abi.encodePacked(
                        // solhint-disable-next-line
                        block.timestamp,
                        msg.sender,
                        blockhash(block.number)
                    )
                )
            );
    }

    //slither-disable-next-line weak-prng
    function generate(
        uint256 seed,
        uint256 minAttributeValue,
        uint256 randCap
    ) internal pure returns (Hopper memory) {
        unchecked {
            return
                Hopper({
                    strength: uint8(
                        ((seed >> (8 * 1)) % randCap) + minAttributeValue
                    ),
                    agility: uint8(
                        ((seed >> (8 * 2)) % randCap) + minAttributeValue
                    ),
                    vitality: uint8(
                        ((seed >> (8 * 3)) % randCap) + minAttributeValue
                    ),
                    intelligence: uint8(
                        ((seed >> (8 * 4)) % randCap) + minAttributeValue
                    ),
                    fertility: uint8(
                        ((seed >> (8 * 5)) % randCap) + minAttributeValue
                    ),
                    level: 1,
                    rebirths: 0
                });
        }
    }

    function _mintHoppers(uint256 numberOfMints, uint256 preTotalHoppers)
        internal
    {
        uint256 seed = enoughRandom();

        uint256 _indexerLength;
        unchecked {
            _indexerLength = MAX_SUPPLY - preTotalHoppers;
        }

        for (uint256 i; i < numberOfMints; ) {
            seed >>= i;

            // Find the next available tokenID
            //slither-disable-next-line weak-prng
            uint256 index = seed % _indexerLength;
            uint256 tokenId = indexer[index];

            if (tokenId == 0) {
                tokenId = index;
            }

            // Swap the picked tokenId for the last element
            unchecked {
                --_indexerLength;
            }

            uint256 last = indexer[_indexerLength];
            if (last == 0) {
                // this _indexerLength value had not been picked before
                indexer[index] = _indexerLength;
            } else {
                // this _indexerLength value had been picked and swapped before
                indexer[index] = last;
            }

            // Mint Hopper and generate its attributes
            _mint(msg.sender, tokenId);

            if (tokenId >= LEGENDARY_ID_START) {
                hoppers[tokenId] = generate(seed, 5, 6);
            } else {
                hoppers[tokenId] = generate(seed, 1, 10);
            }
            unchecked {
                ++i;
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                            HOPPER MINTING
    //////////////////////////////////////////////////////////////*/

    function _handleMint(uint256 numberOfMints) internal {
        // solhint-disable-next-line
        if (msg.sender != tx.origin) revert OnlyEOAAllowed();

        unchecked {
            uint256 totalHoppers = hoppersLength + numberOfMints;

            if (
                numberOfMints > MAX_PER_ADDRESS ||
                totalHoppers > (MAX_SUPPLY - reserved)
            ) revert MintLimit();

            _mintHoppers(numberOfMints, totalHoppers - numberOfMints);
            hoppersLength = totalHoppers;
        }
    }

    function freeMint(
        uint256 numberOfMints,
        uint256 totalGiven,
        bytes32[] memory proof
    ) external {
        unchecked {
            if (block.timestamp < preSaleOpenTime + 30 minutes)
                revert TooSoon();
        }

        if (freeRedeemed[msg.sender] + numberOfMints > totalGiven)
            revert Unauthorized();
        if (reserved < numberOfMints) revert ReservedAmountInvalid();

        if (
            !MerkleProof.verify(
                proof,
                freeMerkleRoot,
                keccak256(abi.encodePacked(msg.sender, totalGiven))
            )
        ) revert Unauthorized();

        unchecked {
            freeRedeemed[msg.sender] += numberOfMints;
            reserved -= numberOfMints;
        }

        _handleMint(numberOfMints);
    }

    function whitelistMint(bytes32[] memory proof) external payable {
        if (wlRedeemed[msg.sender] == 1) revert Unauthorized();
        if (block.timestamp < preSaleOpenTime) revert TooSoon();
        if (WL_MINT_COST > msg.value) revert InsufficientAmount();

        if (
            !MerkleProof.verify(
                proof,
                wlMerkleRoot,
                keccak256(abi.encodePacked(msg.sender))
            )
        ) revert Unauthorized();

        wlRedeemed[msg.sender] = 1;

        _handleMint(1);
    }

    function normalMint(uint256 numberOfMints) external payable {
        unchecked {
            if (block.timestamp < preSaleOpenTime + 30 minutes)
                revert TooSoon();
        }
        if (MINT_COST * numberOfMints > msg.value) revert InsufficientAmount();

        _handleMint(numberOfMints);
    }

    /*///////////////////////////////////////////////////////////////
                          HOPPER VIEW FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function getHopper(uint256 tokenId) external view returns (Hopper memory) {
        return hoppers[tokenId];
    }

    function getHopperName(uint256 tokenId)
        public
        view
        returns (string memory name)
    {
        name = hoppersNames[tokenId];

        if (bytes(name).length == 0) {
            name = string(bytes.concat("hopper #", bytes(_toString(tokenId))));
        }
    }

    function _getTraits(Hopper memory hopper)
        internal
        pure
        returns (string memory)
    {
        return
            string(
                bytes.concat(
                    '{"trait_type": "rebirths", "value": ',
                    bytes(_toString(hopper.rebirths)),
                    "},",
                    '{"trait_type": "strength", "value": ',
                    bytes(_toString(hopper.strength)),
                    "},",
                    '{"trait_type": "agility", "value": ',
                    bytes(_toString(hopper.agility)),
                    "},",
                    '{"trait_type": "vitality", "value": ',
                    bytes(_toString(hopper.vitality)),
                    "},",
                    '{"trait_type": "intelligence", "value": ',
                    bytes(_toString(hopper.intelligence)),
                    "},",
                    '{"trait_type": "fertility", "value": ',
                    bytes(_toString(hopper.fertility)),
                    "}"
                )
            );
    }

    function _jsonString(uint256 tokenId)
        external
        view
        returns (string memory)
    {
        Hopper memory hopper = hoppers[tokenId];

        //slither-disable-next-line incorrect-equality
        if (hopper.level == 0) revert InvalidTokenID();

        return
            string(
                bytes.concat(
                    '{"name":"',
                    bytes(getHopperName(tokenId)),
                    '", "description":"Hopper", "attributes":[',
                    '{"trait_type": "level", "value": ',
                    bytes(_toString(hopper.level)),
                    "},",
                    bytes(_getTraits(hopper)),
                    "],",
                    '"image":"',
                    bytes(imageURL),
                    bytes(_toString(tokenId)),
                    '.png"}'
                )
            );
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        //slither-disable-next-line incorrect-equality
        if (hoppers[tokenId].level == 0) revert InvalidTokenID();

        return string(bytes.concat(bytes(baseURI), bytes(_toString(tokenId))));
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function _toString(uint256 value) internal pure returns (string memory) {
        //slither-disable-next-line incorrect-equality
        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            //slither-disable-next-line weak-prng
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}
contract Fly is ERC20 {
    address public owner;

    // whitelist for minting mechanisms
    mapping(address => bool) public zones;

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/

    error Unauthorized();

    /*///////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed newOwner);

    constructor(string memory _NAME, string memory _SYMBOL)
        ERC20(_NAME, _SYMBOL, 18)
    {
        owner = msg.sender;
    }

    /*///////////////////////////////////////////////////////////////
                    CONTRACT MANAGEMENT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    modifier onlyOwner() {
        if (msg.sender != owner) revert Unauthorized();
        _;
    }

    function setOwner(address newOwner) external onlyOwner {
        //slither-disable-next-line missing-zero-check
        owner = newOwner;
        emit OwnerUpdated(newOwner);
    }

    /*///////////////////////////////////////////////////////////////
                            Zones - can mint
    //////////////////////////////////////////////////////////////*/

    modifier onlyZone() {
        if (!zones[msg.sender]) revert Unauthorized();
        _;
    }

    function addZones(address[] calldata _zones) external onlyOwner {
        uint256 length = _zones.length;
        for (uint256 i; i < length; ) {
            zones[_zones[i]] = true;
            unchecked {
                ++i;
            }
        }
    }

    function removeZone(address zone) external onlyOwner {
        delete zones[zone];
    }

    /*///////////////////////////////////////////////////////////////
                                MINT / BURN
    //////////////////////////////////////////////////////////////*/

    function mint(address receiver, uint256 amount) external onlyZone {
        _mint(receiver, amount);
    }

    function burn(address from, uint256 amount) external onlyZone {
        _burn(from, amount);
    }
}contract Ballot {
    address public owner;

    /*///////////////////////////////////////////////////////////////
                            IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    address public immutable VEFLY;
    address public immutable FLY;

    /*///////////////////////////////////////////////////////////////
                              ZONES
    //////////////////////////////////////////////////////////////*/

    address[] public arrZones;
    mapping(address => bool) public zones;
    mapping(address => uint256) public zonesVotes;

    mapping(address => mapping(address => uint256)) public zonesUserVotes;
    mapping(address => uint256) public userVeFlyUsed;

    /*///////////////////////////////////////////////////////////////
                              EMISSIONS
    //////////////////////////////////////////////////////////////*/

    uint256 public bonusEmissionRate;
    uint256 public rewardSnapshot;
    uint256 public countRewardRate;

    /*///////////////////////////////////////////////////////////////
                              EVENTS
    //////////////////////////////////////////////////////////////*/

    event UpdatedOwner(address indexed owner);

    /*///////////////////////////////////////////////////////////////
                              ERRORS
    //////////////////////////////////////////////////////////////*/

    error Unauthorized();
    error TooSoon();
    error NotEnoughVeFly();

    /*///////////////////////////////////////////////////////////////
                            CONTRACT MANAGEMENT
    //////////////////////////////////////////////////////////////*/

    constructor(address _flyAddress, address _veFlyAddress) {
        owner = msg.sender;
        rewardSnapshot = type(uint256).max;
        FLY = _flyAddress;
        VEFLY = _veFlyAddress;
    }

    modifier onlyOwner() {
        if (owner != msg.sender) revert Unauthorized();
        _;
    }

    function setOwner(address _owner) external onlyOwner {
        owner = _owner;
        emit UpdatedOwner(_owner);
    }

    function openBallot(uint256 _countRewardRate, uint256 _bonusEmissionRate)
        external
        onlyOwner
    {
        rewardSnapshot = block.timestamp;
        countRewardRate = _countRewardRate;
        bonusEmissionRate = _bonusEmissionRate;
    }

    function closeBallot() external onlyOwner {
        rewardSnapshot = type(uint256).max;
    }

    function setBonusEmissionRate(uint256 _bonusEmissionRate)
        external
        onlyOwner
    {
        bonusEmissionRate = _bonusEmissionRate;
    }

    function setCountRewardRate(uint256 _countRewardRate) external onlyOwner {
        countRewardRate = _countRewardRate;
    }

    /*///////////////////////////////////////////////////////////////
                                ZONES
    //////////////////////////////////////////////////////////////*/

    modifier onlyZone() {
        if (!zones[msg.sender]) revert Unauthorized();
        _;
    }

    function addZones(address[] calldata _zones) external onlyOwner {
        uint256 length = _zones.length;
        for (uint256 i; i < length; ) {
            address zone = _zones[i];
            arrZones.push(zone);
            zones[zone] = true;
            unchecked {
                ++i;
            }
        }
    }

    function removeZone(uint256 index) external onlyOwner {
        address removed = arrZones[index];
        arrZones[index] = arrZones[arrZones.length - 1];
        arrZones.pop();
        delete zones[removed];
    }

    /*///////////////////////////////////////////////////////////////
                            VOTING
    //////////////////////////////////////////////////////////////*/

    //slither-disable-next-line costly-loop
    function forceUnvote(address _user) external {
        if (msg.sender != VEFLY) revert Unauthorized();

        uint256 length = arrZones.length;

        for (uint256 i; i < length; ) {
            address zone = arrZones[i];

            uint256 zoneUserVotes = zonesUserVotes[zone][_user];

            if (zoneUserVotes > 0) {
                zonesVotes[zone] -= zoneUserVotes;
                delete userVeFlyUsed[_user];
                delete zonesUserVotes[zone][_user];

                // Done already by veFly on its _forceUncastAllVotes
                // veFly(VEFLY).unsetHasVoted(user)

                Zone(zone).forceUnvote(_user);
            }
            unchecked {
                ++i;
            }
        }
    }

    function _updateVotes(address user, uint256 vefly) internal {
        zonesVotes[msg.sender] =
            zonesVotes[msg.sender] +
            vefly -
            zonesUserVotes[msg.sender][user];

        zonesUserVotes[msg.sender][user] = vefly;
    }

    function vote(address user, uint256 vefly) external onlyZone {
        // veFly Accounting
        uint256 totalVeFly = userVeFlyUsed[user] + vefly;

        if (totalVeFly > veFly(VEFLY).balanceOf(user)) revert NotEnoughVeFly();

        if (vefly > 0) {
            userVeFlyUsed[user] = totalVeFly;

            unchecked {
                _updateVotes(user, zonesUserVotes[msg.sender][user] + vefly);
            }

            // First time he has voted
            if (totalVeFly == vefly) {
                veFly(VEFLY).setHasVoted(user);
            }
        }
    }

    function unvote(address user, uint256 vefly) external onlyZone {
        // veFly Accounting
        uint256 _userVeFlyUsed = userVeFlyUsed[user];
        if (_userVeFlyUsed < vefly) revert NotEnoughVeFly();

        uint256 remainingVeFly;
        unchecked {
            remainingVeFly = _userVeFlyUsed - vefly;
        }

        userVeFlyUsed[user] = remainingVeFly;

        uint256 zoneUserVotes = zonesUserVotes[msg.sender][user];

        if (zoneUserVotes < vefly) revert NotEnoughVeFly();

        unchecked {
            _updateVotes(user, zoneUserVotes - vefly);
        }

        if (remainingVeFly == 0) veFly(VEFLY).unsetHasVoted(user);
    }

    /*///////////////////////////////////////////////////////////////
                            COUNTING
    //////////////////////////////////////////////////////////////*/

    function countReward() public view returns (uint256) {
        uint256 _rewardSnapshot = rewardSnapshot;

        if (block.timestamp < _rewardSnapshot) return 0;

        return countRewardRate * (block.timestamp - _rewardSnapshot);
    }

    function count() external {
        uint256 reward = countReward();
        rewardSnapshot = block.timestamp;

        uint256 totalVotes;
        address[] memory _arrZones = arrZones;
        uint256 length = _arrZones.length;

        for (uint256 i; i < length; ) {
            unchecked {
                totalVotes += zonesVotes[_arrZones[i]];
                ++i;
            }
        }

        for (uint256 i; i < length; ) {
            if (totalVotes == 0) {
                Zone(_arrZones[i]).setBonusEmissionRate(0);
            } else {
                Zone(_arrZones[i]).setBonusEmissionRate(
                    (bonusEmissionRate * zonesVotes[_arrZones[i]]) / totalVotes
                );
            }
            unchecked {
                ++i;
            }
        }

        if (reward > 0) {
            // solhint-disable-next-line avoid-tx-origin
            Fly(FLY).mint(tx.origin, reward);
        }
    }
}
// solhint-disable-next-line
contract veFly {
    /*///////////////////////////////////////////////////////////////
                             METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    // solhint-disable-next-line const-name-snakecase
    string public constant name = "veFLY";
    // solhint-disable-next-line const-name-snakecase
    string public constant symbol = "veFLY";

    address public immutable FLY;

    /*///////////////////////////////////////////////////////////////
                           FLY/VEFLY GENERATION
    //////////////////////////////////////////////////////////////*/

    struct GenerationDetails {
        uint128 maxRatio;
        uint64 generationRateNumerator;
        uint64 generationRateDenominator;
    }

    GenerationDetails public genDetails;

    mapping(address => uint256) public flyBalanceOf;
    mapping(address => uint256) private veFlyBalance;
    mapping(address => uint256) private userSnapshot;

    /*///////////////////////////////////////////////////////////////
                              VOTING
    //////////////////////////////////////////////////////////////*/

    address[] public arrValidBallots;
    mapping(address => bool) public validBallots;
    mapping(address => mapping(address => bool)) public hasUserVoted;

    /*///////////////////////////////////////////////////////////////
                              ERRORS
    //////////////////////////////////////////////////////////////*/
    error Unauthorized();
    error InvalidAmount();
    error InvalidProposal();

    /*///////////////////////////////////////////////////////////////
                              EVENTS
    //////////////////////////////////////////////////////////////*/
    event UpdatedOwner(address indexed owner);
    event AddedBallot(address indexed ballot);
    event RemovedBallot(address indexed ballot);

    /*///////////////////////////////////////////////////////////////
                            CONTRACT MANAGEMENT
    //////////////////////////////////////////////////////////////*/

    constructor(
        address _flyAddress,
        uint256 _generationRateNumerator,
        uint256 _generationRateDenominator,
        uint256 _maxRatio
    ) {
        owner = msg.sender;

        FLY = _flyAddress;

        genDetails = GenerationDetails({
            maxRatio: uint128(_maxRatio),
            generationRateNumerator: uint64(_generationRateNumerator),
            generationRateDenominator: uint64(_generationRateDenominator)
        });
    }

    modifier onlyOwner() {
        if (owner != msg.sender) revert Unauthorized();
        _;
    }

    function setOwner(address _owner) external onlyOwner {
        owner = _owner;
        emit UpdatedOwner(_owner);
    }

    function setGenerationDetails(
        uint256 _maxRatio,
        uint256 _generationRateNumerator,
        uint256 _generationRateDenominator
    ) external onlyOwner {
        GenerationDetails storage gen = genDetails;
        gen.maxRatio = uint128(_maxRatio);
        gen.generationRateNumerator = uint64(_generationRateNumerator);
        gen.generationRateDenominator = uint64(_generationRateDenominator);
    }

    /*///////////////////////////////////////////////////////////////
                               BALLOTS
    //////////////////////////////////////////////////////////////*/

    modifier onlyBallot() {
        if (!validBallots[msg.sender]) revert Unauthorized();
        _;
    }

    function addBallot(address ballot) external onlyOwner {
        if (!validBallots[ballot]) {
            arrValidBallots.push(ballot);
            validBallots[ballot] = true;
            emit AddedBallot(ballot);
        }
    }

    function removeBallot(uint256 index) external onlyOwner {
        address removed = arrValidBallots[index];

        arrValidBallots[index] = arrValidBallots[arrValidBallots.length - 1];
        arrValidBallots.pop();

        delete validBallots[removed];

        emit RemovedBallot(removed);
    }

    function _forceUncastAllVotes() internal {
        uint256 length = arrValidBallots.length;
        for (uint256 i; i < length; ) {
            address ballot = arrValidBallots[i];
            delete hasUserVoted[ballot][msg.sender];

            Ballot(ballot).forceUnvote(msg.sender);
            unchecked {
                ++i;
            }
        }
    }

    function setHasVoted(address user) external onlyBallot {
        hasUserVoted[msg.sender][user] = true;
    }

    function unsetHasVoted(address user) external onlyBallot {
        delete hasUserVoted[msg.sender][user];
    }

    /*///////////////////////////////////////////////////////////////
                               STAKING
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 amount) external {
        //slither-disable-next-line incorrect-equality
        if (genDetails.maxRatio == 0) revert Unauthorized();

        // Reset veFly calculations
        veFlyBalance[msg.sender] = balanceOf(msg.sender);
        userSnapshot[msg.sender] = block.timestamp;

        unchecked {
            flyBalanceOf[msg.sender] += amount;
        }

        // slither-disable-next-line unchecked-transfer
        Fly(FLY).transferFrom(msg.sender, address(this), amount);
    }

    function withdraw(uint256 amount) external {
        if (flyBalanceOf[msg.sender] < amount) revert InvalidAmount();

        // Reset veFly calculations
        delete veFlyBalance[msg.sender];
        userSnapshot[msg.sender] = block.timestamp;

        unchecked {
            flyBalanceOf[msg.sender] -= amount;
        }

        _forceUncastAllVotes();

        // slither-disable-next-line unchecked-transfer
        Fly(FLY).transfer(msg.sender, amount);
    }

    /*///////////////////////////////////////////////////////////////
                               veFly
    //////////////////////////////////////////////////////////////*/

    function balanceOf(address account) public view returns (uint256) {
        GenerationDetails memory gen = genDetails;

        uint256 flyBalance = flyBalanceOf[account];

        uint256 veBalance = veFlyBalance[account] +
            ((flyBalance * gen.generationRateNumerator) *
                (block.timestamp - userSnapshot[account])) /
            gen.generationRateDenominator;

        uint256 maxVe = gen.maxRatio * flyBalance;
        if (veBalance > maxVe) {
            return maxVe;
        } else {
            return veBalance;
        }
    }

    function hasUserVotedAny(address account) external view returns (bool) {
        uint256 length = arrValidBallots.length;
        for (uint256 i; i < length; ) {
            if (hasUserVoted[arrValidBallots[i]][account]) return false;
            unchecked {
                ++i;
            }
        }
        return true;
    }
}/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*///////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*///////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            // Start off with z at 1.
            z := 1

            // Used below to help find a nearby power of 2.
            let y := x

            // Find the lowest power of 2 that is at least sqrt(x).
            if iszero(lt(y, 0x100000000000000000000000000000000)) {
                y := shr(128, y) // Like dividing by 2 ** 128.
                z := shl(64, z) // Like multiplying by 2 ** 64.
            }
            if iszero(lt(y, 0x10000000000000000)) {
                y := shr(64, y) // Like dividing by 2 ** 64.
                z := shl(32, z) // Like multiplying by 2 ** 32.
            }
            if iszero(lt(y, 0x100000000)) {
                y := shr(32, y) // Like dividing by 2 ** 32.
                z := shl(16, z) // Like multiplying by 2 ** 16.
            }
            if iszero(lt(y, 0x10000)) {
                y := shr(16, y) // Like dividing by 2 ** 16.
                z := shl(8, z) // Like multiplying by 2 ** 8.
            }
            if iszero(lt(y, 0x100)) {
                y := shr(8, y) // Like dividing by 2 ** 8.
                z := shl(4, z) // Like multiplying by 2 ** 4.
            }
            if iszero(lt(y, 0x10)) {
                y := shr(4, y) // Like dividing by 2 ** 4.
                z := shl(2, z) // Like multiplying by 2 ** 2.
            }
            if iszero(lt(y, 0x8)) {
                // Equivalent to 2 ** z.
                z := shl(1, z)
            }

            // Shifting right by 1 is like dividing by 2.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // Compute a rounded down version of z.
            let zRoundDown := div(x, z)

            // If zRoundDown is smaller, use it.
            if lt(zRoundDown, z) {
                z := zRoundDown
            }
        }
    }
}
abstract contract Zone {
    /*///////////////////////////////////////////////////////////////
                            IMMUTABLE STORAGE
    //////////////////////////////////////////////////////////////*/
    address public immutable FLY;
    address public immutable VE_FLY;
    address public immutable HOPPER;

    /*///////////////////////////////////////////////////////////////
                                HOPPERS
    //////////////////////////////////////////////////////////////*/
    string public LEVEL_GAUGE_KEY;

    mapping(uint256 => address) public hopperOwners;
    mapping(uint256 => uint256) public hopperBaseShare;
    mapping(address => uint256) public rewards;

    address public owner;
    address public ballot;
    bool public emergency;

    /*///////////////////////////////////////////////////////////////
                        Accounting/Rewards NFT
    //////////////////////////////////////////////////////////////*/
    uint256 public emissionRate;

    uint256 public totalBaseShare;
    uint256 public lastUpdatedTime;
    uint256 public rewardPerShareStored;

    mapping(address => uint256) public baseSharesBalance;
    mapping(address => uint256) public userRewardPerSharePaid;
    mapping(address => uint256) public userMaxFlyGeneration;

    mapping(address => uint256) public generatedPerShareStored;
    mapping(uint256 => uint256) public tokenCapFilledPerShare;

    uint256 public flyLevelCapRatio;

    /*///////////////////////////////////////////////////////////////
                        Accounting/Rewards veFLY
    //////////////////////////////////////////////////////////////*/
    uint256 public bonusEmissionRate;

    uint256 public totalVeShare;
    uint256 public lastBonusUpdatedTime;
    uint256 public bonusRewardPerShareStored;

    mapping(address => uint256) public veSharesBalance;
    mapping(address => uint256) public userBonusRewardPerSharePaid;
    mapping(address => uint256) public veFlyBalance;

    /*///////////////////////////////////////////////////////////////
                                ERRORS
    //////////////////////////////////////////////////////////////*/
    error Unauthorized();
    error UnfitHopper();
    error WrongTokenID();
    error NoHopperStaked();

    /*///////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event UpdatedOwner(address indexed owner);
    event UpdatedBallot(address indexed ballot);
    event UpdatedEmission(uint256 emissionRate);

    /*///////////////////////////////////////////////////////////////
                           CONTRACT MANAGEMENT
    //////////////////////////////////////////////////////////////*/
    constructor(
        address fly,
        address vefly,
        address hopper
    ) {
        owner = msg.sender;

        FLY = fly;
        VE_FLY = vefly;
        HOPPER = hopper;

        flyLevelCapRatio = 3;
        LEVEL_GAUGE_KEY = "LEVEL_GAUGE_KEY";
        lastUpdatedTime = block.timestamp;
        lastBonusUpdatedTime = block.timestamp;
    }

    modifier onlyOwner() {
        if (msg.sender != owner) revert Unauthorized();
        _;
    }

    modifier onlyBallotOrOwner() {
        if (msg.sender != owner && msg.sender != ballot) revert Unauthorized();
        _;
    }

    function setOwner(address _owner) external onlyOwner {
        owner = _owner;
        emit UpdatedOwner(_owner);
    }

    function enableEmergency() external onlyOwner {
        // no going back
        emergency = true;
    }

    function setBallot(address _ballot) external onlyOwner {
        ballot = _ballot;
        emit UpdatedBallot(_ballot);
    }

    function setEmissionRate(uint256 _emissionRate) external onlyOwner {
        _updateBaseRewardPerShareStored();

        emissionRate = _emissionRate;
        emit UpdatedEmission(_emissionRate);
    }

    function setBonusEmissionRate(uint256 _bonusEmissionRate)
        external
        onlyBallotOrOwner
    {
        _updateBonusRewardPerShareStored();

        bonusEmissionRate = _bonusEmissionRate;
    }

    function setFlyLevelCapRatio(uint256 _flyLevelCapRatio) external onlyOwner {
        flyLevelCapRatio = _flyLevelCapRatio;
    }

    /*///////////////////////////////////////////////////////////////
                        HOPPER GENERATION CAP
    //////////////////////////////////////////////////////////////*/

    function getUserBonusGeneratedFly(
        address account,
        uint256 _totalUserBonusShares
    ) public view returns (uint256, uint256) {
        // userMaxFlyGeneration gets updated at _updateAccountBaseReward which happens before this is called
        uint256 cappedFly = userMaxFlyGeneration[account] / 1e12;
        uint256 generatedFly = ((_totalUserBonusShares *
            (bonusRewardPerShare() - userBonusRewardPerSharePaid[account])) /
            1e18);

        return (
            generatedFly > cappedFly ? cappedFly : generatedFly,
            generatedFly
        );
    }

    function getUserGeneratedFly(address account, uint256 _totalUserBaseShares)
        public
        view
        returns (uint256, uint256)
    {
        uint256 cappedFly = userMaxFlyGeneration[account] / 1e12;
        uint256 generatedFly = ((_totalUserBaseShares *
            (baseRewardPerShare() - userRewardPerSharePaid[account])) / 1e18);

        return (
            generatedFly > cappedFly ? cappedFly : generatedFly,
            generatedFly
        );
    }

    function _updateHopperGenerationData(
        address _account,
        uint256 _totalAccountKindShares,
        bool isBonus
    ) internal returns (uint256) {
        uint256 cappedFly;
        uint256 generatedFly;

        if (isBonus) {
            (cappedFly, generatedFly) = getUserBonusGeneratedFly(
                _account,
                _totalAccountKindShares
            );

            // Makes calculations easier, since we don't need to add another
            //    state keeping track of generatedPerVeshare
            generatedPerShareStored[_account] += FixedPointMathLib.mulDivUp(
                generatedFly,
                1e12,
                baseSharesBalance[_account]
            );
        } else {
            (cappedFly, generatedFly) = getUserGeneratedFly(
                _account,
                _totalAccountKindShares
            );
            generatedPerShareStored[_account] += FixedPointMathLib.mulDivUp(
                generatedFly,
                1e12,
                _totalAccountKindShares
            );
        }
        return cappedFly;
    }

    /*///////////////////////////////////////////////////////////////
                           REWARDS ACCOUNTING
    //////////////////////////////////////////////////////////////*/

    function _updateAccountRewards(address _account) internal {
        _updateAccountBaseReward(_account, baseSharesBalance[_account]);
        _updateAccountBonusReward(_account, veSharesBalance[_account]);
    }

    /*///////////////////////////////////////////////////////////////
                           BASE REWARDS
    //////////////////////////////////////////////////////////////*/

    function baseRewardPerShare() public view returns (uint256) {
        uint256 _totalBaseShare = totalBaseShare;
        //slither-disable-next-line incorrect-equality
        if (_totalBaseShare == 0) {
            return rewardPerShareStored;
        }
        return
            rewardPerShareStored +
            (((block.timestamp - lastUpdatedTime) * emissionRate * 1e18) /
                _totalBaseShare);
    }

    function _updateBaseRewardPerShareStored() internal {
        rewardPerShareStored = baseRewardPerShare();
        lastUpdatedTime = block.timestamp;
    }

    function _updateAccountBaseReward(
        address _account,
        uint256 _totalAccountShares
    ) internal {
        _updateBaseRewardPerShareStored();

        if (_totalAccountShares > 0) {
            uint256 cappedFly = _updateHopperGenerationData(
                _account,
                _totalAccountShares,
                false
            );

            unchecked {
                rewards[_account] += cappedFly;
            }
            userMaxFlyGeneration[_account] -= cappedFly * 1e12;
        }

        userRewardPerSharePaid[_account] = rewardPerShareStored;
    }

    /*///////////////////////////////////////////////////////////////
                           BONUS REWARDS
    //////////////////////////////////////////////////////////////*/

    function bonusRewardPerShare() public view returns (uint256) {
        uint256 _totalVeShare = totalVeShare;
        //slither-disable-next-line incorrect-equality
        if (_totalVeShare == 0) {
            return bonusRewardPerShareStored;
        }
        return
            bonusRewardPerShareStored +
            (((block.timestamp - lastBonusUpdatedTime) *
                bonusEmissionRate *
                1e18) / _totalVeShare);
    }

    function _updateBonusRewardPerShareStored() internal {
        bonusRewardPerShareStored = bonusRewardPerShare();
        lastBonusUpdatedTime = block.timestamp;
    }

    function _updateAccountBonusReward(
        address _account,
        uint256 _totalAccountShares
    ) internal {
        _updateBonusRewardPerShareStored();

        if (_totalAccountShares > 0) {
            uint256 cappedFly = _updateHopperGenerationData(
                _account,
                _totalAccountShares,
                true
            );

            unchecked {
                rewards[_account] += cappedFly;
            }
            userMaxFlyGeneration[_account] -= cappedFly * 1e12;
        }
        userBonusRewardPerSharePaid[_account] = bonusRewardPerShareStored;
    }

    /*///////////////////////////////////////////////////////////////
                    NAMES & LEVELING
    //////////////////////////////////////////////////////////////*/

    function payAction(uint256 flyRequired, bool useOwnRewards) internal {
        if (useOwnRewards) {
            uint256 _rewards = rewards[msg.sender];

            // Pays from the pending rewards
            if (_rewards >= flyRequired) {
                unchecked {
                    rewards[msg.sender] -= flyRequired;
                    flyRequired = 0;
                }
            } else if (_rewards > 0) {
                delete rewards[msg.sender];
                unchecked {
                    flyRequired -= _rewards;
                }
            }
        }

        // Sender pays for action. Will revert, if not enough balance
        if (flyRequired > 0) {
            Fly(FLY).burn(msg.sender, flyRequired);
        }
    }

    function changeHopperName(
        uint256 tokenId,
        string calldata name,
        bool useOwnRewards
    ) external {
        if (useOwnRewards) {
            _updateAccountRewards(msg.sender);
        }

        // Check hopper ownership
        address zoneHopperOwner = hopperOwners[tokenId];
        if (zoneHopperOwner != msg.sender) {
            // Saves gas in certain paths
            if (HopperNFT(HOPPER).ownerOf(tokenId) != msg.sender) {
                revert WrongTokenID();
            }
        }

        payAction(
            HopperNFT(HOPPER).changeHopperName(tokenId, name), // returns price
            useOwnRewards
        );
    }

    function _getLevelUpCost(uint256 level) internal pure returns (uint256) {
        unchecked {
            ++level;

            if (level == 100) {
                return 598 ether;
            }
            // x**(1.43522) / 7.5 for x >= 21 where x is next level
            // packing costs in 7 bits
            else if (level > 1 && level < 21) {
                return (level * 1e18) >> 1;
            } else if (level >= 21 && level < 51) {
                return
                    ((0x1223448501f3c74e1b3464c172c54a9426488901e3c70d183058a >>
                        (7 * (level - 21))) & 127) * 1e18;
            } else if (level >= 51 && level < 81) {
                return
                    ((0x23c68b0e14180f9ebc76e9c376cd5a3262c17ae5ab15a9509d325 >>
                        (7 * (level - 51))) & 127) * 1e18;
            } else if (level >= 81 && level < 101) {
                return
                    ((0xc58705ebb6ed59af5aad3a5467ce9b2e549 >>
                        (7 * (level - 81))) & 127) * 1e18;
            } else {
                return type(uint256).max;
            }
        }
    }

    //slither-disable-next-line reentrancy-no-eth
    function levelUp(uint256 tokenId, bool useOwnRewards) external {
        HopperNFT IHOPPER = HopperNFT(HOPPER);
        if (useOwnRewards) {
            _updateAccountRewards(msg.sender);
        }

        // Check hopper ownership
        address zoneHopperOwner = hopperOwners[tokenId];
        if (zoneHopperOwner != msg.sender) {
            // Saves gas in certain paths
            if (IHOPPER.ownerOf(tokenId) != msg.sender) {
                revert WrongTokenID();
            }
        }

        HopperNFT.Hopper memory hopper = IHOPPER.getHopper(tokenId);

        // Update owners shares if hopper is staked
        if (zoneHopperOwner == msg.sender) {
            // Updated above if true
            if (!useOwnRewards) {
                _updateAccountRewards(msg.sender);
            }

            // Fill hopper gauge so we can find whats the remaining
            (, uint256 remainingGauge, ) = _updateHopperGaugeFill(tokenId);

            // Calculate the baseShare that we need to subtract from the user and total
            uint256 prevHopperShare = _calculateBaseShare(hopper);
            unchecked {
                ++hopper.level;
            }
            // Calculate the baseShare that we need to add to the user and total
            uint256 newHopperShare = _calculateBaseShare(hopper);

            // Calculate new baseShares
            uint256 diff = newHopperShare - prevHopperShare;
            unchecked {
                uint256 newBaseShare = baseSharesBalance[msg.sender] + diff;
                baseSharesBalance[msg.sender] = newBaseShare;

                totalBaseShare += diff;

                // Update new value of veShares
                _updateVeShares(newBaseShare, 0, false);
            }

            uint256 boostFill = 0;
            uint256 userMax = userMaxFlyGeneration[msg.sender];
            if (userMax < remainingGauge) {
                boostFill = remainingGauge - userMax;
            }

            // Update the new cap
            userMaxFlyGeneration[msg.sender] += (_getGaugeLimit(hopper.level) *
                1e12 -
                (remainingGauge - boostFill));

            // Make sure getLevelUpCost is passed its current level
            unchecked {
                --hopper.level;
            }
        }

        payAction(getLevelUpCost(hopper.level), useOwnRewards);

        IHOPPER.levelUp(tokenId);

        // Reset Hopper internal gauge
        IHOPPER.setData(LEVEL_GAUGE_KEY, tokenId, 0);
    }

    /*///////////////////////////////////////////////////////////////
                    STAKE / UNSTAKE NFT && CLAIM FLY
    //////////////////////////////////////////////////////////////*/

    function enter(uint256[] calldata tokenIds) external {
        if (emergency) revert Unauthorized();

        _updateAccountRewards(msg.sender);

        uint256 prevBaseShares = baseSharesBalance[msg.sender];
        uint256 _baseShares = prevBaseShares;
        uint256 numTokens = tokenIds.length;

        uint256 flyCapIncrease;

        uint256 _generatedPerShareStored = generatedPerShareStored[msg.sender];
        for (uint256 i; i < numTokens; ) {
            uint256 tokenId = tokenIds[i];

            // Resets this hopper generation tracking
            tokenCapFilledPerShare[tokenId] = _generatedPerShareStored;

            (
                HopperNFT.Hopper memory hopper,
                uint256 hopperGauge,
                uint256 gaugeLimit
            ) = _getHopperAndGauge(tokenId);

            if (!canEnter(hopper)) revert UnfitHopper();

            unchecked {
                // Increment user shares
                _baseShares += _calculateBaseShare(hopper);
            }

            // Update the maximum FLY this user can generate
            flyCapIncrease += (gaugeLimit - hopperGauge);

            // Hopper Accounting
            hopperOwners[tokenId] = msg.sender;
            HopperNFT(HOPPER).transferFrom(msg.sender, address(this), tokenId);

            unchecked {
                ++i;
            }
        }

        baseSharesBalance[msg.sender] = _baseShares;
        unchecked {
            userMaxFlyGeneration[msg.sender] += flyCapIncrease;

            totalBaseShare = totalBaseShare + _baseShares - prevBaseShares;
        }

        _updateVeShares(_baseShares, 0, false);
    }

    //slither-disable-next-line reentrancy-no-eth
    function exit(uint256[] calldata tokenIds) external {
        if (emergency) revert Unauthorized();

        _updateAccountRewards(msg.sender);

        uint256 prevBaseShares = baseSharesBalance[msg.sender];
        uint256 _baseShares = prevBaseShares;
        uint256 numTokens = tokenIds.length;

        uint256 flyCapDecrease;
        uint256 userMax = userMaxFlyGeneration[msg.sender];

        uint256[] memory rTokensRemaining = new uint256[](tokenIds.length);
        uint256[] memory rTokensLimit = new uint256[](tokenIds.length);

        for (uint256 i; i < numTokens; ) {
            uint256 tokenId = tokenIds[i];

            // Can the user unstake this hopper
            if (hopperOwners[tokenId] != msg.sender) revert WrongTokenID();

            (
                uint256 _hopperShare,
                uint256 _remainingGauge,
                uint256 _gaugeLimit
            ) = _updateHopperGaugeFill(tokenId);

            // Decrement user shares
            _baseShares -= _hopperShare;

            // Update the maximum FLY this user can generate
            flyCapDecrease += _remainingGauge;

            // To fill gauge later
            rTokensRemaining[i] = _remainingGauge;
            rTokensLimit[i] = _gaugeLimit;

            // Hopper Accounting
            //slither-disable-next-line costly-loop
            delete hopperOwners[tokenId];
            HopperNFT(HOPPER).transferFrom(address(this), msg.sender, tokenId);

            unchecked {
                ++i;
            }
        }

        baseSharesBalance[msg.sender] = _baseShares;

        if (userMax < flyCapDecrease) {
            // Being boosted, we need to go back and refill uncapped tokens
            refill(
                tokenIds,
                rTokensRemaining,
                rTokensLimit,
                flyCapDecrease - userMax
            );
            delete userMaxFlyGeneration[msg.sender];
        } else if (_baseShares == 0) {
            delete userMaxFlyGeneration[msg.sender];
        } else {
            userMaxFlyGeneration[msg.sender] -= flyCapDecrease;
        }

        unchecked {
            totalBaseShare = totalBaseShare + _baseShares - prevBaseShares;
        }
        _updateVeShares(_baseShares, 0, false);
    }

    function refill(
        uint256[] calldata tokenIds,
        uint256[] memory remaining,
        uint256[] memory limit,
        uint256 leftover
    ) internal {
        uint256 length = tokenIds.length;

        for (uint256 i; i < length; ) {
            if (remaining[i] != 0) {
                if (leftover > remaining[i]) {
                    HopperNFT(HOPPER).setData(
                        LEVEL_GAUGE_KEY,
                        tokenIds[i],
                        bytes32(limit[i] / 1e12)
                    );
                    leftover -= remaining[i];
                } else {
                    HopperNFT(HOPPER).setData(
                        LEVEL_GAUGE_KEY,
                        tokenIds[i],
                        bytes32((limit[i] - remaining[i] + leftover) / 1e12)
                    );
                    leftover = 0;
                    break;
                }
            }

            unchecked {
                ++i;
            }
        }
    }

    function emergencyExit(uint256[] calldata tokenIds, address user) external {
        if (!emergency) revert Unauthorized();

        uint256 numTokens = tokenIds.length;
        for (uint256 i; i < numTokens; ) {
            uint256 tokenId = tokenIds[i];

            // Can the user unstake this hopper
            if (hopperOwners[tokenId] != user) revert WrongTokenID();

            //slither-disable-next-line costly-loop
            delete hopperOwners[tokenId];
            HopperNFT(HOPPER).transferFrom(address(this), user, tokenId);

            unchecked {
                ++i;
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                            CLAIMING
    //////////////////////////////////////////////////////////////*/

    function claimable(address _account) external view returns (uint256) {
        uint256 cappedFly = userMaxFlyGeneration[_account] / 1e12;

        (uint256 gen, ) = getUserGeneratedFly(
            _account,
            baseSharesBalance[_account]
        );
        (uint256 bonusGen, ) = getUserBonusGeneratedFly(
            _account,
            veSharesBalance[_account]
        );

        gen += bonusGen;
        cappedFly = gen > cappedFly ? cappedFly : gen;

        unchecked {
            return rewards[_account] + cappedFly;
        }
    }

    function claim() external {
        _updateAccountRewards(msg.sender);

        uint256 _accountRewards = rewards[msg.sender];
        delete rewards[msg.sender];

        Fly(FLY).mint(msg.sender, _accountRewards);
    }

    /*///////////////////////////////////////////////////////////////
                            VOTE veFLY 
    //////////////////////////////////////////////////////////////*/

    function _calcVeShare(uint256 accountTotalBaseShares, uint256 vefly)
        internal
        pure
        returns (uint256)
    {
        return FixedPointMathLib.sqrt(accountTotalBaseShares * vefly);
    }

    //slither-disable-next-line reentrancy-no-eth
    function _updateVeShares(
        uint256 baseShares,
        uint256 veFlyAmount,
        bool incrementVeFlyAmount
    ) internal {
        uint256 beforeVeShare = veSharesBalance[msg.sender];
        if (veFlyAmount > 0) {
            // Ballot checks if the user has the veFly amount necessary, otherwise reverts
            if (incrementVeFlyAmount) {
                //slither-disable-next-line reentrancy-benign
                Ballot(ballot).vote(msg.sender, veFlyAmount);
                unchecked {
                    veFlyBalance[msg.sender] += veFlyAmount;
                }
            } else {
                //slither-disable-next-line reentrancy-benign
                Ballot(ballot).unvote(msg.sender, veFlyAmount);
                veFlyBalance[msg.sender] -= veFlyAmount;
            }
        }

        uint256 currentVeShare = _calcVeShare(
            baseShares,
            veFlyBalance[msg.sender]
        );
        veSharesBalance[msg.sender] = currentVeShare;

        unchecked {
            totalVeShare = totalVeShare + currentVeShare - beforeVeShare;
        }
    }

    function vote(uint256 veFlyAmount, bool recount) external {
        _updateAccountBonusReward(msg.sender, veSharesBalance[msg.sender]);

        _updateVeShares(baseSharesBalance[msg.sender], veFlyAmount, true);

        if (recount) Ballot(ballot).count();
    }

    function unvote(uint256 veFlyAmount, bool recount) external {
        _updateAccountBonusReward(msg.sender, veSharesBalance[msg.sender]);

        _updateVeShares(baseSharesBalance[msg.sender], veFlyAmount, false);

        if (recount) Ballot(ballot).count();
    }

    function forceUnvote(address user) external {
        if (msg.sender != ballot) revert Unauthorized();

        uint256 userVeShares = veSharesBalance[user];
        _updateAccountBonusReward(user, userVeShares);

        totalVeShare -= userVeShares;
        delete veSharesBalance[user];
        delete veFlyBalance[user];
    }

    /*///////////////////////////////////////////////////////////////
                    HELPER GAUGE FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    // _remaining is scaled with 1e12
    function _updateHopperGaugeFill(uint256 tokenId)
        internal
        returns (
            uint256 _hopperShare,
            uint256 _remaining,
            uint256
        )
    {
        uint256 _generatedPerShareStored = generatedPerShareStored[msg.sender];

        // Resets this hopper generation tracking
        uint256 filledCapPerShare = _generatedPerShareStored -
            tokenCapFilledPerShare[tokenId];

        tokenCapFilledPerShare[tokenId] = _generatedPerShareStored;

        (
            HopperNFT.Hopper memory hopper,
            uint256 prevHopperGauge,
            uint256 gaugeLimit
        ) = _getHopperAndGauge(tokenId);

        _hopperShare = _calculateBaseShare(hopper);

        uint256 flyGeneratedAndBurned = prevHopperGauge +
            filledCapPerShare *
            _hopperShare;

        uint256 currentGauge = flyGeneratedAndBurned > gaugeLimit
            ? gaugeLimit
            : flyGeneratedAndBurned;

        // Update the HOPPER gauge
        HopperNFT(HOPPER).setData(
            LEVEL_GAUGE_KEY,
            tokenId,
            bytes32(currentGauge / 1e12)
        );

        return (_hopperShare, (gaugeLimit - currentGauge), gaugeLimit);
    }

    function _getGaugeLimit(uint256 level) internal view returns (uint256) {
        if (level == 1) return 1.5 ether;
        if (level == 100) return 294 ether;
        unchecked {
            return flyLevelCapRatio * _getLevelUpCost(level - 1);
        }
    }

    function _getHopperAndGauge(uint256 _tokenId)
        internal
        view
        returns (
            HopperNFT.Hopper memory,
            uint256, // hopperGauge
            uint256 // gaugeLimit
        )
    {
        string[] memory arrData = new string[](1);
        arrData[0] = LEVEL_GAUGE_KEY;
        (HopperNFT.Hopper memory hopper, bytes32[] memory _data) = HopperNFT(
            HOPPER
        ).getHopperWithData(arrData, _tokenId);

        return (
            hopper,
            uint256(_data[0]) * 1e12,
            _getGaugeLimit(hopper.level) * 1e12
        );
    }

    function getHopperAndGauge(uint256 tokenId)
        external
        view
        returns (
            HopperNFT.Hopper memory hopper,
            uint256 hopperGauge,
            uint256 gaugeLimit
        )
    {
        (hopper, hopperGauge, gaugeLimit) = _getHopperAndGauge(tokenId);
        return (hopper, hopperGauge / 1e12, gaugeLimit / 1e12);
    }

    /*///////////////////////////////////////////////////////////////
                                VIEW
    //////////////////////////////////////////////////////////////*/

    function getLevelUpCost(uint256 currentLevel)
        public
        pure
        returns (uint256)
    {
        return _getLevelUpCost(currentLevel);
    }

    /*///////////////////////////////////////////////////////////////
                    ZONE SPECIFIC FUNCTIONALITY
    //////////////////////////////////////////////////////////////*/

    function canEnter(HopperNFT.Hopper memory hopper)
        public
        pure
        virtual
        returns (bool)
    {} // solhint-disable-line

    function _calculateBaseShare(HopperNFT.Hopper memory hopper)
        internal
        pure
        virtual
        returns (uint256)
    {} // solhint-disable-line
}

contract Pond is Zone {
    constructor(
        address fly,
        address vefly,
        address hopper
    ) Zone(fly, vefly, hopper) {}

    // solhint-disable-next-line
    function canEnter(HopperNFT.Hopper memory hopper)
        public
        pure
        override
        returns (bool)
    {
        return true;
    }

    function _calculateBaseShare(HopperNFT.Hopper memory hopper)
        internal
        pure
        override
        returns (uint256)
    {
        unchecked {
            return uint256(hopper.strength) * uint256(hopper.level);
        }
    }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"fly","type":"address"},{"internalType":"address","name":"vefly","type":"address"},{"internalType":"address","name":"hopper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NoHopperStaked","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnfitHopper","type":"error"},{"inputs":[],"name":"WrongTokenID","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"ballot","type":"address"}],"name":"UpdatedBallot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"emissionRate","type":"uint256"}],"name":"UpdatedEmission","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"UpdatedOwner","type":"event"},{"inputs":[],"name":"FLY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HOPPER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEVEL_GAUGE_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VE_FLY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ballot","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseRewardPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"baseSharesBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusEmissionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardPerShareStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint200","name":"level","type":"uint200"},{"internalType":"uint16","name":"rebirths","type":"uint16"},{"internalType":"uint8","name":"strength","type":"uint8"},{"internalType":"uint8","name":"agility","type":"uint8"},{"internalType":"uint8","name":"vitality","type":"uint8"},{"internalType":"uint8","name":"intelligence","type":"uint8"},{"internalType":"uint8","name":"fertility","type":"uint8"}],"internalType":"struct HopperNFT.Hopper","name":"hopper","type":"tuple"}],"name":"canEnter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bool","name":"useOwnRewards","type":"bool"}],"name":"changeHopperName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergency","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"user","type":"address"}],"name":"emergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emissionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"enter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flyLevelCapRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"forceUnvote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"generatedPerShareStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getHopperAndGauge","outputs":[{"components":[{"internalType":"uint200","name":"level","type":"uint200"},{"internalType":"uint16","name":"rebirths","type":"uint16"},{"internalType":"uint8","name":"strength","type":"uint8"},{"internalType":"uint8","name":"agility","type":"uint8"},{"internalType":"uint8","name":"vitality","type":"uint8"},{"internalType":"uint8","name":"intelligence","type":"uint8"},{"internalType":"uint8","name":"fertility","type":"uint8"}],"internalType":"struct HopperNFT.Hopper","name":"hopper","type":"tuple"},{"internalType":"uint256","name":"hopperGauge","type":"uint256"},{"internalType":"uint256","name":"gaugeLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"currentLevel","type":"uint256"}],"name":"getLevelUpCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"_totalUserBonusShares","type":"uint256"}],"name":"getUserBonusGeneratedFly","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"_totalUserBaseShares","type":"uint256"}],"name":"getUserGeneratedFly","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hopperBaseShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hopperOwners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastBonusUpdatedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdatedTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bool","name":"useOwnRewards","type":"bool"}],"name":"levelUp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerShareStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ballot","type":"address"}],"name":"setBallot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bonusEmissionRate","type":"uint256"}],"name":"setBonusEmissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_emissionRate","type":"uint256"}],"name":"setEmissionRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_flyLevelCapRatio","type":"uint256"}],"name":"setFlyLevelCapRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenCapFilledPerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBaseShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVeShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"veFlyAmount","type":"uint256"},{"internalType":"bool","name":"recount","type":"bool"}],"name":"unvote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBonusRewardPerSharePaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userMaxFlyGeneration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerSharePaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"veFlyBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"veSharesBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"veFlyAmount","type":"uint256"},{"internalType":"bool","name":"recount","type":"bool"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b5060405162003bac38038062003bac83398101604081905262000034916200017c565b600480546001600160a01b031916331790556001600160a01b0380841660805280831660a052811660c0526003600f908155604080518082019091528181526e4c4556454c5f47415547455f4b455960881b6020909101908152849184918491620000a291600091620000b9565b505042600881905560125550620002039350505050565b828054620000c790620001c6565b90600052602060002090601f016020900481019282620000eb576000855562000136565b82601f106200010657805160ff191683800117855562000136565b8280016001018555821562000136579182015b828111156200013657825182559160200191906001019062000119565b506200014492915062000148565b5090565b5b8082111562000144576000815560010162000149565b80516001600160a01b03811681146200017757600080fd5b919050565b6000806000606084860312156200019257600080fd5b6200019d846200015f565b9250620001ad602085016200015f565b9150620001bd604085016200015f565b90509250925092565b600181811c90821680620001db57607f821691505b60208210811415620001fd57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05161392562000287600039600081816104cf0152818161084901528181611027015281816115c7015281816117bd015281816118b601528181611e3a0152818161217e0152818161257a015281816126940152612997015260006104430152600081816107840152818161128a01526124d101526139256000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c806379f409e0116101b2578063ad914e2e116100f9578063d881e959116100a2578063e42c4e631161007c578063e42c4e63146107a6578063e532a154146107ae578063ee569ba9146107b6578063f5544eb7146107d657600080fd5b8063d881e9591461074c578063dee935681461075f578063e1a61a0c1461077f57600080fd5b8063c9d27afe116100d3578063c9d27afe14610701578063caa6fea414610714578063d051bfa31461073957600080fd5b8063ad914e2e146106c3578063bf856895146106e5578063bf9bc0b2146106ee57600080fd5b806396afc4501161015b578063a49a3e1b11610135578063a49a3e1b1461067b578063ab20355c14610690578063ac3910a2146106a357600080fd5b806396afc4501461064c5780639d4c93c414610655578063a1bdb15e1461066857600080fd5b80638da5cb5b1161018c5780638da5cb5b146105f95780638eb3be2814610619578063968c603d1461062c57600080fd5b806379f409e0146105915780637e2d9af8146105b9578063818ae1ce146105d957600080fd5b80633cfa989e116102815780635834c36d1161022a5780635d35b5d5116102045780635d35b5d51461053e5780636351520e14610547578063769022a31461055a5780637944135d1461057e57600080fd5b80635834c36d14610502578063591adce61461050b5780635c1ab8c01461051e57600080fd5b80634b905e3f1161025b5780634b905e3f146104ca5780634b9ca431146104f15780634e71d92d146104fa57600080fd5b80633cfa989e1461048e578063402914f5146104ae57806343aba89d146104c157600080fd5b80631c1502c4116102e35780632677d07f116102bd5780632677d07f1461043e5780632df97550146104655780633bad0f711461048557600080fd5b80631c1502c4146103ba578063201e29a0146103c3578063215e0f4d1461041e57600080fd5b80630c679fa0116103145780630c679fa01461037f57806313af40351461039457806318c08f26146103a757600080fd5b80630700037d1461033b5780630ab747f01461036e5780630b24216314610377575b600080fd5b61035b610349366004612f48565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61035b60095481565b61035b6107e9565b61039261038d366004612f75565b610847565b005b6103926103a2366004612f48565b610cdd565b6103926103b5366004612fe6565b610d9d565b61035b60135481565b6103f96103d1366004613028565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b61035b61042c366004612f48565b600a6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b610473366004612f48565b60146020526000908152604090205481565b61035b60075481565b61035b61049c366004612f48565b600d6020526000908152604090205481565b61035b6104bc366004612f48565b61112e565b61035b60105481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b60115481565b610392611221565b61035b60125481565b610392610519366004612f75565b6112e9565b61035b61052c366004612f48565b600c6020526000908152604090205481565b61035b600f5481565b610392610555366004613028565b6113ab565b61056e610568366004613110565b50600190565b6040519015158152602001610365565b61039261058c366004612fe6565b611401565b6105a461059f3660046131c8565b61168a565b60408051928352602083019190915201610365565b61035b6105c7366004612f48565b60166020526000908152604090205481565b61035b6105e7366004612f48565b600b6020526000908152604090205481565b6004546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6103926106273660046131f4565b61173c565b61035b61063a366004613028565b60026020526000908152604090205481565b61035b60065481565b610392610663366004613028565b611938565b610392610676366004613028565b6119bc565b610683611a50565b60405161036591906132ec565b6105a461069e3660046131c8565b611ade565b6005546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6106d66106d1366004613028565b611b54565b604051610365939291906132ff565b61035b60085481565b61035b6106fc366004613028565b611bca565b61039261070f366004612f75565b611bdb565b60055461056e9074010000000000000000000000000000000000000000900460ff1681565b610392610747366004612f48565b611c11565b61039261075a366004613398565b611cd1565b61035b61076d366004613028565b600e6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b610392611ea2565b61035b611f34565b61035b6107c4366004612f48565b60156020526000908152604090205481565b6103926107e4366004612f48565b611f8c565b600754600090806107fc57505060095490565b806006546008544261080e919061341e565b6108189190613435565b61082a90670de0b6b3a7640000613435565b6108349190613472565b60095461084191906134ad565b91505090565b7f000000000000000000000000000000000000000000000000000000000000000081156108775761087733612059565b60008381526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114610981576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101859052339073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa158015610910573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093491906134c5565b73ffffffffffffffffffffffffffffffffffffffff1614610981576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5c5503530000000000000000000000000000000000000000000000000000000081526004810185905260009073ffffffffffffffffffffffffffffffffffffffff841690635c5503539060240160e060405180830381865afa1580156109ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1391906135aa565b905073ffffffffffffffffffffffffffffffffffffffff8216331415610b9c5783610a4157610a4133612059565b6000610a4c866120be565b50835160408501516001820178ffffffffffffffffffffffffffffffffffffffffffffffffff90811680885293955060ff909116911681029250026000610a93838361341e565b336000908152600a6020526040812080548301908190556007805484019055919250610ac190829080612243565b50336000908152600c602052604081205485811015610ae757610ae4818761341e565b91505b610af1828761341e565b8751610b179078ffffffffffffffffffffffffffffffffffffffffffffffffff166123f5565b610b269064e8d4a51000613435565b610b30919061341e565b336000908152600c602052604081208054909190610b4f9084906134ad565b909155505086517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0178ffffffffffffffffffffffffffffffffffffffffffffffffff1687525050505050505b610bcd610bc7826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16611bca565b8561243e565b6040517f0ce90ec20000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff841690630ce90ec290602401600060405180830381600087803b158015610c3557600080fd5b505af1158015610c49573d6000803e3d6000fd5b50506040517f3d68b4b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250633d68b4b59150610ca490600090899082906004016136eb565b600060405180830381600087803b158015610cbe57600080fd5b505af1158015610cd2573d6000803e3d6000fd5b505050505050505050565b60045473ffffffffffffffffffffffffffffffffffffffff163314610d2e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f957090e72c0a1b3ebf83c682eb8c1f88c2a18cd0578b91a819efb28859f0f3a390600090a250565b60055474010000000000000000000000000000000000000000900460ff1615610df2576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dfb33612059565b336000908152600a6020908152604080832054600c90925282205490918291849190818367ffffffffffffffff811115610e3757610e37613041565b604051908082528060200260200182016040528015610e60578160200160208202803683370190505b50905060008767ffffffffffffffff811115610e7e57610e7e613041565b604051908082528060200260200182016040528015610ea7578160200160208202803683370190505b50905060005b858110156110925760008a8a83818110610ec957610ec9613710565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff163314610f35576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610f43846120be565b91945092509050610f54838c61341e565b9a50610f60828a6134ad565b985081878681518110610f7557610f75613710565b60200260200101818152505080868681518110610f9457610f94613710565b6020908102919091018101919091526000858152600190915260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810185905273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b15801561106b57600080fd5b505af115801561107f573d6000803e3d6000fd5b5050505084600101945050505050610ead565b50336000908152600a60205260409020869055838310156110d8576110c3898984846110be888a61341e565b61252a565b336000908152600c6020526040812055611117565b856110f257336000908152600c6020526040812055611117565b336000908152600c60205260408120805486929061111190849061341e565b90915550505b6007805487018890039055610cd286600080612243565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600c602052604081205481906111669064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600a60205260408120549192509061119b90859061168a565b5073ffffffffffffffffffffffffffffffffffffffff8516600090815260146020526040812054919250906111d1908690611ade565b5090506111de81836134ad565b91508282116111ed57816111ef565b825b73ffffffffffffffffffffffffffffffffffffffff909516600090815260036020526040902054909401949350505050565b61122a33612059565b336000818152600360205260408082208054929055517f40c10f190000000000000000000000000000000000000000000000000000000081526004810192909252602482018190529073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b1580156112ce57600080fd5b505af11580156112e2573d6000803e3d6000fd5b5050505050565b3360008181526014602052604090205461130391906127c0565b336000908152600a602052604081205461131e918490612243565b80156113a757600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306661abd6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561138e57600080fd5b505af11580156113a2573d6000803e3d6000fd5b505050505b5050565b60045473ffffffffffffffffffffffffffffffffffffffff1633146113fc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f55565b60055474010000000000000000000000000000000000000000900460ff1615611456576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61145f33612059565b336000908152600a6020908152604080832054600d90925282205490918291849190815b8381101561164757600088888381811061149f5761149f613710565b602090810292909201356000818152600e909352604083208690559250819050806114c984612881565b9250925092506114d7600190565b61150d576040517f0ce023b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251604084015160ff1678ffffffffffffffffffffffffffffffffffffffffffffffffff9091160290980197611543828261341e565b61154d90886134ad565b6000858152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163390811790915590517f23b872dd0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018690529097507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b15801561162057600080fd5b505af1158015611634573d6000803e3d6000fd5b5050505084600101945050505050611483565b50336000908152600a60209081526040808320879055600c9091528120805484019055600780548601879003905561168190859080612243565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040812054819081906116c49064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600b602052604081205491925090670de0b6b3a7640000906117006107e9565b61170a919061341e565b6117149087613435565b61171e9190613472565b905081811161172d578061172f565b815b93509150505b9250929050565b801561174b5761174b33612059565b60008481526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114611875576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052339073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015611804573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182891906134c5565b73ffffffffffffffffffffffffffffffffffffffff1614611875576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc60fb6a70000000000000000000000000000000000000000000000000000000081526112e29073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c60fb6a7906118ef9089908990899060040161373f565b6020604051808303816000875af115801561190e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119329190613793565b8361243e565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611978575060055473ffffffffffffffffffffffffffffffffffffffff163314155b156119af576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119b7612acb565b601055565b60045473ffffffffffffffffffffffffffffffffffffffff163314611a0d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a15612adc565b60068190556040518181527f90e51e492b1841b8ed3d459463d02d171ced752c7fcd84a9dd79f90098166aec9060200160405180910390a150565b60008054611a5d906135c6565b80601f0160208091040260200160405190810160405280929190818152602001828054611a89906135c6565b8015611ad65780601f10611aab57610100808354040283529160200191611ad6565b820191906000526020600020905b815481529060010190602001808311611ab957829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604081205481908190611b189064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff861660009081526015602052604081205491925090670de0b6b3a764000090611700611f34565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529080611b9784612881565b9194509250905082611bae64e8d4a5100084613472565b611bbd64e8d4a5100084613472565b9250925092509193909250565b6000611bd582612aed565b92915050565b33600081815260146020526040902054611bf591906127c0565b336000908152600a602052604090205461131e90836001612243565b60045473ffffffffffffffffffffffffffffffffffffffff163314611c62576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f605aa74980dc92c245d8959d233f8c2d7062d874e49326a42e7418279cc8d1f890600090a250565b60055474010000000000000000000000000000000000000000900460ff16611d25576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160005b818110156112e2576000858583818110611d4557611d45613710565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff858116911614611db4576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b158015611e7e57600080fd5b505af1158015611e92573d6000803e3d6000fd5b5050505081600101915050611d29565b60045473ffffffffffffffffffffffffffffffffffffffff163314611ef3576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60115460009080611f4757505060135490565b8060105460125442611f59919061341e565b611f639190613435565b611f7590670de0b6b3a7640000613435565b611f7f9190613472565b60135461084191906134ad565b60055473ffffffffffffffffffffffffffffffffffffffff163314611fdd576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205461200d82826127c0565b806011600082825461201f919061341e565b90915550505073ffffffffffffffffffffffffffffffffffffffff1660009081526014602090815260408083208390556016909152812055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a602052604090205461208a908290612c41565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601460205260409020546120bb9082906127c0565b50565b336000908152600d6020908152604080832054848452600e9092528220548291829182906120ec908361341e565b6000878152600e60205260408120849055909150808061210b89612881565b8251604084015160ff1678ffffffffffffffffffffffffffffffffffffffffffffffffff909116029a509194509250905060006121488986613435565b61215290846134ad565b905060008282116121635781612165565b825b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016633d68b4b560008d6121b564e8d4a5100086613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526121f0939291906004016136eb565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505089818461222f919061341e565b909c909b5092995091975050505050505050565b3360009081526014602052604090205482156123b4578115612304576005546040517f5f74bbde0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff90911690635f74bbde90604401600060405180830381600087803b1580156122d157600080fd5b505af11580156122e5573d6000803e3d6000fd5b5050336000908152601660205260409020805486019055506123b49050565b6005546040517f02aa9be20000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff909116906302aa9be290604401600060405180830381600087803b15801561237657600080fd5b505af115801561238a573d6000803e3d6000fd5b505033600090815260166020526040812080548794509092506123ae90849061341e565b90915550505b336000908152601660205260408120546123cf908690612d02565b336000908152601460205260409020819055601180549091019290920390915550505050565b6000816001141561240f57506714d1120d7b160000919050565b81606414156124285750680ff011d2523cd80000919050565b61243460018303612aed565b600f540292915050565b8015612496573360009081526003602052604090205482811061247857336000908152600360205260408120805494909403909355612494565b8015612494573360009081526003602052604081205591829003915b505b81156113a7576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639dc29fac90604401600060405180830381600087803b15801561138e57600080fd5b8360005b818110156116815784818151811061254857612548613710565b60200260200101516000146127b85784818151811061256957612569613710565b6020026020010151831115612692577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b560008989858181106125c8576125c8613710565b9050602002013564e8d4a510008886815181106125e7576125e7613710565b60200260200101516125f99190613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152612634939291906004016136eb565b600060405180830381600087803b15801561264e57600080fd5b505af1158015612662573d6000803e3d6000fd5b5050505084818151811061267857612678613710565b60200260200101518361268b919061341e565b92506127b8565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b560008989858181106126e2576126e2613710565b9050602002013564e8d4a51000878a878151811061270257612702613710565b60200260200101518a888151811061271c5761271c613710565b602002602001015161272e919061341e565b61273891906134ad565b6127429190613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261277d939291906004016136eb565b600060405180830381600087803b15801561279757600080fd5b505af11580156127ab573d6000803e3d6000fd5b5050505060009250611681565b60010161252e565b6127c8612acb565b80156128545760006127dc83836001612d1d565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040902080548201905590506128188164e8d4a51000613435565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c60205260408120805490919061284d90849061341e565b9091555050505b5060135473ffffffffffffffffffffffffffffffffffffffff909116600090815260156020526040902055565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905283516001808252818601909552929391928392839282015b60608152602001906001900390816128d2579050509050600080546128f6906135c6565b80601f0160208091040260200160405190810160405280929190818152602001828054612922906135c6565b801561296f5780601f106129445761010080835404028352916020019161296f565b820191906000526020600020905b81548152906001019060200180831161295257829003601f168201915b50505050508160008151811061298757612987613710565b60200260200101819052506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630d51186584896040518363ffffffff1660e01b81526004016129f09291906137ac565b600060405180830381865afa158015612a0d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612a539190810190613833565b915091508181600081518110612a6b57612a6b613710565b602002602001015160001c64e8d4a51000612a869190613435565b8351612aac9078ffffffffffffffffffffffffffffffffffffffffffffffffff166123f5565b612abb9064e8d4a51000613435565b9550955095505050509193909250565b612ad3611f34565b60135542601255565b612ae46107e9565b60095542600855565b60010160006064821415612b0b575068206aeac7a903980000919050565b600182118015612b1b5750601582105b15612b315750670de0b6b3a76400000260011c90565b60158210158015612b425750603382105b15612b8057601582036007027a01223448501f3c74e1b3464c172c54a9426488901e3c70d183058a901c607f16670de0b6b3a7640000029050919050565b60338210158015612b915750605182105b15612bcf57603382036007027a023c68b0e14180f9ebc76e9c376cd5a3262c17ae5ab15a9509d325901c607f16670de0b6b3a7640000029050919050565b60518210158015612be05750606582105b15612c155760518203600702710c58705ebb6ed59af5aad3a5467ce9b2e549901c607f16670de0b6b3a7640000029050919050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff919050565b919050565b612c49612adc565b8015612cd5576000612c5d83836000612d1d565b73ffffffffffffffffffffffffffffffffffffffff841660009081526003602052604090208054820190559050612c998164e8d4a51000613435565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612cce90849061341e565b9091555050505b5060095473ffffffffffffffffffffffffffffffffffffffff9091166000908152600b6020526040902055565b6000612d16612d118385613435565b612e12565b9392505050565b60008060008315612daf57612d328686611ade565b73ffffffffffffffffffffffffffffffffffffffff88166000908152600a60205260409020549193509150612d6f90829064e8d4a5100090612ef8565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612da49084906134ad565b90915550612e099050565b612db9868661168a565b9092509050612dce8164e8d4a5100087612ef8565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612e039084906134ad565b90915550505b50949350505050565b6001817001000000000000000000000000000000008110612e385760409190911b9060801c5b680100000000000000008110612e535760209190911b9060401c5b6401000000008110612e6a5760109190911b9060201c5b620100008110612e7f5760089190911b9060101c5b6101008110612e935760049190911b9060081c5b60108110612ea65760029190911b9060041c5b60088110612eb5578160011b91505b5080820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c80820481811015612ef2578091505b50919050565b828202811515841585830485141716612f1057600080fd5b6001826001830304018115150290509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146120bb57600080fd5b600060208284031215612f5a57600080fd5b8135612d1681612f26565b80358015158114612c3c57600080fd5b60008060408385031215612f8857600080fd5b82359150612f9860208401612f65565b90509250929050565b60008083601f840112612fb357600080fd5b50813567ffffffffffffffff811115612fcb57600080fd5b6020830191508360208260051b850101111561173557600080fd5b60008060208385031215612ff957600080fd5b823567ffffffffffffffff81111561301057600080fd5b61301c85828601612fa1565b90969095509350505050565b60006020828403121561303a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156130b7576130b7613041565b604052919050565b78ffffffffffffffffffffffffffffffffffffffffffffffffff811681146120bb57600080fd5b61ffff811681146120bb57600080fd5b60ff811681146120bb57600080fd5b8035612c3c816130f6565b600060e0828403121561312257600080fd5b60405160e0810181811067ffffffffffffffff8211171561314557613145613041565b6040528235613153816130bf565b81526020830135613163816130e6565b60208201526040830135613176816130f6565b60408201526060830135613189816130f6565b606082015261319a60808401613105565b60808201526131ab60a08401613105565b60a08201526131bc60c08401613105565b60c08201529392505050565b600080604083850312156131db57600080fd5b82356131e681612f26565b946020939093013593505050565b6000806000806060858703121561320a57600080fd5b84359350602085013567ffffffffffffffff8082111561322957600080fd5b818701915087601f83011261323d57600080fd5b81358181111561324c57600080fd5b88602082850101111561325e57600080fd5b60208301955080945050505061327660408601612f65565b905092959194509250565b6000815180845260005b818110156132a75760208185018101518683018201520161328b565b818111156132b9576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612d166020830184613281565b60006101208201905078ffffffffffffffffffffffffffffffffffffffffffffffffff855116825261ffff602086015116602083015260ff604086015116604083015260ff606086015116606083015260ff608086015116608083015260a085015161337060a084018260ff169052565b5060c085015161338560c084018260ff169052565b5060e08201939093526101000152919050565b6000806000604084860312156133ad57600080fd5b833567ffffffffffffffff8111156133c457600080fd5b6133d086828701612fa1565b90945092505060208401356133e481612f26565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613430576134306133ef565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561346d5761346d6133ef565b500290565b6000826134a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082198211156134c0576134c06133ef565b500190565b6000602082840312156134d757600080fd5b8151612d1681612f26565b8051612c3c816130f6565b600060e082840312156134ff57600080fd5b60405160e0810181811067ffffffffffffffff8211171561352257613522613041565b80604052508091508251613535816130bf565b81526020830151613545816130e6565b60208201526040830151613558816130f6565b6040820152606083015161356b816130f6565b606082015261357c608084016134e2565b608082015261358d60a084016134e2565b60a082015261359e60c084016134e2565b60c08201525092915050565b600060e082840312156135bc57600080fd5b612d1683836134ed565b600181811c908216806135da57607f821691505b60208210811415612ef2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061362e57607f831692505b6020808410821415613669577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8388526020880182801561368457600181146136b3576136de565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008716825282820197506136de565b60008981526020902060005b878110156136d8578154848201529086019084016136bf565b83019850505b5050505050505092915050565b6060815260006136fe6060830186613614565b60208301949094525060400152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156137a557600080fd5b5051919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015613821577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261380f868351613281565b955093820193908201906001016137d5565b50509490940194909452949350505050565b600080610100838503121561384757600080fd5b61385184846134ed565b915060e083015167ffffffffffffffff8082111561386e57600080fd5b818501915085601f83011261388257600080fd5b815160208282111561389657613896613041565b8160051b92506138a7818401613070565b82815292840181019281810190898511156138c157600080fd5b948201945b848610156138df578551825294820194908201906138c6565b809650505050505050925092905056fea26469706673582212207553e46202818fd396c723f5235a499b3752da913dcd87ac2a7f858425538bdc64736f6c634300080c003300000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe28000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa273240000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b

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

00000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe28000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa273240000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b

-----Decoded View---------------
Arg [0] : fly (address): 0x78ea3fef1c1f07348199bf44f45b803b9b0dbe28
Arg [1] : vefly (address): 0xbaf9a6f8a8afd4be0d85ca40f025bf364fa27324
Arg [2] : hopper (address): 0x4245a1bd84eb5f3ebc115c2edf57e50667f98b0b

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe28
Arg [1] : 000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa27324
Arg [2] : 0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b


Deployed ByteCode Sourcemap

96648:609:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68662:42;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;571:25:1;;;559:2;544:18;68662:42:0;;;;;;;;69096:35;;;;;;75465:428;;;:::i;80994:2561::-;;;;;;:::i;:::-;;:::i;:::-;;71475:122;;;;;;:::i;:::-;;:::i;85507:2330::-;;;;;;:::i;:::-;;:::i;69806:40::-;;;;;;68551:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2200:42:1;2188:55;;;2170:74;;2158:2;2143:18;68551:47:0;2024:226:1;69140:52:0;;;;;;:::i;:::-;;;;;;;;;;;;;;68253:31;;;;;69855:50;;;;;;:::i;:::-;;;;;;;;;;;;;;69023:29;;;;;;69327:58;;;;;;:::i;:::-;;;;;;;;;;;;;;89703:572;;;;;;:::i;:::-;;:::i;69689:32::-;;;;;;68291:31;;;;;69730:27;;;;;;90283:228;;;:::i;69764:35::-;;;;;;92390:272;;;;;;:::i;:::-;;:::i;69263:55::-;;;;;;:::i;:::-;;;;;;;;;;;;;;69458:31;;;;;;72290:130;;;;;;:::i;:::-;;:::i;96836:157::-;;;;;;:::i;:::-;-1:-1:-1;96981:4:0;;96836:157;;;;4632:14:1;;4625:22;4607:41;;4595:2;4580:18;96836:157:0;4467:187:1;83760:1688:0;;;;;;:::i;:::-;;:::i;73238:483::-;;;;;;:::i;:::-;;:::i;:::-;;;;5153:25:1;;;5209:2;5194:18;;5187:34;;;;5126:18;73238:483:0;4979:248:1;69981:47:0;;;;;;:::i;:::-;;;;;;;;;;;;;;69199:57;;;;;;:::i;:::-;;;;;;;;;;;;;;68713:20;;;;;;;;;79099:686;;;;;;:::i;:::-;;:::i;68605:50::-;;;;;;:::i;:::-;;;;;;;;;;;;;;68987:27;;;;;;72070:212;;;;;;:::i;:::-;;:::i;71856:206::-;;;;;;:::i;:::-;;:::i;68513:29::-;;;:::i;:::-;;;;;;;:::i;72618:612::-;;;;;;:::i;:::-;;:::i;68740:21::-;;;;;;;;;95392:369;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;69059:30::-;;;;;;95950:163;;;;;;:::i;:::-;;:::i;92113:269::-;;;;;;:::i;:::-;;:::i;68768:21::-;;;;;;;;;;;;71720:128;;;;;;:::i;:::-;;:::i;88877:637::-;;;;;;:::i;:::-;;:::i;69392:57::-;;;;;;:::i;:::-;;;;;;;;;;;;;;68218:28;;;;;71605:107;;;:::i;76870:458::-;;;:::i;69912:62::-;;;;;;:::i;:::-;;;;;;;;;;;;;;92670:339;;;;;;:::i;:::-;;:::i;75465:428::-;75562:14;;75516:7;;75647:20;75643:80;;-1:-1:-1;;75691:20:0;;;75465:428::o;75643:80::-;75869:15;75829:12;;75810:15;;75792;:33;;;;:::i;:::-;75791:50;;;;:::i;:::-;:57;;75844:4;75791:57;:::i;:::-;75790:94;;;;:::i;:::-;75753:20;;:132;;;;:::i;:::-;75733:152;;;75465:428;:::o;80994:2561::-;81098:6;81116:79;;;;81150:33;81172:10;81150:21;:33::i;:::-;81242:23;81268:21;;;:12;:21;;;;;;;;81323:10;81304:29;;81300:204;;81397:24;;;;;;;;571:25:1;;;81425:10:0;;81397:38;:15;;;;;544:18:1;;81397:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:38;;;81393:100;;81463:14;;;;;;;;;;;;;;81393:100;81549:26;;;;;;;;571:25:1;;;81516:30:0;;81549:17;;;;;;544:18:1;;81549:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81516:59;-1:-1:-1;81645:29:0;;;81664:10;81645:29;81641:1706;;;81734:13;81729:88;;81768:33;81790:10;81768:21;:33::i;:::-;81905:22;81933:31;81956:7;81933:22;:31::i;:::-;-1:-1:-1;97222:12:0;;97195:15;;;;82167:14;;;97214:21;82167:14;;;;;;81902:62;;-1:-1:-1;97187:24:0;;;;97214:21;;97187:48;;;-1:-1:-1;97187:48:0;82070:23;82418:32;97187:48;;82418:32;:::i;:::-;82535:10;82494:20;82517:29;;;:17;:29;;;;;;;:36;;82572:44;;;;82637:14;:22;;;;;;82403:47;;-1:-1:-1;82729:39:0;;82517:36;;82494:20;82729:15;:39::i;:::-;-1:-1:-1;82875:10:0;82800:17;82854:32;;;:20;:32;;;;;;82905:24;;;82901:101;;;82962:24;82979:7;82962:14;:24;:::i;:::-;82950:36;;82901:101;83163:26;83180:9;83163:14;:26;:::i;:::-;83105:12;;83090:28;;;;:14;:28::i;:::-;:52;;83138:4;83090:52;:::i;:::-;:100;;;;:::i;:::-;83074:10;83053:32;;;;:20;:32;;;;;:138;;:32;;;:138;;;;;:::i;:::-;;;;-1:-1:-1;;83306:14:0;;;;;;;;-1:-1:-1;;;;;;81641:1706:0;83359:54;83369:28;83384:6;:12;;;83369:28;;:14;:28::i;:::-;83399:13;83359:9;:54::i;:::-;83426:24;;;;;;;;571:25:1;;;83426:15:0;;;;;;544:18:1;;83426:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;83503:44:0;;;;;:15;;;;-1:-1:-1;83503:15:0;;-1:-1:-1;83503:44:0;;83519:15;;83536:7;;83519:15;;83503:44;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81057:2498;;;80994:2561;;:::o;71475:122::-;71281:5;;;;71267:10;:19;71263:46;;71295:14;;;;;;;;;;;;;;71263:46;71539:5:::1;:14:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;71569:20:::1;::::0;::::1;::::0;-1:-1:-1;;71569:20:0::1;71475:122:::0;:::o;85507:2330::-;85574:9;;;;;;;85570:36;;;85592:14;;;;;;;;;;;;;;85570:36;85619:33;85641:10;85619:21;:33::i;:::-;85708:10;85665:22;85690:29;;;:17;:29;;;;;;;;;85876:20;:32;;;;;;85690:29;;;;85797:8;;85665:22;;85797:8;85957:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;85957:30:0;-1:-1:-1;85921:66:0;-1:-1:-1;85998:29:0;86044:8;86030:30;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;86030:30:0;;85998:62;;86078:9;86073:1007;86093:9;86089:1;:13;86073:1007;;;86121:15;86139:8;;86148:1;86139:11;;;;;;;:::i;:::-;;;;;;;;;;86220:21;;;;:12;:21;;;;;;;;86139:11;;-1:-1:-1;;86220:35:0;:21;86245:10;86220:35;86216:62;;86264:14;;;;;;;;;;;;;;86216:62;86314:20;86353:23;86395:19;86432:31;86455:7;86432:22;:31::i;:::-;86295:168;;-1:-1:-1;86295:168:0;-1:-1:-1;86295:168:0;-1:-1:-1;86518:27:0;86295:168;86518:27;;:::i;:::-;;-1:-1:-1;86624:33:0;86642:15;86624:33;;:::i;:::-;;;86732:15;86710:16;86727:1;86710:19;;;;;;;;:::i;:::-;;;;;;:37;;;;;86780:11;86762:12;86775:1;86762:15;;;;;;;;:::i;:::-;;;;;;;;;;;:29;;;;86902:21;;;;:12;:21;;;;;;;;86895:28;;;;;;86938:66;;;;86977:4;86938:66;;;13810:34:1;86984:10:0;13860:18:1;;;13853:43;13912:18;;;13905:34;;;86895:28:0;86948:6;86938:30;;;;13722:18:1;;86938:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87050:3;;;;;86106:974;;;;86073:1007;;;-1:-1:-1;87110:10:0;87092:29;;;;:17;:29;;;;;:43;;;87152:24;;;87148:522;;;87270:157;87295:8;;87322:16;87357:12;87388:24;87405:7;87388:14;:24;:::i;:::-;87270:6;:157::i;:::-;87470:10;87449:32;;;;:20;:32;;;;;87442:39;87148:522;;;87503:16;87499:171;;87564:10;87543:32;;;;:20;:32;;;;;87536:39;87499:171;;;87629:10;87608:32;;;;:20;:32;;;;;:50;;87644:14;;87608:32;:50;;87644:14;;87608:50;:::i;:::-;;;;-1:-1:-1;;87499:171:0;87724:14;;;:28;;:45;;;87707:62;;87791:38;87741:11;-1:-1:-1;;87791:15:0;:38::i;89703:572::-;89803:30;;;89763:7;89803:30;;;:20;:30;;;;;;89763:7;;89803:37;;89836:4;;89803:37;:::i;:::-;89928:27;;;89854:11;89928:27;;;:17;:27;;;;;;89783:57;;-1:-1:-1;89854:11:0;89871:95;;89905:8;;89871:19;:95::i;:::-;-1:-1:-1;90062:25:0;;;89978:16;90062:25;;;:15;:25;;;;;;89853:113;;-1:-1:-1;89978:16:0;90000:98;;90039:8;;90000:24;:98::i;:::-;-1:-1:-1;89977:121:0;-1:-1:-1;90111:15:0;89977:121;90111:15;;:::i;:::-;;;90155:9;90149:3;:15;:33;;90179:3;90149:33;;;90167:9;90149:33;90227:17;;;;;;;;:7;:17;;;;;;:29;;;;89703:572;-1:-1:-1;;;;89703:572:0:o;90283:228::-;90320:33;90342:10;90320:21;:33::i;:::-;90400:10;90366:23;90392:19;;;:7;:19;;;;;;;;90422:26;;;90461:42;;;;;;;14124:74:1;;;;14214:18;;;14207:34;;;90392:19:0;;90465:3;90461:13;;;;14097:18:1;;90461:42:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90309:202;90283:228::o;92390:272::-;92487:10;92499:27;;;;:15;:27;;;;;;92461:66;;92487:10;92461:25;:66::i;:::-;92574:10;92556:29;;;;:17;:29;;;;;;92540:66;;92587:11;;92540:15;:66::i;:::-;92623:7;92619:35;;;92639:6;;;;;;;;;;;92632:20;;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92619:35;92390:272;;:::o;72290:130::-;71281:5;;;;71267:10;:19;71263:46;;71295:14;;;;;;;;;;;;;;71263:46;72376:16:::1;:36:::0;72290:130::o;83760:1688::-;83828:9;;;;;;;83824:36;;;83846:14;;;;;;;;;;;;;;83824:36;83873:33;83895:10;83873:21;:33::i;:::-;83962:10;83919:22;83944:29;;;:17;:29;;;;;;;;;84149:23;:35;;;;;;83944:29;;;;84051:8;;83919:22;;84195:963;84215:9;84211:1;:13;84195:963;;;84243:15;84261:8;;84270:1;84261:11;;;;;;;:::i;:::-;;;;;;;;;;84344:31;;;;:22;:31;;;;;;:58;;;84261:11;-1:-1:-1;84344:31:0;;-1:-1:-1;84344:31:0;84561:27;84261:11;84561:18;:27::i;:::-;84419:169;;;;;;84610:16;96981:4;;96836:157;84610:16;84605:43;;84635:13;;;;;;;;;;;;;;84605:43;97222:12;;97195:15;;;;97187:24;;97214:21;;;;97187:48;84736:42;;;;84891:24;84904:11;84891:10;:24;:::i;:::-;84872:44;;;;:::i;:::-;84967:21;;;;:12;:21;;;;;;;:34;;;;84991:10;84967:34;;;;;;85016:66;;;;;;;;13810:34:1;;;;85067:4:0;13860:18:1;;;13853:43;13912:18;;;13905:34;;;84872:44:0;;-1:-1:-1;85026:6:0;84967:34;85016:30;;;;13722:18:1;;85016:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85128:3;;;;;84228:930;;;;84195:963;;;-1:-1:-1;85188:10:0;85170:29;;;;:17;:29;;;;;;;;:43;;;85249:20;:32;;;;;:50;;;;;;85333:14;;;:28;;:45;;;85316:62;;85402:38;;85202:11;;85170:29;85402:15;:38::i;:::-;83813:1635;;;;;83760:1688;;:::o;73238:483::-;73416:29;;;73362:7;73416:29;;;:20;:29;;;;;;73362:7;;;;73416:36;;73448:4;;73416:36;:::i;:::-;73548:31;;;73463:20;73548:31;;;:22;:31;;;;;;73396:56;;-1:-1:-1;73463:20:0;73584:4;;73525:20;:18;:20::i;:::-;:54;;;;:::i;:::-;73488:92;;:20;:92;:::i;:::-;73487:101;;;;:::i;:::-;73463:126;;73639:9;73624:12;:24;:51;;73663:12;73624:51;;;73651:9;73624:51;73602:111;-1:-1:-1;73690:12:0;-1:-1:-1;;73238:483:0;;;;;;:::o;79099:686::-;79242:13;79238:79;;;79272:33;79294:10;79272:21;:33::i;:::-;79364:23;79390:21;;;:12;:21;;;;;;;;79445:10;79426:29;;79422:214;;79519:34;;;;;;;;571:25:1;;;79557:10:0;;79519:48;79529:6;79519:25;;;;544:18:1;;79519:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:48;;;79515:110;;79595:14;;;;;;;;;;;;;;79515:110;79672:49;;;;;79648:129;;79672:34;79682:6;79672:34;;;;:49;;79707:7;;79716:4;;;;79672:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79753:13;79648:9;:129::i;72070:212::-;71395:5;;;;71381:10;:19;;;;:43;;-1:-1:-1;71418:6:0;;;;71404:10;:20;;71381:43;71377:70;;;71433:14;;;;;;;;;;;;;;71377:70;72189:34:::1;:32;:34::i;:::-;72236:17;:38:::0;72070:212::o;71856:206::-;71281:5;;;;71267:10;:19;71263:46;;71295:14;;;;;;;;;;;;;;71263:46;71934:33:::1;:31;:33::i;:::-;71980:12;:28:::0;;;72024:30:::1;::::0;571:25:1;;;72024:30:0::1;::::0;559:2:1;544:18;72024:30:0::1;;;;;;;71856:206:::0;:::o;68513:29::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;72618:612::-;72905:29;;;72746:7;72905:29;;;:20;:29;;;;;;72746:7;;;;72905:36;;72937:4;;72905:36;:::i;:::-;73039;;;72952:20;73039:36;;;:27;:36;;;;;;72885:56;;-1:-1:-1;72952:20:0;73093:4;;73015:21;:19;:21::i;95392:369::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95661:27:0;95680:7;95661:18;:27::i;:::-;95625:63;;-1:-1:-1;95625:63:0;-1:-1:-1;95625:63:0;-1:-1:-1;95625:63:0;95715:18;95729:4;95625:63;95715:18;:::i;:::-;95735:17;95748:4;95735:10;:17;:::i;:::-;95699:54;;;;;;95392:369;;;;;:::o;95950:163::-;96044:7;96076:29;96092:12;96076:15;:29::i;:::-;96069:36;95950:163;-1:-1:-1;;95950:163:0:o;92113:269::-;92208:10;92220:27;;;;:15;:27;;;;;;92182:66;;92208:10;92182:25;:66::i;:::-;92295:10;92277:29;;;;:17;:29;;;;;;92261:65;;92308:11;92321:4;92261:15;:65::i;71720:128::-;71281:5;;;;71267:10;:19;71263:46;;71295:14;;;;;;;;;;;;;;71263:46;71786:6:::1;:16:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;71818:22:::1;::::0;::::1;::::0;-1:-1:-1;;71818:22:0::1;71720:128:::0;:::o;88877:637::-;88968:9;;;;;;;88963:37;;88986:14;;;;;;;;;;;;;;88963:37;89033:8;89013:17;89059:448;89079:9;89075:1;:13;89059:448;;;89107:15;89125:8;;89134:1;89125:11;;;;;;;:::i;:::-;;;;;;;;;;89206:21;;;;:12;:21;;;;;;;;89125:11;;-1:-1:-1;;89206:29:0;;;;:21;;:29;89202:56;;89244:14;;;;;;;;;;;;;;89202:56;89335:21;;;;:12;:21;;;;;;;89328:28;;;;;;89371:60;;;;89410:4;89371:60;;;13810:34:1;89328:28:0;13880:15:1;;;13860:18;;;13853:43;13912:18;;;13905:34;;;89381:6:0;89371:30;;;;13722:18:1;;89371:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89477:3;;;;;89092:415;89059:448;;71605:107;71281:5;;;;71267:10;:19;71263:46;;71295:14;;;;;;;;;;;;;;71263:46;71688:9:::1;:16:::0;;;::::1;::::0;::::1;::::0;;71605:107::o;76870:458::-;76966:12;;76922:7;;77049:18;77045:83;;-1:-1:-1;;77091:25:0;;;76870:458::o;77045:83::-;77306:13;77261:17;;77220:20;;77202:15;:38;;;;:::i;:::-;77201:77;;;;:::i;:::-;:101;;77298:4;77201:101;:::i;:::-;77200:119;;;;:::i;:::-;77158:25;;:162;;;;:::i;92670:339::-;92743:6;;;;92729:10;:20;92725:47;;92758:14;;;;;;;;;;;;;;92725:47;92808:21;;;92785:20;92808:21;;;:15;:21;;;;;;92840:45;92824:4;92808:21;92840:25;:45::i;:::-;92914:12;92898;;:28;;;;;;;:::i;:::-;;;;-1:-1:-1;;;92944:21:0;;;;;;:15;:21;;;;;;;;92937:28;;;92983:12;:18;;;;;92976:25;92670:339::o;75060:213::-;75164:27;;;;;;;:17;:27;;;;;;75129:63;;75154:8;;75129:24;:63::i;:::-;75239:25;;;;;;;:15;:25;;;;;;75203:62;;75229:8;;75203:25;:62::i;:::-;75060:213;:::o;93243:1248::-;93504:10;93342:20;93480:35;;;:23;:35;;;;;;;;;93647:31;;;:22;:31;;;;;;93342:20;;;;;;93607:71;;93480:35;93607:71;:::i;:::-;93691:31;;;;:22;:31;;;;;:58;;;93579:99;;-1:-1:-1;93691:31:0;;93892:27;93714:7;93892:18;:27::i;:::-;97222:12;;97195:15;;;;97187:24;;97214:21;;;;97187:48;;-1:-1:-1;97222:12:0;;-1:-1:-1;93762:157:0;-1:-1:-1;93762:157:0;-1:-1:-1;93987:29:0;94050:45;97187:48;94050:17;:45;:::i;:::-;94019:76;;:15;:76;:::i;:::-;93987:108;;94108:20;94155:10;94131:21;:34;:97;;94207:21;94131:97;;;94181:10;94131:97;94108:120;-1:-1:-1;94277:25:0;94287:6;94277:25;;94317:15;94347:7;94377:19;94392:4;94108:120;94377:19;:::i;:::-;94277:131;;;;;;;;;;;;;;94369:28;94277:131;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94429:12;94457;94444:10;:25;;;;:::i;:::-;94421:62;;;;-1:-1:-1;94472:10:0;;-1:-1:-1;93243:1248:0;;-1:-1:-1;;;;;;;;93243:1248:0:o;90975:1130::-;91162:10;91122:21;91146:27;;;:15;:27;;;;;;91188:15;;91184:625;;91316:20;91312:486;;;91427:6;;91420:44;;;;;91440:10;91420:44;;;14124:74:1;14214:18;;;14207:34;;;91427:6:0;;;;;91420:19;;14097:18:1;;91420:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;91529:10:0;91516:24;;;;:12;:24;;;;;:39;;;;;;-1:-1:-1;91312:486:0;;-1:-1:-1;91312:486:0;;91685:6;;91678:46;;;;;91700:10;91678:46;;;14124:74:1;14214:18;;;14207:34;;;91685:6:0;;;;;91678:21;;14097:18:1;;91678:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;91756:10:0;91743:24;;;;:12;:24;;;;;:39;;91771:11;;-1:-1:-1;91743:24:0;;-1:-1:-1;91743:39:0;;91771:11;;91743:39;:::i;:::-;;;;-1:-1:-1;;91312:486:0;91911:10;91821:22;91898:24;;;:12;:24;;;;;;91846:87;;91873:10;;91846:12;:87::i;:::-;91960:10;91944:27;;;;:15;:27;;;;;:44;;;92041:12;;;:29;;;:45;;;;92026:60;;;-1:-1:-1;;;;90975:1130:0:o;94499:266::-;94561:7;94585:5;94594:1;94585:10;94581:32;;;-1:-1:-1;94604:9:0;;94499:266;-1:-1:-1;94499:266:0:o;94581:32::-;94628:5;94637:3;94628:12;94624:34;;;-1:-1:-1;94649:9:0;;94499:266;-1:-1:-1;94499:266:0:o;94624:34::-;94720:26;94744:1;94736:5;:9;94720:15;:26::i;:::-;94701:16;;:45;;94499:266;-1:-1:-1;;94499:266:0:o;78322:769::-;78406:13;78402:513;;;78463:10;78436:16;78455:19;;;:7;:19;;;;;;78541:23;;;78537:367;;78626:10;78618:19;;;;:7;:19;;;;;:34;;;;;;;;;78537:367;;;78735:12;;78731:173;;78783:10;78775:19;;;;:7;:19;;;;;78768:26;78846:23;;;;;78731:173;78421:494;78402:513;79002:15;;78998:86;;79034:38;;;;;79048:10;79034:38;;;14124:74:1;14214:18;;;14207:34;;;79038:3:0;79034:13;;;;;14097:18:1;;79034:38:0;;;;;;;;;;;;;;;;;;;87845:1024;88040:8;88023:14;88068:794;88088:6;88084:1;:10;88068:794;;;88117:9;88127:1;88117:12;;;;;;;;:::i;:::-;;;;;;;88133:1;88117:17;88113:674;;88170:9;88180:1;88170:12;;;;;;;;:::i;:::-;;;;;;;88159:8;:23;88155:617;;;88217:6;88207:25;;;88259:15;88301:8;;88310:1;88301:11;;;;;;;:::i;:::-;;;;;;;88358:4;88347:5;88353:1;88347:8;;;;;;;;:::i;:::-;;;;;;;:15;;;;:::i;:::-;88207:179;;;;;;;;;;;;;;88339:24;88207:179;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88421:9;88431:1;88421:12;;;;;;;;:::i;:::-;;;;;;;88409:24;;;;;:::i;:::-;;;88155:617;;;88492:6;88482:25;;;88534:15;88576:8;;88585:1;88576:11;;;;;;;:::i;:::-;;;;;;;88661:4;88649:8;88634:9;88644:1;88634:12;;;;;;;;:::i;:::-;;;;;;;88623:5;88629:1;88623:8;;;;;;;;:::i;:::-;;;;;;;:23;;;;:::i;:::-;:34;;;;:::i;:::-;88622:43;;;;:::i;:::-;88482:207;;;;;;;;;;;;;;88614:52;88482:207;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88723:1;88712:12;;88747:5;;88155:617;88832:3;;88068:794;;77514:619;77641:34;:32;:34::i;:::-;77692:23;;77688:362;;77732:17;77752:130;77798:8;77825:19;77863:4;77752:27;:130::i;:::-;77928:17;;;;;;;:7;:17;;;;;:30;;;;;;77732:150;-1:-1:-1;78022:16:0;77732:150;78034:4;78022:16;:::i;:::-;77988:30;;;;;;;:20;:30;;;;;:50;;:30;;;:50;;;;;:::i;:::-;;;;-1:-1:-1;;;77688:362:0;-1:-1:-1;78100:25:0;;78060:37;;;;;;;;:27;:37;;;;;:65;77514:619::o;94773:611::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;95033:15:0;;95046:1;95033:15;;;;;;;;;-1:-1:-1;;;;;;;;95033:15:0;;;;;;;;;;;;;;;;;;;95007:41;;95072:15;95059:28;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:7;95067:1;95059:10;;;;;;;;:::i;:::-;;;;;;:28;;;;95099:30;95131:22;95181:6;95157:59;;;95217:7;95226:8;95157:78;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95098:137;;;;95270:6;95299:5;95305:1;95299:8;;;;;;;;:::i;:::-;;;;;;;95291:17;;95311:4;95291:24;;;;:::i;:::-;95345:12;;95330:28;;;;:14;:28::i;:::-;:35;;95361:4;95330:35;:::i;:::-;95248:128;;;;;;;;;94773:611;;;;;:::o;77336:170::-;77428:21;:19;:21::i;:::-;77400:25;:49;77483:15;77460:20;:38;77336:170::o;75901:158::-;75987:20;:18;:20::i;:::-;75964;:43;76036:15;76018;:33;75901:158::o;79793:1142::-;79901:7;;79856;79938:3;79929:12;;79925:992;;;-1:-1:-1;79969:9:0;;79793:1142;-1:-1:-1;79793:1142:0:o;79925:992::-;80134:1;80126:5;:9;:23;;;;;80147:2;80139:5;:10;80126:23;80122:795;;;-1:-1:-1;80186:4:0;80178:12;80195:1;80177:19;;79793:1142::o;80122:795::-;80231:2;80222:5;:11;;:25;;;;;80245:2;80237:5;:10;80222:25;80218:699;;;80396:2;80388:5;:10;80383:1;:16;80298:55;:102;;80404:3;80297:110;80411:4;80296:119;80268:147;;79793:1142;;;:::o;80218:699::-;80450:2;80441:5;:11;;:25;;;;;80464:2;80456:5;:10;80441:25;80437:480;;;80615:2;80607:5;:10;80602:1;:16;80517:55;:102;;80623:3;80516:110;80630:4;80515:119;80487:147;;79793:1142;;;:::o;80437:480::-;80669:2;80660:5;:11;;:26;;;;;80683:3;80675:5;:11;80660:26;80656:261;;;80817:2;80809:5;:10;80804:1;:16;80737:37;:84;;80825:3;80736:92;80832:4;80735:101;80707:129;;79793:1142;;;:::o;80656:261::-;-1:-1:-1;80884:17:0;;79793:1142;-1:-1:-1;79793:1142:0:o;80656:261::-;79793:1142;;;:::o;76067:610::-;76193:33;:31;:33::i;:::-;76243:23;;76239:363;;76283:17;76303:131;76349:8;76376:19;76414:5;76303:27;:131::i;:::-;76480:17;;;;;;;:7;:17;;;;;:30;;;;;;76283:151;-1:-1:-1;76574:16:0;76283:151;76586:4;76574:16;:::i;:::-;76540:30;;;;;;;:20;:30;;;;;:50;;:30;;;:50;;;;;:::i;:::-;;;;-1:-1:-1;;;76239:363:0;-1:-1:-1;76649:20:0;;76614:32;;;;;;;;:22;:32;;;;;:55;76067:610::o;90703:213::-;90822:7;90854:54;90877:30;90902:5;90877:22;:30;:::i;:::-;90854:22;:54::i;:::-;90847:61;90703:213;-1:-1:-1;;;90703:213:0:o;73729:1133::-;73883:7;73903:17;73931:20;73968:7;73964:864;;;74020:108;74063:8;74090:23;74020:24;:108::i;:::-;74421:27;;;;;;;:17;:27;;;;;;73992:136;;-1:-1:-1;73992:136:0;-1:-1:-1;74322:141:0;;73992:136;;74398:4;;74322:26;:141::i;:::-;74285:33;;;;;;;:23;:33;;;;;:178;;:33;;;:178;;;;;:::i;:::-;;;;-1:-1:-1;73964:864:0;;-1:-1:-1;73964:864:0;;74524:103;74562:8;74589:23;74524:19;:103::i;:::-;74496:131;;-1:-1:-1;74496:131:0;-1:-1:-1;74679:137:0;74496:131;74755:4;74778:23;74679:26;:137::i;:::-;74642:33;;;;;;;:23;:33;;;;;:174;;:33;;;:174;;;;;:::i;:::-;;;;-1:-1:-1;;73964:864:0;-1:-1:-1;74845:9:0;73729:1133;-1:-1:-1;;;;73729:1133:0:o;65824:2171::-;65962:1;66049;66151:35;66145:42;;66135:199;;66281:2;66277:10;;;;;66217:3;66213:11;66135:199;66364:19;66361:1;66358:26;66348:181;;66476:2;66472:10;;;;;66414:2;66410:10;66348:181;66559:11;66556:1;66553:18;66543:173;;66663:2;66659:10;;;;;66601:2;66597:10;66543:173;66746:7;66743:1;66740:14;66730:167;;66846:1;66842:9;;;;;66784:2;66780:10;66730:167;66927:5;66924:1;66921:12;66911:163;;67023:1;67019:9;;;;;66963:1;66959:9;66911:163;67104:4;67101:1;67098:11;67088:162;;67199:1;67195:9;;;;;67139:1;67135:9;67088:162;67280:3;67277:1;67274:10;67264:112;;67359:1;67356;67352:9;67347:14;;67264:112;-1:-1:-1;67470:9:0;;;67463:17;67460:1;67456:25;;;67514:9;;;67507:17;67500:25;;67558:9;;;67551:17;67544:25;;67602:9;;;67595:17;67588:25;;67646:9;;;67639:17;67632:25;;67690:9;;;67683:17;67676:25;;67734:9;;;67727:17;67720:25;;67832:9;;;67910:17;;;67907:70;;;67952:10;67947:15;;67907:70;;65824:2171;;;:::o;62023:771::-;62234:9;;;62368:19;;62361:27;62393:9;;62407;;;62404:16;;62390:31;62357:65;62347:123;;62453:1;62450;62443:12;62347:123;62773:1;62759:11;62755:1;62752;62748:9;62744:27;62740:35;62735:1;62728:9;62721:17;62717:59;62712:64;;62023:771;;;;;:::o;14:154:1:-;100:42;93:5;89:54;82:5;79:65;69:93;;158:1;155;148:12;173:247;232:6;285:2;273:9;264:7;260:23;256:32;253:52;;;301:1;298;291:12;253:52;340:9;327:23;359:31;384:5;359:31;:::i;607:160::-;672:20;;728:13;;721:21;711:32;;701:60;;757:1;754;747:12;772:248;837:6;845;898:2;886:9;877:7;873:23;869:32;866:52;;;914:1;911;904:12;866:52;950:9;937:23;927:33;;979:35;1010:2;999:9;995:18;979:35;:::i;:::-;969:45;;772:248;;;;;:::o;1025:367::-;1088:8;1098:6;1152:3;1145:4;1137:6;1133:17;1129:27;1119:55;;1170:1;1167;1160:12;1119:55;-1:-1:-1;1193:20:1;;1236:18;1225:30;;1222:50;;;1268:1;1265;1258:12;1222:50;1305:4;1297:6;1293:17;1281:29;;1365:3;1358:4;1348:6;1345:1;1341:14;1333:6;1329:27;1325:38;1322:47;1319:67;;;1382:1;1379;1372:12;1397:437;1483:6;1491;1544:2;1532:9;1523:7;1519:23;1515:32;1512:52;;;1560:1;1557;1550:12;1512:52;1600:9;1587:23;1633:18;1625:6;1622:30;1619:50;;;1665:1;1662;1655:12;1619:50;1704:70;1766:7;1757:6;1746:9;1742:22;1704:70;:::i;:::-;1793:8;;1678:96;;-1:-1:-1;1397:437:1;-1:-1:-1;;;;1397:437:1:o;1839:180::-;1898:6;1951:2;1939:9;1930:7;1926:23;1922:32;1919:52;;;1967:1;1964;1957:12;1919:52;-1:-1:-1;1990:23:1;;1839:180;-1:-1:-1;1839:180:1:o;2255:184::-;2307:77;2304:1;2297:88;2404:4;2401:1;2394:15;2428:4;2425:1;2418:15;2444:334;2515:2;2509:9;2571:2;2561:13;;2576:66;2557:86;2545:99;;2674:18;2659:34;;2695:22;;;2656:62;2653:88;;;2721:18;;:::i;:::-;2757:2;2750:22;2444:334;;-1:-1:-1;2444:334:1:o;2783:164::-;2869:52;2862:5;2858:64;2851:5;2848:75;2838:103;;2937:1;2934;2927:12;2952:117;3037:6;3030:5;3026:18;3019:5;3016:29;3006:57;;3059:1;3056;3049:12;3074:114;3158:4;3151:5;3147:16;3140:5;3137:27;3127:55;;3178:1;3175;3168:12;3193:130;3259:20;;3288:29;3259:20;3288:29;:::i;3328:1134::-;3411:6;3464:3;3452:9;3443:7;3439:23;3435:33;3432:53;;;3481:1;3478;3471:12;3432:53;3514:2;3508:9;3556:3;3548:6;3544:16;3626:6;3614:10;3611:22;3590:18;3578:10;3575:34;3572:62;3569:88;;;3637:18;;:::i;:::-;3673:2;3666:22;3710:23;;3742:31;3710:23;3742:31;:::i;:::-;3782:21;;3855:2;3840:18;;3827:32;3868;3827;3868;:::i;:::-;3928:2;3916:15;;3909:32;3993:2;3978:18;;3965:32;4006:31;3965:32;4006:31;:::i;:::-;4065:2;4053:15;;4046:32;4130:2;4115:18;;4102:32;4143:31;4102:32;4143:31;:::i;:::-;4202:2;4190:15;;4183:32;4249:37;4281:3;4266:19;;4249:37;:::i;:::-;4243:3;4235:6;4231:16;4224:63;4321:37;4353:3;4342:9;4338:19;4321:37;:::i;:::-;4315:3;4307:6;4303:16;4296:63;4393:37;4425:3;4414:9;4410:19;4393:37;:::i;:::-;4387:3;4375:16;;4368:63;4379:6;3328:1134;-1:-1:-1;;;3328:1134:1:o;4659:315::-;4727:6;4735;4788:2;4776:9;4767:7;4763:23;4759:32;4756:52;;;4804:1;4801;4794:12;4756:52;4843:9;4830:23;4862:31;4887:5;4862:31;:::i;:::-;4912:5;4964:2;4949:18;;;;4936:32;;-1:-1:-1;;;4659:315:1:o;5232:728::-;5318:6;5326;5334;5342;5395:2;5383:9;5374:7;5370:23;5366:32;5363:52;;;5411:1;5408;5401:12;5363:52;5447:9;5434:23;5424:33;;5508:2;5497:9;5493:18;5480:32;5531:18;5572:2;5564:6;5561:14;5558:34;;;5588:1;5585;5578:12;5558:34;5626:6;5615:9;5611:22;5601:32;;5671:7;5664:4;5660:2;5656:13;5652:27;5642:55;;5693:1;5690;5683:12;5642:55;5733:2;5720:16;5759:2;5751:6;5748:14;5745:34;;;5775:1;5772;5765:12;5745:34;5820:7;5815:2;5806:6;5802:2;5798:15;5794:24;5791:37;5788:57;;;5841:1;5838;5831:12;5788:57;5872:2;5868;5864:11;5854:21;;5894:6;5884:16;;;;;5919:35;5950:2;5939:9;5935:18;5919:35;:::i;:::-;5909:45;;5232:728;;;;;;;:::o;6120:531::-;6162:3;6200:5;6194:12;6227:6;6222:3;6215:19;6252:1;6262:162;6276:6;6273:1;6270:13;6262:162;;;6338:4;6394:13;;;6390:22;;6384:29;6366:11;;;6362:20;;6355:59;6291:12;6262:162;;;6442:6;6439:1;6436:13;6433:87;;;6508:1;6501:4;6492:6;6487:3;6483:16;6479:27;6472:38;6433:87;-1:-1:-1;6565:2:1;6553:15;6570:66;6549:88;6540:98;;;;6640:4;6536:109;;6120:531;-1:-1:-1;;6120:531:1:o;6656:220::-;6805:2;6794:9;6787:21;6768:4;6825:45;6866:2;6855:9;6851:18;6843:6;6825:45;:::i;6961:966::-;7157:4;7199:3;7188:9;7184:19;7176:27;;7249:52;7240:6;7234:13;7230:72;7219:9;7212:91;7371:6;7363:4;7355:6;7351:17;7345:24;7341:37;7334:4;7323:9;7319:20;7312:67;7447:4;7439;7431:6;7427:17;7421:24;7417:35;7410:4;7399:9;7395:20;7388:65;7521:4;7513;7505:6;7501:17;7495:24;7491:35;7484:4;7473:9;7469:20;7462:65;7595:4;7587;7579:6;7575:17;7569:24;7565:35;7558:4;7547:9;7543:20;7536:65;7648:4;7640:6;7636:17;7630:24;7663:52;7709:4;7698:9;7694:20;7680:12;6948:4;6937:16;6925:29;;6881:75;7663:52;;7764:4;7756:6;7752:17;7746:24;7779:54;7827:4;7816:9;7812:20;7796:14;6948:4;6937:16;6925:29;;6881:75;7779:54;-1:-1:-1;7864:3:1;7849:19;;7842:35;;;;7908:3;7893:19;7886:35;6961:966;;-1:-1:-1;6961:966:1:o;7932:572::-;8027:6;8035;8043;8096:2;8084:9;8075:7;8071:23;8067:32;8064:52;;;8112:1;8109;8102:12;8064:52;8152:9;8139:23;8185:18;8177:6;8174:30;8171:50;;;8217:1;8214;8207:12;8171:50;8256:70;8318:7;8309:6;8298:9;8294:22;8256:70;:::i;:::-;8345:8;;-1:-1:-1;8230:96:1;-1:-1:-1;;8430:2:1;8415:18;;8402:32;8443:31;8402:32;8443:31;:::i;:::-;8493:5;8483:15;;;7932:572;;;;;:::o;8509:184::-;8561:77;8558:1;8551:88;8658:4;8655:1;8648:15;8682:4;8679:1;8672:15;8698:125;8738:4;8766:1;8763;8760:8;8757:34;;;8771:18;;:::i;:::-;-1:-1:-1;8808:9:1;;8698:125::o;8828:228::-;8868:7;8994:1;8926:66;8922:74;8919:1;8916:81;8911:1;8904:9;8897:17;8893:105;8890:131;;;9001:18;;:::i;:::-;-1:-1:-1;9041:9:1;;8828:228::o;9061:274::-;9101:1;9127;9117:189;;9162:77;9159:1;9152:88;9263:4;9260:1;9253:15;9291:4;9288:1;9281:15;9117:189;-1:-1:-1;9320:9:1;;9061:274::o;9340:128::-;9380:3;9411:1;9407:6;9404:1;9401:13;9398:39;;;9417:18;;:::i;:::-;-1:-1:-1;9453:9:1;;9340:128::o;9473:251::-;9543:6;9596:2;9584:9;9575:7;9571:23;9567:32;9564:52;;;9612:1;9609;9602:12;9564:52;9644:9;9638:16;9663:31;9688:5;9663:31;:::i;9729:134::-;9806:13;;9828:29;9806:13;9828:29;:::i;9868:1122::-;9932:5;9980:4;9968:9;9963:3;9959:19;9955:30;9952:50;;;9998:1;9995;9988:12;9952:50;10031:2;10025:9;10073:4;10065:6;10061:17;10144:6;10132:10;10129:22;10108:18;10096:10;10093:34;10090:62;10087:88;;;10155:18;;:::i;:::-;10195:10;10191:2;10184:22;;10224:6;10215:15;;10260:9;10254:16;10279:33;10304:7;10279:33;:::i;:::-;10321:23;;10389:2;10374:18;;10368:25;10402:32;10368:25;10402:32;:::i;:::-;10462:2;10450:15;;10443:32;10520:2;10505:18;;10499:25;10533:31;10499:25;10533:31;:::i;:::-;10592:2;10580:15;;10573:32;10650:2;10635:18;;10629:25;10663:31;10629:25;10663:31;:::i;:::-;10722:2;10710:15;;10703:32;10769:48;10812:3;10797:19;;10769:48;:::i;:::-;10763:3;10755:6;10751:16;10744:74;10852:48;10895:3;10884:9;10880:19;10852:48;:::i;:::-;10846:3;10838:6;10834:16;10827:74;10935:48;10978:3;10967:9;10963:19;10935:48;:::i;:::-;10929:3;10921:6;10917:16;10910:74;;9868:1122;;;;:::o;10995:248::-;11089:6;11142:3;11130:9;11121:7;11117:23;11113:33;11110:53;;;11159:1;11156;11149:12;11110:53;11182:55;11229:7;11218:9;11182:55;:::i;11248:437::-;11327:1;11323:12;;;;11370;;;11391:61;;11445:4;11437:6;11433:17;11423:27;;11391:61;11498:2;11490:6;11487:14;11467:18;11464:38;11461:218;;;11535:77;11532:1;11525:88;11636:4;11633:1;11626:15;11664:4;11661:1;11654:15;11816:1157;11901:12;;11866:3;;11956:1;11976:18;;;;12029;;;;12056:61;;12110:4;12102:6;12098:17;12088:27;;12056:61;12136:2;12184;12176:6;12173:14;12153:18;12150:38;12147:218;;;12221:77;12218:1;12211:88;12322:4;12319:1;12312:15;12350:4;12347:1;12340:15;12147:218;6052:19;;;6104:4;6095:14;;12451:18;12478:162;;;;12654:1;12649:318;;;;12444:523;;12478:162;12528:66;12517:9;12513:82;12506:5;12499:97;12627:2;12620:5;12616:14;12609:21;;12478:162;;12649:318;11763:1;11756:14;;;11800:4;11787:18;;12743:1;12757:167;12771:6;12768:1;12765:13;12757:167;;;12851:14;;12836:13;;;12829:37;12894:16;;;;12786:10;;12757:167;;;12944:13;;;-1:-1:-1;;12444:523:1;;;;;;;;11816:1157;;;;:::o;12978:375::-;13188:2;13177:9;13170:21;13151:4;13208:53;13257:2;13246:9;13242:18;13234:6;13208:53;:::i;:::-;13292:2;13277:18;;13270:34;;;;-1:-1:-1;13335:2:1;13320:18;13313:34;13200:61;12978:375;-1:-1:-1;12978:375:1:o;13358:184::-;13410:77;13407:1;13400:88;13507:4;13504:1;13497:15;13531:4;13528:1;13521:15;14252:520;14439:6;14428:9;14421:25;14482:2;14477;14466:9;14462:18;14455:30;14521:6;14516:2;14505:9;14501:18;14494:34;14578:6;14570;14565:2;14554:9;14550:18;14537:48;14634:1;14605:22;;;14629:2;14601:31;;;14594:42;;;;14688:2;14676:15;;;14693:66;14672:88;14657:104;14653:113;;14252:520;-1:-1:-1;;14252:520:1:o;14777:184::-;14847:6;14900:2;14888:9;14879:7;14875:23;14871:32;14868:52;;;14916:1;14913;14906:12;14868:52;-1:-1:-1;14939:16:1;;14777:184;-1:-1:-1;14777:184:1:o;15338:935::-;15528:4;15576:2;15565:9;15561:18;15606:2;15595:9;15588:21;15629:6;15664;15658:13;15695:6;15687;15680:22;15733:2;15722:9;15718:18;15711:25;;15795:2;15785:6;15782:1;15778:14;15767:9;15763:30;15759:39;15745:53;;15817:4;15856:2;15848:6;15844:15;15877:1;15887:314;15901:6;15898:1;15895:13;15887:314;;;15990:66;15978:9;15970:6;15966:22;15962:95;15957:3;15950:108;16081:40;16114:6;16105;16099:13;16081:40;:::i;:::-;16071:50;-1:-1:-1;16179:12:1;;;;16144:15;;;;15923:1;15916:9;15887:314;;;-1:-1:-1;;16240:18:1;;;;16233:34;;;;16218:6;15338:935;-1:-1:-1;;;;15338:935:1:o;16278:1064::-;16406:6;16414;16467:3;16455:9;16446:7;16442:23;16438:33;16435:53;;;16484:1;16481;16474:12;16435:53;16507:55;16554:7;16543:9;16507:55;:::i;:::-;16497:65;;16606:3;16595:9;16591:19;16585:26;16630:18;16671:2;16663:6;16660:14;16657:34;;;16687:1;16684;16677:12;16657:34;16725:6;16714:9;16710:22;16700:32;;16770:7;16763:4;16759:2;16755:13;16751:27;16741:55;;16792:1;16789;16782:12;16741:55;16821:2;16815:9;16843:4;16866:2;16862;16859:10;16856:36;;;16872:18;;:::i;:::-;16918:2;16915:1;16911:10;16901:20;;16941:28;16965:2;16961;16957:11;16941:28;:::i;:::-;17003:15;;;17073:11;;;17069:20;;;17034:12;;;;17101:19;;;17098:39;;;17133:1;17130;17123:12;17098:39;17157:11;;;;17177:135;17193:6;17188:3;17185:15;17177:135;;;17259:10;;17247:23;;17210:12;;;;17290;;;;17177:135;;;17331:5;17321:15;;;;;;;;16278:1064;;;;;:::o

Swarm Source

ipfs://7553e46202818fd396c723f5235a499b3752da913dcd87ac2a7f858425538bdc
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.