ETH Price: $2,132.77 (+3.73%)

Transaction Decoder

Block:
12246280 at Apr-15-2021 06:23:07 PM +UTC
Transaction Fee:
0.015598912 ETH $33.27
Gas Used:
243,733 Gas / 64 Gwei

Emitted Events:

287 PlayerBook.eveSettle( pID=4717, affID=1, aff_affID=1, affReward=1671623377894669094, aff_affReward=716410019097715326, amount=23880333969923844204 )
288 DegoToken.Transfer( from=[Receiver] NFTReward, to=0x6666666666666666666666666666666666666666, value=2388033396992384 )
289 DegoToken.Transfer( from=[Receiver] NFTReward, to=0xEA6dEc98e137a87F78495a8386f7A137408f7722, value=2388033396992384 )
290 DegoToken.Transfer( from=[Receiver] NFTReward, to=PlayerBook, value=2383257330198399652 )
291 DegoToken.Transfer( from=[Receiver] NFTReward, to=0x6666666666666666666666666666666666666666, value=1194016698496192 )
292 DegoToken.Transfer( from=[Receiver] NFTReward, to=0xEA6dEc98e137a87F78495a8386f7A137408f7722, value=1194016698496192 )
293 DegoToken.Transfer( from=[Receiver] NFTReward, to=0x3D0a845C5ef9741De999FC068f70E2048A489F2b, value=1191628665099199826 )
294 DegoToken.Transfer( from=[Receiver] NFTReward, to=0x6666666666666666666666666666666666666666, value=20298283874435267 )
295 DegoToken.Transfer( from=[Receiver] NFTReward, to=0xEA6dEc98e137a87F78495a8386f7A137408f7722, value=20298283874435267 )
296 DegoToken.Transfer( from=[Receiver] NFTReward, to=[Sender] 0x4a0573f70e77a28dd079c0e079174135ab6b41c5, value=20257687306686397040 )
297 NFTReward.RewardPaid( user=[Sender] 0x4a0573f70e77a28dd079c0e079174135ab6b41c5, reward=20298283874435267574 )

Account State Difference:

  Address   Before After State Difference Code
0x4a0573F7...5Ab6B41c5
0.321556062468727445 Eth
Nonce: 1605
0.305957150468727445 Eth
Nonce: 1606
0.015598912
0x4cc945E7...e48BBf3a0
0x88EF27e6...0A075cC02
0xB86021cb...263c9E0cd
(DEGO.Finance: NFT Reward Pool)
(Miner: 0xc8F...7C9)
2,119.253307662559825558 Eth2,119.268906574559825558 Eth0.015598912

Execution Trace

NFTReward.CALL( )
  • PlayerBook.settleReward( from=0x4a0573F70E77A28dd079C0e079174135Ab6B41c5, amount=23880333969923844204 ) => ( 2388033396992384420 )
  • DegoToken.transfer( to=0x4cc945E7b97fED1EAD961Cd83eD622Fe48BBf3a0, value=2388033396992384420 ) => ( True )
  • DegoToken.transfer( to=0x3D0a845C5ef9741De999FC068f70E2048A489F2b, value=1194016698496192210 ) => ( True )
  • DegoToken.transfer( to=0x4a0573F70E77A28dd079C0e079174135Ab6B41c5, value=20298283874435267574 ) => ( True )
    File 1 of 3: NFTReward
    /***
     *    ██████╗ ███████╗ ██████╗  ██████╗ 
     *    ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗
     *    ██║  ██║█████╗  ██║  ███╗██║   ██║
     *    ██║  ██║██╔══╝  ██║   ██║██║   ██║
     *    ██████╔╝███████╗╚██████╔╝╚██████╔╝
     *    ╚═════╝ ╚══════╝ ╚═════╝  ╚═════╝ 
     *    
     * https://dego.finance
                                      
    * MIT License
    * ===========
    *
    * Copyright (c) 2020 dego
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    */
    // File: @openzeppelin/contracts/math/Math.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a >= b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
        }
    }
    
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         *
         * _Available since v2.4.0._
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts with custom message when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/GSN/Context.sol
    
    pragma solidity ^0.5.0;
    
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    contract Context {
        // Empty internal constructor, to prevent people from mistakenly deploying
        // an instance of this contract, which should be used via inheritance.
        constructor () internal { }
        // solhint-disable-previous-line no-empty-blocks
    
        function _msgSender() internal view returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    // File: @openzeppelin/contracts/ownership/Ownable.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(isOwner(), "Ownable: caller is not the owner");
            _;
        }
    
        /**
         * @dev Returns true if the caller is the current owner.
         */
        function isOwner() public view returns (bool) {
            return _msgSender() == _owner;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public onlyOwner {
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         */
        function _transferOwnership(address newOwner) internal {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    // File: @openzeppelin/contracts/introspection/IERC165.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    contract IERC721 is IERC165 {
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    
        /**
         * @dev Returns the number of NFTs in `owner`'s account.
         */
        function balanceOf(address owner) public view returns (uint256 balance);
    
        /**
         * @dev Returns the owner of the NFT specified by `tokenId`.
         */
        function ownerOf(uint256 tokenId) public view returns (address owner);
    
        /**
         * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
         * another (`to`).
         *
         *
         *
         * Requirements:
         * - `from`, `to` cannot be zero.
         * - `tokenId` must be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this
         * NFT by either {approve} or {setApprovalForAll}.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) public;
        /**
         * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
         * another (`to`).
         *
         * Requirements:
         * - If the caller is not `from`, it must be approved to move this NFT by
         * either {approve} or {setApprovalForAll}.
         */
        function transferFrom(address from, address to, uint256 tokenId) public;
        function approve(address to, uint256 tokenId) public;
        function getApproved(uint256 tokenId) public view returns (address operator);
    
        function setApprovalForAll(address operator, bool _approved) public;
        function isApprovedForAll(address owner, address operator) public view returns (bool);
    
    
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    contract IERC721Enumerable is IERC721 {
        function totalSupply() public view returns (uint256);
        function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId);
    
        function tokenByIndex(uint256 index) public view returns (uint256);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    contract IERC721Receiver {
        /**
         * @notice Handle the receipt of an NFT
         * @dev The ERC721 smart contract calls this function on the recipient
         * after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
         * otherwise the caller will revert the transaction. The selector to be
         * returned can be obtained as `this.onERC721Received.selector`. This
         * function MAY throw to revert and reject the transfer.
         * Note: the ERC721 contract address is always the message sender.
         * @param operator The address which called `safeTransferFrom` function
         * @param from The address which previously owned the token
         * @param tokenId The NFT identifier which is being transferred
         * @param data Additional data with no specified format
         * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
         */
        function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
        public returns (bytes4);
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    pragma solidity ^0.5.5;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following 
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        /**
         * @dev Converts an `address` into `address payable`. Note that this is
         * simply a type cast: the actual underlying value is not changed.
         *
         * _Available since v2.4.0._
         */
        function toPayable(address account) internal pure returns (address payable) {
            return address(uint160(account));
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         *
         * _Available since v2.4.0._
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-call-value
            (bool success, ) = recipient.call.value(amount)("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    }
    
    // File: @openzeppelin/contracts/drafts/Counters.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @title Counters
     * @author Matt Condon (@shrugs)
     * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
     * of elements in a mapping, issuing ERC721 ids, or counting request ids.
     *
     * Include with `using Counters for Counters.Counter;`
     * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
     * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
     * directly accessed.
     */
    library Counters {
        using SafeMath for uint256;
    
        struct Counter {
            // This variable should never be directly accessed by users of the library: interactions must be restricted to
            // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
            // this feature: see https://github.com/ethereum/solidity/issues/4637
            uint256 _value; // default: 0
        }
    
        function current(Counter storage counter) internal view returns (uint256) {
            return counter._value;
        }
    
        function increment(Counter storage counter) internal {
            // The {SafeMath} overflow check can be skipped here, see the comment at the top
            counter._value += 1;
        }
    
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    
    // File: @openzeppelin/contracts/introspection/ERC165.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts may inherit from this and call {_registerInterface} to declare
     * their support of an interface.
     */
    contract ERC165 is IERC165 {
        /*
         * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
         */
        bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    
        /**
         * @dev Mapping of interface ids to whether or not it's supported.
         */
        mapping(bytes4 => bool) private _supportedInterfaces;
    
        constructor () internal {
            // Derived contracts need only register support for their own interfaces,
            // we register support for ERC165 itself here
            _registerInterface(_INTERFACE_ID_ERC165);
        }
    
        /**
         * @dev See {IERC165-supportsInterface}.
         *
         * Time complexity O(1), guaranteed to always use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool) {
            return _supportedInterfaces[interfaceId];
        }
    
        /**
         * @dev Registers the contract as an implementer of the interface defined by
         * `interfaceId`. Support of the actual ERC165 interface is automatic and
         * registering its interface id is not required.
         *
         * See {IERC165-supportsInterface}.
         *
         * Requirements:
         *
         * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
         */
        function _registerInterface(bytes4 interfaceId) internal {
            require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
            _supportedInterfaces[interfaceId] = true;
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC721/ERC721.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    
    
    
    /**
     * @title ERC721 Non-Fungible Token Standard basic implementation
     * @dev see https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721 is Context, ERC165, IERC721 {
        using SafeMath for uint256;
        using Address for address;
        using Counters for Counters.Counter;
    
        // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
        // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
        bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
    
        // Mapping from token ID to owner
        mapping (uint256 => address) private _tokenOwner;
    
        // Mapping from token ID to approved address
        mapping (uint256 => address) private _tokenApprovals;
    
        // Mapping from owner to number of owned token
        mapping (address => Counters.Counter) private _ownedTokensCount;
    
        // Mapping from owner to operator approvals
        mapping (address => mapping (address => bool)) private _operatorApprovals;
    
        /*
         *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
         *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
         *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
         *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
         *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
         *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
         *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
         *
         *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
         *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
         */
        bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    
        constructor () public {
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721);
        }
    
        /**
         * @dev Gets the balance of the specified address.
         * @param owner address to query the balance of
         * @return uint256 representing the amount owned by the passed address
         */
        function balanceOf(address owner) public view returns (uint256) {
            require(owner != address(0), "ERC721: balance query for the zero address");
    
            return _ownedTokensCount[owner].current();
        }
    
        /**
         * @dev Gets the owner of the specified token ID.
         * @param tokenId uint256 ID of the token to query the owner of
         * @return address currently marked as the owner of the given token ID
         */
        function ownerOf(uint256 tokenId) public view returns (address) {
            address owner = _tokenOwner[tokenId];
            require(owner != address(0), "ERC721: owner query for nonexistent token");
    
            return owner;
        }
    
        /**
         * @dev Approves another address to transfer the given token ID
         * The zero address indicates there is no approved address.
         * There can only be one approved address per token at a given time.
         * Can only be called by the token owner or an approved operator.
         * @param to address to be approved for the given token ID
         * @param tokenId uint256 ID of the token to be approved
         */
        function approve(address to, uint256 tokenId) public {
            address owner = ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
    
            require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                "ERC721: approve caller is not owner nor approved for all"
            );
    
            _tokenApprovals[tokenId] = to;
            emit Approval(owner, to, tokenId);
        }
    
        /**
         * @dev Gets the approved address for a token ID, or zero if no address set
         * Reverts if the token ID does not exist.
         * @param tokenId uint256 ID of the token to query the approval of
         * @return address currently approved for the given token ID
         */
        function getApproved(uint256 tokenId) public view returns (address) {
            require(_exists(tokenId), "ERC721: approved query for nonexistent token");
    
            return _tokenApprovals[tokenId];
        }
    
        /**
         * @dev Sets or unsets the approval of a given operator
         * An operator is allowed to transfer all tokens of the sender on their behalf.
         * @param to operator address to set the approval
         * @param approved representing the status of the approval to be set
         */
        function setApprovalForAll(address to, bool approved) public {
            require(to != _msgSender(), "ERC721: approve to caller");
    
            _operatorApprovals[_msgSender()][to] = approved;
            emit ApprovalForAll(_msgSender(), to, approved);
        }
    
        /**
         * @dev Tells whether an operator is approved by a given owner.
         * @param owner owner address which you want to query the approval of
         * @param operator operator address which you want to query the approval of
         * @return bool whether the given operator is approved by the given owner
         */
        function isApprovedForAll(address owner, address operator) public view returns (bool) {
            return _operatorApprovals[owner][operator];
        }
    
        /**
         * @dev Transfers the ownership of a given token ID to another address.
         * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         * Requires the msg.sender to be the owner, approved, or operator.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function transferFrom(address from, address to, uint256 tokenId) public {
            //solhint-disable-next-line max-line-length
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
    
            _transferFrom(from, to, tokenId);
        }
    
        /**
         * @dev Safely transfers the ownership of a given token ID to another address
         * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * Requires the msg.sender to be the owner, approved, or operator
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) public {
            safeTransferFrom(from, to, tokenId, "");
        }
    
        /**
         * @dev Safely transfers the ownership of a given token ID to another address
         * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * Requires the _msgSender() to be the owner, approved, or operator
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes data to send along with a safe transfer check
         */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
            _safeTransferFrom(from, to, tokenId, _data);
        }
    
        /**
         * @dev Safely transfers the ownership of a given token ID to another address
         * If the target address is a contract, it must implement `onERC721Received`,
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * Requires the msg.sender to be the owner, approved, or operator
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes data to send along with a safe transfer check
         */
        function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
            _transferFrom(from, to, tokenId);
            require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
        }
    
        /**
         * @dev Returns whether the specified token exists.
         * @param tokenId uint256 ID of the token to query the existence of
         * @return bool whether the token exists
         */
        function _exists(uint256 tokenId) internal view returns (bool) {
            address owner = _tokenOwner[tokenId];
            return owner != address(0);
        }
    
        /**
         * @dev Returns whether the given spender can transfer a given token ID.
         * @param spender address of the spender to query
         * @param tokenId uint256 ID of the token to be transferred
         * @return bool whether the msg.sender is approved for the given token ID,
         * is an operator of the owner, or is the owner of the token
         */
        function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
            require(_exists(tokenId), "ERC721: operator query for nonexistent token");
            address owner = ownerOf(tokenId);
            return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
        }
    
        /**
         * @dev Internal function to safely mint a new token.
         * Reverts if the given token ID already exists.
         * If the target address is a contract, it must implement `onERC721Received`,
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * @param to The address that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         */
        function _safeMint(address to, uint256 tokenId) internal {
            _safeMint(to, tokenId, "");
        }
    
        /**
         * @dev Internal function to safely mint a new token.
         * Reverts if the given token ID already exists.
         * If the target address is a contract, it must implement `onERC721Received`,
         * which is called upon a safe transfer, and return the magic value
         * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
         * the transfer is reverted.
         * @param to The address that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         * @param _data bytes data to send along with a safe transfer check
         */
        function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
            _mint(to, tokenId);
            require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
        }
    
        /**
         * @dev Internal function to mint a new token.
         * Reverts if the given token ID already exists.
         * @param to The address that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         */
        function _mint(address to, uint256 tokenId) internal {
            require(to != address(0), "ERC721: mint to the zero address");
            require(!_exists(tokenId), "ERC721: token already minted");
    
            _tokenOwner[tokenId] = to;
            _ownedTokensCount[to].increment();
    
            emit Transfer(address(0), to, tokenId);
        }
    
        /**
         * @dev Internal function to burn a specific token.
         * Reverts if the token does not exist.
         * Deprecated, use {_burn} instead.
         * @param owner owner of the token to burn
         * @param tokenId uint256 ID of the token being burned
         */
        function _burn(address owner, uint256 tokenId) internal {
            require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");
    
            _clearApproval(tokenId);
    
            _ownedTokensCount[owner].decrement();
            _tokenOwner[tokenId] = address(0);
    
            emit Transfer(owner, address(0), tokenId);
        }
    
        /**
         * @dev Internal function to burn a specific token.
         * Reverts if the token does not exist.
         * @param tokenId uint256 ID of the token being burned
         */
        function _burn(uint256 tokenId) internal {
            _burn(ownerOf(tokenId), tokenId);
        }
    
        /**
         * @dev Internal function to transfer ownership of a given token ID to another address.
         * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _transferFrom(address from, address to, uint256 tokenId) internal {
            require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
            require(to != address(0), "ERC721: transfer to the zero address");
    
            _clearApproval(tokenId);
    
            _ownedTokensCount[from].decrement();
            _ownedTokensCount[to].increment();
    
            _tokenOwner[tokenId] = to;
    
            emit Transfer(from, to, tokenId);
        }
    
        /**
         * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * This is an internal detail of the `ERC721` contract and its use is deprecated.
         * @param from address representing the previous owner of the given token ID
         * @param to target address that will receive the tokens
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes optional data to send along with the call
         * @return bool whether the call correctly returned the expected magic value
         */
        function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
            internal returns (bool)
        {
            if (!to.isContract()) {
                return true;
            }
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
                IERC721Receiver(to).onERC721Received.selector,
                _msgSender(),
                from,
                tokenId,
                _data
            ));
            if (!success) {
                if (returndata.length > 0) {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                }
            } else {
                bytes4 retval = abi.decode(returndata, (bytes4));
                return (retval == _ERC721_RECEIVED);
            }
        }
    
        /**
         * @dev Private function to clear current approval of a given token ID.
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _clearApproval(uint256 tokenId) private {
            if (_tokenApprovals[tokenId] != address(0)) {
                _tokenApprovals[tokenId] = address(0);
            }
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC721/ERC721Enumerable.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    /**
     * @title ERC-721 Non-Fungible Token with optional enumeration extension logic
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    contract ERC721Enumerable is Context, ERC165, ERC721, IERC721Enumerable {
        // Mapping from owner to list of owned token IDs
        mapping(address => uint256[]) private _ownedTokens;
    
        // Mapping from token ID to index of the owner tokens list
        mapping(uint256 => uint256) private _ownedTokensIndex;
    
        // Array with all token ids, used for enumeration
        uint256[] private _allTokens;
    
        // Mapping from token id to position in the allTokens array
        mapping(uint256 => uint256) private _allTokensIndex;
    
        /*
         *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
         *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
         *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
         *
         *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
         */
        bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
    
        /**
         * @dev Constructor function.
         */
        constructor () public {
            // register the supported interface to conform to ERC721Enumerable via ERC165
            _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
        }
    
        /**
         * @dev Gets the token ID at a given index of the tokens list of the requested owner.
         * @param owner address owning the tokens list to be accessed
         * @param index uint256 representing the index to be accessed of the requested tokens list
         * @return uint256 token ID at the given index of the tokens list owned by the requested address
         */
        function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) {
            require(index < balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
            return _ownedTokens[owner][index];
        }
    
        /**
         * @dev Gets the total amount of tokens stored by the contract.
         * @return uint256 representing the total amount of tokens
         */
        function totalSupply() public view returns (uint256) {
            return _allTokens.length;
        }
    
        /**
         * @dev Gets the token ID at a given index of all the tokens in this contract
         * Reverts if the index is greater or equal to the total number of tokens.
         * @param index uint256 representing the index to be accessed of the tokens list
         * @return uint256 token ID at the given index of the tokens list
         */
        function tokenByIndex(uint256 index) public view returns (uint256) {
            require(index < totalSupply(), "ERC721Enumerable: global index out of bounds");
            return _allTokens[index];
        }
    
        /**
         * @dev Internal function to transfer ownership of a given token ID to another address.
         * As opposed to transferFrom, this imposes no restrictions on msg.sender.
         * @param from current owner of the token
         * @param to address to receive the ownership of the given token ID
         * @param tokenId uint256 ID of the token to be transferred
         */
        function _transferFrom(address from, address to, uint256 tokenId) internal {
            super._transferFrom(from, to, tokenId);
    
            _removeTokenFromOwnerEnumeration(from, tokenId);
    
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    
        /**
         * @dev Internal function to mint a new token.
         * Reverts if the given token ID already exists.
         * @param to address the beneficiary that will own the minted token
         * @param tokenId uint256 ID of the token to be minted
         */
        function _mint(address to, uint256 tokenId) internal {
            super._mint(to, tokenId);
    
            _addTokenToOwnerEnumeration(to, tokenId);
    
            _addTokenToAllTokensEnumeration(tokenId);
        }
    
        /**
         * @dev Internal function to burn a specific token.
         * Reverts if the token does not exist.
         * Deprecated, use {ERC721-_burn} instead.
         * @param owner owner of the token to burn
         * @param tokenId uint256 ID of the token being burned
         */
        function _burn(address owner, uint256 tokenId) internal {
            super._burn(owner, tokenId);
    
            _removeTokenFromOwnerEnumeration(owner, tokenId);
            // Since tokenId will be deleted, we can clear its slot in _ownedTokensIndex to trigger a gas refund
            _ownedTokensIndex[tokenId] = 0;
    
            _removeTokenFromAllTokensEnumeration(tokenId);
        }
    
        /**
         * @dev Gets the list of token IDs of the requested owner.
         * @param owner address owning the tokens
         * @return uint256[] List of token IDs owned by the requested address
         */
        function _tokensOfOwner(address owner) internal view returns (uint256[] storage) {
            return _ownedTokens[owner];
        }
    
        /**
         * @dev Private function to add a token to this extension's ownership-tracking data structures.
         * @param to address representing the new owner of the given token ID
         * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
         */
        function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
            _ownedTokensIndex[tokenId] = _ownedTokens[to].length;
            _ownedTokens[to].push(tokenId);
        }
    
        /**
         * @dev Private function to add a token to this extension's token tracking data structures.
         * @param tokenId uint256 ID of the token to be added to the tokens list
         */
        function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
            _allTokensIndex[tokenId] = _allTokens.length;
            _allTokens.push(tokenId);
        }
    
        /**
         * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
         * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
         * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
         * This has O(1) time complexity, but alters the order of the _ownedTokens array.
         * @param from address representing the previous owner of the given token ID
         * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
         */
        function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
            // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
            // then delete the last slot (swap and pop).
    
            uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
            uint256 tokenIndex = _ownedTokensIndex[tokenId];
    
            // When the token to delete is the last token, the swap operation is unnecessary
            if (tokenIndex != lastTokenIndex) {
                uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
    
                _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
                _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
            }
    
            // This also deletes the contents at the last position of the array
            _ownedTokens[from].length--;
    
            // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occupied by
            // lastTokenId, or just over the end of the array if the token was the last one).
        }
    
        /**
         * @dev Private function to remove a token from this extension's token tracking data structures.
         * This has O(1) time complexity, but alters the order of the _allTokens array.
         * @param tokenId uint256 ID of the token to be removed from the tokens list
         */
        function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
            // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
            // then delete the last slot (swap and pop).
    
            uint256 lastTokenIndex = _allTokens.length.sub(1);
            uint256 tokenIndex = _allTokensIndex[tokenId];
    
            // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
            // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
            // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
            uint256 lastTokenId = _allTokens[lastTokenIndex];
    
            _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
    
            // This also deletes the contents at the last position of the array
            _allTokens.length--;
            _allTokensIndex[tokenId] = 0;
        }
    }
    
    // File: contracts/interface/IERC20.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
     * the optional functions; to access them see {ERC20Detailed}.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        function mint(address account, uint amount) external;
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    // File: contracts/library/SafeERC20.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
    
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
    
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
    
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves.
    
            // A Solidity high level call has three parts:
            //  1. The target address is checked to verify it contains contract code
            //  2. The call itself is made, and success asserted
            //  3. The return value is decoded, which in turn checks the size of the returned data.
            // solhint-disable-next-line max-line-length
            require(address(token).isContract(), "SafeERC20: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, "SafeERC20: low-level call failed");
    
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    
    // File: contracts/library/Governance.sol
    
    pragma solidity ^0.5.0;
    
    contract Governance {
    
        address public _governance;
    
        constructor() public {
            _governance = tx.origin;
        }
    
        event GovernanceTransferred(address indexed previousOwner, address indexed newOwner);
    
        modifier onlyGovernance {
            require(msg.sender == _governance, "not governance");
            _;
        }
    
        function setGovernance(address governance)  public  onlyGovernance
        {
            require(governance != address(0), "new governance the zero address");
            emit GovernanceTransferred(_governance, governance);
            _governance = governance;
        }
    
    
    }
    
    // File: contracts/interface/IPool.sol
    
    pragma solidity ^0.5.0;
    
    
    interface IPool {
        function totalSupply( ) external view returns (uint256);
        function balanceOf( address player ) external view returns (uint256);
    }
    
    // File: contracts/interface/IPlayerBook.sol
    
    pragma solidity ^0.5.0;
    
    
    interface IPlayerBook {
        function settleReward( address from,uint256 amount ) external returns (uint256);
        function bindRefer( address from,string calldata  affCode )  external returns (bool);
        function hasRefer(address from) external returns(bool);
    
    }
    
    // File: contracts/interface/IGegoFactory.sol
    
    pragma solidity ^0.5.0;
    
    interface IGegoFactory {
        function getGego(uint256 tokenId)
            external view
            returns (
                uint256 grade,
                uint256 quality,
                uint256 degoAmount,
                uint256 createdTime,
                uint256 blockNum,
                uint256 resId,
                address author
            );
    
    
        function getQualityBase() external view 
            returns (uint256 );
    }
    
    // File: contracts/interface/IGegoToken.sol
    
    pragma solidity ^0.5.0;
    
    
    
    contract IGegoToken is IERC721 {
        function mint(address to, uint256 tokenId) external returns (bool) ;
        function burn(uint256 tokenId) external;
    }
    
    // File: contracts/reward/NFTReward.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    // gego
    // import "../interface/IERC20.sol";
    
    
    
    
    
    
    
    
        
    contract NFTReward is IPool,Governance {
        using SafeERC20 for IERC20;
        using SafeMath for uint256;
    
        IERC20 public _dego = IERC20(0x0);
        IGegoFactory public _gegoFactory = IGegoFactory(0x0);
        IGegoToken public _gegoToken = IGegoToken(0x0);
        address public _playerBook = address(0x0);
    
        address public _teamWallet = 0x3D0a845C5ef9741De999FC068f70E2048A489F2b;
        address public _rewardPool = 0xEA6dEc98e137a87F78495a8386f7A137408f7722;
    
        uint256 public constant DURATION = 7 days;
        uint256 public _initReward = 52500 * 1e18;
        uint256 public _startTime =  now + 365 days;
        uint256 public _periodFinish = 0;
        uint256 public _rewardRate = 0;
        uint256 public _lastUpdateTime;
        uint256 public _rewardPerTokenStored;
    
        uint256 public _teamRewardRate = 500;
        uint256 public _poolRewardRate = 1000;
        uint256 public _baseRate = 10000;
        uint256 public _punishTime = 3 days;
    
        mapping(address => uint256) public _userRewardPerTokenPaid;
        mapping(address => uint256) public _rewards;
        mapping(address => uint256) public _lastStakedTime;
    
        bool public _hasStart = false;
        uint256 public _fixRateBase = 100000;
        
        uint256 public _totalWeight;
        mapping(address => uint256) public _weightBalances;
        mapping(uint256 => uint256) public _stakeWeightes;
        mapping(uint256 => uint256) public _stakeBalances;
    
        uint256 public _totalBalance;
        mapping(address => uint256) public _degoBalances;
        uint256 public _maxStakedDego = 200 * 1e18;
    
        mapping(address => uint256[]) public _playerGego;
        mapping(uint256 => uint256) public _gegoMapIndex;
        
    
    
        event RewardAdded(uint256 reward);
        event StakedGEGO(address indexed user, uint256 amount);
        event WithdrawnGego(address indexed user, uint256 amount);
        event RewardPaid(address indexed user, uint256 reward);
        event NFTReceived(address operator, address from, uint256 tokenId, bytes data);
    
        constructor(address dego, address gego, address gegoFactory,address playerBook) public {
            _dego = IERC20(dego);
            _gegoToken = IGegoToken(gego);
            _gegoFactory = IGegoFactory(gegoFactory);
            _playerBook = playerBook;
        }
        
    
        modifier updateReward(address account) {
            _rewardPerTokenStored = rewardPerToken();
            _lastUpdateTime = lastTimeRewardApplicable();
            if (account != address(0)) {
                _rewards[account] = earned(account);
                _userRewardPerTokenPaid[account] = _rewardPerTokenStored;
            }
            _;
        }
    
        function setMaxStakedDego(uint256 amount) external onlyGovernance{
            _maxStakedDego = amount;
        }
    
        /* Fee collection for any other token */
        function seize(IERC20 token, uint256 amount) external onlyGovernance{
            require(token != _dego, "reward");
            token.safeTransfer(_governance, amount);
        }
        
        /* Fee collection for any other token */
        function seizeErc721(IERC721 token, uint256 tokenId) external 
        {
            require(token != _gegoToken, "gego stake");
            token.safeTransferFrom(address(this), _governance, tokenId);
        }
    
        function lastTimeRewardApplicable() public view returns (uint256) {
            return Math.min(block.timestamp, _periodFinish);
        }
    
        function rewardPerToken() public view returns (uint256) {
            if (totalSupply() == 0) {
                return _rewardPerTokenStored;
            }
            return
                _rewardPerTokenStored.add(
                    lastTimeRewardApplicable()
                        .sub(_lastUpdateTime)
                        .mul(_rewardRate)
                        .mul(1e18)
                        .div(totalSupply())
                );
        }
    
        function earned(address account) public view returns (uint256) {
            return
                balanceOf(account)
                    .mul(rewardPerToken().sub(_userRewardPerTokenPaid[account]))
                    .div(1e18)
                    .add(_rewards[account]);
        }
    
        
        //the grade is a number between 1-6
        //the quality is a number between 1-10000
        /*
        1   quality	1.1+ 0.1*quality/5000
        2	quality	1.2+ 0.1*(quality-5000)/3000
        3	quality	1.3+ 0.1*(quality-8000/1000
        4	quality	1.4+ 0.2*(quality-9000)/800
        5	quality	1.6+ 0.2*(quality-9800)/180
        6	quality	1.8+ 0.2*(quality-9980)/20
        */
    
        function getFixRate(uint256 grade,uint256 quality) public pure returns (uint256){
    
            require(grade > 0 && grade <7, "the gego not dego");
    
            uint256 unfold = 0;
    
            if( grade == 1 ){
                unfold = quality*10000/5000;
                return unfold.add(110000);
            }else if( grade == 2){
                unfold = quality.sub(5000)*10000/3000;
                return unfold.add(120000);
            }else if( grade == 3){
                unfold = quality.sub(8000)*10000/1000;
               return unfold.add(130000);
            }else if( grade == 4){
                unfold = quality.sub(9000)*20000/800;
               return unfold.add(140000);
            }else if( grade == 5){
                unfold = quality.sub(9800)*20000/180;
                return unfold.add(160000);
            }else{
                unfold = quality.sub(9980)*20000/20;
                return unfold.add(180000);
            }
        }
    
        function getStakeInfo( uint256 gegoId ) public view returns ( uint256 stakeRate, uint256 degoAmount){
    
            uint256 grade;
            uint256 quality;
            uint256 createdTime;
            uint256 blockNum;
            uint256 resId;
            address author;
    
            (grade, quality, degoAmount, createdTime,blockNum, resId, author) = _gegoFactory.getGego(gegoId);
    
            require(degoAmount > 0,"the gego not dego");
    
            stakeRate = getFixRate(grade,quality);
        }
    
        // stake GEGO 
        function stakeGego(uint256 gegoId, string memory affCode)
            public
            updateReward(msg.sender)
            checkHalve
            checkStart
        {
    
            uint256[] storage gegoIds = _playerGego[msg.sender];
            if (gegoIds.length == 0) {
                gegoIds.push(0);    
                _gegoMapIndex[0] = 0;
            }
            gegoIds.push(gegoId);
            _gegoMapIndex[gegoId] = gegoIds.length - 1;
    
            uint256 stakeRate;
            uint256 degoAmount;
            (stakeRate, degoAmount) = getStakeInfo(gegoId);
    
            uint256 stakedDegoAmount = _degoBalances[msg.sender];
            uint256 stakingDegoAmount = stakedDegoAmount.add(degoAmount) <= _maxStakedDego?degoAmount:_maxStakedDego.sub(stakedDegoAmount);
    
    
            if(stakingDegoAmount > 0){
                uint256 stakeWeight = stakeRate.mul(stakingDegoAmount).div(_fixRateBase);
                _degoBalances[msg.sender] = _degoBalances[msg.sender].add(stakingDegoAmount);
    
                _weightBalances[msg.sender] = _weightBalances[msg.sender].add(stakeWeight);
    
                _stakeBalances[gegoId] = stakingDegoAmount;
                _stakeWeightes[gegoId] = stakeWeight;
                
                _totalBalance = _totalBalance.add(stakingDegoAmount);
                _totalWeight = _totalWeight.add(stakeWeight);
            }
    
            _gegoToken.safeTransferFrom(msg.sender, address(this), gegoId);
    
            if (!IPlayerBook(_playerBook).hasRefer(msg.sender)) {
                IPlayerBook(_playerBook).bindRefer(msg.sender, affCode);
            }
            _lastStakedTime[msg.sender] = now;
            emit StakedGEGO(msg.sender, gegoId);
            
        }
        
        function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4) {
            if(_hasStart == false) {
                return 0;
            }
    
            emit NFTReceived(operator, from, tokenId, data);
            return bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"));
        }
    
        function withdrawGego(uint256 gegoId)
            public
            updateReward(msg.sender)
            checkHalve
            checkStart
        {
            require(gegoId > 0, "the gegoId error");
            
            uint256[] memory gegoIds = _playerGego[msg.sender];
            uint256 gegoIndex = _gegoMapIndex[gegoId];
            
            require(gegoIds[gegoIndex] == gegoId, "not gegoId owner");
    
            uint256 gegoArrayLength = gegoIds.length-1;
            uint256 tailId = gegoIds[gegoArrayLength];
    
            _playerGego[msg.sender][gegoIndex] = tailId;
            _playerGego[msg.sender][gegoArrayLength] = 0;
            _playerGego[msg.sender].length--;
            _gegoMapIndex[tailId] = gegoIndex;
            _gegoMapIndex[gegoId] = 0;
    
            uint256 stakeWeight = _stakeWeightes[gegoId];
            _weightBalances[msg.sender] = _weightBalances[msg.sender].sub(stakeWeight);
            _totalWeight = _totalWeight.sub(stakeWeight);
    
            uint256 stakeBalance = _stakeBalances[gegoId];
            _degoBalances[msg.sender] = _degoBalances[msg.sender].sub(stakeBalance);
            _totalBalance = _totalBalance.sub(stakeBalance);
    
    
    
            _gegoToken.safeTransferFrom(address(this), msg.sender, gegoId);
    
            _stakeBalances[gegoId] = 0;
            _stakeWeightes[gegoId] = 0;
    
            emit WithdrawnGego(msg.sender, gegoId);
        }
    
        function withdraw()
            public
            checkStart
        {
    
            uint256[] memory gegoId = _playerGego[msg.sender];
            for (uint8 index = 1; index < gegoId.length; index++) {
                if (gegoId[index] > 0) {
                    withdrawGego(gegoId[index]);
                }
            }
        }
    
        function getPlayerIds( address account ) public view returns( uint256[] memory gegoId )
        {
            gegoId = _playerGego[account];
        }
    
        function exit() external {
            withdraw();
            getReward();
        }
    
        function getReward() public updateReward(msg.sender) checkHalve checkStart {
            uint256 reward = earned(msg.sender);
            if (reward > 0) {
                _rewards[msg.sender] = 0;
    
                uint256 fee = IPlayerBook(_playerBook).settleReward(msg.sender, reward);
                if(fee > 0){
                    _dego.safeTransfer(_playerBook, fee);
                }
                
                uint256 teamReward = reward.mul(_teamRewardRate).div(_baseRate);
                if(teamReward>0){
                    _dego.safeTransfer(_teamWallet, teamReward);
                }
                uint256 leftReward = reward.sub(fee).sub(teamReward);
                uint256 poolReward = 0;
    
                //withdraw time check
    
                if(now  < (_lastStakedTime[msg.sender] + _punishTime) ){
                    poolReward = leftReward.mul(_poolRewardRate).div(_baseRate);
                }
                if(poolReward>0){
                    _dego.safeTransfer(_rewardPool, poolReward);
                    leftReward = leftReward.sub(poolReward);
                }
    
                if(leftReward>0){
                    _dego.safeTransfer(msg.sender, leftReward );
                }
          
                emit RewardPaid(msg.sender, leftReward);
            }
        }
    
        modifier checkHalve() {
            if (block.timestamp >= _periodFinish) {
                _initReward = _initReward.mul(50).div(100);
    
                _dego.mint(address(this), _initReward);
    
                _rewardRate = _initReward.div(DURATION);
                _periodFinish = block.timestamp.add(DURATION);
                emit RewardAdded(_initReward);
            }
            _;
        }
        
        modifier checkStart() {
            require(block.timestamp > _startTime, "not start");
            _;
        }
    
        // set fix time to start reward
        function startNFTReward(uint256 startTime)
            external
            onlyGovernance
            updateReward(address(0))
        {
            require(_hasStart == false, "has started");
            _hasStart = true;
            
            _startTime = startTime;
    
            _rewardRate = _initReward.div(DURATION); 
            _dego.mint(address(this), _initReward);
    
            _lastUpdateTime = _startTime;
            _periodFinish = _startTime.add(DURATION);
    
            emit RewardAdded(_initReward);
        }
    
        //
    
        //for extra reward
        function notifyMintAmount(uint256 reward)
            external
            onlyGovernance
            updateReward(address(0))
        {
            // IERC20(_dego).safeTransferFrom(msg.sender, address(this), reward);
            _dego.mint(address(this), reward);
            if (block.timestamp >= _periodFinish) {
                _rewardRate = reward.div(DURATION);
            } else {
                uint256 remaining = _periodFinish.sub(block.timestamp);
                uint256 leftover = remaining.mul(_rewardRate);
                _rewardRate = reward.add(leftover).div(DURATION);
            }
            _lastUpdateTime = block.timestamp;
            _periodFinish = block.timestamp.add(DURATION);
            emit RewardAdded(reward);
        }
    
        function setTeamRewardRate( uint256 teamRewardRate ) public onlyGovernance {
            _teamRewardRate = teamRewardRate;
        }
    
        function setPoolRewardRate( uint256  poolRewardRate ) public onlyGovernance{
            _poolRewardRate = poolRewardRate;
        }
    
        function totalSupply()  public view returns (uint256) {
            return _totalWeight;
        }
    
        function balanceOf(address account) public view returns (uint256) {
            return _weightBalances[account];
        }
        
        function setWithDrawPunishTime( uint256  punishTime ) public onlyGovernance{
            _punishTime = punishTime;
        }
    
    }

    File 2 of 3: PlayerBook
    /***
     *    ██████╗ ███████╗ ██████╗  ██████╗ 
     *    ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗
     *    ██║  ██║█████╗  ██║  ███╗██║   ██║
     *    ██║  ██║██╔══╝  ██║   ██║██║   ██║
     *    ██████╔╝███████╗╚██████╔╝╚██████╔╝
     *    ╚═════╝ ╚══════╝ ╚═════╝  ╚═════╝ 
     *    
     * https://dego.finance
                                      
    * MIT License
    * ===========
    *
    * Copyright (c) 2020 dego
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    */
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         *
         * _Available since v2.4.0._
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts with custom message when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/GSN/Context.sol
    
    pragma solidity ^0.5.0;
    
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    contract Context {
        // Empty internal constructor, to prevent people from mistakenly deploying
        // an instance of this contract, which should be used via inheritance.
        constructor () internal { }
        // solhint-disable-previous-line no-empty-blocks
    
        function _msgSender() internal view returns (address payable) {
            return msg.sender;
        }
    
        function _msgData() internal view returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    // File: @openzeppelin/contracts/ownership/Ownable.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor () internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(isOwner(), "Ownable: caller is not the owner");
            _;
        }
    
        /**
         * @dev Returns true if the caller is the current owner.
         */
        function isOwner() public view returns (bool) {
            return _msgSender() == _owner;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public onlyOwner {
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         */
        function _transferOwnership(address newOwner) internal {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    // File: contracts/library/NameFilter.sol
    
    pragma solidity ^0.5.0;
    
    library NameFilter {
        /**
         * @dev filters name strings
         * -converts uppercase to lower case.  
         * -makes sure it does not start/end with a space
         * -makes sure it does not contain multiple spaces in a row
         * -cannot be only numbers
         * -cannot start with 0x 
         * -restricts characters to A-Z, a-z, 0-9, and space.
         * @return reprocessed string in bytes32 format
         */
        function nameFilter(string memory _input)
            internal
            pure
            returns(bytes32)
        {
            bytes memory _temp = bytes(_input);
            uint256 _length = _temp.length;
            
            //sorry limited to 32 characters
            require (_length <= 32 && _length > 0, "string must be between 1 and 32 characters");
            // make sure first two characters are not 0x
            if (_temp[0] == 0x30)
            {
                require(_temp[1] != 0x78, "string cannot start with 0x");
                require(_temp[1] != 0x58, "string cannot start with 0X");
            }
            
            // create a bool to track if we have a non number character
            bool _hasNonNumber;
            
            // convert & check
            for (uint256 i = 0; i < _length; i++)
            {
                // if its uppercase A-Z
                if (_temp[i] > 0x40 && _temp[i] < 0x5b)
                {
                    // convert to lower case a-z
                    _temp[i] = byte(uint8(_temp[i]) + 32);
                    
                    // we have a non number
                    if (_hasNonNumber == false)
                        _hasNonNumber = true;
                } else {
                    require
                    (
                        // OR lowercase a-z
                        (_temp[i] > 0x60 && _temp[i] < 0x7b) ||
                        // or 0-9
                        (_temp[i] > 0x2f && _temp[i] < 0x3a),
                        "string contains invalid characters"
                    );
                    
                    // see if we have a character other than a number
                    if (_hasNonNumber == false && (_temp[i] < 0x30 || _temp[i] > 0x39))
                        _hasNonNumber = true;    
                }
            }
            
            require(_hasNonNumber == true, "string cannot be only numbers");
            
            bytes32 _ret;
            assembly {
                _ret := mload(add(_temp, 32))
            }
            return (_ret);
        }
    }
    
    // File: contracts/interface/IERC20.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
     * the optional functions; to access them see {ERC20Detailed}.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        function mint(address account, uint amount) external;
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    pragma solidity ^0.5.5;
    
    /**
     * @dev Collection of functions related to the address type
     */
    library Address {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following 
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly { codehash := extcodehash(account) }
            return (codehash != accountHash && codehash != 0x0);
        }
    
        /**
         * @dev Converts an `address` into `address payable`. Note that this is
         * simply a type cast: the actual underlying value is not changed.
         *
         * _Available since v2.4.0._
         */
        function toPayable(address account) internal pure returns (address payable) {
            return address(uint160(account));
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         *
         * _Available since v2.4.0._
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, "Address: insufficient balance");
    
            // solhint-disable-next-line avoid-call-value
            (bool success, ) = recipient.call.value(amount)("");
            require(success, "Address: unable to send value, recipient may have reverted");
        }
    }
    
    // File: contracts/library/SafeERC20.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    /**
     * @title SafeERC20
     * @dev Wrappers around ERC20 operations that throw on failure (when the token
     * contract returns false). Tokens that return no value (and instead revert or
     * throw on failure) are also supported, non-reverting calls are assumed to be
     * successful.
     * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
     * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
     */
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
    
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
    
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
    
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
    
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    
        /**
         * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
         * on the return value: the return value is optional (but if data is returned, it must not be false).
         * @param token The token targeted by the call.
         * @param data The call data (encoded using abi.encode or one of its variants).
         */
        function callOptionalReturn(IERC20 token, bytes memory data) private {
            // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
            // we're implementing it ourselves.
    
            // A Solidity high level call has three parts:
            //  1. The target address is checked to verify it contains contract code
            //  2. The call itself is made, and success asserted
            //  3. The return value is decoded, which in turn checks the size of the returned data.
            // solhint-disable-next-line max-line-length
            require(address(token).isContract(), "SafeERC20: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, "SafeERC20: low-level call failed");
    
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }
    
    // File: contracts/library/Governance.sol
    
    pragma solidity ^0.5.0;
    
    contract Governance {
    
        address public _governance;
    
        constructor() public {
            _governance = tx.origin;
        }
    
        event GovernanceTransferred(address indexed previousOwner, address indexed newOwner);
    
        modifier onlyGovernance {
            require(msg.sender == _governance, "not governance");
            _;
        }
    
        function setGovernance(address governance)  public  onlyGovernance
        {
            require(governance != address(0), "new governance the zero address");
            emit GovernanceTransferred(_governance, governance);
            _governance = governance;
        }
    
    
    }
    
    // File: contracts/interface/IPlayerBook.sol
    
    pragma solidity ^0.5.0;
    
    
    interface IPlayerBook {
        function settleReward( address from,uint256 amount ) external returns (uint256);
        function bindRefer( address from,string calldata  affCode )  external returns (bool);
        function hasRefer(address from) external returns(bool);
    
    }
    
    // File: contracts/referral/PlayerBook.sol
    
    pragma solidity ^0.5.0;
    
    
    
    
    
    
    
    contract PlayerBook is Governance, IPlayerBook {
        using NameFilter for string;
        using SafeMath for uint256;
        using SafeERC20 for IERC20;
     
        // register pools       
        mapping (address => bool) public _pools;
    
        // (addr => pID) returns player id by address
        mapping (address => uint256) public _pIDxAddr;   
        // (name => pID) returns player id by name      
        mapping (bytes32 => uint256) public _pIDxName;    
        // (pID => data) player data     
        mapping (uint256 => Player) public _plyr;      
        // (pID => name => bool) list of names a player owns.  (used so you can change your display name amoungst any name you own)        
        mapping (uint256 => mapping (bytes32 => bool)) public _plyrNames; 
      
        // the  of refrerrals
        uint256 public _totalReferReward;         
        // total number of players
        uint256 public _pID;      
        // total register name count
        uint256 public _totalRegisterCount = 0;
    
        // the direct refer's reward rate
        uint256 public _refer1RewardRate = 700; //7%
        // the second direct refer's reward rate
        uint256 public _refer2RewardRate = 300; //3%
        // base rate
        uint256 public _baseRate = 10000;
    
        // base price to register a name
        uint256 public _registrationBaseFee = 100 finney;     
        // register fee count step
        uint256 public _registrationStep = 100;
        // add base price for one step
        uint256 public _stepFee = 100 finney;     
    
        bytes32 public _defaulRefer ="dego";
    
        address payable public _teamWallet = 0x3D0a845C5ef9741De999FC068f70E2048A489F2b;
      
        IERC20 public _dego = IERC20(0x0);
       
        struct Player {
            address addr;
            bytes32 name;
            uint8 nameCount;
            uint256 laff;
            uint256 amount;
            uint256 rreward;
            uint256 allReward;
            uint256 lv1Count;
            uint256 lv2Count;
        }
    
        event eveClaim(uint256 pID, address addr, uint256 reward, uint256 balance );
        event eveBindRefer(uint256 pID, address addr, bytes32 name, uint256 affID, address affAddr, bytes32 affName);
        event eveDefaultPlayer(uint256 pID, address addr, bytes32 name);      
        event eveNewName(uint256 pID, address addr, bytes32 name, uint256 affID, address affAddr, bytes32 affName, uint256 balance  );
        event eveSettle(uint256 pID, uint256 affID, uint256 aff_affID, uint256 affReward, uint256 aff_affReward, uint256 amount);
        event eveAddPool(address addr);
        event eveRemovePool(address addr);
    
    
        constructor()
            public
        {
            _pID = 0;
            _totalReferReward = 0;
            addDefaultPlayer(_teamWallet,_defaulRefer);
        }
    
        /**
         * check address
         */
        modifier validAddress( address addr ) {
            require(addr != address(0x0));
            _;
        }
    
        /**
         * check pool
         */
        modifier isRegisteredPool(){
            require(_pools[msg.sender],"invalid pool address!");
            _;
        }
    
        /**
         * contract dego balances
         */
        function balances()
            public
            view
            returns(uint256)
        {
            return (_dego.balanceOf(address(this)));
        }
    
        // only function for creating additional rewards from dust
        function seize(IERC20 asset) external returns (uint256 balance) {
            require(address(_dego) != address(asset), "forbbiden dego");
    
            balance = asset.balanceOf(address(this));
            asset.safeTransfer(_teamWallet, balance);
        }
    
        // get register fee 
        function seizeEth() external  {
            uint256 _currentBalance =  address(this).balance;
            _teamWallet.transfer(_currentBalance);
        }
        
        /**
         * revert invalid transfer action
         */
        function() external payable {
            revert();
        }
    
    
        /**
         * registe a pool
         */
        function addPool(address poolAddr)
            onlyGovernance
            public
        {
            require( !_pools[poolAddr], "derp, that pool already been registered");
    
            _pools[poolAddr] = true;
    
            emit eveAddPool(poolAddr);
        }
        
        /**
         * remove a pool
         */
        function removePool(address poolAddr)
            onlyGovernance
            public
        {
            require( _pools[poolAddr], "derp, that pool must be registered");
    
            _pools[poolAddr] = false;
    
            emit eveRemovePool(poolAddr);
        }
    
        /**
         * resolve the refer's reward from a player 
         */
        function settleReward(address from, uint256 amount)
            isRegisteredPool()
            validAddress(from)    
            external
            returns (uint256)
        {
             // set up our tx event data and determine if player is new or not
            _determinePID(from);
    
            uint256 pID = _pIDxAddr[from];
            uint256 affID = _plyr[pID].laff;
            
            if(affID <= 0 ){
                affID = _pIDxName[_defaulRefer];
                _plyr[pID].laff = affID;
            }
    
            if(amount <= 0){
                return 0;
            }
    
            uint256 fee = 0;
    
            // father
            uint256 affReward = (amount.mul(_refer1RewardRate)).div(_baseRate);
            _plyr[affID].rreward = _plyr[affID].rreward.add(affReward);
            _totalReferReward = _totalReferReward.add(affReward);
            fee = fee.add(affReward);
    
    
            // grandfather
            uint256 aff_affID = _plyr[affID].laff;
            uint256 aff_affReward = amount.mul(_refer2RewardRate).div(_baseRate);
            if(aff_affID <= 0){
                aff_affID = _pIDxName[_defaulRefer];
            }
            _plyr[aff_affID].rreward = _plyr[aff_affID].rreward.add(aff_affReward);
            _totalReferReward= _totalReferReward.add(aff_affReward);
    
            _plyr[pID].amount = _plyr[pID].amount.add( amount);
    
            fee = fee.add(aff_affReward);
           
            emit eveSettle( pID,affID,aff_affID,affReward,aff_affReward,amount);
    
            return fee;
        }
    
        /**
         * claim all of the refer reward.
         */
        function claim()
            public
        {
            address addr = msg.sender;
            uint256 pid = _pIDxAddr[addr];
            uint256 reward = _plyr[pid].rreward;
    
            require(reward > 0,"only have reward");
            
            //reset
            _plyr[pid].allReward = _plyr[pid].allReward.add(reward);
            _plyr[pid].rreward = 0;
    
            //get reward
            _dego.safeTransfer(addr, reward);
            
            // fire event
            emit eveClaim(_pIDxAddr[addr], addr, reward, balances());
        }
    
    
        /**
         * check name string
         */
        function checkIfNameValid(string memory nameStr)
            public
            view
            returns(bool)
        {
            bytes32 name = nameStr.nameFilter();
            if (_pIDxName[name] == 0)
                return (true);
            else 
                return (false);
        }
        
        /**
         * @dev add a default player
         */
        function addDefaultPlayer(address addr, bytes32 name)
            private
        {        
            _pID++;
    
            _plyr[_pID].addr = addr;
            _plyr[_pID].name = name;
            _plyr[_pID].nameCount = 1;
            _pIDxAddr[addr] = _pID;
            _pIDxName[name] = _pID;
            _plyrNames[_pID][name] = true;
    
            //fire event
            emit eveDefaultPlayer(_pID,addr,name);        
        }
        
        /**
         * @dev set refer reward rate
         */
        function setReferRewardRate(uint256 refer1Rate, uint256 refer2Rate ) public  
            onlyGovernance
        {
            _refer1RewardRate = refer1Rate;
            _refer2RewardRate = refer2Rate;
        }
    
        /**
         * @dev set registration step count
         */
        function setRegistrationStep(uint256 registrationStep) public  
            onlyGovernance
        {
            _registrationStep = registrationStep;
        }
    
        /**
         * @dev set dego contract address
         */
        function setDegoContract(address dego)  public  
            onlyGovernance{
            _dego = IERC20(dego);
        }
    
    
        /**
         * @dev registers a name.  UI will always display the last name you registered.
         * but you will still own all previously registered names to use as affiliate 
         * links.
         * - must pay a registration fee.
         * - name must be unique
         * - names will be converted to lowercase
         * - cannot be only numbers
         * - cannot start with 0x 
         * - name must be at least 1 char
         * - max length of 32 characters long
         * - allowed characters: a-z, 0-9
         * -functionhash- 0x921dec21 (using ID for affiliate)
         * -functionhash- 0x3ddd4698 (using address for affiliate)
         * -functionhash- 0x685ffd83 (using name for affiliate)
         * @param nameString players desired name
         * @param affCode affiliate name of who refered you
         * (this might cost a lot of gas)
         */
    
        function registerNameXName(string memory nameString, string memory affCode)
            public
            payable 
        {
    
            // make sure name fees paid
            require (msg.value >= this.getRegistrationFee(), "umm.....  you have to pay the name fee");
    
            // filter name + condition checks
            bytes32 name = NameFilter.nameFilter(nameString);
            // if names already has been used
            require(_pIDxName[name] == 0, "sorry that names already taken");
    
            // set up address 
            address addr = msg.sender;
             // set up our tx event data and determine if player is new or not
            _determinePID(addr);
            // fetch player id
            uint256 pID = _pIDxAddr[addr];
            // if names already has been used
            require(_plyrNames[pID][name] == false, "sorry that names already taken");
    
            // add name to player profile, registry, and name book
            _plyrNames[pID][name] = true;
            _pIDxName[name] = pID;   
            _plyr[pID].name = name;
            _plyr[pID].nameCount++;
    
            _totalRegisterCount++;
    
    
            //try bind a refer
            if(_plyr[pID].laff == 0){
    
                bytes memory tempCode = bytes(affCode);
                bytes32 affName = 0x0;
                if (tempCode.length >= 0) {
                    assembly {
                        affName := mload(add(tempCode, 32))
                    }
                }
    
                _bindRefer(addr,affName);
            }
            uint256 affID = _plyr[pID].laff;
    
            // fire event
            emit eveNewName(pID, addr, name, affID, _plyr[affID].addr, _plyr[affID].name, _registrationBaseFee );
        }
        
        /**
         * @dev bind a refer,if affcode invalid, use default refer
         */  
        function bindRefer( address from, string calldata  affCode )
            isRegisteredPool()
            external
            returns (bool)
        {
    
            bytes memory tempCode = bytes(affCode);
            bytes32 affName = 0x0;
            if (tempCode.length >= 0) {
                assembly {
                    affName := mload(add(tempCode, 32))
                }
            }
    
            return _bindRefer(from, affName);
        }
    
    
        /**
         * @dev bind a refer,if affcode invalid, use default refer
         */  
        function _bindRefer( address from, bytes32  name )
            validAddress(msg.sender)    
            validAddress(from)  
            private
            returns (bool)
        {
            // set up our tx event data and determine if player is new or not
            _determinePID(from);
    
            // fetch player id
            uint256 pID = _pIDxAddr[from];
            if( _plyr[pID].laff != 0){
                return false;
            }
    
            if (_pIDxName[name] == 0){
                //unregister name 
                name = _defaulRefer;
            }
          
            uint256 affID = _pIDxName[name];
            if( affID == pID){
                affID = _pIDxName[_defaulRefer];
            }
           
            _plyr[pID].laff = affID;
    
            //lvcount
            _plyr[affID].lv1Count++;
            uint256 aff_affID = _plyr[affID].laff;
            if(aff_affID != 0 ){
                _plyr[aff_affID].lv2Count++;
            }
            
            // fire event
            emit eveBindRefer(pID, from, name, affID, _plyr[affID].addr, _plyr[affID].name);
    
            return true;
        }
        
        //
        function _determinePID(address addr)
            private
            returns (bool)
        {
            if (_pIDxAddr[addr] == 0)
            {
                _pID++;
                _pIDxAddr[addr] = _pID;
                _plyr[_pID].addr = addr;
                
                // set the new player bool to true
                return (true);
            } else {
                return (false);
            }
        }
        
        function hasRefer(address from) 
            isRegisteredPool()
            external 
            returns(bool) 
        {
            _determinePID(from);
            uint256 pID =  _pIDxAddr[from];
            return (_plyr[pID].laff > 0);
        }
    
        
        function getPlayerName(address from)
            external
            view
            returns (bytes32)
        {
            uint256 pID =  _pIDxAddr[from];
            if(_pID==0){
                return "";
            }
            return (_plyr[pID].name);
        }
    
        function getPlayerLaffName(address from)
            external
            view
            returns (bytes32)
        {
            uint256 pID =  _pIDxAddr[from];
            if(_pID==0){
                 return "";
            }
    
            uint256 aID=_plyr[pID].laff;
            if( aID== 0){
                return "";
            }
    
            return (_plyr[aID].name);
        }
    
        function getPlayerInfo(address from)
            external
            view
            returns (uint256,uint256,uint256,uint256)
        {
            uint256 pID = _pIDxAddr[from];
            if(_pID==0){
                 return (0,0,0,0);
            }
            return (_plyr[pID].rreward,_plyr[pID].allReward,_plyr[pID].lv1Count,_plyr[pID].lv2Count);
        }
    
        function getTotalReferReward()
            external
            view
            returns (uint256)
        {
            return(_totalReferReward);
        }
    
        function getRegistrationFee()
            external
            view
            returns (uint256)
        {
            if( _totalRegisterCount <_registrationStep || _registrationStep == 0){
                return _registrationBaseFee;
            }
            else{
                uint256 step = _totalRegisterCount.div(_registrationStep);
                return _registrationBaseFee.add(step.mul(_stepFee));
            }
        }
    }

    File 3 of 3: DegoToken
    /***
     *    ██████╗ ███████╗ ██████╗  ██████╗ 
     *    ██╔══██╗██╔════╝██╔════╝ ██╔═══██╗
     *    ██║  ██║█████╗  ██║  ███╗██║   ██║
     *    ██║  ██║██╔══╝  ██║   ██║██║   ██║
     *    ██████╔╝███████╗╚██████╔╝╚██████╔╝
     *    ╚═════╝ ╚══════╝ ╚═════╝  ╚═════╝ 
     *    
     * https://dego.finance
                                      
    * MIT License
    * ===========
    *
    * Copyright (c) 2020 dego
    *
    * Permission is hereby granted, free of charge, to any person obtaining a copy
    * of this software and associated documentation files (the "Software"), to deal
    * in the Software without restriction, including without limitation the rights
    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    * copies of the Software, and to permit persons to whom the Software is
    * furnished to do so, subject to the following conditions:
    *
    * The above copyright notice and this permission notice shall be included in all
    * copies or substantial portions of the Software.
    *
    * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    */
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         * - Subtraction cannot overflow.
         *
         * _Available since v2.4.0._
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
    
            return c;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
                return 0;
            }
    
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
    
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    
            return c;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * Reverts with custom message when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         * - The divisor cannot be zero.
         *
         * _Available since v2.4.0._
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
    
    pragma solidity ^0.5.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
     * the optional functions; to access them see {ERC20Detailed}.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    // File: @openzeppelin/contracts/token/ERC20/ERC20Detailed.sol
    
    pragma solidity ^0.5.0;
    
    
    /**
     * @dev Optional functions from the ERC20 standard.
     */
    contract ERC20Detailed is IERC20 {
        string private _name;
        string private _symbol;
        uint8 private _decimals;
    
        /**
         * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
         * these values are immutable: they can only be set once during
         * construction.
         */
        constructor (string memory name, string memory symbol, uint8 decimals) public {
            _name = name;
            _symbol = symbol;
            _decimals = decimals;
        }
    
        /**
         * @dev Returns the name of the token.
         */
        function name() public view returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public view returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev Returns the number of decimals used to get its user representation.
         * For example, if `decimals` equals `2`, a balance of `505` tokens should
         * be displayed to a user as `5,05` (`505 / 10 ** 2`).
         *
         * Tokens usually opt for a value of 18, imitating the relationship between
         * Ether and Wei.
         *
         * NOTE: This information is only used for _display_ purposes: it in
         * no way affects any of the arithmetic of the contract, including
         * {IERC20-balanceOf} and {IERC20-transfer}.
         */
        function decimals() public view returns (uint8) {
            return _decimals;
        }
    }
    
    // File: contracts/library/Governance.sol
    
    pragma solidity ^0.5.5;
    
    contract Governance {
    
        address public governance;
    
        constructor() public {
            governance = tx.origin;
        }
    
        event GovernanceTransferred(address indexed previousOwner, address indexed newOwner);
    
        modifier onlyGovernance {
            require(msg.sender == governance, "not governance");
            _;
        }
    
        function setGovernance(address _governance)  public  onlyGovernance
        {
            require(_governance != address(0), "new governance the zero address");
            emit GovernanceTransferred(governance, _governance);
            governance = _governance;
        }
    
    
    
    }
    
    // File: contracts/token/DegoToken.sol
    
    pragma solidity ^0.5.5;
    
    
    
    
    /// @title DegoToken Contract
    
    contract DegoToken is Governance, ERC20Detailed{
    
        using SafeMath for uint256;
    
        //events
        event eveSetRate(uint256 burn_rate, uint256 reward_rate);
        event eveRewardPool(address rewardPool);
        event Transfer(address indexed from, address indexed to, uint256 value);
        event Mint(address indexed from, address indexed to, uint256 value);
        event Approval(address indexed owner, address indexed spender, uint256 value);
    
        // for minters
        mapping (address => bool) public _minters;
    
        //token base data
        uint256 internal _totalSupply;
        mapping(address => uint256) public _balances;
        mapping (address => mapping (address => uint256)) public _allowances;
    
        /// Constant token specific fields
        uint256 public  _maxSupply = 0;
    
        ///
        bool public _openTransfer = false;
    
        // hardcode limit rate
        uint256 public constant _maxGovernValueRate = 2000;//2000/10000
        uint256 public constant _minGovernValueRate = 10;  //10/10000
        uint256 public constant _rateBase = 10000; 
    
        // additional variables for use if transaction fees ever became necessary
        uint256 public  _burnRate = 250;       
        uint256 public  _rewardRate = 250;   
    
        uint256 public _totalBurnToken = 0;
        uint256 public _totalRewardToken = 0;
    
        //todo reward pool!
        address public _rewardPool = 0xEA6dEc98e137a87F78495a8386f7A137408f7722;
        //todo burn pool!
        address public _burnPool = 0x6666666666666666666666666666666666666666;
    
        /**
        * @dev set the token transfer switch
        */
        function enableOpenTransfer() public onlyGovernance  
        {
            _openTransfer = true;
        }
    
    
        /**
         * CONSTRUCTOR
         *
         * @dev Initialize the Token
         */
    
        constructor () public ERC20Detailed("dego.finance", "DEGO", 18) {
             _maxSupply = 21000000 * (10**18);
        }
    
    
        
        /**
        * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
        * @param spender The address which will spend the funds.
        * @param amount The amount of tokens to be spent.
        */
        function approve(address spender, uint256 amount) external 
        returns (bool) 
        {
            require(msg.sender != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[msg.sender][spender] = amount;
            emit Approval(msg.sender, spender, amount);
    
            return true;
        }
    
        /**
        * @dev Function to check the amount of tokens than an owner _allowed to a spender.
        * @param owner address The address which owns the funds.
        * @param spender address The address which will spend the funds.
        * @return A uint256 specifying the amount of tokens still available for the spender.
        */
        function allowance(address owner, address spender) external view 
        returns (uint256) 
        {
            return _allowances[owner][spender];
        }
    
        /**
        * @dev Gets the balance of the specified address.
        * @param owner The address to query the the balance of.
        * @return An uint256 representing the amount owned by the passed address.
        */
        function balanceOf(address owner) external  view 
        returns (uint256) 
        {
            return _balances[owner];
        }
    
        /**
        * @dev return the token total supply
        */
        function totalSupply() external view 
        returns (uint256) 
        {
            return _totalSupply;
        }
    
        /**
        * @dev for mint function
        */
        function mint(address account, uint256 amount) external 
        {
            require(account != address(0), "ERC20: mint to the zero address");
            require(_minters[msg.sender], "!minter");
    
            uint256 curMintSupply = _totalSupply.add(_totalBurnToken);
            uint256 newMintSupply = curMintSupply.add(amount);
            require( newMintSupply <= _maxSupply,"supply is max!");
          
            _totalSupply = _totalSupply.add(amount);
            _balances[account] = _balances[account].add(amount);
    
            emit Mint(address(0), account, amount);
            emit Transfer(address(0), account, amount);
        }
    
        function addMinter(address _minter) public onlyGovernance 
        {
            _minters[_minter] = true;
        }
        
        function removeMinter(address _minter) public onlyGovernance 
        {
            _minters[_minter] = false;
        }
        
    
        function() external payable {
            revert();
        }
    
        /**
        * @dev for govern value
        */
        function setRate(uint256 burn_rate, uint256 reward_rate) public 
            onlyGovernance 
        {
            
            require(_maxGovernValueRate >= burn_rate && burn_rate >= _minGovernValueRate,"invalid burn rate");
            require(_maxGovernValueRate >= reward_rate && reward_rate >= _minGovernValueRate,"invalid reward rate");
    
            _burnRate = burn_rate;
            _rewardRate = reward_rate;
    
            emit eveSetRate(burn_rate, reward_rate);
        }
    
    
        /**
        * @dev for set reward
        */
        function setRewardPool(address rewardPool) public 
            onlyGovernance 
        {
            require(rewardPool != address(0x0));
    
            _rewardPool = rewardPool;
    
            emit eveRewardPool(_rewardPool);
        }
        /**
        * @dev transfer token for a specified address
        * @param to The address to transfer to.
        * @param value The amount to be transferred.
        */
       function transfer(address to, uint256 value) external 
       returns (bool)  
       {
            return _transfer(msg.sender,to,value);
        }
    
        /**
        * @dev Transfer tokens from one address to another
        * @param from address The address which you want to send tokens from
        * @param to address The address which you want to transfer to
        * @param value uint256 the amount of tokens to be transferred
        */
        function transferFrom(address from, address to, uint256 value) external 
        returns (bool) 
        {
            uint256 allow = _allowances[from][msg.sender];
            _allowances[from][msg.sender] = allow.sub(value);
            
            return _transfer(from,to,value);
        }
    
     
    
        /**
        * @dev Transfer tokens with fee
        * @param from address The address which you want to send tokens from
        * @param to address The address which you want to transfer to
        * @param value uint256s the amount of tokens to be transferred
        */
        function _transfer(address from, address to, uint256 value) internal 
        returns (bool) 
        {
            // :)
            require(_openTransfer || from == governance, "transfer closed");
    
            require(from != address(0), "ERC20: transfer from the zero address");
            require(to != address(0), "ERC20: transfer to the zero address");
    
            uint256 sendAmount = value;
            uint256 burnFee = (value.mul(_burnRate)).div(_rateBase);
            if (burnFee > 0) {
                //to burn
                _balances[_burnPool] = _balances[_burnPool].add(burnFee);
                _totalSupply = _totalSupply.sub(burnFee);
                sendAmount = sendAmount.sub(burnFee);
    
                _totalBurnToken = _totalBurnToken.add(burnFee);
    
                emit Transfer(from, _burnPool, burnFee);
            }
    
            uint256 rewardFee = (value.mul(_rewardRate)).div(_rateBase);
            if (rewardFee > 0) {
               //to reward
                _balances[_rewardPool] = _balances[_rewardPool].add(rewardFee);
                sendAmount = sendAmount.sub(rewardFee);
    
                _totalRewardToken = _totalRewardToken.add(rewardFee);
    
                emit Transfer(from, _rewardPool, rewardFee);
            }
    
            _balances[from] = _balances[from].sub(value);
            _balances[to] = _balances[to].add(sendAmount);
    
            emit Transfer(from, to, sendAmount);
    
            return true;
        }
    }