ETH Price: $2,463.35 (+2.45%)

Token

 

Overview

Max Total Supply

0

Holders

0

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
DigitalaxGenesisStaking

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU GPLv2 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2020-11-29
*/

// File @openzeppelin/contracts/math/[email protected]

// SPDX-License-Identifier: GPLv2

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}


// File @openzeppelin/contracts/utils/[email protected]



pragma solidity ^0.6.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
 * (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            bytes32 lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(value)));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint256(_at(set._inner, index)));
    }


    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }
}


// File @openzeppelin/contracts/utils/[email protected]



pragma solidity ^0.6.2;

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


// File @openzeppelin/contracts/GSN/[email protected]



pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.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;
    }
}


// File @openzeppelin/contracts/access/[email protected]



pragma solidity ^0.6.0;



/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context {
    using EnumerableSet for EnumerableSet.AddressSet;
    using Address for address;

    struct RoleData {
        EnumerableSet.AddressSet members;
        bytes32 adminRole;
    }

    mapping (bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view returns (bool) {
        return _roles[role].members.contains(account);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view returns (uint256) {
        return _roles[role].members.length();
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
        return _roles[role].members.at(index);
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");

        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual {
        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");

        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
        _roles[role].adminRole = adminRole;
    }

    function _grantRole(bytes32 role, address account) private {
        if (_roles[role].members.add(account)) {
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (_roles[role].members.remove(account)) {
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}


// File contracts/DigitalaxAccessControls.sol

pragma solidity 0.6.12;

/**
 * @notice Access Controls contract for the Digitalax Platform
 * @author BlockRocket.tech
 */
contract DigitalaxAccessControls is AccessControl {
    /// @notice Role definitions
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant SMART_CONTRACT_ROLE = keccak256("SMART_CONTRACT_ROLE");

    /// @notice Events for adding and removing various roles
    event AdminRoleGranted(
        address indexed beneficiary,
        address indexed caller
    );

    event AdminRoleRemoved(
        address indexed beneficiary,
        address indexed caller
    );

    event MinterRoleGranted(
        address indexed beneficiary,
        address indexed caller
    );

    event MinterRoleRemoved(
        address indexed beneficiary,
        address indexed caller
    );

    event SmartContractRoleGranted(
        address indexed beneficiary,
        address indexed caller
    );

    event SmartContractRoleRemoved(
        address indexed beneficiary,
        address indexed caller
    );

    /**
     * @notice The deployer is automatically given the admin role which will allow them to then grant roles to other addresses
     */
    constructor() public {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    /////////////
    // Lookups //
    /////////////

    /**
     * @notice Used to check whether an address has the admin role
     * @param _address EOA or contract being checked
     * @return bool True if the account has the role or false if it does not
     */
    function hasAdminRole(address _address) external view returns (bool) {
        return hasRole(DEFAULT_ADMIN_ROLE, _address);
    }

    /**
     * @notice Used to check whether an address has the minter role
     * @param _address EOA or contract being checked
     * @return bool True if the account has the role or false if it does not
     */
    function hasMinterRole(address _address) external view returns (bool) {
        return hasRole(MINTER_ROLE, _address);
    }

    /**
     * @notice Used to check whether an address has the smart contract role
     * @param _address EOA or contract being checked
     * @return bool True if the account has the role or false if it does not
     */
    function hasSmartContractRole(address _address) external view returns (bool) {
        return hasRole(SMART_CONTRACT_ROLE, _address);
    }

    ///////////////
    // Modifiers //
    ///////////////

    /**
     * @notice Grants the admin role to an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract receiving the new role
     */
    function addAdminRole(address _address) external {
        grantRole(DEFAULT_ADMIN_ROLE, _address);
        emit AdminRoleGranted(_address, _msgSender());
    }

    /**
     * @notice Removes the admin role from an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract affected
     */
    function removeAdminRole(address _address) external {
        revokeRole(DEFAULT_ADMIN_ROLE, _address);
        emit AdminRoleRemoved(_address, _msgSender());
    }

    /**
     * @notice Grants the minter role to an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract receiving the new role
     */
    function addMinterRole(address _address) external {
        grantRole(MINTER_ROLE, _address);
        emit MinterRoleGranted(_address, _msgSender());
    }

    /**
     * @notice Removes the minter role from an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract affected
     */
    function removeMinterRole(address _address) external {
        revokeRole(MINTER_ROLE, _address);
        emit MinterRoleRemoved(_address, _msgSender());
    }

    /**
     * @notice Grants the smart contract role to an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract receiving the new role
     */
    function addSmartContractRole(address _address) external {
        grantRole(SMART_CONTRACT_ROLE, _address);
        emit SmartContractRoleGranted(_address, _msgSender());
    }

    /**
     * @notice Removes the smart contract role from an address
     * @dev The sender must have the admin role
     * @param _address EOA or contract affected
     */
    function removeSmartContractRole(address _address) external {
        revokeRole(SMART_CONTRACT_ROLE, _address);
        emit SmartContractRoleRemoved(_address, _msgSender());
    }
}


// File @openzeppelin/contracts/introspection/[email protected]



pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}


// File @openzeppelin/contracts/token/ERC721/[email protected]



pragma solidity ^0.6.2;

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
      * @dev Safely transfers `tokenId` token from `from` to `to`.
      *
      * Requirements:
      *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
      * - `tokenId` token must exist and be owned by `from`.
      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}


// File @openzeppelin/contracts/token/ERC721/[email protected]



pragma solidity ^0.6.2;

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {

    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}


// File @openzeppelin/contracts/token/ERC721/[email protected]



pragma solidity ^0.6.2;

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {

    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}


// File @openzeppelin/contracts/token/ERC721/[email protected]



pragma solidity ^0.6.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
    external returns (bytes4);
}


// File @openzeppelin/contracts/introspection/[email protected]



pragma solidity ^0.6.0;

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}


// File @openzeppelin/contracts/utils/[email protected]



pragma solidity ^0.6.0;

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
 * supported.
 */
library EnumerableMap {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Map type with
    // bytes32 keys and values.
    // The Map implementation uses private functions, and user-facing
    // implementations (such as Uint256ToAddressMap) are just wrappers around
    // the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit
    // in bytes32.

    struct MapEntry {
        bytes32 _key;
        bytes32 _value;
    }

    struct Map {
        // Storage of map keys and values
        MapEntry[] _entries;

        // Position of the entry defined by a key in the `entries` array, plus 1
        // because index 0 means a key is not in the map.
        mapping (bytes32 => uint256) _indexes;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex == 0) { // Equivalent to !contains(map, key)
            map._entries.push(MapEntry({ _key: key, _value: value }));
            // The entry is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            map._indexes[key] = map._entries.length;
            return true;
        } else {
            map._entries[keyIndex - 1]._value = value;
            return false;
        }
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function _remove(Map storage map, bytes32 key) private returns (bool) {
        // We read and store the key's index to prevent multiple reads from the same storage slot
        uint256 keyIndex = map._indexes[key];

        if (keyIndex != 0) { // Equivalent to contains(map, key)
            // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
            // in the array, and then remove the last entry (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = keyIndex - 1;
            uint256 lastIndex = map._entries.length - 1;

            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            MapEntry storage lastEntry = map._entries[lastIndex];

            // Move the last entry to the index where the entry to delete is
            map._entries[toDeleteIndex] = lastEntry;
            // Update the index for the moved entry
            map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved entry was stored
            map._entries.pop();

            // Delete the index for the deleted slot
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function _contains(Map storage map, bytes32 key) private view returns (bool) {
        return map._indexes[key] != 0;
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function _length(Map storage map) private view returns (uint256) {
        return map._entries.length;
    }

   /**
    * @dev Returns the key-value pair stored at position `index` in the map. O(1).
    *
    * Note that there are no guarantees on the ordering of entries inside the
    * array, and it may change when more entries are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
        require(map._entries.length > index, "EnumerableMap: index out of bounds");

        MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
        return _get(map, key, "EnumerableMap: nonexistent key");
    }

    /**
     * @dev Same as {_get}, with a custom error message when `key` is not in the map.
     */
    function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return _set(map._inner, bytes32(key), bytes32(uint256(value)));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
        return _remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
        return _contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return _length(map._inner);
    }

   /**
    * @dev Returns the element stored at position `index` in the set. O(1).
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);
        return (uint256(key), address(uint256(value)));
    }

    /**
     * @dev Returns the value associated with `key`.  O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint256(_get(map._inner, bytes32(key))));
    }

    /**
     * @dev Same as {get}, with a custom error message when `key` is not in the map.
     */
    function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
        return address(uint256(_get(map._inner, bytes32(key), errorMessage)));
    }
}


// File @openzeppelin/contracts/utils/[email protected]



pragma solidity ^0.6.0;

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

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


// File contracts/ERC721/ERC721WithSameTokenURIForAllTokens.sol



pragma solidity 0.6.12;










/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://eips.ethereum.org/EIPS/eip-721
 * @dev This is a modified OZ ERC721 base contract with one change where all tokens have the same token URI
 */
contract ERC721WithSameTokenURIForAllTokens is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
    using SafeMath for uint256;
    using Address for address;
    using EnumerableSet for EnumerableSet.UintSet;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using Strings for uint256;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from holder address to their (enumerable) set of owned tokens
    mapping (address => EnumerableSet.UintSet) private _holderTokens;

    // Enumerable mapping from token ids to their owners
    EnumerableMap.UintToAddressMap private _tokenOwners;

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

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

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Single token URI for all tokens
    string public tokenURI_;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    /*
     *     bytes4(keccak256('name()')) == 0x06fdde03
     *     bytes4(keccak256('symbol()')) == 0x95d89b41
     *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
     *
     *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
     */
    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;

    /*
     *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
     *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
     *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
     *
     *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
     */
    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;

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

        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
    }

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

        return _holderTokens[owner].length();
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view override returns (address) {
        return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
    }

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

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

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

        return tokenURI_;
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
        return _holderTokens[owner].at(index);
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
        return _tokenOwners.length();
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view override returns (uint256) {
        (uint256 tokenId, ) = _tokenOwners.at(index);
        return tokenId;
    }

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

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

        _approve(to, tokenId);
    }

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

        return _tokenApprovals[tokenId];
    }

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

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        return _tokenOwners.contains(tokenId);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     d*
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
        _mint(to, tokenId);
        require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

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

        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

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

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ownerOf(tokenId);

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

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

        _holderTokens[owner].remove(tokenId);

        _tokenOwners.remove(tokenId);

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

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(address from, address to, uint256 tokenId) internal virtual {
        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

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

        _holderTokens[from].remove(tokenId);
        _holderTokens[to].add(tokenId);

        _tokenOwners.set(tokenId, to);

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
    private returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }
        bytes memory returndata = to.functionCall(abi.encodeWithSelector(
                IERC721Receiver(to).onERC721Received.selector,
                _msgSender(),
                from,
                tokenId,
                _data
            ), "ERC721: transfer to non ERC721Receiver implementer");
        bytes4 retval = abi.decode(returndata, (bytes4));
        return (retval == _ERC721_RECEIVED);
    }

    function _approve(address to, uint256 tokenId) private {
        _tokenApprovals[tokenId] = to;
        emit Approval(ownerOf(tokenId), to, tokenId);
    }

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


// File contracts/DigitalaxGenesisNFT.sol



pragma solidity 0.6.12;



/**
 * @title Digitalax Genesis NFT
 * @dev To facilitate the genesis sale for the Digitialax platform
 */
contract DigitalaxGenesisNFT is ERC721WithSameTokenURIForAllTokens("DigitalaxGenesis", "DXG") {
    using SafeMath for uint256;

    // @notice event emitted upon construction of this contract, used to bootstrap external indexers
    event DigitalaxGenesisNFTContractDeployed();

    // @notice event emitted when a contributor buys a Genesis NFT
    event GenesisPurchased(
        address indexed buyer,
        uint256 indexed tokenId,
        uint256 contribution
    );

    // @notice event emitted when a admin mints a Genesis NFT
    event AdminGenesisMinted(
        address indexed beneficiary,
        address indexed admin,
        uint256 indexed tokenId
    );

    // @notice event emitted when a contributors amount is increased
    event ContributionIncreased(
        address indexed buyer,
        uint256 contribution
    );

    // @notice event emitted when end date is changed
    event GenesisEndUpdated(
        uint256 genesisEndTimestamp,
        address indexed admin
    );

    // @notice event emitted when DigitalaxAccessControls is updated
    event AccessControlsUpdated(
        address indexed newAdress
    );

    // @notice responsible for enforcing admin access
    DigitalaxAccessControls public accessControls;

    // @notice all funds will be sent to this address pon purchase of a Genesis NFT
    address payable public fundsMultisig;

    // @notice start date for them the Genesis sale is open to the public, before this data no purchases can be made
    uint256 public genesisStartTimestamp;

    // @notice end date for them the Genesis sale is closed, no more purchased can be made after this point
    uint256 public genesisEndTimestamp;

    // @notice set after end time has been changed once, prevents further changes to end timestamp
    bool public genesisEndTimestampLocked;

    // @notice the minimum amount a buyer can contribute in a single go
    uint256 public constant minimumContributionAmount = 0.1 ether;

    // @notice the maximum accumulative amount a user can contribute to the genesis sale
    uint256 public constant maximumContributionAmount = 2 ether;

    // @notice accumulative => contribution total
    mapping(address => uint256) public contribution;

    // @notice global accumulative contribution amount
    uint256 public totalContributions;

    // @notice max number of paid contributions to the genesis sale
    uint256 public constant maxGenesisContributionTokens = 460;

    uint256 public totalAdminMints;

    constructor(
        DigitalaxAccessControls _accessControls,
        address payable _fundsMultisig,
        uint256 _genesisStartTimestamp,
        uint256 _genesisEndTimestamp,
        string memory _tokenURI
    ) public {
        accessControls = _accessControls;
        fundsMultisig = _fundsMultisig;
        genesisStartTimestamp = _genesisStartTimestamp;
        genesisEndTimestamp = _genesisEndTimestamp;
        tokenURI_ = _tokenURI;
        emit DigitalaxGenesisNFTContractDeployed();
    }

    /**
     * @dev Proxy method for facilitating a single point of entry to either buy or contribute additional value to the Genesis sale
     * @dev Cannot contribute less than minimumContributionAmount
     * @dev Cannot contribute accumulative more than than maximumContributionAmount
     */
    function buyOrIncreaseContribution() external payable {
        if (contribution[_msgSender()] == 0) {
            buy();
        } else {
            increaseContribution();
        }
    }

    /**
     * @dev Facilitating the initial purchase of a Genesis NFT
     * @dev Cannot contribute less than minimumContributionAmount
     * @dev Cannot contribute accumulative more than than maximumContributionAmount
     * @dev Reverts if already owns an genesis token
     * @dev Buyer receives a NFT on success
     * @dev All funds move to fundsMultisig
     */
    function buy() public payable {
        require(contribution[_msgSender()] == 0, "DigitalaxGenesisNFT.buy: You already own a genesis NFT");
        require(
            _getNow() >= genesisStartTimestamp && _getNow() <= genesisEndTimestamp,
            "DigitalaxGenesisNFT.buy: No genesis are available outside of the genesis window"
        );

        uint256 _contributionAmount = msg.value;
        require(
            _contributionAmount >= minimumContributionAmount,
            "DigitalaxGenesisNFT.buy: Contribution does not meet minimum requirement"
        );

        require(
            _contributionAmount <= maximumContributionAmount,
            "DigitalaxGenesisNFT.buy: You cannot exceed the maximum contribution amount"
        );

        require(remainingGenesisTokens() > 0, "DigitalaxGenesisNFT.buy: Total number of genesis token holders reached");

        contribution[_msgSender()] = _contributionAmount;
        totalContributions = totalContributions.add(_contributionAmount);

        (bool fundsTransferSuccess,) = fundsMultisig.call{value : _contributionAmount}("");
        require(fundsTransferSuccess, "DigitalaxGenesisNFT.buy: Unable to send contribution to funds multisig");

        uint256 tokenId = totalSupply().add(1);
        _safeMint(_msgSender(), tokenId);

        emit GenesisPurchased(_msgSender(), tokenId, _contributionAmount);
    }

    /**
     * @dev Facilitates an owner to increase there contribution
     * @dev Cannot contribute less than minimumContributionAmount
     * @dev Cannot contribute accumulative more than than maximumContributionAmount
     * @dev Reverts if caller does not already owns an genesis token
     * @dev All funds move to fundsMultisig
     */
    function increaseContribution() public payable {
        require(
            _getNow() >= genesisStartTimestamp && _getNow() <= genesisEndTimestamp,
            "DigitalaxGenesisNFT.increaseContribution: No increases are possible outside of the genesis window"
        );

        require(
            contribution[_msgSender()] > 0,
            "DigitalaxGenesisNFT.increaseContribution: You do not own a genesis NFT"
        );

        uint256 _amountToIncrease = msg.value;
        contribution[_msgSender()] = contribution[_msgSender()].add(_amountToIncrease);

        require(
            contribution[_msgSender()] <= maximumContributionAmount,
            "DigitalaxGenesisNFT.increaseContribution: You cannot exceed the maximum contribution amount"
        );

        totalContributions = totalContributions.add(_amountToIncrease);

        (bool fundsTransferSuccess,) = fundsMultisig.call{value : _amountToIncrease}("");
        require(
            fundsTransferSuccess,
            "DigitalaxGenesisNFT.increaseContribution: Unable to send contribution to funds multisig"
        );

        emit ContributionIncreased(_msgSender(), _amountToIncrease);
    }

    // Admin

    /**
     * @dev Allows a whitelisted admin to mint a token and issue it to a beneficiary
     * @dev One token per holder
     * @dev All holders contribution as set o zero on creation
     */
    function adminBuy(address _beneficiary) external {
        require(
            accessControls.hasAdminRole(_msgSender()),
            "DigitalaxGenesisNFT.adminBuy: Sender must be admin"
        );
        require(_beneficiary != address(0), "DigitalaxGenesisNFT.adminBuy: Beneficiary cannot be ZERO");
        require(balanceOf(_beneficiary) == 0, "DigitalaxGenesisNFT.adminBuy: Beneficiary already owns a genesis NFT");

        uint256 tokenId = totalSupply().add(1);
        _safeMint(_beneficiary, tokenId);

        // Increase admin mint counts
        totalAdminMints = totalAdminMints.add(1);

        emit AdminGenesisMinted(_beneficiary, _msgSender(), tokenId);
    }

    /**
     * @dev Allows a whitelisted admin to update the end date of the genesis
     */
    function updateGenesisEnd(uint256 _end) external {
        require(
            accessControls.hasAdminRole(_msgSender()),
            "DigitalaxGenesisNFT.updateGenesisEnd: Sender must be admin"
        );
        // If already passed, dont allow opening again
        require(genesisEndTimestamp > _getNow(), "DigitalaxGenesisNFT.updateGenesisEnd: End time already passed");

        // Only allow setting this once
        require(!genesisEndTimestampLocked, "DigitalaxGenesisNFT.updateGenesisEnd: End time locked");

        genesisEndTimestamp = _end;

        // Lock future end time modifications
        genesisEndTimestampLocked = true;

        emit GenesisEndUpdated(genesisEndTimestamp, _msgSender());
    }

    /**
     * @dev Allows a whitelisted admin to update the start date of the genesis
     */
    function updateAccessControls(DigitalaxAccessControls _accessControls) external {
        require(
            accessControls.hasAdminRole(_msgSender()),
            "DigitalaxGenesisNFT.updateAccessControls: Sender must be admin"
        );
        require(address(_accessControls) != address(0), "DigitalaxGenesisNFT.updateAccessControls: Zero Address");
        accessControls = _accessControls;

        emit AccessControlsUpdated(address(_accessControls));
    }

    /**
    * @dev Returns total remaining number of tokens available in the Genesis sale
    */
    function remainingGenesisTokens() public view returns (uint256) {
        return _getMaxGenesisContributionTokens() - (totalSupply() - totalAdminMints);
    }

    // Internal

    function _getNow() internal virtual view returns (uint256) {
        return block.timestamp;
    }

    function _getMaxGenesisContributionTokens() internal virtual view returns (uint256) {
        return maxGenesisContributionTokens;
    }

    /**
     * @dev Before token transfer hook to enforce that no token can be moved to another address until the genesis sale has ended
     */
    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override {
        if (from != address(0) && _getNow() <= genesisEndTimestamp) {
            revert("DigitalaxGenesisNFT._beforeTokenTransfer: Transfers are currently locked at this time");
        }
    }
}


// File interfaces/IERC20.sol

pragma solidity ^0.6.2;



interface IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);
}


// File interfaces/IDigitalaxRewards.sol



pragma solidity 0.6.12;

/// @dev an interface to interact with the Genesis MONA NFT that will 
interface IDigitalaxRewards {
    function updateRewards() external returns (bool);
    function genesisRewards(uint256 _from, uint256 _to) external view returns(uint256);
    function parentRewards(uint256 _from, uint256 _to) external view returns(uint256);
    function LPRewards(uint256 _from, uint256 _to) external view returns(uint256);
    function lastRewardTime() external view returns (uint256);
}


// File interfaces/IDigitalaxGenesisNFT.sol



pragma solidity 0.6.12;

/// @dev an interface to interact with the Genesis MONA NFT that will 
interface IDigitalaxGenesisNFT {
    function contribution(address user) external view returns (uint256);
    function totalContributions() external view returns (uint256);
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
    function balanceOf(address owner) external view returns (uint256);
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
}


// File contracts/DigitalaxGenesisStaking.sol



pragma solidity 0.6.12;






/**
 * @title Digitalax Staking
 * @dev Stake NFTs, earn tokens on the Digitialax platform
 * @author Adrian Guerrera (deepyr)
 */


contract DigitalaxGenesisStaking {
    using SafeMath for uint256;
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    IERC20 public rewardsToken;
    IDigitalaxGenesisNFT public genesisNFT;
    DigitalaxAccessControls public accessControls;
    IDigitalaxRewards public rewardsContract;

    /// @notice all funds will be sent to this address pon purchase of a Genesis NFT
    address payable public fundsMultisig;

    /// @notice total ethereum staked currently in the gensesis staking contract
    uint256 public stakedEthTotal;
    uint256 public lastUpdateTime;

    uint256 public rewardsPerTokenPoints;
    uint256 public totalUnclaimedRewards;

    uint256 constant pointMultiplier = 10e32;

    /**
    @notice Struct to track what user is staking which tokens
    @dev tokenIds are all the tokens staked by the staker
    @dev balance is the current ether balance of the staker
    @dev rewardsEarned is the total reward for the staker till now
    @dev rewardsReleased is how much reward has been paid to the staker
    */
    struct Staker {
        uint256[] tokenIds;
        mapping (uint256 => uint256) tokenIndex;
        uint256 balance;
        uint256 lastRewardPoints;
        uint256 rewardsEarned;
        uint256 rewardsReleased;
    }

    /// @notice mapping of a staker to its current properties
    mapping (address => Staker) public stakers;

    // Mapping from token ID to owner address
    mapping (uint256 => address) public tokenOwner;

    /// @notice tokenId => amount contributed
    mapping (uint256 => uint256) public contribution;
    uint256 public totalContributions;
    // @notice the maximum accumulative amount a user can contribute to the genesis sale
    uint256 public constant maximumContributionAmount = 2 ether;

    /// @notice sets the token to be claimable or not, cannot claim if it set to false
    bool public tokensClaimable;
    bool initialised;

    /// @notice event emitted when a user has staked a token
    event Staked(address owner, uint256 amount);

    /// @notice event emitted when a user has unstaked a token
    event Unstaked(address owner, uint256 amount);

    /// @notice event emitted when a user claims reward
    event RewardPaid(address indexed user, uint256 reward);
    
    /// @notice Allows reward tokens to be claimed
    event ClaimableStatusUpdated(bool status);

    /// @notice Emergency unstake tokens without rewards
    event EmergencyUnstake(address indexed user, uint256 tokenId);

    // @notice event emitted when a contributors amount is increased
    event ContributionIncreased(
        uint256 indexed tokenId,
        uint256 contribution
    );

    constructor() public {
    }
     /**
     * @dev Single gateway to intialize the staking contract after deploying
     * @dev Sets the contract with the MONA genesis NFT and MONA reward token 
     */
    function initGenesisStaking(
        address payable _fundsMultisig,
        IERC20 _rewardsToken,
        IDigitalaxGenesisNFT _genesisNFT,
        DigitalaxAccessControls _accessControls
    )
        public
    {
        require(!initialised, "Already initialised");
        fundsMultisig = _fundsMultisig;
        rewardsToken = _rewardsToken;
        genesisNFT = _genesisNFT;
        accessControls = _accessControls;
        lastUpdateTime = block.timestamp;
        initialised = true;
    }

    function setRewardsContract(
        address _addr
    )
        external
    {
        require(
            accessControls.hasAdminRole(msg.sender),
            "DigitalaxGenesisStaking.setRewardsContract: Sender must be admin"
        );
        require(_addr != address(0));
        rewardsContract = IDigitalaxRewards(_addr);
    }

    function setTokensClaimable(
        bool _enabled
    )
        external
    {
        require(
            accessControls.hasAdminRole(msg.sender),
            "DigitalaxGenesisStaking.setTokensClaimable: Sender must be admin"
        );
        tokensClaimable = _enabled;
        emit ClaimableStatusUpdated(_enabled);
    }

    /// @dev Getter functions for Staking contract
    /// @dev Get the tokens staked by a user
    function getStakedTokens(
        address _user
    )
        external
        view
        returns (uint256[] memory tokenIds)
    {
        return stakers[_user].tokenIds;
    }


    /// @dev Get the amount a staked nft is valued at ie bought at
    function getGenesisContribution (
        uint256 _tokenId
    ) 
        public
        view
        returns (uint256 amount)
    {
        return contribution[_tokenId];
    }

    /// @notice Stake Genesis MONA NFT and earn reward tokens. 
    function stake(
        uint256 tokenId
    )
        external
    {
        _stake(msg.sender, tokenId);
    }

     /// @notice Stake multiple MONA NFTs and earn reward tokens. 
    function stakeBatch(uint256[] memory tokenIds)
        external
    {
        for (uint i = 0; i < tokenIds.length; i++) {
            _stake(msg.sender, tokenIds[i]);
        }
    }

    /// @notice Stake all your MONA NFTs and earn reward tokens. 
    function stakeAll()
        external
    {
        uint256 balance = genesisNFT.balanceOf(msg.sender);
        for (uint i = 0; i < balance; i++) {
            _stake(msg.sender, genesisNFT.tokenOfOwnerByIndex(msg.sender,i));
        }
    }


    /**
     * @dev All the staking goes through this function
     * @dev Rewards to be given out is calculated
     * @dev Balance of stakers are updated as they stake the nfts based on ether price
    */
    function _stake(
        address _user,
        uint256 _tokenId
    )
        internal
    {
        Staker storage staker = stakers[_user];

        if (staker.balance == 0 && staker.lastRewardPoints == 0 ) {
          staker.lastRewardPoints = rewardsPerTokenPoints;
        }

        updateReward(_user);
        uint256 amount = getGenesisContribution(_tokenId);
        staker.balance = staker.balance.add(amount);
        stakedEthTotal = stakedEthTotal.add(amount);
        staker.tokenIds.push(_tokenId);
        staker.tokenIndex[staker.tokenIds.length - 1];
        tokenOwner[_tokenId] = _user;
        genesisNFT.safeTransferFrom(
            _user,
            address(this),
            _tokenId
        );

        emit Staked(_user, _tokenId);
    }

    /// @notice Unstake Genesis MONA NFTs. 
    function unstake(
        uint256 _tokenId
    ) 
        external 
    {
        require(
            tokenOwner[_tokenId] == msg.sender,
            "DigitalaxGenesisStaking._unstake: Sender must have staked tokenID"
        );
        claimReward(msg.sender);
        _unstake(msg.sender, _tokenId);
    }

    /// @notice Stake multiple Genesis NFTs and claim reward tokens. 
    function unstakeBatch(
        uint256[] memory tokenIds
    )
        external
    {
        claimReward(msg.sender);
        for (uint i = 0; i < tokenIds.length; i++) {
            if (tokenOwner[i] == msg.sender) {
                _unstake(msg.sender, tokenIds[i]);
            }
        }
    }


     /**
     * @dev All the unstaking goes through this function
     * @dev Rewards to be given out is calculated
     * @dev Balance of stakers are updated as they unstake the nfts based on ether price
    */
    function _unstake(
        address _user,
        uint256 _tokenId
    ) 
        internal 
    {

        Staker storage staker = stakers[_user];

        uint256 amount = getGenesisContribution(_tokenId);
        staker.balance = staker.balance.sub(amount);
        stakedEthTotal = stakedEthTotal.sub(amount);

        uint256 lastIndex = staker.tokenIds.length - 1;
        uint256 lastIndexKey = staker.tokenIds[lastIndex];
        staker.tokenIds[staker.tokenIndex[_tokenId]] = lastIndexKey;
        if (staker.tokenIds.length > 0) {
            staker.tokenIds.pop();
            delete staker.tokenIndex[_tokenId];
        }

        if (staker.balance == 0) {
            delete stakers[_user];
        }
        delete tokenOwner[_tokenId];

        genesisNFT.safeTransferFrom(
            address(this),
            _user,
            _tokenId
        );

        emit Unstaked(_user, _tokenId);

    }

    // Unstake without caring about rewards. EMERGENCY ONLY.
    function emergencyUnstake(uint256 _tokenId) external {
        require(
            tokenOwner[_tokenId] == msg.sender,
            "DigitalaxGenesisStaking._unstake: Sender must have staked tokenID"
        );
        _unstake(msg.sender, _tokenId);
        emit EmergencyUnstake(msg.sender, _tokenId);

    }


    /// @dev Updates the amount of rewards owed for each user before any tokens are moved
    function updateReward(
        address _user
    ) 
        public 
    {
        rewardsContract.updateRewards();
        uint256 genesisRewards = rewardsContract.genesisRewards(lastUpdateTime, block.timestamp);

        if (stakedEthTotal > 0) {
            rewardsPerTokenPoints = rewardsPerTokenPoints.add(genesisRewards
                                            .mul(1e18)
                                            .mul(pointMultiplier)
                                            .div(stakedEthTotal));
        }
        
        lastUpdateTime = block.timestamp;
        uint256 rewards = rewardsOwing(_user);

        Staker storage staker = stakers[_user];
        if (_user != address(0)) {
            staker.rewardsEarned = staker.rewardsEarned.add(rewards);
            staker.lastRewardPoints = rewardsPerTokenPoints; 
        }
    }


    /// @notice Returns the rewards owing for a user
    /// @dev The rewards are dynamic and normalised from the other pools
    /// @dev This gets the rewards from each of the periods as one multiplier
    function rewardsOwing(
        address _user
    )
        public
        view
        returns(uint256)
    {
        uint256 newRewardPerToken = rewardsPerTokenPoints.sub(stakers[_user].lastRewardPoints);
        uint256 rewards = stakers[_user].balance.mul(newRewardPerToken)
                                                .div(1e18)
                                                .div(pointMultiplier);
        return rewards;
    }



    /// @notice Lets a user with rewards owing to claim tokens
    function claimReward(
        address _user
    )
        public
    {
        require(
            tokensClaimable == true,
            "Tokens cannnot be claimed yet"
        );
        updateReward(_user);

        Staker storage staker = stakers[_user];
    
        uint256 payableAmount = staker.rewardsEarned.sub(staker.rewardsReleased);
        staker.rewardsReleased = staker.rewardsReleased.add(payableAmount);

        rewardsToken.transfer(_user, payableAmount);
        emit RewardPaid(_user, payableAmount);
    }


    /// @notice Returns the about of rewards yet to be claimed
    function unclaimedRewards(
        address _user
    )
        external
        view
        returns(uint256)
    {
        if (stakedEthTotal == 0) {
            return 0;
        }

        uint256 genesisRewards = rewardsContract.genesisRewards(lastUpdateTime,
                                                        block.timestamp);

        uint256 newRewardPerToken = rewardsPerTokenPoints.add(genesisRewards
                                                                .mul(1e18)
                                                                .mul(pointMultiplier)
                                                                .div(stakedEthTotal))
                                                         .sub(stakers[_user].lastRewardPoints);
                                                         
        uint256 rewards = stakers[_user].balance.mul(newRewardPerToken)
                                                .div(1e18)
                                                .div(pointMultiplier);
        return rewards.add(stakers[_user].rewardsEarned).sub(stakers[_user].rewardsReleased);
    }

    // Set contribution amounts for NFTs
    ///@dev So the genesis contracts did not have any way to check how much was contributed
    ///@dev So instead we put in the amounts using this function
    function setContributions(
        uint256[] memory tokens,
        uint256[] memory amounts
    )
        external
    {
        require(
            accessControls.hasAdminRole(msg.sender),
            "DigitalaxGenesisStaking.setContributions: Sender must be admin"
        );
        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 token = tokens[i];
            uint256 amount = amounts[i];
            contribution[token] = amount;
            totalContributions = totalContributions.add(amount);

        }
    }

    /**
     * @notice Facilitates an owner to increase there contribution
     * @dev Cannot contribute less than minimumContributionAmount
     * @dev Cannot contribute accumulative more than than maximumContributionAmount
     * @dev Reverts if caller does not already owns an genesis token
     * @dev All funds move to fundsMultisig
     */
    function increaseContribution(uint256 _tokenId)
        external
        payable
    {
        updateReward(tokenOwner[_tokenId]);
        require(
            contribution[_tokenId] > 0,
            "DigitalaxGenesisStaking.increaseContribution: genesis NFT was not contribibuted"
        );

        uint256 _amountToIncrease = msg.value;
        contribution[_tokenId] = contribution[_tokenId].add(_amountToIncrease);

        require(
            contribution[_tokenId] <= maximumContributionAmount,
            "DigitalaxGenesisStaking.increaseContribution: You cannot exceed the maximum contribution amount"
        );

        totalContributions = totalContributions.add(_amountToIncrease);

        (bool fundsTransferSuccess,) = fundsMultisig.call{value : _amountToIncrease}("");
        require(
            fundsTransferSuccess,
            "DigitalaxGenesisStaking.increaseContribution: Unable to send contribution to funds multisig"
        );
        
        Staker storage staker = stakers[tokenOwner[_tokenId]];
        /// @dev Update staked balance
        if (staker.tokenIds[staker.tokenIndex[_tokenId]] == _tokenId ) {
            staker.balance = staker.balance.add(_amountToIncrease);
            stakedEthTotal = stakedEthTotal.add(_amountToIncrease);
        }
        emit ContributionIncreased(_tokenId, _amountToIncrease);
    }


    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata data
    )
        public returns(bytes4)
    {
        return _ERC721_RECEIVED;
    }



}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"ClaimableStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"contribution","type":"uint256"}],"name":"ContributionIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"EmergencyUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"accessControls","outputs":[{"internalType":"contract DigitalaxAccessControls","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"contribution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"emergencyUnstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundsMultisig","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"genesisNFT","outputs":[{"internalType":"contract IDigitalaxGenesisNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getGenesisContribution","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getStakedTokens","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"increaseContribution","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_fundsMultisig","type":"address"},{"internalType":"contract IERC20","name":"_rewardsToken","type":"address"},{"internalType":"contract IDigitalaxGenesisNFT","name":"_genesisNFT","type":"address"},{"internalType":"contract DigitalaxAccessControls","name":"_accessControls","type":"address"}],"name":"initGenesisStaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumContributionAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsContract","outputs":[{"internalType":"contract IDigitalaxRewards","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"rewardsOwing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerTokenPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokens","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"setContributions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"name":"setRewardsContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setTokensClaimable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"stakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedEthTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakers","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"lastRewardPoints","type":"uint256"},{"internalType":"uint256","name":"rewardsEarned","type":"uint256"},{"internalType":"uint256","name":"rewardsReleased","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensClaimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalContributions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnclaimedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"unclaimedRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unstakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"updateReward","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50612135806100206000396000f3fe6080604052600436106101ee5760003560e01c8063748365ef1161010d578063aadee22d116100a0578063dbeb61c71161006f578063dbeb61c7146108c2578063dfa0dfa5146108d7578063e3ca00861461090a578063e64a21f31461091f578063e8709c40146109cd576101ee565b8063aadee22d14610850578063c8f33c9114610865578063d1af0c7d1461087a578063d279c1911461088f576101ee565b8063949813b8116100dc578063949813b81461069057806397d5ede5146106c3578063a2010956146106f6578063a694fc3a14610826576101ee565b8063748365ef146105f85780638dcb40611461060d5780638dd4916b146106225780639168ae7214610637576101ee565b80632e17de7811610185578063542360fd11610154578063542360fd14610501578063632447c91461052d57806363c28db11461056057806369f066a3146105e3576101ee565b80632e17de781461046f57806331f684c01461049957806337c08923146104c2578063494f67c2146104d7576101ee565b8063220cce97116101c1578063220cce9714610344578063230f436d146103595780632af59b9e146104075780632cb4836c14610424576101ee565b8063012ce501146101f35780630dc85f541461021f578063150b7a02146102465780631caaa487146102fe575b600080fd5b3480156101ff57600080fd5b5061021d6004803603602081101561021657600080fd5b50356109f7565b005b34801561022b57600080fd5b50610234610a8f565b60408051918252519081900360200190f35b34801561025257600080fd5b506102e16004803603608081101561026957600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460018302840111600160201b831117156102d657600080fd5b509092509050610a9b565b604080516001600160e01b03199092168252519081900360200190f35b34801561030a57600080fd5b506103286004803603602081101561032157600080fd5b5035610aac565b604080516001600160a01b039092168252519081900360200190f35b34801561035057600080fd5b50610328610ac7565b34801561036557600080fd5b5061021d6004803603602081101561037c57600080fd5b810190602081018135600160201b81111561039657600080fd5b8201836020820111156103a857600080fd5b803590602001918460208302840111600160201b831117156103c957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610ad6945050505050565b61021d6004803603602081101561041d57600080fd5b5035610b0b565b34801561043057600080fd5b5061021d6004803603608081101561044757600080fd5b506001600160a01b038135811691602081013582169160408201358116916060013516610d3c565b34801561047b57600080fd5b5061021d6004803603602081101561049257600080fd5b5035610df2565b3480156104a557600080fd5b506104ae610e5d565b604080519115158252519081900360200190f35b3480156104ce57600080fd5b50610234610e66565b3480156104e357600080fd5b50610234600480360360208110156104fa57600080fd5b5035610e6c565b34801561050d57600080fd5b5061021d6004803603602081101561052457600080fd5b50351515610e81565b34801561053957600080fd5b5061021d6004803603602081101561055057600080fd5b50356001600160a01b0316610f7a565b34801561056c57600080fd5b506105936004803603602081101561058357600080fd5b50356001600160a01b031661111c565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105cf5781810151838201526020016105b7565b505050509050019250505060405180910390f35b3480156105ef57600080fd5b50610234611188565b34801561060457600080fd5b5061032861118e565b34801561061957600080fd5b5061021d61119d565b34801561062e57600080fd5b506103286112af565b34801561064357600080fd5b5061066a6004803603602081101561065a57600080fd5b50356001600160a01b03166112be565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561069c57600080fd5b50610234600480360360208110156106b357600080fd5b50356001600160a01b03166112e8565b3480156106cf57600080fd5b50610234600480360360208110156106e657600080fd5b50356001600160a01b0316611461565b34801561070257600080fd5b5061021d6004803603604081101561071957600080fd5b810190602081018135600160201b81111561073357600080fd5b82018360208201111561074557600080fd5b803590602001918460208302840111600160201b8311171561076657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156107b557600080fd5b8201836020820111156107c757600080fd5b803590602001918460208302840111600160201b831117156107e857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506114de945050505050565b34801561083257600080fd5b5061021d6004803603602081101561084957600080fd5b503561160b565b34801561085c57600080fd5b50610234611615565b34801561087157600080fd5b5061023461161b565b34801561088657600080fd5b50610328611621565b34801561089b57600080fd5b5061021d600480360360208110156108b257600080fd5b50356001600160a01b0316611630565b3480156108ce57600080fd5b506103286117a3565b3480156108e357600080fd5b5061021d600480360360208110156108fa57600080fd5b50356001600160a01b03166117b2565b34801561091657600080fd5b50610234611899565b34801561092b57600080fd5b5061021d6004803603602081101561094257600080fd5b810190602081018135600160201b81111561095c57600080fd5b82018360208201111561096e57600080fd5b803590602001918460208302840111600160201b8311171561098f57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061189f945050505050565b3480156109d957600080fd5b50610234600480360360208110156109f057600080fd5b50356118f8565b6000818152600a60205260409020546001600160a01b03163314610a4c5760405162461bcd60e51b81526004018080602001828103825260418152602001806120816041913960600191505060405180910390fd5b610a56338261190a565b60408051828152905133917f571394674ec9d9e81517060110f8f894ce912af2b2febc091bee0cdea68adf00919081900360200190a250565b671bc16d674ec8000081565b630a85bd0160e11b95945050505050565b600a602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60005b8151811015610b0757610aff33838381518110610af257fe5b6020026020010151611b04565b600101610ad9565b5050565b6000818152600a6020526040902054610b2c906001600160a01b0316610f7a565b6000818152600b6020526040902054610b765760405162461bcd60e51b815260040180806020018281038252604f815260200180612032604f913960600191505060405180910390fd5b6000818152600b60205260409020543490610b919082611c68565b6000838152600b60205260409020819055671bc16d674ec800001015610be85760405162461bcd60e51b815260040180806020018281038252605f815260200180611fb2605f913960600191505060405180910390fd5b600c54610bf59082611c68565b600c556004546040516000916001600160a01b03169083908381818185875af1925050503d8060008114610c45576040519150601f19603f3d011682016040523d82523d6000602084013e610c4a565b606091505b5050905080610c8a5760405162461bcd60e51b815260040180806020018281038252605b815260200180611ed7605b913960600191505060405180910390fd5b6000838152600a60209081526040808320546001600160a01b031683526009825280832086845260018101909252909120548154859183918110610cca57fe5b90600052602060002001541415610d00576002810154610cea9084611c68565b6002820155600554610cfc9084611c68565b6005555b60408051848152905185917f80f327f9c1db6dfe75b98bc5424a9e88b2713c0de0c0553394d0158feaa5080b919081900360200190a250505050565b600d54610100900460ff1615610d8f576040805162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5cd959606a1b604482015290519081900360640190fd5b600480546001600160a01b039586166001600160a01b031991821617909155600080549486169482169490941790935560018054928516928416929092179091556002805491909316911617905542600655600d805461ff001916610100179055565b6000818152600a60205260409020546001600160a01b03163314610e475760405162461bcd60e51b81526004018080602001828103825260418152602001806120816041913960600191505060405180910390fd5b610e5033611630565b610e5a338261190a565b50565b600d5460ff1681565b600c5481565b6000818152600b60205260409020545b919050565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b158015610ecc57600080fd5b505afa158015610ee0573d6000803e3d6000fd5b505050506040513d6020811015610ef657600080fd5b5051610f335760405162461bcd60e51b8152600401808060200182810382526040815260200180611f326040913960400191505060405180910390fd5b600d805482151560ff19909116811790915560408051918252517f4a113b1b56ac87c884bce0b1715ef967c43f546e247aa746d79d92335fe9f8259181900360200190a150565b600360009054906101000a90046001600160a01b03166001600160a01b0316633e158b0c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610fca57600080fd5b505af1158015610fde573d6000803e3d6000fd5b505050506040513d6020811015610ff457600080fd5b505060035460065460408051633bc22b5d60e11b81526004810192909252426024830152516000926001600160a01b03169163778456ba916044808301926020929190829003018186803b15801561104b57600080fd5b505afa15801561105f573d6000803e3d6000fd5b505050506040513d602081101561107557600080fd5b5051600554909150156110ca576005546110c6906110bd906110b76d314dc6448d9338c15b0a000000006110b186670de0b6b3a7640000611ccb565b90611ccb565b90611d24565b60075490611c68565b6007555b4260065560006110d983611461565b6001600160a01b0384166000818152600960205260409020919250156111165760048101546111089083611c68565b600482015560075460038201555b50505050565b6001600160a01b03811660009081526009602090815260409182902080548351818402810184019094528084526060939283018282801561117c57602002820191906000526020600020905b815481526020019060010190808311611168575b50505050509050919050565b60085481565b6002546001600160a01b031681565b600154604080516370a0823160e01b815233600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156111e857600080fd5b505afa1580156111fc573d6000803e3d6000fd5b505050506040513d602081101561121257600080fd5b5051905060005b81811015610b075760015460408051632f745c5960e01b815233600482018190526024820185905291516112a7936001600160a01b031691632f745c59916044808301926020929190829003018186803b15801561127657600080fd5b505afa15801561128a573d6000803e3d6000fd5b505050506040513d60208110156112a057600080fd5b5051611b04565b600101611219565b6001546001600160a01b031681565b60096020526000908152604090206002810154600382015460048301546005909301549192909184565b6000600554600014156112fd57506000610e7c565b60035460065460408051633bc22b5d60e11b81526004810192909252426024830152516000926001600160a01b03169163778456ba916044808301926020929190829003018186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d602081101561137c57600080fd5b50516001600160a01b03841660009081526009602052604081206003015460055492935090916113d991906113d3906110bd906110b76d314dc6448d9338c15b0a000000006110b189670de0b6b3a7640000611ccb565b90611d66565b6001600160a01b03851660009081526009602052604081206002015491925090611423906d314dc6448d9338c15b0a00000000906110b790670de0b6b3a764000090829087611ccb565b6001600160a01b03861660009081526009602052604090206005810154600490910154919250611458916113d3908490611c68565b95945050505050565b6001600160a01b038116600090815260096020526040812060030154600754829161148c9190611d66565b6001600160a01b038416600090815260096020526040812060020154919250906114d6906d314dc6448d9338c15b0a00000000906110b790670de0b6b3a764000090829087611ccb565b949350505050565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b15801561152957600080fd5b505afa15801561153d573d6000803e3d6000fd5b505050506040513d602081101561155357600080fd5b50516115905760405162461bcd60e51b815260040180806020018281038252603e8152602001806120c2603e913960400191505060405180910390fd5b60005b82518110156116065760008382815181106115aa57fe5b6020026020010151905060008383815181106115c257fe5b6020026020010151905080600b6000848152602001908152602001600020819055506115f981600c54611c6890919063ffffffff16565b600c555050600101611593565b505050565b610e5a3382611b04565b60055481565b60065481565b6000546001600160a01b031681565b600d5460ff16151560011461168c576040805162461bcd60e51b815260206004820152601d60248201527f546f6b656e732063616e6e6e6f7420626520636c61696d656420796574000000604482015290519081900360640190fd5b61169581610f7a565b6001600160a01b0381166000908152600960205260408120600581015460048201549192916116c391611d66565b60058301549091506116d59082611c68565b6005830155600080546040805163a9059cbb60e01b81526001600160a01b038781166004830152602482018690529151919092169263a9059cbb92604480820193602093909283900390910190829087803b15801561173357600080fd5b505af1158015611747573d6000803e3d6000fd5b505050506040513d602081101561175d57600080fd5b50506040805182815290516001600160a01b038516917fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486919081900360200190a2505050565b6004546001600160a01b031681565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b1580156117fd57600080fd5b505afa158015611811573d6000803e3d6000fd5b505050506040513d602081101561182757600080fd5b50516118645760405162461bcd60e51b8152600401808060200182810382526040815260200180611f726040913960400191505060405180910390fd5b6001600160a01b03811661187757600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60075481565b6118a833611630565b60005b8151811015610b07576000818152600a60205260409020546001600160a01b03163314156118f0576118f0338383815181106118e357fe5b602002602001015161190a565b6001016118ab565b600b6020526000908152604090205481565b6001600160a01b03821660009081526009602052604081209061192c83610e6c565b600283015490915061193e9082611d66565b60028301556005546119509082611d66565b600555815460001981019060009084908390811061196a57fe5b906000526020600020015490508084600001856001016000888152602001908152602001600020548154811061199c57fe5b6000918252602090912001558354156119e45783548490806119ba57fe5b60008281526020808220830160001990810183905590920190925586825260018601905260408120555b6002840154611a2f576001600160a01b038616600090815260096020526040812090611a108282611ea4565b5060006002820181905560038201819055600482018190556005909101555b6000858152600a602052604080822080546001600160a01b03191690556001548151632142170760e11b81523060048201526001600160a01b038a81166024830152604482018a9052925192909116926342842e0e9260648084019382900301818387803b158015611aa057600080fd5b505af1158015611ab4573d6000803e3d6000fd5b5050604080516001600160a01b038a1681526020810189905281517f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759450908190039091019150a1505050505050565b6001600160a01b03821660009081526009602052604090206002810154158015611b3057506003810154155b15611b3e5760075460038201555b611b4783610f7a565b6000611b5283610e6c565b6002830154909150611b649082611c68565b6002830155600554611b769082611c68565b60055581546001808201845560008481526020808220909301869055858152600a909252604080832080546001600160a01b0319166001600160a01b0389811691821790925592548251632142170760e11b815260048101949094523060248501526044840188905291519116926342842e0e926064808201939182900301818387803b158015611c0657600080fd5b505af1158015611c1a573d6000803e3d6000fd5b5050604080516001600160a01b03881681526020810187905281517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9450908190039091019150a150505050565b600082820183811015611cc2576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600082611cda57506000611cc5565b82820282848281611ce757fe5b0414611cc25760405162461bcd60e51b81526004018080602001828103825260218152602001806120116021913960400191505060405180910390fd5b6000611cc283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611da8565b6000611cc283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e4a565b60008183611e345760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611df9578181015183820152602001611de1565b50505050905090810190601f168015611e265780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611e4057fe5b0495945050505050565b60008184841115611e9c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611df9578181015183820152602001611de1565b505050900390565b5080546000825590600052602060002090810190610e5a91905b80821115611ed25760008155600101611ebe565b509056fe4469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a20556e61626c6520746f2073656e6420636f6e747269627574696f6e20746f2066756e6473206d756c74697369674469676974616c617847656e657369735374616b696e672e736574546f6b656e73436c61696d61626c653a2053656e646572206d7573742062652061646d696e4469676974616c617847656e657369735374616b696e672e73657452657761726473436f6e74726163743a2053656e646572206d7573742062652061646d696e4469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a20596f752063616e6e6f742065786365656420746865206d6178696d756d20636f6e747269627574696f6e20616d6f756e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a2067656e65736973204e465420776173206e6f7420636f6e747269626962757465644469676974616c617847656e657369735374616b696e672e5f756e7374616b653a2053656e646572206d7573742068617665207374616b656420746f6b656e49444469676974616c617847656e657369735374616b696e672e736574436f6e747269627574696f6e733a2053656e646572206d7573742062652061646d696ea26469706673582212209e8bbf28c4312267905dbe2456074b732ffb7fd8dd6388e9e90aec6062c6699864736f6c634300060c0033

Deployed Bytecode

0x6080604052600436106101ee5760003560e01c8063748365ef1161010d578063aadee22d116100a0578063dbeb61c71161006f578063dbeb61c7146108c2578063dfa0dfa5146108d7578063e3ca00861461090a578063e64a21f31461091f578063e8709c40146109cd576101ee565b8063aadee22d14610850578063c8f33c9114610865578063d1af0c7d1461087a578063d279c1911461088f576101ee565b8063949813b8116100dc578063949813b81461069057806397d5ede5146106c3578063a2010956146106f6578063a694fc3a14610826576101ee565b8063748365ef146105f85780638dcb40611461060d5780638dd4916b146106225780639168ae7214610637576101ee565b80632e17de7811610185578063542360fd11610154578063542360fd14610501578063632447c91461052d57806363c28db11461056057806369f066a3146105e3576101ee565b80632e17de781461046f57806331f684c01461049957806337c08923146104c2578063494f67c2146104d7576101ee565b8063220cce97116101c1578063220cce9714610344578063230f436d146103595780632af59b9e146104075780632cb4836c14610424576101ee565b8063012ce501146101f35780630dc85f541461021f578063150b7a02146102465780631caaa487146102fe575b600080fd5b3480156101ff57600080fd5b5061021d6004803603602081101561021657600080fd5b50356109f7565b005b34801561022b57600080fd5b50610234610a8f565b60408051918252519081900360200190f35b34801561025257600080fd5b506102e16004803603608081101561026957600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b8111156102a357600080fd5b8201836020820111156102b557600080fd5b803590602001918460018302840111600160201b831117156102d657600080fd5b509092509050610a9b565b604080516001600160e01b03199092168252519081900360200190f35b34801561030a57600080fd5b506103286004803603602081101561032157600080fd5b5035610aac565b604080516001600160a01b039092168252519081900360200190f35b34801561035057600080fd5b50610328610ac7565b34801561036557600080fd5b5061021d6004803603602081101561037c57600080fd5b810190602081018135600160201b81111561039657600080fd5b8201836020820111156103a857600080fd5b803590602001918460208302840111600160201b831117156103c957600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550610ad6945050505050565b61021d6004803603602081101561041d57600080fd5b5035610b0b565b34801561043057600080fd5b5061021d6004803603608081101561044757600080fd5b506001600160a01b038135811691602081013582169160408201358116916060013516610d3c565b34801561047b57600080fd5b5061021d6004803603602081101561049257600080fd5b5035610df2565b3480156104a557600080fd5b506104ae610e5d565b604080519115158252519081900360200190f35b3480156104ce57600080fd5b50610234610e66565b3480156104e357600080fd5b50610234600480360360208110156104fa57600080fd5b5035610e6c565b34801561050d57600080fd5b5061021d6004803603602081101561052457600080fd5b50351515610e81565b34801561053957600080fd5b5061021d6004803603602081101561055057600080fd5b50356001600160a01b0316610f7a565b34801561056c57600080fd5b506105936004803603602081101561058357600080fd5b50356001600160a01b031661111c565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156105cf5781810151838201526020016105b7565b505050509050019250505060405180910390f35b3480156105ef57600080fd5b50610234611188565b34801561060457600080fd5b5061032861118e565b34801561061957600080fd5b5061021d61119d565b34801561062e57600080fd5b506103286112af565b34801561064357600080fd5b5061066a6004803603602081101561065a57600080fd5b50356001600160a01b03166112be565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561069c57600080fd5b50610234600480360360208110156106b357600080fd5b50356001600160a01b03166112e8565b3480156106cf57600080fd5b50610234600480360360208110156106e657600080fd5b50356001600160a01b0316611461565b34801561070257600080fd5b5061021d6004803603604081101561071957600080fd5b810190602081018135600160201b81111561073357600080fd5b82018360208201111561074557600080fd5b803590602001918460208302840111600160201b8311171561076657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b8111156107b557600080fd5b8201836020820111156107c757600080fd5b803590602001918460208302840111600160201b831117156107e857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506114de945050505050565b34801561083257600080fd5b5061021d6004803603602081101561084957600080fd5b503561160b565b34801561085c57600080fd5b50610234611615565b34801561087157600080fd5b5061023461161b565b34801561088657600080fd5b50610328611621565b34801561089b57600080fd5b5061021d600480360360208110156108b257600080fd5b50356001600160a01b0316611630565b3480156108ce57600080fd5b506103286117a3565b3480156108e357600080fd5b5061021d600480360360208110156108fa57600080fd5b50356001600160a01b03166117b2565b34801561091657600080fd5b50610234611899565b34801561092b57600080fd5b5061021d6004803603602081101561094257600080fd5b810190602081018135600160201b81111561095c57600080fd5b82018360208201111561096e57600080fd5b803590602001918460208302840111600160201b8311171561098f57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061189f945050505050565b3480156109d957600080fd5b50610234600480360360208110156109f057600080fd5b50356118f8565b6000818152600a60205260409020546001600160a01b03163314610a4c5760405162461bcd60e51b81526004018080602001828103825260418152602001806120816041913960600191505060405180910390fd5b610a56338261190a565b60408051828152905133917f571394674ec9d9e81517060110f8f894ce912af2b2febc091bee0cdea68adf00919081900360200190a250565b671bc16d674ec8000081565b630a85bd0160e11b95945050505050565b600a602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60005b8151811015610b0757610aff33838381518110610af257fe5b6020026020010151611b04565b600101610ad9565b5050565b6000818152600a6020526040902054610b2c906001600160a01b0316610f7a565b6000818152600b6020526040902054610b765760405162461bcd60e51b815260040180806020018281038252604f815260200180612032604f913960600191505060405180910390fd5b6000818152600b60205260409020543490610b919082611c68565b6000838152600b60205260409020819055671bc16d674ec800001015610be85760405162461bcd60e51b815260040180806020018281038252605f815260200180611fb2605f913960600191505060405180910390fd5b600c54610bf59082611c68565b600c556004546040516000916001600160a01b03169083908381818185875af1925050503d8060008114610c45576040519150601f19603f3d011682016040523d82523d6000602084013e610c4a565b606091505b5050905080610c8a5760405162461bcd60e51b815260040180806020018281038252605b815260200180611ed7605b913960600191505060405180910390fd5b6000838152600a60209081526040808320546001600160a01b031683526009825280832086845260018101909252909120548154859183918110610cca57fe5b90600052602060002001541415610d00576002810154610cea9084611c68565b6002820155600554610cfc9084611c68565b6005555b60408051848152905185917f80f327f9c1db6dfe75b98bc5424a9e88b2713c0de0c0553394d0158feaa5080b919081900360200190a250505050565b600d54610100900460ff1615610d8f576040805162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5cd959606a1b604482015290519081900360640190fd5b600480546001600160a01b039586166001600160a01b031991821617909155600080549486169482169490941790935560018054928516928416929092179091556002805491909316911617905542600655600d805461ff001916610100179055565b6000818152600a60205260409020546001600160a01b03163314610e475760405162461bcd60e51b81526004018080602001828103825260418152602001806120816041913960600191505060405180910390fd5b610e5033611630565b610e5a338261190a565b50565b600d5460ff1681565b600c5481565b6000818152600b60205260409020545b919050565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b158015610ecc57600080fd5b505afa158015610ee0573d6000803e3d6000fd5b505050506040513d6020811015610ef657600080fd5b5051610f335760405162461bcd60e51b8152600401808060200182810382526040815260200180611f326040913960400191505060405180910390fd5b600d805482151560ff19909116811790915560408051918252517f4a113b1b56ac87c884bce0b1715ef967c43f546e247aa746d79d92335fe9f8259181900360200190a150565b600360009054906101000a90046001600160a01b03166001600160a01b0316633e158b0c6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610fca57600080fd5b505af1158015610fde573d6000803e3d6000fd5b505050506040513d6020811015610ff457600080fd5b505060035460065460408051633bc22b5d60e11b81526004810192909252426024830152516000926001600160a01b03169163778456ba916044808301926020929190829003018186803b15801561104b57600080fd5b505afa15801561105f573d6000803e3d6000fd5b505050506040513d602081101561107557600080fd5b5051600554909150156110ca576005546110c6906110bd906110b76d314dc6448d9338c15b0a000000006110b186670de0b6b3a7640000611ccb565b90611ccb565b90611d24565b60075490611c68565b6007555b4260065560006110d983611461565b6001600160a01b0384166000818152600960205260409020919250156111165760048101546111089083611c68565b600482015560075460038201555b50505050565b6001600160a01b03811660009081526009602090815260409182902080548351818402810184019094528084526060939283018282801561117c57602002820191906000526020600020905b815481526020019060010190808311611168575b50505050509050919050565b60085481565b6002546001600160a01b031681565b600154604080516370a0823160e01b815233600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b1580156111e857600080fd5b505afa1580156111fc573d6000803e3d6000fd5b505050506040513d602081101561121257600080fd5b5051905060005b81811015610b075760015460408051632f745c5960e01b815233600482018190526024820185905291516112a7936001600160a01b031691632f745c59916044808301926020929190829003018186803b15801561127657600080fd5b505afa15801561128a573d6000803e3d6000fd5b505050506040513d60208110156112a057600080fd5b5051611b04565b600101611219565b6001546001600160a01b031681565b60096020526000908152604090206002810154600382015460048301546005909301549192909184565b6000600554600014156112fd57506000610e7c565b60035460065460408051633bc22b5d60e11b81526004810192909252426024830152516000926001600160a01b03169163778456ba916044808301926020929190829003018186803b15801561135257600080fd5b505afa158015611366573d6000803e3d6000fd5b505050506040513d602081101561137c57600080fd5b50516001600160a01b03841660009081526009602052604081206003015460055492935090916113d991906113d3906110bd906110b76d314dc6448d9338c15b0a000000006110b189670de0b6b3a7640000611ccb565b90611d66565b6001600160a01b03851660009081526009602052604081206002015491925090611423906d314dc6448d9338c15b0a00000000906110b790670de0b6b3a764000090829087611ccb565b6001600160a01b03861660009081526009602052604090206005810154600490910154919250611458916113d3908490611c68565b95945050505050565b6001600160a01b038116600090815260096020526040812060030154600754829161148c9190611d66565b6001600160a01b038416600090815260096020526040812060020154919250906114d6906d314dc6448d9338c15b0a00000000906110b790670de0b6b3a764000090829087611ccb565b949350505050565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b15801561152957600080fd5b505afa15801561153d573d6000803e3d6000fd5b505050506040513d602081101561155357600080fd5b50516115905760405162461bcd60e51b815260040180806020018281038252603e8152602001806120c2603e913960400191505060405180910390fd5b60005b82518110156116065760008382815181106115aa57fe5b6020026020010151905060008383815181106115c257fe5b6020026020010151905080600b6000848152602001908152602001600020819055506115f981600c54611c6890919063ffffffff16565b600c555050600101611593565b505050565b610e5a3382611b04565b60055481565b60065481565b6000546001600160a01b031681565b600d5460ff16151560011461168c576040805162461bcd60e51b815260206004820152601d60248201527f546f6b656e732063616e6e6e6f7420626520636c61696d656420796574000000604482015290519081900360640190fd5b61169581610f7a565b6001600160a01b0381166000908152600960205260408120600581015460048201549192916116c391611d66565b60058301549091506116d59082611c68565b6005830155600080546040805163a9059cbb60e01b81526001600160a01b038781166004830152602482018690529151919092169263a9059cbb92604480820193602093909283900390910190829087803b15801561173357600080fd5b505af1158015611747573d6000803e3d6000fd5b505050506040513d602081101561175d57600080fd5b50506040805182815290516001600160a01b038516917fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486919081900360200190a2505050565b6004546001600160a01b031681565b6002546040805163c395fcb360e01b815233600482015290516001600160a01b039092169163c395fcb391602480820192602092909190829003018186803b1580156117fd57600080fd5b505afa158015611811573d6000803e3d6000fd5b505050506040513d602081101561182757600080fd5b50516118645760405162461bcd60e51b8152600401808060200182810382526040815260200180611f726040913960400191505060405180910390fd5b6001600160a01b03811661187757600080fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60075481565b6118a833611630565b60005b8151811015610b07576000818152600a60205260409020546001600160a01b03163314156118f0576118f0338383815181106118e357fe5b602002602001015161190a565b6001016118ab565b600b6020526000908152604090205481565b6001600160a01b03821660009081526009602052604081209061192c83610e6c565b600283015490915061193e9082611d66565b60028301556005546119509082611d66565b600555815460001981019060009084908390811061196a57fe5b906000526020600020015490508084600001856001016000888152602001908152602001600020548154811061199c57fe5b6000918252602090912001558354156119e45783548490806119ba57fe5b60008281526020808220830160001990810183905590920190925586825260018601905260408120555b6002840154611a2f576001600160a01b038616600090815260096020526040812090611a108282611ea4565b5060006002820181905560038201819055600482018190556005909101555b6000858152600a602052604080822080546001600160a01b03191690556001548151632142170760e11b81523060048201526001600160a01b038a81166024830152604482018a9052925192909116926342842e0e9260648084019382900301818387803b158015611aa057600080fd5b505af1158015611ab4573d6000803e3d6000fd5b5050604080516001600160a01b038a1681526020810189905281517f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759450908190039091019150a1505050505050565b6001600160a01b03821660009081526009602052604090206002810154158015611b3057506003810154155b15611b3e5760075460038201555b611b4783610f7a565b6000611b5283610e6c565b6002830154909150611b649082611c68565b6002830155600554611b769082611c68565b60055581546001808201845560008481526020808220909301869055858152600a909252604080832080546001600160a01b0319166001600160a01b0389811691821790925592548251632142170760e11b815260048101949094523060248501526044840188905291519116926342842e0e926064808201939182900301818387803b158015611c0657600080fd5b505af1158015611c1a573d6000803e3d6000fd5b5050604080516001600160a01b03881681526020810187905281517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9450908190039091019150a150505050565b600082820183811015611cc2576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b600082611cda57506000611cc5565b82820282848281611ce757fe5b0414611cc25760405162461bcd60e51b81526004018080602001828103825260218152602001806120116021913960400191505060405180910390fd5b6000611cc283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611da8565b6000611cc283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e4a565b60008183611e345760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611df9578181015183820152602001611de1565b50505050905090810190601f168015611e265780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611e4057fe5b0495945050505050565b60008184841115611e9c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611df9578181015183820152602001611de1565b505050900390565b5080546000825590600052602060002090810190610e5a91905b80821115611ed25760008155600101611ebe565b509056fe4469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a20556e61626c6520746f2073656e6420636f6e747269627574696f6e20746f2066756e6473206d756c74697369674469676974616c617847656e657369735374616b696e672e736574546f6b656e73436c61696d61626c653a2053656e646572206d7573742062652061646d696e4469676974616c617847656e657369735374616b696e672e73657452657761726473436f6e74726163743a2053656e646572206d7573742062652061646d696e4469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a20596f752063616e6e6f742065786365656420746865206d6178696d756d20636f6e747269627574696f6e20616d6f756e74536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774469676974616c617847656e657369735374616b696e672e696e637265617365436f6e747269627574696f6e3a2067656e65736973204e465420776173206e6f7420636f6e747269626962757465644469676974616c617847656e657369735374616b696e672e5f756e7374616b653a2053656e646572206d7573742068617665207374616b656420746f6b656e49444469676974616c617847656e657369735374616b696e672e736574436f6e747269627574696f6e733a2053656e646572206d7573742062652061646d696ea26469706673582212209e8bbf28c4312267905dbe2456074b732ffb7fd8dd6388e9e90aec6062c6699864736f6c634300060c0033

Deployed Bytecode Sourcemap

80409:15050:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88933:318;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;88933:318:0;;:::i;:::-;;82172:59;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;95254:196;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;95254:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;95254:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;95254:196:0;;;;;;;;;;-1:-1:-1;95254:196:0;;-1:-1:-1;95254:196:0;-1:-1:-1;95254:196:0;:::i;:::-;;;;-1:-1:-1;;;;;;95254:196:0;;;;;;;;;;;;;;81885:46;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;81885:46:0;;:::i;:::-;;;;-1:-1:-1;;;;;81885:46:0;;;;;;;;;;;;;;80674:40;;;;;;;;;;;;;:::i;85400:189::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;85400:189:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;85400:189:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;85400:189:0;;-1:-1:-1;85400:189:0;;-1:-1:-1;;;;;85400:189:0:i;93854:1390::-;;;;;;;;;;;;;;;;-1:-1:-1;93854:1390:0;;:::i;83363:514::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;83363:514:0;;;;;;;;;;;;;;;;;;;;;;;;:::i;86980:319::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;86980:319:0;;:::i;82328:27::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;82042:33;;;;;;;;;;;;;:::i;84949:185::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84949:185:0;;:::i;84239:339::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84239:339:0;;;;:::i;89352:875::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;89352:875:0;-1:-1:-1;;;;;89352:875:0;;:::i;84684:187::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84684:187:0;-1:-1:-1;;;;;84684:187:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;81053:36;;;;;;;;;;;;;:::i;80622:45::-;;;;;;;;;;;;;:::i;85664:248::-;;;;;;;;;;;;;:::i;80577:38::-;;;;;;;;;;;;;:::i;81787:42::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;81787:42:0;-1:-1:-1;;;;;81787:42:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91588:1142;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91588:1142:0;-1:-1:-1;;;;;91588:1142:0;;:::i;90444:449::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90444:449:0;-1:-1:-1;;;;;90444:449:0;;:::i;92939:554::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;92939:554:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;92939:554:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;92939:554:0;;;;;;;;-1:-1:-1;92939:554:0;;-1:-1:-1;;;;;92939:554:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;92939:554:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;92939:554:0;;-1:-1:-1;92939:554:0;;-1:-1:-1;;;;;92939:554:0:i;85207:117::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;85207:117:0;;:::i;80936:29::-;;;;;;;;;;;;;:::i;80972:::-;;;;;;;;;;;;;:::i;80544:26::-;;;;;;;;;;;;;:::i;90969:545::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;90969:545:0;-1:-1:-1;;;;;90969:545:0;;:::i;80809:36::-;;;;;;;;;;;;;:::i;83885:346::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;83885:346:0;-1:-1:-1;;;;;83885:346:0;;:::i;81010:36::-;;;;;;;;;;;;;:::i;87378:310::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;87378:310:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;87378:310:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;87378:310:0;;-1:-1:-1;87378:310:0;;-1:-1:-1;;;;;87378:310:0:i;81987:48::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;81987:48:0;;:::i;88933:318::-;89019:20;;;;:10;:20;;;;;;-1:-1:-1;;;;;89019:20:0;89043:10;89019:34;88997:149;;;;-1:-1:-1;;;88997:149:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89157:30;89166:10;89178:8;89157;:30::i;:::-;89203:38;;;;;;;;89220:10;;89203:38;;;;;;;;;;88933:318;:::o;82172:59::-;82224:7;82172:59;:::o;95254:196::-;-1:-1:-1;;;95254:196:0;;;;;;;:::o;81885:46::-;;;;;;;;;;;;-1:-1:-1;;;;;81885:46:0;;:::o;80674:40::-;;;-1:-1:-1;;;;;80674:40:0;;:::o;85400:189::-;85486:6;85481:101;85502:8;:15;85498:1;:19;85481:101;;;85539:31;85546:10;85558:8;85567:1;85558:11;;;;;;;;;;;;;;85539:6;:31::i;:::-;85519:3;;85481:101;;;;85400:189;:::o;93854:1390::-;93966:20;;;;:10;:20;;;;;;93953:34;;-1:-1:-1;;;;;93966:20:0;93953:12;:34::i;:::-;94045:1;94020:22;;;:12;:22;;;;;;93998:155;;;;-1:-1:-1;;;93998:155:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94166:25;94239:22;;;:12;:22;;;;;;94194:9;;94239:45;;94194:9;94239:26;:45::i;:::-;94214:22;;;;:12;:22;;;;;:70;;;82224:7;-1:-1:-1;94319:51:0;94297:196;;;;-1:-1:-1;;;94297:196:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94527:18;;:41;;94550:17;94527:22;:41::i;:::-;94506:18;:62;94612:13;;:49;;94582:25;;-1:-1:-1;;;;;94612:13:0;;94639:17;;94582:25;94612:49;94582:25;94612:49;94639:17;94612:13;:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94581:80;;;94694:20;94672:161;;;;-1:-1:-1;;;94672:161:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;94854:21;94886:20;;;:10;:20;;;;;;;;;-1:-1:-1;;;;;94886:20:0;94878:29;;:7;:29;;;;;94978:27;;;94886:20;94978:17;;:27;;;;;;;94962:44;;94897:8;;94878:29;;94962:44;;;;;;;;;;;;;;:56;94958:213;;;95053:14;;;;:37;;95072:17;95053:18;:37::i;:::-;95036:14;;;:54;95122:14;;:37;;95141:17;95122:18;:37::i;:::-;95105:14;:54;94958:213;95186:50;;;;;;;;95208:8;;95186:50;;;;;;;;;;93854:1390;;;;:::o;83363:514::-;83604:11;;;;;;;83603:12;83595:44;;;;;-1:-1:-1;;;83595:44:0;;;;;;;;;;;;-1:-1:-1;;;83595:44:0;;;;;;;;;;;;;;;83650:13;:30;;-1:-1:-1;;;;;83650:30:0;;;-1:-1:-1;;;;;;83650:30:0;;;;;;;:13;83691:28;;;;;;;;;;;;;;;83650:30;83730:24;;;;;;;;;;;;;;;83765:14;:32;;;;;;;;;;;83825:15;83808:14;:32;83851:11;:18;;-1:-1:-1;;83851:18:0;83650:30;83851:18;;;83363:514::o;86980:319::-;87089:20;;;;:10;:20;;;;;;-1:-1:-1;;;;;87089:20:0;87113:10;87089:34;87067:149;;;;-1:-1:-1;;;87067:149:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87227:23;87239:10;87227:11;:23::i;:::-;87261:30;87270:10;87282:8;87261;:30::i;:::-;86980:319;:::o;82328:27::-;;;;;;:::o;82042:33::-;;;;:::o;84949:185::-;85065:14;85104:22;;;:12;:22;;;;;;84949:185;;;;:::o;84239:339::-;84354:14;;:39;;;-1:-1:-1;;;84354:39:0;;84382:10;84354:39;;;;;;-1:-1:-1;;;;;84354:14:0;;;;:27;;:39;;;;;;;;;;;;;;;:14;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84354:39:0;84332:153;;;;-1:-1:-1;;;84332:153:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84496:15;:26;;;;;-1:-1:-1;;84496:26:0;;;;;;;;84538:32;;;;;;;;;;;;;;;;84239:339;:::o;89352:875::-;89439:15;;;;;;;;;-1:-1:-1;;;;;89439:15:0;-1:-1:-1;;;;;89439:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;89506:15:0;;89537:14;;89506:63;;;-1:-1:-1;;;89506:63:0;;;;;;;;;89553:15;89506:63;;;;;89481:22;;-1:-1:-1;;;;;89506:15:0;;:30;;:63;;;;;89439:31;;89506:63;;;;;;;:15;:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;89506:63:0;89586:14;;89506:63;;-1:-1:-1;89586:18:0;89582:305;;89859:14;;89645:230;;89671:203;;:137;81133:5;89671:70;:14;89736:4;89671:64;:70::i;:::-;:120;;:137::i;:::-;:187;;:203::i;:::-;89645:21;;;:25;:230::i;:::-;89621:21;:254;89582:305;89924:15;89907:14;:32;89950:15;89968:19;89981:5;89968:12;:19::i;:::-;-1:-1:-1;;;;;90024:14:0;;90000:21;90024:14;;;:7;:14;;;;;89950:37;;-1:-1:-1;90053:19:0;90049:171;;90112:20;;;;:33;;90137:7;90112:24;:33::i;:::-;90089:20;;;:56;90186:21;;90160:23;;;:47;90049:171;89352:875;;;;:::o;84684:187::-;-1:-1:-1;;;;;84840:14:0;;;;;;:7;:14;;;;;;;;;84833:30;;;;;;;;;;;;;;;;;84790:25;;84833:30;;;84840:14;84833:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84684:187;;;:::o;81053:36::-;;;;:::o;80622:45::-;;;-1:-1:-1;;;;;80622:45:0;;:::o;85664:248::-;85736:10;;:32;;;-1:-1:-1;;;85736:32:0;;85757:10;85736:32;;;;;;85718:15;;-1:-1:-1;;;;;85736:10:0;;:20;;:32;;;;;;;;;;;;;;:10;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;85736:32:0;;-1:-1:-1;85784:6:0;85779:126;85800:7;85796:1;:11;85779:126;;;85848:10;;:44;;;-1:-1:-1;;;85848:44:0;;85836:10;85848:44;;;;;;;;;;;;;;85829:64;;-1:-1:-1;;;;;85848:10:0;;:30;;:44;;;;;;;;;;;;;;:10;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;85848:44:0;85829:6;:64::i;:::-;85809:3;;85779:126;;80577:38;;;-1:-1:-1;;;;;80577:38:0;;:::o;81787:42::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;91588:1142::-;91694:7;91723:14;;91741:1;91723:19;91719:60;;;-1:-1:-1;91766:1:0;91759:8;;91719:60;91816:15;;91847:14;;91816:120;;;-1:-1:-1;;;91816:120:0;;;;;;;;;91920:15;91816:120;;;;;91791:22;;-1:-1:-1;;;;;91816:15:0;;:30;;:120;;;;;;;;;;;;;;:15;:120;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;91816:120:0;-1:-1:-1;;;;;92331:14:0;;91949:25;92331:14;;;:7;91816:120;92331:14;;;;:31;;;92251:14;;91816:120;;-1:-1:-1;91949:25:0;;91977:386;;92331:31;91977:290;;92003:263;;:177;81133:5;92003:90;91816:120;92088:4;92003:84;:90::i;91977:290::-;:353;;:386::i;:::-;-1:-1:-1;;;;;92451:14:0;;92433:15;92451:14;;;:7;:14;;;;;:22;;;91949:414;;-1:-1:-1;92433:15:0;92451:176;;81133:5;;92451:105;;92551:4;;92451:105;;91949:414;92451:26;:45::i;:176::-;-1:-1:-1;;;;;92691:14:0;;;;;;:7;:14;;;;;:30;;;;92657:28;;;;;92433:194;;-1:-1:-1;92645:77:0;;:41;;92433:194;;92645:11;:41::i;:77::-;92638:84;91588:1142;-1:-1:-1;;;;;91588:1142:0:o;90444:449::-;-1:-1:-1;;;;;90623:14:0;;90544:7;90623:14;;;:7;:14;;;;;:31;;;90597:21;;90544:7;;90597:58;;:21;:25;:58::i;:::-;-1:-1:-1;;;;;90684:14:0;;90666:15;90684:14;;;:7;:14;;;;;:22;;;90569:86;;-1:-1:-1;90666:15:0;90684:176;;81133:5;;90684:105;;90784:4;;90684:105;;90569:86;90684:26;:45::i;:176::-;90666:194;90444:449;-1:-1:-1;;;;90444:449:0:o;92939:554::-;93097:14;;:39;;;-1:-1:-1;;;93097:39:0;;93125:10;93097:39;;;;;;-1:-1:-1;;;;;93097:14:0;;;;:27;;:39;;;;;;;;;;;;;;;:14;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;93097:39:0;93075:151;;;;-1:-1:-1;;;93075:151:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;93242:9;93237:249;93261:6;:13;93257:1;:17;93237:249;;;93296:13;93312:6;93319:1;93312:9;;;;;;;;;;;;;;93296:25;;93336:14;93353:7;93361:1;93353:10;;;;;;;;;;;;;;93336:27;;93400:6;93378:12;:19;93391:5;93378:19;;;;;;;;;;;:28;;;;93442:30;93465:6;93442:18;;:22;;:30;;;;:::i;:::-;93421:18;:51;-1:-1:-1;;93276:3:0;;93237:249;;;;92939:554;;:::o;85207:117::-;85289:27;85296:10;85308:7;85289:6;:27::i;80936:29::-;;;;:::o;80972:::-;;;;:::o;80544:26::-;;;-1:-1:-1;;;;;80544:26:0;;:::o;90969:545::-;91075:15;;;;:23;;:15;:23;91053:102;;;;;-1:-1:-1;;;91053:102:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;91166:19;91179:5;91166:12;:19::i;:::-;-1:-1:-1;;;;;91222:14:0;;91198:21;91222:14;;;:7;:14;;;;;91302:22;;;;91277:20;;;;91222:14;;91198:21;91277:48;;:24;:48::i;:::-;91361:22;;;;91253:72;;-1:-1:-1;91361:41:0;;91253:72;91361:26;:41::i;:::-;91336:22;;;:66;91415:12;;;:43;;;-1:-1:-1;;;91415:43:0;;-1:-1:-1;;;;;91415:43:0;;;;;;;;;;;;;;;:12;;;;;:21;;:43;;;;;;;;;;;;;;;;;;:12;:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;91474:32:0;;;;;;;;-1:-1:-1;;;;;91474:32:0;;;;;;;;;91415:43;91474:32;;;90969:545;;;:::o;80809:36::-;;;-1:-1:-1;;;;;80809:36:0;;:::o;83885:346::-;84000:14;;:39;;;-1:-1:-1;;;84000:39:0;;84028:10;84000:39;;;;;;-1:-1:-1;;;;;84000:14:0;;;;:27;;:39;;;;;;;;;;;;;;;:14;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;84000:39:0;83978:153;;;;-1:-1:-1;;;83978:153:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;84150:19:0;;84142:28;;;;;;84181:15;:42;;-1:-1:-1;;;;;;84181:42:0;-1:-1:-1;;;;;84181:42:0;;;;;;;;;;83885:346::o;81010:36::-;;;;:::o;87378:310::-;87477:23;87489:10;87477:11;:23::i;:::-;87516:6;87511:170;87532:8;:15;87528:1;:19;87511:170;;;87573:13;;;;:10;:13;;;;;;-1:-1:-1;;;;;87573:13:0;87590:10;87573:27;87569:101;;;87621:33;87630:10;87642:8;87651:1;87642:11;;;;;;;;;;;;;;87621:8;:33::i;:::-;87549:3;;87511:170;;81987:48;;;;;;;;;;;;;:::o;87915:948::-;-1:-1:-1;;;;;88053:14:0;;88029:21;88053:14;;;:7;:14;;;;;;88097:32;88120:8;88097:22;:32::i;:::-;88157:14;;;;88080:49;;-1:-1:-1;88157:26:0;;88080:49;88157:18;:26::i;:::-;88140:14;;;:43;88211:14;;:26;;88230:6;88211:18;:26::i;:::-;88194:14;:43;88270:22;;-1:-1:-1;;88270:26:0;;;88250:17;;88270:6;;:26;;88330;;;;;;;;;;;;;;88307:49;;88414:12;88367:6;:15;;88383:6;:17;;:27;88401:8;88383:27;;;;;;;;;;;;88367:44;;;;;;;;;;;;;;;;;:59;88441:22;;:26;88437:129;;88484:21;;:6;;:21;;;;;;;;;;;;;;;-1:-1:-1;;88484:21:0;;;;;;;;;;;;88527:27;;;88484:21;88527:17;;:27;;;;;88520:34;88437:129;88582:14;;;;88578:73;;-1:-1:-1;;;;;88625:14:0;;;;;;:7;:14;;;;;;88618:21;88625:14;;88618:21;:::i;:::-;-1:-1:-1;88618:21:0;;;;;;;;;;;;;;;;;;;;;;;;88578:73;88668:20;;;;:10;:20;;;;;;88661:27;;-1:-1:-1;;;;;;88661:27:0;;;-1:-1:-1;88701:10:0;:109;;-1:-1:-1;;;88701:109:0;;88751:4;88701:109;;;;-1:-1:-1;;;;;88701:109:0;;;;;;;;;;;;;;;:10;;;;;:27;;:109;;;;;;;;;;88668:20;88701:10;:109;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;88828:25:0;;;-1:-1:-1;;;;;88828:25:0;;;;;;;;;;;;;;-1:-1:-1;88828:25:0;;;;;;;;-1:-1:-1;88828:25:0;87915:948;;;;;;:::o;86134:793::-;-1:-1:-1;;;;;86266:14:0;;86242:21;86266:14;;;:7;:14;;;;;86297;;;;:19;:51;;;;-1:-1:-1;86320:23:0;;;;:28;86297:51;86293:130;;;86390:21;;86364:23;;;:47;86293:130;86435:19;86448:5;86435:12;:19::i;:::-;86465:14;86482:32;86505:8;86482:22;:32::i;:::-;86542:14;;;;86465:49;;-1:-1:-1;86542:26:0;;86465:49;86542:18;:26::i;:::-;86525:14;;;:43;86596:14;;:26;;86615:6;86596:18;:26::i;:::-;86579:14;:43;86633:30;;;;;;;;-1:-1:-1;86633:30:0;;;;;;;;;;;;;86730:20;;;:10;:20;;;86674:45;86730:20;;;:28;;-1:-1:-1;;;;;;86730:28:0;-1:-1:-1;;;;;86730:28:0;;;;;;;;;86769:10;;:109;;-1:-1:-1;;;86769:109:0;;;;;;;;;86839:4;86769:109;;;;;;;;;;;;:10;;;:27;;:109;;;;;;;;;;;-1:-1:-1;86769:10:0;:109;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;86896:23:0;;;-1:-1:-1;;;;;86896:23:0;;;;;;;;;;;;;;-1:-1:-1;86896:23:0;;;;;;;;-1:-1:-1;86896:23:0;86134:793;;;;:::o;964:181::-;1022:7;1054:5;;;1078:6;;;;1070:46;;;;;-1:-1:-1;;;1070:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;1136:1;-1:-1:-1;964:181:0;;;;;:::o;2318:471::-;2376:7;2621:6;2617:47;;-1:-1:-1;2651:1:0;2644:8;;2617:47;2688:5;;;2692:1;2688;:5;:1;2712:5;;;;;:10;2704:56;;;;-1:-1:-1;;;2704:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3265:132;3323:7;3350:39;3354:1;3357;3350:39;;;;;;;;;;;;;;;;;:3;:39::i;1428:136::-;1486:7;1513:43;1517:1;1520;1513:43;;;;;;;;;;;;;;;;;:3;:43::i;3893:278::-;3979:7;4014:12;4007:5;3999:28;;;;-1:-1:-1;;;3999:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4038:9;4054:1;4050;:5;;;;;;;3893:278;-1:-1:-1;;;;;3893:278:0:o;1867:192::-;1953:7;1989:12;1981:6;;;;1973:29;;;;-1:-1:-1;;;1973:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;2025:5:0;;;1867:192::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o

Swarm Source

ipfs://9e8bbf28c4312267905dbe2456074b732ffb7fd8dd6388e9e90aec6062c66998
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.