Contract Overview |  MCH:Hero_Presale
Balance: 0 Ether
Ether Value: $0
Transactions: 4937 txns
 Latest 25 txns From a total of 4937 Transactions

TxHash Age From To Value [TxFee]
0xc3020285e53109e9ce051e48b983455da5fa15df14c42a7880a252f3967172578 hrs 45 mins ago0x4406571181978028df5621e973ce52cd5f2d05f8  IN   MCH:Hero_Presale0 Ether0.0008655855
0x558fe7bbf18c14d3fbd3ba77539ac927c4b352b0c44629c6c72deb648be20c7b9 hrs 1 min ago0xab3009dbb3c9a5694ed818cf0d159e069dd55107  IN   MCH:Hero_Presale0 Ether0.00133167
0xa9f3009001833691cebe0db312d9b8a942a5066c4bfe103084c7005a6fc53da810 hrs 36 mins ago0x07b99b5a4093be2c4465d55fcaad50a3cb61447a  IN   MCH:Hero_Presale0 Ether0.00223225
0xa070e7c4c427fbbaaf317380a72a01caf7abc85a89bf07c129cfd15d184807fd11 hrs 35 mins ago0xab3009dbb3c9a5694ed818cf0d159e069dd55107  IN   MCH:Hero_Presale0 Ether0.00221945
0xcfb070fd1e2614b14a2b99aa26c62447fdfbeab49046ce090e182dd9b571f65c13 hrs 42 mins ago0xff1a9252def51ede4489c05998f5e7cf8ad2c1b3  IN   MCH:Hero_Presale0 Ether0.00223161
0x7099274aa1f00592ab459cae03f4a6c6a899519411eca1fad591561aa2dd4a0814 hrs 56 mins ago0x4406571181978028df5621e973ce52cd5f2d05f8  IN   MCH:Hero_Presale0 Ether0.000543417
0x84afe041fb34ae82f93d38cd7cbcec860fea9640f5ca029d5edb3f0910a620c314 hrs 58 mins ago0x4406571181978028df5621e973ce52cd5f2d05f8  IN   MCH:Hero_Presale0 Ether0.000669483
0xbb0b64fff3cab362ebffaaa64e3afee68505415659485f8253dcdd7803241ed117 hrs 1 min ago0x07b99b5a4093be2c4465d55fcaad50a3cb61447a  IN   MCH:Hero_Presale0 Ether0.00223225
0xc32b7061a04dc9afa0926886a548eacb3cbde80aca629f31998900b32b70a32917 hrs 55 mins ago0x8e5d30f161ba3ebb09dc3c1f06515656af34baa1  IN   MCH:Hero_Presale0 Ether0.00061790223
0xe411a230b3c13d99611727b3c5ab676fee0feddf93c092c07568ddf087a591da17 hrs 57 mins ago0x8e5d30f161ba3ebb09dc3c1f06515656af34baa1  IN   MCH:Hero_Presale0 Ether0.0006919975
0x06da9054e17c2b7ee2e1435c1597ae2c4d3eacbaee5c0cc0f59f2cc1e940bfae22 hrs 5 mins ago0xaa2a3b5eb611cfde097a5533d8f73ffecac0b214  IN   MCH:Hero_Presale0 Ether0.000050692
0xd5a6542d2dc023d369848c424baa41f621ce91cc97103f84c87a8513c6a85e3f23 hrs 29 mins ago0x798fc047b8628533d70544a24a9ea37f92c88b64  IN   MCH:Hero_Presale0 Ether0.000050692
0xb7ba56d930c83be77105c1ed1e3ff6e475b387d8290ab185a92687b56efa82ae23 hrs 43 mins ago0xcf0e9b4746cfb97bae329fe5f696969f6564566a  IN   MCH:Hero_Presale0 Ether0.001109725
0xd50d1a7cdfe9ef56a9d2f0990f86c555af61a1f181355ab7d31a20b189afa6c91 day 11 mins ago0xcf0e9b4746cfb97bae329fe5f696969f6564566a  IN   MCH:Hero_Presale0 Ether0.001109725
0x6e482b9559a5663d9509be6c56cfad633a8df73b07cc942e865c8b89918f54c81 day 58 mins ago0xaef106ae6c08db1168d115c8e20dbbcda3c7e7de  IN   MCH:Hero_Presale0 Ether0.001624072
0xd54935dfae4d93f4cdacc1a675e2db36dd3d6986d5de5e44a2a0d5b9f6ee1d6e1 day 1 hr ago0xcf0e9b4746cfb97bae329fe5f696969f6564566a  IN   MCH:Hero_Presale0 Ether0.00218009
0x34cb96dcf8322f071f73600af0f63f0e66081d132827813c18c3a6b2df6c8fb01 day 1 hr ago0xd95175032aab87c9f5e3dddf2be20e7b2323478a  IN   MCH:Hero_Presale0 Ether0.001090045
0x740cb93e2346565f7e8bfd4ec69034aa670bf16ff0cee5742b9e389ede659a841 day 1 hr ago0x603c7057311199fcd8218ac276381fd9f6f0eddb  IN   MCH:Hero_Presale0 Ether0.001744072
0x8252cab34e0c3486f6eaefffd5d490852fa7d3dd1fed41dded0dcda0afc1860c1 day 1 hr ago0x4d38d1213f3675f68aa4bccd872d0b1f5ae1a13c  IN   MCH:Hero_Presale0 Ether0.001744072
0x8906e8261eb2b7971836790b8e85aff44936ef0325af9bf16930f8f2110c128a1 day 2 hrs ago0x6097007606193c481c07d2e6a5527ea3b9768cd7  IN   MCH:Hero_Presale0 Ether0.001744072
0xb281746d121b4612fbe1bbf708b7be274c3dcde25d59f0bfc45d5de2be8d33cd1 day 2 hrs ago0x85ab669ba35f5fe2b337a7ba14939b0517aa4017  IN   MCH:Hero_Presale0 Ether0.001624072
0x0c43cd9892aebae87905851410587c727e7ed981ca3c4d65f24696f21a375ab31 day 2 hrs ago0x74a5488fa9213aef751a3d6b124664dd620ff6ee  IN   MCH:Hero_Presale0 Ether0.0010353459
0x8133d9026ec795c79055bcc176990ad68d7acca11e0c241d76a3598176ebf6ea1 day 2 hrs ago0x44569c13864f4a252f512c0fdb1c68a5abc543bf  IN   MCH:Hero_Presale0 Ether0.0010353459
0x3b85a8d2d32280498c0f9f2d4d1f5b67f2f50d37ec66539e0ad9cc02ef0b832e1 day 2 hrs ago0xc658c9b8fcd7cc20025aca9b99149a272b5bf68e  IN   MCH:Hero_Presale0 Ether0.001744072
0x4b8bb3ad1680ba90e02d195c16ae70a8442b3a1ba9f40a310bcfd07b121e34431 day 2 hrs ago0x1264f7d54798c1898611cb07fea0389eea7235d0  IN   MCH:Hero_Presale0 Ether0.001744072
[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
 Latest 25 Internal Txns, Click Here To View More View All
ParentTxHash Block Age From To Value
0x80f9da22c0b5fa47a63d0884e9a6a21ccb334df29a09785507cda6e259d07a9a643279019 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xe7af11370c3bab51230d8307454350bdf6d68f4a35.704222117672495829 Ether
0xab256c924e4160e0c105cd4d0ac46018e536046183fb77122080c8479dae2f03642999819 days 22 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x40c9afd96646df172b6fa31211fb51bf5144081e0.000031221261836837 Ether
0xa949c413deb06677dad32a738cce5d73a5fec2a993538c9d9311e428c1fe4f8a642997719 days 22 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa45c6991a2c3d74ada3a279e21135133ce3da8a0.00235377005848806 Ether
0xf6e434f01a654605913d5a7d385f9eaaf701c07b7391acf45c827313e8d768dd642959019 days 23 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000117520883268269 Ether
0x670b31985a62e8eed3becf6bc9930dd56b854743492777a58adaa485f1dbefe9642796220 days 6 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ad8f1fb5c25f2ac83bf26ca2b6d857037d6ba840.000767529163824232 Ether
0xc4f2fcbbf0448fb335a44459a78bb2e15d24ff6f0742d6463d54ac1de6e31120642689620 days 10 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xcaff49b031e5099a54f5959dc931c27e366273690.00027635849798034 Ether
0x83e4c45e9f8bde79125dfa22167bd9a16861a47893a923e979d18970bb9106c3642673420 days 10 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xf96c878bb8d36d8203fa2a358d770f1ae85a1d470.000056706459629636 Ether
0xdc20e02fed068677404eabf608d31f9b5f8d7c709765ebd07292cc802dca57e2642628120 days 12 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa45c6991a2c3d74ada3a279e21135133ce3da8a0.000042947044652632 Ether
0xb10f69d2de12cc6f5c07ff081959d3c04c3c564fc63effc84407c67ac7044d15642206021 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa7b07b6de964d022c832f20ced2dac16384b7aa0.000589297430622244 Ether
0x30eae0b46e72097c6aa5a3b702ebc6bdfc7aaefded07d540600f7a1a7b26f63b642196821 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa7b07b6de964d022c832f20ced2dac16384b7aa0.000047119936254208 Ether
0x1cec5086ed2f1538d8524b3a2b69765c15fc838ec5a0e862f33021db8d781316642194321 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x431434d43cea4131650520cb105b90fe204fa39d0.000063161054912408 Ether
0x8990af91a3ae9aec187283b2c3add147f3cda60c13ecabb607b036be291fa785641835021 days 19 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x12f561c77e1e542b8d6f9de5f3e2faf03d87b3b80.00003725965242613 Ether
0x1588d281cfacec2e4195fdaa5cb3a5ac4d559f7af72b99f41370d13a427daff2641833321 days 20 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000262467736842824 Ether
0x650e955e98a51a24c17d0e38c57499824018418372312983807146a0f2bd888e641831521 days 20 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000054190227769198 Ether
0x506bf9db530d66a23af6b4cfb4ef9669a8c24544b0209bfae02fcbf2603a5463641615822 days 4 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xaa24875b7bfd15364af1063f8c1330c53146b81f0.000070680592497302 Ether
0xd1113b96af97a3cc6d750c6d073f81035045ba8f8bdda41c9e880c531390b6bd641605222 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x2e1bc1abc2e86e3405766f6b39ed8fe388b344970.000058564601634346 Ether
0x70a9954c196321e4dafd5f0541279934b9350d38278185654966d152e39daba1641601822 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x2a3d897cd8cc82f310b53f4511ebdefca7f0232c0.000040742434896311 Ether
0x49583b65cd655393484b39d94a34b214bd9439eb9618c78ba977a2f5363a6f6a641591022 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ba3e11abf8c93186637847ec590fcd3aa588bd20.000033388657128154 Ether
0x54750d35119882b4e9a8f522f8ffbdb835ce7c83fd8203546cd2abd52bf8545a641588522 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ba3e11abf8c93186637847ec590fcd3aa588bd20.000022920115099777 Ether
0xcb5c94fdb955255fcf9fed3ddf4cd259fff3592663880f90d89a77a3523ec06c641582222 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xaa764d0f94b0ebcf6eb0a29bc2fb19b48edd23350.011795271321073031 Ether
0xda4c5ea6476906133207132b6e06129e19ddd47f453d57fb96901bc61cb1fbb4641528322 days 8 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xbcd2c48e447a45244ccefdb232b2f7b5f86f43bd0.000056682034275433 Ether
0x2bee68c508bfce829c2dc3bf52443ff62fad6c99c4e7159c5be12a799a8203ed641441222 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x8ddd99328f94489460ed8387a9bd6577a42fb3aa0.000026907286942602 Ether
0x075e9814ff52d118a66319984104e2d797ebe46a18fb7c7b18e3c4c7c1d55527641440722 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x8ddd99328f94489460ed8387a9bd6577a42fb3aa0.000157887577158355 Ether
0x1e3c2b4139eb22add1955ae9ddc4ed5dc112f133c9b95c719c9053d138461802641428122 days 12 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x3d3a8ce65e3595f60be146f5f05b42ad63c4be7c0.000013004904153729 Ether
0x9b2cf63a1bc252afb7e40472415548424ed7cfd21fb5bf9620e327f49a7229b0641424922 days 12 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x3d3a8ce65e3595f60be146f5f05b42ad63c4be7c0.000014352468616973 Ether
[ Download CSV Export  ] 
Warning: The Compiled Contract might be susceptible to ExpExponentCleanup (medium/high-severity), EventStructWrongData (very low-severity) SolidityCompiler Bugs.

Contract Source Code Verified (Exact Match)
Contract Name: HeroPresale
Compiler Text: v0.4.24+commit.e67f0147
Optimization Enabled: Yes
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

pragma solidity 0.4.24;

// File: contracts/lib/openzeppelin-solidity/contracts/access/Roles.sol

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
  struct Role {
    mapping (address => bool) bearer;
  }

  /**
   * @dev give an account access to this role
   */
  function add(Role storage role, address account) internal {
    require(account != address(0));
    role.bearer[account] = true;
  }

  /**
   * @dev remove an account's access to this role
   */
  function remove(Role storage role, address account) internal {
    require(account != address(0));
    role.bearer[account] = false;
  }

  /**
   * @dev check if an account has this role
   * @return bool
   */
  function has(Role storage role, address account)
    internal
    view
    returns (bool)
  {
    require(account != address(0));
    return role.bearer[account];
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/access/roles/MinterRole.sol

contract MinterRole {
  using Roles for Roles.Role;

  event MinterAdded(address indexed account);
  event MinterRemoved(address indexed account);

  Roles.Role private minters;

  constructor() public {
    minters.add(msg.sender);
  }

  modifier onlyMinter() {
    require(isMinter(msg.sender));
    _;
  }

  function isMinter(address account) public view returns (bool) {
    return minters.has(account);
  }

  function addMinter(address account) public onlyMinter {
    minters.add(account);
    emit MinterAdded(account);
  }

  function renounceMinter() public {
    minters.remove(msg.sender);
  }

  function _removeMinter(address account) internal {
    minters.remove(account);
    emit MinterRemoved(account);
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/introspection/IERC165.sol

/**
 * @title IERC165
 * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
 */
interface IERC165 {

  /**
   * @notice Query if a contract implements an interface
   * @param interfaceId The interface identifier, as specified in ERC-165
   * @dev Interface identification is specified in ERC-165. This function
   * uses less than 30,000 gas.
   */
  function supportsInterface(bytes4 interfaceId)
    external
    view
    returns (bool);
}

// File: contracts/lib/openzeppelin-solidity/contracts/introspection/ERC165.sol

/**
 * @title ERC165
 * @author Matt Condon (@shrugs)
 * @dev Implements ERC165 using a lookup table.
 */
contract ERC165 is IERC165 {

  bytes4 private constant _InterfaceId_ERC165 = 0x01ffc9a7;
  /**
   * 0x01ffc9a7 ===
   *   bytes4(keccak256('supportsInterface(bytes4)'))
   */

  /**
   * @dev a mapping of interface id to whether or not it's supported
   */
  mapping(bytes4 => bool) internal _supportedInterfaces;

  /**
   * @dev A contract implementing SupportsInterfaceWithLookup
   * implement ERC165 itself
   */
  constructor()
    public
  {
    _registerInterface(_InterfaceId_ERC165);
  }

  /**
   * @dev implement supportsInterface(bytes4) using a lookup table
   */
  function supportsInterface(bytes4 interfaceId)
    external
    view
    returns (bool)
  {
    return _supportedInterfaces[interfaceId];
  }

  /**
   * @dev private method for registering an interface
   */
  function _registerInterface(bytes4 interfaceId)
    internal
  {
    require(interfaceId != 0xffffffff);
    _supportedInterfaces[interfaceId] = true;
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/math/SafeMath.sol

/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, 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);

    return c;
  }

  /**
  * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b > 0); // Solidity only automatically asserts when dividing by 0
    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 numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    require(b <= a);
    uint256 c = a - b;

    return c;
  }

  /**
  * @dev Adds two numbers, reverts on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a);

    return c;
  }

  /**
  * @dev Divides two numbers 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);
    return a % b;
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/utils/Address.sol

/**
 * Utility library of inline functions on addresses
 */
library Address {

  /**
   * Returns whether the target address is a contract
   * @dev This function will return false if invoked during the constructor of a contract,
   * as the code is not actually created until after the constructor finishes.
   * @param account address of the account to check
   * @return whether the target address is a contract
   */
  function isContract(address account) internal view returns (bool) {
    uint256 size;
    // XXX 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.
    // See https://ethereum.stackexchange.com/a/14016/36603
    // for more details about how this works.
    // TODO Check this again before the Serenity release, because all addresses will be
    // contracts then.
    // solium-disable-next-line security/no-inline-assembly
    assembly { size := extcodesize(account) }
    return size > 0;
  }

}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/IERC721.sol

/**
 * @title ERC721 Non-Fungible Token Standard basic interface
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721 is IERC165 {

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 indexed tokenId
  );
  event Approval(
    address indexed owner,
    address indexed approved,
    uint256 indexed tokenId
  );
  event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
  );

  function balanceOf(address owner) public view returns (uint256 balance);
  function ownerOf(uint256 tokenId) public view returns (address owner);

  function approve(address to, uint256 tokenId) public;
  function getApproved(uint256 tokenId)
    public view returns (address operator);

  function setApprovalForAll(address operator, bool _approved) public;
  function isApprovedForAll(address owner, address operator)
    public view returns (bool);

  function transferFrom(address from, address to, uint256 tokenId) public;
  function safeTransferFrom(address from, address to, uint256 tokenId)
    public;

  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes data
  )
    public;
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
  /**
   * @notice Handle the receipt of an NFT
   * @dev The ERC721 smart contract calls this function on the recipient
   * after a `safeTransfer`. This function MUST return the function selector,
   * otherwise the caller will revert the transaction. The selector to be
   * returned can be obtained as `this.onERC721Received.selector`. This
   * function MAY throw to revert and reject the transfer.
   * Note: the ERC721 contract address is always the message sender.
   * @param operator The address which called `safeTransferFrom` function
   * @param from The address which previously owned the token
   * @param tokenId The NFT identifier which is being transferred
   * @param data Additional data with no specified format
   * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
   */
  function onERC721Received(
    address operator,
    address from,
    uint256 tokenId,
    bytes data
  )
    public
    returns(bytes4);
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721.sol

/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721 is ERC165, IERC721 {

  using SafeMath for uint256;
  using Address for address;

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

  // Mapping from token ID to owner
  mapping (uint256 => address) private _tokenOwner;

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

  // Mapping from owner to number of owned token
  mapping (address => uint256) private _ownedTokensCount;

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

  bytes4 private constant _InterfaceId_ERC721 = 0x80ac58cd;
  /*
   * 0x80ac58cd ===
   *   bytes4(keccak256('balanceOf(address)')) ^
   *   bytes4(keccak256('ownerOf(uint256)')) ^
   *   bytes4(keccak256('approve(address,uint256)')) ^
   *   bytes4(keccak256('getApproved(uint256)')) ^
   *   bytes4(keccak256('setApprovalForAll(address,bool)')) ^
   *   bytes4(keccak256('isApprovedForAll(address,address)')) ^
   *   bytes4(keccak256('transferFrom(address,address,uint256)')) ^
   *   bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
   *   bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
   */

  constructor()
    public
  {
    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(_InterfaceId_ERC721);
  }

  /**
   * @dev Gets the balance of the specified address
   * @param owner address to query the balance of
   * @return uint256 representing the amount owned by the passed address
   */
  function balanceOf(address owner) public view returns (uint256) {
    require(owner != address(0));
    return _ownedTokensCount[owner];
  }

  /**
   * @dev Gets the owner of the specified token ID
   * @param tokenId uint256 ID of the token to query the owner of
   * @return owner address currently marked as the owner of the given token ID
   */
  function ownerOf(uint256 tokenId) public view returns (address) {
    address owner = _tokenOwner[tokenId];
    require(owner != address(0));
    return owner;
  }

  /**
   * @dev Approves another address to transfer the given token ID
   * The zero address indicates there is no approved address.
   * There can only be one approved address per token at a given time.
   * Can only be called by the token owner or an approved operator.
   * @param to address to be approved for the given token ID
   * @param tokenId uint256 ID of the token to be approved
   */
  function approve(address to, uint256 tokenId) public {
    address owner = ownerOf(tokenId);
    require(to != owner);
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

    _tokenApprovals[tokenId] = to;
    emit Approval(owner, to, tokenId);
  }

  /**
   * @dev Gets the approved address for a token ID, or zero if no address set
   * Reverts if the token ID does not exist.
   * @param tokenId uint256 ID of the token to query the approval of
   * @return address currently approved for the given token ID
   */
  function getApproved(uint256 tokenId) public view returns (address) {
    require(_exists(tokenId));
    return _tokenApprovals[tokenId];
  }

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param to operator address to set the approval
   * @param approved representing the status of the approval to be set
   */
  function setApprovalForAll(address to, bool approved) public {
    require(to != msg.sender);
    _operatorApprovals[msg.sender][to] = approved;
    emit ApprovalForAll(msg.sender, to, approved);
  }

  /**
   * @dev Tells whether an operator is approved by a given owner
   * @param owner owner address which you want to query the approval of
   * @param operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(
    address owner,
    address operator
  )
    public
    view
    returns (bool)
  {
    return _operatorApprovals[owner][operator];
  }

  /**
   * @dev Transfers the ownership of a given token ID to another address
   * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
  */
  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
  {
    require(_isApprovedOrOwner(msg.sender, tokenId));
    require(to != address(0));

    _clearApproval(from, tokenId);
    _removeTokenFrom(from, tokenId);
    _addTokenTo(to, tokenId);

    emit Transfer(from, to, tokenId);
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   *
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
  */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
  {
    // solium-disable-next-line arg-overflow
    safeTransferFrom(from, to, tokenId, "");
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes data to send along with a safe transfer check
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes _data
  )
    public
  {
    transferFrom(from, to, tokenId);
    // solium-disable-next-line arg-overflow
    require(_checkAndCallSafeTransfer(from, to, tokenId, _data));
  }

  /**
   * @dev Returns whether the specified token exists
   * @param tokenId uint256 ID of the token to query the existence of
   * @return whether the token exists
   */
  function _exists(uint256 tokenId) internal view returns (bool) {
    address owner = _tokenOwner[tokenId];
    return owner != address(0);
  }

  /**
   * @dev Returns whether the given spender can transfer a given token ID
   * @param spender address of the spender to query
   * @param tokenId uint256 ID of the token to be transferred
   * @return bool whether the msg.sender is approved for the given token ID,
   *  is an operator of the owner, or is the owner of the token
   */
  function _isApprovedOrOwner(
    address spender,
    uint256 tokenId
  )
    internal
    view
    returns (bool)
  {
    address owner = ownerOf(tokenId);
    // Disable solium check because of
    // https://github.com/duaraghav8/Solium/issues/175
    // solium-disable-next-line operator-whitespace
    return (
      spender == owner ||
      getApproved(tokenId) == spender ||
      isApprovedForAll(owner, spender)
    );
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param to The address that will own the minted token
   * @param tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address to, uint256 tokenId) internal {
    require(to != address(0));
    _addTokenTo(to, tokenId);
    emit Transfer(address(0), to, tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    _clearApproval(owner, tokenId);
    _removeTokenFrom(owner, tokenId);
    emit Transfer(owner, address(0), tokenId);
  }

  /**
   * @dev Internal function to clear current approval of a given token ID
   * Reverts if the given address is not indeed the owner of the token
   * @param owner owner of the token
   * @param tokenId uint256 ID of the token to be transferred
   */
  function _clearApproval(address owner, uint256 tokenId) internal {
    require(ownerOf(tokenId) == owner);
    if (_tokenApprovals[tokenId] != address(0)) {
      _tokenApprovals[tokenId] = address(0);
    }
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param to address representing the new owner of the given token ID
   * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function _addTokenTo(address to, uint256 tokenId) internal {
    require(_tokenOwner[tokenId] == address(0));
    _tokenOwner[tokenId] = to;
    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param from address representing the previous owner of the given token ID
   * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function _removeTokenFrom(address from, uint256 tokenId) internal {
    require(ownerOf(tokenId) == from);
    _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
    _tokenOwner[tokenId] = address(0);
  }

  /**
   * @dev Internal function to invoke `onERC721Received` on a target address
   * The call is not executed if the target address is not a contract
   * @param from address representing the previous owner of the given token ID
   * @param to target address that will receive the tokens
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return whether the call correctly returned the expected magic value
   */
  function _checkAndCallSafeTransfer(
    address from,
    address to,
    uint256 tokenId,
    bytes _data
  )
    internal
    returns (bool)
  {
    if (!to.isContract()) {
      return true;
    }
    bytes4 retval = IERC721Receiver(to).onERC721Received(
      msg.sender, from, tokenId, _data);
    return (retval == _ERC721_RECEIVED);
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/IERC721Enumerable.sol

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721Enumerable is IERC721 {
  function totalSupply() public view returns (uint256);
  function tokenOfOwnerByIndex(
    address owner,
    uint256 index
  )
    public
    view
    returns (uint256 tokenId);

  function tokenByIndex(uint256 index) public view returns (uint256);
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721Enumerable.sol

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

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

  // Array with all token ids, used for enumeration
  uint256[] private _allTokens;

  // Mapping from token id to position in the allTokens array
  mapping(uint256 => uint256) private _allTokensIndex;

  bytes4 private constant _InterfaceId_ERC721Enumerable = 0x780e9d63;
  /**
   * 0x780e9d63 ===
   *   bytes4(keccak256('totalSupply()')) ^
   *   bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
   *   bytes4(keccak256('tokenByIndex(uint256)'))
   */

  /**
   * @dev Constructor function
   */
  constructor() public {
    // register the supported interface to conform to ERC721 via ERC165
    _registerInterface(_InterfaceId_ERC721Enumerable);
  }

  /**
   * @dev Gets the token ID at a given index of the tokens list of the requested owner
   * @param owner address owning the tokens list to be accessed
   * @param index uint256 representing the index to be accessed of the requested tokens list
   * @return uint256 token ID at the given index of the tokens list owned by the requested address
   */
  function tokenOfOwnerByIndex(
    address owner,
    uint256 index
  )
    public
    view
    returns (uint256)
  {
    require(index < balanceOf(owner));
    return _ownedTokens[owner][index];
  }

  /**
   * @dev Gets the total amount of tokens stored by the contract
   * @return uint256 representing the total amount of tokens
   */
  function totalSupply() public view returns (uint256) {
    return _allTokens.length;
  }

  /**
   * @dev Gets the token ID at a given index of all the tokens in this contract
   * Reverts if the index is greater or equal to the total number of tokens
   * @param index uint256 representing the index to be accessed of the tokens list
   * @return uint256 token ID at the given index of the tokens list
   */
  function tokenByIndex(uint256 index) public view returns (uint256) {
    require(index < totalSupply());
    return _allTokens[index];
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param to address representing the new owner of the given token ID
   * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function _addTokenTo(address to, uint256 tokenId) internal {
    super._addTokenTo(to, tokenId);
    uint256 length = _ownedTokens[to].length;
    _ownedTokens[to].push(tokenId);
    _ownedTokensIndex[tokenId] = length;
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param from address representing the previous owner of the given token ID
   * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function _removeTokenFrom(address from, uint256 tokenId) internal {
    super._removeTokenFrom(from, tokenId);

    // To prevent a gap in the array, we store the last token in the index of the token to delete, and
    // then delete the last slot.
    uint256 tokenIndex = _ownedTokensIndex[tokenId];
    uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
    uint256 lastToken = _ownedTokens[from][lastTokenIndex];

    _ownedTokens[from][tokenIndex] = lastToken;
    // This also deletes the contents at the last position of the array
    _ownedTokens[from].length--;

    // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
    // be zero. Then we can make sure that we will remove tokenId from the ownedTokens list since we are first swapping
    // the lastToken to the first position, and then dropping the element placed in the last position of the list

    _ownedTokensIndex[tokenId] = 0;
    _ownedTokensIndex[lastToken] = tokenIndex;
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param to address the beneficiary that will own the minted token
   * @param tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address to, uint256 tokenId) internal {
    super._mint(to, tokenId);

    _allTokensIndex[tokenId] = _allTokens.length;
    _allTokens.push(tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param owner owner of the token to burn
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    super._burn(owner, tokenId);

    // Reorg all tokens array
    uint256 tokenIndex = _allTokensIndex[tokenId];
    uint256 lastTokenIndex = _allTokens.length.sub(1);
    uint256 lastToken = _allTokens[lastTokenIndex];

    _allTokens[tokenIndex] = lastToken;
    _allTokens[lastTokenIndex] = 0;

    _allTokens.length--;
    _allTokensIndex[tokenId] = 0;
    _allTokensIndex[lastToken] = tokenIndex;
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/IERC721Metadata.sol

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721Metadata is IERC721 {
  function name() external view returns (string);
  function symbol() external view returns (string);
  function tokenURI(uint256 tokenId) public view returns (string);
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721Metadata.sol

contract ERC721Metadata is ERC165, ERC721, IERC721Metadata {
  // Token name
  string internal _name;

  // Token symbol
  string internal _symbol;

  // Optional mapping for token URIs
  mapping(uint256 => string) private _tokenURIs;

  bytes4 private constant InterfaceId_ERC721Metadata = 0x5b5e139f;
  /**
   * 0x5b5e139f ===
   *   bytes4(keccak256('name()')) ^
   *   bytes4(keccak256('symbol()')) ^
   *   bytes4(keccak256('tokenURI(uint256)'))
   */

  /**
   * @dev Constructor function
   */
  constructor(string name, string symbol) public {
    _name = name;
    _symbol = symbol;

    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(InterfaceId_ERC721Metadata);
  }

  /**
   * @dev Gets the token name
   * @return string representing the token name
   */
  function name() external view returns (string) {
    return _name;
  }

  /**
   * @dev Gets the token symbol
   * @return string representing the token symbol
   */
  function symbol() external view returns (string) {
    return _symbol;
  }

  /**
   * @dev Returns an URI for a given token ID
   * Throws if the token ID does not exist. May return an empty string.
   * @param tokenId uint256 ID of the token to query
   */
  function tokenURI(uint256 tokenId) public view returns (string) {
    require(_exists(tokenId));
    return _tokenURIs[tokenId];
  }

  /**
   * @dev Internal function to set the token URI for a given token
   * Reverts if the token ID does not exist
   * @param tokenId uint256 ID of the token to set its URI
   * @param uri string URI to assign
   */
  function _setTokenURI(uint256 tokenId, string uri) internal {
    require(_exists(tokenId));
    _tokenURIs[tokenId] = uri;
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param owner owner of the token to burn
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    super._burn(owner, tokenId);

    // Clear metadata (if any)
    if (bytes(_tokenURIs[tokenId]).length != 0) {
      delete _tokenURIs[tokenId];
    }
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol

/**
 * @title Full ERC721 Token
 * This implementation includes all the required and some optional functionality of the ERC721 standard
 * Moreover, it includes approve all functionality using operator terminology
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721Full is ERC721, ERC721Enumerable, ERC721Metadata {
  constructor(string name, string symbol) ERC721Metadata(name, symbol)
    public
  {
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721Mintable.sol

/**
 * @title ERC721Mintable
 * @dev ERC721 minting logic
 */
contract ERC721Mintable is ERC721Full, MinterRole {
  event MintingFinished();

  bool private _mintingFinished = false;

  modifier onlyBeforeMintingFinished() {
    require(!_mintingFinished);
    _;
  }

  /**
   * @return true if the minting is finished.
   */
  function mintingFinished() public view returns(bool) {
    return _mintingFinished;
  }

  /**
   * @dev Function to mint tokens
   * @param to The address that will receive the minted tokens.
   * @param tokenId The token id to mint.
   * @return A boolean that indicates if the operation was successful.
   */
  function mint(
    address to,
    uint256 tokenId
  )
    public
    onlyMinter
    onlyBeforeMintingFinished
    returns (bool)
  {
    _mint(to, tokenId);
    return true;
  }

  function mintWithTokenURI(
    address to,
    uint256 tokenId,
    string tokenURI
  )
    public
    onlyMinter
    onlyBeforeMintingFinished
    returns (bool)
  {
    mint(to, tokenId);
    _setTokenURI(tokenId, tokenURI);
    return true;
  }

  /**
   * @dev Function to stop minting new tokens.
   * @return True if the operation was successful.
   */
  function finishMinting()
    public
    onlyMinter
    onlyBeforeMintingFinished
    returns (bool)
  {
    _mintingFinished = true;
    emit MintingFinished();
    return true;
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/access/roles/PauserRole.sol

contract PauserRole {
  using Roles for Roles.Role;

  event PauserAdded(address indexed account);
  event PauserRemoved(address indexed account);

  Roles.Role private pausers;

  constructor() public {
    pausers.add(msg.sender);
  }

  modifier onlyPauser() {
    require(isPauser(msg.sender));
    _;
  }

  function isPauser(address account) public view returns (bool) {
    return pausers.has(account);
  }

  function addPauser(address account) public onlyPauser {
    pausers.add(account);
    emit PauserAdded(account);
  }

  function renouncePauser() public {
    pausers.remove(msg.sender);
  }

  function _removePauser(address account) internal {
    pausers.remove(account);
    emit PauserRemoved(account);
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/lifecycle/Pausable.sol

/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is PauserRole {
  event Paused();
  event Unpaused();

  bool private _paused = false;


  /**
   * @return true if the contract is paused, false otherwise.
   */
  function paused() public view returns(bool) {
    return _paused;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!_paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(_paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() public onlyPauser whenNotPaused {
    _paused = true;
    emit Paused();
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() public onlyPauser whenPaused {
    _paused = false;
    emit Unpaused();
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC721/ERC721Pausable.sol

/**
 * @title ERC721 Non-Fungible Pausable token
 * @dev ERC721 modified with pausable transfers.
 **/
contract ERC721Pausable is ERC721, Pausable {
  function approve(
    address to,
    uint256 tokenId
  )
    public
    whenNotPaused
  {
    super.approve(to, tokenId);
  }

  function setApprovalForAll(
    address to,
    bool approved
  )
    public
    whenNotPaused
  {
    super.setApprovalForAll(to, approved);
  }

  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
    whenNotPaused
  {
    super.transferFrom(from, to, tokenId);
  }
}

// File: contracts/HeroAsset.sol

contract HeroAsset is ERC721Mintable, ERC721Pausable {

    uint16 public constant HERO_TYPE_OFFSET = 10000;

    string public tokenURIPrefix = "https://www.mycryptoheroes.net/metadata/hero/";
    mapping(uint16 => uint16) private heroTypeToSupplyLimit;

    constructor() public ERC721Full("MyCryptoHeroes:Hero", "MCHH") {}

    function setSupplyLimit(uint16 _heroType, uint16 _supplyLimit) external onlyMinter {
        require(heroTypeToSupplyLimit[_heroType] == 0 || _supplyLimit < heroTypeToSupplyLimit[_heroType],
            "_supplyLimit is bigger");
        heroTypeToSupplyLimit[_heroType] = _supplyLimit;
    }

    function setTokenURIPrefix(string _tokenURIPrefix) external onlyMinter {
        tokenURIPrefix = _tokenURIPrefix;
    }

    function getSupplyLimit(uint16 _heroType) public view returns (uint16) {
        return heroTypeToSupplyLimit[_heroType];
    }

    function mintHeroAsset(address _owner, uint256 _tokenId) public onlyMinter {
        uint16 _heroType = uint16(_tokenId / HERO_TYPE_OFFSET);
        uint16 _heroTypeIndex = uint16(_tokenId % HERO_TYPE_OFFSET) - 1;
        require(_heroTypeIndex < heroTypeToSupplyLimit[_heroType], "supply over");
        _mint(_owner, _tokenId);
    }

    function tokenURI(uint256 tokenId) public view returns (string) {
        bytes32 tokenIdBytes;
        if (tokenId == 0) {
            tokenIdBytes = "0";
        } else {
            uint256 value = tokenId;
            while (value > 0) {
                tokenIdBytes = bytes32(uint256(tokenIdBytes) / (2 ** 8));
                tokenIdBytes |= bytes32(((value % 10) + 48) * 2 ** (8 * 31));
                value /= 10;
            }
        }

        bytes memory prefixBytes = bytes(tokenURIPrefix);
        bytes memory tokenURIBytes = new bytes(prefixBytes.length + tokenIdBytes.length);

        uint8 i;
        uint8 index = 0;
        
        for (i = 0; i < prefixBytes.length; i++) {
            tokenURIBytes[index] = prefixBytes[i];
            index++;
        }
        
        for (i = 0; i < tokenIdBytes.length; i++) {
            tokenURIBytes[index] = tokenIdBytes[i];
            index++;
        }
        
        return string(tokenURIBytes);
    }

}

// File: contracts/lib/openzeppelin-solidity/contracts/ownership/Ownable.sol

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address private _owner;


  event OwnershipRenounced(address indexed previousOwner);
  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() public {
    _owner = msg.sender;
  }

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

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(isOwner());
    _;
  }

  /**
   * @return true if `msg.sender` is the owner of the contract.
   */
  function isOwner() public view returns(bool) {
    return msg.sender == _owner;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   * @notice Renouncing to ownership will leave the contract without an owner.
   * It will not be possible to call the functions with the `onlyOwner`
   * modifier anymore.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(_owner);
    _owner = address(0);
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0));
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20 {
  function totalSupply() external view returns (uint256);

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

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

  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);

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 value
  );

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

// File: contracts/lib/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol

/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
 * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
 */
contract ERC20 is IERC20 {
  using SafeMath for uint256;

  mapping (address => uint256) private _balances;

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

  uint256 private _totalSupply;

  /**
  * @dev Total number of tokens in existence
  */
  function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address owner) public view returns (uint256) {
    return _balances[owner];
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param owner address The address which owns the funds.
   * @param spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(
    address owner,
    address spender
   )
    public
    view
    returns (uint256)
  {
    return _allowed[owner][spender];
  }

  /**
  * @dev Transfer token for a specified address
  * @param to The address to transfer to.
  * @param value The amount to be transferred.
  */
  function transfer(address to, uint256 value) public returns (bool) {
    require(value <= _balances[msg.sender]);
    require(to != address(0));

    _balances[msg.sender] = _balances[msg.sender].sub(value);
    _balances[to] = _balances[to].add(value);
    emit Transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param spender The address which will spend the funds.
   * @param value The amount of tokens to be spent.
   */
  function approve(address spender, uint256 value) public returns (bool) {
    require(spender != address(0));

    _allowed[msg.sender][spender] = value;
    emit Approval(msg.sender, spender, value);
    return true;
  }

  /**
   * @dev Transfer tokens from one address to another
   * @param from address The address which you want to send tokens from
   * @param to address The address which you want to transfer to
   * @param value uint256 the amount of tokens to be transferred
   */
  function transferFrom(
    address from,
    address to,
    uint256 value
  )
    public
    returns (bool)
  {
    require(value <= _balances[from]);
    require(value <= _allowed[from][msg.sender]);
    require(to != address(0));

    _balances[from] = _balances[from].sub(value);
    _balances[to] = _balances[to].add(value);
    _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
    emit Transfer(from, to, value);
    return true;
  }

  /**
   * @dev Increase the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param addedValue The amount of tokens to increase the allowance by.
   */
  function increaseAllowance(
    address spender,
    uint256 addedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].add(addedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner allowed to a spender.
   * approve should be called when allowed_[_spender] == 0. To decrement
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   * @param spender The address which will spend the funds.
   * @param subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseAllowance(
    address spender,
    uint256 subtractedValue
  )
    public
    returns (bool)
  {
    require(spender != address(0));

    _allowed[msg.sender][spender] = (
      _allowed[msg.sender][spender].sub(subtractedValue));
    emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Internal function that mints an amount of the token and assigns it to
   * an account. This encapsulates the modification of balances such that the
   * proper events are emitted.
   * @param account The account that will receive the created tokens.
   * @param amount The amount that will be created.
   */
  function _mint(address account, uint256 amount) internal {
    require(account != 0);
    _totalSupply = _totalSupply.add(amount);
    _balances[account] = _balances[account].add(amount);
    emit Transfer(address(0), account, amount);
  }

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account.
   * @param account The account whose tokens will be burnt.
   * @param amount The amount that will be burnt.
   */
  function _burn(address account, uint256 amount) internal {
    require(account != 0);
    require(amount <= _balances[account]);

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

  /**
   * @dev Internal function that burns an amount of the token of a given
   * account, deducting from the sender's allowance for said account. Uses the
   * internal burn function.
   * @param account The account whose tokens will be burnt.
   * @param amount The amount that will be burnt.
   */
  function _burnFrom(address account, uint256 amount) internal {
    require(amount <= _allowed[account][msg.sender]);

    // Should https://github.com/OpenZeppelin/zeppelin-solidity/issues/707 be accepted,
    // this function needs to emit an event with the updated approval.
    _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(
      amount);
    _burn(account, amount);
  }
}

// File: contracts/lib/openzeppelin-solidity/contracts/utils/ReentrancyGuard.sol

/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <[email protected]π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard {

  /// @dev counter to allow mutex lock with only one SSTORE operation
  uint256 private _guardCounter = 1;

  /**
   * @dev Prevents a contract from calling itself, directly or indirectly.
   * If you mark a function `nonReentrant`, you should also
   * mark it `external`. Calling one `nonReentrant` function from
   * another is not supported. Instead, you can implement a
   * `private` function doing the actual work, and an `external`
   * wrapper marked as `nonReentrant`.
   */
  modifier nonReentrant() {
    _guardCounter += 1;
    uint256 localCounter = _guardCounter;
    _;
    require(localCounter == _guardCounter);
  }

}

// File: contracts/HeroPresale.sol

contract HeroPresale is Ownable, Pausable, ReentrancyGuard {
    using SafeMath for uint256;

    struct HeroSale {
        uint128 highestPrice;
        uint128 previousPrice;
        uint128 priceIncreaseTo;
        uint64  since;
        uint64  until;
        uint64  previousSaleAt;
        uint16  lowestPriceRate;
        uint16  decreaseRate;
        uint16  supplyLimit;
        uint16  suppliedCounts;
        uint8   currency;
        bool    exists;
    }
    
    mapping(uint16 => HeroSale) public heroTypeToHeroSales;
    mapping(uint16 => uint256[]) public heroTypeIds;
    mapping(uint16 => mapping(address => bool)) public hasAirDropHero;

    ERC20 public coin;
    HeroAsset public heroAsset;
    uint16 constant internal SUPPLY_LIMIT_MAX = 10000;

    event AddSalesEvent(
        uint16 indexed heroType,
        uint128 startPrice,
        uint256 lowestPrice,
        uint256 becomeLowestAt
    );

    event SoldHeroEvent(
        uint16 indexed heroType,
        uint256 soldPrice,
        uint64  soldAt,
        uint256 priceIncreaseTo,
        uint256 lowestPrice,
        uint256 becomeLowestAt,
        address purchasedBy,
        address indexed code,
        uint8   currency
    );

    function setHeroAssetAddress(address _heroAssetAddress) external onlyOwner() {
        heroAsset = HeroAsset(_heroAssetAddress);
    }

    function setCoinAddress(ERC20 _coinAddress) external onlyOwner() {
        coin = _coinAddress;
    }

    function withdrawEther() external onlyOwner() {
        owner().transfer(address(this).balance);
    }

    function withdrawEMONT() external onlyOwner() {
        uint256 emontBalance = coin.balanceOf(this);
        coin.approve(address(this), emontBalance);
        coin.transferFrom(address(this), msg.sender, emontBalance);
    }

    function addSales(
        uint16 _heroType,
        uint128 _startPrice,
        uint16 _lowestPriceRate,
        uint16 _decreaseRate,
        uint64 _since,
        uint64 _until,
        uint16 _supplyLimit,
        uint8  _currency
    ) external onlyOwner() {
        require(!heroTypeToHeroSales[_heroType].exists, "this heroType is already added sales");
        require(0 <= _lowestPriceRate && _lowestPriceRate <= 100, "lowestPriceRate should be between 0 and 100");
        require(1 <= _decreaseRate && _decreaseRate <= 100, "decreaseRate should be should be between 1 and 100");
        require (_until > _since, "until should be later than since");

        HeroSale memory _herosale = HeroSale({
            highestPrice: _startPrice,
            previousPrice: _startPrice,
            priceIncreaseTo: _startPrice,
            since:_since,
            until:_until,
            previousSaleAt: _since,
            lowestPriceRate: _lowestPriceRate,
            decreaseRate: _decreaseRate,
            supplyLimit:_supplyLimit,
            suppliedCounts: 0,
            currency: _currency,
            exists: true
        });

        heroTypeToHeroSales[_heroType] = _herosale;
        heroAsset.setSupplyLimit(_heroType, _supplyLimit);

        uint256 _lowestPrice = uint256(_startPrice).mul(_lowestPriceRate).div(100);
        uint256 _becomeLowestAt = uint256(86400).mul(uint256(100).sub(_lowestPriceRate)).div(_decreaseRate).add(_since);

        emit AddSalesEvent(
            _heroType,
            _startPrice,
            _lowestPrice,
            _becomeLowestAt
        );
    }

    function purchase(uint16 _heroType, address _code) external whenNotPaused() nonReentrant() payable {
    // solium-disable-next-line security/no-block-members
        return purchaseImpl(_heroType, uint64(block.timestamp), _code);
    }

    function purchaseByEMONT(uint16 _heroType, uint256 _price, address _code) external whenNotPaused() {
      // solium-disable-next-line security/no-block-members
        return purchaseByEMONTImpl(_heroType, _price, uint64(block.timestamp), _code);
    }

    function airDrop(uint16 _heroType) external whenNotPaused() {
        HeroSale storage heroSales = heroTypeToHeroSales[_heroType];
        require(airDropHero(_heroType), "currency is not 2 (airdrop)");
        require(!hasAirDropHero[_heroType][msg.sender]);
        uint64 _at = uint64(block.timestamp);
        require(isOnSale(_heroType, _at), "out of sales period");

        createHero(_heroType, msg.sender);
        hasAirDropHero[_heroType][msg.sender] = true;
        heroSales.suppliedCounts++;
        heroSales.previousSaleAt = _at;

        emit SoldHeroEvent(
            _heroType,
            1,
            _at,
            1,
            1,
            1,
            msg.sender,
            0x0000000000000000000000000000000000000000,
            2
        );
    }


    function computeCurrentPrice(uint16 _heroType) external view returns (uint8, uint256){
        // solium-disable-next-line security/no-block-members
        return computeCurrentPriceImpl(_heroType, uint64(block.timestamp));
    }

    function canBePurchasedByETH(uint16 _heroType) internal view returns (bool){
        return (heroTypeToHeroSales[_heroType].currency == 0);
    }

    function canBePurchasedByEMONT(uint16 _heroType) internal view returns (bool){
        return (heroTypeToHeroSales[_heroType].currency == 1);
    }

    function airDropHero(uint16 _heroType) internal view returns (bool){
        return (heroTypeToHeroSales[_heroType].currency == 2);
    }

    function isOnSale(uint16 _heroType, uint64 _now) internal view returns (bool){
        HeroSale storage heroSales = heroTypeToHeroSales[_heroType];
        require(heroSales.exists, "not exist sales of this heroType");

        if (heroSales.since <= _now && _now <= heroSales.until) {
            return true;
        } else {
            return false;
        }
    }

    function computeCurrentPriceImpl(uint16 _heroType, uint64 _at) internal view returns (uint8, uint256) {
        HeroSale storage heroSales = heroTypeToHeroSales[_heroType];
        require(heroSales.exists, "not exist sales of this heroType");
        require(heroSales.previousSaleAt < _at, "current timestamp should be later than previousSaleAt");

        uint256 _lowestPrice = uint256(heroSales.highestPrice).mul(heroSales.lowestPriceRate).div(100);
        uint256 _secondsPassed = uint256(_at).sub(heroSales.previousSaleAt);
        uint256 _decreasedPrice = uint256(heroSales.priceIncreaseTo).mul(_secondsPassed).mul(heroSales.decreaseRate).div(100).div(86400);
        uint256 currentPrice;

        if (uint256(heroSales.priceIncreaseTo).sub(_lowestPrice) > _decreasedPrice){
            currentPrice = uint256(heroSales.priceIncreaseTo).sub(_decreasedPrice);
        } else {
            currentPrice = _lowestPrice;
        }

        return (1, currentPrice);
    }

    function purchaseImpl(uint16 _heroType, uint64 _at, address code)
        internal
    {
        HeroSale storage heroSales = heroTypeToHeroSales[_heroType];
        require(canBePurchasedByETH(_heroType), "currency is not 0 (eth)");
        require(isOnSale(_heroType, _at), "out of sales period");
        (,uint256 _price)  = computeCurrentPriceImpl(_heroType, _at);
        require(msg.value >= _price, "value is less than the price");

        createHero(_heroType, msg.sender);

        if (msg.value > _price){
            msg.sender.transfer(msg.value.sub(_price));
        }

        heroSales.previousPrice = uint128(_price);
        heroSales.suppliedCounts++;
        heroSales.previousSaleAt = _at;

        if (heroSales.previousPrice > heroSales.highestPrice){
            heroSales.highestPrice = heroSales.previousPrice;
        }

        uint256 _priceIncreaseTo;
        uint256 _lowestPrice;
        uint256 _becomeLowestAt;

        if(heroSales.supplyLimit > heroSales.suppliedCounts){
            _priceIncreaseTo = SafeMath.add(_price, _price.div((uint256(heroSales.supplyLimit).sub(heroSales.suppliedCounts))));
            heroSales.priceIncreaseTo = uint128(_priceIncreaseTo);
            _lowestPrice = uint256(heroSales.lowestPriceRate).mul(heroSales.highestPrice).div(100);
            _becomeLowestAt = uint256(86400).mul(100).mul((_priceIncreaseTo.sub(_lowestPrice))).div(_priceIncreaseTo).div(heroSales.decreaseRate).add(_at);
        } else {
            _priceIncreaseTo = heroSales.previousPrice;
            heroSales.priceIncreaseTo = uint128(_priceIncreaseTo);
            _lowestPrice = heroSales.previousPrice;
            _becomeLowestAt = _at;
        }

        address Invitees;

        if (code == msg.sender){
            Invitees = address(0x0);
        } else {
            Invitees = code;
        }

        emit SoldHeroEvent(
            _heroType,
            _price,
            _at,
            _priceIncreaseTo,
            _lowestPrice,
            _becomeLowestAt,
            msg.sender,
            Invitees,
            0
        );

    }

    function purchaseByEMONTImpl(uint16 _heroType, uint256 _inputPrice, uint64 _at, address _code)
        internal
    {
        HeroSale storage heroSales = heroTypeToHeroSales[_heroType];
        require(canBePurchasedByEMONT(_heroType), "currency is not 1 (EMONT)");
        require(isOnSale(_heroType, _at), "out of sales period");
        (,uint256 _price)  = computeCurrentPriceImpl(_heroType, _at);
        require(_inputPrice > _price, "input price is not more than actual price");

        createHero(_heroType, msg.sender);
        coin.transferFrom(msg.sender, address(this), _price);

        heroSales.previousPrice = uint128(_price);
        heroSales.suppliedCounts++;
        heroSales.previousSaleAt = _at;

        if (heroSales.previousPrice > heroSales.highestPrice){
            heroSales.highestPrice = heroSales.previousPrice;
        }

        uint256 _priceIncreaseTo;
        uint256 _lowestPrice;
        uint256 _becomeLowestAt;

        if(heroSales.supplyLimit > heroSales.suppliedCounts){
            _priceIncreaseTo = SafeMath.add(_price, _price.div((uint256(heroSales.supplyLimit).sub(heroSales.suppliedCounts))));
            heroSales.priceIncreaseTo = uint128(_priceIncreaseTo);
            _lowestPrice = uint256(heroSales.lowestPriceRate).mul(heroSales.highestPrice).div(100);
            _becomeLowestAt = uint256(86400).mul(100).mul((_priceIncreaseTo.sub(_lowestPrice))).div(_priceIncreaseTo).div(heroSales.decreaseRate).add(_at);
        } else {
            _priceIncreaseTo = heroSales.previousPrice;
            heroSales.priceIncreaseTo = uint128(_priceIncreaseTo);
            _lowestPrice = heroSales.previousPrice;
            _becomeLowestAt = _at;
        }

        address Invitees;

        if (_code == msg.sender){
            Invitees = address(0x0);
        } else {
            Invitees = _code;
        }

        emit SoldHeroEvent(
            _heroType,
            _price,
            _at,
            _priceIncreaseTo,
            _lowestPrice,
            _becomeLowestAt,
            msg.sender,
            Invitees,
            1
        );

    }

    function createHero(uint16 _heroType, address _owner) internal {
        require(heroTypeToHeroSales[_heroType].exists, "not exist sales of this heroType");
        require(heroTypeIds[_heroType].length < heroTypeToHeroSales[_heroType].supplyLimit, "Heroes cant be created more than supplyLimit");

        uint256 _heroId = uint256(_heroType).mul(SUPPLY_LIMIT_MAX).add(heroTypeIds[_heroType].length).add(1);
        heroTypeIds[_heroType].push(_heroId);
        heroAsset.mintHeroAsset(_owner, _heroId);
    }
}

    Contract ABI  
[{"constant":false,"inputs":[{"name":"_heroType","type":"uint16"},{"name":"_price","type":"uint256"},{"name":"_code","type":"address"}],"name":"purchaseByEMONT","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_heroType","type":"uint16"},{"name":"_startPrice","type":"uint128"},{"name":"_lowestPriceRate","type":"uint16"},{"name":"_decreaseRate","type":"uint16"},{"name":"_since","type":"uint64"},{"name":"_until","type":"uint64"},{"name":"_supplyLimit","type":"uint16"},{"name":"_currency","type":"uint8"}],"name":"addSales","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"coin","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdrawEMONT","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"heroAsset","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint16"}],"name":"heroTypeToHeroSales","outputs":[{"name":"highestPrice","type":"uint128"},{"name":"previousPrice","type":"uint128"},{"name":"priceIncreaseTo","type":"uint128"},{"name":"since","type":"uint64"},{"name":"until","type":"uint64"},{"name":"previousSaleAt","type":"uint64"},{"name":"lowestPriceRate","type":"uint16"},{"name":"decreaseRate","type":"uint16"},{"name":"supplyLimit","type":"uint16"},{"name":"suppliedCounts","type":"uint16"},{"name":"currency","type":"uint8"},{"name":"exists","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_heroType","type":"uint16"},{"name":"_code","type":"address"}],"name":"purchase","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isPauser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint16"},{"name":"","type":"uint256"}],"name":"heroTypeIds","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renouncePauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"withdrawEther","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addPauser","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_heroAssetAddress","type":"address"}],"name":"setHeroAssetAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_coinAddress","type":"address"}],"name":"setCoinAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_heroType","type":"uint16"}],"name":"airDrop","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint16"},{"name":"","type":"address"}],"name":"hasAirDropHero","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_heroType","type":"uint16"}],"name":"computeCurrentPrice","outputs":[{"name":"","type":"uint8"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"heroType","type":"uint16"},{"indexed":false,"name":"startPrice","type":"uint128"},{"indexed":false,"name":"lowestPrice","type":"uint256"},{"indexed":false,"name":"becomeLowestAt","type":"uint256"}],"name":"AddSalesEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"heroType","type":"uint16"},{"indexed":false,"name":"soldPrice","type":"uint256"},{"indexed":false,"name":"soldAt","type":"uint64"},{"indexed":false,"name":"priceIncreaseTo","type":"uint256"},{"indexed":false,"name":"lowestPrice","type":"uint256"},{"indexed":false,"name":"becomeLowestAt","type":"uint256"},{"indexed":false,"name":"purchasedBy","type":"address"},{"indexed":true,"name":"code","type":"address"},{"indexed":false,"name":"currency","type":"uint8"}],"name":"SoldHeroEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"PauserRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]

  Contract Creation Code Switch To Opcodes View
60806040526002805460ff191690556001600381905560008054600160a060020a031916339081179091556100419190640100000000611d7161004682021704565b610080565b600160a060020a038116151561005b57600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b6124528061008f6000396000f30060806040526004361061013d5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630396dcb0811461014257806304803c2a1461016f57806311df9995146101c657806315003368146101f757806316f38b631461020c57806328aa48b414610221578063396c8228146102c35780633f4ba83a146102de57806346fbf68e146102f35780635c975abb146103285780636980f4fb1461033d5780636ef8d66d1461036e578063715018a6146103835780637362377b1461039857806382dc1ec4146103ad5780638456cb59146103ce5780638da5cb5b146103e35780638f32d59b146103f8578063985df3a71461040d578063b0bdacc61461042e578063b27eb3e51461044f578063b673ddb71461046b578063e6d944a714610493578063f2fde38b146104cc575b600080fd5b34801561014e57600080fd5b5061016d61ffff60043516602435600160a060020a03604435166104ed565b005b34801561017b57600080fd5b5061016d61ffff6004358116906001608060020a03602435169060443581169060643581169067ffffffffffffffff60843581169160a4359091169060c4351660ff60e4351661050e565b3480156101d257600080fd5b506101db610b94565b60408051600160a060020a039092168252519081900360200190f35b34801561020357600080fd5b5061016d610ba3565b34801561021857600080fd5b506101db610d83565b34801561022d57600080fd5b5061023d61ffff60043516610d92565b604080516001608060020a039d8e1681529b8d1660208d015299909b168a8a015267ffffffffffffffff97881660608b015295871660808a01529390951660a088015261ffff91821660c0880152811660e087015292831661010086015290911661012084015260ff166101408301529115156101608201529051908190036101800190f35b61016d61ffff60043516600160a060020a0360243516610e5c565b3480156102ea57600080fd5b5061016d610e90565b3480156102ff57600080fd5b50610314600160a060020a0360043516610eea565b604080519115158252519081900360200190f35b34801561033457600080fd5b50610314610f03565b34801561034957600080fd5b5061035c61ffff60043516602435610f0c565b60408051918252519081900360200190f35b34801561037a57600080fd5b5061016d610f3c565b34801561038f57600080fd5b5061016d610f4f565b3480156103a457600080fd5b5061016d610fb7565b3480156103b957600080fd5b5061016d600160a060020a036004351661100d565b3480156103da57600080fd5b5061016d611069565b3480156103ef57600080fd5b506101db6110c5565b34801561040457600080fd5b506103146110d4565b34801561041957600080fd5b5061016d600160a060020a03600435166110e5565b34801561043a57600080fd5b5061016d600160a060020a0360043516611127565b34801561045b57600080fd5b5061016d61ffff60043516611169565b34801561047757600080fd5b5061031461ffff60043516600160a060020a0360243516611367565b34801561049f57600080fd5b506104af61ffff60043516611387565b6040805160ff909316835260208301919091528051918290030190f35b3480156104d857600080fd5b5061016d600160a060020a036004351661139d565b60025460ff16156104fd57600080fd5b610509838342846113b9565b505050565b6105166123c2565b6000806105216110d4565b151561052c57600080fd5b61ffff8b1660009081526004602052604090206002015471010000000000000000000000000000000000900460ff16156105d5576040805160e560020a62461bcd028152602060048201526024808201527f74686973206865726f5479706520697320616c7265616479206164646564207360448201527f616c657300000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b8861ffff166000111580156105ef575060648961ffff1611155b151561066b576040805160e560020a62461bcd02815260206004820152602b60248201527f6c6f776573745072696365526174652073686f756c642062652062657477656560448201527f6e203020616e6420313030000000000000000000000000000000000000000000606482015290519081900360840190fd5b8761ffff16600111158015610685575060648861ffff1611155b1515610701576040805160e560020a62461bcd02815260206004820152603260248201527f6465637265617365526174652073686f756c642062652073686f756c6420626560448201527f206265747765656e203120616e64203130300000000000000000000000000000606482015290519081900360840190fd5b67ffffffffffffffff80881690871611610765576040805160e560020a62461bcd02815260206004820181905260248201527f756e74696c2073686f756c64206265206c61746572207468616e2073696e6365604482015290519081900360640190fd5b610180604051908101604052808b6001608060020a031681526020018b6001608060020a031681526020018b6001608060020a031681526020018867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018867ffffffffffffffff1681526020018a61ffff1681526020018961ffff1681526020018661ffff168152602001600061ffff1681526020018560ff16815260200160011515815250925082600460008d61ffff1661ffff16815260200190815260200160002060008201518160000160006101000a8154816001608060020a0302191690836001608060020a0316021790555060208201518160000160106101000a8154816001608060020a0302191690836001608060020a0316021790555060408201518160010160006101000a8154816001608060020a0302191690836001608060020a0316021790555060608201518160010160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060808201518160010160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c08201518160020160086101000a81548161ffff021916908361ffff16021790555060e082015181600201600a6101000a81548161ffff021916908361ffff16021790555061010082015181600201600c6101000a81548161ffff021916908361ffff16021790555061012082015181600201600e6101000a81548161ffff021916908361ffff1602179055506101408201518160020160106101000a81548160ff021916908360ff1602179055506101608201518160020160116101000a81548160ff021916908315150217905550905050600860009054906101000a9004600160a060020a0316600160a060020a0316636fa23f738c876040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808361ffff1661ffff1681526020018261ffff1661ffff16815260200192505050600060405180830381600087803b158015610a9d57600080fd5b505af1158015610ab1573d6000803e3d6000fd5b50505050610ae66064610ada8b61ffff168d6001608060020a031661187490919063ffffffff16565b9063ffffffff6118ad16565b9150610b358767ffffffffffffffff16610b298a61ffff16610ada610b198e61ffff1660646118d090919063ffffffff16565b620151809063ffffffff61187416565b9063ffffffff6118e716565b604080516001608060020a038d16815260208101859052808201839052905191925061ffff8d16917fbb9aad0aec529392a851fee029d68b1fe345568b44c44e3e4ea716375f4949529181900360600190a25050505050505050505050565b600754600160a060020a031681565b6000610bad6110d4565b1515610bb857600080fd5b600754604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a03909216916370a08231916024808201926020929091908290030181600087803b158015610c1e57600080fd5b505af1158015610c32573d6000803e3d6000fd5b505050506040513d6020811015610c4857600080fd5b5051600754604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152306004820152602481018490529051929350600160a060020a039091169163095ea7b3916044808201926020929091908290030181600087803b158015610cba57600080fd5b505af1158015610cce573d6000803e3d6000fd5b505050506040513d6020811015610ce457600080fd5b5050600754604080517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152336024820152604481018490529051600160a060020a03909216916323b872dd916064808201926020929091908290030181600087803b158015610d5957600080fd5b505af1158015610d6d573d6000803e3d6000fd5b505050506040513d602081101561050957600080fd5b600854600160a060020a031681565b6004602052600090815260409020805460018201546002909201546001608060020a0380831693608060020a938490048216939181169267ffffffffffffffff83830481169378010000000000000000000000000000000000000000000000009093048116929082169161ffff6801000000000000000082048116926a010000000000000000000083048216926c010000000000000000000000008104831692607060020a8204169160ff908204811691710100000000000000000000000000000000009004168c565b60025460ff1615610e6c57600080fd5b6003805460010190819055610e828342846118f9565b600354811461050957600080fd5b610e9933610eea565b1515610ea457600080fd5b60025460ff161515610eb557600080fd5b6002805460ff191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b6000610efd60018363ffffffff611d0316565b92915050565b60025460ff1690565b600560205281600052604060002081815481101515610f2757fe5b90600052602060002001600091509150505481565b610f4d60013363ffffffff611d3a16565b565b610f576110d4565b1515610f6257600080fd5b60008054604051600160a060020a03909116917ff8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c6482091a26000805473ffffffffffffffffffffffffffffffffffffffff19169055565b610fbf6110d4565b1515610fca57600080fd5b610fd26110c5565b604051600160a060020a039190911690303180156108fc02916000818181858888f1935050505015801561100a573d6000803e3d6000fd5b50565b61101633610eea565b151561102157600080fd5b61103260018263ffffffff611d7116565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b61107233610eea565b151561107d57600080fd5b60025460ff161561108d57600080fd5b6002805460ff191660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b600054600160a060020a031690565b600054600160a060020a0316331490565b6110ed6110d4565b15156110f857600080fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b61112f6110d4565b151561113a57600080fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600254600090819060ff161561117e57600080fd5b61ffff83166000908152600460205260409020915061119c83611dab565b15156111f2576040805160e560020a62461bcd02815260206004820152601b60248201527f63757272656e6379206973206e6f742032202861697264726f70290000000000604482015290519081900360640190fd5b61ffff8316600090815260066020908152604080832033845290915290205460ff161561121e57600080fd5b504261122a8382611dd1565b1515611280576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b61128a8333611ec4565b61ffff808416600081815260066020908152604080832033808552908352818420805460ff191660019081179091556002808a01805467ffffffffffffffff8b1667ffffffffffffffff19607060020a8084048d168701909c16909b026fffff00000000000000000000000000001990921691909117999099168917905583518281529485019790975283830181905260608401819052608084015260a083015260c0820194909452925190927f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f919081900360e00190a3505050565b600660209081526000928352604080842090915290825290205460ff1681565b60008061139483426120dd565b91509150915091565b6113a56110d4565b15156113b057600080fd5b61100a816122fb565b61ffff8416600090815260046020526040812090808080806113da8a612378565b1515611430576040805160e560020a62461bcd02815260206004820152601960248201527f63757272656e6379206973206e6f7420312028454d4f4e542900000000000000604482015290519081900360640190fd5b61143a8a89611dd1565b1515611490576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b61149a8a896120dd565b95505084891161151a576040805160e560020a62461bcd02815260206004820152602960248201527f696e707574207072696365206973206e6f74206d6f7265207468616e2061637460448201527f75616c2070726963650000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6115248a33611ec4565b600754604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018890529051600160a060020a03909216916323b872dd916064808201926020929091908290030181600087803b15801561159757600080fd5b505af11580156115ab573d6000803e3d6000fd5b505050506040513d60208110156115c157600080fd5b505085546001608060020a03908116608060020a8783168102919091178089556002890180546fffff0000000000000000000000000000198116607060020a9182900461ffff908116600101169091021767ffffffffffffffff191667ffffffffffffffff8d161790558083169190049091161115611665578554608060020a81046001608060020a03166fffffffffffffffffffffffffffffffff199091161786555b600286015461ffff607060020a820481166c010000000000000000000000009092041611156117925760028601546116d69086906116d1906116c49061ffff6c010000000000000000000000008204811691607060020a9004166118d0565b889063ffffffff6118ad16565b6118e7565b6001870180546fffffffffffffffffffffffffffffffff19166001608060020a03838116919091179091558754600289015492965061172e92606492610ada926801000000000000000090920461ffff169116611874565b600287015490935061178b9067ffffffffffffffff8a1690610b29906a0100000000000000000000900461ffff16610ada888161176b828b6118d0565b61177f62015180606463ffffffff61187416565b9063ffffffff61187416565b91506117d7565b8554600187018054608060020a9092046001608060020a03166fffffffffffffffffffffffffffffffff1990921682179055935083925067ffffffffffffffff881691505b600160a060020a0387163314156117f0575060006117f3565b50855b6040805186815267ffffffffffffffff8a16602082015280820186905260608101859052608081018490523360a0820152600160c08201529051600160a060020a0383169161ffff8d16917f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f9181900360e00190a350505050505050505050565b60008083151561188757600091506118a6565b5082820282848281151561189757fe5b04146118a257600080fd5b8091505b5092915050565b6000808083116118bc57600080fd5b82848115156118c757fe5b04949350505050565b600080838311156118e057600080fd5b5050900390565b6000828201838110156118a257600080fd5b61ffff83166000908152600460205260408120908080808061191a8961239e565b1515611970576040805160e560020a62461bcd02815260206004820152601760248201527f63757272656e6379206973206e6f742030202865746829000000000000000000604482015290519081900360640190fd5b61197a8989611dd1565b15156119d0576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b6119da89896120dd565b95505034851115611a35576040805160e560020a62461bcd02815260206004820152601c60248201527f76616c7565206973206c657373207468616e2074686520707269636500000000604482015290519081900360640190fd5b611a3f8933611ec4565b84341115611a8557336108fc611a5b348863ffffffff6118d016565b6040518115909202916000818181858888f19350505050158015611a83573d6000803e3d6000fd5b505b85546001608060020a03908116608060020a8783168102919091178089556002890180546fffff0000000000000000000000000000198116607060020a9182900461ffff908116600101169091021767ffffffffffffffff191667ffffffffffffffff8d161790558083169190049091161115611b27578554608060020a81046001608060020a03166fffffffffffffffffffffffffffffffff199091161786555b600286015461ffff607060020a820481166c01000000000000000000000000909204161115611c22576002860154611b869086906116d1906116c49061ffff6c010000000000000000000000008204811691607060020a9004166118d0565b6001870180546fffffffffffffffffffffffffffffffff19166001608060020a038381169190911790915587546002890154929650611bde92606492610ada926801000000000000000090920461ffff169116611874565b6002870154909350611c1b9067ffffffffffffffff8a1690610b29906a0100000000000000000000900461ffff16610ada888161176b828b6118d0565b9150611c67565b8554600187018054608060020a9092046001608060020a03166fffffffffffffffffffffffffffffffff1990921682179055935083925067ffffffffffffffff881691505b600160a060020a038716331415611c8057506000611c83565b50855b6040805186815267ffffffffffffffff8a16602082015280820186905260608101859052608081018490523360a0820152600060c08201529051600160a060020a0383169161ffff8c16917f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f9181900360e00190a3505050505050505050565b6000600160a060020a0382161515611d1a57600080fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b600160a060020a0381161515611d4f57600080fd5b600160a060020a0316600090815260209190915260409020805460ff19169055565b600160a060020a0381161515611d8657600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b61ffff166000908152600460205260409020600290810154608060020a900460ff161490565b61ffff82166000908152600460205260408120600281015471010000000000000000000000000000000000900460ff161515611e57576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b600181015467ffffffffffffffff808516608060020a9092041611801590611ead5750600181015467ffffffffffffffff7801000000000000000000000000000000000000000000000000909104811690841611155b15611ebb57600191506118a6565b600091506118a6565b61ffff821660009081526004602052604081206002015471010000000000000000000000000000000000900460ff161515611f49576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b61ffff8084166000908152600460209081526040808320600201546005909252909120546c0100000000000000000000000090910490911611611ffc576040805160e560020a62461bcd02815260206004820152602c60248201527f4865726f65732063616e742062652063726561746564206d6f7265207468616e60448201527f20737570706c794c696d69740000000000000000000000000000000000000000606482015290519081900360840190fd5b61ffff831660008181526005602052604090205461202b91600191610b2991829061271063ffffffff61187416565b61ffff84166000908152600560209081526040808320805460018101825590845291832090910183905560085481517f4d5b335d000000000000000000000000000000000000000000000000000000008152600160a060020a038781166004830152602482018690529251949550911692634d5b335d9260448084019391929182900301818387803b1580156120c057600080fd5b505af11580156120d4573d6000803e3d6000fd5b50505050505050565b61ffff821660009081526004602052604081206002810154829190829081908190819071010000000000000000000000000000000000900460ff16151561216e576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b600285015467ffffffffffffffff808a169116106121fc576040805160e560020a62461bcd02815260206004820152603560248201527f63757272656e742074696d657374616d702073686f756c64206265206c61746560448201527f72207468616e2070726576696f757353616c6541740000000000000000000000606482015290519081900360840190fd5b6002850154855461222f91606491610ada916001608060020a039091169068010000000000000000900461ffff16611874565b60028601549094506122549067ffffffffffffffff8a8116911663ffffffff6118d016565b6002860154600187015491945061229a916201518091610ada9160649183916a010000000000000000000090910461ffff169061177f906001608060020a03168a611874565b600186015490925082906122bd906001608060020a03168663ffffffff6118d016565b11156122e85760018501546122e1906001608060020a03168363ffffffff6118d016565b90506122eb565b50825b6001999098509650505050505050565b600160a060020a038116151561231057600080fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b61ffff16600090815260046020526040902060020154608060020a900460ff1660011490565b61ffff16600090815260046020526040902060020154608060020a900460ff161590565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152905600a165627a7a72305820f98098e6ea4ba6a8b23a13c03df1115e245c511cb9ae500e5b4c64bc4af8f7d40029

   Swarm Source:
bzzr://f98098e6ea4ba6a8b23a13c03df1115e245c511cb9ae500e5b4c64bc4af8f7d4

 

View All
Block Age transaction Difficulty GasUsed Reward
View All
Block Age UncleNumber Difficulty GasUsed Reward
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.