Contract 0x780feb71117157a039e682668d79584d18579e90 3

Contract Overview

Balance:
0 AVAX

AVAX Value:
$0.00

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x9e780caedde55afc0a1af98f567f6156ee38a217a277fd484d18a0f35186ec09Level Up202551112022-09-25 10:33:4313 mins ago0x4ddddec846560e2125f13728c7e6c03a9bf2c299 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0044717955 26.5
0x1b58898478f9f12704e15bb817ff1ec02fa3980f1b31fe521c1b8a7113d9885dLevel Up202546742022-09-25 10:18:3128 mins ago0x5e361f4eca711beb97b864e31e52497f398d1d78 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.00518252279 26.71582524
0x159f4bb0a457d8ea24dff07a29cc12da9884483b51ea14deda3eab8182519b4bLevel Up202538132022-09-25 9:48:3258 mins ago0x33a6514ba9a79fbf74ff1a9d08ab7eb44742c8f0 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0044695165 26.5
0xf1f2152d224565c96484d9a156781245bae5089dfc2260996078bcae34cd61bcLevel Up202537882022-09-25 9:47:3959 mins ago0x33a6514ba9a79fbf74ff1a9d08ab7eb44742c8f0 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0044695165 26.5
0x3338f571cd01e94d648681cde7f2f1d67d847dd3a5a51d4e2efe71a04f5213b8Level Up202537572022-09-25 9:46:371 hr ago0x33a6514ba9a79fbf74ff1a9d08ab7eb44742c8f0 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0049271715 26.5
0x4308ae627887e9e7b506873a88bc758da01adab09412f6fa91a0a0014fe89b10Level Up202536332022-09-25 9:42:221 hr 4 mins ago0x46f0849df698b6c5e31936b21ea28f301fb8d7e2 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.00456092127
0xe326221c93979c4a1c96bb4754171b529aea9624e5c90298fae5989cdf42b061Claim202511332022-09-25 8:14:522 hrs 32 mins ago0x0eed12b3b1637817b4bb3d4b12f6db6df8ef0eff IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.002815099649 27.146835064
0x899c987d3657efa11e8d1cdc94e186ea358e3204af7df31427723bc1c373905aLevel Up202511222022-09-25 8:14:242 hrs 32 mins ago0xcc914544e614d9021893f83971db6902a8ad5693 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.004581864662 27.213232025
0x1419a6107cf8ddefacbb77a88b3c7a0b7044478c7004b10ef065cd6615d60684Level Up202510902022-09-25 8:13:192 hrs 33 mins ago0xcc914544e614d9021893f83971db6902a8ad5693 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0044615135 26.5
0x4a2540fc5cff616d599d17dd7eda0fffeedfb01b3b1d06cd86bd7ff441573803Vote202503992022-09-25 7:49:192 hrs 57 mins ago0xb8385200a0df3588a8c113c870bba3ac0ce75a6f IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.003744761824 26.3254
0xc8b63449da812d30eb3b5187e64abd36bfdf271c2335aec3f5c9126b8654b4b7Level Up202498482022-09-25 7:30:203 hrs 16 mins ago0x0eb205bf618e02f1bddce00c7d3b468b2e2f72f8 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0042347795 26.5
0xf1ce791d9c2f3b1b5abd9ef1fa2fb2a1ac69e7ec383fc51725445b122f9fe3baClaim202477572022-09-25 6:17:234 hrs 29 mins ago0x8047e8e33fab6caec0841a575b3f7e266f6f745a IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0032011735 26.5
0xe19d0707f068b38f52c34a0bcd6a25068c40c7c50caceba96d814b0f8a8b55e0Vote202475712022-09-25 6:11:014 hrs 35 mins ago0xc5c8a07ca60a3d3dc308f9c8e65fb6e207c155cb IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0037695985 26.5
0x79b7001bb05356a468b08ae96cf9fb9dc4b122e12381fe2d23bdb613c1fc9d8dExit202460342022-09-25 5:17:345 hrs 29 mins ago0xac55b64d8c1420af909d3ea07777114cad3ca50c IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.00502870169 26.41
0x21d7bccaba77ce805fb6a480aa777e823862ccd517d1c623fa939032f6496c8aLevel Up202459862022-09-25 5:15:565 hrs 31 mins ago0xac55b64d8c1420af909d3ea07777114cad3ca50c IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0046797675 26.5
0xc2d782ffeb930ccb3da99f6983a524cdf6d04954d7e2fc0f5031e0125e820ee1Level Up202444732022-09-25 4:23:356 hrs 23 mins ago0xf7e997e44fb2072367e3589f4540cb14d8688f2e IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.0044740215 26.5
0xcb2edf0bba41baffac348c18e452dc03f924bec02524e8dce05ea7f524273d54Level Up202443892022-09-25 4:20:426 hrs 26 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005051292915 27.213232025
0xdb249ae8f44c1b0a143904f2f6fac7e7308a9b69cdfa05c24aba5c900f383f59Level Up202443762022-09-25 4:20:146 hrs 26 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005077425519 27.35225
0x14de7d977e3ca60d534801080c149d1947969eb6c133e851c011acc96aeafde8Level Up202443732022-09-25 4:20:086 hrs 26 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005082348924 27.35225
0x8e21d617c4ef7d1b89518e23c3573e356d7d3723466d1c263b07c08774e45044Level Up202443712022-09-25 4:20:046 hrs 26 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005559897675 27.425
0x8423e42eb89ae1f98c24ba40e1ea08ba3cdab3edd2d707489c62c68f3fba804dLevel Up202442372022-09-25 4:15:156 hrs 31 mins ago0x7b5e791a441427689424aca062021e415436cb45 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005516808666 27.211115
0x28f391e0287728624d97efc29d887bc942a913fb597f5d40e35d2ac9499585f4Level Up202442312022-09-25 4:15:046 hrs 31 mins ago0x7b5e791a441427689424aca062021e415436cb45 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.004987265469 27.2795
0x2d3e8f3c85d473ef4b33c4f3c0ef16232ea5cc51f6a53237b68d9abdc6aa868aClaim202441882022-09-25 4:13:376 hrs 33 mins ago0x7b5e791a441427689424aca062021e415436cb45 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.003761843918 27.2816825
0x35731f2353ddfbf4f7152627c5982d8f65df9f57aa9bcb896145ad7e21d409d8Level Up202440792022-09-25 4:09:526 hrs 37 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005094385725 27.425
0x8a1dbd5eb74eb9417362f80a6d70a14545c8bdb7d17ad37646f3436552c6aa77Level Up202440732022-09-25 4:09:406 hrs 37 mins ago0x2b602a68da26ad5eb0eceb9d5c9472031ac8b311 IN  0x780feb71117157a039e682668d79584d18579e900 AVAX0.005094714825 27.425
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Stream

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion, Unlicense 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 Stream 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.agility) * 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"}]

60e06040523480156200001157600080fd5b5060405162003bac38038062003bac83398101604081905262000034916200017c565b600480546001600160a01b031916331790556001600160a01b0380841660805280831660a052811660c0526003600f908155604080518082019091528181526e4c4556454c5f47415547455f4b455960881b6020909101908152849184918491620000a291600091620000b9565b505042600881905560125550620002039350505050565b828054620000c790620001c6565b90600052602060002090601f016020900481019282620000eb576000855562000136565b82601f106200010657805160ff191683800117855562000136565b8280016001018555821562000136579182015b828111156200013657825182559160200191906001019062000119565b506200014492915062000148565b5090565b5b8082111562000144576000815560010162000149565b80516001600160a01b03811681146200017757600080fd5b919050565b6000806000606084860312156200019257600080fd5b6200019d846200015f565b9250620001ad602085016200015f565b9150620001bd604085016200015f565b90509250925092565b600181811c90821680620001db57607f821691505b60208210811415620001fd57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05161392562000287600039600081816104cf0152818161084901528181611027015281816115c7015281816117bd015281816118b601528181611e3a0152818161217e0152818161257a015281816126940152612997015260006104430152600081816107840152818161128a01526124d101526139256000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c806379f409e0116101b2578063ad914e2e116100f9578063d881e959116100a2578063e42c4e631161007c578063e42c4e63146107a6578063e532a154146107ae578063ee569ba9146107b6578063f5544eb7146107d657600080fd5b8063d881e9591461074c578063dee935681461075f578063e1a61a0c1461077f57600080fd5b8063c9d27afe116100d3578063c9d27afe14610701578063caa6fea414610714578063d051bfa31461073957600080fd5b8063ad914e2e146106c3578063bf856895146106e5578063bf9bc0b2146106ee57600080fd5b806396afc4501161015b578063a49a3e1b11610135578063a49a3e1b1461067b578063ab20355c14610690578063ac3910a2146106a357600080fd5b806396afc4501461064c5780639d4c93c414610655578063a1bdb15e1461066857600080fd5b80638da5cb5b1161018c5780638da5cb5b146105f95780638eb3be2814610619578063968c603d1461062c57600080fd5b806379f409e0146105915780637e2d9af8146105b9578063818ae1ce146105d957600080fd5b80633cfa989e116102815780635834c36d1161022a5780635d35b5d5116102045780635d35b5d51461053e5780636351520e14610547578063769022a31461055a5780637944135d1461057e57600080fd5b80635834c36d14610502578063591adce61461050b5780635c1ab8c01461051e57600080fd5b80634b905e3f1161025b5780634b905e3f146104ca5780634b9ca431146104f15780634e71d92d146104fa57600080fd5b80633cfa989e1461048e578063402914f5146104ae57806343aba89d146104c157600080fd5b80631c1502c4116102e35780632677d07f116102bd5780632677d07f1461043e5780632df97550146104655780633bad0f711461048557600080fd5b80631c1502c4146103ba578063201e29a0146103c3578063215e0f4d1461041e57600080fd5b80630c679fa0116103145780630c679fa01461037f57806313af40351461039457806318c08f26146103a757600080fd5b80630700037d1461033b5780630ab747f01461036e5780630b24216314610377575b600080fd5b61035b610349366004612f48565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61035b60095481565b61035b6107e9565b61039261038d366004612f75565b610847565b005b6103926103a2366004612f48565b610cdd565b6103926103b5366004612fe6565b610d9d565b61035b60135481565b6103f96103d1366004613028565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b61035b61042c366004612f48565b600a6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b610473366004612f48565b60146020526000908152604090205481565b61035b60075481565b61035b61049c366004612f48565b600d6020526000908152604090205481565b61035b6104bc366004612f48565b61112e565b61035b60105481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b60115481565b610392611221565b61035b60125481565b610392610519366004612f75565b6112e9565b61035b61052c366004612f48565b600c6020526000908152604090205481565b61035b600f5481565b610392610555366004613028565b6113ab565b61056e610568366004613110565b50600190565b6040519015158152602001610365565b61039261058c366004612fe6565b611401565b6105a461059f3660046131c8565b61168a565b60408051928352602083019190915201610365565b61035b6105c7366004612f48565b60166020526000908152604090205481565b61035b6105e7366004612f48565b600b6020526000908152604090205481565b6004546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6103926106273660046131f4565b61173c565b61035b61063a366004613028565b60026020526000908152604090205481565b61035b60065481565b610392610663366004613028565b611938565b610392610676366004613028565b6119bc565b610683611a50565b60405161036591906132ec565b6105a461069e3660046131c8565b611ade565b6005546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6106d66106d1366004613028565b611b54565b604051610365939291906132ff565b61035b60085481565b61035b6106fc366004613028565b611bca565b61039261070f366004612f75565b611bdb565b60055461056e9074010000000000000000000000000000000000000000900460ff1681565b610392610747366004612f48565b611c11565b61039261075a366004613398565b611cd1565b61035b61076d366004613028565b600e6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b610392611ea2565b61035b611f34565b61035b6107c4366004612f48565b60156020526000908152604090205481565b6103926107e4366004612f48565b611f8c565b600754600090806107fc57505060095490565b806006546008544261080e919061341e565b6108189190613435565b61082a90670de0b6b3a7640000613435565b6108349190613472565b60095461084191906134ad565b91505090565b7f000000000000000000000000000000000000000000000000000000000000000081156108775761087733612059565b60008381526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114610981576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101859052339073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa158015610910573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093491906134c5565b73ffffffffffffffffffffffffffffffffffffffff1614610981576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5c5503530000000000000000000000000000000000000000000000000000000081526004810185905260009073ffffffffffffffffffffffffffffffffffffffff841690635c5503539060240160e060405180830381865afa1580156109ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1391906135aa565b905073ffffffffffffffffffffffffffffffffffffffff8216331415610b9c5783610a4157610a4133612059565b6000610a4c866120be565b50835160608501516001820178ffffffffffffffffffffffffffffffffffffffffffffffffff90811680885293955060ff909116911681029250026000610a93838361341e565b336000908152600a6020526040812080548301908190556007805484019055919250610ac190829080612243565b50336000908152600c602052604081205485811015610ae757610ae4818761341e565b91505b610af1828761341e565b8751610b179078ffffffffffffffffffffffffffffffffffffffffffffffffff166123f5565b610b269064e8d4a51000613435565b610b30919061341e565b336000908152600c602052604081208054909190610b4f9084906134ad565b909155505086517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0178ffffffffffffffffffffffffffffffffffffffffffffffffff1687525050505050505b610bcd610bc7826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16611bca565b8561243e565b6040517f0ce90ec20000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff841690630ce90ec290602401600060405180830381600087803b158015610c3557600080fd5b505af1158015610c49573d6000803e3d6000fd5b50506040517f3d68b4b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250633d68b4b59150610ca490600090899082906004016136eb565b600060405180830381600087803b158015610cbe57600080fd5b505af1158015610cd2573d6000803e3d6000fd5b505050505050505050565b60045473ffffffffffffffffffffffffffffffffffffffff163314610d2e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f957090e72c0a1b3ebf83c682eb8c1f88c2a18cd0578b91a819efb28859f0f3a390600090a250565b60055474010000000000000000000000000000000000000000900460ff1615610df2576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dfb33612059565b336000908152600a6020908152604080832054600c90925282205490918291849190818367ffffffffffffffff811115610e3757610e37613041565b604051908082528060200260200182016040528015610e60578160200160208202803683370190505b50905060008767ffffffffffffffff811115610e7e57610e7e613041565b604051908082528060200260200182016040528015610ea7578160200160208202803683370190505b50905060005b858110156110925760008a8a83818110610ec957610ec9613710565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff163314610f35576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610f43846120be565b91945092509050610f54838c61341e565b9a50610f60828a6134ad565b985081878681518110610f7557610f75613710565b60200260200101818152505080868681518110610f9457610f94613710565b6020908102919091018101919091526000858152600190915260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810185905273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b15801561106b57600080fd5b505af115801561107f573d6000803e3d6000fd5b5050505084600101945050505050610ead565b50336000908152600a60205260409020869055838310156110d8576110c3898984846110be888a61341e565b61252a565b336000908152600c6020526040812055611117565b856110f257336000908152600c6020526040812055611117565b336000908152600c60205260408120805486929061111190849061341e565b90915550505b6007805487018890039055610cd286600080612243565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600c602052604081205481906111669064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600a60205260408120549192509061119b90859061168a565b5073ffffffffffffffffffffffffffffffffffffffff8516600090815260146020526040812054919250906111d1908690611ade565b5090506111de81836134ad565b91508282116111ed57816111ef565b825b73ffffffffffffffffffffffffffffffffffffffff909516600090815260036020526040902054909401949350505050565b61122a33612059565b336000818152600360205260408082208054929055517f40c10f190000000000000000000000000000000000000000000000000000000081526004810192909252602482018190529073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b1580156112ce57600080fd5b505af11580156112e2573d6000803e3d6000fd5b5050505050565b3360008181526014602052604090205461130391906127c0565b336000908152600a602052604081205461131e918490612243565b80156113a757600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306661abd6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561138e57600080fd5b505af11580156113a2573d6000803e3d6000fd5b505050505b5050565b60045473ffffffffffffffffffffffffffffffffffffffff1633146113fc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f55565b60055474010000000000000000000000000000000000000000900460ff1615611456576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61145f33612059565b336000908152600a6020908152604080832054600d90925282205490918291849190815b8381101561164757600088888381811061149f5761149f613710565b602090810292909201356000818152600e909352604083208690559250819050806114c984612881565b9250925092506114d7600190565b61150d576040517f0ce023b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251606084015160ff1678ffffffffffffffffffffffffffffffffffffffffffffffffff9091160290980197611543828261341e565b61154d90886134ad565b6000858152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163390811790915590517f23b872dd0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018690529097507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b15801561162057600080fd5b505af1158015611634573d6000803e3d6000fd5b5050505084600101945050505050611483565b50336000908152600a60209081526040808320879055600c9091528120805484019055600780548601879003905561168190859080612243565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040812054819081906116c49064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600b602052604081205491925090670de0b6b3a7640000906117006107e9565b61170a919061341e565b6117149087613435565b61171e9190613472565b905081811161172d578061172f565b815b93509150505b9250929050565b801561174b5761174b33612059565b60008481526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114611875576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052339073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015611804573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182891906134c5565b73ffffffffffffffffffffffffffffffffffffffff1614611875576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc60fb6a70000000000000000000000000000000000000000000000000000000081526112e29073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c60fb6a7906118ef9089908990899060040161373f565b6020604051808303816000875af115801561190e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119329190613793565b8361243e565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611978575060055473ffffffffffffffffffffffffffffffffffffffff163314155b156119af576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119b7612acb565b601055565b60045473ffffffffffffffffffffffffffffffffffffffff163314611a0d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a15612adc565b60068190556040518181527f90e51e492b1841b8ed3d459463d02d171ced752c7fcd84a9dd79f90098166aec9060200160405180910390a150565b60008054611a5d906135c6565b80601f0160208091040260200160405190810160405280929190818152602001828054611a89906135c6565b8015611ad65780601f10611aab57610100808354040283529160200191611ad6565b820191906000526020600020905b815481529060010190602001808311611ab957829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604081205481908190611b189064e8d4a5100090613472565b73ffffffffffffffffffffffffffffffffffffffff861660009081526015602052604081205491925090670de0b6b3a764000090611700611f34565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529080611b9784612881565b9194509250905082611bae64e8d4a5100084613472565b611bbd64e8d4a5100084613472565b9250925092509193909250565b6000611bd582612aed565b92915050565b33600081815260146020526040902054611bf591906127c0565b336000908152600a602052604090205461131e90836001612243565b60045473ffffffffffffffffffffffffffffffffffffffff163314611c62576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f605aa74980dc92c245d8959d233f8c2d7062d874e49326a42e7418279cc8d1f890600090a250565b60055474010000000000000000000000000000000000000000900460ff16611d25576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160005b818110156112e2576000858583818110611d4557611d45613710565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff858116911614611db4576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b158015611e7e57600080fd5b505af1158015611e92573d6000803e3d6000fd5b5050505081600101915050611d29565b60045473ffffffffffffffffffffffffffffffffffffffff163314611ef3576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60115460009080611f4757505060135490565b8060105460125442611f59919061341e565b611f639190613435565b611f7590670de0b6b3a7640000613435565b611f7f9190613472565b60135461084191906134ad565b60055473ffffffffffffffffffffffffffffffffffffffff163314611fdd576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205461200d82826127c0565b806011600082825461201f919061341e565b90915550505073ffffffffffffffffffffffffffffffffffffffff1660009081526014602090815260408083208390556016909152812055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a602052604090205461208a908290612c41565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601460205260409020546120bb9082906127c0565b50565b336000908152600d6020908152604080832054848452600e9092528220548291829182906120ec908361341e565b6000878152600e60205260408120849055909150808061210b89612881565b8251606084015160ff1678ffffffffffffffffffffffffffffffffffffffffffffffffff909116029a509194509250905060006121488986613435565b61215290846134ad565b905060008282116121635781612165565b825b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016633d68b4b560008d6121b564e8d4a5100086613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526121f0939291906004016136eb565b600060405180830381600087803b15801561220a57600080fd5b505af115801561221e573d6000803e3d6000fd5b5050505089818461222f919061341e565b909c909b5092995091975050505050505050565b3360009081526014602052604090205482156123b4578115612304576005546040517f5f74bbde0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff90911690635f74bbde90604401600060405180830381600087803b1580156122d157600080fd5b505af11580156122e5573d6000803e3d6000fd5b5050336000908152601660205260409020805486019055506123b49050565b6005546040517f02aa9be20000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff909116906302aa9be290604401600060405180830381600087803b15801561237657600080fd5b505af115801561238a573d6000803e3d6000fd5b505033600090815260166020526040812080548794509092506123ae90849061341e565b90915550505b336000908152601660205260408120546123cf908690612d02565b336000908152601460205260409020819055601180549091019290920390915550505050565b6000816001141561240f57506714d1120d7b160000919050565b81606414156124285750680ff011d2523cd80000919050565b61243460018303612aed565b600f540292915050565b8015612496573360009081526003602052604090205482811061247857336000908152600360205260408120805494909403909355612494565b8015612494573360009081526003602052604081205591829003915b505b81156113a7576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639dc29fac90604401600060405180830381600087803b15801561138e57600080fd5b8360005b818110156116815784818151811061254857612548613710565b60200260200101516000146127b85784818151811061256957612569613710565b6020026020010151831115612692577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b560008989858181106125c8576125c8613710565b9050602002013564e8d4a510008886815181106125e7576125e7613710565b60200260200101516125f99190613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152612634939291906004016136eb565b600060405180830381600087803b15801561264e57600080fd5b505af1158015612662573d6000803e3d6000fd5b5050505084818151811061267857612678613710565b60200260200101518361268b919061341e565b92506127b8565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b560008989858181106126e2576126e2613710565b9050602002013564e8d4a51000878a878151811061270257612702613710565b60200260200101518a888151811061271c5761271c613710565b602002602001015161272e919061341e565b61273891906134ad565b6127429190613472565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261277d939291906004016136eb565b600060405180830381600087803b15801561279757600080fd5b505af11580156127ab573d6000803e3d6000fd5b5050505060009250611681565b60010161252e565b6127c8612acb565b80156128545760006127dc83836001612d1d565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040902080548201905590506128188164e8d4a51000613435565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c60205260408120805490919061284d90849061341e565b9091555050505b5060135473ffffffffffffffffffffffffffffffffffffffff909116600090815260156020526040902055565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905283516001808252818601909552929391928392839282015b60608152602001906001900390816128d2579050509050600080546128f6906135c6565b80601f0160208091040260200160405190810160405280929190818152602001828054612922906135c6565b801561296f5780601f106129445761010080835404028352916020019161296f565b820191906000526020600020905b81548152906001019060200180831161295257829003601f168201915b50505050508160008151811061298757612987613710565b60200260200101819052506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630d51186584896040518363ffffffff1660e01b81526004016129f09291906137ac565b600060405180830381865afa158015612a0d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612a539190810190613833565b915091508181600081518110612a6b57612a6b613710565b602002602001015160001c64e8d4a51000612a869190613435565b8351612aac9078ffffffffffffffffffffffffffffffffffffffffffffffffff166123f5565b612abb9064e8d4a51000613435565b9550955095505050509193909250565b612ad3611f34565b60135542601255565b612ae46107e9565b60095542600855565b60010160006064821415612b0b575068206aeac7a903980000919050565b600182118015612b1b5750601582105b15612b315750670de0b6b3a76400000260011c90565b60158210158015612b425750603382105b15612b8057601582036007027a01223448501f3c74e1b3464c172c54a9426488901e3c70d183058a901c607f16670de0b6b3a7640000029050919050565b60338210158015612b915750605182105b15612bcf57603382036007027a023c68b0e14180f9ebc76e9c376cd5a3262c17ae5ab15a9509d325901c607f16670de0b6b3a7640000029050919050565b60518210158015612be05750606582105b15612c155760518203600702710c58705ebb6ed59af5aad3a5467ce9b2e549901c607f16670de0b6b3a7640000029050919050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff919050565b919050565b612c49612adc565b8015612cd5576000612c5d83836000612d1d565b73ffffffffffffffffffffffffffffffffffffffff841660009081526003602052604090208054820190559050612c998164e8d4a51000613435565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612cce90849061341e565b9091555050505b5060095473ffffffffffffffffffffffffffffffffffffffff9091166000908152600b6020526040902055565b6000612d16612d118385613435565b612e12565b9392505050565b60008060008315612daf57612d328686611ade565b73ffffffffffffffffffffffffffffffffffffffff88166000908152600a60205260409020549193509150612d6f90829064e8d4a5100090612ef8565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612da49084906134ad565b90915550612e099050565b612db9868661168a565b9092509050612dce8164e8d4a5100087612ef8565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612e039084906134ad565b90915550505b50949350505050565b6001817001000000000000000000000000000000008110612e385760409190911b9060801c5b680100000000000000008110612e535760209190911b9060401c5b6401000000008110612e6a5760109190911b9060201c5b620100008110612e7f5760089190911b9060101c5b6101008110612e935760049190911b9060081c5b60108110612ea65760029190911b9060041c5b60088110612eb5578160011b91505b5080820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c80820481811015612ef2578091505b50919050565b828202811515841585830485141716612f1057600080fd5b6001826001830304018115150290509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146120bb57600080fd5b600060208284031215612f5a57600080fd5b8135612d1681612f26565b80358015158114612c3c57600080fd5b60008060408385031215612f8857600080fd5b82359150612f9860208401612f65565b90509250929050565b60008083601f840112612fb357600080fd5b50813567ffffffffffffffff811115612fcb57600080fd5b6020830191508360208260051b850101111561173557600080fd5b60008060208385031215612ff957600080fd5b823567ffffffffffffffff81111561301057600080fd5b61301c85828601612fa1565b90969095509350505050565b60006020828403121561303a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156130b7576130b7613041565b604052919050565b78ffffffffffffffffffffffffffffffffffffffffffffffffff811681146120bb57600080fd5b61ffff811681146120bb57600080fd5b60ff811681146120bb57600080fd5b8035612c3c816130f6565b600060e0828403121561312257600080fd5b60405160e0810181811067ffffffffffffffff8211171561314557613145613041565b6040528235613153816130bf565b81526020830135613163816130e6565b60208201526040830135613176816130f6565b60408201526060830135613189816130f6565b606082015261319a60808401613105565b60808201526131ab60a08401613105565b60a08201526131bc60c08401613105565b60c08201529392505050565b600080604083850312156131db57600080fd5b82356131e681612f26565b946020939093013593505050565b6000806000806060858703121561320a57600080fd5b84359350602085013567ffffffffffffffff8082111561322957600080fd5b818701915087601f83011261323d57600080fd5b81358181111561324c57600080fd5b88602082850101111561325e57600080fd5b60208301955080945050505061327660408601612f65565b905092959194509250565b6000815180845260005b818110156132a75760208185018101518683018201520161328b565b818111156132b9576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612d166020830184613281565b60006101208201905078ffffffffffffffffffffffffffffffffffffffffffffffffff855116825261ffff602086015116602083015260ff604086015116604083015260ff606086015116606083015260ff608086015116608083015260a085015161337060a084018260ff169052565b5060c085015161338560c084018260ff169052565b5060e08201939093526101000152919050565b6000806000604084860312156133ad57600080fd5b833567ffffffffffffffff8111156133c457600080fd5b6133d086828701612fa1565b90945092505060208401356133e481612f26565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613430576134306133ef565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561346d5761346d6133ef565b500290565b6000826134a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082198211156134c0576134c06133ef565b500190565b6000602082840312156134d757600080fd5b8151612d1681612f26565b8051612c3c816130f6565b600060e082840312156134ff57600080fd5b60405160e0810181811067ffffffffffffffff8211171561352257613522613041565b80604052508091508251613535816130bf565b81526020830151613545816130e6565b60208201526040830151613558816130f6565b6040820152606083015161356b816130f6565b606082015261357c608084016134e2565b608082015261358d60a084016134e2565b60a082015261359e60c084016134e2565b60c08201525092915050565b600060e082840312156135bc57600080fd5b612d1683836134ed565b600181811c908216806135da57607f821691505b60208210811415612ef2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061362e57607f831692505b6020808410821415613669577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8388526020880182801561368457600181146136b3576136de565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008716825282820197506136de565b60008981526020902060005b878110156136d8578154848201529086019084016136bf565b83019850505b5050505050505092915050565b6060815260006136fe6060830186613614565b60208301949094525060400152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156137a557600080fd5b5051919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015613821577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261380f868351613281565b955093820193908201906001016137d5565b50509490940194909452949350505050565b600080610100838503121561384757600080fd5b61385184846134ed565b915060e083015167ffffffffffffffff8082111561386e57600080fd5b818501915085601f83011261388257600080fd5b815160208282111561389657613896613041565b8160051b92506138a7818401613070565b82815292840181019281810190898511156138c157600080fd5b948201945b848610156138df578551825294820194908201906138c6565b809650505050505050925092905056fea2646970667358221220f7ef447e3703d3177d1f3600f69cb2dfdb353eab43212272be9dbdee688eb56264736f6c634300080c003300000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe28000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa273240000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b

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:610: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;96838:157::-;;;;;;:::i;:::-;-1:-1:-1;96983:4:0;;96838:157;;;;4632:14:1;;4625:22;4607:41;;4595:2;4580:18;96838: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;97223:12:0;;97197:14;;;;82167;;;97215:21;82167:14;;;;;;81902:62;;-1:-1:-1;97189:23:0;;;;97215:21;;97189:47;;;-1:-1:-1;97189:47:0;82070:23;82418:32;97189:47;;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;96983:4;;96838:157;84610:16;84605:43;;84635:13;;;;;;;;;;;;;;84605:43;97223:12;;97197:14;;;;97189:23;;97215:21;;;;97189:47;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;:::-;97223:12;;97197:14;;;;97189:23;;97215:21;;;;97189:47;;-1:-1:-1;97223:12:0;;-1:-1:-1;93762:157:0;-1:-1:-1;93762:157:0;-1:-1:-1;93987:29:0;94050:45;97189:47;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://f7ef447e3703d3177d1f3600f69cb2dfdb353eab43212272be9dbdee688eb562
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.