Contract 0x8d1566569d5b695d44a9a234540f68d393cdc40d 1

 
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x0728e5430cacee4b33bc7111822fdb0be9ce73cc3278f813b2ab2ed78c6ebbdbTransfer242155242022-01-27 6:26:494 hrs 10 mins ago0x562f6ac10723ef6af9f077a83cf25135fb369612 IN  GameCredits: GAME Token0 MATIC0.001205106227 28.292863501
0xd9e898c367a6c621484165426741e46786a648c80897aaadbb33c27456b90cc2Transfer242154772022-01-27 6:25:114 hrs 12 mins ago0x562f6ac10723ef6af9f077a83cf25135fb369612 IN  GameCredits: GAME Token0 MATIC0.001379640672 32.390493328
0x261f70dfb4c092f052363c65795447e7618d0f2b51672ca2315ff22b63e71a36Transfer242058032022-01-27 0:48:019 hrs 49 mins ago0xbcabb17f5145c333a254eaea68a2bfe9c2435545 IN  GameCredits: GAME Token0 MATIC0.001890950
0x69d852c2f397ce01ca8e1e1feb525f7fd718b43b9299b38d6b4ba1058aa7ee3cApprove241991682022-01-26 20:50:5113 hrs 46 mins ago0x1f3bbca2b3e2432af649745288b368cd253444b2 IN  GameCredits: GAME Token0 MATIC0.003814600212 81.930458405
0x7202ee9bbb011c9988803d6df02a81ed6bc9139715707063bb1090f3b8dcc7a9Approve241943652022-01-26 17:51:5616 hrs 45 mins ago0xdcc5c72ce30579cdd5bc2c23d849e0115ac505ea IN  GameCredits: GAME Token0 MATIC0.001408719454 30.256651862
0x4436719e49ec88ea08cd7896f3e6037f343e3acbb1c2edb8edf8ba8af0a1d90eApprove241943282022-01-26 17:49:2816 hrs 48 mins ago0xdcc5c72ce30579cdd5bc2c23d849e0115ac505ea IN  GameCredits: GAME Token0 MATIC0.000938604992 30.070000412
0xad9b2e9eccde4e2fe03d15be814f319857d36dacea5169ef36bbdc6b70663095Approve241942042022-01-26 17:44:2216 hrs 53 mins ago0xa85703840b4ad814c8f581922e18d0b17d2a145d IN  GameCredits: GAME Token0 MATIC0.001372017436 29.468361363
0x9c90ea121492a86ef044b1107643fb2a7c4c3ceffbab5caf3fe7fef6ce59392cApprove241928282022-01-26 16:51:5017 hrs 45 mins ago0x2ed6a123228b9ead7ab4b03972def9ac46bb489e IN  GameCredits: GAME Token0 MATIC0.001580678264 33.950004602
0xeb72e5388499f9f3a1d4dfcd9537ab4e89037ffabb4e92f7f0c39bb4c8282e58Approve241898232022-01-26 14:55:2019 hrs 42 mins ago0x9caf663a9be37294ed59d823300a72a1131af908 IN  GameCredits: GAME Token0 MATIC0.00213401866846.096093941
0xb2259f475b1a47f4bf97a118345ceedf92ba2dd68b3249e10a33efb3b08e8609Approve241893582022-01-26 14:39:2219 hrs 58 mins ago0xa593c07b576c34fb73132994fa851a5700123d86 IN  GameCredits: GAME Token0 MATIC0.003257735012 69.970038291
0x2e13723701126bfa0b87b4c72aad5fb9f33a471188912c6218cc887f028131ffApprove241891692022-01-26 14:30:4420 hrs 6 mins ago0x84b3481609c33d45e6539195153059d682be2973 IN  GameCredits: GAME Token0 MATIC0.003446801083 74.030822912
0x303a9a39cb004d9b1ab267c839201a5aa040e19667e7590c75e0b71f921fd9a2Approve241888862022-01-26 14:21:0220 hrs 16 mins ago0xbe2eb4f72cc897ecff0637791398711b013991ae IN  GameCredits: GAME Token0 MATIC0.001505109296 32.326924892
0xed2d371daa9885ab75d8a66d8baf40243e8140b9da68f79495929437cdf3e8b0Approve241872822022-01-26 13:25:4121 hrs 11 mins ago0xc22f792fe40d19b5ccff7f82fe183bd9556b6123 IN  GameCredits: GAME Token0 MATIC0.00179480453 38.549035208
0x433ca0a0e886c580393836ac8f074da7079487bd93079c51ef24ca3cfa77c84bApprove241848362022-01-26 11:55:2222 hrs 42 mins ago0x40cd7dcea5ac0a937fb16ae978f740aa7c78b839 IN  GameCredits: GAME Token0 MATIC0.000922155781 34.590786656
0xf5776e669efb338f17f09bf2f434482a046b8dee758d78492f67b7c01486449aApprove241848362022-01-26 11:55:2222 hrs 42 mins ago0x40cd7dcea5ac0a937fb16ae978f740aa7c78b839 IN  GameCredits: GAME Token0 MATIC0.001467195022 31.512597393
0x3e34d1158bce71f23f0ac79204245cbd0b1d36f82a03de9fbcf099a246dd4d7fApprove241811462022-01-26 9:33:151 day 1 hr ago0x0740cb7d8752b969fa5183d093c9864997011a5f IN  GameCredits: GAME Token0 MATIC0.005165734552 110.950290012
0xac8b528ae9d5647f0a61c8867230a5041bab8176c36ec5cbb52131a945441509Approve241805302022-01-26 9:09:551 day 1 hr ago0xa1ae85e71c512f755dc56b778446f25082727899 IN  GameCredits: GAME Token0 MATIC0.004022506668 86.395899146
0x849fc9a1ec3c2f6d1e295f0f24f35a87b38b154416039057ef792a47493afb52Transfer241771422022-01-26 7:09:111 day 3 hrs ago0x0451f6613eb2f10b1cc5d60febd42997e5dcc126 IN  GameCredits: GAME Token0 MATIC0.002042266389 47.947278713
0xd67b2cda08c4ebeb40ec3570b610427ac2537397c1560b2c769418d6e4c109f7Approve241771202022-01-26 7:08:271 day 3 hrs ago0xc56bbd2a0b825504a591f12276ddce8adcb99018 IN  GameCredits: GAME Token0 MATIC0.002391964632 51.374914247
0xf5a1c7f507b66d2f75a48347b0ecbf8540110c115ca1772a548d0f22b23b7756Transfer241767472022-01-26 6:55:371 day 3 hrs ago0x59438775139d1787d0bca1df340a182d2fd58384 IN  GameCredits: GAME Token0 MATIC0.004687069192 85.346684005
0x01d9abbe9b0bc830878d9629c782deaa554e008122e6b0f2f7afa4a6e0724cf7Approve241749592022-01-26 5:51:551 day 4 hrs ago0x435b7d470767cb121f37dd296b2ac7913fdf5427 IN  GameCredits: GAME Token0 MATIC0.003851269764 83.211325212
0x2c2ec8c4c95e0a69f25b860f21a20b0dc0cb4c069fdb385eb77458bf39564cb3Transfer241741452022-01-26 5:23:571 day 5 hrs ago0xbc8751b925dbc26caae102fa44d40d0439ce2697 IN  GameCredits: GAME Token0 MATIC0.002664418363 48.516303638
0x69b78d1cffd845f62154ba354b2ba07b5cf0225b5a2503b68df413cd54cbdb6aWorker Execute M...241739742022-01-26 5:18:031 day 5 hrs ago0x5506165460ddbcf62ad3a8f84ecfafa006650dce IN  GameCredits: GAME Token0 MATIC0.0136572660
0x76e10542a62fddf159b2dee17303214b6203547a9b94a2d90cb9778316cf1173Worker Execute M...241739582022-01-26 5:17:311 day 5 hrs ago0xf71a4a4d847deb47d6cbd8318bb59a343d10a9c0 IN  GameCredits: GAME Token0 MATIC0.01251915555
0x0fcb33b00246d6c391dcbf7f8c3349eaea5dd29ec3a3f6293532635298c37545Worker Execute M...241739462022-01-26 5:17:031 day 5 hrs ago0xfe7cfb656cfb9dd10f52714d2dd79e0796d286f8 IN  GameCredits: GAME Token0 MATIC0.0113810550
[ Download CSV Export 

OVERVIEW

The GAME Credits platform provides a suite of tools for gaming, NFTs, and DeFi including the upcoming GENESIS Metaverse and the GAME Rewards Portal.

Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GAME_ERC20

Compiler Version
v0.7.0+commit.9e61f92b

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at polygonscan.com on 2021-06-30
*/

pragma solidity ^0.7.0;
// SPDX-License-Identifier: UNLICENSED






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


abstract contract EIP712Base {
  struct EIP712Domain {
    string name;
    string version;
    uint256 chainId;
    address verifyingContract;
  }

  bytes32 public constant EIP712_DOMAIN_TYPEHASH = keccak256(
    bytes(
      "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    )
  );
  bytes32 internal domainSeperator;
  bytes32 internal workerDomainSeperator;

  constructor(
      string memory name,
      string memory version
  ) {
    domainSeperator = encodeDomainSeperator(name, version);
    workerDomainSeperator = encodeWorkerDomainSeperator(name, version);
  }

  function getChainId() public pure returns (uint256) {
    uint256 id;
    assembly {
      id := chainid()
    }
    return id;
  }

  function getDomainSeperator() public view returns (bytes32) {
    return domainSeperator;
  }

  function getWorkerDomainSeperator() public view returns (bytes32) {
    return workerDomainSeperator;
  }

  function encodeDomainSeperator(string memory name, string memory version) public view returns (bytes32) {
    uint chainId = getChainId();
    require(chainId != 0, "chain ID must not be zero");
    return keccak256(
      abi.encode(
        EIP712_DOMAIN_TYPEHASH,
        keccak256(bytes(name)),
        keccak256(bytes(version)),
        chainId,
        address(this)
      )
    );
  }

  // This encodes the domain separator to the root chain, rather than the main chain.
  function encodeWorkerDomainSeperator(string memory name, string memory version) public view returns (bytes32) {
    uint chainId = getChainId();

    // 1 == truffle test; 1 == Ethereum
    // 137 == matic mainnet; 1 == Ethereum
    // 80001 == matic mumbai; 5 == Goerli
    chainId = chainId == 137 || chainId == 1 ? 1 : chainId == 80001 ? 5 : 0;
    require(chainId != 0, "chain ID must not be zero");
    return keccak256(
      abi.encode(
        EIP712_DOMAIN_TYPEHASH,
        keccak256(bytes(name)),
        keccak256(bytes(version)),
        chainId,
        address(this)
      )
    );
  }

  /**
    * Accept message hash and returns hash message in EIP712 compatible form
    * So that it can be used to recover signer from signature signed using EIP712 formatted data
    * https://eips.ethereum.org/EIPS/eip-712
    * "\\x19" makes the encoding deterministic
    * "\\x01" is the version byte to make it compatible to EIP-191
    */
  function toTypedMessageHash(bytes32 messageHash)
    internal
    view
    returns (bytes32)
  {
    return
      keccak256(
        abi.encodePacked("\x19\x01", getDomainSeperator(), messageHash)
      );
  }
}


/*
 * @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.
 */
abstract contract Context {

  function _msgSender()
    internal
    virtual
    view
    returns (address payable sender)
  {
    if (msg.sender == address(this)) {
      bytes memory array = msg.data;
      uint256 index = msg.data.length;
      assembly {
        // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
        sender := and(
            mload(add(array, index)),
            0xffffffffffffffffffffffffffffffffffffffff
        )
      }
    } else {
      sender = msg.sender;
    }
    return sender;
  }

  function _msgData() internal view virtual returns (bytes memory) {
    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    return msg.data;
  }
}



/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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);
}



/**
 * @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) {
        // This method relies in 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");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        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);
            }
        }
    }
}



/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
abstract contract ERC20 is Context, iERC20 {
  using SafeMath for uint256;
  using Address for address;

  mapping (address => uint256) internal _balances;

  mapping (address => mapping (address => uint256)) private _allowances;

  uint256 private _totalSupply;

  string private _name;
  string private _symbol;
  uint8 private _decimals;

  /**
    * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
    * a default value of 18.
    *
    * To select a different value for {decimals}, use {_setupDecimals}.
    *
    * All three of these values are immutable: they can only be set once during
    * construction.
    */
  constructor (string memory name, string memory symbol) {
    _name = name;
    _symbol = symbol;
    _decimals = 18;
  }

  /**
    * @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. This is the value {ERC20} uses, unless {_setupDecimals} is
    * called.
    *
    * 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;
  }

  /**
    * @dev See {IERC20-totalSupply}.
    */
  function totalSupply() public view override returns (uint256) {
    return _totalSupply;
  }

  /**
    * @dev See {IERC20-balanceOf}.
    */
  function balanceOf(address account) public view override returns (uint256) {
    return _balances[account];
  }

  /**
    * @dev See {IERC20-transfer}.
    *
    * Requirements:
    *
    * - `recipient` cannot be the zero address.
    * - the caller must have a balance of at least `amount`.
    */
  function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
    _transfer(_msgSender(), recipient, amount);
    return true;
  }

  /**
    * @dev See {IERC20-allowance}.
    */
  function allowance(address owner, address spender) public view virtual override returns (uint256) {
    return _allowances[owner][spender];
  }

  /**
    * @dev See {IERC20-approve}.
    *
    * Requirements:
    *
    * - `spender` cannot be the zero address.
    */
  function approve(address spender, uint256 amount) public virtual override returns (bool) {
    _approve(_msgSender(), spender, amount);
    return true;
  }

  /**
    * @dev See {IERC20-transferFrom}.
    *
    * Emits an {Approval} event indicating the updated allowance. This is not
    * required by the EIP. See the note at the beginning of {ERC20};
    *
    * Requirements:
    * - `sender` and `recipient` cannot be the zero address.
    * - `sender` must have a balance of at least `amount`.
    * - the caller must have allowance for ``sender``'s tokens of at least
    * `amount`.
    */
  function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
    _transfer(sender, recipient, amount);
    _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
    return true;
  }

  /**
    * @dev Atomically increases the allowance granted to `spender` by the caller.
    *
    * This is an alternative to {approve} that can be used as a mitigation for
    * problems described in {IERC20-approve}.
    *
    * Emits an {Approval} event indicating the updated allowance.
    *
    * Requirements:
    *
    * - `spender` cannot be the zero address.
    */
  function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
    _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
    return true;
  }

  /**
    * @dev Atomically decreases the allowance granted to `spender` by the caller.
    *
    * This is an alternative to {approve} that can be used as a mitigation for
    * problems described in {IERC20-approve}.
    *
    * Emits an {Approval} event indicating the updated allowance.
    *
    * Requirements:
    *
    * - `spender` cannot be the zero address.
    * - `spender` must have allowance for the caller of at least
    * `subtractedValue`.
    */
  function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
    _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
    return true;
  }

  /**
    * @dev Moves tokens `amount` from `sender` to `recipient`.
    *
    * This is internal function is equivalent to {transfer}, and can be used to
    * e.g. implement automatic token fees, slashing mechanisms, etc.
    *
    * Emits a {Transfer} event.
    *
    * Requirements:
    *
    * - `sender` cannot be the zero address.
    * - `recipient` cannot be the zero address.
    * - `sender` must have a balance of at least `amount`.
    */
  function _transfer(address sender, address recipient, uint256 amount) internal virtual {
    require(sender != address(0), "ERC20: transfer from the zero address");
    require(recipient != address(0), "ERC20: transfer to the zero address");

    _beforeTokenTransfer(sender, recipient, amount);

    _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
    _balances[recipient] = _balances[recipient].add(amount);
    emit Transfer(sender, recipient, amount);
  }

  /** @dev Creates `amount` tokens and assigns them to `account`, increasing
    * the total supply.
    *
    * Emits a {Transfer} event with `from` set to the zero address.
    *
    * Requirements
    *
    * - `to` cannot be the zero address.
    */
  function _mint(address account, uint256 amount) internal virtual {
    require(account != address(0), "ERC20: mint to the zero address");

    _beforeTokenTransfer(address(0), account, amount);

    _totalSupply = _totalSupply.add(amount);
    _balances[account] = _balances[account].add(amount);
    emit Transfer(address(0), account, amount);
  }

  /**
    * @dev Destroys `amount` tokens from `account`, reducing the
    * total supply.
    *
    * Emits a {Transfer} event with `to` set to the zero address.
    *
    * Requirements
    *
    * - `account` cannot be the zero address.
    * - `account` must have at least `amount` tokens.
    */
  function _burn(address account, uint256 amount) internal virtual {
    require(account != address(0), "ERC20: burn from the zero address");

    _beforeTokenTransfer(account, address(0), amount);

    _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
    _totalSupply = _totalSupply.sub(amount);
    emit Transfer(account, address(0), amount);
  }

  /**
    * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
    *
    * This internal function is equivalent to `approve`, and can be used to
    * e.g. set automatic allowances for certain subsystems, etc.
    *
    * Emits an {Approval} event.
    *
    * Requirements:
    *
    * - `owner` cannot be the zero address.
    * - `spender` cannot be the zero address.
    */
  function _approve(address owner, address spender, uint256 amount) internal virtual {
    require(owner != address(0), "ERC20: approve from the zero address");
    require(spender != address(0), "ERC20: approve to the zero address");

    _allowances[owner][spender] = amount;
    emit Approval(owner, spender, amount);
  }

  /**
    * @dev Sets {decimals} to a value other than the default one of 18.
    *
    * WARNING: This function should only be called from the constructor. Most
    * applications that interact with token contracts will not expect
    * {decimals} to ever change, and may work incorrectly if it does.
    */
  function _setupDecimals(uint8 decimals_) internal {
    _decimals = decimals_;
  }

  /**
    * @dev Hook that is called before any transfer of tokens. This includes
    * minting and burning.
    *
    * Calling conditions:
    *
    * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
    * will be to transferred to `to`.
    * - when `from` is zero, `amount` tokens will be minted for `to`.
    * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
    * - `from` and `to` are never both zero.
    *
    * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
    */
  function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}



interface iChildToken {
    function deposit(address user, bytes calldata depositData) external;
}



abstract contract NetworkAgnostic is EIP712Base, Context {
  using SafeMath for uint256;
  bytes32 internal constant META_TRANSACTION_TYPEHASH = keccak256(
    bytes(
      "MetaTransaction(uint256 nonce,address from,bytes functionSignature)"
    )
  );
  event MetaTransactionExecuted(
    address userAddress,
    address payable relayerAddress,
    bytes functionSignature
  );
  mapping(address => uint256) nonces;

  /*
    * Meta transaction structure.
    * No point of including value field here as if user is doing value transfer then he has the funds to pay for gas
    * He should call the desired function directly in that case.
    */
  struct MetaTransaction {
    uint256 nonce;
    address from;
    bytes functionSignature;
  }

  constructor(
    string memory name,
    string memory version
  ) EIP712Base(name, version) {}

  function executeMetaTransaction(
    address userAddress,
    bytes memory functionSignature,
    bytes32 sigR,
    bytes32 sigS,
    uint8 sigV
  ) public payable returns (bytes memory) {
    MetaTransaction memory metaTx = MetaTransaction({
      nonce: nonces[userAddress],
      from: userAddress,
      functionSignature: functionSignature
    });

    require(
      verify(userAddress, metaTx, sigR, sigS, sigV),
      "Signer and signature do not match"
    );

    // increase nonce for user (to avoid re-use)
    nonces[userAddress] = nonces[userAddress].add(1);

    emit MetaTransactionExecuted(
      userAddress,
      msg.sender,
      functionSignature
    );

    // Append userAddress and relayer address at the end to extract it from calling context
    (bool success, bytes memory returnData) = address(this).call(
      abi.encodePacked(functionSignature, userAddress)
    );
    require(success, "Function call not successful");

    return returnData;
  }

  function hashMetaTransaction(MetaTransaction memory metaTx)
    internal
    pure
    returns (bytes32)
  {
    return
      keccak256(
        abi.encode(
          META_TRANSACTION_TYPEHASH,
          metaTx.nonce,
          metaTx.from,
          keccak256(metaTx.functionSignature)
        )
      );
  }

  function getNonce(address user) public view returns (uint256 nonce) {
    nonce = nonces[user];
  }

  function verify(
    address signer,
    MetaTransaction memory metaTx,
    bytes32 sigR,
    bytes32 sigS,
    uint8 sigV
  ) internal view returns (bool) {
    return
      signer != address(0) && signer ==
      ecrecover(
        toTypedMessageHash(hashMetaTransaction(metaTx)),
        sigV,
        sigR,
        sigS
      );
  }
}




// @title iLocalContract
// @dev The interface for the main Token Manager contract
//  Only methods required for calling by sibling contracts are required here
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract iLocalContract {

  function updateLocalContract(address contract_, bool isLocal_) virtual external;

  function metaTxSenderIsWorkerOrMinion() internal virtual returns (bool);

  function isLocalContract()
    external
    virtual
    pure
  returns(bool) {
    return true;
  }
}

abstract contract WorkerMetaTransactions is NetworkAgnostic, iLocalContract {
  using SafeMath for uint256;
  bytes32 private constant WORKER_META_TRANSACTION_TYPEHASH = keccak256(
    bytes(
      "WorkerMetaTransaction(bytes32 replayPrevention,address from,bytes functionSignature)"
    )
  );

  // This mapping records all meta-transactions that have been played.
  // It costs more than the nonce method, but this is permissioned, so it's more reliable.
  mapping(address => mapping(bytes32 => bool)) playedTransactions;

  /*
    * Meta transaction structure.
    * No point of including value field here as a user who is doing value transfer has the funds to pay for gas
    *   and should call the desired function directly in that case.
    */
  struct WorkerMetaTransaction {
    bytes32 replayPrevention;
    address from;
    bytes functionSignature;
  }

  function workerExecuteMetaTransaction(
    address userAddress_,
    bytes32 replayPrevention_,
    bytes memory functionSignature_,
    bytes32 sigR_,
    bytes32 sigS_,
    uint8 sigV_
  )
    public
    payable
  returns (bytes memory) {
    require(metaTxSenderIsWorkerOrMinion(), "Worker Meta-Transaction sent by account other than a worker/minion");
    WorkerMetaTransaction memory metaTx = WorkerMetaTransaction({
      replayPrevention: replayPrevention_,
      from: userAddress_,
      functionSignature: functionSignature_
    });

    require(
      workerVerify(userAddress_, metaTx, sigR_, sigS_, sigV_),
      "Signer and signature do not match"
    );

    require(playedTransactions[userAddress_][replayPrevention_] == false, "REPLAY of a previous transaction");
    playedTransactions[userAddress_][replayPrevention_] = true;

    emit MetaTransactionExecuted(
      userAddress_,
      msg.sender,
      functionSignature_
    );

    // Append userAddress and relayer address at the end to extract it from calling context
    (bool success, bytes memory returnData) = address(this).call(
      abi.encodePacked(functionSignature_, userAddress_)
    );
    require(success, "Function call not successful");

    return returnData;
  }

  function hashWorkerMetaTransaction(WorkerMetaTransaction memory metaTx_)
    internal
    pure
  returns (bytes32) {
    return
      keccak256(
        abi.encode(
          WORKER_META_TRANSACTION_TYPEHASH,
          metaTx_.replayPrevention,
          metaTx_.from,
          keccak256(metaTx_.functionSignature)
        )
      );
  }

  function workerVerify(
    address signer_,
    WorkerMetaTransaction memory metaTx_,
    bytes32 sigR_,
    bytes32 sigS_,
    uint8 sigV_
  ) 
    internal
    view
  returns (bool) {
    return
      signer_ != address(0) && signer_ ==
      ecrecover(
        toWorkerTypedMessageHash(hashWorkerMetaTransaction(metaTx_)),
        sigV_,
        sigR_,
        sigS_
      );
  }

  /**
    * Accept message hash and returns hash message in EIP712 compatible form
    * So that it can be used to recover signer from signature signed using EIP712 formatted data
    * https://eips.ethereum.org/EIPS/eip-712
    * "\\x19" makes the encoding deterministic
    * "\\x01" is the version byte to make it compatible to EIP-191
    */
  function toWorkerTypedMessageHash(bytes32 messageHash_)
    internal
    view
    returns (bytes32)
  {
    return
      keccak256(
        abi.encodePacked("\x19\x01", getWorkerDomainSeperator(), messageHash_)
      );
  }
}



abstract contract ChildERC20 is ERC20, iChildToken, WorkerMetaTransactions {

  address public depositor;

  constructor(
    string memory name_,
    string memory symbol_,
    uint8 decimals_,
    address depositor_
  ) ERC20(name_, symbol_) {
    _setupDecimals(decimals_);
    depositor = depositor_;
  }

  modifier onlyDepositor() {
    require(_msgSender() == depositor, "ChildERC20: INSUFFICIENT_PERMISSIONS");
    _;
  }

  function _setDepositor(address _depositor)
    internal
  {
    depositor = _depositor;
  }

  /**
    * @notice called when token is deposited on root chain
    * @dev Should be callable only by ChildChainManager
    * Should handle deposit by minting the required amount for user
    * Make sure minting is done only by this function
    * @param user user address for whom deposit is being done
    * @param depositData abi encoded amount
    */
  function deposit(address user, bytes calldata depositData)
    external
    override
    onlyDepositor
  {
    uint256 amount = abi.decode(depositData, (uint256));
    _mint(user, amount);
  }

  /**
    * @notice called when user wants to withdraw tokens back to root chain
    * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain
    * @param amount amount of tokens to withdraw
    */
  function withdraw(uint256 amount) external {
    _burn(_msgSender(), amount);
  }

  // To recieve ether in contract
  receive() external payable {}
}



// @title iGAME_Game
// @dev The interface for the GAME Credits Game Data contract
//  Only methods required for calling by sibling contracts are required here
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract iGAME_Game {
  mapping(uint => mapping(address => bool)) public gameAdmins;
  mapping(uint => mapping(address => bool)) public gameOperators;

  function getCardPrice(uint game_, uint set_, uint card_) virtual external view returns(uint256);
  function getCardLoyaltyPrice(uint game_, uint set_, uint card_) virtual external view returns(uint256);
  function isGameAdmin(uint game_, address admin_) virtual external view returns(bool);
  function linkContracts(address erc721Contract_, address erc20Contract_) virtual external;
  function isOperatorOrMinion(uint game_, address sender_) virtual external returns(bool);
  function isValidCaller(address account_, bool isMinion_, uint game_) virtual external view returns(bool isValid);
  function burnToken(uint tokenId_) virtual external;
  function createTokenFromCard(uint game_, uint set_, uint card_) virtual external returns(uint tokenId, uint tradeLockTime, uint fixedXp);
}



// @title iGAME_Master
// @dev The interface for the Master contract
//  Only methods required for calling by sibling contracts are required here
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract iGAME_Master {
  function isOwner(address owner_) virtual external view returns (bool);
  function isCFO(address cfo_) virtual external view returns (bool);
  function isCOO(address coo_) virtual external view returns (bool);
  function isWorker(address account_) virtual external view returns (bool);
  function isWorkerOrMinion(address account_) virtual external view returns (bool);
  function makeFundedCall(address account_) virtual external returns (bool);
  function updateCollectibleSaleStatus(uint game_, uint card_, bool isOnSale_) virtual external;

  function isMaster()
    external
    pure
  returns(bool) {
    return true;
  }
}



// @title iGAME_ERC721
// @dev The interface for the main Token Manager contract
//  Only methods required for calling by sibling contracts are required here
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract iGAME_ERC721 {

  function auctionTransfer(address from_, address to_, uint tokenId_) virtual external;

  function inGameOwnerOf(uint tokenId_) virtual external view returns (bytes32 owner_);

  function revokeToken(uint game_, uint tokenId_, bytes32 purchaseId_)
    virtual external returns (bool _isRevoked);

  function transferNewToken(bytes32 recipient_, uint tokenId_, uint tradeLockTime_)
    virtual external;

  function getCryptoAccount(uint game_, bytes32 inGameAccount_)
    virtual public view returns(address cryptoAccount);

  function getValidCryptoAccount(uint game_, bytes32 inGameAccount_)
    virtual public view returns(address cryptoAccount);

  function getInGameAccount(uint game_, address cryptoAccount_)
    virtual public view returns(bytes32 inGameAccount);

  function getValidInGameAccount(uint game_, address cryptoAccount_)
    virtual public view returns(bytes32 inGameAccount);

  function getOrCreateInGameAccount(uint game_, address cryptoAccount_)
    virtual external returns(bytes32 inGameAccount);

  function linkContracts(address gameContract_, address erc20Contract_) virtual external;

  function generateCollectible(uint tokenId_, uint xp_, uint xpPerHour_, uint creationTime_) virtual external;
}



// @title iGAME_ERC20
// @dev The interface for the Auction & ERC-20 contract
//  Only methods required for calling by sibling contracts are required here
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract iGAME_ERC20 {

  function cancelAuctionByManager(uint tokenId_) virtual external;

  function transferByContract(address from_, address to_, uint256 value_) virtual external;

  function linkContracts(address gameContract_, address erc721Contract_) virtual external;

  function getGameBalance(uint game_) virtual public view returns(uint balance);

  function getLoyaltyPointsGranted(uint game_, address account_) virtual public view returns(uint currentPoints);

  function getLoyaltyPointSpends(uint game_, address account_) virtual public view returns(uint currentPoints);

  function getLoyaltyPointsTotal(uint game_, address account_) virtual public view returns(uint currentPoints);

  function thirdPartySpendLoyaltyPoints(uint game_, address account_, uint pointsToSpend_) virtual external;
}


// @title ERC20 Sidechain manager imlpementation
// @dev Utility contract that manages Ethereum and ERC-20 tokens transferred in from the main chain
// @dev Can manage any number of tokens
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract GAME_ERC20Access is iGAME_ERC20, ChildERC20 {
  using SafeMath for uint256;

  event Balance(address account, uint256 value);

  iGAME_Master public masterContract;
  iGAME_Game public gameContract;
  iGAME_ERC721 public erc721Contract;
  mapping(address => bool) public localContracts;

  // Tracks contracts that are allowed to spend Loyalty Points
  mapping(address => bool) public approvedLoyaltySpenders;

  event ThirdPartyRewwardsSpender(address indexed spenderContract, bool isSpender);

  constructor(address masterContract_)
  {
    masterContract = iGAME_Master(masterContract_);
    localContracts[masterContract_] = true;
  }


  modifier workerOrMinion() {
    require(masterContract.makeFundedCall(_msgSender()), "must be called by a worker or minion");
    _;
  }

  modifier onlyCFO() {
    require(masterContract.isCFO(_msgSender()), "sender must be the cfo");
    _;
  }

  modifier onlyOwner() {
    require(masterContract.isOwner(_msgSender()), "sender must be the owner");
    _;
  }

  modifier onlyGameAdmin(uint game_) {
    require(gameContract.isGameAdmin(game_, _msgSender()), "sender must be a game admin");
    _;
  }

  modifier onlyLocalContract() {
    // Cannot be called using native meta-transactions
    require(localContracts[msg.sender], "must be called by a local contract");
    _;
  }

  function updateLocalContract(address contract_, bool isLocal_)
    external
    override
    onlyLocalContract
  {
    require(contract_ != address(masterContract), "can't reset the master contract");
    require(contract_ != address(erc721Contract), "can't reset the erc721 contract");
    require(contract_ != address(0), "can't be the zero address");
    localContracts[contract_] = isLocal_;
  }

  function linkContracts(address gameContract_, address erc721Contract_)
    external
    override
    onlyLocalContract
  {
    require(address(gameContract) == address(0), "token contract must be blank");
    require(address(erc721Contract) == address(0), "token contract must be blank");
    gameContract = iGAME_Game(gameContract_);
    erc721Contract = iGAME_ERC721(erc721Contract_);

    approvedLoyaltySpenders[gameContract_] = true;
    emit ThirdPartyRewwardsSpender(gameContract_, true);
    approvedLoyaltySpenders[erc721Contract_] = true;
    emit ThirdPartyRewwardsSpender(erc721Contract_, true);
    approvedLoyaltySpenders[address(masterContract)] = true;
    emit ThirdPartyRewwardsSpender(address(masterContract), true);
  }

  function setDepositor(address depositor_)
    external
    onlyOwner
  {
    _setDepositor(depositor_);
  }

  function transferByContract(address from_, address to_, uint256 value_)
    external
    override
    onlyLocalContract
  {
    _transfer(from_, to_, value_);
  }

  function metaTxSenderIsWorkerOrMinion()
    internal
    override
  returns (bool) {
    return masterContract.makeFundedCall(msg.sender);
  }
}

// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract GAME_ERC20Loyalty is GAME_ERC20Access {
  using SafeMath for uint256;

  // Emitted whenever a user's stake is increased or decreased.
  event LoyaltyPointsChange(
    uint indexed game,
    address indexed account,
    uint indexed week,
    uint currentStake,
    uint totalGranted,
    uint totalSpent
  );
  event LoyaltyPointsGranted(uint indexed game, address indexed account, uint pointsGrant);
  event LoyaltyPointsRemoved(uint indexed game, address indexed account, uint pointsRemoved);
  event LoyaltyPartnerSet(uint indexed game, address indexed account, uint week);

  // GAME stake needed to gain one Loyalty Point, per week (10 ** 18 is 1 GAME)
  uint public gcPerLoyaltyPoint = 10 ** 18;

  uint public constant WEEK_ZERO_START = 1538352000; // 10/1/2018 @ 00:00:00
  uint public constant SECONDS_PER_WEEK = 604800;

  // Granted by the account stake amount; can also be granted
  mapping(uint => mapping (address => uint)) public gameAccountLoyaltyPoints;

  // Tracks the user's spending of Loyalty Points.
  mapping(uint => mapping (address => uint)) public gameAccountPointsSpent;

  // Used to manage updates to gameAccountStaked and gameStake;
  mapping(uint => mapping (address => uint)) public gameAccountStakeWeek;

  // Tracks the user's current stake
  mapping(uint => mapping (address => uint)) public gameAccountStaked;

  mapping(address => uint) public loyaltyPartners;

  // Tracks the current
  mapping(address => uint) public loyaltyWeeks;

  function getCurrentWeek()
    public
    view
  returns(uint) {
    return (block.timestamp - WEEK_ZERO_START) / SECONDS_PER_WEEK;
  }

  function workerGrantLoyaltyPoints(uint game_, address account_, uint pointsGrant_)
    external
    workerOrMinion
  {
    emit LoyaltyPointsGranted(game_, account_, pointsGrant_);
    _addLoyaltyPoints(game_, account_, pointsGrant_);
  }

  function _addLoyaltyPoints(uint game_, address account_, uint pointsGrant_)
    internal
  {
    gameAccountLoyaltyPoints[game_][account_] = gameAccountLoyaltyPoints[game_][account_].add(pointsGrant_);

    uint newBalance = getLoyaltyPointsGranted(game_, account_);

    emit LoyaltyPointsChange(
      game_,
      account_,
      getCurrentWeek(),
      gameAccountStaked[game_][account_],
      newBalance,
      gameAccountPointsSpent[game_][account_]);
  }

  function workerRemoveLoyaltyPoints(uint game_, address account_, uint pointsToRemove_)
    external
    workerOrMinion
  {
    gameAccountLoyaltyPoints[game_][account_] = gameAccountLoyaltyPoints[game_][account_].sub(pointsToRemove_);

    uint newBalance = getLoyaltyPointsGranted(game_, account_);

    emit LoyaltyPointsRemoved(game_, account_, pointsToRemove_);
    emit LoyaltyPointsChange(
      game_,
      account_,
      getCurrentWeek(),
      gameAccountStaked[game_][account_],
      newBalance,
      gameAccountPointsSpent[game_][account_]);
  }

  function approveThirdPartyLoyaltySpender(address contract_, bool isSpender_)
    external
    onlyCFO
  {
    if(isSpender_) {
      require(!approvedLoyaltySpenders[contract_], "Contract is already a spender");
    } else {
      require(approvedLoyaltySpenders[contract_], "Contract isn't an existing spender");
    }
    approvedLoyaltySpenders[contract_] = isSpender_;
    emit ThirdPartyRewwardsSpender(contract_, isSpender_);
  }

  function thirdPartySpendLoyaltyPoints(uint game_, address account_, uint pointsToSpend_)
    external
    override
  {
    // Cannot be called using native meta-transactions
    require(approvedLoyaltySpenders[msg.sender], "must be an approved Loyalty Points spender contract");
    _spendLoyaltyPoints(game_, account_, pointsToSpend_);
  }

  function workerSpendLoyaltyPoints(uint game_, address account_, uint pointsToSpend_)
    external
    workerOrMinion
  {
    _spendLoyaltyPoints(game_, account_, pointsToSpend_);
  }

  function _spendLoyaltyPoints(uint game_, address account_, uint pointsToSpend_)
    internal
  {
    uint currentPoints = getLoyaltyPointsGranted(game_, account_);
    // Ensure balance is sufficient
    uint newSpend = gameAccountPointsSpent[game_][account_].add(pointsToSpend_);
    require(currentPoints >= newSpend, "spent more Loyalty Points than current balance");
    gameAccountPointsSpent[game_][account_] = newSpend;
    emit LoyaltyPointsChange(game_, account_, getCurrentWeek(), gameAccountStaked[game_][account_], currentPoints, newSpend);
  }

  // What happens if we spend during an update; we don't want to update the actual balance, just calculate it.
  function getLoyaltyPointsGranted(uint game_, address account_)
    public
    override
    view
  returns(uint currentPoints)
  {
    uint stakeWeek = gameAccountStakeWeek[game_][account_];
    uint _currentWeek = getCurrentWeek();
    uint currentStake = gameAccountStaked[game_][account_];


    currentPoints = gameAccountLoyaltyPoints[game_][account_]
      .add((_currentWeek.sub(stakeWeek)).mul(currentStake.div(gcPerLoyaltyPoint)));
    // add their outstanding balance LP 

    uint currentPartner = loyaltyPartners[account_]; 
    if(currentPartner == game_ && game_ != 0) {
      uint loyaltyWeek = loyaltyWeeks[account_];
      if(loyaltyWeek < _currentWeek) {
        uint balance = _balances[account_];
        uint pointsToAdd = balance.div(gcPerLoyaltyPoint).mul(_currentWeek.sub(loyaltyWeek));
        currentPoints = currentPoints.add(pointsToAdd);
      }
    }
  }

  function getLoyaltyPointSpends(uint game_, address account_)
    public
    override
    view
  returns(uint totalSpend)
  {
    totalSpend = gameAccountPointsSpent[game_][account_];
  }

  function getLoyaltyPointsTotal(uint game_, address account_)
    public
    override
    view
  returns(uint totalRemaining)
  {
    uint points = getLoyaltyPointsGranted(game_, account_);
    uint spent = getLoyaltyPointSpends(game_, account_);
    if(points <= spent) {
      totalRemaining = 0;
    } else {
      totalRemaining = points.sub(spent);
    }
  }

  // Internal transfer of ERC20 tokens to complete payment of an auction.
  // @param from_ The address which you want to send tokens from
  // @param to_ The address which you want to transfer to
  // @param value_ The amout of tokens to be transferred
  function _beforeTokenTransfer(address from_, address to_, uint256 value_)
    internal
    override
  {
    if(from_ != address(0)) {
      emit Balance(from_, _balances[from_].sub(value_));
      _updateLoyalty(from_);
    }
    if(to_ != address(0)) {
      emit Balance(to_, _balances[to_].add(value_));
      _updateLoyalty(to_);
    }
  }

  function selectLoyaltyPartner(uint partnerId_)
    external
  {
    _setLoyaltyPartner(_msgSender(), partnerId_);
  }

  function workerSelectLoyaltyPartner(address account_, uint partnerId_)
    external
    workerOrMinion
  {
    _setLoyaltyPartner(account_, partnerId_);
  }


  // When a user picks a game,
  // if the user has a game picked and their last update week is last week or before
  // then grant N weeks of LP based on their prior balance
  // and update their last update week to this week
  function _setLoyaltyPartner(address account_, uint partnerId_)
    internal
  {
    _updateLoyalty(account_);
    uint currentPartner = loyaltyPartners[account_];
    loyaltyPartners[account_] = partnerId_;
    uint loyaltyWeek = loyaltyWeeks[account_];
    uint currentWeek = getCurrentWeek();
    if(loyaltyWeek == 0) {
      loyaltyWeeks[account_] = currentWeek;
    }
    if(currentPartner != partnerId_) {
      emit LoyaltyPartnerSet(partnerId_, account_, currentWeek);
    }
  }

  // handle loyalty points here
  // if the user has a game picked and their last update week is last week or before
  // then grant N weeks of LP based on their prior balance
  // and update their last update week to this week
  function _updateLoyalty(address account_)
    internal
  {
    uint currentPartner = loyaltyPartners[account_]; 
    if(currentPartner != 0) {
      uint loyaltyWeek = loyaltyWeeks[account_];
      uint currentWeek = getCurrentWeek();
      if(loyaltyWeek < currentWeek) {
        uint balance = _balances[account_];
        uint pointsToAdd = balance.div(gcPerLoyaltyPoint).mul(currentWeek.sub(loyaltyWeek));
        _addLoyaltyPoints(currentPartner, account_, pointsToAdd);
        loyaltyWeeks[account_] = currentWeek;
      }
    }
  }
}

// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract GAME_ERC20Staking is GAME_ERC20Loyalty {
  using SafeMath for uint256;

  event OracleTransaction(bytes32 indexed txHash);

  uint[] public gameStakeLevelCaps = [1, 2, 3, 4, 5, 6, 100000000000];

  uint public gameLevelPoints = 50;
  uint public auctionSitePoints = 100;
  uint public totalFeePoints = 400;


  // Tracks the current stake of each game.
  mapping(uint => uint) public gameStaked;
  // Stake
  uint public totalStaked;


  mapping(bytes32 => bool) public updateStakesOracleHashes;

  function setGameLevelPoints(uint points_)
    external
    onlyCFO
  {
    require(points_ <= 100, "must be less than or equal to 1%");
    gameLevelPoints = points_;
    totalFeePoints = auctionSitePoints.add(points_.mul(6));
  }

  function setAuctionSitePoints(uint points_)
    external
    onlyCFO
  {
    require(points_ <= 500, "must be less than or equal to 5%");
    auctionSitePoints = points_;
    totalFeePoints = points_.add(gameLevelPoints.mul(6));
  }

  function setGameStakeLevelCaps(uint[7] calldata caps_)
    external
    onlyCFO
  {
    uint previousData = 0;
    uint cap = 0;
    for(uint i = 0; i < 7; i++) {
      cap = caps_[i];
      require(cap > previousData, "caps must be ascending and non-zero");
      gameStakeLevelCaps[i] = cap;
      previousData = cap;
    }
    require(cap == 100000000000, "highest cap must be 100 billion");
  }

  function getGameStakeLevel(uint game_)
    public
    view
  returns (uint level) {
    uint gameStake = gameStaked[game_];
    for(level = 0; level < 7; level++) {
      if(gameStake < gameStakeLevelCaps[level]) {
        return level;
      }
    }
  }

  function getGameBalance(uint game_)
    public
    override
    view
  returns(uint balance) {
    balance = _balances[game_ == 0 ? address(this) : address(game_)];
  }

  // @dev Internal function to calculate the game, account, and total stakes on a stake change
  // @param week_ - the week we're updating (must be current or past)
  // @param game_ - the game to be staked on
  // @param staker_ - the account doing the staking
  // @param newStake_ - the newly updated stake of the staker on that game
  function oracleUpdateStakes(bytes32 txHash_, uint week_, uint game_, address staker_, uint newStake_)
    external
    workerOrMinion
  {
    if(updateStakesOracleHashes[txHash_]) {
      return;
    }
    updateStakesOracleHashes[txHash_] = true;
    emit OracleTransaction(txHash_);

    uint _currentWeek = getCurrentWeek();
    require(week_ <= _currentWeek, "requested week must be now or in the past");
    require(newStake_ <= 10 ** 29, "account stake underflow - must be <100Bn");

    // Check if the week is (a) less (do nothing), (b) equal (diff the stake), (c) greater (update everything)
    uint stakeWeek = gameAccountStakeWeek[game_][staker_];

    // If this is data for a previous week, ignore it
    // (we could adjust based on complex logic, but ignore is safer)
    require(stakeWeek <= week_, "requested week must be equal or later than stake week");

    uint playerStake = gameAccountStaked[game_][staker_];
    bool isStakeIncrease = newStake_ > playerStake ? true : false;
    uint stakeChange = isStakeIncrease ? newStake_ - playerStake : playerStake - newStake_;
    // update gameAccountStaked to the new stake amount
    // update gameStake based on the diff
    // update totalStake based on the diff
    gameAccountStakeWeek[game_][staker_] = week_;
    gameAccountStaked[game_][staker_] = newStake_;
    gameStaked[game_] = isStakeIncrease
      ? gameStaked[game_] + stakeChange
      : gameStaked[game_] - stakeChange;
    require(gameStaked[game_] <= 10 ** 29, "game stake underflow");
    totalStaked = isStakeIncrease
      ? totalStaked + stakeChange
      : totalStaked - stakeChange;
    require(totalStaked <= 10 ** 29, "total stake underflow");

    uint weeksToPay = (stakeWeek >= _currentWeek || stakeWeek >= week_ || stakeWeek == 0)
      ? 0
      : week_ - stakeWeek;
    uint pointsSpent = gameAccountPointsSpent[game_][staker_];
    // Update the Loyalty Points with the change
    gameAccountLoyaltyPoints[game_][staker_] = gameAccountLoyaltyPoints[game_][staker_].add(weeksToPay.mul(playerStake.div(gcPerLoyaltyPoint)));
    // If the last edit was made more than a week ago, collect Loyalty Points for the intervening weeks.

    // The current points is "what the points would be if you
    uint grantedPoints = getLoyaltyPointsGranted(game_, staker_);

    emit LoyaltyPointsChange(
      game_,
      staker_,
      week_,
      newStake_,
      grantedPoints,
      pointsSpent);
  }
}


// @title Auction Base
// @dev Contains models, variables, and internal methods for the auction.
// @notice We omit a fallback function to prevent accidental sends to this contract.
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract AuctionBase is GAME_ERC20Staking {
  using SafeMath for uint256;

  // @dev Map from tokenId to their corresponding auction data.
  // @notice We use two uints here because it's much more efficient than a struct
  mapping (uint => uint) public auctionIdToMetadata;
  mapping (uint => uint) public auctionIdToPrices;

  event AuctionCreated(
    address indexed seller,
    uint indexed tokenId,
    uint startingPrice,
    uint endingPrice,
    uint startTime,
    uint duration
  );

  event AuctionSuccessful(
    address indexed seller,
    address indexed buyer,
    uint indexed tokenId,
    uint totalPrice
  );

  event AuctionCancelled(address indexed seller, uint indexed tokenId);

  // @dev Adds an auction to the list of open auctions. Also fires the
  //  AuctionCreated event.
  // @param tokenId_ The Id of the token to be put on auction.
  // @param startingPrice - the start price of the Auction to add.
  // @param endingPrice - the end price of the Auction to add.
  // @param duration - the length of the Auction in seconds.
  // @param seller - the seller of the token.
  function _addAuction(
    uint tokenId_,
    uint startingPrice_,
    uint endingPrice_,
    uint duration_,
    address seller_
  )
    internal
  {
    require(duration_ == uint(uint48(duration_)), "add auction: duration must be a uint48");
    require(startingPrice_ == uint(uint128(startingPrice_)), "add auction: start price must be a uint128");
    require(endingPrice_ == uint(uint128(endingPrice_)), "add auction: end price must be a uint128");
    require(startingPrice_ > 0, "starting price must be non-zero");
    require(endingPrice_ > 0, "ending price must be non-zero");
    // Require that all auctions have a duration of
    // at least one minute. (Keeps our math from getting hairy!)
    require(duration_ >= 1 minutes, "auctions must be 1 minute long or more");

    uint auctionMetadata = uint(seller_)|duration_<<160|uint(uint48(block.timestamp))<<208;
    uint auctionPrices = endingPrice_|startingPrice_<<128;
    auctionIdToMetadata[tokenId_] = auctionMetadata;
    auctionIdToPrices[tokenId_] = auctionPrices;

    emit AuctionCreated(
      seller_,
      uint(tokenId_),
      uint(startingPrice_),
      uint(endingPrice_),
      uint(block.timestamp),
      uint(duration_)
    );
  }

  // @dev Cancels an auction unconditionally.
  // @param tokenId_ The Id of the token to cancelled.
  // @param seller_ - the seller of the token.
  function _cancelAuction(uint tokenId_, address seller_)
    internal
  {
    _removeAuction(tokenId_);
    erc721Contract.auctionTransfer(address(this), seller_, tokenId_);
    emit AuctionCancelled(seller_, tokenId_);
  }

  // @dev Retrieves the auction details for the requested auction
  // @param tokenId_ The Id of the token to be bid on.
  function _getAuction(uint tokenId_)
    internal
    view
    returns
  (
    address seller,
    uint startingPrice,
    uint endingPrice,
    uint duration,
    uint startedAt
  )
  {
    uint auctionMetadata = auctionIdToMetadata[tokenId_];
    uint auctionPrices = auctionIdToPrices[tokenId_];
    seller = address(auctionMetadata);
    duration = uint(uint48(auctionMetadata>>160));
    startedAt = uint(uint48(auctionMetadata>>208));
    startingPrice = uint(uint128(auctionPrices>>128));
    endingPrice = uint(uint128(auctionPrices));
  }

  // @dev Removes an auction from the list of open auctions.
  // @param tokenId_ - Id of NFT on auction.
  function _removeAuction(uint tokenId_)
    internal
  {
    delete auctionIdToMetadata[tokenId_];
    delete auctionIdToPrices[tokenId_];
  }

  // @dev Returns true if the NFT is on auction.
  // @param startedAt - the start time of the Auction to check.
  function _isOnAuction(uint startedAt_)
    internal
    pure
  returns (bool) {
    return (startedAt_ > 0);
  }

  // @dev Returns current price of an NFT on auction. Broken into two
  //  functions (this one, that computes the duration from the auction
  //  structure, and the other that does the price computation) so we
  //  can easily test that the price computation works correctly.
  function _auctionCurrentPrice(uint startingPrice_, uint endingPrice_, uint duration_, uint startedAt_)
    internal
    view
    returns (uint)
  {
    require(_isOnAuction(startedAt_), "must be on auction");
    uint secondsPassed = 0;

    // A bit of insurance against negative values (or wraparound).
    // Probably not necessary (since Ethereum guarnatees that the
    // now variable doesn't ever go backwards).
    if (block.timestamp > startedAt_) {
      secondsPassed = block.timestamp.sub(startedAt_);
    }

    return _computeAuctionCurrentPrice(
      startingPrice_,
      endingPrice_,
      duration_,
      secondsPassed
    );
  }

  // @dev Computes the current price of an auction. Factored out
  //  from _currentPrice so we can run extensive unit tests.
  //  When testing, make this function public and turn on
  //  `Current price computation` test suite.
  function _computeAuctionCurrentPrice(
    uint startingPrice_,
    uint endingPrice_,
    uint duration_,
    uint secondsPassed_
  )
    internal
    pure
    returns (uint)
  {
    // NOTE: We don't use SafeMath (or similar) in this function because
    //  all of our public functions cap the maximum values for
    //  time (at 48-bits) and currency (at 128-bits). duration_ is
    //  also known to be non-zero (see the require() statement in
    //  _addAuction())
    if (secondsPassed_ >= duration_) {
      // We've reached the end of the dynamic pricing portion
      // of the auction, just return the end price.
      return endingPrice_;
    } else {
      // Starting price can be higher than ending price (and often is!), so
      // this delta can be negative.
      int256 totalPriceChange = int256(endingPrice_) - int256(startingPrice_);

      // This multiplication can't overflow, secondsPassed_ will easily fit within
      // 48-bits, and totalPriceChange will easily fit within 128-bits, their product
      // will always fit within 256-bits.
      int256 currentPriceChange = totalPriceChange * int256(secondsPassed_) / int256(duration_);

      // currentPriceChange can be negative, but if so, will have a magnitude
      // less that startingPrice_. Thus, this result will always end up positive.
      int256 currentPrice = int256(startingPrice_) + currentPriceChange;

      return uint(currentPrice);
    }
  }

  function _payForAuction(uint game_, uint price_, address auctionSite_, address seller_, address buyer_)
    internal
  {
    uint totalFee = price_.mul(totalFeePoints).div(10000);
    uint level = getGameStakeLevel(game_);
    uint auctioneerFee = auctionSite_ == address(0) ? 0 : price_.mul(auctionSitePoints).div(10000);
    uint gameFee = price_.mul(level).mul(gameLevelPoints).div(10000);
    uint systemFee = totalFee.sub(auctioneerFee).sub(gameFee);

    // Transfer payment to the seller, then from the seller to the fee takers.
    _transfer(buyer_, seller_, price_);
    _transfer(seller_, address(this), systemFee);
    _transfer(seller_, game_ == 0 ? address(this) : address(game_), gameFee);
    if(auctioneerFee > 0) {
      _transfer(seller_, auctionSite_, auctioneerFee);
    }
  }
}



// @title ERC-721 Non-Fungible Token Standard
// @dev Interface for contracts conforming to ERC-721: Non-Fungible Tokens
// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
//  Note: the ERC-165 identifier for this interface is 0x80ac58cd

interface iERC721 {

  // @notice Count all NFTs assigned to an owner
  // @dev NFTs assigned to the zero address are considered invalid, and this
  //  function throws for queries about the zero address.
  // @param owner_ An address for whom to query the balance
  // @return The number of NFTs owned by `owner_`, possibly zero
  function balanceOf(address owner_) external view returns (uint);

  // @notice Find the owner of an NFT
  // @param tokenId_ The identifier for an NFT
  // @dev NFTs assigned to zero address are considered invalid, and queries
  //  about them do throw.
  // @return The address of the owner of the NFT
  function ownerOf(uint tokenId_) external view returns (address);

  // @notice Transfers the ownership of an NFT from one address to another address
  // @dev Throws unless `msg.sender` is the current owner, an authorized
  //  operator, or the approved address for this NFT. Throws if `from_` is
  //  not the current owner. Throws if `to_` is the zero address. Throws if
  //  `tokenId_` is not a valid NFT. When transfer is complete, this function
  //  checks if `to_` is a smart contract (code size > 0). If so, it calls
  //  `onERC721Received` on `to_` and throws if the return value is not
  //  `bytes4(keccak256("onERC721Received(address,address,uint,bytes)"))`.
  // @param from_ The current owner of the NFT
  // @param to_ The new owner
  // @param tokenId_ The NFT to transfer
  // @param data Additional data with no specified format, sent in call to `to_`
  function safeTransferFrom(address from_, address to_, uint tokenId_, bytes calldata data_) external;

  // @notice Transfers the ownership of an NFT from one address to another address
  // @dev This works identically to the other function with an extra data parameter,
  //  except this function just sets data to ""
  // @param from_ The current owner of the NFT
  // @param to_ The new owner
  // @param tokenId_ The NFT to transfer
  function safeTransferFrom(address from_, address to_, uint tokenId_) external;

  // @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  //  TO CONFIRM THAT `to_` IS CAPABLE OF RECEIVING NFTS OR ELSE
  //  THEY MAY BE PERMANENTLY LOST
  // @dev Throws unless `msg.sender` is the current owner, an authorized
  //  operator, or the approved address for this NFT. Throws if `from_` is
  //  not the current owner. Throws if `to_` is the zero address. Throws if
  //  `tokenId_` is not a valid NFT.
  // @param from_ The current owner of the NFT
  // @param to_ The new owner
  // @param tokenId_ The NFT to transfer
  function transferFrom(address from_, address to_, uint tokenId_) external;

  // @notice Set or reaffirm the approved address for an NFT
  // @dev The zero address indicates there is no approved address.
  // @dev Throws unless `msg.sender` is the current NFT owner, or an authorized
  //  operator of the current owner.
  // @param approved_ The new approved NFT controller
  // @param tokenId_ The NFT to approve
  function approve(address approved_, uint tokenId_) external;

  // @notice Enable or disable approval for a third party ("operator") to manage
  //  all your assets.
  // @dev Throws unless `msg.sender` is the current NFT owner.
  // @dev Emits the ApprovalForAll event
  // @param operator_ Address to add to the set of authorized operators.
  // @param approved_ True if the operators is approved, false to revoke approval
  function setApprovalForAll(address operator_, bool approved_) external;

  // @notice Get the approved address for a single NFT
  // @dev Throws if `tokenId_` is not a valid NFT
  // @param tokenId_ The NFT to find the approved address for
  // @return The approved address for this NFT, or the zero address if there is none
  function getApproved(uint tokenId_) external view returns (address);

  // @notice Query if an address is an authorized operator for another address
  // @param owner_ The address that owns the NFTs
  // @param operator_ The address that acts on behalf of the owner
  // @return True if `operator_` is an approved operator for `owner_`, false otherwise
  function isApprovedForAll(address owner_, address operator_) external view returns (bool);
}


// @title AuctionContract
// @dev Clock auction designed for sale of tokens
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

abstract contract AuctionExternal is AuctionBase {

  // @dev Returns auction info for an NFT on auction.
  // @param tokenId_ - Id of NFT on auction.
  function getExistingAuction(uint tokenId_)
    external
    view
    returns
  (
    address seller,
    uint startingPrice,
    uint endingPrice,
    uint duration,
    uint startedAt
  )
  {
    (seller, startingPrice, endingPrice, duration, startedAt) = _getAuction(tokenId_);

    require(_isOnAuction(startedAt), "must be on auction");
  }

  // @dev Returns the current price of an auction.
  // @param tokenId_ - Id of the token price we are checking.
  function getAuctionCurrentPrice(uint tokenId_)
    external
    view
  returns (uint) {
    address seller;
    uint startingPrice;
    uint endingPrice;
    uint duration;
    uint startedAt;
    (seller, startingPrice, endingPrice, duration, startedAt) = _getAuction(tokenId_);
    return _auctionCurrentPrice(startingPrice, endingPrice, duration, startedAt);
  }

  // @dev Put a token up for auction. Does some ownership trickery to create auctions in one tx.
  //   Also fires the AuctionCreated event.
  // @param tokenId_ The Id of the token to be put on auction.
  // @param startingPrice_ - the start price of the Auction to add.
  // @param endingPrice_ - the end price of the Auction to add.
  // @param duration_ - the length of the Auction in seconds.
  function createAuction(
    uint tokenId_,
    uint startingPrice_,
    uint endingPrice_,
    uint duration_
  )
    external
  {
    // Sanity check that no inputs overflow how many bits we've allocated
    // to store them in the auction struct.
    require(startingPrice_ == uint(uint128(startingPrice_)), "starting price under/overflow");
    require(endingPrice_ == uint(uint128(endingPrice_)), "ending price under/overflow");
    require(duration_ == uint(uint48(duration_)), "duration under/overflow");

    // Our auctions are only Dutch or fixed price.
    require(startingPrice_ >= endingPrice_, "starting price must be >= ending price");

    // Auctions can be no more than 7 days, and no less than 10 minutes
    require(duration_ <= 7 days, "duration must be <= 7 days");
    require(duration_ >= 10 minutes, "duration must be >= 10 minutes");

    address sender = _msgSender();
    // This checks "can transfer"
    erc721Contract.auctionTransfer(sender, address(this), tokenId_);
    // Auction throws if inputs are invalid and clears transfer of the token.

    _addAuction(tokenId_, startingPrice_, endingPrice_, duration_, sender);
  }

  // @dev Bids on an open auction, completing the auction and transferring
  //  ownership of the NFT if enough Ether is supplied.
  // @param tokenId_ - Id of token to bid on.
  // @param bidAmount_ - The amount of the bid (for safety, to ensure people don't pay too much)
  // @param auctioneer_ - The account that will receive 1% of the auction proceeds
  //   Usually, an exchange website will put its own address in as auctioneer_, so it can
  //   earn revenue for the public-facing portion of sales.
  function bidOnAuction(uint tokenId_, uint bidAmount_, address auctioneer_)
    external
  {
    address seller;
    uint startingPrice;
    uint endingPrice;
    uint duration;
    uint startedAt;
    (seller, startingPrice, endingPrice, duration, startedAt) = _getAuction(tokenId_);

    // This contract must own the on sale token
    require(iERC721(address(erc721Contract)).ownerOf(tokenId_) == address(this), "contract must own on-sale token");

    // Explicitly check that this auction is currently live.
    require(_isOnAuction(startedAt), "auction must be live");

    // Check that the bid is greater than or equal to the current price
    uint price = _auctionCurrentPrice(startingPrice, endingPrice, duration, startedAt);
    require(bidAmount_ >= price, "bid must be greater than or equal to price");

    // The bid is good! Remove the auction before sending the fees
    // so we can't have a reentrancy attack.
    _removeAuction(tokenId_);

    uint game = uint256(uint64(tokenId_));
    address sender = _msgSender();

    // Transfer the payment from the buyer to the seller, and the fees to the game, system, and auctioneer
    _payForAuction(game, price, auctioneer_, seller, sender);

    // Tell the world!
    emit AuctionSuccessful(seller, sender, tokenId_, price);

    // Reassign ownership (also clears pending approvals and emits Transfer event).
    erc721Contract.auctionTransfer(address(this), sender, tokenId_);
  }

  // @dev Cancels an auction that hasn't been won yet.
  //  Returns the NFT to original owner.
  // @param tokenId_ - Id of token on auction
  function cancelAuction(uint tokenId_)
    external
  {
    uint auctionMetadata = auctionIdToMetadata[tokenId_];
    address seller = address(auctionMetadata);
    uint startedAt = uint(uint48(auctionMetadata>>208));

    require(_isOnAuction(startedAt), "token must be on auction");
    require(_msgSender() == seller, "token seller must be sender");
    _cancelAuction(tokenId_, seller);
  }

  // @dev Cancels an auction.
  //  Only the manager may do this, and NFTs are returned to
  //  the seller. This should only be used in emergencies.
  // @param tokenId_ - Id of the NFT on auction to cancel.
  function cancelAuctionByManager(uint tokenId_)
    external
    override
    onlyLocalContract
  {
    uint auctionMetadata = auctionIdToMetadata[tokenId_];
    address seller = address(auctionMetadata);
    uint startedAt = uint(uint48(auctionMetadata>>208));
    require(_isOnAuction(startedAt), "token must be on auction");
    _cancelAuction(tokenId_, seller);
  }
}


// @title GAME Credits ERC20 contract
// @dev ERC20 management contract, designed to make using ERC-20 tokens easier
// @author GAME Credits (gamecredits.org)
// (c) 2020 GAME Credits All Rights Reserved. This code is not open source.

contract GAME_ERC20 is AuctionExternal {
  using SafeMath for uint256;

  string constant public CONTRACT_ERC712_VERSION = "1";
  string constant public CONTRACT_ERC712_NAME = "GAME Credits Sidechain ERC20 Contract";

  // @dev Constructor creates a reference to the master contract
  //  and the ERC20 depositor contract.
  // @param masterContract_ - address of the master contract
  // @param depositor_ - address of the erc20 depositor contract
  // @param rootChainId_ - ID of the chain the contract is deployed on
  constructor(address masterContract_, address depositor_)
    GAME_ERC20Access(masterContract_)
    ChildERC20("GAME Credits", "GAME", 18, depositor_)
    NetworkAgnostic(CONTRACT_ERC712_NAME, CONTRACT_ERC712_VERSION)
  {
  }

  // @dev Withdraws the whole balance of a game to an admin account.
  // @param uint game_ The game Id of the game for which sender is an admin
  function withdrawGameBalance(uint game_)
    external
    onlyGameAdmin(game_)
  {
    require(game_ > 0, "can't withdraw from the zero address");
    _transfer(address(game_), _msgSender(), _balances[address(game_)]);
  }

  // @dev Withdraws the whole balance of the system to an admin account.
  // @param uint game_ The game Id of the game for which sender is an admin
  function withdrawSystemBalance()
    external
    onlyCFO
  {
    _transfer(address(this), _msgSender(), _balances[address(this)]);
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"masterContract_","type":"address"},{"internalType":"address","name":"depositor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"AuctionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startingPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endingPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalPrice","type":"uint256"}],"name":"AuctionSuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Balance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"game","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"week","type":"uint256"}],"name":"LoyaltyPartnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"game","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"week","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalGranted","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSpent","type":"uint256"}],"name":"LoyaltyPointsChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"game","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"pointsGrant","type":"uint256"}],"name":"LoyaltyPointsGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"game","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"pointsRemoved","type":"uint256"}],"name":"LoyaltyPointsRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"address payable","name":"relayerAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"functionSignature","type":"bytes"}],"name":"MetaTransactionExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"txHash","type":"bytes32"}],"name":"OracleTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spenderContract","type":"address"},{"indexed":false,"internalType":"bool","name":"isSpender","type":"bool"}],"name":"ThirdPartyRewwardsSpender","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CONTRACT_ERC712_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTRACT_ERC712_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECONDS_PER_WEEK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WEEK_ZERO_START","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bool","name":"isSpender_","type":"bool"}],"name":"approveThirdPartyLoyaltySpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedLoyaltySpenders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"auctionIdToMetadata","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"auctionIdToPrices","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionSitePoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"bidAmount_","type":"uint256"},{"internalType":"address","name":"auctioneer_","type":"address"}],"name":"bidOnAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"cancelAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"cancelAuctionByManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"startingPrice_","type":"uint256"},{"internalType":"uint256","name":"endingPrice_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"}],"name":"createAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes","name":"depositData","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"encodeDomainSeperator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"encodeWorkerDomainSeperator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721Contract","outputs":[{"internalType":"contract iGAME_ERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"bytes","name":"functionSignature","type":"bytes"},{"internalType":"bytes32","name":"sigR","type":"bytes32"},{"internalType":"bytes32","name":"sigS","type":"bytes32"},{"internalType":"uint8","name":"sigV","type":"uint8"}],"name":"executeMetaTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"gameAccountLoyaltyPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"gameAccountPointsSpent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"gameAccountStakeWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"gameAccountStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameContract","outputs":[{"internalType":"contract iGAME_Game","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameLevelPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"gameStakeLevelCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"gameStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gcPerLoyaltyPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getAuctionCurrentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getCurrentWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeperator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getExistingAuction","outputs":[{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"startingPrice","type":"uint256"},{"internalType":"uint256","name":"endingPrice","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"startedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"}],"name":"getGameBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"}],"name":"getGameStakeLevel","outputs":[{"internalType":"uint256","name":"level","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"}],"name":"getLoyaltyPointSpends","outputs":[{"internalType":"uint256","name":"totalSpend","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"}],"name":"getLoyaltyPointsGranted","outputs":[{"internalType":"uint256","name":"currentPoints","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"}],"name":"getLoyaltyPointsTotal","outputs":[{"internalType":"uint256","name":"totalRemaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWorkerDomainSeperator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isLocalContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"gameContract_","type":"address"},{"internalType":"address","name":"erc721Contract_","type":"address"}],"name":"linkContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"localContracts","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"loyaltyPartners","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"loyaltyWeeks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterContract","outputs":[{"internalType":"contract iGAME_Master","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"txHash_","type":"bytes32"},{"internalType":"uint256","name":"week_","type":"uint256"},{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"staker_","type":"address"},{"internalType":"uint256","name":"newStake_","type":"uint256"}],"name":"oracleUpdateStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"partnerId_","type":"uint256"}],"name":"selectLoyaltyPartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"points_","type":"uint256"}],"name":"setAuctionSitePoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositor_","type":"address"}],"name":"setDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"points_","type":"uint256"}],"name":"setGameLevelPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[7]","name":"caps_","type":"uint256[7]"}],"name":"setGameStakeLevelCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"pointsToSpend_","type":"uint256"}],"name":"thirdPartySpendLoyaltyPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalFeePoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"transferByContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"},{"internalType":"bool","name":"isLocal_","type":"bool"}],"name":"updateLocalContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"updateStakesOracleHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"}],"name":"withdrawGameBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSystemBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress_","type":"address"},{"internalType":"bytes32","name":"replayPrevention_","type":"bytes32"},{"internalType":"bytes","name":"functionSignature_","type":"bytes"},{"internalType":"bytes32","name":"sigR_","type":"bytes32"},{"internalType":"bytes32","name":"sigS_","type":"bytes32"},{"internalType":"uint8","name":"sigV_","type":"uint8"}],"name":"workerExecuteMetaTransaction","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"pointsGrant_","type":"uint256"}],"name":"workerGrantLoyaltyPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"pointsToRemove_","type":"uint256"}],"name":"workerRemoveLoyaltyPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"partnerId_","type":"uint256"}],"name":"workerSelectLoyaltyPartner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"game_","type":"uint256"},{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"pointsToSpend_","type":"uint256"}],"name":"workerSpendLoyaltyPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

670de0b6b3a764000060105561016060405260016080908152600260a052600360c052600460e05260056101005260066101205264174876e800610140526200004d9060179060076200035e565b5060326018556064601955610190601a553480156200006b57600080fd5b506040516200617738038062006177833981810160405260408110156200009157600080fd5b508051602091820151604080518082018252600c81526b47414d45204372656469747360a01b8186015281518083018352600481526347414d4560e01b818701528251606081019093526025808452949593948694929391926012928792909162006100908301396040805180820190915260018152603160f81b602082015285858383620001218282620001d1565b600055620001308282620002a9565b600155505081516200014a906005906020850190620003b7565b50805162000160906006906020840190620003b7565b50506007805460ff19166012179055506200017f915083905062000344565b600a80546001600160a01b039283166001600160a01b031991821617909155600b8054969092169516851790555050506000908152600e60205260409020805460ff1916600117905550620004419050565b600080620001de6200035a565b90508062000233576040805162461bcd60e51b815260206004820152601960248201527f636861696e204944206d757374206e6f74206265207a65726f00000000000000604482015290519081900360640190fd5b60405180608001604052806052815260200162006125605291398051602091820120855186830120855186840120604080518086019490945283810192909252606083015260808201939093523060a0808301919091528351808303909101815260c09091019092528151910120905092915050565b600080620002b66200035a565b90508060891480620002c85750806001145b620002e957806201388114620002e0576000620002e3565b60055b620002ec565b60015b60ff1690508062000233576040805162461bcd60e51b815260206004820152601960248201527f636861696e204944206d757374206e6f74206265207a65726f00000000000000604482015290519081900360640190fd5b6007805460ff191660ff92909216919091179055565b4690565b828054828255906000526020600020908101928215620003a5579160200282015b82811115620003a5578251829064ffffffffff169055916020019190600101906200037f565b50620003b39291506200042a565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003fa57805160ff1916838001178555620003a5565b82800160010185558215620003a5579182015b82811115620003a55782518255916020019190600101906200040d565b5b80821115620003b357600081556001016200042b565b615caf80620004516000396000f3fe6080604052600436106104615760003560e01c80637672b33c1161023f578063b9c24a4811610139578063d7c97fb4116100b6578063f2c098b71161007a578063f2c098b714611507578063f40c96ab1461153a578063fbc394ea1461154f578063fbd2695b14611579578063fe6399b8146115b857610468565b8063d7c97fb41461144a578063dd62ed3e1461145f578063e1a1a66c1461149a578063e2340c95146114af578063e2b8e7d3146114c457610468565b8063cc165837116100fd578063cc1658371461136b578063cc9c6eeb14611380578063cd446e2214611395578063cf2c52cb146113aa578063d3f330091461143557610468565b8063b9c24a481461128f578063bdc3c59d146112b9578063be46fcb9146112ec578063c7977be714611325578063c7c4ff461461133a57610468565b8063a457c2d7116101c7578063ad2ded2b1161018b578063ad2ded2b14611118578063ad39f8b4146111df578063b26fcc5814611209578063b6acd1e614611233578063b74e32261461125c57610468565b8063a457c2d714611028578063a593d19114611061578063a84069631461108b578063a9059cbb146110b5578063ace31e7d146110ee57610468565b806396b5a7551161020e57806396b5a75514610f565780639a1d804414610f805780639dad1da514610fbf5780639f3fba5914610fe9578063a1fd47d61461101357610468565b80637672b33c14610ede578063817b1cd214610f1757806384ae2a7414610f2c57806395d89b4114610f4157610468565b80633250c6d11161035b5780635958b301116102d85780636d4b99e01161029c5780636d4b99e014610d185780636eb227ce14610e4e57806370a0823114610e6357806372012a0b14610e96578063765d6cce14610ec957610468565b80635958b30114610bcd5780635c57e2b314610c085780635f489a5314610c415780636138939a14610c80578063644b2b9f14610cdf57610468565b8063395093511161031f5780633950935114610acf5780633dc9abfa14610b085780633f990fc014610b4357806342bf989d14610b58578063431f21da14610b9157610468565b80633250c6d1146109e25780633408e47014610a0c57806335490cdd14610a2157806335e748fb14610a6c578063368a5a1a14610a9657610468565b806318160ddd116103e957806327430a42116103ad57806327430a421461080f5780632d0335ab146109455780632e1a7d4d146109785780632ed3aae3146109a2578063313ce567146109b757610468565b806318160ddd146107365780631b5eb0c11461074b5780631c9b5c0a1461078457806320379ee5146107b757806323b872dd146107cc57610468565b8063095ea7b311610430578063095ea7b3146105b157806309bcdcfe146105ea5780630c53c51c1461062657806312a92a56146106e8578063161e650d1461072157610468565b80630434f5fd1461046d57806304598bc2146104aa57806306fdde03146104e957806307c3353d1461057357610468565b3661046857005b600080fd5b34801561047957600080fd5b506104a86004803603604081101561049057600080fd5b506001600160a01b03813516906020013515156115f7565b005b3480156104b657600080fd5b506104a8600480360360608110156104cd57600080fd5b508035906001600160a01b0360208201351690604001356117e1565b3480156104f557600080fd5b506104fe6118f0565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610538578181015183820152602001610520565b50505050905090810190601f1680156105655780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561057f57600080fd5b5061059d6004803603602081101561059657600080fd5b5035611987565b604080519115158252519081900360200190f35b3480156105bd57600080fd5b5061059d600480360360408110156105d457600080fd5b506001600160a01b03813516906020013561199c565b3480156105f657600080fd5b506106146004803603602081101561060d57600080fd5b50356119ba565b60408051918252519081900360200190f35b6104fe600480360360a081101561063c57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561066657600080fd5b82018360208201111561067857600080fd5b803590602001918460018302840111600160201b8311171561069957600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550508235935050506020810135906040013560ff16611a0a565b3480156106f457600080fd5b506106146004803603604081101561070b57600080fd5b50803590602001356001600160a01b0316611d17565b34801561072d57600080fd5b50610614611d34565b34801561074257600080fd5b50610614611d3a565b34801561075757600080fd5b506106146004803603604081101561076e57600080fd5b50803590602001356001600160a01b0316611d40565b34801561079057600080fd5b5061059d600480360360208110156107a757600080fd5b50356001600160a01b0316611d5d565b3480156107c357600080fd5b50610614611d72565b3480156107d857600080fd5b5061059d600480360360608110156107ef57600080fd5b506001600160a01b03813581169160208101359091169060400135611d78565b34801561081b57600080fd5b506106146004803603604081101561083257600080fd5b810190602081018135600160201b81111561084c57600080fd5b82018360208201111561085e57600080fd5b803590602001918460018302840111600160201b8311171561087f57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156108d157600080fd5b8201836020820111156108e357600080fd5b803590602001918460018302840111600160201b8311171561090457600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611dff945050505050565b34801561095157600080fd5b506106146004803603602081101561096857600080fd5b50356001600160a01b0316611f03565b34801561098457600080fd5b506104a86004803603602081101561099b57600080fd5b5035611f1e565b3480156109ae57600080fd5b50610614611f32565b3480156109c357600080fd5b506109cc611f3a565b6040805160ff9092168252519081900360200190f35b3480156109ee57600080fd5b506104a860048036036020811015610a0557600080fd5b5035611f43565b348015610a1857600080fd5b5061061461200b565b348015610a2d57600080fd5b506104a8600480360360a0811015610a4457600080fd5b508035906020810135906040810135906001600160a01b03606082013516906080013561200f565b348015610a7857600080fd5b5061061460048036036020811015610a8f57600080fd5b50356124dd565b348015610aa257600080fd5b5061061460048036036040811015610ab957600080fd5b50803590602001356001600160a01b03166124ef565b348015610adb57600080fd5b5061059d60048036036040811015610af257600080fd5b506001600160a01b038135169060200135612516565b348015610b1457600080fd5b506104a860048036036040811015610b2b57600080fd5b506001600160a01b0381358116916020013516612564565b348015610b4f57600080fd5b5061061461277c565b348015610b6457600080fd5b5061061460048036036040811015610b7b57600080fd5b50803590602001356001600160a01b0316612782565b348015610b9d57600080fd5b506104a860048036036080811015610bb457600080fd5b50803590602081013590604081013590606001356127c4565b348015610bd957600080fd5b506104a860048036036040811015610bf057600080fd5b506001600160a01b0381351690602001351515612a54565b348015610c1457600080fd5b506104a860048036036040811015610c2b57600080fd5b506001600160a01b038135169060200135612bee565b348015610c4d57600080fd5b506104a860048036036060811015610c6457600080fd5b508035906001600160a01b036020820135169060400135612cbb565b348015610c8c57600080fd5b50610caa60048036036020811015610ca357600080fd5b5035612ea3565b604080516001600160a01b03909616865260208601949094528484019290925260608401526080830152519081900360a00190f35b348015610ceb57600080fd5b5061061460048036036040811015610d0257600080fd5b50803590602001356001600160a01b0316612f18565b348015610d2457600080fd5b5061061460048036036040811015610d3b57600080fd5b810190602081018135600160201b811115610d5557600080fd5b820183602082011115610d6757600080fd5b803590602001918460018302840111600160201b83111715610d8857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b811115610dda57600080fd5b820183602082011115610dec57600080fd5b803590602001918460018302840111600160201b83111715610e0d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612f35945050505050565b348015610e5a57600080fd5b50610614612f90565b348015610e6f57600080fd5b5061061460048036036020811015610e8657600080fd5b50356001600160a01b0316612fa0565b348015610ea257600080fd5b5061059d60048036036020811015610eb957600080fd5b50356001600160a01b0316612fbb565b348015610ed557600080fd5b5061059d612fd0565b348015610eea57600080fd5b5061061460048036036040811015610f0157600080fd5b50803590602001356001600160a01b0316612fd5565b348015610f2357600080fd5b50610614612ff2565b348015610f3857600080fd5b50610614612ff8565b348015610f4d57600080fd5b506104fe612fff565b348015610f6257600080fd5b506104a860048036036020811015610f7957600080fd5b5035613060565b348015610f8c57600080fd5b506104a860048036036060811015610fa357600080fd5b508035906001600160a01b036020820135169060400135613137565b348015610fcb57600080fd5b5061061460048036036020811015610fe257600080fd5b5035613190565b348015610ff557600080fd5b506104a86004803603602081101561100c57600080fd5b50356131c3565b34801561101f57600080fd5b506104a8613309565b34801561103457600080fd5b5061059d6004803603604081101561104b57600080fd5b506001600160a01b0381351690602001356133f8565b34801561106d57600080fd5b506106146004803603602081101561108457600080fd5b5035613460565b34801561109757600080fd5b506104a8600480360360208110156110ae57600080fd5b5035613495565b3480156110c157600080fd5b5061059d600480360360408110156110d857600080fd5b506001600160a01b0381351690602001356135d9565b3480156110fa57600080fd5b506106146004803603602081101561111157600080fd5b50356135ed565b6104fe600480360360c081101561112e57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b81111561115d57600080fd5b82018360208201111561116f57600080fd5b803590602001918460018302840111600160201b8311171561119057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550508235935050506020810135906040013560ff166135ff565b3480156111eb57600080fd5b506106146004803603602081101561120257600080fd5b5035613990565b34801561121557600080fd5b506106146004803603602081101561122c57600080fd5b50356139a2565b34801561123f57600080fd5b506104a8600480360360e081101561125657600080fd5b506139c0565b34801561126857600080fd5b506106146004803603602081101561127f57600080fd5b50356001600160a01b0316613b6d565b34801561129b57600080fd5b506104a8600480360360208110156112b257600080fd5b5035613b7f565b3480156112c557600080fd5b50610614600480360360208110156112dc57600080fd5b50356001600160a01b0316613b90565b3480156112f857600080fd5b506106146004803603604081101561130f57600080fd5b50803590602001356001600160a01b0316613ba2565b34801561133157600080fd5b50610614613ce6565b34801561134657600080fd5b5061134f613d09565b604080516001600160a01b039092168252519081900360200190f35b34801561137757600080fd5b50610614613d18565b34801561138c57600080fd5b50610614613d1e565b3480156113a157600080fd5b5061134f613d24565b3480156113b657600080fd5b506104a8600480360360408110156113cd57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156113f757600080fd5b82018360208201111561140957600080fd5b803590602001918460018302840111600160201b8311171561142a57600080fd5b509092509050613d33565b34801561144157600080fd5b5061134f613dac565b34801561145657600080fd5b5061134f613dbb565b34801561146b57600080fd5b506106146004803603604081101561148257600080fd5b506001600160a01b0381358116916020013516613dca565b3480156114a657600080fd5b506104fe613df5565b3480156114bb57600080fd5b50610614613e11565b3480156114d057600080fd5b506104a8600480360360608110156114e757600080fd5b506001600160a01b03813581169160208101359091169060400135613e17565b34801561151357600080fd5b506104a86004803603602081101561152a57600080fd5b50356001600160a01b0316613e70565b34801561154657600080fd5b506104fe613f4c565b34801561155b57600080fd5b506104a86004803603602081101561157257600080fd5b5035613f69565b34801561158557600080fd5b506104a86004803603606081101561159c57600080fd5b508035906001600160a01b0360208201351690604001356140aa565b3480156115c457600080fd5b506104a8600480360360608110156115db57600080fd5b50803590602081013590604001356001600160a01b0316614169565b600b546001600160a01b031663b4ff232e611610614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561164d57600080fd5b505afa158015611661573d6000803e3d6000fd5b505050506040513d602081101561167757600080fd5b50516116c3576040805162461bcd60e51b815260206004820152601660248201527573656e646572206d757374206265207468652063666f60501b604482015290519081900360640190fd5b801561173c576001600160a01b0382166000908152600f602052604090205460ff1615611737576040805162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420697320616c72656164792061207370656e646572000000604482015290519081900360640190fd5b611793565b6001600160a01b0382166000908152600f602052604090205460ff166117935760405162461bcd60e51b8152600401808060200182810382526022815260200180615c0b6022913960400191505060405180910390fd5b6001600160a01b0382166000818152600f6020908152604091829020805460ff191685151590811790915582519081529151600080516020615b168339815191529281900390910190a25050565b600b546001600160a01b03166317937a076117fa614411565b6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050602060405180830381600087803b15801561183957600080fd5b505af115801561184d573d6000803e3d6000fd5b505050506040513d602081101561186357600080fd5b50516118a05760405162461bcd60e51b8152600401808060200182810382526024815260200180615a656024913960400191505060405180910390fd5b6040805182815290516001600160a01b0384169185917fd41290e38d33620ad1b04f29dd43f8c059267cc4fc1f8ed57a0f3d768efb5f919181900360200190a36118eb83838361446e565b505050565b60058054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561197c5780601f106119515761010080835404028352916020019161197c565b820191906000526020600020905b81548152906001019060200180831161195f57829003601f168201915b505050505090505b90565b601d6020526000908152604090205460ff1681565b60006119b06119a9614411565b84846144d5565b5060015b92915050565b6000818152601b60205260408120545b6007821015611a0357601782815481106119e057fe5b90600052602060002001548110156119f85750611a05565b6001909101906119ca565b505b919050565b6060611a14615692565b50604080516060810182526001600160a01b03881660008181526008602090815290849020548352820152908101869052611a5287828787876145c1565b611a8d5760405162461bcd60e51b8152600401808060200182810382526021815260200180615a896021913960400191505060405180910390fd5b6001600160a01b038716600090815260086020526040902054611ab1906001614669565b60086000896001600160a01b03166001600160a01b03168152602001908152602001600020819055507f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b87338860405180846001600160a01b03168152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611b59578181015183820152602001611b41565b50505050905090810190601f168015611b865780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a160006060306001600160a01b0316888a6040516020018083805190602001908083835b60208310611bd75780518252601f199092019160209182019101611bb8565b6001836020036101000a038019825116818451168082178552505050505050905001826001600160a01b031660601b8152601401925050506040516020818303038152906040526040518082805190602001908083835b60208310611c4d5780518252601f199092019160209182019101611c2e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611caf576040519150601f19603f3d011682016040523d82523d6000602084013e611cb4565b606091505b509150915081611d0b576040805162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c00000000604482015290519081900360640190fd5b98975050505050505050565b601260209081526000928352604080842090915290825290205481565b60015490565b60045490565b601360209081526000928352604080842090915290825290205481565b600f6020526000908152604090205460ff1681565b60005490565b6000611d858484846146ca565b611df584611d91614411565b611df085604051806060016040528060288152602001615a3d602891396001600160a01b038a16600090815260036020526040812090611dcf614411565b6001600160a01b031681526020810191909152604001600020549190614827565b6144d5565b5060019392505050565b600080611e0a61200b565b90508060891480611e1b5750806001145b611e3857806201388114611e30576000611e33565b60055b611e3b565b60015b60ff16905080611e8e576040805162461bcd60e51b8152602060048201526019602482015278636861696e204944206d757374206e6f74206265207a65726f60381b604482015290519081900360640190fd5b604051806080016040528060528152602001615976605291398051602091820120855186830120855186840120604080518086019490945283810192909252606083015260808201939093523060a0808301919091528351808303909101815260c09091019092528151910120905092915050565b6001600160a01b031660009081526008602052604090205490565b611f2f611f29614411565b826148be565b50565b635bb1638081565b60075460ff1690565b336000908152600e602052604090205460ff16611f915760405162461bcd60e51b8152600401808060200182810382526022815260200180615b366022913960400191505060405180910390fd5b6000818152601e60205260409020548060d081901c611faf816149ba565b611ffb576040805162461bcd60e51b81526020600482015260186024820152773a37b5b2b71036bab9ba1031329037b71030bab1ba34b7b760411b604482015290519081900360640190fd5b61200584836149bf565b50505050565b4690565b600b546001600160a01b03166317937a07612028614411565b6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050602060405180830381600087803b15801561206757600080fd5b505af115801561207b573d6000803e3d6000fd5b505050506040513d602081101561209157600080fd5b50516120ce5760405162461bcd60e51b8152600401808060200182810382526024815260200180615a656024913960400191505060405180910390fd5b6000858152601d602052604090205460ff16156120ea576124d6565b6000858152601d6020526040808220805460ff191660011790555186917f5b6a3ef0e5bffde11ba16a6f95c28598fd3c36913011167e2239d3ebcbc07f8591a26000612134612f90565b9050808511156121755760405162461bcd60e51b81526004018080602001828103825260298152602001806158f46029913960400191505060405180910390fd5b6c01431e0fae6d7217caa00000008211156121c15760405162461bcd60e51b8152600401808060200182810382526028815260200180615c2d6028913960400191505060405180910390fd5b60008481526013602090815260408083206001600160a01b0387168452909152902054858111156122235760405162461bcd60e51b81526004018080602001828103825260358152602001806159416035913960400191505060405180910390fd5b60008581526014602090815260408083206001600160a01b038816845290915281205490818511612255576000612258565b60015b90506000816122695785830361226d565b8286035b60008981526013602090815260408083206001600160a01b038c168085529083528184208e90558c84526014835281842090845290915290208790559050816122c7576000888152601b60205260409020548190036122d9565b6000888152601b602052604090205481015b6000898152601b602052604090208190556c01431e0fae6d7217caa00000001015612342576040805162461bcd60e51b815260206004820152601460248201527367616d65207374616b6520756e646572666c6f7760601b604482015290519081900360640190fd5b816123515780601c5403612357565b80601c54015b601c8190556c01431e0fae6d7217caa000000010156123b5576040805162461bcd60e51b8152602060048201526015602482015274746f74616c207374616b6520756e646572666c6f7760581b604482015290519081900360640190fd5b600085851015806123c65750898510155b806123cf575084155b6123db57848a036123de565b60005b60008a81526012602090815260408083206001600160a01b038d1684529091529020546010549192509061244b906124229061241b908890614a75565b8490614ab7565b60008c81526011602090815260408083206001600160a01b038f16845290915290205490614669565b60008b81526011602090815260408083206001600160a01b038e16845290915281209190915561247b8b8b613ba2565b604080518b81526020810183905280820185905290519192508d916001600160a01b038d16918e917f19f1796adcb2405f90c02fdd22577ab1e1bde3ba7966ccea9d3a3ea1f589287b9181900360600190a450505050505050505b5050505050565b601b6020526000908152604090205481565b60009182526012602090815260408084206001600160a01b03909316845291905290205490565b60006119b0612523614411565b84611df08560036000612534614411565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490614669565b336000908152600e602052604090205460ff166125b25760405162461bcd60e51b8152600401808060200182810382526022815260200180615b366022913960400191505060405180910390fd5b600c546001600160a01b031615612610576040805162461bcd60e51b815260206004820152601c60248201527f746f6b656e20636f6e7472616374206d75737420626520626c616e6b00000000604482015290519081900360640190fd5b600d546001600160a01b03161561266e576040805162461bcd60e51b815260206004820152601c60248201527f746f6b656e20636f6e7472616374206d75737420626520626c616e6b00000000604482015290519081900360640190fd5b600c80546001600160a01b038085166001600160a01b03199283168117909355600d8054918516919092161790556000818152600f6020908152604091829020805460ff1916600190811790915582519081529151600080516020615b168339815191529281900390910190a26001600160a01b0381166000818152600f6020908152604091829020805460ff1916600190811790915582519081529151600080516020615b168339815191529281900390910190a2600b80546001600160a01b039081166000908152600f6020908152604091829020805460ff191660019081179091559354825194855291519190921692600080516020615b1683398151915292908290030190a25050565b60195481565b60008061278f8484613ba2565b9050600061279d85856124ef565b90508082116127af57600092506127bc565b6127b98282614b10565b92505b505092915050565b826001600160801b03168314612821576040805162461bcd60e51b815260206004820152601d60248201527f7374617274696e6720707269636520756e6465722f6f766572666c6f77000000604482015290519081900360640190fd5b816001600160801b0316821461287e576040805162461bcd60e51b815260206004820152601b60248201527f656e64696e6720707269636520756e6465722f6f766572666c6f770000000000604482015290519081900360640190fd5b8065ffffffffffff1681146128da576040805162461bcd60e51b815260206004820152601760248201527f6475726174696f6e20756e6465722f6f766572666c6f77000000000000000000604482015290519081900360640190fd5b818310156129195760405162461bcd60e51b815260040180806020018281038252602681526020018061587c6026913960400191505060405180910390fd5b62093a80811115612971576040805162461bcd60e51b815260206004820152601a60248201527f6475726174696f6e206d757374206265203c3d20372064617973000000000000604482015290519081900360640190fd5b6102588110156129c8576040805162461bcd60e51b815260206004820152601e60248201527f6475726174696f6e206d757374206265203e3d203130206d696e757465730000604482015290519081900360640190fd5b60006129d2614411565b600d5460408051631f80982160e11b81526001600160a01b038085166004830152306024830152604482018a90529151939450911691633f0130429160648082019260009290919082900301818387803b158015612a2f57600080fd5b505af1158015612a43573d6000803e3d6000fd5b505050506124d68585858585614b52565b336000908152600e602052604090205460ff16612aa25760405162461bcd60e51b8152600401808060200182810382526022815260200180615b366022913960400191505060405180910390fd5b600b546001600160a01b0383811691161415612b05576040805162461bcd60e51b815260206004820152601f60248201527f63616e277420726573657420746865206d617374657220636f6e747261637400604482015290519081900360640190fd5b600d546001600160a01b0383811691161415612b68576040805162461bcd60e51b815260206004820152601f60248201527f63616e2774207265736574207468652065726337323120636f6e747261637400604482015290519081900360640190fd5b6001600160a01b038216612bc3576040805162461bcd60e51b815260206004820152601960248201527f63616e277420626520746865207a65726f206164647265737300000000000000604482015290519081900360640190fd5b6001600160a01b03919091166000908152600e60205260409020805460ff1916911515919091179055565b600b546001600160a01b03166317937a07612c07614411565b6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050602060405180830381600087803b158015612c4657600080fd5b505af1158015612c5a573d6000803e3d6000fd5b505050506040513d6020811015612c7057600080fd5b5051612cad5760405162461bcd60e51b8152600401808060200182810382526024815260200180615a656024913960400191505060405180910390fd5b612cb78282614db4565b5050565b600b546001600160a01b03166317937a07612cd4614411565b6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050602060405180830381600087803b158015612d1357600080fd5b505af1158015612d27573d6000803e3d6000fd5b505050506040513d6020811015612d3d57600080fd5b5051612d7a5760405162461bcd60e51b8152600401808060200182810382526024815260200180615a656024913960400191505060405180910390fd5b60008381526011602090815260408083206001600160a01b0386168452909152902054612da79082614b10565b60008481526011602090815260408083206001600160a01b0387168452909152812091909155612dd78484613ba2565b9050826001600160a01b0316847f4e6c02e9bc74e4cebedd8785daa9604431c9150d3deac966a5a71e937a228d0e846040518082815260200191505060405180910390a3612e23612f90565b60008581526014602090815260408083206001600160a01b03881680855290835281842054898552601284528285208286528452938290205482519485529284018690528382019290925251909187917f19f1796adcb2405f90c02fdd22577ab1e1bde3ba7966ccea9d3a3ea1f589287b9181900360600190a450505050565b6000806000806000612eb486614e61565b939850919650945092509050612ec9816149ba565b612f0f576040805162461bcd60e51b815260206004820152601260248201527136bab9ba1031329037b71030bab1ba34b7b760711b604482015290519081900360640190fd5b91939590929450565b601460209081526000928352604080842090915290825290205481565b600080612f4061200b565b905080611e8e576040805162461bcd60e51b8152602060048201526019602482015278636861696e204944206d757374206e6f74206265207a65726f60381b604482015290519081900360640190fd5b62093a8042635bb1637f19010490565b6001600160a01b031660009081526002602052604090205490565b600e6020526000908152604090205460ff1681565b600190565b601160209081526000928352604080842090915290825290205481565b601c5481565b62093a8081565b60068054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561197c5780601f106119515761010080835404028352916020019161197c565b6000818152601e60205260409020548060d081901c61307e816149ba565b6130ca576040805162461bcd60e51b81526020600482015260186024820152773a37b5b2b71036bab9ba1031329037b71030bab1ba34b7b760411b604482015290519081900360640190fd5b816001600160a01b03166130dc614411565b6001600160a01b031614611ffb576040805162461bcd60e51b815260206004820152601b60248201527f746f6b656e2073656c6c6572206d7573742062652073656e6465720000000000604482015290519081900360640190fd5b336000908152600f602052604090205460ff166131855760405162461bcd60e51b81526004018080602001828103825260338152602001806157fb6033913960400191505060405180910390fd5b6118eb838383614ea4565b600060028183156131a157836131a3565b305b6001600160a01b0316815260208101919091526040016000205492915050565b600c5481906001600160a01b031663110371ac826131df614411565b6040518363ffffffff1660e01b815260040180838152602001826001600160a01b031681526020019250505060206040518083038186803b15801561322357600080fd5b505afa158015613237573d6000803e3d6000fd5b505050506040513d602081101561324d57600080fd5b50516132a0576040805162461bcd60e51b815260206004820152601b60248201527f73656e646572206d75737420626520612067616d652061646d696e0000000000604482015290519081900360640190fd5b600082116132df5760405162461bcd60e51b815260040180806020018281038252602481526020018061591d6024913960400191505060405180910390fd5b612cb7826132eb614411565b6001600160a01b0385166000908152600260205260409020546146ca565b600b546001600160a01b031663b4ff232e613322614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561335f57600080fd5b505afa158015613373573d6000803e3d6000fd5b505050506040513d602081101561338957600080fd5b50516133d5576040805162461bcd60e51b815260206004820152601660248201527573656e646572206d757374206265207468652063666f60501b604482015290519081900360640190fd5b6133f6306133e1614411565b306000908152600260205260409020546146ca565b565b60006119b0613405614411565b84611df085604051806060016040528060258152602001615c55602591396003600061342f614411565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190614827565b60008060008060008061347287614e61565b93985091965094509250905061348a84848484614fbb565b979650505050505050565b600b546001600160a01b031663b4ff232e6134ae614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156134eb57600080fd5b505afa1580156134ff573d6000803e3d6000fd5b505050506040513d602081101561351557600080fd5b5051613561576040805162461bcd60e51b815260206004820152601660248201527573656e646572206d757374206265207468652063666f60501b604482015290519081900360640190fd5b60648111156135b7576040805162461bcd60e51b815260206004820181905260248201527f6d757374206265206c657373207468616e206f7220657175616c20746f203125604482015290519081900360640190fd5b60188190556135d36135ca826006614ab7565b60195490614669565b601a5550565b60006119b06135e6614411565b84846146ca565b601e6020526000908152604090205481565b606061360961503b565b6136445760405162461bcd60e51b8152600401808060200182810382526042815260200180615ba66042913960600191505060405180910390fd5b61364c6156bc565b50604080516060810182528781526001600160a01b038916602082015290810186905261367c88828787876150b8565b6136b75760405162461bcd60e51b8152600401808060200182810382526021815260200180615a896021913960400191505060405180910390fd5b6001600160a01b03881660009081526009602090815260408083208a845290915290205460ff1615613730576040805162461bcd60e51b815260206004820181905260248201527f5245504c4159206f6620612070726576696f7573207472616e73616374696f6e604482015290519081900360640190fd5b6001600160a01b03881660008181526009602090815260408083208b84528252808320805460ff1916600117905580519384523384830181905260609185018281528b51928601929092528a517f5845892132946850460bff5a0083f71031bc5bf9aadcd40f1de79423eac9b10b958e9592948d94919391926080850192918601918190849084905b838110156137d15781810151838201526020016137b9565b50505050905090810190601f1680156137fe5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a160006060306001600160a01b0316888b6040516020018083805190602001908083835b6020831061384f5780518252601f199092019160209182019101613830565b6001836020036101000a038019825116818451168082178552505050505050905001826001600160a01b031660601b8152601401925050506040516020818303038152906040526040518082805190602001908083835b602083106138c55780518252601f1990920191602091820191016138a6565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613927576040519150601f19603f3d011682016040523d82523d6000602084013e61392c565b606091505b509150915081613983576040805162461bcd60e51b815260206004820152601c60248201527f46756e6374696f6e2063616c6c206e6f74207375636365737366756c00000000604482015290519081900360640190fd5b9998505050505050505050565b601f6020526000908152604090205481565b601781815481106139af57fe5b600091825260209091200154905081565b600b546001600160a01b031663b4ff232e6139d9614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015613a1657600080fd5b505afa158015613a2a573d6000803e3d6000fd5b505050506040513d6020811015613a4057600080fd5b5051613a8c576040805162461bcd60e51b815260206004820152601660248201527573656e646572206d757374206265207468652063666f60501b604482015290519081900360640190fd5b60008060005b6007811015613b1357838160078110613aa757fe5b60200201359150828211613aec5760405162461bcd60e51b8152600401808060200182810382526023815260200180615be86023913960400191505060405180910390fd5b8160178281548110613afa57fe5b6000918252602090912001559091508190600101613a92565b508064174876e800146118eb576040805162461bcd60e51b815260206004820152601f60248201527f6869676865737420636170206d757374206265203130302062696c6c696f6e00604482015290519081900360640190fd5b60166020526000908152604090205481565b611f2f613b8a614411565b82614db4565b60156020526000908152604090205481565b60008281526013602090815260408083206001600160a01b038516845290915281205481613bce612f90565b60008681526014602090815260408083206001600160a01b038916845290915290205460105491925090613c4490613c1b90613c0b908490614a75565b613c158587614b10565b90614ab7565b60008881526011602090815260408083206001600160a01b038b16845290915290205490614669565b6001600160a01b0386166000908152601560205260409020549094508681148015613c6e57508615155b15613cdc576001600160a01b03861660009081526016602052604090205483811015613cda576001600160a01b03871660009081526002602052604081205490613cc9613cbb8785614b10565b601054613c15908590614a75565b9050613cd58882614669565b975050505b505b5050505092915050565b604051806080016040528060528152602001615976605291398051906020012081565b600a546001600160a01b031681565b601a5481565b60105481565b600b546001600160a01b031681565b600a546001600160a01b0316613d47614411565b6001600160a01b031614613d8c5760405162461bcd60e51b81526004018080602001828103825260248152602001806158a26024913960400191505060405180910390fd5b600082826020811015613d9e57600080fd5b5035905061200584826150e0565b600c546001600160a01b031681565b600d546001600160a01b031681565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b6040518060600160405280602581526020016157216025913981565b60185481565b336000908152600e602052604090205460ff16613e655760405162461bcd60e51b8152600401808060200182810382526022815260200180615b366022913960400191505060405180910390fd5b6118eb8383836146ca565b600b546001600160a01b0316632f54bf6e613e89614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015613ec657600080fd5b505afa158015613eda573d6000803e3d6000fd5b505050506040513d6020811015613ef057600080fd5b5051613f43576040805162461bcd60e51b815260206004820152601860248201527f73656e646572206d75737420626520746865206f776e65720000000000000000604482015290519081900360640190fd5b611f2f816151d2565b604051806040016040528060018152602001603160f81b81525081565b600b546001600160a01b031663b4ff232e613f82614411565b6040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015613fbf57600080fd5b505afa158015613fd3573d6000803e3d6000fd5b505050506040513d6020811015613fe957600080fd5b5051614035576040805162461bcd60e51b815260206004820152601660248201527573656e646572206d757374206265207468652063666f60501b604482015290519081900360640190fd5b6101f481111561408c576040805162461bcd60e51b815260206004820181905260248201527f6d757374206265206c657373207468616e206f7220657175616c20746f203525604482015290519081900360640190fd5b60198190556018546135d3906140a3906006614ab7565b8290614669565b600b546001600160a01b03166317937a076140c3614411565b6040518263ffffffff1660e01b815260040180826001600160a01b03168152602001915050602060405180830381600087803b15801561410257600080fd5b505af1158015614116573d6000803e3d6000fd5b505050506040513d602081101561412c57600080fd5b50516131855760405162461bcd60e51b8152600401808060200182810382526024815260200180615a656024913960400191505060405180910390fd5b600080600080600061417a88614e61565b8095508196508297508398508499505050505050306001600160a01b0316600d60009054906101000a90046001600160a01b03166001600160a01b0316636352211e8a6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156141f157600080fd5b505afa158015614205573d6000803e3d6000fd5b505050506040513d602081101561421b57600080fd5b50516001600160a01b031614614278576040805162461bcd60e51b815260206004820152601f60248201527f636f6e7472616374206d757374206f776e206f6e2d73616c6520746f6b656e00604482015290519081900360640190fd5b614281816149ba565b6142c9576040805162461bcd60e51b815260206004820152601460248201527361756374696f6e206d757374206265206c69766560601b604482015290519081900360640190fd5b60006142d785858585614fbb565b9050808810156143185760405162461bcd60e51b815260040180806020018281038252602a815260200180615b58602a913960400191505060405180910390fd5b614321896151f4565b67ffffffffffffffff89166000614336614411565b905061434582848b8b85615212565b8a816001600160a01b0316896001600160a01b03167fb2f957e6e6ed6377e70534f97fc23756b916174a0228bf795ee7d21597c5f637866040518082815260200191505060405180910390a4600d5460408051631f80982160e11b81523060048201526001600160a01b038481166024830152604482018f905291519190921691633f01304291606480830192600092919082900301818387803b1580156143ec57600080fd5b505af1158015614400573d6000803e3d6000fd5b505050505050505050505050505050565b6000333014156144695760606000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050503601516001600160a01b031691506119849050565b503390565b60008381526011602090815260408083206001600160a01b038616845290915290205461449b9082614669565b60008481526011602090815260408083206001600160a01b03871684529091528120919091556144cb8484613ba2565b9050612e23612f90565b6001600160a01b03831661451a5760405162461bcd60e51b8152600401808060200182810382526024815260200180615b826024913960400191505060405180910390fd5b6001600160a01b03821661455f5760405162461bcd60e51b81526004018080602001828103825260228152602001806157d96022913960400191505060405180910390fd5b6001600160a01b03808416600081815260036020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b60006001600160a01b0386161580159061465f575060016145e96145e487615300565b615383565b83868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015614640573d6000803e3d6000fd5b505050602060405103516001600160a01b0316866001600160a01b0316145b9695505050505050565b6000828201838110156146c3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b03831661470f5760405162461bcd60e51b8152600401808060200182810382526025815260200180615af16025913960400191505060405180910390fd5b6001600160a01b0382166147545760405162461bcd60e51b81526004018080602001828103825260238152602001806156dc6023913960400191505060405180910390fd5b61475f8383836153cf565b61479c8160405180606001604052806026815260200161582e602691396001600160a01b0386166000908152600260205260409020549190614827565b6001600160a01b0380851660009081526002602052604080822093909355908416815220546147cb9082614669565b6001600160a01b0380841660008181526002602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156148b65760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561487b578181015183820152602001614863565b50505050905090810190601f1680156148a85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b0382166149035760405162461bcd60e51b8152600401808060200182810382526021815260200180615ad06021913960400191505060405180910390fd5b61490f826000836153cf565b61494c816040518060600160405280602281526020016156ff602291396001600160a01b0385166000908152600260205260409020549190614827565b6001600160a01b0383166000908152600260205260409020556004546149729082614b10565b6004556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b151590565b6149c8826151f4565b600d5460408051631f80982160e11b81523060048201526001600160a01b0384811660248301526044820186905291519190921691633f01304291606480830192600092919082900301818387803b158015614a2357600080fd5b505af1158015614a37573d6000803e3d6000fd5b50506040518492506001600160a01b03841691507f018b64b6242d32aa550e95d78985b938d71af5b3f10827b0683f55da1639304890600090a35050565b60006146c383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506154d1565b600082614ac6575060006119b4565b82820282848281614ad357fe5b04146146c35760405162461bcd60e51b8152600401808060200182810382526021815260200180615a1c6021913960400191505060405180910390fd5b60006146c383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614827565b8165ffffffffffff168214614b985760405162461bcd60e51b81526004018080602001828103825260268152602001806157466026913960400191505060405180910390fd5b836001600160801b03168414614bdf5760405162461bcd60e51b815260040180806020018281038252602a8152602001806157af602a913960400191505060405180910390fd5b826001600160801b03168314614c265760405162461bcd60e51b81526004018080602001828103825260288152602001806158546028913960400191505060405180910390fd5b60008411614c7b576040805162461bcd60e51b815260206004820152601f60248201527f7374617274696e67207072696365206d757374206265206e6f6e2d7a65726f00604482015290519081900360640190fd5b60008311614cd0576040805162461bcd60e51b815260206004820152601d60248201527f656e64696e67207072696365206d757374206265206e6f6e2d7a65726f000000604482015290519081900360640190fd5b603c821015614d105760405162461bcd60e51b8152600401808060200182810382526026815260200180615aaa6026913960400191505060405180910390fd5b6000858152601e602090815260408083204260d081901b6001600160d01b03191660a088901b6001600160a01b0388169081179190911792839055601f85529483902060808a811b8a179182905584518b81529586018a905285850192909252606085018890529251919492938a93927fabdd2430f9e10eb5db384c1218c42f980dd5fcda760a680a0d95ec506f0963cb929181900390910190a350505050505050565b614dbd82615536565b6001600160a01b038216600090815260156020908152604080832080549085905560169092528220549091614df0612f90565b905081614e13576001600160a01b03851660009081526016602052604090208190555b8383146124d6576040805182815290516001600160a01b0387169186917f48bf5c652deea67c8e1387e2003591e18b66d5b2a7642e6afd87efd825cbefae9181900360200190a35050505050565b6000908152601e6020908152604080832054601f909252909120549091608082901c916001600160801b03169065ffffffffffff60a085901c169060d085901c90565b6000614eb08484613ba2565b60008581526012602090815260408083206001600160a01b038816845290915281205491925090614ee19084614669565b905080821015614f225760405162461bcd60e51b815260040180806020018281038252602e8152602001806158c6602e913960400191505060405180910390fd5b60008581526012602090815260408083206001600160a01b03881684529091529020819055614f4f612f90565b60008681526014602090815260408083206001600160a01b038916808552908352928190205481519081529182018690528181018590525188917f19f1796adcb2405f90c02fdd22577ab1e1bde3ba7966ccea9d3a3ea1f589287b919081900360600190a45050505050565b6000614fc6826149ba565b61500c576040805162461bcd60e51b815260206004820152601260248201527136bab9ba1031329037b71030bab1ba34b7b760711b604482015290519081900360640190fd5b600082421115615023576150204284614b10565b90505b61502f868686846155d8565b9150505b949350505050565b600b54604080516317937a0760e01b815233600482015290516000926001600160a01b0316916317937a0791602480830192602092919082900301818787803b15801561508757600080fd5b505af115801561509b573d6000803e3d6000fd5b505050506040513d60208110156150b157600080fd5b5051905090565b60006001600160a01b0386161580159061465f575060016145e96150db87615605565b615688565b6001600160a01b03821661513b576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b615147600083836153cf565b6004546151549082614669565b6004556001600160a01b03821660009081526002602052604090205461517a9082614669565b6001600160a01b03831660008181526002602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6000908152601e60209081526040808320839055601f909152812055565b600061523561271061522f601a5488614ab790919063ffffffff16565b90614a75565b90506000615242876119ba565b905060006001600160a01b038616156152755761527061271061522f6019548a614ab790919063ffffffff16565b615278565b60005b9050600061529b61271061522f601854613c15878d614ab790919063ffffffff16565b905060006152b3826152ad8786614b10565b90614b10565b90506152c086888b6146ca565b6152cb8730836146ca565b6152e3878b156152db578b6152dd565b305b846146ca565b82156152f4576152f48789856146ca565b50505050505050505050565b600060405180608001604052806043815260200161576c60439139805190602001208260000151836020015184604001518051906020012060405160200180858152602001848152602001836001600160a01b03168152602001828152602001945050505050604051602081830303815290604052805190602001209050919050565b600061538d611d72565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b6001600160a01b03831615615450576001600160a01b0383166000908152600260205260409020547f134e340554ff8a7d64280a2a28b982df554e2595e5bf45cd39368f31099172a69084906154259084614b10565b604080516001600160a01b03909316835260208301919091528051918290030190a161545083615536565b6001600160a01b038216156118eb576001600160a01b0382166000908152600260205260409020547f134e340554ff8a7d64280a2a28b982df554e2595e5bf45cd39368f31099172a69083906154a69084614669565b604080516001600160a01b03909316835260208301919091528051918290030190a16118eb82615536565b600081836155205760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561487b578181015183820152602001614863565b50600083858161552c57fe5b0495945050505050565b6001600160a01b0381166000908152601560205260409020548015612cb7576001600160a01b03821660009081526016602052604081205490615577612f90565b905080821015612005576001600160a01b038416600090815260026020526040812054906155a8613cbb8486614b10565b90506155b585878361446e565b50506001600160a01b038416600090815260166020526040902081905550505050565b60008282106155e8575082615033565b848403600084848302816155f857fe5b0587019250615033915050565b60006040518060800160405280605481526020016159c860549139805190602001208260000151836020015184604001518051906020012060405160200180858152602001848152602001836001600160a01b03168152602001828152602001945050505050604051602081830303815290604052805190602001209050919050565b600061538d611d34565b60405180606001604052806000815260200160006001600160a01b03168152602001606081525090565b604080516060808201835260008083526020830152918101919091529056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636547414d4520437265646974732053696465636861696e20455243323020436f6e74726163746164642061756374696f6e3a206475726174696f6e206d75737420626520612075696e7434384d6574615472616e73616374696f6e2875696e74323536206e6f6e63652c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e6174757265296164642061756374696f6e3a207374617274207072696365206d75737420626520612075696e7431323845524332303a20617070726f766520746f20746865207a65726f20616464726573736d75737420626520616e20617070726f766564204c6f79616c747920506f696e7473207370656e64657220636f6e747261637445524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63656164642061756374696f6e3a20656e64207072696365206d75737420626520612075696e743132387374617274696e67207072696365206d757374206265203e3d20656e64696e672070726963654368696c6445524332303a20494e53554646494349454e545f5045524d495353494f4e537370656e74206d6f7265204c6f79616c747920506f696e7473207468616e2063757272656e742062616c616e6365726571756573746564207765656b206d757374206265206e6f77206f7220696e20746865207061737463616e27742077697468647261772066726f6d20746865207a65726f2061646472657373726571756573746564207765656b206d75737420626520657175616c206f72206c61746572207468616e207374616b65207765656b454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429576f726b65724d6574615472616e73616374696f6e2862797465733332207265706c617950726576656e74696f6e2c616464726573732066726f6d2c62797465732066756e6374696f6e5369676e617475726529536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63656d7573742062652063616c6c6564206279206120776f726b6572206f72206d696e696f6e5369676e657220616e64207369676e617475726520646f206e6f74206d6174636861756374696f6e73206d7573742062652031206d696e757465206c6f6e67206f72206d6f726545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f20616464726573730c86b472d7e1cc408d1374136df3b65e32cf0d1d4f74e9ecfddb8dbcbf2513a66d7573742062652063616c6c65642062792061206c6f63616c20636f6e7472616374626964206d7573742062652067726561746572207468616e206f7220657175616c20746f20707269636545524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373576f726b6572204d6574612d5472616e73616374696f6e2073656e74206279206163636f756e74206f74686572207468616e206120776f726b65722f6d696e696f6e63617073206d75737420626520617363656e64696e6720616e64206e6f6e2d7a65726f436f6e74726163742069736e277420616e206578697374696e67207370656e6465726163636f756e74207374616b6520756e646572666c6f77202d206d757374206265203c313030426e45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220ab6ee013fa41be9b39904f2c5a8d9a3c203391aa4d783260b0e126097037337a64736f6c6343000700003347414d4520437265646974732053696465636861696e20455243323020436f6e7472616374454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e7472616374290000000000000000000000002550aa5c84edb92a66125a85527c151923be35e1000000000000000000000000a6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa

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

0000000000000000000000002550aa5c84edb92a66125a85527c151923be35e1000000000000000000000000a6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa

-----Decoded View---------------
Arg [0] : masterContract_ (address): 0x2550aa5c84edb92a66125a85527c151923be35e1
Arg [1] : depositor_ (address): 0xa6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002550aa5c84edb92a66125a85527c151923be35e1
Arg [1] : 000000000000000000000000a6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa


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