ETH Price: $1,980.50 (-5.35%)

Contract

0x8F9f04cD33d4480fd39b1480559EC20b4e28CE0b
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Funded By

N/A

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

2 Internal Transactions found.

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Method Block
From
To
-132423492021-09-17 9:15:261631 days ago1631870126
0x8F9f04cD...b4e28CE0b
0 ETH
-130736092021-08-22 6:52:111657 days ago1629615131  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
Contract Self Destruct called at Txn Hash 0x5458febf469ea9b755dafaec75bc8164d95d421d20970f2bcf31e6d14f3d5430


Contract Source Code Verified (Exact Match)

Contract Name:
Booster

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, Apache-2.0 license
/*
 * Copyright (C) 2021 The Wolfpack
 * This file is part of wolves.finance - https://github.com/wolvesofwallstreet/wolves.finance
 *
 * SPDX-License-Identifier: Apache-2.0
 * See the file LICENSES/README.md for more information.
 */

pragma solidity 0.7.6;

import '../../0xerc1155/interfaces/IERC1155.sol';
import '../../0xerc1155/utils/SafeERC20.sol';
import '../../0xerc1155/utils/SafeMath.sol';
import '../../0xerc1155/access/AccessControl.sol';

import '../investment/interfaces/IRewardHandler.sol';
import '../token/interfaces/IWOWSERC1155.sol';
import '../utils/TokenIds.sol';

import './interfaces/IBooster.sol';

contract Booster is IBooster, AccessControl {
  using SafeERC20 for IERC20;
  using SafeMath for uint256;
  using TokenIds for uint256;

  //////////////////////////////////////////////////////////////////////////////
  // Constants
  //////////////////////////////////////////////////////////////////////////////

  bytes32 public constant CONTROLLER_ROLE = bytes32('CONTROLLER');

  // 30 days in seconds multiplied by 10 (10% per month)
  uint256 private constant MONTHLY_REWARD = 25920000;

  // Maximum rewards provided from tokenomics
  uint256 private constant MAX_TOKENOMICS_REWARDS = 7500000000000000000000;

  // SECONDS PER YEAR
  uint256 private constant SECONDS_PER_YEAR = 360 * 86400;

  //////////////////////////////////////////////////////////////////////////////
  // State
  //////////////////////////////////////////////////////////////////////////////

  // The rewardHandler to distribute rewards
  IRewardHandler public rewardHandler;

  // The SFT contract to validate recipients
  IWOWSERC1155 public sftHolder;

  // Our timelock
  struct TimeLock {
    uint256 totalAmount;
    uint256 pendingAmount;
    uint256 providedAmount;
    uint256 last;
    uint256 end;
    uint256 apr;
    uint32 fee;
  }
  mapping(address => TimeLock) public timeLocks;

  // Reward definition (1 / 3 / 6 month)
  struct RewardDefinition {
    uint256 length; // in seconds
    uint256 apr; // 1E18 == 100%
  }
  RewardDefinition[] public rewardDefinitions;

  // Overall provided rewards
  uint256 public rewardsProvided;

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

  modifier onlyAdmin() {
    require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), 'B: Only admin');
    _;
  }

  modifier onlyController() {
    require(hasRole(CONTROLLER_ROLE, _msgSender()), 'B: Only controller');
    _;
  }

  //////////////////////////////////////////////////////////////////////////////
  // Events
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Temporary tokens owned by recipient were locked
   *
   * Tokens are owned by recipient for a specific duration of seconds.
   *
   * @param recipient The recipient of the rewards
   * @param amountIn The amount of tokens in
   * @param amountLocked The amount of tokens locked (amount plus reward)
   */
  event TokensLocked(
    address indexed recipient,
    uint256 amountIn,
    uint256 amountLocked
  );

  /**
   * @dev More amount was added into existing lock pool
   *
   * @param recipient The SFT receiving the rewards
   * @param amount The amount of tokens claimed
   * @param amountLocked The amount of tokens locked
   */
  event MoreAdded(
    address indexed recipient,
    uint256 amount,
    uint256 amountLocked
  );

  /**
   * @dev Rrewards were claimed either into wallet or re-locked
   *
   * @param recipient The recipient of the rewards
   * @param amount The amount of tokens claimed
   */
  event RewardsClaimed(address indexed recipient, uint256 amount);

  //////////////////////////////////////////////////////////////////////////////
  // Initialization
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Constructs implementation part and provides admin access
   * for a later selfDestruct call.
   */
  constructor(address admin) {
    // For administrative calls
    _setupRole(DEFAULT_ADMIN_ROLE, admin);
  }

  /**
   * @dev One time initializer for proxy
   */
  function initialize(address admin, address rewardHandler_) external {
    // Validate parameters
    require(
      getRoleMemberCount(DEFAULT_ADMIN_ROLE) == 0,
      'B: Already initialized'
    );

    // For administrative calls
    _setupRole(DEFAULT_ADMIN_ROLE, admin);
    _setRewardHandler(rewardHandler_);

    // Reward definition: 180 days / 175% APR
    rewardDefinitions.push(RewardDefinition(15552000, 1750000000000000000));

    // Reward definition: 90 days / 130% APR
    rewardDefinitions.push(RewardDefinition(7776000, 1300000000000000000));

    // Reward definition: 30 days / 100% APR
    rewardDefinitions.push(RewardDefinition(2592000, 1000000000000000000));
  }

  //////////////////////////////////////////////////////////////////////////////
  // Implementation of {IBooster}
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev See {IBooster-getRewardInfo}
   */
  function getRewardInfo(uint256[] memory tokenIds)
    external
    view
    override
    returns (
      uint256[] memory locked,
      uint256[] memory pending,
      uint256[] memory apr,
      uint256[] memory secsLeft
    )
  {
    locked = new uint256[](tokenIds.length);
    pending = new uint256[](tokenIds.length);
    apr = new uint256[](tokenIds.length);
    secsLeft = new uint256[](tokenIds.length);

    uint256 ts = _getTimestamp();

    for (uint256 i = 0; i < tokenIds.length; ++i) {
      address cfolio = sftHolder.tokenIdToAddress(tokenIds[i].toSftTokenId());
      require(cfolio != address(0), 'B: Invalid tokenId');

      TimeLock storage currentLock = timeLocks[cfolio];
      locked[i] = currentLock.totalAmount;
      pending[i] = _getPendingAmount(currentLock, ts);
      apr[i] = currentLock.apr;
      secsLeft[i] = currentLock.end >= ts
        ? currentLock.end.sub(ts)
        : uint256(-1);
    }
  }

  /**
   * @dev See {IBooster-distributeFromFarm}
   */
  function distributeFromFarm(
    address, /* farm*/
    address recipient,
    uint256 amount,
    uint32 fee
  ) external override onlyController {
    // Validate input
    require(recipient != address(0), 'B: Invalid recipient');

    if (sftHolder.addressToTokenId(recipient) != uint256(-1)) {
      // Prepare locking amount into SFT
      TimeLock storage currentLock = timeLocks[recipient];

      if (currentLock.end != 0) {
        uint256 ts = _getTimestamp();

        // Update pending rewards
        _updatePendingRewards(currentLock, ts);

        // Add more
        require(currentLock.fee == fee, 'B: Fee change');

        // Add amount to total
        _addMore(recipient, currentLock, ts, amount);
      } else {
        // Validate state
        require(
          currentLock.totalAmount == 0 || currentLock.fee == fee,
          'B: Fee mismatch'
        );

        // Prepare for a new lock
        currentLock.fee = fee;
        currentLock.totalAmount = currentLock.totalAmount.add(amount);
      }
    } else {
      rewardHandler.distribute2(recipient, amount, fee);
    }
  }

  /**
   * @dev See {IBooster-lock}
   */
  function lock(address recipient, uint256 lockPeriod)
    external
    override
    onlyController
  {
    uint256 ts = _getTimestamp();

    TimeLock storage currentLock = timeLocks[recipient];

    // Verify that we have already updated lock (from preceeding
    // {distributeFromFarm} call)
    require(currentLock.end == 0 || currentLock.last == ts, 'B: Sync failure');

    if (currentLock.end == 0) {
      // Start a new lock session. Calculate the amount we provide.
      for (uint256 i = 0; i < rewardDefinitions.length; ++i) {
        if (lockPeriod >= rewardDefinitions[i].length) {
          uint256 reward = (
            currentLock.totalAmount.mul(rewardDefinitions[i].length).mul(
              rewardDefinitions[i].apr
            )
          ).div(SECONDS_PER_YEAR.mul(1E18));

          currentLock.totalAmount = currentLock.totalAmount.add(reward);
          currentLock.end = ts + rewardDefinitions[i].length;
          currentLock.apr = rewardDefinitions[i].apr;
          currentLock.last = ts;

          rewardsProvided.add(reward);

          // Validate state
          _verifyRewardsProvided();

          // Dispatch event
          emit TokensLocked(
            recipient,
            currentLock.totalAmount.sub(reward),
            currentLock.totalAmount
          );

          // Candidate found, return
          return;
        }
      }

      // We never should reach this line
      revert('B: LockPeriod wrong');
    }
  }

  /**
   * @dev See {IBooster-claimRewards}
   */
  function claimRewards(uint256 sftTokenId, bool reLock) external override {
    // Validate access
    address cfolio = sftHolder.tokenIdToAddress(sftTokenId);
    require(cfolio != address(0), 'B: Invalid cfolio');
    require(
      IERC1155(address(sftHolder)).balanceOf(_msgSender(), sftTokenId) == 1,
      'B: Access denied'
    );

    TimeLock storage currentLock = timeLocks[cfolio];
    uint256 ts = _getTimestamp();

    _updatePendingRewards(currentLock, ts);

    uint256 claimable = currentLock.pendingAmount;
    currentLock.pendingAmount = 0;
    currentLock.providedAmount.add(claimable);

    // Dispatch event
    emit RewardsClaimed(cfolio, claimable);

    // Update state
    if (reLock) {
      _addMore(cfolio, currentLock, ts, claimable);
    } else {
      rewardHandler.distribute2(_msgSender(), claimable, currentLock.fee);
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  // Maintanance functions
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Self destruct implementation contract
   */
  function destructContract(address payable newContract) external onlyAdmin {
    // slither-disable-next-line suicidal
    selfdestruct(newContract);
  }

  /**
   * @dev Set reward handler in case it will be upgraded
   */
  function setRewardHandler(address rewardHandler_) external onlyAdmin {
    _setRewardHandler(rewardHandler_);
  }

  /**
   * @dev Set sftHolder contract which is deployed after Booster
   */
  function setSftHolder(address sftHolder_) external onlyAdmin {
    // Validate input
    require(sftHolder_ != address(0), 'B: Invalid sftHolder');

    // Update state
    sftHolder = IWOWSERC1155(sftHolder_);
  }

  /**
   * @dev Replace reward definition.
   * Durations are required to be in descending order
   */
  function setRewardDefinition(
    uint256[] calldata durations,
    uint256[] calldata aprs
  ) external onlyAdmin {
    // Validate input
    require(durations.length == aprs.length, 'B: Length mismatch');

    // Update state
    delete (rewardDefinitions);
    for (uint256 i = 0; i < durations.length; ++i) {
      require(i == 0 || durations[i] > durations[i - 1], 'B: Wrong sorting');
      rewardDefinitions.push(RewardDefinition(durations[i], aprs[i]));
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  // Implementation details
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Helper function to avoid disabling solhint in several places
   */
  function _getTimestamp() private view returns (uint256) {
    // solhint-disable-next-line not-rely-on-time
    return block.timestamp;
  }

  /**
   * @dev Internal setRewardhandler which checks for valid address
   */
  function _setRewardHandler(address rewardHandler_) internal {
    // Validate input
    require(rewardHandler_ != address(0), 'B: Invalid rewardHandler');

    // Update state
    rewardHandler = IRewardHandler(rewardHandler_);
  }

  /**
   * @dev Add more amount into existing lock pool
   *
   * Function will revert in case lock is closed because lock_.end is 0
   * and every subtraction with ts > 0 will fail in SafeMath
   */
  function _addMore(
    address recipient,
    TimeLock storage lock_,
    uint256 ts,
    uint256 amount
  ) private {
    // Following line reverts in SafeMath if timestamps are invalid
    uint256 reward = (amount.mul(lock_.end.sub(ts)).mul(lock_.apr)).div(
      SECONDS_PER_YEAR.mul(1E18)
    );

    // Update state
    lock_.totalAmount = lock_.totalAmount.add(amount).add(reward);
    rewardsProvided.add(reward);

    // Validate state
    _verifyRewardsProvided();

    // Dispatch event
    emit MoreAdded(recipient, amount, amount.add(reward));
  }

  /**
   * @dev Write all pending rewards into pendingAmount so we can
   * safely add more amounts or finalize the lock pool.
   */
  function _updatePendingRewards(TimeLock storage lock_, uint256 ts) private {
    lock_.pendingAmount = _getPendingAmount(lock_, ts);
    if (lock_.end != 0) {
      if (ts >= lock_.end) {
        lock_.end = 0;
        lock_.totalAmount = 0;
        lock_.providedAmount = 0;
      } else {
        lock_.last = ts;
      }
    }
  }

  /**
   * @dev Calculate the current pending amount
   */
  function _getPendingAmount(TimeLock storage lock_, uint256 ts)
    private
    view
    returns (uint256)
  {
    if (lock_.end != 0) {
      if (ts >= lock_.end) {
        return lock_.totalAmount.sub(lock_.providedAmount);
      } else {
        return
          lock_.pendingAmount.add(
            lock_.totalAmount.mul(ts.sub(lock_.last)).div(MONTHLY_REWARD)
          );
      }
    } else {
      return lock_.pendingAmount;
    }
  }

  /**
   * @dev Verify that we never exceed the token supply from tokenomics and fees
   */
  function _verifyRewardsProvided() private view {
    uint256 externalSupply = rewardHandler.getBoosterRewards();

    require(
      rewardsProvided <= externalSupply.add(MAX_TOKENOMICS_REWARDS),
      'B: Cap reached'
    );
  }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

import '../utils/EnumerableSet.sol';
import '../utils/Address.sol';
import '../utils/Context.sol';

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

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

  mapping(bytes32 => RoleData) private _roles;

  bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

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

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

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

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

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

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

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

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

    _grantRole(role, account);
  }

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

    _revokeRole(role, account);
  }

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

    _revokeRole(role, account);
  }

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

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

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

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

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.7.6;

interface IERC1155 {
  /****************************************|
  |                 Events                 |
  |_______________________________________*/

  /**
   * @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero amount transfers as well as minting or burning
   *   Operator MUST be msg.sender
   *   When minting/creating tokens, the `_from` field MUST be set to `0x0`
   *   When burning/destroying tokens, the `_to` field MUST be set to `0x0`
   *   The total amount transferred from address 0x0 minus the total amount transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID
   *   To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the TransferSingle event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_amount` of 0
   */
  event TransferSingle(
    address indexed _operator,
    address indexed _from,
    address indexed _to,
    uint256 _id,
    uint256 _amount
  );

  /**
   * @dev Either TransferSingle or TransferBatch MUST emit when tokens are transferred, including zero amount transfers as well as minting or burning
   *   Operator MUST be msg.sender
   *   When minting/creating tokens, the `_from` field MUST be set to `0x0`
   *   When burning/destroying tokens, the `_to` field MUST be set to `0x0`
   *   The total amount transferred from address 0x0 minus the total amount transferred to 0x0 may be used by clients and exchanges to be added to the "circulating supply" for a given token ID
   *   To broadcast the existence of multiple token IDs with no initial balance, this SHOULD emit the TransferBatch event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_amount` of 0
   */
  event TransferBatch(
    address indexed _operator,
    address indexed _from,
    address indexed _to,
    uint256[] _ids,
    uint256[] _amounts
  );

  /**
   * @dev MUST emit when an approval is updated
   */
  event ApprovalForAll(
    address indexed _owner,
    address indexed _operator,
    bool _approved
  );

  /****************************************|
  |                Functions               |
  |_______________________________________*/

  /**
   * @notice Transfers amount of an _id from the _from address to the _to address specified
   * @dev MUST emit TransferSingle event on success
   * Caller must be approved to manage the _from account's tokens (see isApprovedForAll)
   * MUST throw if `_to` is the zero address
   * MUST throw if balance of sender for token `_id` is lower than the `_amount` sent
   * MUST throw on any other error
   * When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155Received` on `_to` and revert if the return amount is not `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
   * @param _from    Source address
   * @param _to      Target address
   * @param _id      ID of the token type
   * @param _amount  Transfered amount
   * @param _data    Additional data with no specified format, sent in call to `_to`
   */
  function safeTransferFrom(
    address _from,
    address _to,
    uint256 _id,
    uint256 _amount,
    bytes calldata _data
  ) external;

  /**
   * @notice Send multiple types of Tokens from the _from address to the _to address (with safety call)
   * @dev MUST emit TransferBatch event on success
   * Caller must be approved to manage the _from account's tokens (see isApprovedForAll)
   * MUST throw if `_to` is the zero address
   * MUST throw if length of `_ids` is not the same as length of `_amounts`
   * MUST throw if any of the balance of sender for token `_ids` is lower than the respective `_amounts` sent
   * MUST throw on any other error
   * When transfer is complete, this function MUST check if `_to` is a smart contract (code size > 0). If so, it MUST call `onERC1155BatchReceived` on `_to` and revert if the return amount is not `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
   * Transfers and events MUST occur in the array order they were submitted (_ids[0] before _ids[1], etc)
   * @param _from     Source addresses
   * @param _to       Target addresses
   * @param _ids      IDs of each token type
   * @param _amounts  Transfer amounts per token type
   * @param _data     Additional data with no specified format, sent in call to `_to`
   */
  function safeBatchTransferFrom(
    address _from,
    address _to,
    uint256[] calldata _ids,
    uint256[] calldata _amounts,
    bytes calldata _data
  ) external;

  /**
   * @notice Get the balance of an account's Tokens
   * @param _owner  The address of the token holder
   * @param _id     ID of the Token
   * @return        The _owner's balance of the Token type requested
   */
  function balanceOf(address _owner, uint256 _id)
    external
    view
    returns (uint256);

  /**
   * @notice Get the balance of multiple account/token pairs
   * @param _owners The addresses of the token holders
   * @param _ids    ID of the Tokens
   * @return        The _owner's balance of the Token types requested (i.e. balance for each (owner, id) pair)
   */
  function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids)
    external
    view
    returns (uint256[] memory);

  /**
   * @notice Enable or disable approval for a third party ("operator") to manage all of caller's tokens
   * @dev MUST emit the ApprovalForAll event on success
   * @param _operator  Address to add to the set of authorized operators
   * @param _approved  True if the operator is approved, false to revoke approval
   */
  function setApprovalForAll(address _operator, bool _approved) external;

  /**
   * @notice Queries the approval status of an operator for a given owner
   * @param _owner     The owner of the Tokens
   * @param _operator  Address of authorized operator
   * @return isOperator True if the operator is approved, false if not
   */
  function isApprovedForAll(address _owner, address _operator)
    external
    view
    returns (bool isOperator);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.7.6;

/**
 * @title ERC20 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 {
  function transfer(address to, uint256 value) external returns (bool);

  function approve(address spender, uint256 value) external returns (bool);

  function transferFrom(
    address from,
    address to,
    uint256 value
  ) external returns (bool);

  function totalSupply() external view returns (uint256);

  function balanceOf(address who) external view returns (uint256);

  function allowance(address owner, address spender)
    external
    view
    returns (uint256);

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

// SPDX-License-Identifier: MIT AND Apache-2.0
pragma solidity 0.7.6;

/**
 * Utility library of inline functions on addresses
 */
library Address {
  // Default hash for EOA accounts returned by extcodehash
  bytes32 internal constant ACCOUNT_HASH =
    0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;

  /**
   * Returns whether the target address is a contract
   * @dev This function will return false if invoked during the constructor of a contract.
   * @param _address address of the account to check
   * @return Whether the target address is a contract
   */
  function isContract(address _address) internal view returns (bool) {
    bytes32 codehash;

    // Currently there is no better way to check if there is a contract in an address
    // than to check the size of the code at that address or if it has a non-zero code hash or account hash
    assembly {
      codehash := extcodehash(_address)
    }
    return (codehash != 0x0 && codehash != ACCOUNT_HASH);
  }

  /**
   * @dev Performs a Solidity function call using a low level `call`.
   *
   * If `target` reverts with a revert reason, it is bubbled up by this
   * function (like regular Solidity function calls).
   *
   * Returns the raw returned data. To convert to the expected return value,
   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
   *
   * Requirements:
   *
   * - `target` must be a contract.
   * - calling `target` with `data` must not revert.
   */
  function functionCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal returns (bytes memory) {
    require(isContract(target), 'Address: call to non-contract');

    // solhint-disable-next-line avoid-low-level-calls
    (bool success, bytes memory returndata) = target.call(data);

    if (success) {
      return returndata;
    } else {
      // Look for revert reason and bubble it up if present
      if (returndata.length > 0) {
        // The easiest way to bubble the revert reason is using memory via assembly

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

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

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

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

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

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

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

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

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

      bytes32 lastvalue = set._values[lastIndex];

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

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

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

      return true;
    } else {
      return false;
    }
  }

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

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

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

  // Bytes32Set

  struct Bytes32Set {
    Set _inner;
  }

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

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

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

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

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

  // AddressSet

  struct AddressSet {
    Set _inner;
  }

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

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

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

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

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

  // UintSet

  struct UintSet {
    Set _inner;
  }

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

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

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

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

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

// SPDX-License-Identifier: MIT AND Apache-2.0

pragma solidity 0.7.6;

import '../interfaces/IERC20.sol';
import '../utils/SafeMath.sol';
import '../utils/Address.sol';

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  using SafeMath for uint256;
  using Address for address;

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

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

  /**
   * @dev Deprecated. This function has issues similar to the ones found in
   * {IERC20-approve}, and its usage is discouraged.
   *
   * Whenever possible, use {safeIncreaseAllowance} and
   * {safeDecreaseAllowance} instead.
   */
  function safeApprove(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    // safeApprove should only be called when setting an initial allowance,
    // or when resetting it to zero. To increase and decrease it, use
    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    // solhint-disable-next-line max-line-length
    require(
      (value == 0) || (token.allowance(address(this), spender) == 0),
      'SafeERC20: approve from non-zero to non-zero allowance'
    );
    _callOptionalReturn(
      token,
      abi.encodeWithSelector(token.approve.selector, spender, value)
    );
  }

  function safeIncreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    uint256 newAllowance = token.allowance(address(this), spender).add(value);
    _callOptionalReturn(
      token,
      abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
    );
  }

  function safeDecreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    uint256 newAllowance = token.allowance(address(this), spender).sub(value);
    _callOptionalReturn(
      token,
      abi.encodeWithSelector(token.approve.selector, spender, newAllowance)
    );
  }

  /**
   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
   * on the return value: the return value is optional (but if data is returned, it must not be false).
   * @param token The token targeted by the call.
   * @param data The call data (encoded using abi.encode or one of its variants).
   */
  function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

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

// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.7.6;

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error
 */
library SafeMath {
  /**
   * @dev Multiplies two unsigned integers, reverts on 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-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b, 'SafeMath#mul: OVERFLOW');

    return c;
  }

  /**
   * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
   */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // Solidity only automatically asserts when dividing by 0
    require(b > 0, 'SafeMath#div: DIVISION_BY_ZERO');
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold

    return c;
  }

  /**
   * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
   */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a, 'SafeMath#sub: UNDERFLOW');
    uint256 c = a - b;

    return c;
  }

  /**
   * @dev Adds two unsigned integers, reverts on overflow.
   */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a, 'SafeMath#add: OVERFLOW');

    return c;
  }

  /**
   * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
   * reverts when dividing by zero.
   */
  function mod(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b != 0, 'SafeMath#mod: DIVISION_BY_ZERO');
    return a % b;
  }
}

/*
 * Copyright (C) 2021 The Wolfpack
 * This file is part of wolves.finance - https://github.com/wolvesofwallstreet/wolves.finance
 *
 * SPDX-License-Identifier: Apache-2.0
 * See LICENSE.txt for more information.
 */

pragma solidity >=0.7.0 <0.8.0;

/**
 * @dev Interface to C-folio item contracts
 */
interface IBooster {
  /**
   * @dev Return information about the reward state in Booster
   *
   * @param tokenIds The SFT or TF tokenId
   *
   * @return locked The total amounts locked
   * @return pending The pending amounts claimable
   * @return apr The APR of this lock pool
   * @return secsLeft Numbers of seconds until unlock, or -1 if unlocked
   */
  function getRewardInfo(uint256[] calldata tokenIds)
    external
    view
    returns (
      uint256[] memory locked,
      uint256[] memory pending,
      uint256[] memory apr,
      uint256[] memory secsLeft
    );

  /**
   * @dev Handles farm distribution, only callable from controller
   *
   * If recipient is booster contract, amount is temporarily stored and locked
   * in a second call.
   *
   * @param farm The reward farm that the call originates from
   * @param recipient The recipient of the rewards
   * @param amount The amount to distribute
   * @param fee The fee in 6 decimal notation
   */
  function distributeFromFarm(
    address farm,
    address recipient,
    uint256 amount,
    uint32 fee
  ) external;

  /**
   * @dev Locks temporary tokens owned by recipient for a specific duration
   * of seconds.
   *
   * @param recipient The recipient of the rewards
   * @param lockPeriod The lock period in seconds
   */
  function lock(address recipient, uint256 lockPeriod) external;

  /**
   * @dev Claim rewards either into wallet or re-lock them
   *
   * @param sftTokenId The tokenId that manages the rewards
   * @param reLock True to re-lock existing rewards to earn more
   */
  function claimRewards(uint256 sftTokenId, bool reLock) external;
}

/*
 * Copyright (C) 2020-2021 The Wolfpack
 * This file is part of wolves.finance - https://github.com/wolvesofwallstreet/wolves.finance
 *
 * SPDX-License-Identifier: Apache-2.0
 * See the file LICENSES/README.md for more information.
 */

pragma solidity 0.7.6;

interface IRewardHandler {
  /**
   * @dev Get the amount allocated for the Booster
   *
   * @return The amount which is allocated for the Booster (18 decimals)
   */
  function getBoosterRewards() external view returns (uint256);

  /**
   * @dev Transfer reward and distribute the fee
   *
   * This is the new implementation of distribute() which uses internal fees
   * defined in the {RewardHandler} contract.
   *
   * @param recipient The recipient of the reward
   * @param amount The amount of WOWS to transfer to the recipient
   * @param fee The reward fee in 1e6 factor notation
   */
  function distribute2(
    address recipient,
    uint256 amount,
    uint32 fee
  ) external;

  /**
   * @dev Transfer reward and distribute the fee
   *
   * This is the current implementation, needed for backward compatibility.
   *
   * Current ERC1155Minter and Controller call this function, later
   * reward handler clients should call the the new one with internal
   * fees specified in this contract.
   *
   * uint32 values are in 1e6 factor notation.
   */
  function distribute(
    address recipient,
    uint256 amount,
    uint32 fee,
    uint32 toTeam,
    uint32 toMarketing,
    uint32 toBooster,
    uint32 toRewardPool
  ) external;
}

/*
 * Copyright (C) 2021 The Wolfpack
 * This file is part of wolves.finance - https://github.com/wolvesofwallstreet/wolves.finance
 *
 * SPDX-License-Identifier: Apache-2.0
 * See the file LICENSES/README.md for more information.
 */

pragma solidity >=0.7.0 <0.8.0;

/**
 * @notice Cryptofolio interface
 */
interface IWOWSERC1155 {
  //////////////////////////////////////////////////////////////////////////////
  // Getters
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Check if the specified address is a known tradefloor
   *
   * @param account The address to check
   *
   * @return True if the address is a known tradefloor, false otherwise
   */
  function isTradeFloor(address account) external view returns (bool);

  /**
   * @dev Get the token ID of a given address
   *
   * A cross check is required because token ID 0 is valid.
   *
   * @param tokenAddress The address to convert to a token ID
   *
   * @return The token ID on success, or uint256(-1) if `tokenAddress` does not
   * belong to a token ID
   */
  function addressToTokenId(address tokenAddress)
    external
    view
    returns (uint256);

  /**
   * @dev Get the address for a given token ID
   *
   * @param tokenId The token ID to convert
   *
   * @return The address, or address(0) in case the token ID does not belong
   * to an NFT
   */
  function tokenIdToAddress(uint256 tokenId) external view returns (address);

  /**
   * @dev Get the next mintable token ID for the specified card
   *
   * @param level The level of the card
   * @param cardId The ID of the card
   *
   * @return bool True if a free token ID was found, false otherwise
   * @return uint256 The first free token ID if one was found, or invalid otherwise
   */
  function getNextMintableTokenId(uint8 level, uint8 cardId)
    external
    view
    returns (bool, uint256);

  /**
   * @dev Return the next mintable custom token ID
   */
  function getNextMintableCustomToken() external view returns (uint256);

  /**
   * @dev Return the level and the mint timestamp of tokenId
   *
   * @param tokenId The tokenId to query
   *
   * @return mintTimestamp The timestamp token was minted
   * @return level The level token belongs to
   */
  function getTokenData(uint256 tokenId)
    external
    view
    returns (uint64 mintTimestamp, uint8 level);

  /**
   * @dev Return all tokenIds owned by account
   */
  function getTokenIds(address account)
    external
    view
    returns (uint256[] memory);

  //////////////////////////////////////////////////////////////////////////////
  // State modifiers
  //////////////////////////////////////////////////////////////////////////////

  /**
   * @dev Set the base URI for either predefined cards or custom cards
   * which don't have it's own URI.
   *
   * The resulting uri is baseUri+[hex(tokenId)] + '.json'. where
   * tokenId will be reduces to upper 16 bit (>> 16) before building the hex string.
   *
   */
  function setBaseMetadataURI(string memory baseContractMetadata) external;

  /**
   * @dev Set the contracts metadata URI
   *
   * @param contractMetadataURI The URI which point to the contract metadata file.
   */
  function setContractMetadataURI(string memory contractMetadataURI) external;

  /**
   * @dev Set the URI for a custom card
   *
   * @param tokenId The token ID whose URI is being set.
   * @param customURI The URI which point to an unique metadata file.
   */
  function setCustomURI(uint256 tokenId, string memory customURI) external;

  /**
   * @dev Each custom card has its own level. Level will be used when
   * calculating rewards and raiding power.
   *
   * @param tokenId The ID of the token whose level is being set
   * @param cardLevel The new level of the specified token
   */
  function setCustomCardLevel(uint256 tokenId, uint8 cardLevel) external;
}

/*
 * Copyright (C) 2021 The Wolfpack
 * This file is part of wolves.finance - https://github.com/wolvesofwallstreet/wolves.finance
 *
 * SPDX-License-Identifier: Apache-2.0
 * See LICENSE.txt for more information.
 */

pragma solidity >=0.7.0 <0.8.0;

library TokenIds {
  // 128 bit underlying hash
  uint256 public constant HASH_MASK = (1 << 128) - 1;

  function isBaseCard(uint256 tokenId) internal pure returns (bool) {
    return (tokenId & HASH_MASK) < (1 << 64);
  }

  function isStockCard(uint256 tokenId) internal pure returns (bool) {
    return (tokenId & HASH_MASK) < (1 << 32);
  }

  function isCFolioCard(uint256 tokenId) internal pure returns (bool) {
    return
      (tokenId & HASH_MASK) >= (1 << 64) && (tokenId & HASH_MASK) < (1 << 128);
  }

  function toSftTokenId(uint256 tokenId) internal pure returns (uint256) {
    return tokenId & HASH_MASK;
  }

  function maskHash(uint256 tokenId) internal pure returns (uint256) {
    return tokenId & ~HASH_MASK;
  }
}

Settings
{
  "evmVersion": "berlin",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLocked","type":"uint256"}],"name":"MoreAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountLocked","type":"uint256"}],"name":"TokensLocked","type":"event"},{"inputs":[],"name":"CONTROLLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sftTokenId","type":"uint256"},{"internalType":"bool","name":"reLock","type":"bool"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"newContract","type":"address"}],"name":"destructContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"fee","type":"uint32"}],"name":"distributeFromFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"getRewardInfo","outputs":[{"internalType":"uint256[]","name":"locked","type":"uint256[]"},{"internalType":"uint256[]","name":"pending","type":"uint256[]"},{"internalType":"uint256[]","name":"apr","type":"uint256[]"},{"internalType":"uint256[]","name":"secsLeft","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"rewardHandler_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardDefinitions","outputs":[{"internalType":"uint256","name":"length","type":"uint256"},{"internalType":"uint256","name":"apr","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardHandler","outputs":[{"internalType":"contract IRewardHandler","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsProvided","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"durations","type":"uint256[]"},{"internalType":"uint256[]","name":"aprs","type":"uint256[]"}],"name":"setRewardDefinition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rewardHandler_","type":"address"}],"name":"setRewardHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sftHolder_","type":"address"}],"name":"setSftHolder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sftHolder","outputs":[{"internalType":"contract IWOWSERC1155","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"timeLocks","outputs":[{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"pendingAmount","type":"uint256"},{"internalType":"uint256","name":"providedAmount","type":"uint256"},{"internalType":"uint256","name":"last","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"apr","type":"uint256"},{"internalType":"uint32","name":"fee","type":"uint32"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506040516200244c3803806200244c833981810160405260208110156200003757600080fd5b5051620000466000826200004d565b5062000161565b6200005982826200005d565b5050565b6000828152602081815260409091206200008291839062001a53620000d6821b17901c565b15620000595762000092620000f6565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000620000ed836001600160a01b038416620000fa565b90505b92915050565b3390565b600062000108838362000149565b6200014057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620000f0565b506000620000f0565b60009081526001919091016020526040902054151590565b6122db80620001716000396000f3fe608060405234801561001057600080fd5b506004361061018c5760003560e01c8063485cc955116100e3578063a217fddf1161008c578063e468475f11610066578063e468475f1461054f578063e63755cb14610574578063ee9248091461059a5761018c565b8063a217fddf146104fe578063ca15c87314610506578063d547741f146105235761018c565b80639010d07c116100bd5780639010d07c1461047557806391d14854146104985780639a0313ab146104d85761018c565b8063485cc955146103db578063670fb821146104095780637f76b223146104115761018c565b80632437c60b116101455780632f2ff15d1161011f5780632f2ff15d1461034d57806336568abe146103795780633ee22f79146103a55761018c565b80632437c60b146102e0578063248a9ca314610304578063282d3fdf146103215761018c565b8063092c5b3b11610176578063092c5b3b146102985780630c192254146102b25780631deee612146102ba5761018c565b8062ded9b41461019157806308ad8d0014610255575b600080fd5b610253600480360360408110156101a757600080fd5b8101906020810181356401000000008111156101c257600080fd5b8201836020820111156101d457600080fd5b803590602001918460208302840111640100000000831117156101f657600080fd5b91939092909160208101903564010000000081111561021457600080fd5b82018360208201111561022657600080fd5b8035906020019184602083028401116401000000008311171561024857600080fd5b509092509050610760565b005b6102536004803603608081101561026b57600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060013563ffffffff16610915565b6102a0610c58565b60408051918252519081900360200190f35b6102a0610c69565b610253600480360360208110156102d057600080fd5b50356001600160a01b0316610c6f565b6102e8610cc9565b604080516001600160a01b039092168252519081900360200190f35b6102a06004803603602081101561031a57600080fd5b5035610cd8565b6102536004803603604081101561033757600080fd5b506001600160a01b038135169060200135610ced565b6102536004803603604081101561036357600080fd5b50803590602001356001600160a01b0316610fc5565b6102536004803603604081101561038f57600080fd5b50803590602001356001600160a01b0316611028565b6103c2600480360360208110156103bb57600080fd5b5035611089565b6040805192835260208301919091528051918290030190f35b610253600480360360408110156103f157600080fd5b506001600160a01b03813581169160200135166110b7565b6102e8611222565b6104376004803603602081101561042757600080fd5b50356001600160a01b0316611231565b604080519788526020880196909652868601949094526060860192909252608085015260a084015263ffffffff1660c0830152519081900360e00190f35b6102e86004803603604081101561048b57600080fd5b5080359060200135611275565b6104c4600480360360408110156104ae57600080fd5b50803590602001356001600160a01b0316611296565b604080519115158252519081900360200190f35b610253600480360360208110156104ee57600080fd5b50356001600160a01b03166112ae565b6102a0611308565b6102a06004803603602081101561051c57600080fd5b503561130d565b6102536004803603604081101561053957600080fd5b50803590602001356001600160a01b0316611324565b6102536004803603604081101561056557600080fd5b5080359060200135151561137d565b6102536004803603602081101561058a57600080fd5b50356001600160a01b0316611697565b61063d600480360360208110156105b057600080fd5b8101906020810181356401000000008111156105cb57600080fd5b8201836020820111156105dd57600080fd5b803590602001918460208302840111640100000000831117156105ff57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061176f945050505050565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b83811015610689578181015183820152602001610671565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156106c85781810151838201526020016106b0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b838110156107075781810151838201526020016106ef565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561074657818101518382015260200161072e565b505050509050019850505050505050505060405180910390f35b610772600061076d611a68565b611296565b6107b3576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b828114610807576040805162461bcd60e51b815260206004820152601260248201527f423a204c656e677468206d69736d617463680000000000000000000000000000604482015290519081900360640190fd5b610813600460006121ba565b60005b8381101561090e57801580610851575084846001830381811061083557fe5b9050602002013585858381811061084857fe5b90506020020135115b6108a2576040805162461bcd60e51b815260206004820152601060248201527f423a2057726f6e6720736f7274696e6700000000000000000000000000000000604482015290519081900360640190fd5b600460405180604001604052808787858181106108bb57fe5b9050602002013581526020018585858181106108d357fe5b602090810292909201359092528354600181810186556000958652948290208451600290920201908155920151918301919091555001610816565b5050505050565b61092e6921a7a72a2927a62622a960b11b61076d611a68565b61097f576040805162461bcd60e51b815260206004820152601260248201527f423a204f6e6c7920636f6e74726f6c6c65720000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b0383166109da576040805162461bcd60e51b815260206004820152601460248201527f423a20496e76616c696420726563697069656e74000000000000000000000000604482015290519081900360640190fd5b600254604080517f6511bf2e0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529151600019939290921691636511bf2e91602480820192602092909190829003018186803b158015610a4557600080fd5b505afa158015610a59573d6000803e3d6000fd5b505050506040513d6020811015610a6f57600080fd5b505114610bbf576001600160a01b0383166000908152600360205260409020600481015415610b21576000610aa2611a6c565b9050610aae8282611a70565b600682015463ffffffff848116911614610b0f576040805162461bcd60e51b815260206004820152600d60248201527f423a20466565206368616e676500000000000000000000000000000000000000604482015290519081900360640190fd5b610b1b85838387611ab3565b50610bb9565b80541580610b3b5750600681015463ffffffff8381169116145b610b8c576040805162461bcd60e51b815260206004820152600f60248201527f423a20466565206d69736d617463680000000000000000000000000000000000604482015290519081900360640190fd5b60068101805463ffffffff191663ffffffff848116919091179091558154610bb6918590611b7f16565b81555b50610c52565b600154604080517f0bd3ce940000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820186905263ffffffff8516604483015291519190921691630bd3ce9491606480830192600092919082900301818387803b158015610c3957600080fd5b505af1158015610c4d573d6000803e3d6000fd5b505050505b50505050565b6921a7a72a2927a62622a960b11b81565b60055481565b610c7c600061076d611a68565b610cbd576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b610cc681611bd9565b50565b6002546001600160a01b031681565b60009081526020819052604090206002015490565b610d066921a7a72a2927a62622a960b11b61076d611a68565b610d57576040805162461bcd60e51b815260206004820152601260248201527f423a204f6e6c7920636f6e74726f6c6c65720000000000000000000000000000604482015290519081900360640190fd5b6000610d61611a6c565b6001600160a01b03841660009081526003602052604090206004810154919250901580610d915750818160030154145b610de2576040805162461bcd60e51b815260206004820152600f60248201527f423a2053796e63206661696c7572650000000000000000000000000000000000604482015290519081900360640190fd5b6004810154610c525760005b600454811015610f735760048181548110610e0557fe5b9060005260206000209060020201600001548410610f6b576000610e8f610e386301da9c00670de0b6b3a7640000611c63565b610e8960048581548110610e4857fe5b906000526020600020906002020160010154610e8360048781548110610e6a57fe5b6000918252602090912060029091020154885490611c63565b90611c63565b90611cd2565b8354909150610e9e9082611b7f565b83556004805483908110610eae57fe5b9060005260206000209060020201600001548401836004018190555060048281548110610ed757fe5b60009182526020909120600160029092020101546005808501919091556003840185905554610f069082611b7f565b50610f0f611d3c565b82546001600160a01b038716907fd741e738a23fd18a03a26522320d9fc6cac1fed483e215ea9150fbc2fc43385d90610f489084611e32565b85546040805192835260208301919091528051918290030190a250505050610fc1565b600101610dee565b506040805162461bcd60e51b815260206004820152601360248201527f423a204c6f636b506572696f642077726f6e6700000000000000000000000000604482015290519081900360640190fd5b5050565b600082815260208190526040902060020154610fe39061076d611a68565b61101e5760405162461bcd60e51b815260040180806020018281038252602f815260200180612218602f913960400191505060405180910390fd5b610fc18282611e8f565b611030611a68565b6001600160a01b0316816001600160a01b03161461107f5760405162461bcd60e51b815260040180806020018281038252602f815260200180612277602f913960400191505060405180910390fd5b610fc18282611ef8565b6004818154811061109957600080fd5b60009182526020909120600290910201805460019091015490915082565b6110c1600061130d565b15611113576040805162461bcd60e51b815260206004820152601660248201527f423a20416c726561647920696e697469616c697a656400000000000000000000604482015290519081900360640190fd5b61111e60008361101e565b61112781611bd9565b505060408051808201825262ed4e0081526718493fba64ef0000602080830191825260048054600181810183556000838152955160029283027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8181019290925595517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c96870155875180890189526276a700815267120a871cc002000081870190815285548085018755868a529151918502808401929092555190870155875180890190985262278d008852670de0b6b3a76400009488019485528354918201845592909552945193909402938401929092559051910155565b6001546001600160a01b031681565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006909501549395929492939192909163ffffffff1687565b600082815260208190526040812061128d9083611f61565b90505b92915050565b600082815260208190526040812061128d9083611f6d565b6112bb600061076d611a68565b6112fc576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b806001600160a01b0316ff5b600081565b600081815260208190526040812061129090611f82565b6000828152602081905260409020600201546113429061076d611a68565b61107f5760405162461bcd60e51b81526004018080602001828103825260308152602001806122476030913960400191505060405180910390fd5b600254604080517f08bb76a50000000000000000000000000000000000000000000000000000000081526004810185905290516000926001600160a01b0316916308bb76a5916024808301926020929190829003018186803b1580156113e257600080fd5b505afa1580156113f6573d6000803e3d6000fd5b505050506040513d602081101561140c57600080fd5b505190506001600160a01b03811661146b576040805162461bcd60e51b815260206004820152601160248201527f423a20496e76616c69642063666f6c696f000000000000000000000000000000604482015290519081900360640190fd5b6002546001600160a01b031662fdd58e611483611a68565b856040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b1580156114c857600080fd5b505afa1580156114dc573d6000803e3d6000fd5b505050506040513d60208110156114f257600080fd5b5051600114611548576040805162461bcd60e51b815260206004820152601060248201527f423a204163636573732064656e69656400000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038116600090815260036020526040812090611569611a6c565b90506115758282611a70565b6001820180546000909155600283015461158f9082611b7f565b506040805182815290516001600160a01b038616917ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe919081900360200190a284156115e6576115e184848484611ab3565b61168f565b6001546001600160a01b0316630bd3ce946115ff611a68565b6006860154604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0390931660048401526024830186905263ffffffff909116604483015251606480830192600092919082900301818387803b15801561167657600080fd5b505af115801561168a573d6000803e3d6000fd5b505050505b505050505050565b6116a4600061076d611a68565b6116e5576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b6001600160a01b038116611740576040805162461bcd60e51b815260206004820152601460248201527f423a20496e76616c696420736674486f6c646572000000000000000000000000604482015290519081900360640190fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b606080606080845167ffffffffffffffff8111801561178d57600080fd5b506040519080825280602002602001820160405280156117b7578160200160208202803683370190505b509350845167ffffffffffffffff811180156117d257600080fd5b506040519080825280602002602001820160405280156117fc578160200160208202803683370190505b509250845167ffffffffffffffff8111801561181757600080fd5b50604051908082528060200260200182016040528015611841578160200160208202803683370190505b509150845167ffffffffffffffff8111801561185c57600080fd5b50604051908082528060200260200182016040528015611886578160200160208202803683370190505b5090506000611893611a6c565b905060005b8651811015611a4a5760025487516000916001600160a01b0316906308bb76a5906118d6908b90869081106118c957fe5b6020026020010151611f8d565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561190a57600080fd5b505afa15801561191e573d6000803e3d6000fd5b505050506040513d602081101561193457600080fd5b505190506001600160a01b038116611993576040805162461bcd60e51b815260206004820152601260248201527f423a20496e76616c696420746f6b656e49640000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b0381166000908152600360205260409020805488518990859081106119bb57fe5b6020026020010181815250506119d18185611fa2565b8784815181106119dd57fe5b60200260200101818152505080600501548684815181106119fa57fe5b6020026020010181815250508381600401541015611a1a57600019611a29565b6004810154611a299085611e32565b858481518110611a3557fe5b60209081029190910101525050600101611898565b50509193509193565b600061128d836001600160a01b038416612015565b3390565b4290565b611a7a8282611fa2565b6001830155600482015415610fc15781600401548110611aaa576000600483018190558083556002830155610fc1565b60039190910155565b6000611af7611ace6301da9c00670de0b6b3a7640000611c63565b610e898660050154610e83611af0888a60040154611e3290919063ffffffff16565b8790611c63565b8454909150611b12908290611b0c9085611b7f565b90611b7f565b8455600554611b219082611b7f565b50611b2a611d3c565b6001600160a01b0385167faa89513d5d558adb42dfbb3259feaf493d4aea25a61d8b8882a69bde91ff744783611b608185611b7f565b6040805192835260208301919091528051918290030190a25050505050565b60008282018381101561128d576040805162461bcd60e51b815260206004820152601660248201527f536166654d617468236164643a204f564552464c4f5700000000000000000000604482015290519081900360640190fd5b6001600160a01b038116611c34576040805162461bcd60e51b815260206004820152601860248201527f423a20496e76616c69642072657761726448616e646c65720000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b600082611c7257506000611290565b82820282848281611c7f57fe5b041461128d576040805162461bcd60e51b815260206004820152601660248201527f536166654d617468236d756c3a204f564552464c4f5700000000000000000000604482015290519081900360640190fd5b6000808211611d28576040805162461bcd60e51b815260206004820152601e60248201527f536166654d617468236469763a204449564953494f4e5f42595f5a45524f0000604482015290519081900360640190fd5b6000828481611d3357fe5b04949350505050565b600154604080517f63da12ba00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916363da12ba916004808301926020929190829003018186803b158015611d9a57600080fd5b505afa158015611dae573d6000803e3d6000fd5b505050506040513d6020811015611dc457600080fd5b50519050611ddc816901969368974c05b00000611b7f565b6005541115610cc6576040805162461bcd60e51b815260206004820152600e60248201527f423a204361702072656163686564000000000000000000000000000000000000604482015290519081900360640190fd5b600082821115611e89576040805162461bcd60e51b815260206004820152601760248201527f536166654d617468237375623a20554e444552464c4f57000000000000000000604482015290519081900360640190fd5b50900390565b6000828152602081905260409020611ea79082611a53565b15610fc157611eb4611a68565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081905260409020611f10908261205f565b15610fc157611f1d611a68565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600061128d8383612074565b600061128d836001600160a01b0384166120d8565b6000611290826120f0565b6fffffffffffffffffffffffffffffffff1690565b6000826004015460001461200a5782600401548210611fd25760028301548354611fcb91611e32565b9050611290565b611fcb611fff63018b8200610e89611ff7876003015487611e3290919063ffffffff16565b875490611c63565b600185015490611b7f565b506001820154611290565b600061202183836120d8565b61205757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611290565b506000611290565b600061128d836001600160a01b0384166120f4565b815460009082106120b65760405162461bcd60e51b81526004018080602001828103825260228152602001806121f66022913960400191505060405180910390fd5b8260000182815481106120c557fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b600081815260018301602052604081205480156121b0578354600019808301919081019060009087908390811061212757fe5b906000526020600020015490508087600001848154811061214457fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061217457fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611290565b6000915050611290565b5080546000825560020290600052602060002090810190610cc691905b808211156121f157600080825560018201556002016121d7565b509056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e74416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b65416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a264697066735822122038af1846770ea91bd607b5a0e038cd2b013085b0e739f178522c5ee96be4243b64736f6c63430007060033000000000000000000000000bb5a7c17ade983f03afd8b09922b1c117b9eabc0

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061018c5760003560e01c8063485cc955116100e3578063a217fddf1161008c578063e468475f11610066578063e468475f1461054f578063e63755cb14610574578063ee9248091461059a5761018c565b8063a217fddf146104fe578063ca15c87314610506578063d547741f146105235761018c565b80639010d07c116100bd5780639010d07c1461047557806391d14854146104985780639a0313ab146104d85761018c565b8063485cc955146103db578063670fb821146104095780637f76b223146104115761018c565b80632437c60b116101455780632f2ff15d1161011f5780632f2ff15d1461034d57806336568abe146103795780633ee22f79146103a55761018c565b80632437c60b146102e0578063248a9ca314610304578063282d3fdf146103215761018c565b8063092c5b3b11610176578063092c5b3b146102985780630c192254146102b25780631deee612146102ba5761018c565b8062ded9b41461019157806308ad8d0014610255575b600080fd5b610253600480360360408110156101a757600080fd5b8101906020810181356401000000008111156101c257600080fd5b8201836020820111156101d457600080fd5b803590602001918460208302840111640100000000831117156101f657600080fd5b91939092909160208101903564010000000081111561021457600080fd5b82018360208201111561022657600080fd5b8035906020019184602083028401116401000000008311171561024857600080fd5b509092509050610760565b005b6102536004803603608081101561026b57600080fd5b5080356001600160a01b03908116916020810135909116906040810135906060013563ffffffff16610915565b6102a0610c58565b60408051918252519081900360200190f35b6102a0610c69565b610253600480360360208110156102d057600080fd5b50356001600160a01b0316610c6f565b6102e8610cc9565b604080516001600160a01b039092168252519081900360200190f35b6102a06004803603602081101561031a57600080fd5b5035610cd8565b6102536004803603604081101561033757600080fd5b506001600160a01b038135169060200135610ced565b6102536004803603604081101561036357600080fd5b50803590602001356001600160a01b0316610fc5565b6102536004803603604081101561038f57600080fd5b50803590602001356001600160a01b0316611028565b6103c2600480360360208110156103bb57600080fd5b5035611089565b6040805192835260208301919091528051918290030190f35b610253600480360360408110156103f157600080fd5b506001600160a01b03813581169160200135166110b7565b6102e8611222565b6104376004803603602081101561042757600080fd5b50356001600160a01b0316611231565b604080519788526020880196909652868601949094526060860192909252608085015260a084015263ffffffff1660c0830152519081900360e00190f35b6102e86004803603604081101561048b57600080fd5b5080359060200135611275565b6104c4600480360360408110156104ae57600080fd5b50803590602001356001600160a01b0316611296565b604080519115158252519081900360200190f35b610253600480360360208110156104ee57600080fd5b50356001600160a01b03166112ae565b6102a0611308565b6102a06004803603602081101561051c57600080fd5b503561130d565b6102536004803603604081101561053957600080fd5b50803590602001356001600160a01b0316611324565b6102536004803603604081101561056557600080fd5b5080359060200135151561137d565b6102536004803603602081101561058a57600080fd5b50356001600160a01b0316611697565b61063d600480360360208110156105b057600080fd5b8101906020810181356401000000008111156105cb57600080fd5b8201836020820111156105dd57600080fd5b803590602001918460208302840111640100000000831117156105ff57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092955061176f945050505050565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b83811015610689578181015183820152602001610671565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156106c85781810151838201526020016106b0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b838110156107075781810151838201526020016106ef565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561074657818101518382015260200161072e565b505050509050019850505050505050505060405180910390f35b610772600061076d611a68565b611296565b6107b3576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b828114610807576040805162461bcd60e51b815260206004820152601260248201527f423a204c656e677468206d69736d617463680000000000000000000000000000604482015290519081900360640190fd5b610813600460006121ba565b60005b8381101561090e57801580610851575084846001830381811061083557fe5b9050602002013585858381811061084857fe5b90506020020135115b6108a2576040805162461bcd60e51b815260206004820152601060248201527f423a2057726f6e6720736f7274696e6700000000000000000000000000000000604482015290519081900360640190fd5b600460405180604001604052808787858181106108bb57fe5b9050602002013581526020018585858181106108d357fe5b602090810292909201359092528354600181810186556000958652948290208451600290920201908155920151918301919091555001610816565b5050505050565b61092e6921a7a72a2927a62622a960b11b61076d611a68565b61097f576040805162461bcd60e51b815260206004820152601260248201527f423a204f6e6c7920636f6e74726f6c6c65720000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b0383166109da576040805162461bcd60e51b815260206004820152601460248201527f423a20496e76616c696420726563697069656e74000000000000000000000000604482015290519081900360640190fd5b600254604080517f6511bf2e0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529151600019939290921691636511bf2e91602480820192602092909190829003018186803b158015610a4557600080fd5b505afa158015610a59573d6000803e3d6000fd5b505050506040513d6020811015610a6f57600080fd5b505114610bbf576001600160a01b0383166000908152600360205260409020600481015415610b21576000610aa2611a6c565b9050610aae8282611a70565b600682015463ffffffff848116911614610b0f576040805162461bcd60e51b815260206004820152600d60248201527f423a20466565206368616e676500000000000000000000000000000000000000604482015290519081900360640190fd5b610b1b85838387611ab3565b50610bb9565b80541580610b3b5750600681015463ffffffff8381169116145b610b8c576040805162461bcd60e51b815260206004820152600f60248201527f423a20466565206d69736d617463680000000000000000000000000000000000604482015290519081900360640190fd5b60068101805463ffffffff191663ffffffff848116919091179091558154610bb6918590611b7f16565b81555b50610c52565b600154604080517f0bd3ce940000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820186905263ffffffff8516604483015291519190921691630bd3ce9491606480830192600092919082900301818387803b158015610c3957600080fd5b505af1158015610c4d573d6000803e3d6000fd5b505050505b50505050565b6921a7a72a2927a62622a960b11b81565b60055481565b610c7c600061076d611a68565b610cbd576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b610cc681611bd9565b50565b6002546001600160a01b031681565b60009081526020819052604090206002015490565b610d066921a7a72a2927a62622a960b11b61076d611a68565b610d57576040805162461bcd60e51b815260206004820152601260248201527f423a204f6e6c7920636f6e74726f6c6c65720000000000000000000000000000604482015290519081900360640190fd5b6000610d61611a6c565b6001600160a01b03841660009081526003602052604090206004810154919250901580610d915750818160030154145b610de2576040805162461bcd60e51b815260206004820152600f60248201527f423a2053796e63206661696c7572650000000000000000000000000000000000604482015290519081900360640190fd5b6004810154610c525760005b600454811015610f735760048181548110610e0557fe5b9060005260206000209060020201600001548410610f6b576000610e8f610e386301da9c00670de0b6b3a7640000611c63565b610e8960048581548110610e4857fe5b906000526020600020906002020160010154610e8360048781548110610e6a57fe5b6000918252602090912060029091020154885490611c63565b90611c63565b90611cd2565b8354909150610e9e9082611b7f565b83556004805483908110610eae57fe5b9060005260206000209060020201600001548401836004018190555060048281548110610ed757fe5b60009182526020909120600160029092020101546005808501919091556003840185905554610f069082611b7f565b50610f0f611d3c565b82546001600160a01b038716907fd741e738a23fd18a03a26522320d9fc6cac1fed483e215ea9150fbc2fc43385d90610f489084611e32565b85546040805192835260208301919091528051918290030190a250505050610fc1565b600101610dee565b506040805162461bcd60e51b815260206004820152601360248201527f423a204c6f636b506572696f642077726f6e6700000000000000000000000000604482015290519081900360640190fd5b5050565b600082815260208190526040902060020154610fe39061076d611a68565b61101e5760405162461bcd60e51b815260040180806020018281038252602f815260200180612218602f913960400191505060405180910390fd5b610fc18282611e8f565b611030611a68565b6001600160a01b0316816001600160a01b03161461107f5760405162461bcd60e51b815260040180806020018281038252602f815260200180612277602f913960400191505060405180910390fd5b610fc18282611ef8565b6004818154811061109957600080fd5b60009182526020909120600290910201805460019091015490915082565b6110c1600061130d565b15611113576040805162461bcd60e51b815260206004820152601660248201527f423a20416c726561647920696e697469616c697a656400000000000000000000604482015290519081900360640190fd5b61111e60008361101e565b61112781611bd9565b505060408051808201825262ed4e0081526718493fba64ef0000602080830191825260048054600181810183556000838152955160029283027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b8181019290925595517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c96870155875180890189526276a700815267120a871cc002000081870190815285548085018755868a529151918502808401929092555190870155875180890190985262278d008852670de0b6b3a76400009488019485528354918201845592909552945193909402938401929092559051910155565b6001546001600160a01b031681565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006909501549395929492939192909163ffffffff1687565b600082815260208190526040812061128d9083611f61565b90505b92915050565b600082815260208190526040812061128d9083611f6d565b6112bb600061076d611a68565b6112fc576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b806001600160a01b0316ff5b600081565b600081815260208190526040812061129090611f82565b6000828152602081905260409020600201546113429061076d611a68565b61107f5760405162461bcd60e51b81526004018080602001828103825260308152602001806122476030913960400191505060405180910390fd5b600254604080517f08bb76a50000000000000000000000000000000000000000000000000000000081526004810185905290516000926001600160a01b0316916308bb76a5916024808301926020929190829003018186803b1580156113e257600080fd5b505afa1580156113f6573d6000803e3d6000fd5b505050506040513d602081101561140c57600080fd5b505190506001600160a01b03811661146b576040805162461bcd60e51b815260206004820152601160248201527f423a20496e76616c69642063666f6c696f000000000000000000000000000000604482015290519081900360640190fd5b6002546001600160a01b031662fdd58e611483611a68565b856040518363ffffffff1660e01b815260040180836001600160a01b031681526020018281526020019250505060206040518083038186803b1580156114c857600080fd5b505afa1580156114dc573d6000803e3d6000fd5b505050506040513d60208110156114f257600080fd5b5051600114611548576040805162461bcd60e51b815260206004820152601060248201527f423a204163636573732064656e69656400000000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b038116600090815260036020526040812090611569611a6c565b90506115758282611a70565b6001820180546000909155600283015461158f9082611b7f565b506040805182815290516001600160a01b038616917ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe919081900360200190a284156115e6576115e184848484611ab3565b61168f565b6001546001600160a01b0316630bd3ce946115ff611a68565b6006860154604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0390931660048401526024830186905263ffffffff909116604483015251606480830192600092919082900301818387803b15801561167657600080fd5b505af115801561168a573d6000803e3d6000fd5b505050505b505050505050565b6116a4600061076d611a68565b6116e5576040805162461bcd60e51b815260206004820152600d60248201526c211d1027b7363c9030b236b4b760991b604482015290519081900360640190fd5b6001600160a01b038116611740576040805162461bcd60e51b815260206004820152601460248201527f423a20496e76616c696420736674486f6c646572000000000000000000000000604482015290519081900360640190fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b606080606080845167ffffffffffffffff8111801561178d57600080fd5b506040519080825280602002602001820160405280156117b7578160200160208202803683370190505b509350845167ffffffffffffffff811180156117d257600080fd5b506040519080825280602002602001820160405280156117fc578160200160208202803683370190505b509250845167ffffffffffffffff8111801561181757600080fd5b50604051908082528060200260200182016040528015611841578160200160208202803683370190505b509150845167ffffffffffffffff8111801561185c57600080fd5b50604051908082528060200260200182016040528015611886578160200160208202803683370190505b5090506000611893611a6c565b905060005b8651811015611a4a5760025487516000916001600160a01b0316906308bb76a5906118d6908b90869081106118c957fe5b6020026020010151611f8d565b6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561190a57600080fd5b505afa15801561191e573d6000803e3d6000fd5b505050506040513d602081101561193457600080fd5b505190506001600160a01b038116611993576040805162461bcd60e51b815260206004820152601260248201527f423a20496e76616c696420746f6b656e49640000000000000000000000000000604482015290519081900360640190fd5b6001600160a01b0381166000908152600360205260409020805488518990859081106119bb57fe5b6020026020010181815250506119d18185611fa2565b8784815181106119dd57fe5b60200260200101818152505080600501548684815181106119fa57fe5b6020026020010181815250508381600401541015611a1a57600019611a29565b6004810154611a299085611e32565b858481518110611a3557fe5b60209081029190910101525050600101611898565b50509193509193565b600061128d836001600160a01b038416612015565b3390565b4290565b611a7a8282611fa2565b6001830155600482015415610fc15781600401548110611aaa576000600483018190558083556002830155610fc1565b60039190910155565b6000611af7611ace6301da9c00670de0b6b3a7640000611c63565b610e898660050154610e83611af0888a60040154611e3290919063ffffffff16565b8790611c63565b8454909150611b12908290611b0c9085611b7f565b90611b7f565b8455600554611b219082611b7f565b50611b2a611d3c565b6001600160a01b0385167faa89513d5d558adb42dfbb3259feaf493d4aea25a61d8b8882a69bde91ff744783611b608185611b7f565b6040805192835260208301919091528051918290030190a25050505050565b60008282018381101561128d576040805162461bcd60e51b815260206004820152601660248201527f536166654d617468236164643a204f564552464c4f5700000000000000000000604482015290519081900360640190fd5b6001600160a01b038116611c34576040805162461bcd60e51b815260206004820152601860248201527f423a20496e76616c69642072657761726448616e646c65720000000000000000604482015290519081900360640190fd5b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b600082611c7257506000611290565b82820282848281611c7f57fe5b041461128d576040805162461bcd60e51b815260206004820152601660248201527f536166654d617468236d756c3a204f564552464c4f5700000000000000000000604482015290519081900360640190fd5b6000808211611d28576040805162461bcd60e51b815260206004820152601e60248201527f536166654d617468236469763a204449564953494f4e5f42595f5a45524f0000604482015290519081900360640190fd5b6000828481611d3357fe5b04949350505050565b600154604080517f63da12ba00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916363da12ba916004808301926020929190829003018186803b158015611d9a57600080fd5b505afa158015611dae573d6000803e3d6000fd5b505050506040513d6020811015611dc457600080fd5b50519050611ddc816901969368974c05b00000611b7f565b6005541115610cc6576040805162461bcd60e51b815260206004820152600e60248201527f423a204361702072656163686564000000000000000000000000000000000000604482015290519081900360640190fd5b600082821115611e89576040805162461bcd60e51b815260206004820152601760248201527f536166654d617468237375623a20554e444552464c4f57000000000000000000604482015290519081900360640190fd5b50900390565b6000828152602081905260409020611ea79082611a53565b15610fc157611eb4611a68565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000828152602081905260409020611f10908261205f565b15610fc157611f1d611a68565b6001600160a01b0316816001600160a01b0316837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45050565b600061128d8383612074565b600061128d836001600160a01b0384166120d8565b6000611290826120f0565b6fffffffffffffffffffffffffffffffff1690565b6000826004015460001461200a5782600401548210611fd25760028301548354611fcb91611e32565b9050611290565b611fcb611fff63018b8200610e89611ff7876003015487611e3290919063ffffffff16565b875490611c63565b600185015490611b7f565b506001820154611290565b600061202183836120d8565b61205757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611290565b506000611290565b600061128d836001600160a01b0384166120f4565b815460009082106120b65760405162461bcd60e51b81526004018080602001828103825260228152602001806121f66022913960400191505060405180910390fd5b8260000182815481106120c557fe5b9060005260206000200154905092915050565b60009081526001919091016020526040902054151590565b5490565b600081815260018301602052604081205480156121b0578354600019808301919081019060009087908390811061212757fe5b906000526020600020015490508087600001848154811061214457fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061217457fe5b60019003818190600052602060002001600090559055866001016000878152602001908152602001600020600090556001945050505050611290565b6000915050611290565b5080546000825560020290600052602060002090810190610cc691905b808211156121f157600080825560018201556002016121d7565b509056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e6473416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f206772616e74416363657373436f6e74726f6c3a2073656e646572206d75737420626520616e2061646d696e20746f207265766f6b65416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636520726f6c657320666f722073656c66a264697066735822122038af1846770ea91bd607b5a0e038cd2b013085b0e739f178522c5ee96be4243b64736f6c63430007060033

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

000000000000000000000000bb5a7c17ade983f03afd8b09922b1c117b9eabc0

-----Decoded View---------------
Arg [0] : admin (address): 0xbb5a7c17adE983f03AFd8B09922b1C117b9eabc0

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000bb5a7c17ade983f03afd8b09922b1c117b9eabc0


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.