ETH Price: $3,069.16 (-8.02%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim124416322021-05-15 22:08:031352 days ago1621116483IN
0x1d972971...b29931676
0.001 ETH0.0029314593
Claim123465772021-05-01 6:04:461367 days ago1619849086IN
0x1d972971...b29931676
0.001 ETH0.00499232
Claim123465222021-05-01 5:52:011367 days ago1619848321IN
0x1d972971...b29931676
0.001 ETH0.00499232
Claim123464822021-05-01 5:43:151367 days ago1619847795IN
0x1d972971...b29931676
0.001 ETH0.0054635
Claim123464382021-05-01 5:34:161367 days ago1619847256IN
0x1d972971...b29931676
0.001 ETH0.00561636
Claim123462572021-05-01 4:51:391367 days ago1619844699IN
0x1d972971...b29931676
0.001 ETH0.00514833
Claim123462242021-05-01 4:43:121367 days ago1619844192IN
0x1d972971...b29931676
0.001 ETH0.0053035934
Claim123461642021-05-01 4:30:051367 days ago1619843405IN
0x1d972971...b29931676
0.001 ETH0.00811252
Claim123461392021-05-01 4:24:081367 days ago1619843048IN
0x1d972971...b29931676
0.001 ETH0.00514833
Claim123461082021-05-01 4:15:291367 days ago1619842529IN
0x1d972971...b29931676
0.001 ETH0.00530434
Claim123460922021-05-01 4:11:371367 days ago1619842297IN
0x1d972971...b29931676
0.001 ETH0.00514833
Claim123460612021-05-01 4:06:281367 days ago1619841988IN
0x1d972971...b29931676
0.001 ETH0.00530434
Claim123460492021-05-01 4:03:171367 days ago1619841797IN
0x1d972971...b29931676
0.001 ETH0.00561636
Claim123459492021-05-01 3:46:021367 days ago1619840762IN
0x1d972971...b29931676
0.001 ETH0.00514833
Claim123458852021-05-01 3:31:201367 days ago1619839880IN
0x1d972971...b29931676
0.001 ETH0.00608439
Claim123458562021-05-01 3:24:121367 days ago1619839452IN
0x1d972971...b29931676
0.001 ETH0.00464129.75
Claim123456612021-05-01 2:43:021367 days ago1619836982IN
0x1d972971...b29931676
0.001 ETH0.00592838
Claim123456142021-05-01 2:32:311367 days ago1619836351IN
0x1d972971...b29931676
0.001 ETH0.0070194645
Claim123449142021-04-30 23:53:211367 days ago1619826801IN
0x1d972971...b29931676
0.001 ETH0.00670843
Claim123430442021-04-30 16:57:071368 days ago1619801827IN
0x1d972971...b29931676
0.001 ETH0.00998464
Claim123415782021-04-30 11:33:121368 days ago1619782392IN
0x1d972971...b29931676
0.001 ETH0.0067074843
Claim123406842021-04-30 8:06:251368 days ago1619769985IN
0x1d972971...b29931676
0.001 ETH0.0059383838.0666
Claim123406352021-04-30 7:55:071368 days ago1619769307IN
0x1d972971...b29931676
0.001 ETH0.00670843
Claim123366662021-04-29 17:19:161369 days ago1619716756IN
0x1d972971...b29931676
0.001 ETH0.021996141
Claim123366512021-04-29 17:15:131369 days ago1619716513IN
0x1d972971...b29931676
0.001 ETH0.01871856120
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
123465772021-05-01 6:04:461367 days ago1619849086
0x1d972971...b29931676
0.001 ETH
123465222021-05-01 5:52:011367 days ago1619848321
0x1d972971...b29931676
0.001 ETH
123464822021-05-01 5:43:151367 days ago1619847795
0x1d972971...b29931676
0.001 ETH
123464382021-05-01 5:34:161367 days ago1619847256
0x1d972971...b29931676
0.001 ETH
123462572021-05-01 4:51:391367 days ago1619844699
0x1d972971...b29931676
0.001 ETH
123462242021-05-01 4:43:121367 days ago1619844192
0x1d972971...b29931676
0.001 ETH
123461642021-05-01 4:30:051367 days ago1619843405
0x1d972971...b29931676
0.001 ETH
123461392021-05-01 4:24:081367 days ago1619843048
0x1d972971...b29931676
0.001 ETH
123461082021-05-01 4:15:291367 days ago1619842529
0x1d972971...b29931676
0.001 ETH
123460922021-05-01 4:11:371367 days ago1619842297
0x1d972971...b29931676
0.001 ETH
123460612021-05-01 4:06:281367 days ago1619841988
0x1d972971...b29931676
0.001 ETH
123460492021-05-01 4:03:171367 days ago1619841797
0x1d972971...b29931676
0.001 ETH
123459492021-05-01 3:46:021367 days ago1619840762
0x1d972971...b29931676
0.001 ETH
123458852021-05-01 3:31:201367 days ago1619839880
0x1d972971...b29931676
0.001 ETH
123458562021-05-01 3:24:121367 days ago1619839452
0x1d972971...b29931676
0.001 ETH
123456612021-05-01 2:43:021367 days ago1619836982
0x1d972971...b29931676
0.001 ETH
123456142021-05-01 2:32:311367 days ago1619836351
0x1d972971...b29931676
0.001 ETH
123449142021-04-30 23:53:211367 days ago1619826801
0x1d972971...b29931676
0.001 ETH
123430442021-04-30 16:57:071368 days ago1619801827
0x1d972971...b29931676
0.001 ETH
123415782021-04-30 11:33:121368 days ago1619782392
0x1d972971...b29931676
0.001 ETH
123406842021-04-30 8:06:251368 days ago1619769985
0x1d972971...b29931676
0.001 ETH
123406352021-04-30 7:55:071368 days ago1619769307
0x1d972971...b29931676
0.001 ETH
123366662021-04-29 17:19:161369 days ago1619716756
0x1d972971...b29931676
0.001 ETH
123366512021-04-29 17:15:131369 days ago1619716513
0x1d972971...b29931676
0.001 ETH
123315762021-04-28 22:21:131369 days ago1619648473
0x1d972971...b29931676
0.001 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StrongNFTClaimerV4

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Unlicense license

Contract Source Code (Solidity Multiple files format)

File 1 of 15: StrongNFTClaimerV4.sol
//SPDX-License-Identifier: Unlicense
pragma solidity 0.6.12;

import "./ServiceInterfaceV10.sol";
import "./IERC1155Preset.sol";
import "./Context.sol";
import "./Counters.sol";

contract StrongNFTClaimerV4 is Context {
  using Counters for Counters.Counter;

  IERC1155Preset public NftToken;
  bool public initDone;
  address public serviceAdmin;
  address public superAdmin;
  address payable public feeCollector;
  uint256 public claimingFeeInWei;
  Counters.Counter public tokenCounter;
  mapping(address => bool) public addressClaimed;

  function init(
    address _tokenContract,
    address _serviceAdminAddress,
    address _superAdminAddress,
    uint256 _counterValue
  ) public {
    require(initDone == false, "init done");

    NftToken = IERC1155Preset(_tokenContract);
    serviceAdmin = _serviceAdminAddress;
    superAdmin = _superAdminAddress;
    tokenCounter = Counters.Counter(_counterValue);
    initDone = true;
  }

  function isEligible(address _address, bytes memory _signature) public view returns (bool) {
    bytes32 hash = prefixed(keccak256(abi.encodePacked(_address)));
    address signer = recoverSigner(hash, _signature);

    return !addressClaimed[_address] && (signer == superAdmin || signer == serviceAdmin);
  }

  function claim(bytes memory _signature) public payable {
    require(msg.value == claimingFeeInWei, "invalid fee");
    require(isEligible(_msgSender(), _signature), "not eligible");

    NftToken.mint(_msgSender(), tokenCounter.current(), 1, "");
    tokenCounter.increment();
    addressClaimed[_msgSender()] = true;

    feeCollector.transfer(msg.value);
  }

  // Signatures

  function recoverSigner(bytes32 _hash, bytes memory _sig) public pure returns (address) {
    (uint8 v, bytes32 r, bytes32 s) = splitSignature(_sig);

    return ecrecover(_hash, v, r, s);
  }

  function prefixed(bytes32 _hash) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
  }

  function splitSignature(bytes memory _sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
    require(_sig.length == 65);

    assembly {
      r := mload(add(_sig, 32))
      s := mload(add(_sig, 64))
      v := byte(0, mload(add(_sig, 96)))
    }

    return (v, r, s);
  }

  // Admin

  function updateAddressClaimed(address _address, bool _value) public {
    require(msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    addressClaimed[_address] = _value;
  }

  function updateCounterValue(uint256 _counterValue) public {
    require(msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    tokenCounter = Counters.Counter(_counterValue);
  }

  function updateClaimingFee(uint256 _valueWei) public {
    require(msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    claimingFeeInWei = _valueWei;
  }

  function updateFeeCollector(address payable _address) public {
    require(_address != address(0), "zero");
    require(msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    feeCollector = _address;
  }

}

File 2 of 15: Context.sol
// SPDX-License-Identifier: MIT

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 3 of 15: Counters.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "./SafeMath.sol";

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
 * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
 * directly accessed.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        // The {SafeMath} overflow check can be skipped here, see the comment at the top
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

File 4 of 15: IERC1155Preset.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.2;

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155Preset {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;

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

    /**
     * @dev Creates `amount` new tokens for `to`, of token type `id`.
     *
     * See {ERC1155-_mint}.
     *
     * Requirements:
     *
     * - the caller must have the `MINTER_ROLE`.
     */
    function mint(address to, uint256 id, uint256 amount, bytes memory data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.
     */
    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external;

    function getOwnerIdByIndex(address owner, uint256 index) external view returns (uint256);

    function getOwnerIdIndex(address owner, uint256 id) external view returns (uint256);
}

File 5 of 15: IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 6 of 15: rewards.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./SafeMath.sol";

library rewards {

    using SafeMath for uint256;

    function blocks(uint256 lastClaimedOnBlock, uint256 newRewardBlock, uint256 blockNumber) internal pure returns (uint256[2] memory) {
        if (lastClaimedOnBlock >= blockNumber) return [uint256(0), uint256(0)];

        if (blockNumber <= newRewardBlock || newRewardBlock == 0) {
            return [blockNumber.sub(lastClaimedOnBlock), uint256(0)];
        }
        else if (lastClaimedOnBlock >= newRewardBlock) {
            return [uint256(0), blockNumber.sub(lastClaimedOnBlock)];
        }
        else {
            return [newRewardBlock.sub(lastClaimedOnBlock), blockNumber.sub(newRewardBlock)];
        }
    }

}

File 7 of 15: SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

        return c;
    }

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

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

File 8 of 15: ServiceInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface ServiceInterface {
  function claimingFeeNumerator() external view returns(uint256);

  function claimingFeeDenominator() external view returns(uint256);

  function doesNodeExist(address entity, uint128 nodeId) external view returns (bool);

  function getNodeId(address entity, uint128 nodeId) external view returns (bytes memory);

  function getReward(address entity, uint128 nodeId) external view returns (uint256);

  function getRewardByBlock(address entity, uint128 nodeId, uint256 blockNumber) external view returns (uint256);

  function getTraunch(address entity) external view returns (uint256);

  function isEntityActive(address entity) external view returns (bool);

  function claim(uint128 nodeId, uint256 blockNumber, bool toStrongPool) external payable;
}

File 9 of 15: ServiceInterfaceV10.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface ServiceInterfaceV10 {
  function traunch(address) external view returns(uint256);

  function claimingFeeNumerator() external view returns(uint256);

  function claimingFeeDenominator() external view returns(uint256);

  function doesNodeExist(address entity, uint128 nodeId) external view returns (bool);

  function getNodeId(address entity, uint128 nodeId) external view returns (bytes memory);

  function getReward(address entity, uint128 nodeId) external view returns (uint256);

  function getRewardByBlock(address entity, uint128 nodeId, uint256 blockNumber) external view returns (uint256);

  function isEntityActive(address entity) external view returns (bool);

  function claim(uint128 nodeId, uint256 blockNumber, bool toStrongPool) external payable;
}

File 10 of 15: ServiceV10.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./StrongPoolInterface.sol";
import "./IERC1155Preset.sol";
import "./StrongNFTBonusInterface.sol";
import "./rewards.sol";

contract ServiceV10 {
  event Requested(address indexed miner);
  event Claimed(address indexed miner, uint256 reward);

  using SafeMath for uint256;
  bool public initDone;
  address public admin;
  address public pendingAdmin;
  address public superAdmin;
  address public pendingSuperAdmin;
  address public serviceAdmin;
  address public parameterAdmin;
  address payable public feeCollector;

  IERC20 public strongToken;
  StrongPoolInterface public strongPool;

  uint256 public rewardPerBlockNumerator;
  uint256 public rewardPerBlockDenominator;

  uint256 public naasRewardPerBlockNumerator;
  uint256 public naasRewardPerBlockDenominator;

  uint256 public claimingFeeNumerator;
  uint256 public claimingFeeDenominator;

  uint256 public requestingFeeInWei;

  uint256 public strongFeeInWei;

  uint256 public recurringFeeInWei;
  uint256 public recurringNaaSFeeInWei;
  uint256 public recurringPaymentCycleInBlocks;

  uint256 public rewardBalance;

  mapping(address => uint256) public entityBlockLastClaimedOn;

  address[] public entities;
  mapping(address => uint256) public entityIndex;
  mapping(address => bool) public entityActive;
  mapping(address => bool) public requestPending;
  mapping(address => bool) public entityIsNaaS;
  mapping(address => uint256) public paidOnBlock;
  uint256 public activeEntities;

  string public desciption;

  uint256 public claimingFeeInWei;

  uint256 public naasRequestingFeeInWei;

  uint256 public naasStrongFeeInWei;

  bool public removedTokens;

  mapping(address => uint256) public traunch;

  uint256 public currentTraunch;

  mapping(bytes => bool) public entityNodeIsActive;
  mapping(bytes => bool) public entityNodeIsBYON;
  mapping(bytes => uint256) public entityNodeTraunch;
  mapping(bytes => uint256) public entityNodePaidOnBlock;
  mapping(bytes => uint256) public entityNodeClaimedOnBlock;
  mapping(address => uint128) public entityNodeCount;

  event Paid(address indexed entity, uint128 nodeId, bool isBYON, bool isRenewal, uint256 upToBlockNumber);
  event Migrated(address indexed from, address indexed to, uint128 fromNodeId, uint128 toNodeId, bool isBYON);

  uint256 public rewardPerBlockNumeratorNew;
  uint256 public rewardPerBlockDenominatorNew;
  uint256 public naasRewardPerBlockNumeratorNew;
  uint256 public naasRewardPerBlockDenominatorNew;
  uint256 public rewardPerBlockNewEffectiveBlock;

  StrongNFTBonusInterface public strongNFTBonus;

  function init(
    address strongTokenAddress,
    address strongPoolAddress,
    address adminAddress,
    address superAdminAddress,
    uint256 rewardPerBlockNumeratorValue,
    uint256 rewardPerBlockDenominatorValue,
    uint256 naasRewardPerBlockNumeratorValue,
    uint256 naasRewardPerBlockDenominatorValue,
    uint256 requestingFeeInWeiValue,
    uint256 strongFeeInWeiValue,
    uint256 recurringFeeInWeiValue,
    uint256 recurringNaaSFeeInWeiValue,
    uint256 recurringPaymentCycleInBlocksValue,
    uint256 claimingFeeNumeratorValue,
    uint256 claimingFeeDenominatorValue,
    string memory desc
  ) public {
    require(!initDone, "init done");
    strongToken = IERC20(strongTokenAddress);
    strongPool = StrongPoolInterface(strongPoolAddress);
    admin = adminAddress;
    superAdmin = superAdminAddress;
    rewardPerBlockNumerator = rewardPerBlockNumeratorValue;
    rewardPerBlockDenominator = rewardPerBlockDenominatorValue;
    naasRewardPerBlockNumerator = naasRewardPerBlockNumeratorValue;
    naasRewardPerBlockDenominator = naasRewardPerBlockDenominatorValue;
    requestingFeeInWei = requestingFeeInWeiValue;
    strongFeeInWei = strongFeeInWeiValue;
    recurringFeeInWei = recurringFeeInWeiValue;
    recurringNaaSFeeInWei = recurringNaaSFeeInWeiValue;
    claimingFeeNumerator = claimingFeeNumeratorValue;
    claimingFeeDenominator = claimingFeeDenominatorValue;
    recurringPaymentCycleInBlocks = recurringPaymentCycleInBlocksValue;
    desciption = desc;
    initDone = true;
  }

  // ADMIN
  // *************************************************************************************

  function updateServiceAdmin(address newServiceAdmin) public {
    require(msg.sender == superAdmin);
    serviceAdmin = newServiceAdmin;
  }

  function updateParameterAdmin(address newParameterAdmin) public {
    require(newParameterAdmin != address(0), "zero");
    require(msg.sender == superAdmin);
    parameterAdmin = newParameterAdmin;
  }

  function updateFeeCollector(address payable newFeeCollector) public {
    require(newFeeCollector != address(0), "zero");
    require(msg.sender == superAdmin);
    feeCollector = newFeeCollector;
  }

  function setPendingAdmin(address newPendingAdmin) public {
    require(msg.sender == admin, "not admin");
    pendingAdmin = newPendingAdmin;
  }

  function acceptAdmin() public {
    require(msg.sender == pendingAdmin && msg.sender != address(0), "not pendingAdmin");
    admin = pendingAdmin;
    pendingAdmin = address(0);
  }

  function setPendingSuperAdmin(address newPendingSuperAdmin) public {
    require(msg.sender == superAdmin, "not superAdmin");
    pendingSuperAdmin = newPendingSuperAdmin;
  }

  function acceptSuperAdmin() public {
    require(msg.sender == pendingSuperAdmin && msg.sender != address(0), "not pendingSuperAdmin");
    superAdmin = pendingSuperAdmin;
    pendingSuperAdmin = address(0);
  }

  // ENTITIES
  // *************************************************************************************

  function getEntities() public view returns (address[] memory) {
    return entities;
  }

  function isEntityActive(address entity) public view returns (bool) {
    return entityActive[entity];
  }

  // TRAUNCH
  // *************************************************************************************

  function updateCurrentTraunch(uint256 value) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    currentTraunch = value;
  }

  // REWARD
  // *************************************************************************************

  function updateRewardPerBlock(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    require(denominator != 0, "invalid value");
    rewardPerBlockNumerator = numerator;
    rewardPerBlockDenominator = denominator;
  }

  function updateNaaSRewardPerBlock(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    require(denominator != 0, "invalid value");
    naasRewardPerBlockNumerator = numerator;
    naasRewardPerBlockDenominator = denominator;
  }

  function updateRewardPerBlockNew(
    uint256 numerator,
    uint256 denominator,
    uint256 numeratorNass,
    uint256 denominatorNass,
    uint256 effectiveBlock
  ) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");

    rewardPerBlockNumeratorNew = numerator;
    rewardPerBlockDenominatorNew = denominator;
    naasRewardPerBlockNumeratorNew = numeratorNass;
    naasRewardPerBlockDenominatorNew = denominatorNass;
    rewardPerBlockNewEffectiveBlock = effectiveBlock != 0 ? effectiveBlock : block.number;
  }

  function deposit(uint256 amount) public {
    require(msg.sender == superAdmin, "not admin");
    require(amount > 0, "zero");
    strongToken.transferFrom(msg.sender, address(this), amount);
    rewardBalance = rewardBalance.add(amount);
  }

  function withdraw(address destination, uint256 amount) public {
    require(msg.sender == superAdmin, "not admin");
    require(amount > 0, "zero");
    require(rewardBalance >= amount, "not enough");
    strongToken.transfer(destination, amount);
    rewardBalance = rewardBalance.sub(amount);
  }

  // FEES
  // *************************************************************************************

  function updateRequestingFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    requestingFeeInWei = feeInWei;
  }

  function updateStrongFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    strongFeeInWei = feeInWei;
  }

  function updateNaasRequestingFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    naasRequestingFeeInWei = feeInWei;
  }

  function updateNaasStrongFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    naasStrongFeeInWei = feeInWei;
  }

  function updateClaimingFee(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    require(denominator != 0, "invalid value");
    claimingFeeNumerator = numerator;
    claimingFeeDenominator = denominator;
  }

  function updateRecurringFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    recurringFeeInWei = feeInWei;
  }

  function updateRecurringNaaSFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    recurringNaaSFeeInWei = feeInWei;
  }

  function updateRecurringPaymentCycleInBlocks(uint256 blocks) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, "not admin");
    require(blocks > 0, "zero");
    recurringPaymentCycleInBlocks = blocks;
  }

  // CORE
  // *************************************************************************************

  function requestAccess(bool isNaaS) public payable {
    uint256 rFee;
    uint256 sFee;

    if (hasLegacyNode(msg.sender)) {
      migrateLegacyNode(msg.sender);
    }

    uint128 nodeId = entityNodeCount[msg.sender] + 1;
    bytes memory id = getNodeId(msg.sender, nodeId);

    if (isNaaS) {
      rFee = naasRequestingFeeInWei;
      sFee = naasStrongFeeInWei;
      activeEntities = activeEntities.add(1);
    } else {
      rFee = requestingFeeInWei;
      sFee = strongFeeInWei;
      entityNodeIsBYON[id] = true;
    }

    require(msg.value == rFee, "invalid fee");

    entityNodePaidOnBlock[id] = block.number;
    entityNodeTraunch[id] = currentTraunch;
    entityNodeClaimedOnBlock[id] = block.number;
    entityNodeCount[msg.sender] = entityNodeCount[msg.sender] + 1;

    feeCollector.transfer(msg.value);
    strongToken.transferFrom(msg.sender, address(this), sFee);
    strongToken.transfer(feeCollector, sFee);

    emit Paid(msg.sender, nodeId, entityNodeIsBYON[id], false, entityNodePaidOnBlock[id].add(recurringPaymentCycleInBlocks));
  }

  function setEntityActiveStatus(address entity, bool status) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");
    uint256 index = entityIndex[entity];
    require(entities[index] == entity, "invalid entity");
    require(entityActive[entity] != status, "already set");
    entityActive[entity] = status;
    if (status) {
      activeEntities = activeEntities.add(1);
      entityBlockLastClaimedOn[entity] = block.number;
    } else {
      activeEntities = activeEntities.sub(1);
      entityBlockLastClaimedOn[entity] = 0;
    }
  }

  function payFee(uint128 nodeId) public payable {
    address sender = msg.sender == address(this) ? tx.origin : msg.sender;
    bytes memory id = getNodeId(sender, nodeId);
    uint256 blockLastPaidOn = entityNodePaidOnBlock[id];

    if (hasLegacyNode(sender)) {
      migrateLegacyNode(sender);
    }

    bool isExpired = block.number > blockLastPaidOn.add(recurringPaymentCycleInBlocks).add(recurringPaymentCycleInBlocks);

    require(doesNodeExist(sender, nodeId), "doesnt exist");
    require(isExpired == false || msg.sender == address(this), "too late");

    if (isExpired) {
      return;
    }

    if (entityNodeIsBYON[id]) {
      require(msg.value == recurringFeeInWei, "invalid fee");
    } else {
      require(msg.value == recurringNaaSFeeInWei, "invalid fee");
    }

    feeCollector.transfer(msg.value);
    entityNodePaidOnBlock[id] = entityNodePaidOnBlock[id].add(recurringPaymentCycleInBlocks);

    emit Paid(sender, nodeId, entityNodeIsBYON[id], true, entityNodePaidOnBlock[id]);
  }

  function getReward(address entity, uint128 nodeId) public view returns (uint256) {
    return getRewardByBlock(entity, nodeId, block.number);
  }

  function getRewardByBlock(address entity, uint128 nodeId, uint256 blockNumber) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);

    if (hasLegacyNode(entity)) {
      return getRewardByBlockLegacy(entity, blockNumber);
    }

    uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];

    if (blockNumber > block.number) return 0;
    if (blockLastClaimedOn == 0) return 0;
    if (blockNumber < blockLastClaimedOn) return 0;
    if (activeEntities == 0) return 0;
    if (entityNodeIsBYON[id] && !entityNodeIsActive[id]) return 0;

    uint256 rewardNumerator = entityNodeIsBYON[id] ? rewardPerBlockNumerator : naasRewardPerBlockNumerator;
    uint256 rewardDenominator = entityNodeIsBYON[id] ? rewardPerBlockDenominator : naasRewardPerBlockDenominator;
    uint256 newRewardNumerator = entityNodeIsBYON[id] ? rewardPerBlockNumeratorNew : naasRewardPerBlockNumeratorNew;
    uint256 newRewardDenominator = entityNodeIsBYON[id] ? rewardPerBlockDenominatorNew : naasRewardPerBlockDenominatorNew;

    uint256 bonus = address(strongNFTBonus) != address(0)
    ? strongNFTBonus.getBonus(entity, nodeId, blockLastClaimedOn, blockNumber)
    : 0;

    uint256[2] memory rewardBlocks = rewards.blocks(blockLastClaimedOn, rewardPerBlockNewEffectiveBlock, blockNumber);
    uint256 rewardOld = rewardDenominator > 0 ? rewardBlocks[0].mul(rewardNumerator).div(rewardDenominator) : 0;
    uint256 rewardNew = newRewardDenominator > 0 ? rewardBlocks[1].mul(newRewardNumerator).div(newRewardDenominator) : 0;

    return rewardOld.add(rewardNew).add(bonus);
  }

  function getRewardByBlockLegacy(address entity, uint256 blockNumber) public view returns (uint256) {
    if (blockNumber > block.number) return 0;
    if (entityBlockLastClaimedOn[entity] == 0) return 0;
    if (blockNumber < entityBlockLastClaimedOn[entity]) return 0;
    if (activeEntities == 0) return 0;
    uint256 blockResult = blockNumber.sub(entityBlockLastClaimedOn[entity]);
    uint256 rewardNumerator;
    uint256 rewardDenominator;
    if (entityIsNaaS[entity]) {
      rewardNumerator = naasRewardPerBlockNumerator;
      rewardDenominator = naasRewardPerBlockDenominator;
    } else {
      rewardNumerator = rewardPerBlockNumerator;
      rewardDenominator = rewardPerBlockDenominator;
    }
    uint256 rewardPerBlockResult = blockResult.mul(rewardNumerator).div(rewardDenominator);

    return rewardPerBlockResult;
  }

  function claim(uint128 nodeId, uint256 blockNumber, bool toStrongPool) public payable {
    address sender = msg.sender == address(this) || msg.sender == address(strongNFTBonus) ? tx.origin : msg.sender;
    bytes memory id = getNodeId(sender, nodeId);

    if (hasLegacyNode(sender)) {
      migrateLegacyNode(sender);
    }

    uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];
    uint256 blockLastPaidOn = entityNodePaidOnBlock[id];

    require(blockLastClaimedOn != 0, "never claimed");
    require(blockNumber <= block.number, "invalid block");
    require(blockNumber > blockLastClaimedOn, "too soon");
    require(!entityNodeIsBYON[id] || entityNodeIsActive[id], "not active");

    if (
      (!entityNodeIsBYON[id] && recurringNaaSFeeInWei != 0) || (entityNodeIsBYON[id] && recurringFeeInWei != 0)
    ) {
      require(blockNumber < blockLastPaidOn.add(recurringPaymentCycleInBlocks), "pay fee");
    }

    uint256 reward = getRewardByBlock(sender, nodeId, blockNumber);
    require(reward > 0, "no reward");

    uint256 fee = reward.mul(claimingFeeNumerator).div(claimingFeeDenominator);
    require(msg.value >= fee, "invalid fee");

    feeCollector.transfer(msg.value);

    if (toStrongPool) {
      strongToken.approve(address(strongPool), reward);
      strongPool.mineFor(sender, reward);
    } else {
      strongToken.transfer(sender, reward);
    }

    rewardBalance = rewardBalance.sub(reward);
    entityNodeClaimedOnBlock[id] = blockNumber;
    emit Claimed(sender, reward);
  }

  function getRewardAll(address entity, uint256 blockNumber) public view returns (uint256) {
    uint256 rewardsAll = 0;

    for (uint128 i = 1; i <= entityNodeCount[entity]; i++) {
      rewardsAll = rewardsAll.add(getRewardByBlock(entity, i, blockNumber > 0 ? blockNumber : block.number));
    }

    return rewardsAll;
  }

  function doesNodeExist(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodePaidOnBlock[id] > 0;
  }

  function getNodeId(address entity, uint128 nodeId) public view returns (bytes memory) {
    uint128 id = nodeId != 0 ? nodeId : entityNodeCount[entity] + 1;
    return abi.encodePacked(entity, id);
  }

  function getNodePaidOn(address entity, uint128 nodeId) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodePaidOnBlock[id];
  }

  function getNodeFee(address entity, uint128 nodeId) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsBYON[id] ? recurringFeeInWei : recurringNaaSFeeInWei;
  }

  function isNodeActive(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsActive[id] || !entityNodeIsBYON[id];
  }

  function isNodeBYON(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsBYON[id];
  }

  function hasLegacyNode(address entity) public view returns (bool) {
    return entityActive[entity] && entityNodeCount[entity] == 0;
  }

  function approveBYONNode(address entity, uint128 nodeId) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    bytes memory id = getNodeId(entity, nodeId);
    entityNodeIsActive[id] = true;
    entityNodeClaimedOnBlock[id] = block.number;
    activeEntities = activeEntities.add(1);
  }

  function suspendBYONNode(address entity, uint128 nodeId) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    bytes memory id = getNodeId(entity, nodeId);
    entityNodeIsActive[id] = false;
    activeEntities = activeEntities.sub(1);
  }

  function setNodeIsActive(address entity, uint128 nodeId, bool isActive) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");
    bytes memory id = getNodeId(entity, nodeId);

    if (isActive && !entityNodeIsActive[id]) {
      activeEntities = activeEntities.add(1);
      entityNodeClaimedOnBlock[id] = block.number;
    }

    if (!isActive && entityNodeIsActive[id]) {
      activeEntities = activeEntities.sub(1);
    }

    entityNodeIsActive[id] = isActive;
  }

  function setNodeIsNaaS(address entity, uint128 nodeId, bool isNaaS) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");
    bytes memory id = getNodeId(entity, nodeId);

    entityNodeIsBYON[id] = !isNaaS;
  }

  function migrateLegacyNode(address entity) private {
    bytes memory id = getNodeId(entity, 1);
    entityNodeClaimedOnBlock[id] = entityBlockLastClaimedOn[entity];
    entityNodePaidOnBlock[id] = paidOnBlock[entity];
    entityNodeTraunch[id] = traunch[entity];
    entityNodeIsBYON[id] = !entityIsNaaS[entity];
    if (entityNodeIsBYON[id]) {
      entityNodeIsActive[id] = true;
    }
    entityNodeCount[msg.sender] = 1;
  }

  function migrateNode(uint128 nodeId, address to) public {
    if (hasLegacyNode(msg.sender)) {
      migrateLegacyNode(msg.sender);
    }

    if (hasLegacyNode(to)) {
      migrateLegacyNode(to);
    }

    require(doesNodeExist(msg.sender, nodeId), "doesnt exist");

    uint128 toNodeId = entityNodeCount[to] + 1;
    bytes memory fromId = getNodeId(msg.sender, nodeId);
    bytes memory toId = getNodeId(to, toNodeId);

    // move node to another address
    entityNodeIsActive[toId] = entityNodeIsActive[fromId];
    entityNodeIsBYON[toId] = entityNodeIsBYON[fromId];
    entityNodePaidOnBlock[toId] = entityNodePaidOnBlock[fromId];
    entityNodeClaimedOnBlock[toId] = entityNodeClaimedOnBlock[fromId];
    entityNodeTraunch[toId] = entityNodeTraunch[fromId];
    entityNodeCount[to] = entityNodeCount[to] + 1;

    // deactivate node
    entityNodeIsActive[fromId] = false;
    entityNodePaidOnBlock[fromId] = 0;
    entityNodeClaimedOnBlock[fromId] = 0;
    entityNodeCount[msg.sender] = entityNodeCount[msg.sender] - 1;

    emit Migrated(msg.sender, to, nodeId, toNodeId, entityNodeIsBYON[fromId]);
  }

  function claimAll(uint256 blockNumber, bool toStrongPool) public payable {
    for (uint16 i = 1; i <= entityNodeCount[msg.sender]; i++) {
      uint256 reward = getRewardByBlock(msg.sender, i, blockNumber);
      uint256 fee = reward.mul(claimingFeeNumerator).div(claimingFeeDenominator);
      this.claim{value : fee}(i, blockNumber, toStrongPool);
    }
  }

  function payAll() public payable {
    for (uint16 i = 1; i <= entityNodeCount[msg.sender]; i++) {
      bytes memory id = getNodeId(msg.sender, i);
      uint256 fee = entityNodeIsBYON[id] ? recurringFeeInWei : recurringNaaSFeeInWei;
      this.payFee{value : fee}(i);
    }
  }

  function addNFTBonusContract(address _contract) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    strongNFTBonus = StrongNFTBonusInterface(_contract);
  }
}

File 11 of 15: ServiceV9.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;

import "./IERC20.sol";
import "./SafeMath.sol";
import "./StrongPoolInterface.sol";

contract ServiceV9 {
  event Requested(address indexed miner);
  event Claimed(address indexed miner, uint256 reward);

  using SafeMath for uint256;
  bool public initDone;
  address public admin;
  address public pendingAdmin;
  address public superAdmin;
  address public pendingSuperAdmin;
  address public serviceAdmin;
  address public parameterAdmin;
  address payable public feeCollector;

  IERC20 public strongToken;
  StrongPoolInterface public strongPool;

  uint256 public rewardPerBlockNumerator;
  uint256 public rewardPerBlockDenominator;

  uint256 public naasRewardPerBlockNumerator;
  uint256 public naasRewardPerBlockDenominator;

  uint256 public claimingFeeNumerator;
  uint256 public claimingFeeDenominator;

  uint256 public requestingFeeInWei;

  uint256 public strongFeeInWei;

  uint256 public recurringFeeInWei;
  uint256 public recurringNaaSFeeInWei;
  uint256 public recurringPaymentCycleInBlocks;

  uint256 public rewardBalance;

  mapping(address => uint256) public entityBlockLastClaimedOn;

  address[] public entities;
  mapping(address => uint256) public entityIndex;
  mapping(address => bool) public entityActive;
  mapping(address => bool) public requestPending;
  mapping(address => bool) public entityIsNaaS;
  mapping(address => uint256) public paidOnBlock;
  uint256 public activeEntities;

  string public desciption;

  uint256 public claimingFeeInWei;

  uint256 public naasRequestingFeeInWei;

  uint256 public naasStrongFeeInWei;

  bool public removedTokens;

  mapping(address => uint256) public traunch;

  uint256 public currentTraunch;

  mapping(bytes => bool) public entityNodeIsActive;
  mapping(bytes => bool) public entityNodeIsBYON;
  mapping(bytes => uint256) public entityNodeTraunch;
  mapping(bytes => uint256) public entityNodePaidOnBlock;
  mapping(bytes => uint256) public entityNodeClaimedOnBlock;
  mapping(address => uint128) public entityNodeCount;

  event Paid(address indexed entity, uint128 nodeId, bool isBYON, bool isRenewal, uint256 upToBlockNumber);
  event Migrated(address indexed from, address indexed to, uint128 fromNodeId, uint128 toNodeId, bool isBYON);

  function init(
    address strongTokenAddress,
    address strongPoolAddress,
    address adminAddress,
    address superAdminAddress,
    uint256 rewardPerBlockNumeratorValue,
    uint256 rewardPerBlockDenominatorValue,
    uint256 naasRewardPerBlockNumeratorValue,
    uint256 naasRewardPerBlockDenominatorValue,
    uint256 requestingFeeInWeiValue,
    uint256 strongFeeInWeiValue,
    uint256 recurringFeeInWeiValue,
    uint256 recurringNaaSFeeInWeiValue,
    uint256 recurringPaymentCycleInBlocksValue,
    uint256 claimingFeeNumeratorValue,
    uint256 claimingFeeDenominatorValue,
    string memory desc
  ) public {
    require(!initDone, 'init done');
    strongToken = IERC20(strongTokenAddress);
    strongPool = StrongPoolInterface(strongPoolAddress);
    admin = adminAddress;
    superAdmin = superAdminAddress;
    rewardPerBlockNumerator = rewardPerBlockNumeratorValue;
    rewardPerBlockDenominator = rewardPerBlockDenominatorValue;
    naasRewardPerBlockNumerator = naasRewardPerBlockNumeratorValue;
    naasRewardPerBlockDenominator = naasRewardPerBlockDenominatorValue;
    requestingFeeInWei = requestingFeeInWeiValue;
    strongFeeInWei = strongFeeInWeiValue;
    recurringFeeInWei = recurringFeeInWeiValue;
    recurringNaaSFeeInWei = recurringNaaSFeeInWeiValue;
    claimingFeeNumerator = claimingFeeNumeratorValue;
    claimingFeeDenominator = claimingFeeDenominatorValue;
    recurringPaymentCycleInBlocks = recurringPaymentCycleInBlocksValue;
    desciption = desc;
    initDone = true;
  }

  // ADMIN
  // *************************************************************************************

  function updateServiceAdmin(address newServiceAdmin) public {
    require(msg.sender == superAdmin);
    serviceAdmin = newServiceAdmin;
  }

  function updateParameterAdmin(address newParameterAdmin) public {
    require(newParameterAdmin != address(0), 'zero');
    require(msg.sender == superAdmin);
    parameterAdmin = newParameterAdmin;
  }

  function updateFeeCollector(address payable newFeeCollector) public {
    require(newFeeCollector != address(0), 'zero');
    require(msg.sender == superAdmin);
    feeCollector = newFeeCollector;
  }

  function setPendingAdmin(address newPendingAdmin) public {
    require(msg.sender == admin, 'not admin');
    pendingAdmin = newPendingAdmin;
  }

  function acceptAdmin() public {
    require(msg.sender == pendingAdmin && msg.sender != address(0), 'not pendingAdmin');
    admin = pendingAdmin;
    pendingAdmin = address(0);
  }

  function setPendingSuperAdmin(address newPendingSuperAdmin) public {
    require(msg.sender == superAdmin, 'not superAdmin');
    pendingSuperAdmin = newPendingSuperAdmin;
  }

  function acceptSuperAdmin() public {
    require(msg.sender == pendingSuperAdmin && msg.sender != address(0), 'not pendingSuperAdmin');
    superAdmin = pendingSuperAdmin;
    pendingSuperAdmin = address(0);
  }

  // ENTITIES
  // *************************************************************************************

  function getEntities() public view returns (address[] memory) {
    return entities;
  }

  function isEntityActive(address entity) public view returns (bool) {
    return entityActive[entity];
  }

  // TRAUNCH
  // *************************************************************************************

  function updateCurrentTraunch(uint256 value) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    currentTraunch = value;
  }

  function getTraunch(address entity) public view returns (uint256) {
    return traunch[entity];
  }

  // REWARD
  // *************************************************************************************

  function updateRewardPerBlock(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    require(denominator != 0, 'invalid value');
    rewardPerBlockNumerator = numerator;
    rewardPerBlockDenominator = denominator;
  }

  function updateNaaSRewardPerBlock(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    require(denominator != 0, 'invalid value');
    naasRewardPerBlockNumerator = numerator;
    naasRewardPerBlockDenominator = denominator;
  }

  function deposit(uint256 amount) public {
    require(msg.sender == superAdmin, 'not an admin');
    require(amount > 0, 'zero');
    strongToken.transferFrom(msg.sender, address(this), amount);
    rewardBalance = rewardBalance.add(amount);
  }

  function withdraw(address destination, uint256 amount) public {
    require(msg.sender == superAdmin, 'not an admin');
    require(amount > 0, 'zero');
    require(rewardBalance >= amount, 'not enough');
    strongToken.transfer(destination, amount);
    rewardBalance = rewardBalance.sub(amount);
  }

  function removeTokens() public {
    require(!removedTokens, 'already removed');
    require(msg.sender == superAdmin, 'not an admin');
    // removing 2500 STRONG tokens sent in this tx: 0xe27640beda32a5e49aad3b6692790b9d380ed25da0cf8dca7fd5f3258efa600a
    strongToken.transfer(superAdmin, 2500000000000000000000);
    removedTokens = true;
  }

  // FEES
  // *************************************************************************************

  function updateRequestingFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    requestingFeeInWei = feeInWei;
  }

  function updateStrongFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    strongFeeInWei = feeInWei;
  }

  function updateNaasRequestingFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    naasRequestingFeeInWei = feeInWei;
  }

  function updateNaasStrongFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    naasStrongFeeInWei = feeInWei;
  }

  function updateClaimingFee(uint256 numerator, uint256 denominator) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    require(denominator != 0, 'invalid value');
    claimingFeeNumerator = numerator;
    claimingFeeDenominator = denominator;
  }

  function updateRecurringFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    recurringFeeInWei = feeInWei;
  }

  function updateRecurringNaaSFee(uint256 feeInWei) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    recurringNaaSFeeInWei = feeInWei;
  }

  function updateRecurringPaymentCycleInBlocks(uint256 blocks) public {
    require(msg.sender == admin || msg.sender == parameterAdmin || msg.sender == superAdmin, 'not an admin');
    require(blocks > 0, 'zero');
    recurringPaymentCycleInBlocks = blocks;
  }

  // CORE
  // *************************************************************************************

  function requestAccess(bool isNaaS) public payable {
    uint256 rFee;
    uint256 sFee;

    if (hasLegacyNode(msg.sender)) {
      migrateLegacyNode(msg.sender);
    }

    uint128 nodeId = entityNodeCount[msg.sender] + 1;
    bytes memory id = getNodeId(msg.sender, nodeId);

    if (isNaaS) {
      rFee = naasRequestingFeeInWei;
      sFee = naasStrongFeeInWei;
      activeEntities = activeEntities.add(1);
    } else {
      rFee = requestingFeeInWei;
      sFee = strongFeeInWei;
      entityNodeIsBYON[id] = true;
    }

    require(msg.value == rFee, 'invalid fee');

    entityNodePaidOnBlock[id] = block.number;
    entityNodeTraunch[id] = currentTraunch;
    entityNodeClaimedOnBlock[id] = block.number;
    entityNodeCount[msg.sender] = entityNodeCount[msg.sender] + 1;

    feeCollector.transfer(msg.value);
    strongToken.transferFrom(msg.sender, address(this), sFee);
    strongToken.transfer(feeCollector, sFee);

    emit Paid(msg.sender, nodeId, entityNodeIsBYON[id], false, entityNodePaidOnBlock[id].add(recurringPaymentCycleInBlocks));
  }

  function setEntityActiveStatus(address entity, bool status) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');
    uint256 index = entityIndex[entity];
    require(entities[index] == entity, 'invalid entity');
    require(entityActive[entity] != status, 'already set');
    entityActive[entity] = status;
    if (status) {
      activeEntities = activeEntities.add(1);
      entityBlockLastClaimedOn[entity] = block.number;
    } else {
      activeEntities = activeEntities.sub(1);
      entityBlockLastClaimedOn[entity] = 0;
    }
  }

  function setTraunch(address entity, uint256 value) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');

    traunch[entity] = value;
  }

  function payFee(uint128 nodeId) public payable {
    address sender = msg.sender == address(this) ? tx.origin : msg.sender;
    bytes memory id = getNodeId(sender, nodeId);

    if (hasLegacyNode(sender)) {
      migrateLegacyNode(sender);
    }

    require(doesNodeExist(sender, nodeId), 'doesnt exist');

    if (entityNodeIsBYON[id]) {
      require(msg.value == recurringFeeInWei, 'invalid fee');
    } else {
      require(msg.value == recurringNaaSFeeInWei, 'invalid fee');
    }

    feeCollector.transfer(msg.value);
    entityNodePaidOnBlock[id] = entityNodePaidOnBlock[id].add(recurringPaymentCycleInBlocks);

    emit Paid(sender, nodeId, entityNodeIsBYON[id], true, entityNodePaidOnBlock[id]);
  }

  function getReward(address entity, uint128 nodeId) public view returns (uint256) {
    return getRewardByBlock(entity, nodeId, block.number);
  }

  function getRewardByBlock(address entity, uint128 nodeId, uint256 blockNumber) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);

    if (hasLegacyNode(entity)) {
      return getRewardByBlockLegacy(entity, blockNumber);
    }

    uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];

    if (blockNumber > block.number) return 0;
    if (blockLastClaimedOn == 0) return 0;
    if (blockNumber < blockLastClaimedOn) return 0;
    if (activeEntities == 0) return 0;
    if (entityNodeIsBYON[id] && !entityNodeIsActive[id]) return 0;

    uint256 blockResult = blockNumber.sub(blockLastClaimedOn);
    uint256 rewardNumerator;
    uint256 rewardDenominator;

    if (entityNodeIsBYON[id]) {
      rewardNumerator = rewardPerBlockNumerator;
      rewardDenominator = rewardPerBlockDenominator;
    } else {
      rewardNumerator = naasRewardPerBlockNumerator;
      rewardDenominator = naasRewardPerBlockDenominator;
    }

    uint256 rewardPerBlockResult = blockResult.mul(rewardNumerator).div(rewardDenominator);

    return rewardPerBlockResult;
  }

  function getRewardByBlockLegacy(address entity, uint256 blockNumber) public view returns (uint256) {
    if (blockNumber > block.number) return 0;
    if (entityBlockLastClaimedOn[entity] == 0) return 0;
    if (blockNumber < entityBlockLastClaimedOn[entity]) return 0;
    if (activeEntities == 0) return 0;
    uint256 blockResult = blockNumber.sub(entityBlockLastClaimedOn[entity]);
    uint256 rewardNumerator;
    uint256 rewardDenominator;
    if (entityIsNaaS[entity]) {
      rewardNumerator = naasRewardPerBlockNumerator;
      rewardDenominator = naasRewardPerBlockDenominator;
    } else {
      rewardNumerator = rewardPerBlockNumerator;
      rewardDenominator = rewardPerBlockDenominator;
    }
    uint256 rewardPerBlockResult = blockResult.mul(rewardNumerator).div(rewardDenominator);

    return rewardPerBlockResult;
  }

  function claim(uint128 nodeId, uint256 blockNumber, bool toStrongPool) public payable {
    address sender = msg.sender == address(this) ? tx.origin : msg.sender;
    bytes memory id = getNodeId(sender, nodeId);

    if (hasLegacyNode(sender)) {
      migrateLegacyNode(sender);
    }

    uint256 blockLastClaimedOn = entityNodeClaimedOnBlock[id] != 0 ? entityNodeClaimedOnBlock[id] : entityNodePaidOnBlock[id];
    uint256 blockLastPaidOn = entityNodePaidOnBlock[id];

    require(blockLastClaimedOn != 0, 'never claimed');
    require(blockNumber <= block.number, 'invalid block');
    require(blockNumber > blockLastClaimedOn, 'too soon');
    require(!entityNodeIsBYON[id] || entityNodeIsActive[id], 'not active');

    if (
      (!entityNodeIsBYON[id] && recurringNaaSFeeInWei != 0) || (entityNodeIsBYON[id] && recurringFeeInWei != 0)
    ) {
      require(blockNumber < blockLastPaidOn.add(recurringPaymentCycleInBlocks), 'pay fee');
    }

    uint256 reward = getRewardByBlock(sender, nodeId, blockNumber);
    require(reward > 0, 'no reward');

    uint256 fee = reward.mul(claimingFeeNumerator).div(claimingFeeDenominator);
    require(msg.value >= fee, 'invalid fee');

    feeCollector.transfer(msg.value);

    if (toStrongPool) {
      strongToken.approve(address(strongPool), reward);
      strongPool.mineFor(sender, reward);
    } else {
      strongToken.transfer(sender, reward);
    }

    rewardBalance = rewardBalance.sub(reward);
    entityNodeClaimedOnBlock[id] = blockNumber;
    emit Claimed(sender, reward);
  }

  function getRewardAll(address entity, uint256 blockNumber) public view returns (uint256) {
    uint256 rewardsAll = 0;

    for (uint128 i = 1; i <= entityNodeCount[entity]; i++) {
      rewardsAll = rewardsAll.add(getRewardByBlock(entity, i, blockNumber > 0 ? blockNumber : block.number));
    }

    return rewardsAll;
  }

  function doesNodeExist(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodePaidOnBlock[id] > 0;
  }

  function getNodeId(address entity, uint128 nodeId) public view returns (bytes memory) {
    uint128 id = nodeId != 0 ? nodeId : entityNodeCount[entity] + 1;
    return abi.encodePacked(entity, id);
  }

  function getNodePaidOn(address entity, uint128 nodeId) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodePaidOnBlock[id];
  }

  function getNodeFee(address entity, uint128 nodeId) public view returns (uint256) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsBYON[id] ? recurringFeeInWei : recurringNaaSFeeInWei;
  }

  function isNodeActive(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsActive[id] || !entityNodeIsBYON[id];
  }

  function isNodeBYON(address entity, uint128 nodeId) public view returns (bool) {
    bytes memory id = getNodeId(entity, nodeId);
    return entityNodeIsBYON[id];
  }

  function hasLegacyNode(address entity) public view returns (bool) {
    return entityActive[entity] && entityNodeCount[entity] == 0;
  }

  function approveBYONNode(address entity, uint128 nodeId) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');

    bytes memory id = getNodeId(entity, nodeId);
    entityNodeIsActive[id] = true;
    entityNodeClaimedOnBlock[id] = block.number;
    activeEntities = activeEntities.add(1);
  }

  function suspendBYONNode(address entity, uint128 nodeId) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');

    bytes memory id = getNodeId(entity, nodeId);
    entityNodeIsActive[id] = false;
    activeEntities = activeEntities.sub(1);
  }

  function setNodeIsActive(address entity, uint128 nodeId, bool isActive) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');
    bytes memory id = getNodeId(entity, nodeId);

    if (isActive && !entityNodeIsActive[id]) {
      activeEntities = activeEntities.add(1);
      entityNodeClaimedOnBlock[id] = block.number;
    }

    if (!isActive && entityNodeIsActive[id]) {
      activeEntities = activeEntities.sub(1);
    }

    entityNodeIsActive[id] = isActive;
  }

  function setNodeIsNaaS(address entity, uint128 nodeId, bool isNaaS) public {
    require(msg.sender == admin || msg.sender == serviceAdmin || msg.sender == superAdmin, 'not admin');
    bytes memory id = getNodeId(entity, nodeId);

    entityNodeIsBYON[id] = !isNaaS;
  }

  function migrateLegacyNode(address entity) private {
    bytes memory id = getNodeId(entity, 1);
    entityNodeClaimedOnBlock[id] = entityBlockLastClaimedOn[entity];
    entityNodePaidOnBlock[id] = paidOnBlock[entity];
    entityNodeTraunch[id] = traunch[entity];
    entityNodeIsBYON[id] = !entityIsNaaS[entity];
    if (entityNodeIsBYON[id]) {
      entityNodeIsActive[id] = true;
    }
    entityNodeCount[msg.sender] = 1;
  }

  function migrateNode(uint128 nodeId, address to) public {
    if (hasLegacyNode(msg.sender)) {
      migrateLegacyNode(msg.sender);
    }

    if (hasLegacyNode(to)) {
      migrateLegacyNode(to);
    }

    require(doesNodeExist(msg.sender, nodeId), 'doesnt exist');

    uint128 toNodeId = entityNodeCount[to] + 1;
    bytes memory fromId = getNodeId(msg.sender, nodeId);
    bytes memory toId = getNodeId(to, toNodeId);

    // move node to another address
    entityNodeIsActive[toId] = entityNodeIsActive[fromId];
    entityNodeIsBYON[toId] = entityNodeIsBYON[fromId];
    entityNodePaidOnBlock[toId] = entityNodePaidOnBlock[fromId];
    entityNodeClaimedOnBlock[toId] = entityNodeClaimedOnBlock[fromId];
    entityNodeTraunch[toId] = entityNodeTraunch[fromId];
    entityNodeCount[to] = entityNodeCount[to] + 1;

    // deactivate node
    entityNodeIsActive[fromId] = false;
    entityNodePaidOnBlock[fromId] = 0;
    entityNodeClaimedOnBlock[fromId] = 0;
    entityNodeCount[msg.sender] = entityNodeCount[msg.sender] - 1;

    emit Migrated(msg.sender, to, nodeId, toNodeId, entityNodeIsBYON[fromId]);
  }

  function claimAll(uint256 blockNumber, bool toStrongPool) public payable {
    for (uint16 i = 1; i <= entityNodeCount[msg.sender]; i++) {
      uint256 reward = getRewardByBlock(msg.sender, i, blockNumber);
      uint256 fee = reward.mul(claimingFeeNumerator).div(claimingFeeDenominator);
      this.claim{ value: fee }(i, blockNumber, toStrongPool);
    }
  }

  function payAll() public payable {
    for (uint16 i = 1; i <= entityNodeCount[msg.sender]; i++) {
      bytes memory id = getNodeId(msg.sender, i);
      uint256 fee = entityNodeIsBYON[id] ? recurringFeeInWei : recurringNaaSFeeInWei;
      this.payFee{ value: fee }(i);
    }
  }
}

File 12 of 15: StrongNFTBonus.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.6.8;

import "./ServiceInterface.sol";
import "./IERC1155Preset.sol";
import "./SafeMath.sol";
import "./Context.sol";

contract StrongNFTBonus is Context {

  using SafeMath for uint256;

  event Staked(address indexed sender, uint256 tokenId, uint128 nodeId, uint256 block);
  event Unstaked(address indexed sender, uint256 tokenId, uint128 nodeId, uint256 block);

  ServiceInterface public service;
  IERC1155Preset public nft;

  bool public initDone;

  address public serviceAdmin;
  address public superAdmin;

  string[] public nftBonusNames;
  mapping(string => uint256) public nftBonusLowerBound;
  mapping(string => uint256) public nftBonusUpperBound;
  mapping(string => uint256) public nftBonusValue;

  mapping(uint256 => uint256) public nftIdStakedForNodeId;
  mapping(address => mapping(uint128 => uint256)) public entityNodeStakedNftId;
  mapping(address => mapping(uint128 => uint256)) public entityNodeStakedNftBlock;

  function init(address serviceContract, address nftContract, address serviceAdminAddress, address superAdminAddress) public {
    require(initDone == false, "init done");

    serviceAdmin = serviceAdminAddress;
    superAdmin = superAdminAddress;
    service = ServiceInterface(serviceContract);
    nft = IERC1155Preset(nftContract);
    initDone = true;
  }

  function isNftStaked(uint256 _tokenId) public view returns (bool) {
    return nftIdStakedForNodeId[_tokenId] != 0;
  }

  function getNftStakedForNodeId(uint256 _tokenId) public view returns (uint256) {
    return nftIdStakedForNodeId[_tokenId];
  }

  function getStakedNftId(address _entity, uint128 _nodeId) public view returns (uint256) {
    return entityNodeStakedNftId[_entity][_nodeId];
  }

  function getStakedNftBlock(address _entity, uint128 _nodeId) public view returns (uint256) {
    return entityNodeStakedNftBlock[_entity][_nodeId];
  }

  function getBonus(address _entity, uint128 _nodeId, uint256 _fromBlock, uint256 _toBlock) public view returns (uint256) {
    uint256 nftId = entityNodeStakedNftId[_entity][_nodeId];

    if (nftId == 0) return 0;
    if (nftId < nftBonusLowerBound["BRONZE"]) return 0;
    if (nftId > nftBonusUpperBound["BRONZE"]) return 0;
    if (nft.balanceOf(_entity, nftId) == 0) return 0;
    if (_fromBlock >= _toBlock) return 0;

    uint256 stakedAtBlock = entityNodeStakedNftBlock[_entity][_nodeId];

    if (stakedAtBlock == 0) return 0;

    uint256 startFromBlock = stakedAtBlock > _fromBlock ? stakedAtBlock : _fromBlock;

    if (startFromBlock >= _toBlock) return 0;

    return _toBlock.sub(startFromBlock).mul(nftBonusValue["BRONZE"]);
  }

  function stakeNFT(uint256 _tokenId, uint128 _nodeId) public payable {
    require(nft.balanceOf(_msgSender(), _tokenId) != 0, "not enough");
    require(_tokenId >= nftBonusLowerBound["BRONZE"] && _tokenId <= nftBonusUpperBound["BRONZE"], "not eligible");
    require(nftIdStakedForNodeId[_tokenId] == 0, "already staked");
    require(service.doesNodeExist(_msgSender(), _nodeId), "node doesnt exist");

    nftIdStakedForNodeId[_tokenId] = _nodeId;
    entityNodeStakedNftId[_msgSender()][_nodeId] = _tokenId;
    entityNodeStakedNftBlock[_msgSender()][_nodeId] = block.number;

    emit Staked(msg.sender, _tokenId, _nodeId, block.number);
  }

  function unStakeNFT(uint256 _tokenId, uint128 _nodeId, uint256 _blockNumber) public payable {
    require(nft.balanceOf(_msgSender(), _tokenId) != 0, "not enough");
    require(nftIdStakedForNodeId[_tokenId] == _nodeId, "not this node");

    service.claim{value : msg.value}(_nodeId, _blockNumber, false);

    nftIdStakedForNodeId[_tokenId] = 0;
    entityNodeStakedNftId[_msgSender()][_nodeId] = 0;
    entityNodeStakedNftBlock[_msgSender()][_nodeId] = 0;

    emit Unstaked(msg.sender, _tokenId, _nodeId, _blockNumber);
  }

  function updateBonus(string memory _name, uint256 _lowerBound, uint256 _upperBound, uint256 _value) public {
    require(msg.sender == serviceAdmin || msg.sender == superAdmin, "not admin");

    bool alreadyExit = false;
    for (uint i = 0; i < nftBonusNames.length; i++) {
      if (keccak256(abi.encode(nftBonusNames[i])) == keccak256(abi.encode(_name))) {
        alreadyExit = true;
      }
    }

    if (!alreadyExit) {
      nftBonusNames.push(_name);
    }

    nftBonusLowerBound[_name] = _lowerBound;
    nftBonusUpperBound[_name] = _upperBound;
    nftBonusValue[_name] = _value;
  }

  function updateContracts(address serviceContract, address nftContract) public {
    require(msg.sender == superAdmin, "not admin");
    service = ServiceInterface(serviceContract);
    nft = IERC1155Preset(nftContract);
  }

  function updateServiceAdmin(address newServiceAdmin) public {
    require(msg.sender == superAdmin, "not admin");
    serviceAdmin = newServiceAdmin;
  }
}

File 13 of 15: StrongNFTBonusInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface StrongNFTBonusInterface {
  function getBonus(address _entity, uint128 _nodeId, uint256 _fromBlock, uint256 _toBlock) external view returns (uint256);
}

File 14 of 15: StrongNFTClaimerInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface StrongNFTClaimerInterface {
  function tokenNameAddressClaimed(string memory, address) external view returns(bool);
}

File 15 of 15: StrongPoolInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;

interface StrongPoolInterface {
  function mineFor(address miner, uint256 amount) external;
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"NftToken","outputs":[{"internalType":"contract IERC1155Preset","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimingFeeInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenContract","type":"address"},{"internalType":"address","name":"_serviceAdminAddress","type":"address"},{"internalType":"address","name":"_superAdminAddress","type":"address"},{"internalType":"uint256","name":"_counterValue","type":"uint256"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initDone","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"isEligible","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_sig","type":"bytes"}],"name":"recoverSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"serviceAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenCounter","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"updateAddressClaimed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_valueWei","type":"uint256"}],"name":"updateClaimingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_counterValue","type":"uint256"}],"name":"updateCounterValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_address","type":"address"}],"name":"updateFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50610c0e806100206000396000f3fe6080604052600436106100f35760003560e01c8063b54d5a9c1161008a578063d082e38111610059578063d082e381146104be578063d2c35ce8146104d3578063da998dca14610506578063fed0a20e1461051b576100f3565b8063b54d5a9c146103a1578063c2b2fdca146103dc578063c415b95c14610403578063c63ff8dd14610418576100f3565b806346639dba116100c657806346639dba146101945780635dcbc01b146101dd578063772dc32f146102b457806397aba7f9146102e7576100f3565b80630f1139cf146100f857806328e4dc311461012457806329575f6a146101555780632a5a6c411461016a575b600080fd5b34801561010457600080fd5b506101226004803603602081101561011b57600080fd5b5035610530565b005b34801561013057600080fd5b50610139610595565b604080516001600160a01b039092168252519081900360200190f35b34801561016157600080fd5b506101396105a4565b34801561017657600080fd5b506101226004803603602081101561018d57600080fd5b50356105b3565b3480156101a057600080fd5b50610122600480360360808110156101b757600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135610626565b3480156101e957600080fd5b506102a06004803603604081101561020057600080fd5b6001600160a01b03823516919081019060408101602082013564010000000081111561022b57600080fd5b82018360208201111561023d57600080fd5b8035906020019184600183028401116401000000008311171561025f57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506106d1945050505050565b604080519115158252519081900360200190f35b3480156102c057600080fd5b506102a0600480360360208110156102d757600080fd5b50356001600160a01b0316610776565b3480156102f357600080fd5b506101396004803603604081101561030a57600080fd5b8135919081019060408101602082013564010000000081111561032c57600080fd5b82018360208201111561033e57600080fd5b8035906020019184600183028401116401000000008311171561036057600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061078b945050505050565b3480156103ad57600080fd5b50610122600480360360408110156103c457600080fd5b506001600160a01b038135169060200135151561080f565b3480156103e857600080fd5b506103f161089a565b60408051918252519081900360200190f35b34801561040f57600080fd5b506101396108a0565b6101226004803603602081101561042e57600080fd5b81019060208101813564010000000081111561044957600080fd5b82018360208201111561045b57600080fd5b8035906020019184600183028401116401000000008311171561047d57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506108af945050505050565b3480156104ca57600080fd5b506103f1610a5c565b3480156104df57600080fd5b50610122600480360360208110156104f657600080fd5b50356001600160a01b0316610a62565b34801561051257600080fd5b50610139610b28565b34801561052757600080fd5b506102a0610b37565b6001546001600160a01b031633148061055357506002546001600160a01b031633145b610590576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b600455565b6000546001600160a01b031681565b6002546001600160a01b031681565b6001546001600160a01b03163314806105d657506002546001600160a01b031633145b610613576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b6040805160208101909152819052600555565b600054600160a01b900460ff1615610671576040805162461bcd60e51b8152602060048201526009602482015268696e697420646f6e6560b81b604482015290519081900360640190fd5b60008054600180546001600160a01b039687166001600160a01b0319918216179091556002805495871695821695909517909455604080516020810190915283905260059290925560ff60a01b199390941691161716600160a01b179055565b60008061070f8460405160200180826001600160a01b031660601b815260140191505060405160208183030381529060405280519060200120610b47565b9050600061071d828561078b565b6001600160a01b03861660009081526006602052604090205490915060ff1615801561076d57506002546001600160a01b038281169116148061076d57506001546001600160a01b038281169116145b95945050505050565b60066020526000908152604090205460ff1681565b60008060008061079a85610b98565b92509250925060018684848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156107fa573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6001546001600160a01b031633148061083257506002546001600160a01b031633145b61086f576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b60045481565b6003546001600160a01b031681565b60045434146108f3576040805162461bcd60e51b815260206004820152600b60248201526a696e76616c69642066656560a81b604482015290519081900360640190fd5b6109046108fe610bc7565b826106d1565b610944576040805162461bcd60e51b815260206004820152600c60248201526b6e6f7420656c696769626c6560a01b604482015290519081900360640190fd5b6000546001600160a01b031663731133e961095d610bc7565b6109676005610bcb565b604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526001604483015260806064830152600060848301819052905160c48084019382900301818387803b1580156109c857600080fd5b505af11580156109dc573d6000803e3d6000fd5b505050506109ea6005610bcf565b6001600660006109f8610bc7565b6001600160a01b039081168252602082019290925260409081016000908120805494151560ff199095169490941790935560035490519116913480156108fc02929091818181858888f19350505050158015610a58573d6000803e3d6000fd5b5050565b60055481565b6001600160a01b038116610aa6576040805162461bcd60e51b815260206004808301919091526024820152637a65726f60e01b604482015290519081900360640190fd5b6001546001600160a01b0316331480610ac957506002546001600160a01b031633145b610b06576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b600054600160a01b900460ff1681565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b60008060008351604114610bab57600080fd5b5050506020810151604082015160609092015160001a92909190565b3390565b5490565b8054600101905556fea26469706673582212202a3c9ee4cc9201caddb5b812c8e32b3be25ec11ddae0df11780a16520406d51e64736f6c634300060c0033

Deployed Bytecode

0x6080604052600436106100f35760003560e01c8063b54d5a9c1161008a578063d082e38111610059578063d082e381146104be578063d2c35ce8146104d3578063da998dca14610506578063fed0a20e1461051b576100f3565b8063b54d5a9c146103a1578063c2b2fdca146103dc578063c415b95c14610403578063c63ff8dd14610418576100f3565b806346639dba116100c657806346639dba146101945780635dcbc01b146101dd578063772dc32f146102b457806397aba7f9146102e7576100f3565b80630f1139cf146100f857806328e4dc311461012457806329575f6a146101555780632a5a6c411461016a575b600080fd5b34801561010457600080fd5b506101226004803603602081101561011b57600080fd5b5035610530565b005b34801561013057600080fd5b50610139610595565b604080516001600160a01b039092168252519081900360200190f35b34801561016157600080fd5b506101396105a4565b34801561017657600080fd5b506101226004803603602081101561018d57600080fd5b50356105b3565b3480156101a057600080fd5b50610122600480360360808110156101b757600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135610626565b3480156101e957600080fd5b506102a06004803603604081101561020057600080fd5b6001600160a01b03823516919081019060408101602082013564010000000081111561022b57600080fd5b82018360208201111561023d57600080fd5b8035906020019184600183028401116401000000008311171561025f57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506106d1945050505050565b604080519115158252519081900360200190f35b3480156102c057600080fd5b506102a0600480360360208110156102d757600080fd5b50356001600160a01b0316610776565b3480156102f357600080fd5b506101396004803603604081101561030a57600080fd5b8135919081019060408101602082013564010000000081111561032c57600080fd5b82018360208201111561033e57600080fd5b8035906020019184600183028401116401000000008311171561036057600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955061078b945050505050565b3480156103ad57600080fd5b50610122600480360360408110156103c457600080fd5b506001600160a01b038135169060200135151561080f565b3480156103e857600080fd5b506103f161089a565b60408051918252519081900360200190f35b34801561040f57600080fd5b506101396108a0565b6101226004803603602081101561042e57600080fd5b81019060208101813564010000000081111561044957600080fd5b82018360208201111561045b57600080fd5b8035906020019184600183028401116401000000008311171561047d57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295506108af945050505050565b3480156104ca57600080fd5b506103f1610a5c565b3480156104df57600080fd5b50610122600480360360208110156104f657600080fd5b50356001600160a01b0316610a62565b34801561051257600080fd5b50610139610b28565b34801561052757600080fd5b506102a0610b37565b6001546001600160a01b031633148061055357506002546001600160a01b031633145b610590576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b600455565b6000546001600160a01b031681565b6002546001600160a01b031681565b6001546001600160a01b03163314806105d657506002546001600160a01b031633145b610613576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b6040805160208101909152819052600555565b600054600160a01b900460ff1615610671576040805162461bcd60e51b8152602060048201526009602482015268696e697420646f6e6560b81b604482015290519081900360640190fd5b60008054600180546001600160a01b039687166001600160a01b0319918216179091556002805495871695821695909517909455604080516020810190915283905260059290925560ff60a01b199390941691161716600160a01b179055565b60008061070f8460405160200180826001600160a01b031660601b815260140191505060405160208183030381529060405280519060200120610b47565b9050600061071d828561078b565b6001600160a01b03861660009081526006602052604090205490915060ff1615801561076d57506002546001600160a01b038281169116148061076d57506001546001600160a01b038281169116145b95945050505050565b60066020526000908152604090205460ff1681565b60008060008061079a85610b98565b92509250925060018684848460405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156107fa573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6001546001600160a01b031633148061083257506002546001600160a01b031633145b61086f576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b6001600160a01b03919091166000908152600660205260409020805460ff1916911515919091179055565b60045481565b6003546001600160a01b031681565b60045434146108f3576040805162461bcd60e51b815260206004820152600b60248201526a696e76616c69642066656560a81b604482015290519081900360640190fd5b6109046108fe610bc7565b826106d1565b610944576040805162461bcd60e51b815260206004820152600c60248201526b6e6f7420656c696769626c6560a01b604482015290519081900360640190fd5b6000546001600160a01b031663731133e961095d610bc7565b6109676005610bcb565b604080516001600160e01b031960e086901b1681526001600160a01b03909316600484015260248301919091526001604483015260806064830152600060848301819052905160c48084019382900301818387803b1580156109c857600080fd5b505af11580156109dc573d6000803e3d6000fd5b505050506109ea6005610bcf565b6001600660006109f8610bc7565b6001600160a01b039081168252602082019290925260409081016000908120805494151560ff199095169490941790935560035490519116913480156108fc02929091818181858888f19350505050158015610a58573d6000803e3d6000fd5b5050565b60055481565b6001600160a01b038116610aa6576040805162461bcd60e51b815260206004808301919091526024820152637a65726f60e01b604482015290519081900360640190fd5b6001546001600160a01b0316331480610ac957506002546001600160a01b031633145b610b06576040805162461bcd60e51b81526020600482015260096024820152683737ba1030b236b4b760b91b604482015290519081900360640190fd5b600380546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b600054600160a01b900460ff1681565b604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083019490945282518083039094018452605c909101909152815191012090565b60008060008351604114610bab57600080fd5b5050506020810151604082015160609092015160001a92909190565b3390565b5490565b8054600101905556fea26469706673582212202a3c9ee4cc9201caddb5b812c8e32b3be25ec11ddae0df11780a16520406d51e64736f6c634300060c0033

Deployed Bytecode Sourcemap

179:2917:12:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2691:175;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2691:175:12;;:::i;:::-;;262:30;;;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;262:30:12;;;;;;;;;;;;;;351:25;;;;;;;;;;;;;:::i;2489:198::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2489:198:12;;:::i;545:395::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;545:395:12;;;;;;;;;;;;;;;;;;;;;;:::i;944:308::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;944:308:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;944:308:12;;-1:-1:-1;944:308:12;;-1:-1:-1;;;;;944:308:12:i;:::-;;;;;;;;;;;;;;;;;;494:46;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;494:46:12;-1:-1:-1;;;;;494:46:12;;:::i;1638:191::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1638:191:12;;-1:-1:-1;1638:191:12;;-1:-1:-1;;;;;1638:191:12:i;2290:195::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2290:195:12;;;;;;;;;;:::i;419:31::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;380:35;;;;;;;;;;;;;:::i;1256:361::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1256:361:12;;-1:-1:-1;1256:361:12;;-1:-1:-1;;;;;1256:361:12:i;454:36::-;;;;;;;;;;;;;:::i;2870:223::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2870:223:12;-1:-1:-1;;;;;2870:223:12;;:::i;320:27::-;;;;;;;;;;;;;:::i;296:20::-;;;;;;;;;;;;;:::i;2691:175::-;2772:12;;-1:-1:-1;;;;;2772:12:12;2758:10;:26;;:54;;-1:-1:-1;2802:10:12;;-1:-1:-1;;;;;2802:10:12;2788;:24;2758:54;2750:76;;;;;-1:-1:-1;;;2750:76:12;;;;;;;;;;;;-1:-1:-1;;;2750:76:12;;;;;;;;;;;;;;;2833:16;:28;2691:175::o;262:30::-;;;-1:-1:-1;;;;;262:30:12;;:::o;351:25::-;;;-1:-1:-1;;;;;351:25:12;;:::o;2489:198::-;2575:12;;-1:-1:-1;;;;;2575:12:12;2561:10;:26;;:54;;-1:-1:-1;2605:10:12;;-1:-1:-1;;;;;2605:10:12;2591;:24;2561:54;2553:76;;;;;-1:-1:-1;;;2553:76:12;;;;;;;;;;;;-1:-1:-1;;;2553:76:12;;;;;;;;;;;;;;;2651:31;;;;;;;;;;;;2636:12;:46;2489:198::o;545:395::-;705:8;;-1:-1:-1;;;705:8:12;;;;:17;697:39;;;;;-1:-1:-1;;;697:39:12;;;;;;;;;;;;-1:-1:-1;;;697:39:12;;;;;;;;;;;;;;;743:8;:41;;;790:35;;-1:-1:-1;;;;;790:35:12;;;-1:-1:-1;;;;;;790:35:12;;;;;;;831:10;:31;;;;;;;;;;;;;;;883;;;;;;;;;;;;868:12;:46;;;;-1:-1:-1;;;;743:41:12;;;;;;;920:15;-1:-1:-1;;;920:15:12;;;545:395::o;944:308::-;1028:4;1040:12;1055:47;1091:8;1074:26;;;;;;-1:-1:-1;;;;;1074:26:12;;;;;;;;;;;;;;;;;;;;;;1064:37;;;;;;1055:8;:47::i;:::-;1040:62;;1108:14;1125:31;1139:4;1145:10;1125:13;:31::i;:::-;-1:-1:-1;;;;;1171:24:12;;;;;;:14;:24;;;;;;1108:48;;-1:-1:-1;1171:24:12;;1170:25;:77;;;;-1:-1:-1;1210:10:12;;-1:-1:-1;;;;;1200:20:12;;;1210:10;;1200:20;;:46;;-1:-1:-1;1234:12:12;;-1:-1:-1;;;;;1224:22:12;;;1234:12;;1224:22;1200:46;1163:84;944:308;-1:-1:-1;;;;;944:308:12:o;494:46::-;;;;;;;;;;;;;;;:::o;1638:191::-;1716:7;1732;1741:9;1752;1765:20;1780:4;1765:14;:20::i;:::-;1731:54;;;;;;1799:25;1809:5;1816:1;1819;1822;1799:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1799:25:12;;-1:-1:-1;;1799:25:12;;;1638:191;-1:-1:-1;;;;;;;1638:191:12:o;2290:195::-;2386:12;;-1:-1:-1;;;;;2386:12:12;2372:10;:26;;:54;;-1:-1:-1;2416:10:12;;-1:-1:-1;;;;;2416:10:12;2402;:24;2372:54;2364:76;;;;;-1:-1:-1;;;2364:76:12;;;;;;;;;;;;-1:-1:-1;;;2364:76:12;;;;;;;;;;;;;;;-1:-1:-1;;;;;2447:24:12;;;;;;;;:14;:24;;;;;:33;;-1:-1:-1;;2447:33:12;;;;;;;;;;2290:195::o;419:31::-;;;;:::o;380:35::-;;;-1:-1:-1;;;;;380:35:12;;:::o;1256:361::-;1338:16;;1325:9;:29;1317:53;;;;;-1:-1:-1;;;1317:53:12;;;;;;;;;;;;-1:-1:-1;;;1317:53:12;;;;;;;;;;;;;;;1384:36;1395:12;:10;:12::i;:::-;1409:10;1384;:36::i;:::-;1376:61;;;;;-1:-1:-1;;;1376:61:12;;;;;;;;;;;;-1:-1:-1;;;1376:61:12;;;;;;;;;;;;;;;1444:8;;-1:-1:-1;;;;;1444:8:12;:13;1458:12;:10;:12::i;:::-;1472:22;:12;:20;:22::i;:::-;1444:58;;;-1:-1:-1;;;;;;1444:58:12;;;;;;;-1:-1:-1;;;;;1444:58:12;;;;;;;;;;;;;;1496:1;1444:58;;;;;;;;;-1:-1:-1;1444:58:12;;;;;;;;;;;;;;;;;;-1:-1:-1;1444:58:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1508:24;:12;:22;:24::i;:::-;1569:4;1538:14;:28;1553:12;:10;:12::i;:::-;-1:-1:-1;;;;;1538:28:12;;;;;;;;;;;;;;;;-1:-1:-1;1538:28:12;;;:35;;;;;-1:-1:-1;;1538:35:12;;;;;;;;;;1580:12;;:32;;:12;;;1602:9;1580:32;;;;;1602:9;;1580:32;-1:-1:-1;1580:32:12;1602:9;1580:12;:32;;;;;;;;;;;;;;;;;;;;;1256:361;:::o;454:36::-;;;;:::o;2870:223::-;-1:-1:-1;;;;;2945:22:12;;2937:39;;;;;-1:-1:-1;;;2937:39:12;;;;;;;;;;;;;;;-1:-1:-1;;;2937:39:12;;;;;;;;;;;;;;;3004:12;;-1:-1:-1;;;;;3004:12:12;2990:10;:26;;:54;;-1:-1:-1;3034:10:12;;-1:-1:-1;;;;;3034:10:12;3020;:24;2990:54;2982:76;;;;;-1:-1:-1;;;2982:76:12;;;;;;;;;;;;-1:-1:-1;;;2982:76:12;;;;;;;;;;;;;;;3065:12;:23;;-1:-1:-1;;;;;;3065:23:12;-1:-1:-1;;;;;3065:23:12;;;;;;;;;;2870:223::o;320:27::-;;;-1:-1:-1;;;;;320:27:12;;:::o;296:20::-;;;-1:-1:-1;;;296:20:12;;;;;:::o;1833:153::-;1921:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1911:70;;;;;;1833:153::o;1990:284::-;2056:7;2065:9;2076;2101:4;:11;2116:2;2101:17;2093:26;;;;;;-1:-1:-1;;;2164:2:12;2154:13;;2148:20;2196:2;2186:13;;2180:20;2236:2;2226:13;;;2220:20;2217:1;2212:29;;2148:20;;2180;1990:284::o;590:104:0:-;677:10;590:104;:::o;1092:112:1:-;1183:14;;1092:112::o;1210:178::-;1362:19;;1380:1;1362:19;;;1210:178::o

Swarm Source

ipfs://2a3c9ee4cc9201caddb5b812c8e32b3be25ec11ddae0df11780a16520406d51e

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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