ETH Price: $4,005.23 (+2.89%)

Contract Diff Checker

Contract Name:
Coin98Stake

Contract Source Code:

File 1 of 1 : Coin98Stake

/**
 *Submitted for verification at BscScan.com on 2021-09-14
*/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.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.
     */
    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.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        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.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

/**
 * @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);
    }
}

interface IBEP20 {
    function totalSupply() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
    function transfer(address recipient, uint amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint);
    function approve(address spender, uint amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint value);
    event Approval(address indexed owner, address indexed spender, uint value);
}

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

interface IERC721 is IERC165 {
    event Transfer(address indexed from, address indexed to, uint indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    function balanceOf(address owner) external view returns (uint balance);
    function ownerOf(uint tokenId) external view returns (address owner);
    function safeTransferFrom(address from, address to, uint tokenId) external;
    function transferFrom(address from, address to, uint tokenId) external;
    function approve(address to, uint tokenId) external;
    function getApproved(uint tokenId) external view returns (address operator);
    function setApprovalForAll(address operator, bool _approved) external;
    function isApprovedForAll(address owner, address operator) external view returns (bool);
    function safeTransferFrom(address from, address to, uint tokenId, bytes calldata data) external;
}

interface IERC721Receiver {
    function onERC721Received(address operator, address from, uint tokenId, bytes calldata data) external returns (bytes4);
}

interface IERC721Metadata is IERC721 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function tokenURI(uint tokenId) external view returns (string memory);
}

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) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }

    /**
     * @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].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

library Strings {
    bytes16 private constant alphabet = "0123456789abcdef";

    /**
     * @dev Converts a `uint` to its ASCII `string` decimal representation.
     */
    function toString(uint value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint temp = value;
        uint digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}

library Math {
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

abstract contract Context {
    function _msgSender() internal view returns (address payable) {
        return payable(msg.sender);
    }
    function _msgData() internal view returns (bytes memory) {
        this;
        return msg.data;
    }
}

abstract 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() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override
    returns (bool)
    {
        return interfaceId == type(IERC165).interfaceId;
    }
}

contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint) private _balances;

    // Mapping from token ID to approved address
    mapping(uint => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(ERC165, IERC165)
    returns (bool)
    {
        return
        interfaceId == type(IERC721).interfaceId ||
        interfaceId == type(IERC721Metadata).interfaceId ||
        super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner)
    public
    view
    virtual
    override
    returns (uint)
    {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint tokenId)
    public
    view
    virtual
    override
    returns (address)
    {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint tokenId)
    public
    view
    virtual
    override
    returns (string memory)
    {
        require(
            _exists(tokenId),
            "ERC721Metadata: URI query for nonexistent token"
        );

        string memory baseURI = _baseURI();
        return
        bytes(baseURI).length > 0
        ? string(abi.encodePacked(baseURI, tokenId.toString()))
        : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. Empty by default, can be overriden
     * in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint tokenId)
    public
    view
    virtual
    override
    returns (address)
    {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved)
    public
    virtual
    override
    {
        require(operator != _msgSender(), "ERC721: approve to caller");

        _operatorApprovals[_msgSender()][operator] = approved;
        emit ApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator)
    public
    view
    virtual
    override
    returns (bool)
    {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) public virtual override {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );
        _safeTransfer(from, to, tokenId, _data);
    }

    function _safeTransfer(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(
            _checkOnERC721Received(from, to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    function _exists(uint tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    function _isApprovedOrOwner(address spender, uint tokenId)
    internal
    view
    virtual
    returns (bool)
    {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner ||
        getApproved(tokenId) == spender ||
        ERC721.isApprovedForAll(owner, spender));
    }

    function _safeMint(address to, uint tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    function _safeMint(
        address to,
        uint tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    function _mint(address to, uint tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

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

    function _burn(uint tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

    function _transfer(
        address from,
        address to,
        uint tokenId
    ) internal virtual {
        require(
            ERC721.ownerOf(tokenId) == from,
            "ERC721: transfer of token that is not own"
        );
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    function _approve(address to, uint tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try
            IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data)
            returns (bytes4 retval) {
                return retval == IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint tokenId
    ) internal virtual {}
}

interface IERC721Enumerable is IERC721 {
    function totalSupply() external view returns (uint);
    function tokenOfOwnerByIndex(address owner, uint index) external view returns (uint tokenId);
    function tokenByIndex(uint index) external view returns (uint);
}

abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint => uint)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint => uint) private _ownedTokensIndex;

    // The current index of the token
    uint currentIndex;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(IERC165, ERC721)
    returns (bool)
    {
        return
        interfaceId == type(IERC721Enumerable).interfaceId ||
        super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint index)
    public
    view
    virtual
    override
    returns (uint)
    {
        require(
            index < ERC721.balanceOf(owner),
            "ERC721Enumerable: owner index out of bounds"
        );
        return _ownedTokens[owner][uint(index)];
    }

    function totalSupply() public view virtual override returns (uint) {
        return currentIndex;
    }

    function tokenByIndex(uint index)
    public
    view
    virtual
    override
    returns (uint)
    {
        require(
            index < currentIndex,
            "ERC721Enumerable: global index out of bounds"
        );
        return index;
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint tokenId
    ) internal virtual override {
        require (to != address(0), "Token not burnable");

        super._beforeTokenTransfer(from, to, tokenId);

        if (from == address(0)) {
            currentIndex++;
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }

        if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    function _addTokenToOwnerEnumeration(address to, uint tokenId) private {
        uint length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    function _removeTokenFromOwnerEnumeration(address from, uint 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).

        uint lastTokenIndex = uint(ERC721.balanceOf(from) - 1);
        uint tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint 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
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }
}

library Convertible {
    function convertAddressToString(address sender) internal pure returns (string memory) {
        return toString(abi.encodePacked(sender));
    }

    function compareStrings(string memory a, string memory b) internal pure returns (bool) {
        return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
    }

    function toString(bytes memory data) public pure returns(string memory) {
        bytes memory alphabet = "0123456789abcdef";

        bytes memory str = new bytes(2 + data.length * 2);
        str[0] = "0";
        str[1] = "x";
        for (uint i = 0; i < data.length; i++) {
            str[2+i*2] = alphabet[uint(uint8(data[i] >> 4))];
            str[3+i*2] = alphabet[uint(uint8(data[i] & 0x0f))];
        }
        return string(str);
    }
    
    function sliceString(uint256 begin, uint256 end, string memory text) internal pure returns (string memory) {
        bytes memory a = new bytes(end-begin+1);
        for(uint i=0;i<=end-begin;i++){
            a[i] = bytes(text)[i+begin-1];
        }
        return string(a);    
    }
    
    function stringToBytes32(string memory source) internal pure returns (bytes32 result) {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
            return 0x0;
        }
    
        assembly {
            result := mload(add(source, 32))
        }
    }
    
    function uint2str(uint256 _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len;
        while (_i != 0) {
            k = k-1;
            uint8 temp = (48 + uint8(_i - _i / 10 * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }

    /// @dev Converts a numeric string to it's unsigned integer representation.
    /// @param v The string to be converted.
    function bytesToUInt(bytes32 v) pure internal returns (uint256 ret) {
        if (v == 0x0) {
            revert();
        }

        uint digit;

        for (uint i = 0; i < 32; i++) {
            digit = uint((uint(v) / (2 ** (8 * (31 - i)))) & 0xff);
            if (digit == 0) {
                break;
            }
            else if (digit < 48 || digit > 57) {
               revert();
            }
            ret *= 10;
            ret += (digit - 48);
        }
        return ret;
    }
}

/**
 * @title SafeERC20
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IBEP20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IBEP20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IBEP20 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'
        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(
        IBEP20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IBEP20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _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(IBEP20 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. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

/**
 * Coin98 Staking Contract
 * The main Token used for staking is Coin98 (C98)
 * Each staking in the Contract will have an NFT ID with a prefix + 12 random numbers
 * The Default locked time after staking is based on locked_time (E.g 15 days)
 * The Default floating_rate is the profit when a user does not meet the condition in any package and wants to withdraw soon
 * Example 9898 1234 5678 9101
 * Naming will be free at the first time when first inititiating a staking. After that, will charge a naming_fee will be charged each time the staking name is changed
 */
contract Coin98Stake is ERC721Enumerable, Ownable {
    using SafeERC20 for IBEP20;
    using SafeMath for uint256;
    using Counters for Counters.Counter;
    
    uint256 private Percent = 10000;
    uint256 yearTimestamp = 31104000;
    
    string public baseTokenURI;
    Counters.Counter private _tokenIdTracker;

    // Meta information
    struct MetaInfo {
        uint256 total_staked; // Total Meta staked amount
        uint256 max_staked; // Max Meta staked amount
        uint256 naming_fee; // The Fee charged when changing the Staking name
        uint256 id_fee; // The Fee charged when user wants to customize NFT ID
        uint256 locked_time; // The Lock time after tokens are deposited
        uint256 pending_time; // The Pending time after over staked time
        uint256 floating_rate; // Floating rate
        string name_prefix; // Prefix first for Name
        string nft_prefix; // Prefix first for NFT ID
    }
    
    // Package information
    struct PackageInfo {
        address meta; // Meta token address
        uint256 min; // Min package amount
        uint256 max; // Max package amount
        uint256 time; // Package time
        uint256 rate; // Package rate
    }
    
    // Stake information
    struct StakeInfo {
        bool pending_flag; // Flag for checking pending_time
        bool flag; // Flag for check staked status
        string name; // Staking name
        uint256 amount; // Staking amount
        uint256 time; // Staking time
        string packageID; // Package ID
        
        bool isCustomID; // Flag for checking the custom ID
        address meta; // Meta token address
        uint256 package_time; // Package time
        uint256 pending_time; // Pending time
        uint256 rate; // Package rate

        // Saved Informations after unstaked        
        uint256 unstaked_time; // Unstaked Time
        uint256 claim_pending_time; // Claim Pending Time
        uint256 earn_staked; // Earn Staked

        // Read Informations
        uint256 id; // NFT ID
        uint256 est_staked; // Estimated Staked
    }

   // Map the meta address for each Meta information
    mapping(address => MetaInfo) public MetaInfos;
    // Map the package id for each information
    mapping(string => PackageInfo) public PackageInfos;
    // Map the stakeId for each information
    mapping(uint256 => StakeInfo) private StakeInfos;
    
    // emit event when a user starts staking
    event _stake(uint256 id,bool isCustomID);
    // emit event when a user renames an NFT
    event _renaming(uint256 id,string name);
    // emit event when a user unstakes
    event _unstake(uint256 id,uint256 amount, uint256 time);
    // emit event when a user claim pending
    event _claim(uint256 id,uint256 amount, uint256 time);

    constructor(string memory baseURI) ERC721("Coin98 Staking Certificate", "C98SC"){
        setBaseURI(baseURI);
    }

    /**
     * @dev Register a new meta for the package register in
     *
     * Requirements:
     *
     * - `token` the meta staked token.
     * - `max` the maximum staked amount in meta.
     * - `naming_fee` the fee charged when changing an NFT's name.
     * - `id_fee` the fee charged when customizing an NFT's ID.
     * - `lockedTime` the lock time after depositing tokens
     * - `pending_time` the pending time after over staked time
     * - `floatingRate` the default rate when a user does not meet the package rate condition.
     * - `name_prefix` the prefix first for name NFT
     * - `nft_prefix` the prefix first for NFT ID
     */
    function registerMeta(
        address _token,
        uint256 _max_staked,
        uint256 _naming_fee,
        uint256 _id_fee,
        uint256 _locked_time,
        uint256 _pending_time,
        uint256 _floating_rate,
        string memory _name_prefix,
        string memory _nft_prefix
    )
        public
        onlyOwner()
    {
        uint256 nameSize = bytes(_name_prefix).length;
        require(nameSize <= 5, "C98Stake: Name prefix size error");
        uint256 nftPrefixSize = bytes(_nft_prefix).length;
        require(nftPrefixSize == 4, "C98Stake: NFT prefix size error");

        MetaInfo storage metaInfo = MetaInfos[_token];

        metaInfo.floating_rate = _floating_rate;
        metaInfo.max_staked = _max_staked;
        metaInfo.naming_fee = _naming_fee;
        metaInfo.id_fee = _id_fee;
        metaInfo.pending_time = _pending_time;
        metaInfo.locked_time = _locked_time;
        metaInfo.name_prefix = _name_prefix;
        metaInfo.nft_prefix = _nft_prefix;
    }

    function validMeta(address _token) internal view returns (bool isValid){
        return MetaInfos[_token].max_staked > 0;
    }
    
    /**
     * @dev Check validate package condition
     *
     * Requirements:
     *
     * - `package` must be existed.
     * - `min` must be larger than zero and less than max.
     * - `max` must be larger than zero and larger than min.
     */
    function validPackage(string memory _package) internal view returns (bool isValid){
        PackageInfo memory pkInfo = PackageInfos[_package];
        
        return pkInfo.min > 0 && pkInfo.max > 0 && pkInfo.min < pkInfo.max;
    }
    
    function validPackageCondition(uint256 _min, uint256 _max, uint256 _time, uint256 _rate, address _meta) internal view{
        require(_min>0 && _max >0 && _min < _max , "C98Stake: Wrong numeric format");
        MetaInfo memory metaInfo = MetaInfos[_meta];

        require(_time > metaInfo.locked_time && _rate > metaInfo.floating_rate,"C98Stake: Lower than minimum time & rate");
    }

    /**
     * @dev Register a new package for the user to stake in
     *
     * Requirements:
     *
     * - `package` must not be existed.
     * - `meta` the meta staked token.
     * - `min` must be larger than zero and less than max.
     * - `max` must be larger than zero and larger than min.
     * - `time` in staking the user needs to meet before can get `rate` staked.
     * - `rate` profit if the user can meet the package time condition.
     */
    function register(
        string memory _package,
        address _meta,
        uint256 _min,
        uint256 _max,
        uint256 _time,
        uint256 _rate
    )
        public
        onlyOwner()
    {
        require(!validPackage(_package), "C98Stake: Package already existed");
        require(validMeta(_meta),"C98Stake: Unregistered Meta");
        validPackageCondition(_min,_max,_time,_rate,_meta);

        PackageInfo storage pkInfo = PackageInfos[_package];

        pkInfo.meta = _meta;
        pkInfo.min = _min;
        pkInfo.max = _max;
        pkInfo.time = _time;
        pkInfo.rate = _rate;
    }
    
    /**
     * @dev UnRegister existed package
     *
     * Requirements:
     *
     * - `package` must be existed.
    */
    function unRegister(
        string memory _package
    )
        public
        onlyOwner()
    {
        require(validPackage(_package), "C98Stake: Package not found");
        delete PackageInfos[_package];
    }

    /**
     * @dev Configure variable for existed package
     *
     * Requirements:
     *
     * - `package` must be existed.
     * - `min` must be larger than zero and less than max.
     * - `max` must be larger than zero and larger than min.
     * - `time` in staking a user needs to meet before can get `rate` staked.
     * - `rate` profit if the user can meet the package time condition.
     */
    function configurePackage(
        string memory _package,
        uint256 _min,
        uint256 _max,
        uint256 _time,
        uint256 _rate
    )
        public
        onlyOwner()
    {
        require(validPackage(_package), "C98Stake: Package not found");
        PackageInfo storage pkInfo = PackageInfos[_package];

        validPackageCondition(_min,_max,_time,_rate,pkInfo.meta);

        pkInfo.min = _min;
        pkInfo.max = _max;
        pkInfo.time = _time;
        pkInfo.rate = _rate;
    }
    
    /**
     * @dev Return `profit` staked by NFT ID
     *
     * Requirements:
     *
     * - `tokenId` must be existed.
     * -  if the `timeStaked` does not meet the`locked_time` condition or the user has already unstaked, the result will return to zero.
     * -  if the `timeStaked` does not meet the package time condition, the rate will be based on the `floating_rate`
     */
    function getStakedByTokenId(uint256 _tokenId) private view returns (uint256) {
        StakeInfo memory stakeInfo = StakeInfos[_tokenId];
        MetaInfo memory metaInfo = MetaInfos[stakeInfo.meta];

        uint256 current = block.timestamp;
        uint256 timeStaked = current - stakeInfo.time;
        
        if(!stakeInfo.flag || (timeStaked < metaInfo.locked_time)){
            return 0;
        } else {
            uint256 calRate = timeStaked < stakeInfo.package_time ? metaInfo.floating_rate: stakeInfo.rate;
            
            uint256 amountProfitBySeconds = stakeInfo.amount.div(Percent).div(yearTimestamp).mul(calRate);
            return amountProfitBySeconds.mul(timeStaked);
        }
    }

    function validateCustomName(string memory name, string memory name_prefix, address user) private pure returns (bool){
        uint256 nameSize = bytes(name).length;
        uint256 prefixNameSize = bytes(name_prefix).length;
        if(prefixNameSize == 0){
            return Convertible.compareStrings(Convertible.sliceString(1,10, Convertible.convertAddressToString(user)), name);
        }
        return Convertible.compareStrings(Convertible.sliceString(1,prefixNameSize,name), name_prefix) && nameSize == 10;
    }
    
    /**
     * @dev Staking an `amount` in the registered package and returning an NFT to msg.sender.
     *
     * Requirements:
     *
     * - `amount` must be larger than zero.
     * - `name` charge `naming_fee` when user wants to customize the name ( if following C98 Rule Ref ID not charging `naming_fee` ).
     * - `package` registered package ID
     * - `customID` The custom NFT ID is optional for user and will be charged in `id_fee`. If input 0 the system will make a random ID.
     * Emits a {_stake} event.
     */
    function stake(uint256 _amount, string memory _name, string memory _package, uint256 _customID) public {
        require(validPackage(_package), "C98Stake: Package not found");
        
        PackageInfo memory pkInfo = PackageInfos[_package];
        // Check the validity of the package min, max & the amount of transferFrom
        require(_amount >= pkInfo.min && _amount < pkInfo.max , "C98Stake: Wrong min max format");
        MetaInfo storage metaInfo = MetaInfos[pkInfo.meta];
        IBEP20 metaToken = IBEP20(pkInfo.meta);

        uint256 totalStakedFinal = metaInfo.total_staked.add(_amount);
        require(totalStakedFinal <= metaInfo.max_staked, "C98Stake: Maximum number of staked");
    
        bool _isCustomID = _customID != 0;
        //Validate the custom name if basing on C98 Ref ID Rule, it will be free of change
        uint256 nameSize = bytes(_name).length;

        bool _isNotCustomname = validateCustomName(_name, metaInfo.name_prefix, msg.sender);
        
        if(!_isNotCustomname){
            require(nameSize <= 20 && nameSize > 0,"C98Stake: Not meet name condition");
        }
        
        uint256 payAmount =  _amount.add(_isCustomID ? metaInfo.id_fee : 0 ).add(_isNotCustomname ? 0 : metaInfo.naming_fee);
        metaToken.safeTransferFrom(msg.sender, address(this), payAmount);
        
        string memory randomID;
        
        if (_isCustomID){
            randomID = Convertible.uint2str(_customID);
        } else {
            string memory randomConvert = Convertible.uint2str(uint256(keccak256(abi.encodePacked(totalToken().add(1),_amount,block.timestamp,metaInfo.nft_prefix))));
            randomID = Convertible.sliceString(10,21,randomConvert);
        }
        
        // Random string after prefix is fixed at 12
        require(bytes(randomID).length == 12);
        
        // Token ID start with nft_prefix
        uint256 nftPackageId = Convertible.bytesToUInt(Convertible.stringToBytes32(string(abi.encodePacked(metaInfo.nft_prefix,randomID))));
        
        require(!_exists(nftPackageId), "ERC721: token already minted");
        
        // Storage stake information
        StakeInfo storage stakeInfo = StakeInfos[nftPackageId];
        stakeInfo.flag = true;
        stakeInfo.amount = _amount;
        stakeInfo.time = block.timestamp;
        stakeInfo.packageID = _package;
        stakeInfo.meta = pkInfo.meta;
        
        stakeInfo.name = _name;
        stakeInfo.isCustomID = _isCustomID;
        
        stakeInfo.pending_flag = false;
        stakeInfo.pending_time = metaInfo.pending_time;
        stakeInfo.package_time = pkInfo.time;
        stakeInfo.rate = pkInfo.rate;
        
        metaInfo.total_staked = totalStakedFinal;
        _mintAnElement(msg.sender, nftPackageId, _isCustomID);
    }
    
    /**
     * @dev Renaming the existed NFT and charging `naming_fee`.
     *
     * Requirements:
     *
     * - `tokenId` must be existed.
     * - `name` must be existed.
     * Emits a {_renaming} event.
     */
    function renaming (uint256 _tokenId,string memory _name) public {
        StakeInfo storage stakeInfo = StakeInfos[_tokenId];
        MetaInfo memory metaInfo = MetaInfos[stakeInfo.meta];
        IBEP20 metaToken = IBEP20(stakeInfo.meta);

        require(ownerOf(_tokenId) == msg.sender, "C98Stake: Not meet owner condition");
        metaToken.safeTransferFrom(msg.sender, address(this), metaInfo.naming_fee);
        uint256 nameSize = bytes(_name).length;
        require(nameSize <= 20 && nameSize > 0,"C98Stake: Not meet name condition");
        
        stakeInfo.name = _name;
        emit _renaming(_tokenId, _name);
    }
    
    /**
     * @dev Unstake the `amount` in NFT and get the profit following the previous conditions.
     *
     * Requirements:
     *
     * - `tokenId` must be existed.
     * Emits a {_unstake} event.
     */
    function unstake(uint256 _tokenId) public {
        StakeInfo storage stakeInfo = StakeInfos[_tokenId];
        MetaInfo storage metaInfo = MetaInfos[stakeInfo.meta];

        uint256 _profit = getStakedByTokenId(_tokenId);
        require(_profit > 0, "C98Stake: Not meet unstake condition");
        require(ownerOf(_tokenId) == msg.sender, "C98Stake: Not meet owner condition");
        
        IBEP20 metaToken = IBEP20(stakeInfo.meta);
         
        uint256 _profitTotal = _profit.add(stakeInfo.amount);
          
        require(metaToken.balanceOf(address(this)) >= _profitTotal);
        stakeInfo.flag = false;
        metaInfo.total_staked = metaInfo.total_staked.sub(stakeInfo.amount);
        
        if(stakeInfo.pending_time == 0){
          metaToken.safeTransfer(msg.sender, _profitTotal);
        } else {
            stakeInfo.pending_flag = true;
        }
        
        stakeInfo.unstaked_time = block.timestamp;
        stakeInfo.earn_staked  = _profitTotal;
        
        emit _unstake(_tokenId, _profitTotal, stakeInfo.time);
    }

    /**
     * @dev Claim Pending the `amount` in NFT and get the earn_staked after unstake and wait for pending_time.
     *
     * Requirements:
     *
     * - `tokenId` must be existed and already unstaked.
     * Emits a {_claim} event.
     */
    function claimPending(uint256 _tokenId) public {
        StakeInfo storage stakeInfo = StakeInfos[_tokenId];

        require(stakeInfo.pending_flag, "C98Stake: Not meet claim pending condition");
        require(ownerOf(_tokenId) == msg.sender, "C98Stake: Not meet owner condition");

        IBEP20 metaToken = IBEP20(stakeInfo.meta);

        require(metaToken.balanceOf(address(this)) >= stakeInfo.earn_staked,"C98Stake: Not enough pool");

        stakeInfo.pending_flag = false;
        metaToken.safeTransfer(msg.sender, stakeInfo.earn_staked);
        
        stakeInfo.claim_pending_time = block.timestamp;
        
        emit _claim(_tokenId, stakeInfo.earn_staked, stakeInfo.time);
    }
    
    function _mintAnElement(address _to, uint256 _tokenId, bool _isCustomID) private {
        _tokenIdTracker.increment();
        _safeMint(_to, _tokenId);
        emit _stake(_tokenId, _isCustomID);
    }
    
    /**
     * @dev The Owner withdraws any tokens for emergency case
     *
     * Requirements:
     *
     * - `amount` must be larger than zero.
     */
    function withdraw(uint256 _amount, IBEP20 _token) public onlyOwner {
        require(_amount > 0);
        require(_token.balanceOf(address(this)) >= _amount);
        _token.safeTransfer(msg.sender, _amount);
    }

    /**
     * @dev Get info Staked by NFT ID
     */
    function getStakedInfo(uint256 tokenId) external view returns (StakeInfo memory) {
        StakeInfo memory stakeInfo = StakeInfos[tokenId];
        stakeInfo.est_staked = getStakedByTokenId(tokenId);
        stakeInfo.id = tokenId;
        return stakeInfo;
    }

    /**
     * @dev Get list NFT staked by address
     */
    function walletOfOwner(address _owner) external view returns (StakeInfo[] memory) {
        uint256 tokenCount = balanceOf(_owner);

        StakeInfo[]memory addressStaked = new StakeInfo[](tokenCount);
        
        for (uint256 i = 0; i < tokenCount; i++) {
            uint256 tokenIndex = tokenOfOwnerByIndex(_owner, i);
            StakeInfo memory stakeInfoIndex = StakeInfos[tokenIndex];
            stakeInfoIndex.est_staked = getStakedByTokenId(tokenIndex);
            stakeInfoIndex.id = tokenIndex;
            addressStaked[i] = stakeInfoIndex;
        }
    
        return addressStaked;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return baseTokenURI;
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        baseTokenURI = baseURI;
    }

    function totalToken() public view returns (uint256) {
        return _tokenIdTracker.current();
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):