Contract 0x946048a75af11c300a274344887ec39452218b3d

 

TxHash Block Age From To Value [TxFee]
0xc15b5143c78d78873bbdcc8158f09999c2dc16c865f24f91c2ee1b7a633e5634709327732 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0xddb87d76047cd7827a8f7606f4535032d6e4c5ae59be6a9e70ac2947a04e9fd2709327532 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0x6b86c7ff1b213394d6913025cd5a114df1dba783a78dc6aa80c9dd76cc451c43709327332 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0xa381ec173fac6d7e64740861dbcf2f753a0bad3b337df045f3056b62ae88f828709327132 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0x2cf33bb80a834d728c3140090a95fb0673cb5cd3ca34c43883b8af6e6f89b50e709327132 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0x7f745234a1a34531759fa19a4835c69cb8610fc4c869bfa5d32e8b1f317fa1e8709326932 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0xe32743ee6219291b15d359643c85112ea2b699b323579bdfe4d0357eba185cb0709326732 days 6 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0x1b22adbb4bd0fb00fb3216bca7d0e3445bb85de24610fc783b73ba66de976afa709326532 days 7 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0x78fcd3890c79e6a7c4b2188df833e6f35c36db3075d2e22dffe5ca9695f87ec1709326132 days 7 hrs ago0xa4031ee06bcce066f3aa708c6151fedd5c779aec IN  MCH: Presale0 Ether0.000195136
0xf0f625fc501e55af2e4b8526d02903241fbd1a8e4da80a771a1fab3bdc6ee9f8695420056 days 16 hrs ago0x17cba3340a6794814fdb89aad3b72b05405ac6f4 IN  MCH: Presale0 Ether0.000195136
0x9cf6a0492855f7c87cc418534f180b07e7cc31e30b16f6c517f208039241e6b0695419856 days 17 hrs ago0x17cba3340a6794814fdb89aad3b72b05405ac6f4 IN  MCH: Presale0 Ether0.000195136
0x2922d9b49b3642d3acd4e37ebab490684a0a667d75e705011487cba7c8d05656695419556 days 17 hrs ago0x17cba3340a6794814fdb89aad3b72b05405ac6f4 IN  MCH: Presale0 Ether0.000195136
0x384b36ce85ff5d72f08b092c623c027fda732fc480934bfa576ecb216a9c5406695419356 days 17 hrs ago0x17cba3340a6794814fdb89aad3b72b05405ac6f4 IN  MCH: Presale0 Ether0.000195136
0x259ed178b35e4e096d532cda7c9e3188dcb585c3831eda903127720aeb92b633685931472 days 14 hrs agoMCH: Owner IN  MCH: Presale0 Ether0.000196995
0x399c40125bdb14958ff49a56dd3db72ad7beb49b04ae553cf2238f765c3b3acf679052183 days 23 hrs ago0x05f3ba3a53be572a07cc5d54013810aa6da3cffe IN  MCH: Presale0 Ether0.000084184
0x9fbe0b8debabc1d7e5ab9de81ee91c58e0478a1504ada88a60d01fa3dd2bc61a675880389 days 4 hrs ago0x416a2bdc3479d0e0bad1ff4e926d4401e7c941c8 IN  MCH: Presale0 Ether0.000185752
0x97a5fcce0e52fd4de7f8cb69811ff22ea0de02c71c41c5fc324bd16ffa763dc7675880189 days 4 hrs ago0x416a2bdc3479d0e0bad1ff4e926d4401e7c941c8 IN  MCH: Presale0 Ether0.000185752
0x33ae72f85d3af02744b52612aea914649e3c6c231324023fad15143b8ca64c6e675879989 days 4 hrs ago0x416a2bdc3479d0e0bad1ff4e926d4401e7c941c8 IN  MCH: Presale0 Ether0.000185752
0x555e9aeef23fdc7dbd6009af432d1c8b6d57a4a38fba6f831a38737e5ba7e4516619616112 days 55 mins ago0x3f2360806442a4d7dc643a9e235a93a6ab1c5000 IN  MCH: Presale0 Ether0.000006354814
0xf1ffa3308793905784a76176fa544b3bf9ec429224dbc25820c471714b95ac386613894112 days 23 hrs ago0x793e193a27744025f8f60736eda8a863aca5b699 IN  MCH: Presale0 Ether0.000532668
0x26df5d3935e802996faa20b2d656d999f738f1fd6e7795e76b24f45cfe572f3b6612634113 days 4 hrs ago0x573b23dad4741a6c746322eb5416abd51a4c7ecb IN  MCH: Presale0 Ether0.0011319195
0x134dd365ccbd27893474a764738cf68a39a62e492e7b588c1db6dafadf35ebd76612508113 days 4 hrs ago0xb08237d62eca2bc1e336ccf22dcc88e8a3214e8c IN  MCH: Presale0 Ether0.0011319195
0xf3689f8ac24244671a57ac4963426e7e5c9683f199ad75e783be6952789058c86612505113 days 4 hrs ago0xc474471670ad3680ec739d342e72d35355403c69 IN  MCH: Presale0 Ether0.0011319195
0xc1d0b7d98c88e4c652aa10aca772bcf4880a862a9ba2dfafbc8c4ae83c4fc13e6612463113 days 4 hrs ago0x93340f248036e07dcf47c96f964a9a201c1d5383 IN  MCH: Presale0 Ether0.0011319195
0xec6202c4e618c90452ceb9ceac1df2b7a51d58a77f7bccdcbe150a7b27f890366612462113 days 4 hrs ago0xec94cb51585c7783a9104481dba8761422133838 IN  MCH: Presale0 Ether0.0011319195
[ Download CSV Export 

Latest 25 Internal Transaction, Click here to view more Internal Transactions as a result of Contract Execution

Parent TxHash Block Age From To Value
0x80f9da22c0b5fa47a63d0884e9a6a21ccb334df29a09785507cda6e259d07a9a6432790142 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xe7af11370c3bab51230d8307454350bdf6d68f4a35.704222117672495829 Ether
0xab256c924e4160e0c105cd4d0ac46018e536046183fb77122080c8479dae2f036429998142 days 22 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x40c9afd96646df172b6fa31211fb51bf5144081e0.000031221261836837 Ether
0xa949c413deb06677dad32a738cce5d73a5fec2a993538c9d9311e428c1fe4f8a6429977142 days 22 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa45c6991a2c3d74ada3a279e21135133ce3da8a0.00235377005848806 Ether
0xf6e434f01a654605913d5a7d385f9eaaf701c07b7391acf45c827313e8d768dd6429590143 days 6 mins ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000117520883268269 Ether
0x670b31985a62e8eed3becf6bc9930dd56b854743492777a58adaa485f1dbefe96427962143 days 6 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ad8f1fb5c25f2ac83bf26ca2b6d857037d6ba840.000767529163824232 Ether
0xc4f2fcbbf0448fb335a44459a78bb2e15d24ff6f0742d6463d54ac1de6e311206426896143 days 10 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xcaff49b031e5099a54f5959dc931c27e366273690.00027635849798034 Ether
0x83e4c45e9f8bde79125dfa22167bd9a16861a47893a923e979d18970bb9106c36426734143 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xf96c878bb8d36d8203fa2a358d770f1ae85a1d470.000056706459629636 Ether
0xdc20e02fed068677404eabf608d31f9b5f8d7c709765ebd07292cc802dca57e26426281143 days 13 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa45c6991a2c3d74ada3a279e21135133ce3da8a0.000042947044652632 Ether
0xb10f69d2de12cc6f5c07ff081959d3c04c3c564fc63effc84407c67ac7044d156422060144 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa7b07b6de964d022c832f20ced2dac16384b7aa0.000589297430622244 Ether
0x30eae0b46e72097c6aa5a3b702ebc6bdfc7aaefded07d540600f7a1a7b26f63b6421968144 days 6 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xfa7b07b6de964d022c832f20ced2dac16384b7aa0.000047119936254208 Ether
0x1cec5086ed2f1538d8524b3a2b69765c15fc838ec5a0e862f33021db8d7813166421943144 days 6 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x431434d43cea4131650520cb105b90fe204fa39d0.000063161054912408 Ether
0x8990af91a3ae9aec187283b2c3add147f3cda60c13ecabb607b036be291fa7856418350144 days 20 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x12f561c77e1e542b8d6f9de5f3e2faf03d87b3b80.00003725965242613 Ether
0x1588d281cfacec2e4195fdaa5cb3a5ac4d559f7af72b99f41370d13a427daff26418333144 days 20 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000262467736842824 Ether
0x650e955e98a51a24c17d0e38c57499824018418372312983807146a0f2bd888e6418315144 days 20 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x6c5f503e290bba6a659972da78715694797fbac40.000054190227769198 Ether
0x506bf9db530d66a23af6b4cfb4ef9669a8c24544b0209bfae02fcbf2603a54636416158145 days 4 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xaa24875b7bfd15364af1063f8c1330c53146b81f0.000070680592497302 Ether
0xd1113b96af97a3cc6d750c6d073f81035045ba8f8bdda41c9e880c531390b6bd6416052145 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x2e1bc1abc2e86e3405766f6b39ed8fe388b344970.000058564601634346 Ether
0x70a9954c196321e4dafd5f0541279934b9350d38278185654966d152e39daba16416018145 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x2a3d897cd8cc82f310b53f4511ebdefca7f0232c0.000040742434896311 Ether
0x49583b65cd655393484b39d94a34b214bd9439eb9618c78ba977a2f5363a6f6a6415910145 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ba3e11abf8c93186637847ec590fcd3aa588bd20.000033388657128154 Ether
0x54750d35119882b4e9a8f522f8ffbdb835ce7c83fd8203546cd2abd52bf8545a6415885145 days 5 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x5ba3e11abf8c93186637847ec590fcd3aa588bd20.000022920115099777 Ether
0xcb5c94fdb955255fcf9fed3ddf4cd259fff3592663880f90d89a77a3523ec06c6415822145 days 6 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xaa764d0f94b0ebcf6eb0a29bc2fb19b48edd23350.011795271321073031 Ether
0xda4c5ea6476906133207132b6e06129e19ddd47f453d57fb96901bc61cb1fbb46415283145 days 8 hrs ago0x946048a75af11c300a274344887ec39452218b3d0xbcd2c48e447a45244ccefdb232b2f7b5f86f43bd0.000056682034275433 Ether
0x2bee68c508bfce829c2dc3bf52443ff62fad6c99c4e7159c5be12a799a8203ed6414412145 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x8ddd99328f94489460ed8387a9bd6577a42fb3aa0.000026907286942602 Ether
0x075e9814ff52d118a66319984104e2d797ebe46a18fb7c7b18e3c4c7c1d555276414407145 days 11 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x8ddd99328f94489460ed8387a9bd6577a42fb3aa0.000157887577158355 Ether
0x1e3c2b4139eb22add1955ae9ddc4ed5dc112f133c9b95c719c9053d1384618026414281145 days 12 hrs ago0x946048a75af11c300a274344887ec39452218b3d0x3d3a8ce65e3595f60be146f5f05b42ad63c4be7c0.000013004904153729 Ether
0x9b2cf63a1bc252afb7e40472415548424ed7cfd21fb5bf9620e327f49a7229b06414249145 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) Solidity Compiler Bugs.

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


Contract Source Code
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
60806040526002805460ff191690556001600381905560008054600160a060020a031916339081179091556100419190640100000000611d7161004682021704565b610080565b600160a060020a038116151561005b57600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b6124528061008f6000396000f30060806040526004361061013d5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630396dcb0811461014257806304803c2a1461016f57806311df9995146101c657806315003368146101f757806316f38b631461020c57806328aa48b414610221578063396c8228146102c35780633f4ba83a146102de57806346fbf68e146102f35780635c975abb146103285780636980f4fb1461033d5780636ef8d66d1461036e578063715018a6146103835780637362377b1461039857806382dc1ec4146103ad5780638456cb59146103ce5780638da5cb5b146103e35780638f32d59b146103f8578063985df3a71461040d578063b0bdacc61461042e578063b27eb3e51461044f578063b673ddb71461046b578063e6d944a714610493578063f2fde38b146104cc575b600080fd5b34801561014e57600080fd5b5061016d61ffff60043516602435600160a060020a03604435166104ed565b005b34801561017b57600080fd5b5061016d61ffff6004358116906001608060020a03602435169060443581169060643581169067ffffffffffffffff60843581169160a4359091169060c4351660ff60e4351661050e565b3480156101d257600080fd5b506101db610b94565b60408051600160a060020a039092168252519081900360200190f35b34801561020357600080fd5b5061016d610ba3565b34801561021857600080fd5b506101db610d83565b34801561022d57600080fd5b5061023d61ffff60043516610d92565b604080516001608060020a039d8e1681529b8d1660208d015299909b168a8a015267ffffffffffffffff97881660608b015295871660808a01529390951660a088015261ffff91821660c0880152811660e087015292831661010086015290911661012084015260ff166101408301529115156101608201529051908190036101800190f35b61016d61ffff60043516600160a060020a0360243516610e5c565b3480156102ea57600080fd5b5061016d610e90565b3480156102ff57600080fd5b50610314600160a060020a0360043516610eea565b604080519115158252519081900360200190f35b34801561033457600080fd5b50610314610f03565b34801561034957600080fd5b5061035c61ffff60043516602435610f0c565b60408051918252519081900360200190f35b34801561037a57600080fd5b5061016d610f3c565b34801561038f57600080fd5b5061016d610f4f565b3480156103a457600080fd5b5061016d610fb7565b3480156103b957600080fd5b5061016d600160a060020a036004351661100d565b3480156103da57600080fd5b5061016d611069565b3480156103ef57600080fd5b506101db6110c5565b34801561040457600080fd5b506103146110d4565b34801561041957600080fd5b5061016d600160a060020a03600435166110e5565b34801561043a57600080fd5b5061016d600160a060020a0360043516611127565b34801561045b57600080fd5b5061016d61ffff60043516611169565b34801561047757600080fd5b5061031461ffff60043516600160a060020a0360243516611367565b34801561049f57600080fd5b506104af61ffff60043516611387565b6040805160ff909316835260208301919091528051918290030190f35b3480156104d857600080fd5b5061016d600160a060020a036004351661139d565b60025460ff16156104fd57600080fd5b610509838342846113b9565b505050565b6105166123c2565b6000806105216110d4565b151561052c57600080fd5b61ffff8b1660009081526004602052604090206002015471010000000000000000000000000000000000900460ff16156105d5576040805160e560020a62461bcd028152602060048201526024808201527f74686973206865726f5479706520697320616c7265616479206164646564207360448201527f616c657300000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b8861ffff166000111580156105ef575060648961ffff1611155b151561066b576040805160e560020a62461bcd02815260206004820152602b60248201527f6c6f776573745072696365526174652073686f756c642062652062657477656560448201527f6e203020616e6420313030000000000000000000000000000000000000000000606482015290519081900360840190fd5b8761ffff16600111158015610685575060648861ffff1611155b1515610701576040805160e560020a62461bcd02815260206004820152603260248201527f6465637265617365526174652073686f756c642062652073686f756c6420626560448201527f206265747765656e203120616e64203130300000000000000000000000000000606482015290519081900360840190fd5b67ffffffffffffffff80881690871611610765576040805160e560020a62461bcd02815260206004820181905260248201527f756e74696c2073686f756c64206265206c61746572207468616e2073696e6365604482015290519081900360640190fd5b610180604051908101604052808b6001608060020a031681526020018b6001608060020a031681526020018b6001608060020a031681526020018867ffffffffffffffff1681526020018767ffffffffffffffff1681526020018867ffffffffffffffff1681526020018a61ffff1681526020018961ffff1681526020018661ffff168152602001600061ffff1681526020018560ff16815260200160011515815250925082600460008d61ffff1661ffff16815260200190815260200160002060008201518160000160006101000a8154816001608060020a0302191690836001608060020a0316021790555060208201518160000160106101000a8154816001608060020a0302191690836001608060020a0316021790555060408201518160010160006101000a8154816001608060020a0302191690836001608060020a0316021790555060608201518160010160106101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060808201518160010160186101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060c08201518160020160086101000a81548161ffff021916908361ffff16021790555060e082015181600201600a6101000a81548161ffff021916908361ffff16021790555061010082015181600201600c6101000a81548161ffff021916908361ffff16021790555061012082015181600201600e6101000a81548161ffff021916908361ffff1602179055506101408201518160020160106101000a81548160ff021916908360ff1602179055506101608201518160020160116101000a81548160ff021916908315150217905550905050600860009054906101000a9004600160a060020a0316600160a060020a0316636fa23f738c876040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808361ffff1661ffff1681526020018261ffff1661ffff16815260200192505050600060405180830381600087803b158015610a9d57600080fd5b505af1158015610ab1573d6000803e3d6000fd5b50505050610ae66064610ada8b61ffff168d6001608060020a031661187490919063ffffffff16565b9063ffffffff6118ad16565b9150610b358767ffffffffffffffff16610b298a61ffff16610ada610b198e61ffff1660646118d090919063ffffffff16565b620151809063ffffffff61187416565b9063ffffffff6118e716565b604080516001608060020a038d16815260208101859052808201839052905191925061ffff8d16917fbb9aad0aec529392a851fee029d68b1fe345568b44c44e3e4ea716375f4949529181900360600190a25050505050505050505050565b600754600160a060020a031681565b6000610bad6110d4565b1515610bb857600080fd5b600754604080517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a03909216916370a08231916024808201926020929091908290030181600087803b158015610c1e57600080fd5b505af1158015610c32573d6000803e3d6000fd5b505050506040513d6020811015610c4857600080fd5b5051600754604080517f095ea7b3000000000000000000000000000000000000000000000000000000008152306004820152602481018490529051929350600160a060020a039091169163095ea7b3916044808201926020929091908290030181600087803b158015610cba57600080fd5b505af1158015610cce573d6000803e3d6000fd5b505050506040513d6020811015610ce457600080fd5b5050600754604080517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152336024820152604481018490529051600160a060020a03909216916323b872dd916064808201926020929091908290030181600087803b158015610d5957600080fd5b505af1158015610d6d573d6000803e3d6000fd5b505050506040513d602081101561050957600080fd5b600854600160a060020a031681565b6004602052600090815260409020805460018201546002909201546001608060020a0380831693608060020a938490048216939181169267ffffffffffffffff83830481169378010000000000000000000000000000000000000000000000009093048116929082169161ffff6801000000000000000082048116926a010000000000000000000083048216926c010000000000000000000000008104831692607060020a8204169160ff908204811691710100000000000000000000000000000000009004168c565b60025460ff1615610e6c57600080fd5b6003805460010190819055610e828342846118f9565b600354811461050957600080fd5b610e9933610eea565b1515610ea457600080fd5b60025460ff161515610eb557600080fd5b6002805460ff191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b6000610efd60018363ffffffff611d0316565b92915050565b60025460ff1690565b600560205281600052604060002081815481101515610f2757fe5b90600052602060002001600091509150505481565b610f4d60013363ffffffff611d3a16565b565b610f576110d4565b1515610f6257600080fd5b60008054604051600160a060020a03909116917ff8df31144d9c2f0f6b59d69b8b98abd5459d07f2742c4df920b25aae33c6482091a26000805473ffffffffffffffffffffffffffffffffffffffff19169055565b610fbf6110d4565b1515610fca57600080fd5b610fd26110c5565b604051600160a060020a039190911690303180156108fc02916000818181858888f1935050505015801561100a573d6000803e3d6000fd5b50565b61101633610eea565b151561102157600080fd5b61103260018263ffffffff611d7116565b604051600160a060020a038216907f6719d08c1888103bea251a4ed56406bd0c3e69723c8a1686e017e7bbe159b6f890600090a250565b61107233610eea565b151561107d57600080fd5b60025460ff161561108d57600080fd5b6002805460ff191660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b600054600160a060020a031690565b600054600160a060020a0316331490565b6110ed6110d4565b15156110f857600080fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b61112f6110d4565b151561113a57600080fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600254600090819060ff161561117e57600080fd5b61ffff83166000908152600460205260409020915061119c83611dab565b15156111f2576040805160e560020a62461bcd02815260206004820152601b60248201527f63757272656e6379206973206e6f742032202861697264726f70290000000000604482015290519081900360640190fd5b61ffff8316600090815260066020908152604080832033845290915290205460ff161561121e57600080fd5b504261122a8382611dd1565b1515611280576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b61128a8333611ec4565b61ffff808416600081815260066020908152604080832033808552908352818420805460ff191660019081179091556002808a01805467ffffffffffffffff8b1667ffffffffffffffff19607060020a8084048d168701909c16909b026fffff00000000000000000000000000001990921691909117999099168917905583518281529485019790975283830181905260608401819052608084015260a083015260c0820194909452925190927f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f919081900360e00190a3505050565b600660209081526000928352604080842090915290825290205460ff1681565b60008061139483426120dd565b91509150915091565b6113a56110d4565b15156113b057600080fd5b61100a816122fb565b61ffff8416600090815260046020526040812090808080806113da8a612378565b1515611430576040805160e560020a62461bcd02815260206004820152601960248201527f63757272656e6379206973206e6f7420312028454d4f4e542900000000000000604482015290519081900360640190fd5b61143a8a89611dd1565b1515611490576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b61149a8a896120dd565b95505084891161151a576040805160e560020a62461bcd02815260206004820152602960248201527f696e707574207072696365206973206e6f74206d6f7265207468616e2061637460448201527f75616c2070726963650000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6115248a33611ec4565b600754604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018890529051600160a060020a03909216916323b872dd916064808201926020929091908290030181600087803b15801561159757600080fd5b505af11580156115ab573d6000803e3d6000fd5b505050506040513d60208110156115c157600080fd5b505085546001608060020a03908116608060020a8783168102919091178089556002890180546fffff0000000000000000000000000000198116607060020a9182900461ffff908116600101169091021767ffffffffffffffff191667ffffffffffffffff8d161790558083169190049091161115611665578554608060020a81046001608060020a03166fffffffffffffffffffffffffffffffff199091161786555b600286015461ffff607060020a820481166c010000000000000000000000009092041611156117925760028601546116d69086906116d1906116c49061ffff6c010000000000000000000000008204811691607060020a9004166118d0565b889063ffffffff6118ad16565b6118e7565b6001870180546fffffffffffffffffffffffffffffffff19166001608060020a03838116919091179091558754600289015492965061172e92606492610ada926801000000000000000090920461ffff169116611874565b600287015490935061178b9067ffffffffffffffff8a1690610b29906a0100000000000000000000900461ffff16610ada888161176b828b6118d0565b61177f62015180606463ffffffff61187416565b9063ffffffff61187416565b91506117d7565b8554600187018054608060020a9092046001608060020a03166fffffffffffffffffffffffffffffffff1990921682179055935083925067ffffffffffffffff881691505b600160a060020a0387163314156117f0575060006117f3565b50855b6040805186815267ffffffffffffffff8a16602082015280820186905260608101859052608081018490523360a0820152600160c08201529051600160a060020a0383169161ffff8d16917f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f9181900360e00190a350505050505050505050565b60008083151561188757600091506118a6565b5082820282848281151561189757fe5b04146118a257600080fd5b8091505b5092915050565b6000808083116118bc57600080fd5b82848115156118c757fe5b04949350505050565b600080838311156118e057600080fd5b5050900390565b6000828201838110156118a257600080fd5b61ffff83166000908152600460205260408120908080808061191a8961239e565b1515611970576040805160e560020a62461bcd02815260206004820152601760248201527f63757272656e6379206973206e6f742030202865746829000000000000000000604482015290519081900360640190fd5b61197a8989611dd1565b15156119d0576040805160e560020a62461bcd02815260206004820152601360248201527f6f7574206f662073616c657320706572696f6400000000000000000000000000604482015290519081900360640190fd5b6119da89896120dd565b95505034851115611a35576040805160e560020a62461bcd02815260206004820152601c60248201527f76616c7565206973206c657373207468616e2074686520707269636500000000604482015290519081900360640190fd5b611a3f8933611ec4565b84341115611a8557336108fc611a5b348863ffffffff6118d016565b6040518115909202916000818181858888f19350505050158015611a83573d6000803e3d6000fd5b505b85546001608060020a03908116608060020a8783168102919091178089556002890180546fffff0000000000000000000000000000198116607060020a9182900461ffff908116600101169091021767ffffffffffffffff191667ffffffffffffffff8d161790558083169190049091161115611b27578554608060020a81046001608060020a03166fffffffffffffffffffffffffffffffff199091161786555b600286015461ffff607060020a820481166c01000000000000000000000000909204161115611c22576002860154611b869086906116d1906116c49061ffff6c010000000000000000000000008204811691607060020a9004166118d0565b6001870180546fffffffffffffffffffffffffffffffff19166001608060020a038381169190911790915587546002890154929650611bde92606492610ada926801000000000000000090920461ffff169116611874565b6002870154909350611c1b9067ffffffffffffffff8a1690610b29906a0100000000000000000000900461ffff16610ada888161176b828b6118d0565b9150611c67565b8554600187018054608060020a9092046001608060020a03166fffffffffffffffffffffffffffffffff1990921682179055935083925067ffffffffffffffff881691505b600160a060020a038716331415611c8057506000611c83565b50855b6040805186815267ffffffffffffffff8a16602082015280820186905260608101859052608081018490523360a0820152600060c08201529051600160a060020a0383169161ffff8c16917f3db18ae119a752978a5fdd210c2d8457748cafadf61769dde052bb15edb62e7f9181900360e00190a3505050505050505050565b6000600160a060020a0382161515611d1a57600080fd5b50600160a060020a03166000908152602091909152604090205460ff1690565b600160a060020a0381161515611d4f57600080fd5b600160a060020a0316600090815260209190915260409020805460ff19169055565b600160a060020a0381161515611d8657600080fd5b600160a060020a0316600090815260209190915260409020805460ff19166001179055565b61ffff166000908152600460205260409020600290810154608060020a900460ff161490565b61ffff82166000908152600460205260408120600281015471010000000000000000000000000000000000900460ff161515611e57576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b600181015467ffffffffffffffff808516608060020a9092041611801590611ead5750600181015467ffffffffffffffff7801000000000000000000000000000000000000000000000000909104811690841611155b15611ebb57600191506118a6565b600091506118a6565b61ffff821660009081526004602052604081206002015471010000000000000000000000000000000000900460ff161515611f49576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b61ffff8084166000908152600460209081526040808320600201546005909252909120546c0100000000000000000000000090910490911611611ffc576040805160e560020a62461bcd02815260206004820152602c60248201527f4865726f65732063616e742062652063726561746564206d6f7265207468616e60448201527f20737570706c794c696d69740000000000000000000000000000000000000000606482015290519081900360840190fd5b61ffff831660008181526005602052604090205461202b91600191610b2991829061271063ffffffff61187416565b61ffff84166000908152600560209081526040808320805460018101825590845291832090910183905560085481517f4d5b335d000000000000000000000000000000000000000000000000000000008152600160a060020a038781166004830152602482018690529251949550911692634d5b335d9260448084019391929182900301818387803b1580156120c057600080fd5b505af11580156120d4573d6000803e3d6000fd5b50505050505050565b61ffff821660009081526004602052604081206002810154829190829081908190819071010000000000000000000000000000000000900460ff16151561216e576040805160e560020a62461bcd02815260206004820181905260248201527f6e6f742065786973742073616c6573206f662074686973206865726f54797065604482015290519081900360640190fd5b600285015467ffffffffffffffff808a169116106121fc576040805160e560020a62461bcd02815260206004820152603560248201527f63757272656e742074696d657374616d702073686f756c64206265206c61746560448201527f72207468616e2070726576696f757353616c6541740000000000000000000000606482015290519081900360840190fd5b6002850154855461222f91606491610ada916001608060020a039091169068010000000000000000900461ffff16611874565b60028601549094506122549067ffffffffffffffff8a8116911663ffffffff6118d016565b6002860154600187015491945061229a916201518091610ada9160649183916a010000000000000000000090910461ffff169061177f906001608060020a03168a611874565b600186015490925082906122bd906001608060020a03168663ffffffff6118d016565b11156122e85760018501546122e1906001608060020a03168363ffffffff6118d016565b90506122eb565b50825b6001999098509650505050505050565b600160a060020a038116151561231057600080fd5b60008054604051600160a060020a03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36000805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b61ffff16600090815260046020526040902060020154608060020a900460ff1660011490565b61ffff16600090815260046020526040902060020154608060020a900460ff161590565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810191909152905600a165627a7a72305820f98098e6ea4ba6a8b23a13c03df1115e245c511cb9ae500e5b4c64bc4af8f7d40029


   Swarm Source:
bzzr://f98098e6ea4ba6a8b23a13c03df1115e245c511cb9ae500e5b4c64bc4af8f7d4
Block Age transaction Difficulty GasUsed Reward
Block Age Uncle Number Difficulty GasUsed Reward
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.