AVAX Price: $22.40 (+4.82%)
Gas: 1 nAVAX
 

Overview

AVAX Balance

Avalanche C-Chain LogoAvalanche C-Chain LogoAvalanche C-Chain Logo0 AVAX

AVAX Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Level Up607972362025-04-23 12:58:001 hr ago1745413080IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000299771.61197298
Level Up607972242025-04-23 12:57:361 hr ago1745413056IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000301261.61688861
Level Up607972162025-04-23 12:57:261 hr ago1745413046IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000300571.6163184
Level Up607971912025-04-23 12:57:011 hr ago1745413021IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000298491.60511517
Level Up607971722025-04-23 12:56:301 hr ago1745412990IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000300041.61347073
Level Up607971672025-04-23 12:56:171 hr ago1745412977IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000329211.61845637
Level Up607883812025-04-23 9:37:195 hrs ago1745401039IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000272531.60936319
Level Up607841962025-04-23 8:00:546 hrs ago1745395254IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000272241.60934432
Level Up607841832025-04-23 8:00:296 hrs ago1745395229IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000273681.61622699
Level Up607563782025-04-22 21:31:5817 hrs ago1745357518IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000319921.89310583
Level Up607563752025-04-22 21:31:5517 hrs ago1745357515IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000312821.85106158
Level Up607563712025-04-22 21:31:4817 hrs ago1745357508IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000280061.85999269
Level Up607563672025-04-22 21:31:4417 hrs ago1745357504IN
0x1009CbA3...fB8A3efE2
0 AVAX0.00031531.86563824
Level Up607563622025-04-22 21:31:3917 hrs ago1745357499IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000314481.8607687
Level Up607563592025-04-22 21:31:3617 hrs ago1745357496IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000316121.87045156
Level Up607563552025-04-22 21:31:3117 hrs ago1745357491IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000283621.88351062
Level Up607563532025-04-22 21:31:2717 hrs ago1745357487IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000320651.89728208
Level Up607563492025-04-22 21:31:2317 hrs ago1745357483IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000318151.87849277
Level Up607563422025-04-22 21:31:1317 hrs ago1745357473IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000322121.90593816
Level Up607563392025-04-22 21:31:1017 hrs ago1745357470IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000287291.90785361
Level Up607563362025-04-22 21:31:0717 hrs ago1745357467IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000321991.9011362
Level Up607563312025-04-22 21:31:0017 hrs ago1745357460IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000322531.90433471
Level Up607563282025-04-22 21:30:5717 hrs ago1745357457IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000287321.90351123
Level Up607563262025-04-22 21:30:5517 hrs ago1745357455IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000323011.9078162
Level Up607563222025-04-22 21:30:4817 hrs ago1745357448IN
0x1009CbA3...fB8A3efE2
0 AVAX0.000288791.91325201
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Lake

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 snowscan.xyz 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 Lake 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)
    {
        if (
            hopper.agility < 5 ||
            hopper.vitality < 5 ||
            hopper.intelligence < 5 ||
            hopper.strength < 5 ||
            hopper.level < 20
        ) return false;
        return true;
    }

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

Contract Security Audit

Contract ABI

API
[{"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"}]

60e06040523480156200001157600080fd5b5060405162003cf138038062003cf183398101604081905262000034916200017c565b600480546001600160a01b031916331790556001600160a01b0380841660805280831660a052811660c0526003600f908155604080518082019091528181526e4c4556454c5f47415547455f4b455960881b6020909101908152849184918491620000a291600091620000b9565b505042600881905560125550620002039350505050565b828054620000c790620001c6565b90600052602060002090601f016020900481019282620000eb576000855562000136565b82601f106200010657805160ff191683800117855562000136565b8280016001018555821562000136579182015b828111156200013657825182559160200191906001019062000119565b506200014492915062000148565b5090565b5b8082111562000144576000815560010162000149565b80516001600160a01b03811681146200017757600080fd5b919050565b6000806000606084860312156200019257600080fd5b6200019d846200015f565b9250620001ad602085016200015f565b9150620001bd604085016200015f565b90509250925092565b600181811c90821680620001db57607f821691505b60208210811415620001fd57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c051613a6a62000287600039600081816104cf0152818161084801528181611098015281816116e4015281816118da015281816119d301528181611f57015281816122c3015281816126bf015281816127d90152612adc01526000610443015260008181610783015281816112fb01526126160152613a6a6000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c806379f409e0116101b2578063ad914e2e116100f9578063d881e959116100a2578063e42c4e631161007c578063e42c4e63146107a5578063e532a154146107ad578063ee569ba9146107b5578063f5544eb7146107d557600080fd5b8063d881e9591461074b578063dee935681461075e578063e1a61a0c1461077e57600080fd5b8063c9d27afe116100d3578063c9d27afe14610700578063caa6fea414610713578063d051bfa31461073857600080fd5b8063ad914e2e146106c2578063bf856895146106e4578063bf9bc0b2146106ed57600080fd5b806396afc4501161015b578063a49a3e1b11610135578063a49a3e1b1461067a578063ab20355c1461068f578063ac3910a2146106a257600080fd5b806396afc4501461064b5780639d4c93c414610654578063a1bdb15e1461066757600080fd5b80638da5cb5b1161018c5780638da5cb5b146105f85780638eb3be2814610618578063968c603d1461062b57600080fd5b806379f409e0146105905780637e2d9af8146105b8578063818ae1ce146105d857600080fd5b80633cfa989e116102815780635834c36d1161022a5780635d35b5d5116102045780635d35b5d51461053e5780636351520e14610547578063769022a31461055a5780637944135d1461057d57600080fd5b80635834c36d14610502578063591adce61461050b5780635c1ab8c01461051e57600080fd5b80634b905e3f1161025b5780634b905e3f146104ca5780634b9ca431146104f15780634e71d92d146104fa57600080fd5b80633cfa989e1461048e578063402914f5146104ae57806343aba89d146104c157600080fd5b80631c1502c4116102e35780632677d07f116102bd5780632677d07f1461043e5780632df97550146104655780633bad0f711461048557600080fd5b80631c1502c4146103ba578063201e29a0146103c3578063215e0f4d1461041e57600080fd5b80630c679fa0116103145780630c679fa01461037f57806313af40351461039457806318c08f26146103a757600080fd5b80630700037d1461033b5780630ab747f01461036e5780630b24216314610377575b600080fd5b61035b61034936600461308d565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61035b60095481565b61035b6107e8565b61039261038d3660046130ba565b610846565b005b6103926103a236600461308d565b610d4e565b6103926103b536600461312b565b610e0e565b61035b60135481565b6103f96103d136600461316d565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b61035b61042c36600461308d565b600a6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b61047336600461308d565b60146020526000908152604090205481565b61035b60075481565b61035b61049c36600461308d565b600d6020526000908152604090205481565b61035b6104bc36600461308d565b61119f565b61035b60105481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b61035b60115481565b610392611292565b61035b60125481565b6103926105193660046130ba565b61135a565b61035b61052c36600461308d565b600c6020526000908152604090205481565b61035b600f5481565b61039261055536600461316d565b61141c565b61056d610568366004613255565b611472565b6040519015158152602001610365565b61039261058b36600461312b565b6114f4565b6105a361059e36600461330d565b6117a7565b60408051928352602083019190915201610365565b61035b6105c636600461308d565b60166020526000908152604090205481565b61035b6105e636600461308d565b600b6020526000908152604090205481565b6004546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b610392610626366004613339565b611859565b61035b61063936600461316d565b60026020526000908152604090205481565b61035b60065481565b61039261066236600461316d565b611a55565b61039261067536600461316d565b611ad9565b610682611b6d565b6040516103659190613431565b6105a361069d36600461330d565b611bfb565b6005546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6106d56106d036600461316d565b611c71565b60405161036593929190613444565b61035b60085481565b61035b6106fb36600461316d565b611ce7565b61039261070e3660046130ba565b611cf8565b60055461056d9074010000000000000000000000000000000000000000900460ff1681565b61039261074636600461308d565b611d2e565b6103926107593660046134dd565b611dee565b61035b61076c36600461316d565b600e6020526000908152604090205481565b6103f97f000000000000000000000000000000000000000000000000000000000000000081565b610392611fbf565b61035b612051565b61035b6107c336600461308d565b60156020526000908152604090205481565b6103926107e336600461308d565b6120a9565b600754600090806107fb57505060095490565b806006546008544261080d9190613563565b610817919061357a565b61082990670de0b6b3a764000061357a565b61083391906135b7565b60095461084091906135f2565b91505090565b7f000000000000000000000000000000000000000000000000000000000000000081156108765761087633612176565b60008381526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114610980576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101859052339073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa15801561090f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610933919061360a565b73ffffffffffffffffffffffffffffffffffffffff1614610980576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5c5503530000000000000000000000000000000000000000000000000000000081526004810185905260009073ffffffffffffffffffffffffffffffffffffffff841690635c5503539060240160e060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906136ef565b905073ffffffffffffffffffffffffffffffffffffffff8216331415610c0d5783610a4057610a4033612176565b6000610a4b866121db565b509150506000610aa2836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b835160010178ffffffffffffffffffffffffffffffffffffffffffffffffff16808552604085015160a08601516080870151606088015194955060009460ff90811691811691909102918116919091029116020290506000610b048383613563565b336000908152600a6020526040812080548301908190556007805484019055919250610b3290829080612388565b50336000908152600c602052604081205485811015610b5857610b558187613563565b91505b610b628287613563565b8751610b889078ffffffffffffffffffffffffffffffffffffffffffffffffff1661253a565b610b979064e8d4a5100061357a565b610ba19190613563565b336000908152600c602052604081208054909190610bc09084906135f2565b909155505086517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0178ffffffffffffffffffffffffffffffffffffffffffffffffff1687525050505050505b610c3e610c38826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16611ce7565b85612583565b6040517f0ce90ec20000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff841690630ce90ec290602401600060405180830381600087803b158015610ca657600080fd5b505af1158015610cba573d6000803e3d6000fd5b50506040517f3d68b4b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250633d68b4b59150610d159060009089908290600401613830565b600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b505050505050505050565b60045473ffffffffffffffffffffffffffffffffffffffff163314610d9f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f957090e72c0a1b3ebf83c682eb8c1f88c2a18cd0578b91a819efb28859f0f3a390600090a250565b60055474010000000000000000000000000000000000000000900460ff1615610e63576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e6c33612176565b336000908152600a6020908152604080832054600c90925282205490918291849190818367ffffffffffffffff811115610ea857610ea8613186565b604051908082528060200260200182016040528015610ed1578160200160208202803683370190505b50905060008767ffffffffffffffff811115610eef57610eef613186565b604051908082528060200260200182016040528015610f18578160200160208202803683370190505b50905060005b858110156111035760008a8a83818110610f3a57610f3a613855565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff163314610fa6576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610fb4846121db565b91945092509050610fc5838c613563565b9a50610fd1828a6135f2565b985081878681518110610fe657610fe6613855565b6020026020010181815250508086868151811061100557611005613855565b6020908102919091018101919091526000858152600190915260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810185905273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b1580156110dc57600080fd5b505af11580156110f0573d6000803e3d6000fd5b5050505084600101945050505050610f1e565b50336000908152600a6020526040902086905583831015611149576111348989848461112f888a613563565b61266f565b336000908152600c6020526040812055611188565b8561116357336000908152600c6020526040812055611188565b336000908152600c602052604081208054869290611182908490613563565b90915550505b6007805487018890039055610d4386600080612388565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600c602052604081205481906111d79064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600a60205260408120549192509061120c9085906117a7565b5073ffffffffffffffffffffffffffffffffffffffff851660009081526014602052604081205491925090611242908690611bfb565b50905061124f81836135f2565b915082821161125e5781611260565b825b73ffffffffffffffffffffffffffffffffffffffff909516600090815260036020526040902054909401949350505050565b61129b33612176565b336000818152600360205260408082208054929055517f40c10f190000000000000000000000000000000000000000000000000000000081526004810192909252602482018190529073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b15801561133f57600080fd5b505af1158015611353573d6000803e3d6000fd5b5050505050565b336000818152601460205260409020546113749190612905565b336000908152600a602052604081205461138f918490612388565b801561141857600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306661abd6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b505050505b5050565b60045473ffffffffffffffffffffffffffffffffffffffff16331461146d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f55565b60006005826060015160ff16108061149157506005826080015160ff16105b806114a3575060058260a0015160ff16105b806114b557506005826040015160ff16105b806114df57506014826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16105b156114ec57506000919050565b506001919050565b60055474010000000000000000000000000000000000000000900460ff1615611549576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61155233612176565b336000908152600a6020908152604080832054600d90925282205490918291849190815b8381101561176457600088888381811061159257611592613855565b602090810292909201356000818152600e909352604083208690559250819050806115bc846129c6565b9250925092506115cb83611472565b611601576040517f0ce023b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611652836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b909801976116608282613563565b61166a90886135f2565b6000858152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163390811790915590517f23b872dd0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018690529097507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b15801561173d57600080fd5b505af1158015611751573d6000803e3d6000fd5b5050505084600101945050505050611576565b50336000908152600a60209081526040808320879055600c9091528120805484019055600780548601879003905561179e90859080612388565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040812054819081906117e19064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600b602052604081205491925090670de0b6b3a76400009061181d6107e8565b6118279190613563565b611831908761357a565b61183b91906135b7565b905081811161184a578061184c565b815b93509150505b9250929050565b80156118685761186833612176565b60008481526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114611992576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052339073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015611921573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611945919061360a565b73ffffffffffffffffffffffffffffffffffffffff1614611992576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc60fb6a70000000000000000000000000000000000000000000000000000000081526113539073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063c60fb6a790611a0c90899089908990600401613884565b6020604051808303816000875af1158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f91906138d8565b83612583565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611a95575060055473ffffffffffffffffffffffffffffffffffffffff163314155b15611acc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ad4612c10565b601055565b60045473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b32612c21565b60068190556040518181527f90e51e492b1841b8ed3d459463d02d171ced752c7fcd84a9dd79f90098166aec9060200160405180910390a150565b60008054611b7a9061370b565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba69061370b565b8015611bf35780601f10611bc857610100808354040283529160200191611bf3565b820191906000526020600020905b815481529060010190602001808311611bd657829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604081205481908190611c359064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff861660009081526015602052604081205491925090670de0b6b3a76400009061181d612051565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529080611cb4846129c6565b9194509250905082611ccb64e8d4a51000846135b7565b611cda64e8d4a51000846135b7565b9250925092509193909250565b6000611cf282612c32565b92915050565b33600081815260146020526040902054611d129190612905565b336000908152600a602052604090205461138f90836001612388565b60045473ffffffffffffffffffffffffffffffffffffffff163314611d7f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f605aa74980dc92c245d8959d233f8c2d7062d874e49326a42e7418279cc8d1f890600090a250565b60055474010000000000000000000000000000000000000000900460ff16611e42576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160005b81811015611353576000858583818110611e6257611e62613855565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff858116911614611ed1576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b158015611f9b57600080fd5b505af1158015611faf573d6000803e3d6000fd5b5050505081600101915050611e46565b60045473ffffffffffffffffffffffffffffffffffffffff163314612010576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6011546000908061206457505060135490565b80601054601254426120769190613563565b612080919061357a565b61209290670de0b6b3a764000061357a565b61209c91906135b7565b60135461084091906135f2565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120fa576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205461212a8282612905565b806011600082825461213c9190613563565b90915550505073ffffffffffffffffffffffffffffffffffffffff1660009081526014602090815260408083208390556016909152812055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a60205260409020546121a7908290612d86565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601460205260409020546121d8908290612905565b50565b336000908152600d6020908152604080832054848452600e9092528220548291829182906122099083613563565b6000878152600e602052604081208490559091508080612228896129c6565b92509250925061227f836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b9750600061228d898661357a565b61229790846135f2565b905060008282116122a857816122aa565b825b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016633d68b4b560008d6122fa64e8d4a51000866135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261233593929190600401613830565b600060405180830381600087803b15801561234f57600080fd5b505af1158015612363573d6000803e3d6000fd5b505050508981846123749190613563565b909c909b5092995091975050505050505050565b3360009081526014602052604090205482156124f9578115612449576005546040517f5f74bbde0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff90911690635f74bbde90604401600060405180830381600087803b15801561241657600080fd5b505af115801561242a573d6000803e3d6000fd5b5050336000908152601660205260409020805486019055506124f99050565b6005546040517f02aa9be20000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff909116906302aa9be290604401600060405180830381600087803b1580156124bb57600080fd5b505af11580156124cf573d6000803e3d6000fd5b505033600090815260166020526040812080548794509092506124f3908490613563565b90915550505b33600090815260166020526040812054612514908690612e47565b336000908152601460205260409020819055601180549091019290920390915550505050565b6000816001141561255457506714d1120d7b160000919050565b816064141561256d5750680ff011d2523cd80000919050565b61257960018303612c32565b600f540292915050565b80156125db57336000908152600360205260409020548281106125bd573360009081526003602052604081208054949094039093556125d9565b80156125d9573360009081526003602052604081205591829003915b505b8115611418576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639dc29fac90604401600060405180830381600087803b1580156113ff57600080fd5b8360005b8181101561179e5784818151811061268d5761268d613855565b60200260200101516000146128fd578481815181106126ae576126ae613855565b60200260200101518311156127d7577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b5600089898581811061270d5761270d613855565b9050602002013564e8d4a5100088868151811061272c5761272c613855565b602002602001015161273e91906135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261277993929190600401613830565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b505050508481815181106127bd576127bd613855565b6020026020010151836127d09190613563565b92506128fd565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633d68b4b5600089898581811061282757612827613855565b9050602002013564e8d4a51000878a878151811061284757612847613855565b60200260200101518a888151811061286157612861613855565b60200260200101516128739190613563565b61287d91906135f2565b61288791906135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526128c293929190600401613830565b600060405180830381600087803b1580156128dc57600080fd5b505af11580156128f0573d6000803e3d6000fd5b505050506000925061179e565b600101612673565b61290d612c10565b801561299957600061292183836001612e62565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600360205260409020805482019055905061295d8164e8d4a5100061357a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612992908490613563565b9091555050505b5060135473ffffffffffffffffffffffffffffffffffffffff909116600090815260156020526040902055565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905283516001808252818601909552929391928392839282015b6060815260200190600190039081612a1757905050905060008054612a3b9061370b565b80601f0160208091040260200160405190810160405280929190818152602001828054612a679061370b565b8015612ab45780601f10612a8957610100808354040283529160200191612ab4565b820191906000526020600020905b815481529060010190602001808311612a9757829003601f168201915b505050505081600081518110612acc57612acc613855565b60200260200101819052506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16630d51186584896040518363ffffffff1660e01b8152600401612b359291906138f1565b600060405180830381865afa158015612b52573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b989190810190613978565b915091508181600081518110612bb057612bb0613855565b602002602001015160001c64e8d4a51000612bcb919061357a565b8351612bf19078ffffffffffffffffffffffffffffffffffffffffffffffffff1661253a565b612c009064e8d4a5100061357a565b9550955095505050509193909250565b612c18612051565b60135542601255565b612c296107e8565b60095542600855565b60010160006064821415612c50575068206aeac7a903980000919050565b600182118015612c605750601582105b15612c765750670de0b6b3a76400000260011c90565b60158210158015612c875750603382105b15612cc557601582036007027a01223448501f3c74e1b3464c172c54a9426488901e3c70d183058a901c607f16670de0b6b3a7640000029050919050565b60338210158015612cd65750605182105b15612d1457603382036007027a023c68b0e14180f9ebc76e9c376cd5a3262c17ae5ab15a9509d325901c607f16670de0b6b3a7640000029050919050565b60518210158015612d255750606582105b15612d5a5760518203600702710c58705ebb6ed59af5aad3a5467ce9b2e549901c607f16670de0b6b3a7640000029050919050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff919050565b919050565b612d8e612c21565b8015612e1a576000612da283836000612e62565b73ffffffffffffffffffffffffffffffffffffffff841660009081526003602052604090208054820190559050612dde8164e8d4a5100061357a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612e13908490613563565b9091555050505b5060095473ffffffffffffffffffffffffffffffffffffffff9091166000908152600b6020526040902055565b6000612e5b612e56838561357a565b612f57565b9392505050565b60008060008315612ef457612e778686611bfb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152600a60205260409020549193509150612eb490829064e8d4a510009061303d565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612ee99084906135f2565b90915550612f4e9050565b612efe86866117a7565b9092509050612f138164e8d4a510008761303d565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612f489084906135f2565b90915550505b50949350505050565b6001817001000000000000000000000000000000008110612f7d5760409190911b9060801c5b680100000000000000008110612f985760209190911b9060401c5b6401000000008110612faf5760109190911b9060201c5b620100008110612fc45760089190911b9060101c5b6101008110612fd85760049190911b9060081c5b60108110612feb5760029190911b9060041c5b60088110612ffa578160011b91505b5080820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c80820481811015613037578091505b50919050565b82820281151584158583048514171661305557600080fd5b6001826001830304018115150290509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146121d857600080fd5b60006020828403121561309f57600080fd5b8135612e5b8161306b565b80358015158114612d8157600080fd5b600080604083850312156130cd57600080fd5b823591506130dd602084016130aa565b90509250929050565b60008083601f8401126130f857600080fd5b50813567ffffffffffffffff81111561311057600080fd5b6020830191508360208260051b850101111561185257600080fd5b6000806020838503121561313e57600080fd5b823567ffffffffffffffff81111561315557600080fd5b613161858286016130e6565b90969095509350505050565b60006020828403121561317f57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156131fc576131fc613186565b604052919050565b78ffffffffffffffffffffffffffffffffffffffffffffffffff811681146121d857600080fd5b61ffff811681146121d857600080fd5b60ff811681146121d857600080fd5b8035612d818161323b565b600060e0828403121561326757600080fd5b60405160e0810181811067ffffffffffffffff8211171561328a5761328a613186565b604052823561329881613204565b815260208301356132a88161322b565b602082015260408301356132bb8161323b565b604082015260608301356132ce8161323b565b60608201526132df6080840161324a565b60808201526132f060a0840161324a565b60a082015261330160c0840161324a565b60c08201529392505050565b6000806040838503121561332057600080fd5b823561332b8161306b565b946020939093013593505050565b6000806000806060858703121561334f57600080fd5b84359350602085013567ffffffffffffffff8082111561336e57600080fd5b818701915087601f83011261338257600080fd5b81358181111561339157600080fd5b8860208285010111156133a357600080fd5b6020830195508094505050506133bb604086016130aa565b905092959194509250565b6000815180845260005b818110156133ec576020818501810151868301820152016133d0565b818111156133fe576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612e5b60208301846133c6565b60006101208201905078ffffffffffffffffffffffffffffffffffffffffffffffffff855116825261ffff602086015116602083015260ff604086015116604083015260ff606086015116606083015260ff608086015116608083015260a08501516134b560a084018260ff169052565b5060c08501516134ca60c084018260ff169052565b5060e08201939093526101000152919050565b6000806000604084860312156134f257600080fd5b833567ffffffffffffffff81111561350957600080fd5b613515868287016130e6565b90945092505060208401356135298161306b565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561357557613575613534565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156135b2576135b2613534565b500290565b6000826135ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000821982111561360557613605613534565b500190565b60006020828403121561361c57600080fd5b8151612e5b8161306b565b8051612d818161323b565b600060e0828403121561364457600080fd5b60405160e0810181811067ffffffffffffffff8211171561366757613667613186565b8060405250809150825161367a81613204565b8152602083015161368a8161322b565b6020820152604083015161369d8161323b565b604082015260608301516136b08161323b565b60608201526136c160808401613627565b60808201526136d260a08401613627565b60a08201526136e360c08401613627565b60c08201525092915050565b600060e0828403121561370157600080fd5b612e5b8383613632565b600181811c9082168061371f57607f821691505b60208210811415613037577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061377357607f831692505b60208084108214156137ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b838852602088018280156137c957600181146137f857613823565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00871682528282019750613823565b60008981526020902060005b8781101561381d57815484820152908601908401613804565b83019850505b5050505050505092915050565b6060815260006138436060830186613759565b60208301949094525060400152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156138ea57600080fd5b5051919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015613966577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526139548683516133c6565b9550938201939082019060010161391a565b50509490940194909452949350505050565b600080610100838503121561398c57600080fd5b6139968484613632565b915060e083015167ffffffffffffffff808211156139b357600080fd5b818501915085601f8301126139c757600080fd5b81516020828211156139db576139db613186565b8160051b92506139ec8184016131b5565b8281529284018101928181019089851115613a0657600080fd5b948201945b84861015613a2457855182529482019490820190613a0b565b809650505050505050925092905056fea26469706673582212207dafd72379692ef45e0c5a4f2adbce4b0b1307c1dfaf6cfc4d03d6854d7760bb64736f6c634300080c003300000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe28000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa273240000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103365760003560e01c806379f409e0116101b2578063ad914e2e116100f9578063d881e959116100a2578063e42c4e631161007c578063e42c4e63146107a5578063e532a154146107ad578063ee569ba9146107b5578063f5544eb7146107d557600080fd5b8063d881e9591461074b578063dee935681461075e578063e1a61a0c1461077e57600080fd5b8063c9d27afe116100d3578063c9d27afe14610700578063caa6fea414610713578063d051bfa31461073857600080fd5b8063ad914e2e146106c2578063bf856895146106e4578063bf9bc0b2146106ed57600080fd5b806396afc4501161015b578063a49a3e1b11610135578063a49a3e1b1461067a578063ab20355c1461068f578063ac3910a2146106a257600080fd5b806396afc4501461064b5780639d4c93c414610654578063a1bdb15e1461066757600080fd5b80638da5cb5b1161018c5780638da5cb5b146105f85780638eb3be2814610618578063968c603d1461062b57600080fd5b806379f409e0146105905780637e2d9af8146105b8578063818ae1ce146105d857600080fd5b80633cfa989e116102815780635834c36d1161022a5780635d35b5d5116102045780635d35b5d51461053e5780636351520e14610547578063769022a31461055a5780637944135d1461057d57600080fd5b80635834c36d14610502578063591adce61461050b5780635c1ab8c01461051e57600080fd5b80634b905e3f1161025b5780634b905e3f146104ca5780634b9ca431146104f15780634e71d92d146104fa57600080fd5b80633cfa989e1461048e578063402914f5146104ae57806343aba89d146104c157600080fd5b80631c1502c4116102e35780632677d07f116102bd5780632677d07f1461043e5780632df97550146104655780633bad0f711461048557600080fd5b80631c1502c4146103ba578063201e29a0146103c3578063215e0f4d1461041e57600080fd5b80630c679fa0116103145780630c679fa01461037f57806313af40351461039457806318c08f26146103a757600080fd5b80630700037d1461033b5780630ab747f01461036e5780630b24216314610377575b600080fd5b61035b61034936600461308d565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b61035b60095481565b61035b6107e8565b61039261038d3660046130ba565b610846565b005b6103926103a236600461308d565b610d4e565b6103926103b536600461312b565b610e0e565b61035b60135481565b6103f96103d136600461316d565b60016020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610365565b61035b61042c36600461308d565b600a6020526000908152604090205481565b6103f97f000000000000000000000000baf9a6f8a8afd4be0d85ca40f025bf364fa2732481565b61035b61047336600461308d565b60146020526000908152604090205481565b61035b60075481565b61035b61049c36600461308d565b600d6020526000908152604090205481565b61035b6104bc36600461308d565b61119f565b61035b60105481565b6103f97f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b81565b61035b60115481565b610392611292565b61035b60125481565b6103926105193660046130ba565b61135a565b61035b61052c36600461308d565b600c6020526000908152604090205481565b61035b600f5481565b61039261055536600461316d565b61141c565b61056d610568366004613255565b611472565b6040519015158152602001610365565b61039261058b36600461312b565b6114f4565b6105a361059e36600461330d565b6117a7565b60408051928352602083019190915201610365565b61035b6105c636600461308d565b60166020526000908152604090205481565b61035b6105e636600461308d565b600b6020526000908152604090205481565b6004546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b610392610626366004613339565b611859565b61035b61063936600461316d565b60026020526000908152604090205481565b61035b60065481565b61039261066236600461316d565b611a55565b61039261067536600461316d565b611ad9565b610682611b6d565b6040516103659190613431565b6105a361069d36600461330d565b611bfb565b6005546103f99073ffffffffffffffffffffffffffffffffffffffff1681565b6106d56106d036600461316d565b611c71565b60405161036593929190613444565b61035b60085481565b61035b6106fb36600461316d565b611ce7565b61039261070e3660046130ba565b611cf8565b60055461056d9074010000000000000000000000000000000000000000900460ff1681565b61039261074636600461308d565b611d2e565b6103926107593660046134dd565b611dee565b61035b61076c36600461316d565b600e6020526000908152604090205481565b6103f97f00000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe2881565b610392611fbf565b61035b612051565b61035b6107c336600461308d565b60156020526000908152604090205481565b6103926107e336600461308d565b6120a9565b600754600090806107fb57505060095490565b806006546008544261080d9190613563565b610817919061357a565b61082990670de0b6b3a764000061357a565b61083391906135b7565b60095461084091906135f2565b91505090565b7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b81156108765761087633612176565b60008381526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114610980576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101859052339073ffffffffffffffffffffffffffffffffffffffff841690636352211e90602401602060405180830381865afa15801561090f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610933919061360a565b73ffffffffffffffffffffffffffffffffffffffff1614610980576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5c5503530000000000000000000000000000000000000000000000000000000081526004810185905260009073ffffffffffffffffffffffffffffffffffffffff841690635c5503539060240160e060405180830381865afa1580156109ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1291906136ef565b905073ffffffffffffffffffffffffffffffffffffffff8216331415610c0d5783610a4057610a4033612176565b6000610a4b866121db565b509150506000610aa2836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b835160010178ffffffffffffffffffffffffffffffffffffffffffffffffff16808552604085015160a08601516080870151606088015194955060009460ff90811691811691909102918116919091029116020290506000610b048383613563565b336000908152600a6020526040812080548301908190556007805484019055919250610b3290829080612388565b50336000908152600c602052604081205485811015610b5857610b558187613563565b91505b610b628287613563565b8751610b889078ffffffffffffffffffffffffffffffffffffffffffffffffff1661253a565b610b979064e8d4a5100061357a565b610ba19190613563565b336000908152600c602052604081208054909190610bc09084906135f2565b909155505086517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0178ffffffffffffffffffffffffffffffffffffffffffffffffff1687525050505050505b610c3e610c38826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16611ce7565b85612583565b6040517f0ce90ec20000000000000000000000000000000000000000000000000000000081526004810186905273ffffffffffffffffffffffffffffffffffffffff841690630ce90ec290602401600060405180830381600087803b158015610ca657600080fd5b505af1158015610cba573d6000803e3d6000fd5b50506040517f3d68b4b500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff86169250633d68b4b59150610d159060009089908290600401613830565b600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b505050505050505050565b60045473ffffffffffffffffffffffffffffffffffffffff163314610d9f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f957090e72c0a1b3ebf83c682eb8c1f88c2a18cd0578b91a819efb28859f0f3a390600090a250565b60055474010000000000000000000000000000000000000000900460ff1615610e63576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e6c33612176565b336000908152600a6020908152604080832054600c90925282205490918291849190818367ffffffffffffffff811115610ea857610ea8613186565b604051908082528060200260200182016040528015610ed1578160200160208202803683370190505b50905060008767ffffffffffffffff811115610eef57610eef613186565b604051908082528060200260200182016040528015610f18578160200160208202803683370190505b50905060005b858110156111035760008a8a83818110610f3a57610f3a613855565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff163314610fa6576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610fb4846121db565b91945092509050610fc5838c613563565b9a50610fd1828a6135f2565b985081878681518110610fe657610fe6613855565b6020026020010181815250508086868151811061100557611005613855565b6020908102919091018101919091526000858152600190915260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd0000000000000000000000000000000000000000000000000000000081523060048201523360248201526044810185905273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b16906323b872dd90606401600060405180830381600087803b1580156110dc57600080fd5b505af11580156110f0573d6000803e3d6000fd5b5050505084600101945050505050610f1e565b50336000908152600a6020526040902086905583831015611149576111348989848461112f888a613563565b61266f565b336000908152600c6020526040812055611188565b8561116357336000908152600c6020526040812055611188565b336000908152600c602052604081208054869290611182908490613563565b90915550505b6007805487018890039055610d4386600080612388565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600c602052604081205481906111d79064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600a60205260408120549192509061120c9085906117a7565b5073ffffffffffffffffffffffffffffffffffffffff851660009081526014602052604081205491925090611242908690611bfb565b50905061124f81836135f2565b915082821161125e5781611260565b825b73ffffffffffffffffffffffffffffffffffffffff909516600090815260036020526040902054909401949350505050565b61129b33612176565b336000818152600360205260408082208054929055517f40c10f190000000000000000000000000000000000000000000000000000000081526004810192909252602482018190529073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe2816906340c10f1990604401600060405180830381600087803b15801561133f57600080fd5b505af1158015611353573d6000803e3d6000fd5b5050505050565b336000818152601460205260409020546113749190612905565b336000908152600a602052604081205461138f918490612388565b801561141857600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306661abd6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156113ff57600080fd5b505af1158015611413573d6000803e3d6000fd5b505050505b5050565b60045473ffffffffffffffffffffffffffffffffffffffff16331461146d576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f55565b60006005826060015160ff16108061149157506005826080015160ff16105b806114a3575060058260a0015160ff16105b806114b557506005826040015160ff16105b806114df57506014826000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16105b156114ec57506000919050565b506001919050565b60055474010000000000000000000000000000000000000000900460ff1615611549576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61155233612176565b336000908152600a6020908152604080832054600d90925282205490918291849190815b8381101561176457600088888381811061159257611592613855565b602090810292909201356000818152600e909352604083208690559250819050806115bc846129c6565b9250925092506115cb83611472565b611601576040517f0ce023b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611652836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b909801976116608282613563565b61166a90886135f2565b6000858152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000163390811790915590517f23b872dd0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018690529097507f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b73ffffffffffffffffffffffffffffffffffffffff16906323b872dd90606401600060405180830381600087803b15801561173d57600080fd5b505af1158015611751573d6000803e3d6000fd5b5050505084600101945050505050611576565b50336000908152600a60209081526040808320879055600c9091528120805484019055600780548601879003905561179e90859080612388565b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020526040812054819081906117e19064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600b602052604081205491925090670de0b6b3a76400009061181d6107e8565b6118279190613563565b611831908761357a565b61183b91906135b7565b905081811161184a578061184c565b815b93509150505b9250929050565b80156118685761186833612176565b60008481526001602052604090205473ffffffffffffffffffffffffffffffffffffffff16338114611992576040517f6352211e00000000000000000000000000000000000000000000000000000000815260048101869052339073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b1690636352211e90602401602060405180830381865afa158015611921573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611945919061360a565b73ffffffffffffffffffffffffffffffffffffffff1614611992576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc60fb6a70000000000000000000000000000000000000000000000000000000081526113539073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b169063c60fb6a790611a0c90899089908990600401613884565b6020604051808303816000875af1158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f91906138d8565b83612583565b60045473ffffffffffffffffffffffffffffffffffffffff163314801590611a95575060055473ffffffffffffffffffffffffffffffffffffffff163314155b15611acc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ad4612c10565b601055565b60045473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b32612c21565b60068190556040518181527f90e51e492b1841b8ed3d459463d02d171ced752c7fcd84a9dd79f90098166aec9060200160405180910390a150565b60008054611b7a9061370b565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba69061370b565b8015611bf35780601f10611bc857610100808354040283529160200191611bf3565b820191906000526020600020905b815481529060010190602001808311611bd657829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c602052604081205481908190611c359064e8d4a51000906135b7565b73ffffffffffffffffffffffffffffffffffffffff861660009081526015602052604081205491925090670de0b6b3a76400009061181d612051565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290529080611cb4846129c6565b9194509250905082611ccb64e8d4a51000846135b7565b611cda64e8d4a51000846135b7565b9250925092509193909250565b6000611cf282612c32565b92915050565b33600081815260146020526040902054611d129190612905565b336000908152600a602052604090205461138f90836001612388565b60045473ffffffffffffffffffffffffffffffffffffffff163314611d7f576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f605aa74980dc92c245d8959d233f8c2d7062d874e49326a42e7418279cc8d1f890600090a250565b60055474010000000000000000000000000000000000000000900460ff16611e42576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160005b81811015611353576000858583818110611e6257611e62613855565b60209081029290920135600081815260019093526040909220549192505073ffffffffffffffffffffffffffffffffffffffff858116911614611ed1576040517f5483a62900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8581166024830152604482018390527f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b16906323b872dd90606401600060405180830381600087803b158015611f9b57600080fd5b505af1158015611faf573d6000803e3d6000fd5b5050505081600101915050611e46565b60045473ffffffffffffffffffffffffffffffffffffffff163314612010576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b6011546000908061206457505060135490565b80601054601254426120769190613563565b612080919061357a565b61209290670de0b6b3a764000061357a565b61209c91906135b7565b60135461084091906135f2565b60055473ffffffffffffffffffffffffffffffffffffffff1633146120fa576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526014602052604090205461212a8282612905565b806011600082825461213c9190613563565b90915550505073ffffffffffffffffffffffffffffffffffffffff1660009081526014602090815260408083208390556016909152812055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a60205260409020546121a7908290612d86565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601460205260409020546121d8908290612905565b50565b336000908152600d6020908152604080832054848452600e9092528220548291829182906122099083613563565b6000878152600e602052604081208490559091508080612228896129c6565b92509250925061227f836000816000015178ffffffffffffffffffffffffffffffffffffffffffffffffff16826040015160ff168360a0015160ff16846080015160ff16856060015160ff16020202029050919050565b9750600061228d898661357a565b61229790846135f2565b905060008282116122a857816122aa565b825b905073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b16633d68b4b560008d6122fa64e8d4a51000866135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261233593929190600401613830565b600060405180830381600087803b15801561234f57600080fd5b505af1158015612363573d6000803e3d6000fd5b505050508981846123749190613563565b909c909b5092995091975050505050505050565b3360009081526014602052604090205482156124f9578115612449576005546040517f5f74bbde0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff90911690635f74bbde90604401600060405180830381600087803b15801561241657600080fd5b505af115801561242a573d6000803e3d6000fd5b5050336000908152601660205260409020805486019055506124f99050565b6005546040517f02aa9be20000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff909116906302aa9be290604401600060405180830381600087803b1580156124bb57600080fd5b505af11580156124cf573d6000803e3d6000fd5b505033600090815260166020526040812080548794509092506124f3908490613563565b90915550505b33600090815260166020526040812054612514908690612e47565b336000908152601460205260409020819055601180549091019290920390915550505050565b6000816001141561255457506714d1120d7b160000919050565b816064141561256d5750680ff011d2523cd80000919050565b61257960018303612c32565b600f540292915050565b80156125db57336000908152600360205260409020548281106125bd573360009081526003602052604081208054949094039093556125d9565b80156125d9573360009081526003602052604081205591829003915b505b8115611418576040517f9dc29fac000000000000000000000000000000000000000000000000000000008152336004820152602481018390527f00000000000000000000000078ea3fef1c1f07348199bf44f45b803b9b0dbe2873ffffffffffffffffffffffffffffffffffffffff1690639dc29fac90604401600060405180830381600087803b1580156113ff57600080fd5b8360005b8181101561179e5784818151811061268d5761268d613855565b60200260200101516000146128fd578481815181106126ae576126ae613855565b60200260200101518311156127d7577f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b73ffffffffffffffffffffffffffffffffffffffff16633d68b4b5600089898581811061270d5761270d613855565b9050602002013564e8d4a5100088868151811061272c5761272c613855565b602002602001015161273e91906135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261277993929190600401613830565b600060405180830381600087803b15801561279357600080fd5b505af11580156127a7573d6000803e3d6000fd5b505050508481815181106127bd576127bd613855565b6020026020010151836127d09190613563565b92506128fd565b7f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b73ffffffffffffffffffffffffffffffffffffffff16633d68b4b5600089898581811061282757612827613855565b9050602002013564e8d4a51000878a878151811061284757612847613855565b60200260200101518a888151811061286157612861613855565b60200260200101516128739190613563565b61287d91906135f2565b61288791906135b7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526128c293929190600401613830565b600060405180830381600087803b1580156128dc57600080fd5b505af11580156128f0573d6000803e3d6000fd5b505050506000925061179e565b600101612673565b61290d612c10565b801561299957600061292183836001612e62565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600360205260409020805482019055905061295d8164e8d4a5100061357a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612992908490613563565b9091555050505b5060135473ffffffffffffffffffffffffffffffffffffffff909116600090815260156020526040902055565b6040805160e08101825260008082526020808301829052828401829052606083018290526080830182905260a0830182905260c0830182905283516001808252818601909552929391928392839282015b6060815260200190600190039081612a1757905050905060008054612a3b9061370b565b80601f0160208091040260200160405190810160405280929190818152602001828054612a679061370b565b8015612ab45780601f10612a8957610100808354040283529160200191612ab4565b820191906000526020600020905b815481529060010190602001808311612a9757829003601f168201915b505050505081600081518110612acc57612acc613855565b60200260200101819052506000807f0000000000000000000000004245a1bd84eb5f3ebc115c2edf57e50667f98b0b73ffffffffffffffffffffffffffffffffffffffff16630d51186584896040518363ffffffff1660e01b8152600401612b359291906138f1565b600060405180830381865afa158015612b52573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052612b989190810190613978565b915091508181600081518110612bb057612bb0613855565b602002602001015160001c64e8d4a51000612bcb919061357a565b8351612bf19078ffffffffffffffffffffffffffffffffffffffffffffffffff1661253a565b612c009064e8d4a5100061357a565b9550955095505050509193909250565b612c18612051565b60135542601255565b612c296107e8565b60095542600855565b60010160006064821415612c50575068206aeac7a903980000919050565b600182118015612c605750601582105b15612c765750670de0b6b3a76400000260011c90565b60158210158015612c875750603382105b15612cc557601582036007027a01223448501f3c74e1b3464c172c54a9426488901e3c70d183058a901c607f16670de0b6b3a7640000029050919050565b60338210158015612cd65750605182105b15612d1457603382036007027a023c68b0e14180f9ebc76e9c376cd5a3262c17ae5ab15a9509d325901c607f16670de0b6b3a7640000029050919050565b60518210158015612d255750606582105b15612d5a5760518203600702710c58705ebb6ed59af5aad3a5467ce9b2e549901c607f16670de0b6b3a7640000029050919050565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff919050565b919050565b612d8e612c21565b8015612e1a576000612da283836000612e62565b73ffffffffffffffffffffffffffffffffffffffff841660009081526003602052604090208054820190559050612dde8164e8d4a5100061357a565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600c602052604081208054909190612e13908490613563565b9091555050505b5060095473ffffffffffffffffffffffffffffffffffffffff9091166000908152600b6020526040902055565b6000612e5b612e56838561357a565b612f57565b9392505050565b60008060008315612ef457612e778686611bfb565b73ffffffffffffffffffffffffffffffffffffffff88166000908152600a60205260409020549193509150612eb490829064e8d4a510009061303d565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612ee99084906135f2565b90915550612f4e9050565b612efe86866117a7565b9092509050612f138164e8d4a510008761303d565b73ffffffffffffffffffffffffffffffffffffffff87166000908152600d602052604081208054909190612f489084906135f2565b90915550505b50949350505050565b6001817001000000000000000000000000000000008110612f7d5760409190911b9060801c5b680100000000000000008110612f985760209190911b9060401c5b6401000000008110612faf5760109190911b9060201c5b620100008110612fc45760089190911b9060101c5b6101008110612fd85760049190911b9060081c5b60108110612feb5760029190911b9060041c5b60088110612ffa578160011b91505b5080820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c80820481811015613037578091505b50919050565b82820281151584158583048514171661305557600080fd5b6001826001830304018115150290509392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146121d857600080fd5b60006020828403121561309f57600080fd5b8135612e5b8161306b565b80358015158114612d8157600080fd5b600080604083850312156130cd57600080fd5b823591506130dd602084016130aa565b90509250929050565b60008083601f8401126130f857600080fd5b50813567ffffffffffffffff81111561311057600080fd5b6020830191508360208260051b850101111561185257600080fd5b6000806020838503121561313e57600080fd5b823567ffffffffffffffff81111561315557600080fd5b613161858286016130e6565b90969095509350505050565b60006020828403121561317f57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156131fc576131fc613186565b604052919050565b78ffffffffffffffffffffffffffffffffffffffffffffffffff811681146121d857600080fd5b61ffff811681146121d857600080fd5b60ff811681146121d857600080fd5b8035612d818161323b565b600060e0828403121561326757600080fd5b60405160e0810181811067ffffffffffffffff8211171561328a5761328a613186565b604052823561329881613204565b815260208301356132a88161322b565b602082015260408301356132bb8161323b565b604082015260608301356132ce8161323b565b60608201526132df6080840161324a565b60808201526132f060a0840161324a565b60a082015261330160c0840161324a565b60c08201529392505050565b6000806040838503121561332057600080fd5b823561332b8161306b565b946020939093013593505050565b6000806000806060858703121561334f57600080fd5b84359350602085013567ffffffffffffffff8082111561336e57600080fd5b818701915087601f83011261338257600080fd5b81358181111561339157600080fd5b8860208285010111156133a357600080fd5b6020830195508094505050506133bb604086016130aa565b905092959194509250565b6000815180845260005b818110156133ec576020818501810151868301820152016133d0565b818111156133fe576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612e5b60208301846133c6565b60006101208201905078ffffffffffffffffffffffffffffffffffffffffffffffffff855116825261ffff602086015116602083015260ff604086015116604083015260ff606086015116606083015260ff608086015116608083015260a08501516134b560a084018260ff169052565b5060c08501516134ca60c084018260ff169052565b5060e08201939093526101000152919050565b6000806000604084860312156134f257600080fd5b833567ffffffffffffffff81111561350957600080fd5b613515868287016130e6565b90945092505060208401356135298161306b565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008282101561357557613575613534565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156135b2576135b2613534565b500290565b6000826135ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000821982111561360557613605613534565b500190565b60006020828403121561361c57600080fd5b8151612e5b8161306b565b8051612d818161323b565b600060e0828403121561364457600080fd5b60405160e0810181811067ffffffffffffffff8211171561366757613667613186565b8060405250809150825161367a81613204565b8152602083015161368a8161322b565b6020820152604083015161369d8161323b565b604082015260608301516136b08161323b565b60608201526136c160808401613627565b60808201526136d260a08401613627565b60a08201526136e360c08401613627565b60c08201525092915050565b600060e0828403121561370157600080fd5b612e5b8383613632565b600181811c9082168061371f57607f821691505b60208210811415613037577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8054600090600181811c908083168061377357607f831692505b60208084108214156137ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b838852602088018280156137c957600181146137f857613823565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00871682528282019750613823565b60008981526020902060005b8781101561381d57815484820152908601908401613804565b83019850505b5050505050505092915050565b6060815260006138436060830186613759565b60208301949094525060400152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b83815260406020820152816040820152818360608301376000818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b6000602082840312156138ea57600080fd5b5051919050565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b83811015613966577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08887030185526139548683516133c6565b9550938201939082019060010161391a565b50509490940194909452949350505050565b600080610100838503121561398c57600080fd5b6139968484613632565b915060e083015167ffffffffffffffff808211156139b357600080fd5b818501915085601f8301126139c757600080fd5b81516020828211156139db576139db613186565b8160051b92506139ec8184016131b5565b8281529284018101928181019089851115613a0657600080fd5b948201945b84861015613a2457855182529482019490820190613a0b565b809650505050505050925092905056fea26469706673582212207dafd72379692ef45e0c5a4f2adbce4b0b1307c1dfaf6cfc4d03d6854d7760bb64736f6c634300080c0033

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:995:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68662:42;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;571:25:1;;;559:2;544:18;68662:42:0;;;;;;;;69096:35;;;;;;75465:428;;;:::i;80994:2561::-;;;;;;:::i;:::-;;:::i;:::-;;71475:122;;;;;;:::i;:::-;;:::i;85507:2330::-;;;;;;:::i;:::-;;:::i;69806:40::-;;;;;;68551:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2200:42:1;2188:55;;;2170:74;;2158:2;2143:18;68551:47:0;2024:226:1;69140:52:0;;;;;;:::i;:::-;;;;;;;;;;;;;;68253:31;;;;;69855:50;;;;;;:::i;:::-;;;;;;;;;;;;;;69023:29;;;;;;69327:58;;;;;;:::i;:::-;;;;;;;;;;;;;;89703:572;;;;;;:::i;:::-;;:::i;69689:32::-;;;;;;68291:31;;;;;69730:27;;;;;;90283:228;;;:::i;69764:35::-;;;;;;92390:272;;;;;;:::i;:::-;;:::i;69263:55::-;;;;;;:::i;:::-;;;;;;;;;;;;;;69458:31;;;;;;72290:130;;;;;;:::i;:::-;;:::i;96836:374::-;;;;;;:::i;:::-;;:::i;:::-;;;4632:14:1;;4625:22;4607:41;;4595:2;4580:18;96836:374: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;:::-;81902:62;;;;82070:23;82096:27;82116:6;97347:7;97608:6;:12;;;97600:21;;97564:6;:15;;;97556:24;;97516:6;:19;;;97508:28;;97472:6;:15;;;97464:24;;97429:6;:14;;;97421:23;;:67;:115;:159;:200;97397:224;;97218:422;;;;82096:27;82167:14;;;;;;;;;97564:15;;;;97516:19;;;;97472:15;;;;97429:14;;;;82070:53;;-1:-1:-1;;;97556:24:0;97421:23;;;97464:24;;;97421:67;;;;97508:28;;;97421:115;;;;97556:24;;97421:159;:200;82293:52;-1:-1:-1;82403:12:0;82418:32;82435:15;82293:52;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;96836:374::-;96952:4;97009:1;96992:6;:14;;;:18;;;:54;;;;97045:1;97027:6;:15;;;:19;;;96992:54;:94;;;;97085:1;97063:6;:19;;;:23;;;96992:94;:130;;;;97121:1;97103:6;:15;;;:19;;;96992:130;:164;;;;97154:2;97139:6;:12;;;:17;;;96992:164;96974:206;;;-1:-1:-1;97175:5:0;;96836:374;-1:-1:-1;96836:374:0:o;96974:206::-;-1:-1:-1;97198:4:0;;96836:374;-1:-1:-1;96836:374:0: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;84619:6;84610:8;:16::i;:::-;84605:43;;84635:13;;;;;;;;;;;;;;84605:43;84751:27;84771:6;97347:7;97608:6;:12;;;97600:21;;97564:6;:15;;;97556:24;;97516:6;:19;;;97508:28;;97472:6;:15;;;97464:24;;97429:6;:14;;;97421:23;;:67;:115;:159;:200;97397:224;;97218:422;;;;84751:27;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;:::-;93762:157;;;;;;93947:27;93967:6;97347:7;97608:6;:12;;;97600:21;;97564:6;:15;;;97556:24;;97516:6;:19;;;97508:28;;97472:6;:15;;;97464:24;;97429:6;:14;;;97421:23;;:67;:115;:159;:200;97397:224;;97218:422;;;;93947:27;93932:42;-1:-1:-1;93987:29:0;94050:45;93932:42;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://7dafd72379692ef45e0c5a4f2adbce4b0b1307c1dfaf6cfc4d03d6854d7760bb

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.