Transaction Hash:
Block:
5208034 at Mar-06-2018 05:55:38 PM +UTC
Transaction Fee:
0.001072284 ETH
$2.68
Gas Used:
357,428 Gas / 3 Gwei
Emitted Events:
55 |
EtheremonWorld.EventCatchMonster( trainer=[Sender] 0x09884af62d26d21442f130a1fca4915958d40e0f, objId=27407 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x09884aF6...958D40E0f |
3.864822372 Eth
Nonce: 17
|
3.863750088 Eth
Nonce: 18
| 0.001072284 | ||
0x829BD824...93333A830
Miner
| (F2Pool Old) | 2,530.107509389949327786 Eth | 2,530.108581673949327786 Eth | 0.001072284 | |
0xABC1c404...81D18Eb3E | (Etheremon: Data) |
Execution Trace
EtheremonWorld.catchMonster( _classId=26, _name=Omnom )
-
EtheremonData.getMonsterClass( _classId=26 ) => ( classId=26, price=0, returnPrice=0, total=5052, catchable=True )
-
EtheremonData.getMonsterDexSize( _trainer=0x09884aF62d26D21442f130a1fCa4915958D40E0f ) => ( 2 )
-
EtheremonData.getExtraBalance( _trainer=0x09884aF62d26D21442f130a1fCa4915958D40E0f ) => ( 0 )
-
EtheremonData.setExtraBalance( _trainer=0x09884aF62d26D21442f130a1fCa4915958D40E0f, _amount=0 )
-
EtheremonData.addMonsterObj( _classId=26, _trainer=0x09884aF62d26D21442f130a1fCa4915958D40E0f, _name=Omnom ) => ( 27407 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=0 ) => ( 58 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=70 ) => ( 1 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=1 ) => ( 40 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=65 ) => ( 2 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=2 ) => ( 61 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=80 ) => ( 3 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=3 ) => ( 42 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=48 ) => ( 4 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=4 ) => ( 63 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=66 ) => ( 5 )
-
EtheremonData.getElementInArrayType( _type=2, _id=26, _index=5 ) => ( 47 )
-
EtheremonData.addElementToArrayType( _type=3, _id=27407, _value=63 ) => ( 6 )
catchMonster[EtheremonWorld (ln:487)]
getMonsterClass[EtheremonWorld (ln:490)]
revert[EtheremonWorld (ln:493)]
getMonsterDexSize[EtheremonWorld (ln:497)]
revert[EtheremonWorld (ln:498)]
safeAdd[EtheremonWorld (ln:500)]
getExtraBalance[EtheremonWorld (ln:500)]
revert[EtheremonWorld (ln:506)]
setExtraBalance[EtheremonWorld (ln:511)]
safeSubtract[EtheremonWorld (ln:511)]
addMonsterObj[EtheremonWorld (ln:514)]
getRandom[EtheremonWorld (ln:517)]
blockhash[EtheremonWorld (ln:387)]
getElementInArrayType[EtheremonWorld (ln:517)]
addElementToArrayType[EtheremonWorld (ln:518)]
EventCatchMonster[EtheremonWorld (ln:522)]
File 1 of 2: EtheremonWorld
File 2 of 2: 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; 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(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 is EtheremonEnum, BasicAccessControl, SafeMath { uint64 public totalMonster; uint32 public totalClass; // write function withdrawEther(address _sendTo, uint _amount) onlyOwner public returns(ResultCode); 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 EtheremonGateway is EtheremonEnum, BasicAccessControl { // using for battle contract later function increaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public; function decreaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public; // read function isGason(uint64 _objId) constant external returns(bool); function getObjBattleInfo(uint64 _objId) constant external returns(uint32 classId, uint32 exp, bool isGason, uint ancestorLength, uint xfactorsLength); function getClassPropertySize(uint32 _classId, PropertyType _type) constant external returns(uint); function getClassPropertyValue(uint32 _classId, PropertyType _type, uint index) constant external returns(uint32); } contract EtheremonWorld is EtheremonGateway, SafeMath { // old processor address constant public ETHEREMON_PROCESSOR = address(0x8a60806F05876f4d6dB00c877B0558DbCAD30682); uint8 constant public STAT_COUNT = 6; uint8 constant public STAT_MAX = 32; uint8 constant public GEN0_NO = 24; 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; } // Gen0 has return price & no longer can be caught when this contract is deployed struct Gen0Config { uint32 classId; uint256 originalPrice; uint256 returnPrice; uint32 total; // total caught (not count those from eggs) } struct GenXProperty { uint32 classId; bool isGason; uint32[] ancestors; uint32[] xfactors; } mapping(uint32 => Gen0Config) public gen0Config; mapping(uint32 => GenXProperty) public genxProperty; uint256 public totalCashout = 0; // for admin uint256 public totalEarn = 0; // exclude gen 0 uint16 public priceIncreasingRatio = 1000; uint public maxDexSize = 500; address private lastHunter = address(0x0); // data contract address public dataContract; // event event EventCatchMonster(address indexed trainer, uint64 objId); event EventCashOut(address indexed trainer, ResultCode result, uint256 amount); event EventWithdrawEther(address indexed sendTo, ResultCode result, uint256 amount); function EtheremonWorld(address _dataContract) public { dataContract = _dataContract; } // admin & moderators function setMaxDexSize(uint _value) onlyModerators external { maxDexSize = _value; } function setOriginalPriceGen0() onlyModerators external { gen0Config[1] = Gen0Config(1, 0.3 ether, 0.003 ether, 374); gen0Config[2] = Gen0Config(2, 0.3 ether, 0.003 ether, 408); gen0Config[3] = Gen0Config(3, 0.3 ether, 0.003 ether, 373); gen0Config[4] = Gen0Config(4, 0.2 ether, 0.002 ether, 437); gen0Config[5] = Gen0Config(5, 0.1 ether, 0.001 ether, 497); gen0Config[6] = Gen0Config(6, 0.3 ether, 0.003 ether, 380); gen0Config[7] = Gen0Config(7, 0.2 ether, 0.002 ether, 345); gen0Config[8] = Gen0Config(8, 0.1 ether, 0.001 ether, 518); gen0Config[9] = Gen0Config(9, 0.1 ether, 0.001 ether, 447); gen0Config[10] = Gen0Config(10, 0.2 ether, 0.002 ether, 380); gen0Config[11] = Gen0Config(11, 0.2 ether, 0.002 ether, 354); gen0Config[12] = Gen0Config(12, 0.2 ether, 0.002 ether, 346); gen0Config[13] = Gen0Config(13, 0.2 ether, 0.002 ether, 351); gen0Config[14] = Gen0Config(14, 0.2 ether, 0.002 ether, 338); gen0Config[15] = Gen0Config(15, 0.2 ether, 0.002 ether, 341); gen0Config[16] = Gen0Config(16, 0.35 ether, 0.0035 ether, 384); gen0Config[17] = Gen0Config(17, 0.1 ether, 0.001 ether, 305); gen0Config[18] = Gen0Config(18, 0.1 ether, 0.001 ether, 427); gen0Config[19] = Gen0Config(19, 0.1 ether, 0.001 ether, 304); gen0Config[20] = Gen0Config(20, 0.4 ether, 0.005 ether, 82); gen0Config[21] = Gen0Config(21, 1, 1, 123); gen0Config[22] = Gen0Config(22, 0.2 ether, 0.001 ether, 468); gen0Config[23] = Gen0Config(23, 0.5 ether, 0.0025 ether, 302); gen0Config[24] = Gen0Config(24, 1 ether, 0.005 ether, 195); } function getEarningAmount() constant public returns(uint256) { // calculate value for gen0 uint256 totalValidAmount = 0; for (uint32 classId=1; classId <= GEN0_NO; classId++) { // make sure there is a class Gen0Config storage gen0 = gen0Config[classId]; if (gen0.total >0 && gen0.classId == classId && gen0.originalPrice > 0 && gen0.returnPrice > 0) { uint256 rate = gen0.originalPrice/gen0.returnPrice; if (rate < gen0.total) { totalValidAmount += (gen0.originalPrice + gen0.returnPrice) * rate / 2; totalValidAmount += (gen0.total - rate) * gen0.returnPrice; } else { totalValidAmount += (gen0.originalPrice + gen0.returnPrice * (rate - gen0.total + 1)) / 2 * gen0.total; } } } // add in earn from genx totalValidAmount = safeAdd(totalValidAmount, totalEarn); // deduct amount of cashing out totalValidAmount = safeSubtract(totalValidAmount, totalCashout); return totalValidAmount; } function withdrawEther(address _sendTo, uint _amount) onlyModerators external returns(ResultCode) { if (_amount > this.balance) { EventWithdrawEther(_sendTo, ResultCode.ERROR_INVALID_AMOUNT, 0); return ResultCode.ERROR_INVALID_AMOUNT; } uint256 totalValidAmount = getEarningAmount(); if (_amount > totalValidAmount) { EventWithdrawEther(_sendTo, ResultCode.ERROR_INVALID_AMOUNT, 0); return ResultCode.ERROR_INVALID_AMOUNT; } _sendTo.transfer(_amount); totalCashout += _amount; EventWithdrawEther(_sendTo, ResultCode.SUCCESS, _amount); return ResultCode.SUCCESS; } // convenient tool to add monster function addMonsterClassBasic(uint32 _classId, uint8 _type, uint256 _price, uint256 _returnPrice, uint8 _ss1, uint8 _ss2, uint8 _ss3, uint8 _ss4, uint8 _ss5, uint8 _ss6) onlyModerators external { EtheremonDataBase data = EtheremonDataBase(dataContract); MonsterClassAcc memory class; (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId); // can add only one time if (_classId == 0 || class.classId == _classId) revert(); data.setMonsterClass(_classId, _price, _returnPrice, true); data.addElementToArrayType(ArrayType.CLASS_TYPE, uint64(_classId), _type); // add stat step data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss1); data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss2); data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss3); data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss4); data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss5); data.addElementToArrayType(ArrayType.STAT_START, uint64(_classId), _ss6); } function addMonsterClassExtend(uint32 _classId, uint8 _type2, uint8 _type3, uint8 _st1, uint8 _st2, uint8 _st3, uint8 _st4, uint8 _st5, uint8 _st6 ) onlyModerators external { EtheremonDataBase data = EtheremonDataBase(dataContract); if (_classId == 0 || data.getSizeArrayType(ArrayType.STAT_STEP, uint64(_classId)) > 0) revert(); if (_type2 > 0) { data.addElementToArrayType(ArrayType.CLASS_TYPE, uint64(_classId), _type2); } if (_type3 > 0) { data.addElementToArrayType(ArrayType.CLASS_TYPE, uint64(_classId), _type3); } // add stat base data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st1); data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st2); data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st3); data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st4); data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st5); data.addElementToArrayType(ArrayType.STAT_STEP, uint64(_classId), _st6); } function setCatchable(uint32 _classId, bool catchable) onlyModerators external { // can not edit gen 0 - can not catch forever Gen0Config storage gen0 = gen0Config[_classId]; if (gen0.classId == _classId) revert(); EtheremonDataBase data = EtheremonDataBase(dataContract); MonsterClassAcc memory class; (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId); data.setMonsterClass(class.classId, class.price, class.returnPrice, catchable); } function setPriceIncreasingRatio(uint16 _ratio) onlyModerators external { priceIncreasingRatio = _ratio; } function setGason(uint32 _classId, bool _isGason) onlyModerators external { GenXProperty storage pro = genxProperty[_classId]; pro.isGason = _isGason; } function addClassProperty(uint32 _classId, PropertyType _type, uint32 value) onlyModerators external { GenXProperty storage pro = genxProperty[_classId]; pro.classId = _classId; if (_type == PropertyType.ANCESTOR) { pro.ancestors.push(value); } else { pro.xfactors.push(value); } } // gate way function increaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public { EtheremonDataBase data = EtheremonDataBase(dataContract); data.increaseMonsterExp(_objId, amount); } function decreaseMonsterExp(uint64 _objId, uint32 amount) onlyModerators public { EtheremonDataBase data = EtheremonDataBase(dataContract); data.decreaseMonsterExp(_objId, amount); } // helper function getRandom(uint8 maxRan, uint8 index, address priAddress) constant public returns(uint8) { uint256 genNum = uint256(block.blockhash(block.number-1)) + uint256(priAddress); for (uint8 i = 0; i < index && i < 6; i ++) { genNum /= 256; } return uint8(genNum % maxRan); } function () payable public { if (msg.sender != ETHEREMON_PROCESSOR) revert(); } // public function isGason(uint64 _objId) constant external 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); GenXProperty storage pro = genxProperty[obj.classId]; return pro.isGason; } function getObjIndex(uint64 _objId) constant public returns(uint32 classId, uint32 createIndex, uint32 lastClaimIndex) { EtheremonDataBase data = EtheremonDataBase(dataContract); MonsterObjAcc memory obj; (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_objId); return (obj.classId, obj.createIndex, obj.lastClaimIndex); } function getObjBattleInfo(uint64 _objId) constant external returns(uint32 classId, uint32 exp, bool isGason, uint ancestorLength, uint xfactorsLength) { EtheremonDataBase data = EtheremonDataBase(dataContract); MonsterObjAcc memory obj; (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(_objId); GenXProperty storage pro = genxProperty[obj.classId]; return (obj.classId, obj.exp, pro.isGason, pro.ancestors.length, pro.xfactors.length); } function getClassPropertySize(uint32 _classId, PropertyType _type) constant external returns(uint) { if (_type == PropertyType.ANCESTOR) return genxProperty[_classId].ancestors.length; else return genxProperty[_classId].xfactors.length; } function getClassPropertyValue(uint32 _classId, PropertyType _type, uint index) constant external returns(uint32) { if (_type == PropertyType.ANCESTOR) return genxProperty[_classId].ancestors[index]; else return genxProperty[_classId].xfactors[index]; } // only gen 0 function getGen0COnfig(uint32 _classId) constant public returns(uint32, uint256, uint32) { Gen0Config storage gen0 = gen0Config[_classId]; return (gen0.classId, gen0.originalPrice, gen0.total); } // only gen 0 function getReturnFromMonster(uint64 _objId) constant public returns(uint256 current, uint256 total) { /* 1. Gen 0 can not be caught anymore. 2. Egg will not give return. */ uint32 classId = 0; uint32 createIndex = 0; uint32 lastClaimIndex = 0; (classId, createIndex, lastClaimIndex) = getObjIndex(_objId); Gen0Config storage gen0 = gen0Config[classId]; if (gen0.classId != classId) { return (0, 0); } uint32 currentGap = 0; uint32 totalGap = 0; if (lastClaimIndex < gen0.total) currentGap = gen0.total - lastClaimIndex; if (createIndex < gen0.total) totalGap = gen0.total - createIndex; return (safeMult(currentGap, gen0.returnPrice), safeMult(totalGap, gen0.returnPrice)); } // write access function moveDataContractBalanceToWorld() external { EtheremonDataBase data = EtheremonDataBase(dataContract); data.withdrawEther(address(this), data.balance); } 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(uint32 _classId, string _name) isActive external payable { EtheremonDataBase data = EtheremonDataBase(dataContract); MonsterClassAcc memory class; (class.classId, class.price, class.returnPrice, class.total, class.catchable) = data.getMonsterClass(_classId); if (class.classId == 0 || class.catchable == false) { revert(); } // can not keep too much etheremon if (data.getMonsterDexSize(msg.sender) > maxDexSize) revert(); uint256 totalBalance = safeAdd(msg.value, data.getExtraBalance(msg.sender)); uint256 payPrice = class.price; // increase price for each etheremon created if (class.total > 0) payPrice += class.price*(class.total-1)/priceIncreasingRatio; if (payPrice > totalBalance) { revert(); } totalEarn += payPrice; // deduct the balance data.setExtraBalance(msg.sender, safeSubtract(totalBalance, payPrice)); // add monster uint64 objId = data.addMonsterObj(_classId, msg.sender, _name); // generate base stat for the previous one for (uint i=0; i < STAT_COUNT; i+= 1) { uint8 value = getRandom(STAT_MAX, uint8(i), lastHunter) + data.getElementInArrayType(ArrayType.STAT_START, uint64(_classId), i); data.addElementToArrayType(ArrayType.STAT_BASE, objId, value); } lastHunter = msg.sender; EventCatchMonster(msg.sender, objId); } function cashOut(uint256 _amount) public returns(ResultCode) { EtheremonDataBase data = EtheremonDataBase(dataContract); uint256 totalAmount = data.getExtraBalance(msg.sender); uint64 objId = 0; // collect gen 0 return price uint dexSize = data.getMonsterDexSize(msg.sender); for (uint i = 0; i < dexSize; i++) { objId = data.getMonsterObjId(msg.sender, i); if (objId > 0) { MonsterObjAcc memory obj; (obj.monsterId, obj.classId, obj.trainer, obj.exp, obj.createIndex, obj.lastClaimIndex, obj.createTime) = data.getMonsterObj(objId); Gen0Config storage gen0 = gen0Config[obj.classId]; if (gen0.classId == obj.classId) { if (obj.lastClaimIndex < gen0.total) { uint32 gap = uint32(safeSubtract(gen0.total, obj.lastClaimIndex)); if (gap > 0) { totalAmount += safeMult(gap, gen0.returnPrice); // reset total (except name is cleared :( ) data.setMonsterObj(obj.monsterId, " name me ", obj.exp, obj.createIndex, gen0.total); } } } } } // default to cash out all if (_amount == 0) { _amount = totalAmount; } if (_amount > totalAmount) { revert(); } // check contract has enough money if (this.balance + data.balance < _amount){ revert(); } else if (this.balance < _amount) { data.withdrawEther(address(this), data.balance); } if (_amount > 0) { data.setExtraBalance(msg.sender, totalAmount - _amount); if (!msg.sender.send(_amount)) { data.setExtraBalance(msg.sender, totalAmount); EventCashOut(msg.sender, ResultCode.ERROR_SEND_FAIL, 0); return ResultCode.ERROR_SEND_FAIL; } } EventCashOut(msg.sender, ResultCode.SUCCESS, _amount); return ResultCode.SUCCESS; } // read access function getTrainerEarn(address _trainer) constant public returns(uint256) { EtheremonDataBase data = EtheremonDataBase(dataContract); uint256 returnFromMonster = 0; // collect gen 0 return price uint256 gen0current = 0; uint256 gen0total = 0; uint64 objId = 0; uint dexSize = data.getMonsterDexSize(_trainer); for (uint i = 0; i < dexSize; i++) { objId = data.getMonsterObjId(_trainer, i); if (objId > 0) { (gen0current, gen0total) = getReturnFromMonster(objId); returnFromMonster += gen0current; } } return returnFromMonster; } function getTrainerBalance(address _trainer) constant external returns(uint256) { EtheremonDataBase data = EtheremonDataBase(dataContract); uint256 userExtraBalance = data.getExtraBalance(_trainer); uint256 returnFromMonster = getTrainerEarn(_trainer); return (userExtraBalance + returnFromMonster); } 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); } }
File 2 of 2: 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)); } }