ETH Price: $1,863.24 (-0.51%)

Transaction Decoder

Block:
7089500 at Jan-18-2019 10:34:55 PM +UTC
Transaction Fee:
0.000233376 ETH $0.43
Gas Used:
155,584 Gas / 1.5 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x150b0b96...683bF9739
(Nanopool)
9,132.042696680414932204 Eth9,132.042930056414932204 Eth0.000233376
0xbBA8FBaa...BAA74172A
(Dragonereum: Egg Marketplace)
0xfCAd2859...8f9009F7b
0xFEfBdC19...c7EedA019
2.163702180680419964 Eth
Nonce: 3675
2.163468804680419964 Eth
Nonce: 3676
0.000233376

Execution Trace

MainMarket.buyEgg( _id=2979, _expectedPrice=2000000000000000000000, _isGold=True )
  • MarketplaceController.buyEgg( _sender=0xFEfBdC19a0d855a8b9bBf79144BC32Cc7EedA019, _value=0, _id=2979, _expectedPrice=2000000000000000000000, _isGold=True ) => ( seller=0x5302D0b614947EC0b2c3607C838ceb0262027560, price=2000000000000000000000, success=True )
    • EggMarketplace.sellerOf( _id=2979 ) => ( 0x5302D0b614947EC0b2c3607C838ceb0262027560 )
    • EggStorage.isApprovedOrOwner( _spender=0x6D81d1fda601Df52f83188DCe617b65AC9b3C5BE, _tokenId=2979 ) => ( True )
    • EggStorage.ownerOf( _tokenId=2979 ) => ( 0x5302D0b614947EC0b2c3607C838ceb0262027560 )
    • Gold.balanceOf( owner=0xFEfBdC19a0d855a8b9bBf79144BC32Cc7EedA019 ) => ( 2100000000000000000000 )
    • EggMarketplace.buyToken( _tokenId=2979, _value=2100000000000000000000, _expectedPrice=2000000000000000000000, _expectedIsGold=True ) => ( price=2000000000000000000000 )
    • EggStorage.transferFrom( _from=0x5302D0b614947EC0b2c3607C838ceb0262027560, _to=0xFEfBdC19a0d855a8b9bBf79144BC32Cc7EedA019, _tokenId=2979 )
    • Gold.remoteTransfer( _to=0x5302D0b614947EC0b2c3607C838ceb0262027560, _value=2000000000000000000000 )
    • 0x5302d0b614947ec0b2c3607c838ceb0262027560.CALL( )
    • Events.emitEggBought( _buyer=0xFEfBdC19a0d855a8b9bBf79144BC32Cc7EedA019, _seller=0x5302D0b614947EC0b2c3607C838ceb0262027560, _id=2979, _price=2000000000000000000000 )
      File 1 of 6: MainMarket
      pragma solidity 0.4.25;
      
      library SafeMath256 {
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      
          function pow(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              if (b == 0) return 1;
      
              uint256 c = a ** b;
              assert(c / (a ** (b - 1)) == a);
              return c;
          }
      }
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Pausable is Ownable {
          event Pause();
          event Unpause();
      
          bool public paused = false;
      
          modifier whenNotPaused() {
              require(!paused, "contract is paused");
              _;
          }
      
          modifier whenPaused() {
              require(paused, "contract is not paused");
              _;
          }
      
          function pause() public onlyOwner whenNotPaused {
              paused = true;
              emit Pause();
          }
      
          function unpause() public onlyOwner whenPaused {
              paused = false;
              emit Unpause();
          }
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      contract HumanOriented {
          modifier onlyHuman() {
              require(msg.sender == tx.origin, "not a human");
              _;
          }
      }
      
      contract Events {
          function emitEggCreated(address, uint256) external;
          function emitDragonOnSale(address, uint256) external;
          function emitDragonRemovedFromSale(address, uint256) external;
          function emitDragonRemovedFromBreeding(address, uint256) external;
          function emitDragonOnBreeding(address, uint256) external;
          function emitDragonBought(address, address, uint256, uint256) external;
          function emitDragonBreedingBought(address, address, uint256, uint256) external;
          function emitDistributionUpdated(uint256, uint256, uint256) external;
          function emitEggOnSale(address, uint256) external;
          function emitEggRemovedFromSale(address, uint256) external;
          function emitEggBought(address, address, uint256, uint256) external;
          function emitGoldSellOrderCreated(address, uint256, uint256) external;
          function emitGoldSellOrderCancelled(address) external;
          function emitGoldSold(address, address, uint256, uint256) external;
          function emitGoldBuyOrderCreated(address, uint256, uint256) external;
          function emitGoldBuyOrderCancelled(address) external;
          function emitGoldBought(address, address, uint256, uint256) external;
          function emitSkillOnSale(address, uint256) external;
          function emitSkillRemovedFromSale(address, uint256) external;
          function emitSkillBought(address, address, uint256, uint256, uint256) external;
      }
      
      
      contract MarketplaceController {
          function buyEgg(address, uint256, uint256, uint256, bool) external returns (address, uint256, bool);
          function sellEgg(address, uint256, uint256, uint256, uint16, bool) external;
          function removeEggFromSale(address, uint256) external;
          function buyDragon(address, uint256, uint256, uint256, bool) external returns (address, uint256, bool);
          function sellDragon(address, uint256, uint256, uint256, uint16, bool) external;
          function removeDragonFromSale(address, uint256) external;
          function buyBreeding(address, uint256, uint256, uint256, uint256, bool) external returns (uint256, address, uint256, bool);
          function sellBreeding(address, uint256, uint256, uint256, uint16, bool) external;
          function removeBreedingFromSale(address, uint256) external;
          function buySkill(address, uint256, uint256, uint256, uint32) external returns (address, uint256, bool);
          function sellSkill(address, uint256, uint256) external;
          function removeSkillFromSale(address, uint256) external;
      }
      
      contract GoldMarketplace {
          function createSellOrder(address, uint256, uint256) external;
          function cancelSellOrder(address) external;
          function fillSellOrder(address, uint256, address, uint256, uint256) external returns (uint256);
          function createBuyOrder(address, uint256, uint256, uint256) external;
          function cancelBuyOrder(address) external;
          function fillBuyOrder(address, address, uint256, uint256) external returns (uint256);
      }
      
      
      
      
      //////////////CONTRACT//////////////
      
      
      
      
      contract MainMarket is Pausable, Upgradable, HumanOriented {
          using SafeMath256 for uint256;
      
          MarketplaceController public marketplaceController;
          GoldMarketplace goldMarketplace;
          Events events;
      
          // MARKETPLACE
      
          function _transferEth(
              address _from,
              address _to,
              uint256 _available,
              uint256 _required_,
              bool _isGold
          ) internal {
              uint256 _required = _required_;
              if (_isGold) {
                  _required = 0;
              }
      
              _to.transfer(_required);
              if (_available > _required) {
                  _from.transfer(_available.sub(_required));
              }
          }
      
          // EGG
      
          function buyEgg(
              uint256 _id,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyHuman whenNotPaused payable {
              (
                  address _seller,
                  uint256 _price,
                  bool _success
              ) = marketplaceController.buyEgg(
                  msg.sender,
                  msg.value,
                  _id,
                  _expectedPrice,
                  _isGold
              );
              if (_success) {
                  _transferEth(msg.sender, _seller, msg.value, _price, _isGold);
                  events.emitEggBought(msg.sender, _seller, _id, _price);
              } else {
                  msg.sender.transfer(msg.value);
                  events.emitEggRemovedFromSale(_seller, _id);
              }
          }
      
          function sellEgg(
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyHuman whenNotPaused {
              marketplaceController.sellEgg(msg.sender, _id, _maxPrice, _minPrice, _period, _isGold);
              events.emitEggOnSale(msg.sender, _id);
          }
      
          function removeEggFromSale(uint256 _id) external onlyHuman whenNotPaused {
              marketplaceController.removeEggFromSale(msg.sender, _id);
              events.emitEggRemovedFromSale(msg.sender, _id);
          }
      
          // DRAGON
      
          function buyDragon(
              uint256 _id,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyHuman whenNotPaused payable {
              (
                  address _seller,
                  uint256 _price,
                  bool _success
              ) = marketplaceController.buyDragon(
                  msg.sender,
                  msg.value,
                  _id,
                  _expectedPrice,
                  _isGold
              );
              if (_success) {
                  _transferEth(msg.sender, _seller, msg.value, _price, _isGold);
                  events.emitDragonBought(msg.sender, _seller, _id, _price);
              } else {
                  msg.sender.transfer(msg.value);
                  events.emitDragonRemovedFromSale(_seller, _id);
              }
          }
      
          function sellDragon(
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyHuman whenNotPaused {
              marketplaceController.sellDragon(msg.sender, _id, _maxPrice, _minPrice, _period, _isGold);
              events.emitDragonOnSale(msg.sender, _id);
          }
      
          function removeDragonFromSale(uint256 _id) external onlyHuman whenNotPaused {
              marketplaceController.removeDragonFromSale(msg.sender, _id);
              events.emitDragonRemovedFromSale(msg.sender, _id);
          }
      
          // BREEDING
      
          function buyBreeding(
              uint256 _momId,
              uint256 _dadId,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyHuman whenNotPaused payable {
              (
                  uint256 _eggId,
                  address _seller,
                  uint256 _price,
                  bool _success
              ) = marketplaceController.buyBreeding(
                  msg.sender,
                  msg.value,
                  _momId,
                  _dadId,
                  _expectedPrice,
                  _isGold
              );
              if (_success) {
                  events.emitEggCreated(msg.sender, _eggId);
                  _transferEth(msg.sender, _seller, msg.value, _price, _isGold);
                  events.emitDragonBreedingBought(msg.sender, _seller, _dadId, _price);
              } else {
                  msg.sender.transfer(msg.value);
                  events.emitDragonRemovedFromBreeding(_seller, _dadId);
              }
          }
      
          function sellBreeding(
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyHuman whenNotPaused {
              marketplaceController.sellBreeding(msg.sender, _id, _maxPrice, _minPrice, _period, _isGold);
              events.emitDragonOnBreeding(msg.sender, _id);
          }
      
          function removeBreedingFromSale(uint256 _id) external onlyHuman whenNotPaused {
              marketplaceController.removeBreedingFromSale(msg.sender, _id);
              events.emitDragonRemovedFromBreeding(msg.sender, _id);
          }
      
          // GOLD
      
          // SELL
      
          function fillGoldSellOrder(
              address _seller,
              uint256 _price,
              uint256 _amount
          ) external onlyHuman whenNotPaused payable {
              address(goldMarketplace).transfer(msg.value);
              uint256 _priceForOne = goldMarketplace.fillSellOrder(msg.sender, msg.value, _seller, _price, _amount);
              events.emitGoldSold(msg.sender, _seller, _amount, _priceForOne);
          }
      
          function createGoldSellOrder(
              uint256 _price,
              uint256 _amount
          ) external onlyHuman whenNotPaused {
              goldMarketplace.createSellOrder(msg.sender, _price, _amount);
              events.emitGoldSellOrderCreated(msg.sender, _price, _amount);
          }
      
          function cancelGoldSellOrder() external onlyHuman whenNotPaused {
              goldMarketplace.cancelSellOrder(msg.sender);
              events.emitGoldSellOrderCancelled(msg.sender);
          }
      
          // BUY
      
          function fillGoldBuyOrder(
              address _buyer,
              uint256 _price,
              uint256 _amount
          ) external onlyHuman whenNotPaused {
              uint256 _priceForOne = goldMarketplace.fillBuyOrder(msg.sender, _buyer, _price, _amount);
              events.emitGoldBought(msg.sender, _buyer, _amount, _priceForOne);
          }
      
          function createGoldBuyOrder(
              uint256 _price,
              uint256 _amount
          ) external onlyHuman whenNotPaused payable {
              address(goldMarketplace).transfer(msg.value);
              goldMarketplace.createBuyOrder(msg.sender, msg.value, _price, _amount);
              events.emitGoldBuyOrderCreated(msg.sender, _price, _amount);
          }
      
          function cancelGoldBuyOrder() external onlyHuman whenNotPaused {
              goldMarketplace.cancelBuyOrder(msg.sender);
              events.emitGoldBuyOrderCancelled(msg.sender);
          }
      
          // SKILL
      
          function buySkill(
              uint256 _id,
              uint256 _target,
              uint256 _expectedPrice,
              uint32 _expectedEffect
          ) external onlyHuman whenNotPaused {
              (
                  address _seller,
                  uint256 _price,
                  bool _success
              ) = marketplaceController.buySkill(
                  msg.sender,
                  _id,
                  _target,
                  _expectedPrice,
                  _expectedEffect
              );
      
              if (_success) {
                  events.emitSkillBought(msg.sender, _seller, _id, _target, _price);
              } else {
                  events.emitSkillRemovedFromSale(_seller, _id);
              }
          }
      
          function sellSkill(
              uint256 _id,
              uint256 _price
          ) external onlyHuman whenNotPaused {
              marketplaceController.sellSkill(msg.sender, _id, _price);
              events.emitSkillOnSale(msg.sender, _id);
          }
      
          function removeSkillFromSale(uint256 _id) external onlyHuman whenNotPaused {
              marketplaceController.removeSkillFromSale(msg.sender, _id);
              events.emitSkillRemovedFromSale(msg.sender, _id);
          }
      
          // UPDATE CONTRACT
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              super.setInternalDependencies(_newDependencies);
      
              marketplaceController = MarketplaceController(_newDependencies[0]);
              goldMarketplace = GoldMarketplace(_newDependencies[1]);
              events = Events(_newDependencies[2]);
          }
      }

      File 2 of 6: EggStorage
      pragma solidity 0.4.25;
      
      library SafeMath256 {
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      
          function pow(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              if (b == 0) return 1;
      
              uint256 c = a ** b;
              assert(c / (a ** (b - 1)) == a);
              return c;
          }
      }
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      contract ERC721Basic {
          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 exists(uint256 _tokenId) public view returns (bool _exists);
      
          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;
      
          function supportsInterface(bytes4 _interfaceID) external pure returns (bool);
      }
      
      contract ERC721Enumerable is ERC721Basic {
          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);
      }
      
      contract ERC721Metadata is ERC721Basic {
          function name() public view returns (string _name);
          function symbol() public view returns (string _symbol);
          function tokenURI(uint256 _tokenId) public view returns (string);
      }
      
      
      contract ERC721 is ERC721Basic, ERC721Enumerable, ERC721Metadata {}
      
      contract ERC721Receiver {
          function onERC721Received(
              address _operator,
              address _from,
              uint256 _tokenId,
              bytes _data
          )
              public
              returns(bytes4);
      }
      
      contract ERC721BasicToken is ERC721Basic, Upgradable {
      
          using SafeMath256 for uint256;
      
          // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
          // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
          bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
      
          // Mapping from token ID to owner
          mapping (uint256 => address) internal tokenOwner;
      
          // Mapping from token ID to approved address
          mapping (uint256 => address) internal tokenApprovals;
      
          // Mapping from owner to number of owned token
          mapping (address => uint256) internal ownedTokensCount;
      
          // Mapping from owner to operator approvals
          mapping (address => mapping (address => bool)) internal operatorApprovals;
      
          function _checkRights(bool _has) internal pure {
              require(_has, "no rights to manage");
          }
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          function _checkOwner(uint256 _tokenId, address _owner) internal view {
              require(ownerOf(_tokenId) == _owner, "not an owner");
          }
      
          function _checkThatUserHasTokens(bool _has) internal pure {
              require(_has, "user has no tokens");
          }
      
          function balanceOf(address _owner) public view returns (uint256) {
              _validateAddress(_owner);
              return ownedTokensCount[_owner];
          }
      
          function ownerOf(uint256 _tokenId) public view returns (address) {
              address owner = tokenOwner[_tokenId];
              _validateAddress(owner);
              return owner;
          }
      
          function exists(uint256 _tokenId) public view returns (bool) {
              address owner = tokenOwner[_tokenId];
              return owner != address(0);
          }
      
          function _approve(address _from, address _to, uint256 _tokenId) internal {
              address owner = ownerOf(_tokenId);
              require(_to != owner, "can't be approved to owner");
              _checkRights(_from == owner || isApprovedForAll(owner, _from));
      
              if (getApproved(_tokenId) != address(0) || _to != address(0)) {
                  tokenApprovals[_tokenId] = _to;
                  emit Approval(owner, _to, _tokenId);
              }
          }
      
          function approve(address _to, uint256 _tokenId) public {
              _approve(msg.sender, _to, _tokenId);
          }
      
          function remoteApprove(address _to, uint256 _tokenId) external onlyController {
              _approve(tx.origin, _to, _tokenId);
          }
      
          function getApproved(uint256 _tokenId) public view returns (address) {
              require(exists(_tokenId), "token doesn't exist");
              return tokenApprovals[_tokenId];
          }
      
          function setApprovalForAll(address _to, bool _approved) public {
              require(_to != msg.sender, "wrong sender");
              operatorApprovals[msg.sender][_to] = _approved;
              emit ApprovalForAll(msg.sender, _to, _approved);
          }
      
          function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
              return operatorApprovals[_owner][_operator];
          }
      
          function transferFrom(address _from, address _to, uint256 _tokenId) public {
              _checkRights(isApprovedOrOwner(msg.sender, _tokenId));
              _validateAddress(_from);
              _validateAddress(_to);
      
              clearApproval(_from, _tokenId);
              removeTokenFrom(_from, _tokenId);
              addTokenTo(_to, _tokenId);
      
              emit Transfer(_from, _to, _tokenId);
          }
      
          function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId
          ) public {
              safeTransferFrom(_from, _to, _tokenId, "");
          }
      
          function safeTransferFrom(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes _data
          ) public {
              transferFrom(_from, _to, _tokenId);
              require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data), "can't make safe transfer");
          }
      
          function isApprovedOrOwner(address _spender, uint256 _tokenId) public view returns (bool) {
              address owner = ownerOf(_tokenId);
              return _spender == owner || getApproved(_tokenId) == _spender || isApprovedForAll(owner, _spender);
          }
      
          function _mint(address _to, uint256 _tokenId) internal {
              _validateAddress(_to);
              addTokenTo(_to, _tokenId);
              emit Transfer(address(0), _to, _tokenId);
          }
      
          function _burn(address _owner, uint256 _tokenId) internal {
              clearApproval(_owner, _tokenId);
              removeTokenFrom(_owner, _tokenId);
              emit Transfer(_owner, address(0), _tokenId);
          }
      
          function clearApproval(address _owner, uint256 _tokenId) internal {
              _checkOwner(_tokenId, _owner);
              if (tokenApprovals[_tokenId] != address(0)) {
                  tokenApprovals[_tokenId] = address(0);
                  emit Approval(_owner, address(0), _tokenId);
              }
          }
      
          function addTokenTo(address _to, uint256 _tokenId) internal {
              require(tokenOwner[_tokenId] == address(0), "token already has an owner");
              tokenOwner[_tokenId] = _to;
              ownedTokensCount[_to] = ownedTokensCount[_to].add(1);
          }
      
          function removeTokenFrom(address _from, uint256 _tokenId) internal {
              _checkOwner(_tokenId, _from);
              _checkThatUserHasTokens(ownedTokensCount[_from] > 0);
              ownedTokensCount[_from] = ownedTokensCount[_from].sub(1);
              tokenOwner[_tokenId] = address(0);
          }
      
          function _isContract(address addr) internal view returns (bool) {
              uint256 size;
              assembly { size := extcodesize(addr) }
              return size > 0;
          }
      
          function checkAndCallSafeTransfer(
              address _from,
              address _to,
              uint256 _tokenId,
              bytes _data
          ) internal returns (bool) {
              if (!_isContract(_to)) {
                  return true;
              }
              bytes4 retval = ERC721Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
              return (retval == _ERC721_RECEIVED);
          }
      }
      
      contract ERC721Token is ERC721, ERC721BasicToken {
      
          bytes4 internal constant INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
          bytes4 internal constant INTERFACE_SIGNATURE_ERC721 = 0x80ac58cd;
          bytes4 internal constant INTERFACE_SIGNATURE_ERC721TokenReceiver = 0xf0b9e5ba;
          bytes4 internal constant INTERFACE_SIGNATURE_ERC721Metadata = 0x5b5e139f;
          bytes4 internal constant INTERFACE_SIGNATURE_ERC721Enumerable = 0x780e9d63;
      
          string internal name_;
          string internal symbol_;
      
          // Mapping from owner to list of owned token IDs
          mapping (address => uint256[]) internal ownedTokens;
      
          // Mapping from token ID to index of the owner tokens list
          mapping(uint256 => uint256) internal ownedTokensIndex;
      
          // Array with all token ids, used for enumeration
          uint256[] internal allTokens;
      
          // Mapping from token id to position in the allTokens array
          mapping(uint256 => uint256) internal allTokensIndex;
      
          // Optional mapping for token URIs
          mapping(uint256 => string) internal tokenURIs;
      
          // The contract owner can change the base URL, in case it becomes necessary. It is needed for Metadata.
          string public url;
      
      
          constructor(string _name, string _symbol) public {
              name_ = _name;
              symbol_ = _symbol;
          }
      
          function name() public view returns (string) {
              return name_;
          }
      
          function symbol() public view returns (string) {
              return symbol_;
          }
      
          function _validateIndex(bool _isValid) internal pure {
              require(_isValid, "wrong index");
          }
      
          function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
              _validateIndex(_index < balanceOf(_owner));
              return ownedTokens[_owner][_index];
          }
      
          function tokensOfOwner(address _owner) external view returns (uint256[]) {
              return ownedTokens[_owner];
          }
      
          function getAllTokens() external view returns (uint256[]) {
              return allTokens;
          }
      
          function totalSupply() public view returns (uint256) {
              return allTokens.length;
          }
      
          function tokenByIndex(uint256 _index) public view returns (uint256) {
              _validateIndex(_index < totalSupply());
              return allTokens[_index];
          }
      
          function addTokenTo(address _to, uint256 _tokenId) internal {
              super.addTokenTo(_to, _tokenId);
              uint256 length = ownedTokens[_to].length;
              ownedTokens[_to].push(_tokenId);
              ownedTokensIndex[_tokenId] = length;
          }
      
          function removeTokenFrom(address _from, uint256 _tokenId) internal {
              _checkThatUserHasTokens(ownedTokens[_from].length > 0);
      
              super.removeTokenFrom(_from, _tokenId);
      
              uint256 tokenIndex = ownedTokensIndex[_tokenId];
              uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
              uint256 lastToken = ownedTokens[_from][lastTokenIndex];
      
              ownedTokens[_from][tokenIndex] = lastToken;
              ownedTokens[_from][lastTokenIndex] = 0;
      
              ownedTokens[_from].length--;
              ownedTokensIndex[_tokenId] = 0;
              ownedTokensIndex[lastToken] = tokenIndex;
          }
      
          function _mint(address _to, uint256 _tokenId) internal {
              super._mint(_to, _tokenId);
      
              allTokensIndex[_tokenId] = allTokens.length;
              allTokens.push(_tokenId);
          }
      
          function _burn(address _owner, uint256 _tokenId) internal {
              require(allTokens.length > 0, "no tokens");
      
              super._burn(_owner, _tokenId);
      
              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;
          }
      
          function supportsInterface(bytes4 _interfaceID) external pure returns (bool) {
              return (
                  _interfaceID == INTERFACE_SIGNATURE_ERC165 ||
                  _interfaceID == INTERFACE_SIGNATURE_ERC721 ||
                  _interfaceID == INTERFACE_SIGNATURE_ERC721TokenReceiver ||
                  _interfaceID == INTERFACE_SIGNATURE_ERC721Metadata ||
                  _interfaceID == INTERFACE_SIGNATURE_ERC721Enumerable
              );
          }
      
          function tokenURI(uint256 _tokenId) public view returns (string) {
              require(exists(_tokenId), "token doesn't exist");
              return string(abi.encodePacked(url, _uint2str(_tokenId)));
          }
      
          function setUrl(string _url) external onlyOwner {
              url = _url;
          }
      
          function _uint2str(uint _i) internal pure returns (string){
              if (i == 0) return "0";
              uint i = _i;
              uint j = _i;
              uint length;
              while (j != 0){
                  length++;
                  j /= 10;
              }
              bytes memory bstr = new bytes(length);
              uint k = length - 1;
              while (i != 0){
                  bstr[k--] = byte(48 + i % 10);
                  i /= 10;
              }
              return string(bstr);
          }
      }
      
      
      contract EggStorage is ERC721Token {
          struct Egg {
              uint256[2] parents;
              uint8 dragonType; // used for genesis only
          }
      
          Egg[] eggs;
      
          constructor(string _name, string _symbol) public ERC721Token(_name, _symbol) {
              eggs.length = 1; // to avoid some issues with 0
          }
      
          function push(address _sender, uint256[2] _parents, uint8 _dragonType) public onlyController returns (uint256 id) {
              Egg memory _egg = Egg(_parents, _dragonType);
              id = eggs.push(_egg).sub(1);
              _mint(_sender, id);
          }
      
          function get(uint256 _id) external view returns (uint256[2], uint8) {
              return (eggs[_id].parents, eggs[_id].dragonType);
          }
      
          function remove(address _owner, uint256 _id) external onlyController {
              delete eggs[_id];
              _burn(_owner, _id);
          }
      }

      File 3 of 6: Gold
      pragma solidity 0.4.25;
      
      library SafeMath256 {
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      
          function pow(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              if (b == 0) return 1;
      
              uint256 c = a ** b;
              assert(c / (a ** (b - 1)) == a);
              return c;
          }
      }
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      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
        );
      }
      
      contract ERC20 is IERC20 {
          using SafeMath256 for uint256;
      
          mapping (address => uint256) _balances;
      
          mapping (address => mapping (address => uint256)) _allowed;
      
          uint256 _totalSupply;
      
          string public name;
          string public symbol;
          uint8 public decimals;
      
          function totalSupply() public view returns (uint256) {
              return _totalSupply;
          }
      
          function balanceOf(address owner) public view returns (uint256) {
              return _balances[owner];
          }
      
          function allowance(
              address owner,
              address spender
          )
            public
            view
            returns (uint256)
          {
              return _allowed[owner][spender];
          }
      
          function transfer(address to, uint256 value) public returns (bool) {
              _transfer(msg.sender, to, value);
              return true;
          }
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          function approve(address spender, uint256 value) public returns (bool) {
              _validateAddress(spender);
      
              _allowed[msg.sender][spender] = value;
              emit Approval(msg.sender, spender, value);
              return true;
          }
      
          function transferFrom(
              address from,
              address to,
              uint256 value
          )
            public
            returns (bool)
          {
              require(value <= _allowed[from][msg.sender], "not enough allowed tokens");
      
              _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);
              _transfer(from, to, value);
              return true;
          }
      
          function increaseAllowance(
              address spender,
              uint256 addedValue
          )
            public
            returns (bool)
          {
              _validateAddress(spender);
      
              _allowed[msg.sender][spender] = _allowed[msg.sender][spender].add(addedValue);
              emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
              return true;
          }
      
          function decreaseAllowance(
              address spender,
              uint256 subtractedValue
          )
            public
            returns (bool)
          {
              _validateAddress(spender);
      
              _allowed[msg.sender][spender] = _allowed[msg.sender][spender].sub(subtractedValue);
              emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);
              return true;
          }
      
          function _transfer(address from, address to, uint256 value) internal {
              require(value <= _balances[from], "not enough tokens");
              _validateAddress(to);
      
              _balances[from] = _balances[from].sub(value);
              _balances[to] = _balances[to].add(value);
              emit Transfer(from, to, value);
          }
      
          function _mint(address account, uint256 value) internal {
              _validateAddress(account);
              _totalSupply = _totalSupply.add(value);
              _balances[account] = _balances[account].add(value);
              emit Transfer(address(0), account, value);
          }
      
          function _burn(address account, uint256 value) internal {
              _validateAddress(account);
              require(value <= _balances[account], "not enough tokens to burn");
      
              _totalSupply = _totalSupply.sub(value);
              _balances[account] = _balances[account].sub(value);
              emit Transfer(account, address(0), value);
          }
      
          function _burnFrom(address account, uint256 value) internal {
              require(value <= _allowed[account][msg.sender], "not enough allowed tokens to burn");
      
              _allowed[account][msg.sender] = _allowed[account][msg.sender].sub(value);
              _burn(account, value);
          }
      }
      
      contract Gold is ERC20, Upgradable {
          address[5] founders = [
              0x23b3763f31F4da6B42F47927BCF66A221E8705Cd,
              0x5CFF40372b96e133967d980F72812653163121fa,
              0xE246C5Aa2D57878DA70779A75B12dCDFFd77aDBA,
              0x950eEAf8ddbA1409dbD25aD16d50A867EEA75c3E,
              0x87252E8F04F6c6bC4d2c690893addb7108aa8a5f
          ];
      
          address foundation = 0x5Ff8957EF7e964E8072815211c9Fc3E7F820F1D4;
          address NonsenseGames = 0x10208FB4Ef202BdC49803995b0A8CA185383bba4;
      
          string constant WP_IPFS_HASH = "QmfR75tK12q2LpkU5dzYqykUUpYswSiewpCbDuwYhRb6M5";
      
      
          constructor(address treasury) public {
              name = "Dragonereum Gold";
              symbol = "GOLD";
              decimals = 18;
      
              uint256 _foundersGold = 6000000 * 10**18; // 10%
              uint256 _foundationGold = 6000000 * 10**18; // 10%
              uint256 _NonsenseGamesGold = 3000000 * 10**18; // 5%
              uint256 _gameAccountGold = 45000000 * 10**18; // 75%
      
              uint256 _founderStake = _foundersGold.div(founders.length);
              for (uint256 i = 0; i < founders.length; i++) {
                  _mint(founders[i], _founderStake);
              }
      
              _mint(foundation, _foundationGold);
              _mint(NonsenseGames, _NonsenseGamesGold);
              _mint(treasury, _gameAccountGold);
      
              require(_totalSupply == 60000000 * 10**18, "wrong total supply");
          }
      
          function remoteTransfer(address _to, uint256 _value) external onlyController {
              _transfer(tx.origin, _to, _value);
          }
      
          function burn(uint256 _value) external onlyController {
              _burn(msg.sender, _value);
          }
      }

      File 4 of 6: Events
      pragma solidity 0.4.25;
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      
      
      
      //////////////CONTRACT//////////////
      
      
      
      
      contract Events is Upgradable {
          event EggClaimed(address indexed user, uint256 indexed id);
          event EggSentToNest(address indexed user, uint256 indexed id);
          event EggHatched(address indexed user, uint256 indexed dragonId, uint256 indexed eggId);
          event DragonUpgraded(uint256 indexed id);
          event EggCreated(address indexed user, uint256 indexed id);
          event DragonOnSale(address indexed seller, uint256 indexed id);
          event DragonRemovedFromSale(address indexed seller, uint256 indexed id);
          event DragonRemovedFromBreeding(address indexed seller, uint256 indexed id);
          event DragonOnBreeding(address indexed seller, uint256 indexed id);
          event DragonBought(address indexed buyer, address indexed seller, uint256 indexed id, uint256 price);
          event DragonBreedingBought(address indexed buyer, address indexed seller, uint256 indexed id, uint256 price);
          event DistributionUpdated(uint256 restAmount, uint256 lastBlock, uint256 interval);
          event EggOnSale(address indexed seller, uint256 indexed id);
          event EggRemovedFromSale(address indexed seller, uint256 indexed id);
          event EggBought(address indexed buyer, address indexed seller, uint256 indexed id, uint256 price);
          event GoldSellOrderCreated(address indexed seller, uint256 price, uint256 amount);
          event GoldSellOrderCancelled(address indexed seller);
          event GoldSold(address indexed buyer, address indexed seller, uint256 amount, uint256 price);
          event GoldBuyOrderCreated(address indexed buyer, uint256 price, uint256 amount);
          event GoldBuyOrderCancelled(address indexed buyer);
          event GoldBought(address indexed seller, address indexed buyer, uint256 amount, uint256 price);
          event SkillOnSale(address indexed seller, uint256 indexed id);
          event SkillRemovedFromSale(address indexed seller, uint256 indexed id);
          event SkillBought(address indexed buyer, address indexed seller, uint256 id, uint256 indexed target, uint256 price);
          event SkillSet(uint256 indexed id);
          event SkillUsed(uint256 indexed id, uint256 indexed target);
          event DragonNameSet(uint256 indexed id, bytes32 name);
          event DragonTacticsSet(uint256 indexed id, uint8 melee, uint8 attack);
          event UserNameSet(address indexed user, bytes32 name);
          event BattleEnded(
              uint256 indexed battleId,
              uint256 date,
              uint256 seed,
              uint256 attackerId,
              uint256 indexed winnerId,
              uint256 indexed looserId,
              bool isGladiator,
              uint256 gladiatorBattleId
          );
          event BattleDragonsDetails(
              uint256 indexed battleId,
              uint8 winnerLevel,
              uint32 winnerCoolness,
              uint8 looserLevel,
              uint32 looserCoolness
          );
          event BattleHealthAndMana(
              uint256 indexed battleId,
              uint32 attackerMaxHealth,
              uint32 attackerMaxMana,
              uint32 attackerInitHealth,
              uint32 attackerInitMana,
              uint32 opponentMaxHealth,
              uint32 opponentMaxMana,
              uint32 opponentInitHealth,
              uint32 opponentInitMana
          );
          event BattleSkills(
              uint256 indexed battleId,
              uint32 attackerAttack,
              uint32 attackerDefense,
              uint32 attackerStamina,
              uint32 attackerSpeed,
              uint32 attackerIntelligence,
              uint32 opponentAttack,
              uint32 opponentDefense,
              uint32 opponentStamina,
              uint32 opponentSpeed,
              uint32 opponentIntelligence
          );
          event BattleTacticsAndBuffs(
              uint256 indexed battleId,
              uint8 attackerMeleeChance,
              uint8 attackerAttackChance,
              uint8 opponentMeleeChance,
              uint8 opponentAttackChance,
              uint32[5] attackerBuffs,
              uint32[5] opponentBuffs
          );
          event GladiatorBattleEnded(
              uint256 indexed id,
              uint256 battleId,
              address indexed winner,
              address indexed looser,
              uint256 reward,
              bool isGold
          );
          event GladiatorBattleCreated(
              uint256 indexed id,
              address indexed user,
              uint256 indexed dragonId,
              uint256 bet,
              bool isGold
          );
          event GladiatorBattleApplicantAdded(
              uint256 indexed id,
              address indexed user,
              uint256 indexed dragonId
          );
          event GladiatorBattleOpponentSelected(
              uint256 indexed id,
              uint256 indexed dragonId
          );
          event GladiatorBattleCancelled(uint256 indexed id);
          event GladiatorBattleBetReturned(uint256 indexed id, address indexed user);
          event GladiatorBattleOpponentSelectTimeUpdated(uint256 indexed id, uint256 blockNumber);
          event GladiatorBattleBlockNumberUpdated(uint256 indexed id, uint256 blockNumber);
          event GladiatorBattleSpectatorBetPlaced(
              uint256 indexed id,
              address indexed user,
              bool indexed willCreatorWin,
              uint256 bet,
              bool isGold
          );
          event GladiatorBattleSpectatorBetRemoved(uint256 indexed id, address indexed user);
          event GladiatorBattleSpectatorRewardPaidOut(
              uint256 indexed id,
              address indexed user,
              uint256 reward,
              bool isGold
          );
          event LeaderboardRewardsDistributed(uint256[10] dragons, address[10] users);
      
          function emitEggClaimed(
              address _user,
              uint256 _id
          ) external onlyController {
              emit EggClaimed(_user, _id);
          }
      
          function emitEggSentToNest(
              address _user,
              uint256 _id
          ) external onlyController {
              emit EggSentToNest(_user, _id);
          }
      
          function emitDragonUpgraded(
              uint256 _id
          ) external onlyController {
              emit DragonUpgraded(_id);
          }
      
          function emitEggHatched(
              address _user,
              uint256 _dragonId,
              uint256 _eggId
          ) external onlyController {
              emit EggHatched(_user, _dragonId, _eggId);
          }
      
          function emitEggCreated(
              address _user,
              uint256 _id
          ) external onlyController {
              emit EggCreated(_user, _id);
          }
      
          function emitDragonOnSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit DragonOnSale(_user, _id);
          }
      
          function emitDragonRemovedFromSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit DragonRemovedFromSale(_user, _id);
          }
      
          function emitDragonRemovedFromBreeding(
              address _user,
              uint256 _id
          ) external onlyController {
              emit DragonRemovedFromBreeding(_user, _id);
          }
      
          function emitDragonOnBreeding(
              address _user,
              uint256 _id
          ) external onlyController {
              emit DragonOnBreeding(_user, _id);
          }
      
          function emitDragonBought(
              address _buyer,
              address _seller,
              uint256 _id,
              uint256 _price
          ) external onlyController {
              emit DragonBought(_buyer, _seller, _id, _price);
          }
      
          function emitDragonBreedingBought(
              address _buyer,
              address _seller,
              uint256 _id,
              uint256 _price
          ) external onlyController {
              emit DragonBreedingBought(_buyer, _seller, _id, _price);
          }
      
          function emitDistributionUpdated(
              uint256 _restAmount,
              uint256 _lastBlock,
              uint256 _interval
          ) external onlyController {
              emit DistributionUpdated(_restAmount, _lastBlock, _interval);
          }
      
          function emitEggOnSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit EggOnSale(_user, _id);
          }
      
          function emitEggRemovedFromSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit EggRemovedFromSale(_user, _id);
          }
      
          function emitEggBought(
              address _buyer,
              address _seller,
              uint256 _id,
              uint256 _price
          ) external onlyController {
              emit EggBought(_buyer, _seller, _id, _price);
          }
      
          function emitGoldSellOrderCreated(
              address _user,
              uint256 _price,
              uint256 _amount
          ) external onlyController {
              emit GoldSellOrderCreated(_user, _price, _amount);
          }
      
          function emitGoldSellOrderCancelled(
              address _user
          ) external onlyController {
              emit GoldSellOrderCancelled(_user);
          }
      
          function emitGoldSold(
              address _buyer,
              address _seller,
              uint256 _amount,
              uint256 _price
          ) external onlyController {
              emit GoldSold(_buyer, _seller, _amount, _price);
          }
      
          function emitGoldBuyOrderCreated(
              address _user,
              uint256 _price,
              uint256 _amount
          ) external onlyController {
              emit GoldBuyOrderCreated(_user, _price, _amount);
          }
      
          function emitGoldBuyOrderCancelled(
              address _user
          ) external onlyController {
              emit GoldBuyOrderCancelled(_user);
          }
      
          function emitGoldBought(
              address _buyer,
              address _seller,
              uint256 _amount,
              uint256 _price
          ) external onlyController {
              emit GoldBought(_buyer, _seller, _amount, _price);
          }
      
          function emitSkillOnSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit SkillOnSale(_user, _id);
          }
      
          function emitSkillRemovedFromSale(
              address _user,
              uint256 _id
          ) external onlyController {
              emit SkillRemovedFromSale(_user, _id);
          }
      
          function emitSkillBought(
              address _buyer,
              address _seller,
              uint256 _id,
              uint256 _target,
              uint256 _price
          ) external onlyController {
              emit SkillBought(_buyer, _seller, _id, _target, _price);
          }
      
          function emitSkillSet(
              uint256 _id
          ) external onlyController {
              emit SkillSet(_id);
          }
      
          function emitSkillUsed(
              uint256 _id,
              uint256 _target
          ) external onlyController {
              emit SkillUsed(_id, _target);
          }
      
          function emitDragonNameSet(
              uint256 _id,
              bytes32 _name
          ) external onlyController {
              emit DragonNameSet(_id, _name);
          }
      
          function emitDragonTacticsSet(
              uint256 _id,
              uint8 _melee,
              uint8 _attack
          ) external onlyController {
              emit DragonTacticsSet(_id, _melee, _attack);
          }
      
          function emitUserNameSet(
              address _user,
              bytes32 _name
          ) external onlyController {
              emit UserNameSet(_user, _name);
          }
      
          function emitBattleEnded(
              uint256 _battleId,
              uint256 _date,
              uint256 _seed,
              uint256 _attackerId,
              uint256 _winnerId,
              uint256 _looserId,
              bool _isGladiator,
              uint256 _gladiatorBattleId
          ) external onlyController {
              emit BattleEnded(
                  _battleId,
                  _date,
                  _seed,
                  _attackerId,
                  _winnerId,
                  _looserId,
                  _isGladiator,
                  _gladiatorBattleId
              );
          }
      
          function emitBattleDragonsDetails(
              uint256 _battleId,
              uint8 _winnerLevel,
              uint32 _winnerCoolness,
              uint8 _looserLevel,
              uint32 _looserCoolness
          ) external onlyController {
              emit BattleDragonsDetails(
                  _battleId,
                  _winnerLevel,
                  _winnerCoolness,
                  _looserLevel,
                  _looserCoolness
              );
          }
      
          function emitBattleHealthAndMana(
              uint256 _battleId,
              uint32 _attackerMaxHealth,
              uint32 _attackerMaxMana,
              uint32 _attackerInitHealth,
              uint32 _attackerInitMana,
              uint32 _opponentMaxHealth,
              uint32 _opponentMaxMana,
              uint32 _opponentInitHealth,
              uint32 _opponentInitMana
          ) external onlyController {
              emit BattleHealthAndMana(
                  _battleId,
                  _attackerMaxHealth,
                  _attackerMaxMana,
                  _attackerInitHealth,
                  _attackerInitMana,
                  _opponentMaxHealth,
                  _opponentMaxMana,
                  _opponentInitHealth,
                  _opponentInitMana
              );
          }
      
          function emitBattleSkills(
              uint256 _battleId,
              uint32 _attackerAttack,
              uint32 _attackerDefense,
              uint32 _attackerStamina,
              uint32 _attackerSpeed,
              uint32 _attackerIntelligence,
              uint32 _opponentAttack,
              uint32 _opponentDefense,
              uint32 _opponentStamina,
              uint32 _opponentSpeed,
              uint32 _opponentIntelligence
          ) external onlyController {
              emit BattleSkills(
                  _battleId,
                  _attackerAttack,
                  _attackerDefense,
                  _attackerStamina,
                  _attackerSpeed,
                  _attackerIntelligence,
                  _opponentAttack,
                  _opponentDefense,
                  _opponentStamina,
                  _opponentSpeed,
                  _opponentIntelligence
              );
          }
      
          function emitBattleTacticsAndBuffs(
              uint256 _battleId,
              uint8 _attackerMeleeChance,
              uint8 _attackerAttackChance,
              uint8 _opponentMeleeChance,
              uint8 _opponentAttackChance,
              uint32[5] _attackerBuffs,
              uint32[5] _opponentBuffs
          ) external onlyController {
              emit BattleTacticsAndBuffs(
                  _battleId,
                  _attackerMeleeChance,
                  _attackerAttackChance,
                  _opponentMeleeChance,
                  _opponentAttackChance,
                  _attackerBuffs,
                  _opponentBuffs
              );
          }
      
          function emitGladiatorBattleEnded(
              uint256 _id,
              uint256 _battleId,
              address _winner,
              address _looser,
              uint256 _reward,
              bool _isGold
          ) external onlyController {
              emit GladiatorBattleEnded(
                  _id,
                  _battleId,
                  _winner,
                  _looser,
                  _reward,
                  _isGold
              );
          }
      
          function emitGladiatorBattleCreated(
              uint256 _id,
              address _user,
              uint256 _dragonId,
              uint256 _bet,
              bool _isGold
          ) external onlyController {
              emit GladiatorBattleCreated(
                  _id,
                  _user,
                  _dragonId,
                  _bet,
                  _isGold
              );
          }
      
          function emitGladiatorBattleApplicantAdded(
              uint256 _id,
              address _user,
              uint256 _dragonId
          ) external onlyController {
              emit GladiatorBattleApplicantAdded(
                  _id,
                  _user,
                  _dragonId
              );
          }
      
          function emitGladiatorBattleOpponentSelected(
              uint256 _id,
              uint256 _dragonId
          ) external onlyController {
              emit GladiatorBattleOpponentSelected(
                  _id,
                  _dragonId
              );
          }
      
          function emitGladiatorBattleCancelled(
              uint256 _id
          ) external onlyController {
              emit GladiatorBattleCancelled(
                  _id
              );
          }
      
          function emitGladiatorBattleBetReturned(
              uint256 _id,
              address _user
          ) external onlyController {
              emit GladiatorBattleBetReturned(
                  _id,
                  _user
              );
          }
      
          function emitGladiatorBattleOpponentSelectTimeUpdated(
              uint256 _id,
              uint256 _blockNumber
          ) external onlyController {
              emit GladiatorBattleOpponentSelectTimeUpdated(
                  _id,
                  _blockNumber
              );
          }
      
          function emitGladiatorBattleBlockNumberUpdated(
              uint256 _id,
              uint256 _blockNumber
          ) external onlyController {
              emit GladiatorBattleBlockNumberUpdated(
                  _id,
                  _blockNumber
              );
          }
      
          function emitGladiatorBattleSpectatorBetPlaced(
              uint256 _id,
              address _user,
              bool _willCreatorWin,
              uint256 _value,
              bool _isGold
          ) external onlyController {
              emit GladiatorBattleSpectatorBetPlaced(
                  _id,
                  _user,
                  _willCreatorWin,
                  _value,
                  _isGold
              );
          }
      
          function emitGladiatorBattleSpectatorBetRemoved(
              uint256 _id,
              address _user
          ) external onlyController {
              emit GladiatorBattleSpectatorBetRemoved(
                  _id,
                  _user
              );
          }
      
          function emitGladiatorBattleSpectatorRewardPaidOut(
              uint256 _id,
              address _user,
              uint256 _value,
              bool _isGold
          ) external onlyController {
              emit GladiatorBattleSpectatorRewardPaidOut(
                  _id,
                  _user,
                  _value,
                  _isGold
              );
          }
      
          function emitLeaderboardRewardsDistributed(
              uint256[10] _dragons,
              address[10] _users
          ) external onlyController {
              emit LeaderboardRewardsDistributed(
                  _dragons,
                  _users
              );
          }
      }

      File 5 of 6: MarketplaceController
      pragma solidity 0.4.25;
      
      library SafeMath256 {
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      
          function pow(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              if (b == 0) return 1;
      
              uint256 c = a ** b;
              assert(c / (a ** (b - 1)) == a);
              return c;
          }
      }
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      contract Core {
          function breed(address, uint256, uint256) external returns (uint256);
          function isEggInNest(uint256) external view returns (bool);
          function useDragonSpecialPeacefulSkill(address, uint256, uint256) external;
      }
      
      contract Marketplace {
          function sellToken(uint256, address, uint256, uint256, uint16, bool) external;
          function removeFromAuction(uint256) external;
          function buyToken(uint256, uint256, uint256, bool) external returns (uint256);
          function sellerOf(uint256) external view returns (address);
      }
      
      contract EggMarketplace is Marketplace {}
      contract DragonMarketplace is Marketplace {}
      contract BreedingMarketplace is Marketplace {}
      
      contract GoldMarketplace {}
      
      contract SkillMarketplace is Upgradable {
          function sellToken(uint256, uint256) external;
          function removeFromAuction(uint256) external;
          function getAuction(uint256) external view returns (uint256);
      }
      
      contract ERC721Token {
          function ownerOf(uint256) public view returns (address);
          function exists(uint256) public view returns (bool);
          function remoteApprove(address, uint256) external;
          function isApprovedOrOwner(address, uint256) public view returns (bool);
          function transferFrom(address, address, uint256) public;
      }
      
      contract DragonStorage is ERC721Token {}
      contract EggStorage is ERC721Token {}
      
      contract ERC20 {
          function balanceOf(address) public view returns (uint256);
      }
      
      contract Gold is ERC20 {
          function remoteTransfer(address, uint256) external;
      }
      
      contract Getter {
          function isDragonBreedingAllowed(uint256) external view returns (bool);
          function getDragonSpecialPeacefulSkill(uint256) external view returns (uint8, uint32, uint32);
          function isDragonInGladiatorBattle(uint256) public view returns (bool);
      }
      
      
      
      
      //////////////CONTRACT//////////////
      
      
      
      
      contract MarketplaceController is Upgradable {
          using SafeMath256 for uint256;
      
          Core core;
          BreedingMarketplace breedingMarketplace;
          EggMarketplace eggMarketplace;
          DragonMarketplace dragonMarketplace;
          GoldMarketplace goldMarketplace;
          SkillMarketplace skillMarketplace;
          DragonStorage dragonStorage;
          EggStorage eggStorage;
          Gold goldTokens;
          Getter getter;
      
          // ACTIONS WITH OWN TOKEN
      
          function _isEggOwner(address _user, uint256 _tokenId) internal view returns (bool) {
              return _user == eggStorage.ownerOf(_tokenId);
          }
      
          function _isDragonOwner(address _user, uint256 _tokenId) internal view returns (bool) {
              return _user == dragonStorage.ownerOf(_tokenId);
          }
      
          function _checkOwner(bool _isOwner) internal pure {
              require(_isOwner, "not an owner");
          }
      
          function _checkEggOwner(uint256 _tokenId, address _user) internal view {
              _checkOwner(_isEggOwner(_user, _tokenId));
          }
      
          function _checkDragonOwner(uint256 _tokenId, address _user) internal view {
              _checkOwner(_isDragonOwner(_user, _tokenId));
          }
      
          function _compareBuyerAndSeller(address _buyer, address _seller) internal pure {
              require(_buyer != _seller, "seller can't be buyer");
          }
      
          function _checkTheDragonIsNotInGladiatorBattle(uint256 _id) internal view {
              require(!getter.isDragonInGladiatorBattle(_id), "dragon participates in gladiator battle");
          }
      
          function _checkIfBreedingIsAllowed(uint256 _id) internal view {
              require(getter.isDragonBreedingAllowed(_id), "dragon has no enough DNA points for breeding");
          }
      
          function _checkEnoughGold(uint256 _required, uint256 _available) internal pure {
              require(_required <= _available, "not enough gold");
          }
      
          function _safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
              return b > a ? 0 : a.sub(b);
          }
      
          // MARKETPLACE
      
          function _transferGold(address _to, uint256 _value) internal {
              goldTokens.remoteTransfer(_to, _value);
          }
      
          // EGG
      
          function buyEgg(
              address _sender,
              uint256 _value,
              uint256 _id,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyController returns (address seller, uint256 price, bool success) {
              seller = eggMarketplace.sellerOf(_id);
              _compareBuyerAndSeller(_sender, seller);
      
              if (eggStorage.isApprovedOrOwner(this, _id) && _isEggOwner(seller, _id)) {
                  uint256 _balance = goldTokens.balanceOf(_sender);
                  price = eggMarketplace.buyToken(_id, _isGold ? _balance : _value, _expectedPrice, _isGold);
                  eggStorage.transferFrom(seller, _sender, _id);
                  if (_isGold) {
                      _transferGold(seller, price);
                  }
                  success = true;
              } else {
                  eggMarketplace.removeFromAuction(_id);
                  success = false;
              }
          }
      
          function sellEgg(
              address _sender,
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyController {
              _checkEggOwner(_id, _sender);
              require(!core.isEggInNest(_id), "egg is in nest");
              eggStorage.remoteApprove(this, _id);
              eggMarketplace.sellToken(_id, _sender, _maxPrice, _minPrice, _period, _isGold);
          }
      
          function removeEggFromSale(
              address _sender,
              uint256 _id
          ) external onlyController {
              _checkEggOwner(_id, _sender);
              eggMarketplace.removeFromAuction(_id);
          }
      
          // DRAGON
      
          function buyDragon(
              address _sender,
              uint256 _value,
              uint256 _id,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyController returns (address seller, uint256 price, bool success) {
              seller = dragonMarketplace.sellerOf(_id);
              _compareBuyerAndSeller(_sender, seller);
      
              if (dragonStorage.isApprovedOrOwner(this, _id) && _isDragonOwner(seller, _id)) {
                  uint256 _balance = goldTokens.balanceOf(_sender);
                  price = dragonMarketplace.buyToken(_id, _isGold ? _balance : _value, _expectedPrice, _isGold);
                  dragonStorage.transferFrom(seller, _sender, _id);
                  if (_isGold) {
                      _transferGold(seller, price);
                  }
                  success = true;
              } else {
                  dragonMarketplace.removeFromAuction(_id);
                  success = false;
              }
          }
      
          function sellDragon(
              address _sender,
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyController {
              _checkDragonOwner(_id, _sender);
              _checkTheDragonIsNotInGladiatorBattle(_id);
              require(breedingMarketplace.sellerOf(_id) == address(0), "dragon is on breeding sale");
              dragonStorage.remoteApprove(this, _id);
      
              dragonMarketplace.sellToken(_id, _sender, _maxPrice, _minPrice, _period, _isGold);
          }
      
          function removeDragonFromSale(
              address _sender,
              uint256 _id
          ) external onlyController {
              _checkDragonOwner(_id, _sender);
              dragonMarketplace.removeFromAuction(_id);
          }
      
          // BREEDING
      
          function buyBreeding(
              address _sender,
              uint256 _value,
              uint256 _momId,
              uint256 _dadId,
              uint256 _expectedPrice,
              bool _isGold
          ) external onlyController returns (uint256 eggId, address seller, uint256 price, bool success) {
              _checkIfBreedingIsAllowed(_momId);
              require(_momId != _dadId, "the same dragon");
              _checkDragonOwner(_momId, _sender);
              seller = breedingMarketplace.sellerOf(_dadId);
              _compareBuyerAndSeller(_sender, seller);
      
              if (getter.isDragonBreedingAllowed(_dadId) && _isDragonOwner(seller, _dadId)) {
                  uint256 _balance = goldTokens.balanceOf(_sender);
                  price = breedingMarketplace.buyToken(_dadId, _isGold ? _balance : _value, _expectedPrice, _isGold);
                  eggId = core.breed(_sender, _momId, _dadId);
                  if (_isGold) {
                      _transferGold(seller, price);
                  }
                  success = true;
              } else {
                  breedingMarketplace.removeFromAuction(_dadId);
                  success = false;
              }
          }
      
          function sellBreeding(
              address _sender,
              uint256 _id,
              uint256 _maxPrice,
              uint256 _minPrice,
              uint16 _period,
              bool _isGold
          ) external onlyController {
              _checkIfBreedingIsAllowed(_id);
              _checkDragonOwner(_id, _sender);
              _checkTheDragonIsNotInGladiatorBattle(_id);
              require(dragonMarketplace.sellerOf(_id) == address(0), "dragon is on sale");
              breedingMarketplace.sellToken(_id, _sender, _maxPrice, _minPrice, _period, _isGold);
          }
      
          function removeBreedingFromSale(
              address _sender,
              uint256 _id
          ) external onlyController {
              _checkDragonOwner(_id, _sender);
              breedingMarketplace.removeFromAuction(_id);
          }
      
          // SKILL
      
          function buySkill(
              address _sender,
              uint256 _id,
              uint256 _target,
              uint256 _expectedPrice,
              uint32 _expectedEffect
          ) external onlyController returns (address seller, uint256 price, bool success) {
              if (dragonStorage.exists(_id)) {
                  price = skillMarketplace.getAuction(_id);
                  seller = dragonStorage.ownerOf(_id);
                  _compareBuyerAndSeller(_sender, seller);
                  _checkTheDragonIsNotInGladiatorBattle(_id);
                  _checkTheDragonIsNotInGladiatorBattle(_target);
      
                  require(price <= _expectedPrice, "wrong price");
                  uint256 _balance = goldTokens.balanceOf(_sender);
                  _checkEnoughGold(price, _balance);
      
                  ( , , uint32 _effect) = getter.getDragonSpecialPeacefulSkill(_id);
                  require(_effect >= _expectedEffect, "effect decreased");
      
                  core.useDragonSpecialPeacefulSkill(seller, _id, _target);
      
                  _transferGold(seller, price);
                  success = true;
              } else {
                  skillMarketplace.removeFromAuction(_id);
                  success = false;
              }
          }
      
          function sellSkill(
              address _sender,
              uint256 _id,
              uint256 _price
          ) external onlyController {
              _checkDragonOwner(_id, _sender);
              _checkTheDragonIsNotInGladiatorBattle(_id);
              (uint8 _skillClass, , ) = getter.getDragonSpecialPeacefulSkill(_id);
              require(_skillClass > 0, "special peaceful skill is not yet set");
      
              skillMarketplace.sellToken(_id, _price);
          }
      
          function removeSkillFromSale(
              address _sender,
              uint256 _id
          ) external onlyController {
              _checkDragonOwner(_id, _sender);
              skillMarketplace.removeFromAuction(_id);
          }
      
          // UPDATE CONTRACT
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              super.setInternalDependencies(_newDependencies);
      
              core = Core(_newDependencies[0]);
              dragonStorage = DragonStorage(_newDependencies[1]);
              eggStorage = EggStorage(_newDependencies[2]);
              dragonMarketplace = DragonMarketplace(_newDependencies[3]);
              breedingMarketplace = BreedingMarketplace(_newDependencies[4]);
              eggMarketplace = EggMarketplace(_newDependencies[5]);
              goldMarketplace = GoldMarketplace(_newDependencies[6]);
              skillMarketplace = SkillMarketplace(_newDependencies[7]);
              goldTokens = Gold(_newDependencies[8]);
              getter = Getter(_newDependencies[9]);
          }
      }

      File 6 of 6: EggMarketplace
      pragma solidity 0.4.25;
      
      library SafeMath256 {
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              assert(c / a == b);
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return a / b;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              assert(b <= a);
              return a - b;
          }
      
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              assert(c >= a);
              return c;
          }
      
          function pow(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) return 0;
              if (b == 0) return 1;
      
              uint256 c = a ** b;
              assert(c / (a ** (b - 1)) == a);
              return c;
          }
      }
      
      contract Ownable {
          address public owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          function _validateAddress(address _addr) internal pure {
              require(_addr != address(0), "invalid address");
          }
      
          constructor() public {
              owner = msg.sender;
          }
      
          modifier onlyOwner() {
              require(msg.sender == owner, "not a contract owner");
              _;
          }
      
          function transferOwnership(address newOwner) public onlyOwner {
              _validateAddress(newOwner);
              emit OwnershipTransferred(owner, newOwner);
              owner = newOwner;
          }
      
      }
      
      contract Controllable is Ownable {
          mapping(address => bool) controllers;
      
          modifier onlyController {
              require(_isController(msg.sender), "no controller rights");
              _;
          }
      
          function _isController(address _controller) internal view returns (bool) {
              return controllers[_controller];
          }
      
          function _setControllers(address[] _controllers) internal {
              for (uint256 i = 0; i < _controllers.length; i++) {
                  _validateAddress(_controllers[i]);
                  controllers[_controllers[i]] = true;
              }
          }
      }
      
      contract Upgradable is Controllable {
          address[] internalDependencies;
          address[] externalDependencies;
      
          function getInternalDependencies() public view returns(address[]) {
              return internalDependencies;
          }
      
          function getExternalDependencies() public view returns(address[]) {
              return externalDependencies;
          }
      
          function setInternalDependencies(address[] _newDependencies) public onlyOwner {
              for (uint256 i = 0; i < _newDependencies.length; i++) {
                  _validateAddress(_newDependencies[i]);
              }
              internalDependencies = _newDependencies;
          }
      
          function setExternalDependencies(address[] _newDependencies) public onlyOwner {
              externalDependencies = _newDependencies;
              _setControllers(_newDependencies);
          }
      }
      
      
      
      
      //////////////CONTRACT//////////////
      
      
      
      
      contract Marketplace is Upgradable {
          using SafeMath256 for uint256;
      
          struct Auction {
              address seller;
              uint256 startPrice;
              uint256 endPrice;
              uint16 period; // in hours
              uint256 created;
              bool isGold; // gold or ether
          }
      
          uint256 constant MULTIPLIER = 1000000; // for more accurate calculations
          uint16 constant MAX_PERIOD = 8760; // 8760 hours = 1 year
      
          uint8 constant FLAT_TYPE = 0;
          uint8 constant INCREASING_TYPE = 1;
          uint8 constant DUTCH_TYPE = 2;
      
          mapping (address => uint256[]) internal ownedTokens;
          mapping (uint256 => uint256) internal ownedTokensIndex;
          mapping (uint256 => uint256) allTokensIndex;
          mapping (uint256 => Auction) tokenToAuction;
      
          uint256[] allTokens;
      
          constructor() public {}
      
          function sellToken(
              uint256 _tokenId,
              address _seller,
              uint256 _startPrice,
              uint256 _endPrice,
              uint16 _period,
              bool _isGold
          ) external onlyController {
              Auction memory _auction;
      
              require(_startPrice > 0 && _endPrice > 0, "price must be more than 0");
              if (_startPrice != _endPrice) {
                  require(_period > 0 && _period <= MAX_PERIOD, "wrong period value");
              }
              _auction = Auction(_seller, _startPrice, _endPrice, _period, now, _isGold);
      
              // if auction doesn't exist
              if (tokenToAuction[_tokenId].seller == address(0)) {
                  uint256 length = ownedTokens[_seller].length;
                  ownedTokens[_seller].push(_tokenId);
                  ownedTokensIndex[_tokenId] = length;
      
                  allTokensIndex[_tokenId] = allTokens.length;
                  allTokens.push(_tokenId);
              }
              tokenToAuction[_tokenId] = _auction;
          }
      
          function removeFromAuction(uint256 _tokenId) external onlyController {
              address _seller = tokenToAuction[_tokenId].seller;
              require(_seller != address(0), "token is not on sale");
              _remove(_seller, _tokenId);
          }
      
          function buyToken(
              uint256 _tokenId,
              uint256 _value,
              uint256 _expectedPrice,
              bool _expectedIsGold
          ) external onlyController returns (uint256 price) {
              Auction memory _auction = tokenToAuction[_tokenId];
      
              require(_auction.seller != address(0), "invalid address");
              require(_auction.isGold == _expectedIsGold, "wrong currency");
              price = _getCurrentPrice(_tokenId);
              require(price <= _expectedPrice, "wrong price");
              require(price <= _value, "not enough ether/gold");
      
              _remove(_auction.seller, _tokenId);
          }
      
          function _remove(address _from, uint256 _tokenId) internal {
              require(allTokens.length > 0, "no auctions");
      
              delete tokenToAuction[_tokenId];
      
              _removeFrom(_from, _tokenId);
      
              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;
          }
      
          function _removeFrom(address _from, uint256 _tokenId) internal {
              require(ownedTokens[_from].length > 0, "no seller auctions");
      
              uint256 tokenIndex = ownedTokensIndex[_tokenId];
              uint256 lastTokenIndex = ownedTokens[_from].length.sub(1);
              uint256 lastToken = ownedTokens[_from][lastTokenIndex];
      
              ownedTokens[_from][tokenIndex] = lastToken;
              ownedTokens[_from][lastTokenIndex] = 0;
      
              ownedTokens[_from].length--;
              ownedTokensIndex[_tokenId] = 0;
              ownedTokensIndex[lastToken] = tokenIndex;
          }
      
          function _getCurrentPrice(uint256 _id) internal view returns (uint256) {
              Auction memory _auction = tokenToAuction[_id];
              if (_auction.startPrice == _auction.endPrice) {
                  return _auction.startPrice;
              }
              return _calculateCurrentPrice(
                  _auction.startPrice,
                  _auction.endPrice,
                  _auction.period,
                  _auction.created
              );
          }
      
          function _calculateCurrentPrice(
              uint256 _startPrice,
              uint256 _endPrice,
              uint16 _period,
              uint256 _created
          ) internal view returns (uint256) {
              bool isIncreasingType = _startPrice < _endPrice;
              uint256 _fullPeriod = uint256(1 hours).mul(_period); // price changing period
              uint256 _interval = isIncreasingType ? _endPrice.sub(_startPrice) : _startPrice.sub(_endPrice);
              uint256 _pastTime = now.sub(_created);
              if (_pastTime >= _fullPeriod) return _endPrice;
              // how much is _pastTime in percents to period
              uint256 _percent = MULTIPLIER.sub(_fullPeriod.sub(_pastTime).mul(MULTIPLIER).div(_fullPeriod));
              uint256 _diff = _interval.mul(_percent).div(MULTIPLIER);
              return isIncreasingType ? _startPrice.add(_diff) : _startPrice.sub(_diff);
          }
      
          // GETTERS
      
          function sellerOf(uint256 _id) external view returns (address) {
              return tokenToAuction[_id].seller;
          }
      
          function getAuction(uint256 _id) external view returns (
              address, uint256, uint256, uint256, uint16, uint256, bool
          ) {
              Auction memory _auction = tokenToAuction[_id];
              return (
                  _auction.seller,
                  _getCurrentPrice(_id),
                  _auction.startPrice,
                  _auction.endPrice,
                  _auction.period,
                  _auction.created,
                  _auction.isGold
              );
          }
      
          function tokensOfOwner(address _owner) external view returns (uint256[]) {
              return ownedTokens[_owner];
          }
      
          function getAllTokens() external view returns (uint256[]) {
              return allTokens;
          }
      
          function totalSupply() public view returns (uint256) {
              return allTokens.length;
          }
      }
      
      
      contract EggMarketplace is Marketplace {}