ETH Price: $3,770.19 (-3.00%)

Transaction Decoder

Block:
22030300 at Mar-12-2025 10:50:35 AM +UTC
Transaction Fee:
0.000138971449719296 ETH $0.52
Gas Used:
225,058 Gas / 0.617491712 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
(beaverbuild)
9.147879389607717565 Eth9.147892315656632023 Eth0.000012926048914458
0xABC1c404...81D18Eb3E
(Etheremon: Data)
0xe4eAb999...dfbaA230f
0.000159388195685708 Eth
Nonce: 115
0.000020416745966412 Eth
Nonce: 116
0.000138971449719296

Execution Trace

EtheremonMonsterToken.safeTransferFrom( _from=0xe4eAb9999bE8D90892951B16242C2DCdfbaA230f, _to=0xC76eC158652a6A1fA3232374137df96c23114A95, _tokenId=52399 )
  • EtheremonData.getMonsterObj( _objId=52399 ) => ( objId=52399, classId=31, trainer=0xe4eAb9999bE8D90892951B16242C2DCdfbaA230f, exp=1, createIndex=292, lastClaimIndex=292, createTime=1555311037 )
  • EtheremonRankBattle.isOnBattle( _objId=52399 ) => ( False )
    • EtheremonData.getMonsterObj( _objId=52399 ) => ( objId=52399, classId=31, trainer=0xe4eAb9999bE8D90892951B16242C2DCdfbaA230f, exp=1, createIndex=292, lastClaimIndex=292, createTime=1555311037 )
    • EtheremonRankData.isOnBattle( _trainer=0xe4eAb9999bE8D90892951B16242C2DCdfbaA230f, _objId=52399 ) => ( False )
    • EtheremonTradingVerifier.isOnTrading( _objId=52399 ) => ( False )
      • EtheremonTradeData.isOnTrade( _objId=52399 ) => ( False )
      • EtheremonData.removeMonsterIdMapping( _trainer=0xe4eAb9999bE8D90892951B16242C2DCdfbaA230f, _monsterId=52399 )
      • EtheremonData.addMonsterIdMapping( _trainer=0xC76eC158652a6A1fA3232374137df96c23114A95, _monsterId=52399 )
        File 1 of 6: EtheremonMonsterToken
        pragma solidity ^0.4.24;
        
        /**
         * @title SafeMath
         * @dev Math operations with safety checks that throw on error
         */
        library SafeMath {
        
          /**
          * @dev Multiplies two numbers, throws on overflow.
          */
          function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
            if (a == 0) {
              return 0;
            }
            c = a * b;
            assert(c / a == b);
            return c;
          }
        
          /**
          * @dev Integer division of two numbers, truncating the quotient.
          */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            // assert(b > 0); // Solidity automatically throws when dividing by 0
            // uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return a / b;
          }
        
          /**
          * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
          */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            assert(b <= a);
            return a - b;
          }
        
          /**
          * @dev Adds two numbers, throws on overflow.
          */
          function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
            c = a + b;
            assert(c >= a);
            return c;
          }
        }
        
        /**
         * Utility library of inline functions on addresses
         */
        library AddressUtils {
        
          /**
           * Returns whether the target address is a contract
           * @dev This function will return false if invoked during the constructor of a contract,
           *  as the code is not actually created until after the constructor finishes.
           * @param addr address to check
           * @return whether the target address is a contract
           */
          function isContract(address addr) internal view returns (bool) {
            uint256 size;
            // XXX Currently there is no better way to check if there is a contract in an address
            // than to check the size of the code at that address.
            // See https://ethereum.stackexchange.com/a/14016/36603
            // for more details about how this works.
            // TODO Check this again before the Serenity release, because all addresses will be
            // contracts then.
            // solium-disable-next-line security/no-inline-assembly
            assembly { size := extcodesize(addr) }
            return size > 0;
          }
        
        }
        
        interface ERC165 {
            function supportsInterface(bytes4 _interfaceID) external view returns (bool);
        }
        
        contract SupportsInterface is ERC165 {
            
            mapping(bytes4 => bool) internal supportedInterfaces;
        
            constructor() public {
                supportedInterfaces[0x01ffc9a7] = true; // ERC165
            }
        
            function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
                return supportedInterfaces[_interfaceID];
            }
        }
        
        interface ERC721 {
            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) external view returns (uint256);
            function ownerOf(uint256 _tokenId) external view returns (address);
            function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external;
            function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;
            
            function transferFrom(address _from, address _to, uint256 _tokenId) external;
            function transfer(address _to, uint256 _tokenId) external;
            function approve(address _approved, uint256 _tokenId) external;
            function setApprovalForAll(address _operator, bool _approved) external;
            
            function getApproved(uint256 _tokenId) external view returns (address);
            function isApprovedForAll(address _owner, address _operator) external view returns (bool);
        }
        
        interface ERC721Enumerable {
            function totalSupply() external view returns (uint256);
            function tokenByIndex(uint256 _index) external view returns (uint256);
            function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
        }
        
        interface ERC721Metadata {
            function name() external view returns (string _name);
            function symbol() external view returns (string _symbol);
            function tokenURI(uint256 _tokenId) external view returns (string);
        }
        
        interface ERC721TokenReceiver {
          function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
        }
        
        contract BasicAccessControl {
            address public owner;
            // address[] public moderators;
            uint16 public totalModerators = 0;
            mapping (address => bool) public moderators;
            bool public isMaintaining = false;
        
            constructor() public {
                owner = msg.sender;
            }
        
            modifier onlyOwner {
                require(msg.sender == owner);
                _;
            }
        
            modifier onlyModerators() {
                require(msg.sender == owner || moderators[msg.sender] == true);
                _;
            }
        
            modifier isActive {
                require(!isMaintaining);
                _;
            }
        
            function ChangeOwner(address _newOwner) onlyOwner public {
                if (_newOwner != address(0)) {
                    owner = _newOwner;
                }
            }
        
        
            function AddModerator(address _newModerator) onlyOwner public {
                if (moderators[_newModerator] == false) {
                    moderators[_newModerator] = true;
                    totalModerators += 1;
                }
            }
            
            function RemoveModerator(address _oldModerator) onlyOwner public {
                if (moderators[_oldModerator] == true) {
                    moderators[_oldModerator] = false;
                    totalModerators -= 1;
                }
            }
        
            function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
                isMaintaining = _isMaintaining;
            }
        }
        
        contract EtheremonEnum {
        
            enum ResultCode {
                SUCCESS,
                ERROR_CLASS_NOT_FOUND,
                ERROR_LOW_BALANCE,
                ERROR_SEND_FAIL,
                ERROR_NOT_TRAINER,
                ERROR_NOT_ENOUGH_MONEY,
                ERROR_INVALID_AMOUNT
            }
            
            enum ArrayType {
                CLASS_TYPE,
                STAT_STEP,
                STAT_START,
                STAT_BASE,
                OBJ_SKILL
            }
            
            enum PropertyType {
                ANCESTOR,
                XFACTOR
            }
        }
        
        contract EtheremonDataBase {
            
            uint64 public totalMonster;
            uint32 public totalClass;
            
            // write
            function withdrawEther(address _sendTo, uint _amount) external returns(EtheremonEnum.ResultCode);
            function addElementToArrayType(EtheremonEnum.ArrayType _type, uint64 _id, uint8 _value) external returns(uint);
            function updateIndexOfArrayType(EtheremonEnum.ArrayType _type, uint64 _id, uint _index, uint8 _value) external returns(uint);
            function setMonsterClass(uint32 _classId, uint256 _price, uint256 _returnPrice, bool _catchable) external returns(uint32);
            function addMonsterObj(uint32 _classId, address _trainer, string _name) external returns(uint64);
            function setMonsterObj(uint64 _objId, string _name, uint32 _exp, uint32 _createIndex, uint32 _lastClaimIndex) external;
            function increaseMonsterExp(uint64 _objId, uint32 amount) external;
            function decreaseMonsterExp(uint64 _objId, uint32 amount) external;
            function removeMonsterIdMapping(address _trainer, uint64 _monsterId) external;
            function addMonsterIdMapping(address _trainer, uint64 _monsterId) external;
            function clearMonsterReturnBalance(uint64 _monsterId) external returns(uint256 amount);
            function collectAllReturnBalance(address _trainer) external returns(uint256 amount);
            function transferMonster(address _from, address _to, uint64 _monsterId) external returns(EtheremonEnum.ResultCode);
            function addExtraBalance(address _trainer, uint256 _amount) external returns(uint256);
            function deductExtraBalance(address _trainer, uint256 _amount) external returns(uint256);
            function setExtraBalance(address _trainer, uint256 _amount) external;
            
            // read
            function getSizeArrayType(EtheremonEnum.ArrayType _type, uint64 _id) constant external returns(uint);
            function getElementInArrayType(EtheremonEnum.ArrayType _type, uint64 _id, uint _index) constant external returns(uint8);
            function getMonsterClass(uint32 _classId) constant external returns(uint32 classId, uint256 price, uint256 returnPrice, uint32 total, bool catchable);
            function getMonsterObj(uint64 _objId) constant external returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime);
            function getMonsterName(uint64 _objId) constant external returns(string name);
            function getExtraBalance(address _trainer) constant external returns(uint256);
            function getMonsterDexSize(address _trainer) constant external returns(uint);
            function getMonsterObjId(address _trainer, uint index) constant external returns(uint64);
            function getExpectedBalance(address _trainer) constant external returns(uint256);
            function getMonsterReturn(uint64 _objId) constant external returns(uint256 current, uint256 total);
        }
        
        interface EtheremonBattle {
            function isOnBattle(uint64 _objId) constant external returns(bool);
        }
        
        interface EtheremonTradeInterface {
            function isOnTrading(uint64 _objId) constant external returns(bool);
        }
        
        
        contract EtheremonMonsterTokenBasic is ERC721, SupportsInterface, BasicAccessControl {
        
            using SafeMath for uint256;
            using AddressUtils for address;
            
            struct MonsterClassAcc {
                uint32 classId;
                uint256 price;
                uint256 returnPrice;
                uint32 total;
                bool catchable;
            }
        
            struct MonsterObjAcc {
                uint64 monsterId;
                uint32 classId;
                address trainer;
                string name;
                uint32 exp;
                uint32 createIndex;
                uint32 lastClaimIndex;
                uint createTime;
            }
        
            // data contract
            address public dataContract;
            address public battleContract;
            address public tradeContract;
            
            // Mapping from NFT ID to approved address.
            mapping (uint256 => address) internal idToApprovals;
            
            // Mapping from owner address to mapping of operator addresses.
            mapping (address => mapping (address => bool)) internal ownerToOperators;
            
            /**
            * @dev Magic value of a smart contract that can recieve NFT.
            * Equal to: bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")).
            */
            bytes4 constant MAGIC_ON_ERC721_RECEIVED = 0x150b7a02;
        
            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);
            
            // internal function
            function _canOperate(address _tokenOwner) constant internal {
                require(_tokenOwner == msg.sender || ownerToOperators[_tokenOwner][msg.sender]);
            }
            
            function _canTransfer(uint256 _tokenId, address _tokenOwner) constant internal {
                EtheremonBattle battle = EtheremonBattle(battleContract);
                EtheremonTradeInterface trade = EtheremonTradeInterface(tradeContract);
                require(!battle.isOnBattle(uint64(_tokenId)) && !trade.isOnTrading(uint64(_tokenId)));
                require(_tokenOwner != address(0));
                require(_tokenOwner == msg.sender || idToApprovals[_tokenId] == msg.sender || ownerToOperators[_tokenOwner][msg.sender]);
            }
            
            function setOperationContracts(address _dataContract, address _battleContract, address _tradeContract) onlyModerators external {
                dataContract = _dataContract;
                battleContract = _battleContract;
                tradeContract = _tradeContract;
            }
            
            // public function
        
            constructor() public {
                supportedInterfaces[0x80ac58cd] = true; // ERC721
            }
        
            function isApprovable(address _owner, uint256 _tokenId) public constant returns(bool) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                if (obj.monsterId != uint64(_tokenId))
                    return false;
                if (obj.trainer != _owner)
                    return false;
                // check battle & trade contract 
                EtheremonBattle battle = EtheremonBattle(battleContract);
                EtheremonTradeInterface trade = EtheremonTradeInterface(tradeContract);
                return (!battle.isOnBattle(obj.monsterId) && !trade.isOnTrading(obj.monsterId));
            }
        
            function balanceOf(address _owner) external view returns (uint256) {
                require(_owner != address(0));
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                return data.getMonsterDexSize(_owner);
            }
        
            function ownerOf(uint256 _tokenId) external view returns (address _owner) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, _owner, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(_owner != address(0));
            }
        
        
            function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external {
                _safeTransferFrom(_from, _to, _tokenId, _data);
            }
        
            function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {
                _safeTransferFrom(_from, _to, _tokenId, "");
            }
        
            function transferFrom(address _from, address _to, uint256 _tokenId) external {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                _canTransfer(_tokenId, obj.trainer);
                
                require(obj.trainer == _from);
                require(_to != address(0));
                _transfer(obj.trainer, _to, _tokenId);
            }
        
            function transfer(address _to, uint256 _tokenId) external {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                _canTransfer(_tokenId, obj.trainer);
                
                require(obj.trainer == msg.sender);
                require(_to != address(0));
                _transfer(obj.trainer, _to, _tokenId);
            }
        
            function approve(address _approved, uint256 _tokenId) external {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                _canOperate(obj.trainer);
                EtheremonBattle battle = EtheremonBattle(battleContract);
                EtheremonTradeInterface trade = EtheremonTradeInterface(tradeContract);
                if(battle.isOnBattle(obj.monsterId) || trade.isOnTrading(obj.monsterId))
                    revert();
                
                require(_approved != obj.trainer);
        
                idToApprovals[_tokenId] = _approved;
                emit Approval(obj.trainer, _approved, _tokenId);
            }
        
            function setApprovalForAll(address _operator, bool _approved) external {
                require(_operator != address(0));
                ownerToOperators[msg.sender][_operator] = _approved;
                emit ApprovalForAll(msg.sender, _operator, _approved);
            }
        
            function getApproved(uint256 _tokenId) public view returns (address) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                return idToApprovals[_tokenId];
            }
        
            function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
                require(_owner != address(0));
                require(_operator != address(0));
                return ownerToOperators[_owner][_operator];
            }
        
            function _safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) internal {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                _canTransfer(_tokenId, obj.trainer);
                
                require(obj.trainer == _from);
                require(_to != address(0));
        
                _transfer(obj.trainer, _to, _tokenId);
        
                if (_to.isContract()) {
                    bytes4 retval = ERC721TokenReceiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data);
                    require(retval == MAGIC_ON_ERC721_RECEIVED);
                }
            }
        
            function _transfer(address _from, address _to, uint256 _tokenId) private {
                _clearApproval(_tokenId);
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                data.removeMonsterIdMapping(_from, uint64(_tokenId));
                data.addMonsterIdMapping(_to, uint64(_tokenId));
                emit Transfer(_from, _to, _tokenId);
            }
        
        
            function _burn(uint256 _tokenId) internal { 
                _clearApproval(_tokenId);
                
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(uint64(_tokenId));
                require(obj.trainer != address(0));
                
                EtheremonBattle battle = EtheremonBattle(battleContract);
                EtheremonTradeInterface trade = EtheremonTradeInterface(tradeContract);
                if(battle.isOnBattle(obj.monsterId) || trade.isOnTrading(obj.monsterId))
                    revert();
                
                data.removeMonsterIdMapping(obj.trainer, uint64(_tokenId));
                
                emit Transfer(obj.trainer, address(0), _tokenId);
            }
        
            function _clearApproval(uint256 _tokenId) internal {
                if(idToApprovals[_tokenId] != 0) {
                    delete idToApprovals[_tokenId];
                }
            }
        
        }
        
        
        contract EtheremonMonsterEnumerable is EtheremonMonsterTokenBasic, ERC721Enumerable {
        
            constructor() public {
                supportedInterfaces[0x780e9d63] = true; // ERC721Enumerable
            }
        
            function totalSupply() external view returns (uint256) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                return data.totalMonster();
            }
        
            function tokenByIndex(uint256 _index) external view returns (uint256) {
                return _index;
            }
        
            function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256) {
                require(_owner != address(0));
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                return data.getMonsterObjId(_owner, _index);
            }
        
        }
        
        
        contract EtheremonMonsterStandard is EtheremonMonsterEnumerable, ERC721Metadata {
            string internal nftName;
            string internal nftSymbol;
            
            mapping (uint256 => string) internal idToUri;
            
            constructor(string _name, string _symbol) public {
                nftName = _name;
                nftSymbol = _symbol;
                supportedInterfaces[0x5b5e139f] = true; // ERC721Metadata
            }
            
            function _burn(uint256 _tokenId) internal {
                super._burn(_tokenId);
                if (bytes(idToUri[_tokenId]).length != 0) {
                    delete idToUri[_tokenId];
                }
            }
            
            function _setTokenUri(uint256 _tokenId, string _uri) internal {
                idToUri[_tokenId] = _uri;
            }
            
            function name() external view returns (string _name) {
                _name = nftName;
            }
            
            function symbol() external view returns (string _symbol) {
                _symbol = nftSymbol;
            }
            
            function tokenURI(uint256 _tokenId) external view returns (string) {
                return idToUri[_tokenId];
            }
        }
        
        contract EtheremonMonsterToken is EtheremonMonsterStandard("EtheremonMonster", "EMONA") {
            uint8 constant public STAT_COUNT = 6;
            uint8 constant public STAT_MAX = 32;
        
            uint seed = 0;
            
            mapping(uint8 => uint32) public levelExps;
            mapping(uint32 => bool) classWhitelist;
            mapping(address => bool) addressWhitelist;
            
            uint public gapFactor = 0.001 ether;
            uint16 public priceIncreasingRatio = 1000;
            
            function setPriceIncreasingRatio(uint16 _ratio) onlyModerators external {
                priceIncreasingRatio = _ratio;
            }
            
            function setFactor(uint _gapFactor) onlyModerators public {
                gapFactor = _gapFactor;
            }
            
            function genLevelExp() onlyModerators external {
                uint8 level = 1;
                uint32 requirement = 100;
                uint32 sum = requirement;
                while(level <= 100) {
                    levelExps[level] = sum;
                    level += 1;
                    requirement = (requirement * 11) / 10 + 5;
                    sum += requirement;
                }
            }
            
            function setClassWhitelist(uint32 _classId, bool _status) onlyModerators external {
                classWhitelist[_classId] = _status;
            }
        
            function setAddressWhitelist(address _smartcontract, bool _status) onlyModerators external {
                addressWhitelist[_smartcontract] = _status;
            }
        
            function setTokenURI(uint256 _tokenId, string _uri) onlyModerators external {
                _setTokenUri(_tokenId, _uri);
            }
            
            function withdrawEther(address _sendTo, uint _amount) onlyOwner public {
                if (_amount > address(this).balance) {
                    revert();
                }
                _sendTo.transfer(_amount);
            }
            
            function mintMonster(uint32 _classId, address _trainer, string _name) onlyModerators external returns(uint){
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                // add monster
                uint64 objId = data.addMonsterObj(_classId, _trainer, _name);
                uint8 value;
                seed = getRandom(_trainer, block.number-1, seed, objId);
                // generate base stat for the previous one
                for (uint i=0; i < STAT_COUNT; i+= 1) {
                    value = uint8(seed % STAT_MAX) + data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_START, uint64(_classId), i);
                    data.addElementToArrayType(EtheremonEnum.ArrayType.STAT_BASE, objId, value);
                }
                emit Transfer(address(0), _trainer, objId);
                return objId;
            }
            
            function burnMonster(uint64 _tokenId) onlyModerators external {
                _burn(_tokenId);
            }
            
            function clearApproval(uint _tokenId) onlyModerators external {
                _clearApproval(_tokenId);
            }
            
            function triggerTransferEvent(address _from, address _to, uint _tokenId) onlyModerators external {
                _clearApproval(_tokenId);
                emit Transfer(_from, _to, _tokenId);
            }
            
            // public api 
            function getRandom(address _player, uint _block, uint _seed, uint _count) view public returns(uint) {
                return uint(keccak256(abi.encodePacked(blockhash(_block), _player, _seed, _count)));
            }
            
            function getLevel(uint32 exp) view public returns (uint8) {
                uint8 minIndex = 1;
                uint8 maxIndex = 100;
                uint8 currentIndex;
             
                while (minIndex < maxIndex) {
                    currentIndex = (minIndex + maxIndex) / 2;
                    if (exp < levelExps[currentIndex])
                        maxIndex = currentIndex;
                    else
                        minIndex = currentIndex + 1;
                }
        
                return minIndex;
            }
            
            function getMonsterBaseStats(uint64 _monsterId) constant external returns(uint hp, uint pa, uint pd, uint sa, uint sd, uint speed) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                uint[6] memory stats;
                for(uint i=0; i < STAT_COUNT; i+=1) {
                    stats[i] = data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_BASE, _monsterId, i);
                }
                return (stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]);
            }
            
            function getMonsterCurrentStats(uint64 _monsterId) constant external returns(uint exp, uint level, uint hp, uint pa, uint pd, uint sa, uint sd, uint speed) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_monsterId);
                
                uint[6] memory stats;
                uint i = 0;
                level = getLevel(obj.exp);
                for(i=0; i < STAT_COUNT; i+=1) {
                    stats[i] = data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_BASE, _monsterId, i);
                }
                for(i=0; i < STAT_COUNT; i++) {
                    stats[i] += uint(data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_STEP, obj.classId, i)) * level * 3;
                }
                
                return (obj.exp, level, stats[0], stats[1], stats[2], stats[3], stats[4], stats[5]);
            }
            
            function getMonsterCP(uint64 _monsterId) constant external returns(uint cp) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_monsterId);
                
                uint[6] memory stats;
                uint i = 0;
                cp = getLevel(obj.exp);
                for(i=0; i < STAT_COUNT; i+=1) {
                    stats[i] = data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_BASE, _monsterId, i);
                }
                for(i=0; i < STAT_COUNT; i++) {
                    stats[i] += uint(data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_STEP, obj.classId, i)) * cp * 3;
                }
                
                cp = (stats[0] + stats[1] + stats[2] + stats[3] + stats[4] + stats[5]) / 6;
            }
            
            function getPrice(uint32 _classId) constant external returns(bool catchable, uint price) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterClassAcc memory class;
                (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId);
                
                price = class.price;
                if (class.total > 0)
                    price += class.price*(class.total-1)/priceIncreasingRatio;
                
                if (class.catchable == false) {
                    if (addressWhitelist[msg.sender] == true && classWhitelist[_classId] == true) {
                        return (true, price);
                    }
                }
                
                return (class.catchable, price);
            }
            
            function getMonsterClassBasic(uint32 _classId) constant external returns(uint256, uint256, uint256, bool) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterClassAcc memory class;
                (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId);
                return (class.price, class.returnPrice, class.total, class.catchable);
            }
            
            function renameMonster(uint64 _objId, string name) isActive external {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_objId);
                if (obj.monsterId != _objId || obj.trainer != msg.sender) {
                    revert();
                }
                data.setMonsterObj(_objId, name, obj.exp, obj.createIndex, obj.lastClaimIndex);
            }
            
            function catchMonster(address _player, uint32 _classId, string _name) isActive external payable returns(uint tokenId) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterClassAcc memory class;
                (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId);
                if (class.classId == 0) {
                    revert();
                }
                
                if (class.catchable == false) {
                    if (addressWhitelist[msg.sender] == false || classWhitelist[_classId] == false) {
                        revert();
                    }
                }
                
                uint price = class.price;
                if (class.total > 0)
                    price += class.price*(class.total-1)/priceIncreasingRatio;
                if (msg.value + gapFactor < price) {
                    revert();
                }
                
                // add new monster 
                uint64 objId = data.addMonsterObj(_classId, _player, _name);
                uint8 value;
                seed = getRandom(_player, block.number-1, seed, objId);
                // generate base stat for the previous one
                for (uint i=0; i < STAT_COUNT; i+= 1) {
                    value = uint8(seed % STAT_MAX) + data.getElementInArrayType(EtheremonEnum.ArrayType.STAT_START, uint64(_classId), i);
                    data.addElementToArrayType(EtheremonEnum.ArrayType.STAT_BASE, objId, value);
                }
                
                emit Transfer(address(0), _player, objId);
        
                return objId; 
            }
            
            
        }

        File 2 of 6: EtheremonData
        pragma solidity ^0.4.16;
        
        // copyright [email protected]
        
        contract SafeMath {
        
            /* function assert(bool assertion) internal { */
            /*   if (!assertion) { */
            /*     throw; */
            /*   } */
            /* }      // assert no longer needed once solidity is on 0.4.10 */
        
            function safeAdd(uint256 x, uint256 y) pure internal returns(uint256) {
              uint256 z = x + y;
              assert((z >= x) && (z >= y));
              return z;
            }
        
            function safeSubtract(uint256 x, uint256 y) pure internal returns(uint256) {
              assert(x >= y);
              uint256 z = x - y;
              return z;
            }
        
            function safeMult(uint256 x, uint256 y) pure internal returns(uint256) {
              uint256 z = x * y;
              assert((x == 0)||(z/x == y));
              return z;
            }
        
        }
        
        contract BasicAccessControl {
            address public owner;
            address[] public moderators;
        
            function BasicAccessControl() public {
                owner = msg.sender;
            }
        
            modifier onlyOwner {
                require(msg.sender == owner);
                _;
            }
        
            modifier onlyModerators() {
                if (msg.sender != owner) {
                    bool found = false;
                    for (uint index = 0; index < moderators.length; index++) {
                        if (moderators[index] == msg.sender) {
                            found = true;
                            break;
                        }
                    }
                    require(found);
                }
                _;
            }
        
            function ChangeOwner(address _newOwner) onlyOwner public {
                if (_newOwner != address(0)) {
                    owner = _newOwner;
                }
            }
        
            function Kill() onlyOwner public {
                selfdestruct(owner);
            }
        
            function AddModerator(address _newModerator) onlyOwner public {
                if (_newModerator != address(0)) {
                    for (uint index = 0; index < moderators.length; index++) {
                        if (moderators[index] == _newModerator) {
                            return;
                        }
                    }
                    moderators.push(_newModerator);
                }
            }
            
            function RemoveModerator(address _oldModerator) onlyOwner public {
                uint foundIndex = 0;
                for (; foundIndex < moderators.length; foundIndex++) {
                    if (moderators[foundIndex] == _oldModerator) {
                        break;
                    }
                }
                if (foundIndex < moderators.length) {
                    moderators[foundIndex] = moderators[moderators.length-1];
                    delete moderators[moderators.length-1];
                    moderators.length--;
                }
            }
        }
        
        
        contract EtheremonEnum {
        
            enum ResultCode {
                SUCCESS,
                ERROR_CLASS_NOT_FOUND,
                ERROR_LOW_BALANCE,
                ERROR_SEND_FAIL,
                ERROR_NOT_TRAINER,
                ERROR_NOT_ENOUGH_MONEY,
                ERROR_INVALID_AMOUNT
            }
            
            enum ArrayType {
                CLASS_TYPE,
                STAT_STEP,
                STAT_START,
                STAT_BASE,
                OBJ_SKILL
            }
        }
        
        contract EtheremonDataBase is EtheremonEnum, BasicAccessControl, SafeMath {
            
            uint64 public totalMonster;
            uint32 public totalClass;
            
            // write
            function addElementToArrayType(ArrayType _type, uint64 _id, uint8 _value) onlyModerators public returns(uint);
            function updateIndexOfArrayType(ArrayType _type, uint64 _id, uint _index, uint8 _value) onlyModerators public returns(uint);
            function setMonsterClass(uint32 _classId, uint256 _price, uint256 _returnPrice, bool _catchable) onlyModerators public returns(uint32);
            function addMonsterObj(uint32 _classId, address _trainer, string _name) onlyModerators public returns(uint64);
            function setMonsterObj(uint64 _objId, string _name, uint32 _exp, uint32 _createIndex, uint32 _lastClaimIndex) onlyModerators public;
            function increaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public;
            function decreaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public;
            function removeMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public;
            function addMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public;
            function clearMonsterReturnBalance(uint64 _monsterId) onlyModerators public returns(uint256 amount);
            function collectAllReturnBalance(address _trainer) onlyModerators public returns(uint256 amount);
            function transferMonster(address _from, address _to, uint64 _monsterId) onlyModerators public returns(ResultCode);
            function addExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256);
            function deductExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256);
            function setExtraBalance(address _trainer, uint256 _amount) onlyModerators public;
            
            // read
            function getSizeArrayType(ArrayType _type, uint64 _id) constant public returns(uint);
            function getElementInArrayType(ArrayType _type, uint64 _id, uint _index) constant public returns(uint8);
            function getMonsterClass(uint32 _classId) constant public returns(uint32 classId, uint256 price, uint256 returnPrice, uint32 total, bool catchable);
            function getMonsterObj(uint64 _objId) constant public returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime);
            function getMonsterName(uint64 _objId) constant public returns(string name);
            function getExtraBalance(address _trainer) constant public returns(uint256);
            function getMonsterDexSize(address _trainer) constant public returns(uint);
            function getMonsterObjId(address _trainer, uint index) constant public returns(uint64);
            function getExpectedBalance(address _trainer) constant public returns(uint256);
            function getMonsterReturn(uint64 _objId) constant public returns(uint256 current, uint256 total);
        }
        
        contract EtheremonData is EtheremonDataBase {
        
            struct MonsterClass {
                uint32 classId;
                uint8[] types;
                uint8[] statSteps;
                uint8[] statStarts;
                uint256 price;
                uint256 returnPrice;
                uint32 total;
                bool catchable;
            }
            
            struct MonsterObj {
                uint64 monsterId;
                uint32 classId;
                address trainer;
                string name;
                uint32 exp;
                uint8[] statBases;
                uint8[] skills;
                uint32 createIndex;
                uint32 lastClaimIndex;
                uint createTime;
            }
        
            mapping(uint32 => MonsterClass) public monsterClass;
            mapping(uint64 => MonsterObj) public monsterWorld;
            mapping(address => uint64[]) public trainerDex;
            mapping(address => uint256) public trainerExtraBalance;
            
            
            // write access
            function withdrawEther(address _sendTo, uint _amount) onlyOwner public returns(ResultCode) {
                if (_amount > this.balance) {
                    return ResultCode.ERROR_INVALID_AMOUNT;
                }
                
                _sendTo.transfer(_amount);
                return ResultCode.SUCCESS;
            }
            
            function addElementToArrayType(ArrayType _type, uint64 _id, uint8 _value) onlyModerators public returns(uint) {
                uint8[] storage array = monsterWorld[_id].statBases;
                if (_type == ArrayType.CLASS_TYPE) {
                    array = monsterClass[uint32(_id)].types;
                } else if (_type == ArrayType.STAT_STEP) {
                    array = monsterClass[uint32(_id)].statSteps;
                } else if (_type == ArrayType.STAT_START) {
                    array = monsterClass[uint32(_id)].statStarts;
                } else if (_type == ArrayType.OBJ_SKILL) {
                    array = monsterWorld[_id].skills;
                }
                array.push(_value);
                return array.length;
            }
            
            function updateIndexOfArrayType(ArrayType _type, uint64 _id, uint _index, uint8 _value) onlyModerators public returns(uint) {
                uint8[] storage array = monsterWorld[_id].statBases;
                if (_type == ArrayType.CLASS_TYPE) {
                    array = monsterClass[uint32(_id)].types;
                } else if (_type == ArrayType.STAT_STEP) {
                    array = monsterClass[uint32(_id)].statSteps;
                } else if (_type == ArrayType.STAT_START) {
                    array = monsterClass[uint32(_id)].statStarts;
                } else if (_type == ArrayType.OBJ_SKILL) {
                    array = monsterWorld[_id].skills;
                }
                if (_index < array.length) {
                    if (_value == 255) {
                        // consider as delete
                        for(uint i = _index; i < array.length - 1; i++) {
                            array[i] = array[i+1];
                        }
                        delete array[array.length-1];
                        array.length--;
                    } else {
                        array[_index] = _value;
                    }
                }
            }
            
            function setMonsterClass(uint32 _classId, uint256 _price, uint256 _returnPrice, bool _catchable) onlyModerators public returns(uint32) {
                MonsterClass storage class = monsterClass[_classId];
                if (class.classId == 0) {
                    totalClass += 1;
                }
                class.classId = _classId;
                class.price = _price;
                class.returnPrice = _returnPrice;
                class.catchable = _catchable;
                return totalClass;
            }
            
            function addMonsterObj(uint32 _classId, address _trainer, string _name) onlyModerators public returns(uint64) {
                MonsterClass storage class = monsterClass[_classId];
                if (class.classId == 0)
                    return 0;
                        
                // construct new monster
                totalMonster += 1;
                class.total += 1;
        
                MonsterObj storage obj = monsterWorld[totalMonster];
                obj.monsterId = totalMonster;
                obj.classId = _classId;
                obj.trainer = _trainer;
                obj.name = _name;
                obj.exp = 1;
                obj.createIndex = class.total;
                obj.lastClaimIndex = class.total;
                obj.createTime = now;
        
                // add to monsterdex
                addMonsterIdMapping(_trainer, obj.monsterId);
                return obj.monsterId;
            }
            
            function setMonsterObj(uint64 _objId, string _name, uint32 _exp, uint32 _createIndex, uint32 _lastClaimIndex) onlyModerators public {
                MonsterObj storage obj = monsterWorld[_objId];
                if (obj.monsterId == _objId) {
                    obj.name = _name;
                    obj.exp = _exp;
                    obj.createIndex = _createIndex;
                    obj.lastClaimIndex = _lastClaimIndex;
                }
            }
        
            function increaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public {
                MonsterObj storage obj = monsterWorld[_objId];
                if (obj.monsterId == _objId) {
                    obj.exp = uint32(safeAdd(obj.exp, amount));
                }
            }
        
            function decreaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public {
                MonsterObj storage obj = monsterWorld[_objId];
                if (obj.monsterId == _objId) {
                    obj.exp = uint32(safeSubtract(obj.exp, amount));
                }
            }
        
            function removeMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public {
                uint foundIndex = 0;
                uint64[] storage objIdList = trainerDex[_trainer];
                for (; foundIndex < objIdList.length; foundIndex++) {
                    if (objIdList[foundIndex] == _monsterId) {
                        break;
                    }
                }
                if (foundIndex < objIdList.length) {
                    objIdList[foundIndex] = objIdList[objIdList.length-1];
                    delete objIdList[objIdList.length-1];
                    objIdList.length--;
                    MonsterObj storage monster = monsterWorld[_monsterId];
                    monster.trainer = 0;
                }
            }
            
            function addMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public {
                if (_trainer != address(0) && _monsterId > 0) {
                    uint64[] storage objIdList = trainerDex[_trainer];
                    for (uint i = 0; i < objIdList.length; i++) {
                        if (objIdList[i] == _monsterId) {
                            return;
                        }
                    }
                    objIdList.push(_monsterId);
                    MonsterObj storage monster = monsterWorld[_monsterId];
                    monster.trainer = _trainer;
                }
            }
            
            function clearMonsterReturnBalance(uint64 _monsterId) onlyModerators public returns(uint256) {
                MonsterObj storage monster = monsterWorld[_monsterId];
                MonsterClass storage class = monsterClass[monster.classId];
                if (monster.monsterId == 0 || class.classId == 0)
                    return 0;
                uint256 amount = 0;
                uint32 gap = uint32(safeSubtract(class.total, monster.lastClaimIndex));
                if (gap > 0) {
                    monster.lastClaimIndex = class.total;
                    amount = safeMult(gap, class.returnPrice);
                    trainerExtraBalance[monster.trainer] = safeAdd(trainerExtraBalance[monster.trainer], amount);
                }
                return amount;
            }
            
            function collectAllReturnBalance(address _trainer) onlyModerators public returns(uint256 amount) {
                uint64[] storage objIdList = trainerDex[_trainer];
                for (uint i = 0; i < objIdList.length; i++) {
                    clearMonsterReturnBalance(objIdList[i]);
                }
                return trainerExtraBalance[_trainer];
            }
            
            function transferMonster(address _from, address _to, uint64 _monsterId) onlyModerators public returns(ResultCode) {
                MonsterObj storage monster = monsterWorld[_monsterId];
                if (monster.trainer != _from) {
                    return ResultCode.ERROR_NOT_TRAINER;
                }
                
                clearMonsterReturnBalance(_monsterId);
                
                removeMonsterIdMapping(_from, _monsterId);
                addMonsterIdMapping(_to, _monsterId);
                return ResultCode.SUCCESS;
            }
            
            function addExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256) {
                trainerExtraBalance[_trainer] = safeAdd(trainerExtraBalance[_trainer], _amount);
                return trainerExtraBalance[_trainer];
            }
            
            function deductExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256) {
                trainerExtraBalance[_trainer] = safeSubtract(trainerExtraBalance[_trainer], _amount);
                return trainerExtraBalance[_trainer];
            }
            
            function setExtraBalance(address _trainer, uint256 _amount) onlyModerators public {
                trainerExtraBalance[_trainer] = _amount;
            }
            
            
            // public
            function () payable public {
                addExtraBalance(msg.sender, msg.value);
            }
        
            // read access
            function getSizeArrayType(ArrayType _type, uint64 _id) constant public returns(uint) {
                uint8[] storage array = monsterWorld[_id].statBases;
                if (_type == ArrayType.CLASS_TYPE) {
                    array = monsterClass[uint32(_id)].types;
                } else if (_type == ArrayType.STAT_STEP) {
                    array = monsterClass[uint32(_id)].statSteps;
                } else if (_type == ArrayType.STAT_START) {
                    array = monsterClass[uint32(_id)].statStarts;
                } else if (_type == ArrayType.OBJ_SKILL) {
                    array = monsterWorld[_id].skills;
                }
                return array.length;
            }
            
            function getElementInArrayType(ArrayType _type, uint64 _id, uint _index) constant public returns(uint8) {
                uint8[] storage array = monsterWorld[_id].statBases;
                if (_type == ArrayType.CLASS_TYPE) {
                    array = monsterClass[uint32(_id)].types;
                } else if (_type == ArrayType.STAT_STEP) {
                    array = monsterClass[uint32(_id)].statSteps;
                } else if (_type == ArrayType.STAT_START) {
                    array = monsterClass[uint32(_id)].statStarts;
                } else if (_type == ArrayType.OBJ_SKILL) {
                    array = monsterWorld[_id].skills;
                }
                if (_index >= array.length)
                    return 0;
                return array[_index];
            }
            
            
            function getMonsterClass(uint32 _classId) constant public returns(uint32 classId, uint256 price, uint256 returnPrice, uint32 total, bool catchable) {
                MonsterClass storage class = monsterClass[_classId];
                classId = class.classId;
                price = class.price;
                returnPrice = class.returnPrice;
                total = class.total;
                catchable = class.catchable;
            }
            
            function getMonsterObj(uint64 _objId) constant public returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime) {
                MonsterObj storage monster = monsterWorld[_objId];
                objId = monster.monsterId;
                classId = monster.classId;
                trainer = monster.trainer;
                exp = monster.exp;
                createIndex = monster.createIndex;
                lastClaimIndex = monster.lastClaimIndex;
                createTime = monster.createTime;
            }
            
            function getMonsterName(uint64 _objId) constant public returns(string name) {
                return monsterWorld[_objId].name;
            }
        
            function getExtraBalance(address _trainer) constant public returns(uint256) {
                return trainerExtraBalance[_trainer];
            }
            
            function getMonsterDexSize(address _trainer) constant public returns(uint) {
                return trainerDex[_trainer].length;
            }
            
            function getMonsterObjId(address _trainer, uint index) constant public returns(uint64) {
                if (index >= trainerDex[_trainer].length)
                    return 0;
                return trainerDex[_trainer][index];
            }
            
            function getExpectedBalance(address _trainer) constant public returns(uint256) {
                uint64[] storage objIdList = trainerDex[_trainer];
                uint256 monsterBalance = 0;
                for (uint i = 0; i < objIdList.length; i++) {
                    MonsterObj memory monster = monsterWorld[objIdList[i]];
                    MonsterClass storage class = monsterClass[monster.classId];
                    uint32 gap = uint32(safeSubtract(class.total, monster.lastClaimIndex));
                    monsterBalance += safeMult(gap, class.returnPrice);
                }
                return monsterBalance;
            }
            
            function getMonsterReturn(uint64 _objId) constant public returns(uint256 current, uint256 total) {
                MonsterObj memory monster = monsterWorld[_objId];
                MonsterClass storage class = monsterClass[monster.classId];
                uint32 totalGap = uint32(safeSubtract(class.total, monster.createIndex));
                uint32 currentGap = uint32(safeSubtract(class.total, monster.lastClaimIndex));
                return (safeMult(currentGap, class.returnPrice), safeMult(totalGap, class.returnPrice));
            }
        
        }

        File 3 of 6: EtheremonRankBattle
        pragma solidity ^0.4.16;
        
        contract BasicAccessControl {
            address public owner;
            // address[] public moderators;
            uint16 public totalModerators = 0;
            mapping (address => bool) public moderators;
            bool public isMaintaining = false;
        
            function BasicAccessControl() public {
                owner = msg.sender;
            }
        
            modifier onlyOwner {
                require(msg.sender == owner);
                _;
            }
        
            modifier onlyModerators() {
                require(msg.sender == owner || moderators[msg.sender] == true);
                _;
            }
        
            modifier isActive {
                require(!isMaintaining);
                _;
            }
        
            function ChangeOwner(address _newOwner) onlyOwner public {
                if (_newOwner != address(0)) {
                    owner = _newOwner;
                }
            }
        
        
            function AddModerator(address _newModerator) onlyOwner public {
                if (moderators[_newModerator] == false) {
                    moderators[_newModerator] = true;
                    totalModerators += 1;
                }
            }
            
            function RemoveModerator(address _oldModerator) onlyOwner public {
                if (moderators[_oldModerator] == true) {
                    moderators[_oldModerator] = false;
                    totalModerators -= 1;
                }
            }
        
            function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
                isMaintaining = _isMaintaining;
            }
        }
        
        contract EtheremonEnum {
            enum ArrayType {
                CLASS_TYPE,
                STAT_STEP,
                STAT_START,
                STAT_BASE,
                OBJ_SKILL
            }
        }
        
        interface EtheremonTradeInterface {
            function isOnTrading(uint64 _objId) constant external returns(bool);
        }
        
        contract EtheremonDataBase is EtheremonEnum {
            uint64 public totalMonster;
        
            function getMonsterObj(uint64 _objId) constant public returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime);
            function getMonsterDexSize(address _trainer) constant public returns(uint);
            function getElementInArrayType(ArrayType _type, uint64 _id, uint _index) constant public returns(uint8);
            
            function addMonsterObj(uint32 _classId, address _trainer, string _name)  public returns(uint64);
            function addElementToArrayType(ArrayType _type, uint64 _id, uint8 _value) public returns(uint);
        }
        
        interface EtheremonRankData {
            function setPlayer(address _trainer, uint64 _a0, uint64 _a1, uint64 _a2, uint64 _s0, uint64 _s1, uint64 _s2) external returns(uint32 playerId);
            function isOnBattle(address _trainer, uint64 _objId) constant external returns(bool);
        }
        
        contract EtheremonRankBattle is BasicAccessControl, EtheremonEnum {
        
            struct MonsterObjAcc {
                uint64 monsterId;
                uint32 classId;
                address trainer;
                string name;
                uint32 exp;
                uint32 createIndex;
                uint32 lastClaimIndex;
                uint createTime;
            }
            
            // linked smart contract
            address public dataContract;
            address public tradeContract;
            address public rankDataContract;
            
            // modifier
            modifier requireDataContract {
                require(dataContract != address(0));
                _;
            }
            
            modifier requireTradeContract {
                require(tradeContract != address(0));
                _;
            }
        
            modifier requireRankDataContract {
                require(rankDataContract != address(0));
                _;
            }
        
            // event
            event EventUpdateCastle(address indexed trainer, uint32 playerId);
            
            function EtheremonRankBattle(address _dataContract, address _tradeContract, address _rankDataContract) public {
                dataContract = _dataContract;
                tradeContract = _tradeContract;
                rankDataContract = _rankDataContract;
            }
            
            function setContract(address _dataContract, address _tradeContract, address _rankDataContract) onlyModerators external {
                dataContract = _dataContract;
                tradeContract = _tradeContract;
                rankDataContract = _rankDataContract;
            }
        
            // public
            
            function getValidClassId(uint64 _objId, address _owner) constant public returns(uint32) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_objId);
                if (obj.trainer != _owner || obj.classId == 21) return 0;
                return obj.classId;
            }
            
            function hasValidParam(address _trainer, uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3) constant public returns(bool) {
                if (_a1 == 0 || _a2 == 0 || _a3 == 0)
                    return false;
                if (_a1 == _a2 || _a1 == _a3 || _a1 == _s1 || _a1 == _s2 || _a1 == _s3)
                    return false;
                if (_a2 == _a3 || _a2 == _s1 || _a2 == _s2 || _a2 == _s3)
                    return false;
                if (_a3 == _s1 || _a3 == _s2 || _a3 == _s3)
                    return false;
                if (_s1 > 0 && (_s1 == _s2 || _s1 == _s3))
                    return false;
                if (_s2 > 0 && (_s2 == _s3))
                    return false;
                
                uint32 classA1 = getValidClassId(_a1, _trainer);
                uint32 classA2 = getValidClassId(_a2, _trainer);
                uint32 classA3 = getValidClassId(_a3, _trainer);
                
                if (classA1 == 0 || classA2 == 0 || classA3 == 0)
                    return false;
                if (classA1 == classA2 || classA1 == classA3 || classA2 == classA3)
                    return false;
                if (_s1 > 0 && getValidClassId(_s1, _trainer) == 0)
                    return false;
                if (_s2 > 0 && getValidClassId(_s2, _trainer) == 0)
                    return false;
                if (_s3 > 0 && getValidClassId(_s3, _trainer) == 0)
                    return false;
                return true;
            }
            
            function setCastle(uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3) isActive requireDataContract 
                requireTradeContract requireRankDataContract external {
                
                if (!hasValidParam(msg.sender, _a1, _a2, _a3, _s1, _s2, _s3))
                    revert();
                
                EtheremonTradeInterface trade = EtheremonTradeInterface(tradeContract);
                if (trade.isOnTrading(_a1) || trade.isOnTrading(_a2) || trade.isOnTrading(_a3) || 
                    trade.isOnTrading(_s1) || trade.isOnTrading(_s2) || trade.isOnTrading(_s3))
                    revert();
        
                EtheremonRankData rank = EtheremonRankData(rankDataContract);
                uint32 playerId = rank.setPlayer(msg.sender, _a1, _a2, _a3, _s1, _s2, _s3);
                EventUpdateCastle(msg.sender, playerId);
            }
            
            function isOnBattle(uint64 _objId) constant external requireDataContract requireRankDataContract returns(bool) {
                EtheremonDataBase data = EtheremonDataBase(dataContract);
                MonsterObjAcc memory obj;
                (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_objId);
                if (obj.monsterId == 0)
                    return false;
                EtheremonRankData rank = EtheremonRankData(rankDataContract);
                return rank.isOnBattle(obj.trainer, _objId);
            }
        }

        File 4 of 6: EtheremonRankData
        pragma solidity ^0.4.16;
        
        // copyright [email protected]
        
        contract BasicAccessControl {
            address public owner;
            // address[] public moderators;
            uint16 public totalModerators = 0;
            mapping (address => bool) public moderators;
            bool public isMaintaining = true;
        
            function BasicAccessControl() public {
                owner = msg.sender;
            }
        
            modifier onlyOwner {
                require(msg.sender == owner);
                _;
            }
        
            modifier onlyModerators() {
                require(msg.sender == owner || moderators[msg.sender] == true);
                _;
            }
        
            modifier isActive {
                require(!isMaintaining);
                _;
            }
        
            function ChangeOwner(address _newOwner) onlyOwner public {
                if (_newOwner != address(0)) {
                    owner = _newOwner;
                }
            }
        
        
            function AddModerator(address _newModerator) onlyOwner public {
                if (moderators[_newModerator] == false) {
                    moderators[_newModerator] = true;
                    totalModerators += 1;
                }
            }
            
            function RemoveModerator(address _oldModerator) onlyOwner public {
                if (moderators[_oldModerator] == true) {
                    moderators[_oldModerator] = false;
                    totalModerators -= 1;
                }
            }
        
            function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
                isMaintaining = _isMaintaining;
            }
        }
        
        
        contract EtheremonRankData is BasicAccessControl {
        
            struct PlayerData {
                address trainer;
                uint32 point;
                uint32 energy;
                uint lastClaim;
                uint32 totalWin;
                uint32 totalLose;
                uint64[6] monsters;
            }
            
            mapping(uint32 => PlayerData) players;
            mapping(address => uint32) playerIds;
            
            uint32 public totalPlayer = 0;
            uint32 public startingPoint = 1200;
            
            // only moderators
            /*
            TO AVOID ANY BUGS, WE ALLOW MODERATORS TO HAVE PERMISSION TO ALL THESE FUNCTIONS AND UPDATE THEM IN EARLY BETA STAGE.
            AFTER THE SYSTEM IS STABLE, WE WILL REMOVE OWNER OF THIS SMART CONTRACT AND ONLY KEEP ONE MODERATOR WHICH IS ETHEREMON BATTLE CONTRACT.
            HENCE, THE DECENTRALIZED ATTRIBUTION IS GUARANTEED.
            */
            
            function updateConfig(uint32 _startingPoint) onlyModerators external {
                startingPoint = _startingPoint;
            }
            
            function setPlayer(address _trainer, uint64 _a0, uint64 _a1, uint64 _a2, uint64 _s0, uint64 _s1, uint64 _s2) onlyModerators external returns(uint32 playerId){
                require(_trainer != address(0));
                playerId = playerIds[_trainer];
                
                bool isNewPlayer = false;
                if (playerId == 0) {
                    totalPlayer += 1;
                    playerId = totalPlayer;
                    playerIds[_trainer] = playerId;
                    isNewPlayer = true;
                }
                
                PlayerData storage player = players[playerId];
                if (isNewPlayer)
                    player.point = startingPoint;
                player.trainer = _trainer;
                player.monsters[0] = _a0;
                player.monsters[1] = _a1;
                player.monsters[2] = _a2;
                player.monsters[3] = _s0;
                player.monsters[4] = _s1;
                player.monsters[5] = _s2;
            }
            
            function updatePlayerPoint(uint32 _playerId, uint32 _totalWin, uint32 _totalLose, uint32 _point) onlyModerators external {
                PlayerData storage player = players[_playerId];
                player.point = _point;
                player.totalWin = _totalWin;
                player.totalLose = _totalLose;
            }
            
            function updateEnergy(uint32 _playerId, uint32 _energy, uint _lastClaim) onlyModerators external {
                PlayerData storage player = players[_playerId];
                player.energy = _energy;
                player.lastClaim = _lastClaim;
            }
            
            // read access 
            function getPlayerData(uint32 _playerId) constant external returns(address trainer, uint32 totalWin, uint32 totalLose, uint32 point, 
                uint64 a0, uint64 a1, uint64 a2, uint64 s0, uint64 s1, uint64 s2, uint32 energy, uint lastClaim) {
                PlayerData memory player = players[_playerId];
                return (player.trainer, player.totalWin, player.totalLose, player.point, player.monsters[0], player.monsters[1], player.monsters[2], 
                    player.monsters[3], player.monsters[4], player.monsters[5], player.energy, player.lastClaim);
            }
            
            function getPlayerDataByAddress(address _trainer) constant external returns(uint32 playerId, uint32 totalWin, uint32 totalLose, uint32 point,
                uint64 a0, uint64 a1, uint64 a2, uint64 s0, uint64 s1, uint64 s2, uint32 energy, uint lastClaim) {
                playerId = playerIds[_trainer];
                PlayerData memory player = players[playerId];
                totalWin = player.totalWin;
                totalLose = player.totalLose;
                point = player.point;
                a0 = player.monsters[0];
                a1 = player.monsters[1];
                a2 = player.monsters[2];
                s0 = player.monsters[3];
                s1 = player.monsters[4];
                s2 = player.monsters[5];
                energy = player.energy;
                lastClaim = player.lastClaim;
            }
            
            function isOnBattle(address _trainer, uint64 _objId) constant external returns(bool) {
                uint32 playerId = playerIds[_trainer];
                if (playerId == 0)
                    return false;
                PlayerData memory player = players[playerId];
                for (uint i = 0; i < player.monsters.length; i++)
                    if (player.monsters[i] == _objId)
                        return true;
                return false;
            }
        
            function getPlayerPoint(uint32 _playerId) constant external returns(address trainer, uint32 totalWin, uint32 totalLose, uint32 point) {
                PlayerData memory player = players[_playerId];
                return (player.trainer, player.totalWin, player.totalLose, player.point);
            }
            
            function getPlayerId(address _trainer) constant external returns(uint32 playerId) {
                return playerIds[_trainer];
            }
        
            function getPlayerEnergy(uint32 _playerId) constant external returns(address trainer, uint32 energy, uint lastClaim) {
                PlayerData memory player = players[_playerId];
                trainer = player.trainer;
                energy = player.energy;
                lastClaim = player.lastClaim;
            }
            
            function getPlayerEnergyByAddress(address _trainer) constant external returns(uint32 playerId, uint32 energy, uint lastClaim) {
                playerId = playerIds[_trainer];
                PlayerData memory player = players[playerId];
                energy = player.energy;
                lastClaim = player.lastClaim;
            }
        }

        File 5 of 6: EtheremonTradingVerifier
        pragma solidity ^0.4.16;
        
        interface EtheremonTradeData {
            function isOnTrade(uint _objId) constant external returns(bool);
        }
        
        contract EtheremonTradingVerifier {
            address public tradingData;
            
            function EtheremonTradingVerifier(address _tradingData) public {
                tradingData = _tradingData;
            }
            
            function isOnTrading(uint64 _objId) constant external returns(bool) {
                EtheremonTradeData monTradeData = EtheremonTradeData(tradingData);
                return monTradeData.isOnTrade(_objId);
            }
        }

        File 6 of 6: EtheremonTradeData
        pragma solidity ^0.4.16;
        
        // copyright [email protected]
        
        contract SafeMath {
        
            /* function assert(bool assertion) internal { */
            /*   if (!assertion) { */
            /*     throw; */
            /*   } */
            /* }      // assert no longer needed once solidity is on 0.4.10 */
        
            function safeAdd(uint256 x, uint256 y) pure internal returns(uint256) {
              uint256 z = x + y;
              assert((z >= x) && (z >= y));
              return z;
            }
        
            function safeSubtract(uint256 x, uint256 y) pure internal returns(uint256) {
              assert(x >= y);
              uint256 z = x - y;
              return z;
            }
        
            function safeMult(uint256 x, uint256 y) pure internal returns(uint256) {
              uint256 z = x * y;
              assert((x == 0)||(z/x == y));
              return z;
            }
        
        }
        
        contract BasicAccessControl {
            address public owner;
            // address[] public moderators;
            uint16 public totalModerators = 0;
            mapping (address => bool) public moderators;
            bool public isMaintaining = false;
        
            function BasicAccessControl() public {
                owner = msg.sender;
            }
        
            modifier onlyOwner {
                require(msg.sender == owner);
                _;
            }
        
            modifier onlyModerators() {
                require(msg.sender == owner || moderators[msg.sender] == true);
                _;
            }
        
            modifier isActive {
                require(!isMaintaining);
                _;
            }
        
            function ChangeOwner(address _newOwner) onlyOwner public {
                if (_newOwner != address(0)) {
                    owner = _newOwner;
                }
            }
        
        
            function AddModerator(address _newModerator) onlyOwner public {
                if (moderators[_newModerator] == false) {
                    moderators[_newModerator] = true;
                    totalModerators += 1;
                }
            }
            
            function RemoveModerator(address _oldModerator) onlyOwner public {
                if (moderators[_oldModerator] == true) {
                    moderators[_oldModerator] = false;
                    totalModerators -= 1;
                }
            }
        
            function UpdateMaintaining(bool _isMaintaining) onlyOwner public {
                isMaintaining = _isMaintaining;
            }
        }
        
        contract EtheremonEnum {
        
            enum ResultCode {
                SUCCESS,
                ERROR_CLASS_NOT_FOUND,
                ERROR_LOW_BALANCE,
                ERROR_SEND_FAIL,
                ERROR_NOT_TRAINER,
                ERROR_NOT_ENOUGH_MONEY,
                ERROR_INVALID_AMOUNT,
                ERROR_OBJ_NOT_FOUND,
                ERROR_OBJ_INVALID_OWNERSHIP
            }
            
            enum ArrayType {
                CLASS_TYPE,
                STAT_STEP,
                STAT_START,
                STAT_BASE,
                OBJ_SKILL
            }
        }
        
        contract EtheremonDataBase is EtheremonEnum, BasicAccessControl, SafeMath {
            
            uint64 public totalMonster;
            uint32 public totalClass;
            
            // write
            function addElementToArrayType(ArrayType _type, uint64 _id, uint8 _value) onlyModerators public returns(uint);
            function removeElementOfArrayType(ArrayType _type, uint64 _id, uint8 _value) onlyModerators public returns(uint);
            function setMonsterClass(uint32 _classId, uint256 _price, uint256 _returnPrice, bool _catchable) onlyModerators public returns(uint32);
            function addMonsterObj(uint32 _classId, address _trainer, string _name) onlyModerators public returns(uint64);
            function setMonsterObj(uint64 _objId, string _name, uint32 _exp, uint32 _createIndex, uint32 _lastClaimIndex) onlyModerators public;
            function increaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public;
            function decreaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public;
            function removeMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public;
            function addMonsterIdMapping(address _trainer, uint64 _monsterId) onlyModerators public;
            function clearMonsterReturnBalance(uint64 _monsterId) onlyModerators public returns(uint256 amount);
            function collectAllReturnBalance(address _trainer) onlyModerators public returns(uint256 amount);
            function transferMonster(address _from, address _to, uint64 _monsterId) onlyModerators public returns(ResultCode);
            function addExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256);
            function deductExtraBalance(address _trainer, uint256 _amount) onlyModerators public returns(uint256);
            function setExtraBalance(address _trainer, uint256 _amount) onlyModerators public;
            
            // read
            function getSizeArrayType(ArrayType _type, uint64 _id) constant public returns(uint);
            function getElementInArrayType(ArrayType _type, uint64 _id, uint _index) constant public returns(uint8);
            function getMonsterClass(uint32 _classId) constant public returns(uint32 classId, uint256 price, uint256 returnPrice, uint32 total, bool catchable);
            function getMonsterObj(uint64 _objId) constant public returns(uint64 objId, uint32 classId, address trainer, uint32 exp, uint32 createIndex, uint32 lastClaimIndex, uint createTime);
            function getMonsterName(uint64 _objId) constant public returns(string name);
            function getExtraBalance(address _trainer) constant public returns(uint256);
            function getMonsterDexSize(address _trainer) constant public returns(uint);
            function getMonsterObjId(address _trainer, uint index) constant public returns(uint64);
            function getExpectedBalance(address _trainer) constant public returns(uint256);
            function getMonsterReturn(uint64 _objId) constant public returns(uint256 current, uint256 total);
        }
        
        interface EtheremonBattleInterface {
            function isOnBattle(uint64 _objId) constant external returns(bool) ;
        }
        
        interface EtheremonMonsterNFTInterface {
           function triggerTransferEvent(address _from, address _to, uint _tokenId) external;
           function getMonsterCP(uint64 _monsterId) constant external returns(uint cp);
        }
        
        contract EtheremonTradeData is BasicAccessControl {
            struct BorrowItem {
                uint index;
                address owner;
                address borrower;
                uint price;
                bool lent;
                uint releaseTime;
                uint createTime;
            }
            
            struct SellingItem {
                uint index;
                uint price;
                uint createTime;
            }
        
            mapping(uint => SellingItem) public sellingDict; // monster id => item
            uint[] public sellingList; // monster id
            
            mapping(uint => BorrowItem) public borrowingDict;
            uint[] public borrowingList;
        
            mapping(address => uint[]) public lendingList;
            
            function removeSellingItem(uint _itemId) onlyModerators external {
                SellingItem storage item = sellingDict[_itemId];
                if (item.index == 0)
                    return;
                
                if (item.index <= sellingList.length) {
                    // Move an existing element into the vacated key slot.
                    sellingDict[sellingList[sellingList.length-1]].index = item.index;
                    sellingList[item.index-1] = sellingList[sellingList.length-1];
                    sellingList.length -= 1;
                    delete sellingDict[_itemId];
                }
            }
            
            function addSellingItem(uint _itemId, uint _price, uint _createTime) onlyModerators external {
                SellingItem storage item = sellingDict[_itemId];
                item.price = _price;
                item.createTime = _createTime;
                
                if (item.index == 0) {
                    item.index = ++sellingList.length;
                    sellingList[item.index - 1] = _itemId;
                }
            }
            
            function removeBorrowingItem(uint _itemId) onlyModerators external {
                BorrowItem storage item = borrowingDict[_itemId];
                if (item.index == 0)
                    return;
                
                if (item.index <= borrowingList.length) {
                    // Move an existing element into the vacated key slot.
                    borrowingDict[borrowingList[borrowingList.length-1]].index = item.index;
                    borrowingList[item.index-1] = borrowingList[borrowingList.length-1];
                    borrowingList.length -= 1;
                    delete borrowingDict[_itemId];
                }
            }
        
            function addBorrowingItem(address _owner, uint _itemId, uint _price, address _borrower, bool _lent, uint _releaseTime, uint _createTime) onlyModerators external {
                BorrowItem storage item = borrowingDict[_itemId];
                item.owner = _owner;
                item.borrower = _borrower;
                item.price = _price;
                item.lent = _lent;
                item.releaseTime = _releaseTime;
                item.createTime = _createTime;
                
                if (item.index == 0) {
                    item.index = ++borrowingList.length;
                    borrowingList[item.index - 1] = _itemId;
                }
            }
            
            function addItemLendingList(address _trainer, uint _objId) onlyModerators external {
                lendingList[_trainer].push(_objId);
            }
            
            function removeItemLendingList(address _trainer, uint _objId) onlyModerators external {
                uint foundIndex = 0;
                uint[] storage objList = lendingList[_trainer];
                for (; foundIndex < objList.length; foundIndex++) {
                    if (objList[foundIndex] == _objId) {
                        break;
                    }
                }
                if (foundIndex < objList.length) {
                    objList[foundIndex] = objList[objList.length-1];
                    delete objList[objList.length-1];
                    objList.length--;
                }
            }
        
            // read access
            function isOnBorrow(uint _objId) constant external returns(bool) {
                return (borrowingDict[_objId].index > 0);
            }
            
            function isOnSell(uint _objId) constant external returns(bool) {
                return (sellingDict[_objId].index > 0);
            }
            
            function isOnLent(uint _objId) constant external returns(bool) {
                return borrowingDict[_objId].lent;
            }
            
            function getSellPrice(uint _objId) constant external returns(uint) {
                return sellingDict[_objId].price;
            }
            
            function isOnTrade(uint _objId) constant external returns(bool) {
                return ((borrowingDict[_objId].index > 0) || (sellingDict[_objId].index > 0)); 
            }
            
            function getBorrowBasicInfo(uint _objId) constant external returns(address owner, bool lent) {
                BorrowItem storage borrowItem = borrowingDict[_objId];
                return (borrowItem.owner, borrowItem.lent);
            }
            
            function getBorrowInfo(uint _objId) constant external returns(uint index, address owner, address borrower, uint price, bool lent, uint createTime, uint releaseTime) {
                BorrowItem storage borrowItem = borrowingDict[_objId];
                return (borrowItem.index, borrowItem.owner, borrowItem.borrower, borrowItem.price, borrowItem.lent, borrowItem.createTime, borrowItem.releaseTime);
            }
            
            function getSellInfo(uint _objId) constant external returns(uint index, uint price, uint createTime) {
                SellingItem storage item = sellingDict[_objId];
                return (item.index, item.price, item.createTime);
            }
            
            function getTotalSellingItem() constant external returns(uint) {
                return sellingList.length;
            }
            
            function getTotalBorrowingItem() constant external returns(uint) {
                return borrowingList.length;
            }
            
            function getTotalLendingItem(address _trainer) constant external returns(uint) {
                return lendingList[_trainer].length;
            }
            
            function getSellingInfoByIndex(uint _index) constant external returns(uint objId, uint price, uint createTime) {
                objId = sellingList[_index];
                SellingItem storage item = sellingDict[objId];
                price = item.price;
                createTime = item.createTime;
            }
            
            function getBorrowInfoByIndex(uint _index) constant external returns(uint objId, address owner, address borrower, uint price, bool lent, uint createTime, uint releaseTime) {
                objId = borrowingList[_index];
                BorrowItem storage borrowItem = borrowingDict[objId];
                return (objId, borrowItem.owner, borrowItem.borrower, borrowItem.price, borrowItem.lent, borrowItem.createTime, borrowItem.releaseTime);
            }
            
            function getLendingObjId(address _trainer, uint _index) constant external returns(uint) {
                return lendingList[_trainer][_index];
            }
            
            function getLendingInfo(address _trainer, uint _index) constant external returns(uint objId, address owner, address borrower, uint price, bool lent, uint createTime, uint releaseTime) {
                objId = lendingList[_trainer][_index];
                BorrowItem storage borrowItem = borrowingDict[objId];
                return (objId, borrowItem.owner, borrowItem.borrower, borrowItem.price, borrowItem.lent, borrowItem.createTime, borrowItem.releaseTime);
            }
            
            function getTradingInfo(uint _objId) constant external returns(uint sellingPrice, uint lendingPrice, bool lent, uint releaseTime, address owner, address borrower) {
                SellingItem storage item = sellingDict[_objId];
                sellingPrice = item.price;
                BorrowItem storage borrowItem = borrowingDict[_objId];
                lendingPrice = borrowItem.price;
                lent = borrowItem.lent;
                releaseTime = borrowItem.releaseTime;
                owner = borrowItem.owner;
                borrower = borrower;
            }
        }