Transaction Hash:
Block:
5310429 at Mar-24-2018 01:47:22 AM +UTC
Transaction Fee:
0.000983648 ETH
$2.01
Gas Used:
245,912 Gas / 4 Gwei
Emitted Events:
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x95dAaaB9...6fa394A31 | |||||
| 0xABC1c404...81D18Eb3E | (Etheremon: Data) | ||||
| 0xb902E19F...3fA842B03 | (Etheremon: Contract 1) | 5.887 Eth | 5.892 Eth | 0.005 | |
| 0xCd7123e8...4671F1a32 |
0.63403863556 Eth
Nonce: 827
|
0.62805498756 Eth
Nonce: 828
| 0.005983648 | ||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 726.495924186234530711 Eth | 726.496907834234530711 Eth | 0.000983648 |
Execution Trace
ETH 0.005
Etheremon: Contract 1.315058ae( )
-
Null: 0x000...001.0b13215e( ) -
EtheremonCastleBattle.getCastleBasicInfoById( _castleId=1280 ) => ( 29, 0xFF48bACD50bCCE218bfbeAE51A8db02A600316dA, 5 ) -
EtheremonToken.transfer( _to=0xFF48bACD50bCCE218bfbeAE51A8db02A600316dA, _value=25000000 )
-
EtheremonCastleBattle.getCastleBasicInfoById( _castleId=1215 ) => ( 26, 0x773cd61af29fc0EC27141Bdb9c077B125a421885, 10 ) -
EtheremonToken.transfer( _to=0x773cd61af29fc0EC27141Bdb9c077B125a421885, _value=25000000 )
-
EtheremonCastleBattle.getCastleBasicInfoById( _castleId=1249 ) => ( 12, 0x95567C6502625ae5A8F4027aFf27221a39C5FEAb, 5 ) -
EtheremonToken.transfer( _to=0x95567C6502625ae5A8F4027aFf27221a39C5FEAb, _value=25000000 )
-
EtheremonCastleBattle.getCastleBasicInfoById( _castleId=1265 ) => ( 15, 0xF54097CAaF78Bc826B9720F09453F182bB7C50c7, 10 ) -
EtheremonToken.transfer( _to=0xF54097CAaF78Bc826B9720F09453F182bB7C50c7, _value=25000000 )
-
EtheremonCastleBattle.getCastleBasicInfoById( _castleId=1273 ) => ( 14, 0x69aAE7a2969d5ef1A6521ED2F2CC68b9d16360B3, 5 ) -
EtheremonToken.transfer( _to=0x69aAE7a2969d5ef1A6521ED2F2CC68b9d16360B3, _value=25000000 )
-
EtheremonData.increaseMonsterExp( _objId=28564, amount=246 ) -
EtheremonData.increaseMonsterExp( _objId=28568, amount=293 ) -
EtheremonData.increaseMonsterExp( _objId=28651, amount=60 )
File 1 of 3: EtheremonToken
File 2 of 3: EtheremonCastleBattle
File 3 of 3: EtheremonData
pragma solidity ^0.4.16;
// copyright contact@Etheremon.com
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(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;
}
}
interface TokenRecipient {
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public;
}
contract TokenERC20 {
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
event Transfer(address indexed from, address indexed to, uint256 value);
event Burn(address indexed from, uint256 value);
function _transfer(address _from, address _to, uint _value) internal {
require(_to != 0x0);
require(balanceOf[_from] >= _value);
require(balanceOf[_to] + _value > balanceOf[_to]);
uint previousBalances = balanceOf[_from] + balanceOf[_to];
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
function transfer(address _to, uint256 _value) public {
_transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
allowance[msg.sender][_spender] = _value;
return true;
}
function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) {
TokenRecipient spender = TokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value);
balanceOf[msg.sender] -= _value;
totalSupply -= _value;
Burn(msg.sender, _value);
return true;
}
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
allowance[_from][msg.sender] -= _value;
totalSupply -= _value;
Burn(_from, _value);
return true;
}
}
contract PaymentInterface {
function createCastle(address _trainer, uint _tokens, string _name, uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3) public returns(uint);
function catchMonster(address _trainer, uint _tokens, uint32 _classId, string _name) public returns(uint);
function payService(address _trainer, uint _tokens, uint32 _type, string _text, uint64 _param1, uint64 _param2, uint64 _param3, uint64 _param4, uint64 _param5, uint64 _param6) public returns(uint);
}
contract EtheremonToken is BasicAccessControl, TokenERC20 {
// metadata
string public constant name = "EtheremonToken";
string public constant symbol = "EMONT";
uint256 public constant decimals = 8;
string public version = "1.0";
// deposit address
address public inGameRewardAddress;
address public userGrowPoolAddress;
address public developerAddress;
// Etheremon payment
address public paymentContract;
// for future feature
uint256 public sellPrice;
uint256 public buyPrice;
bool public trading = false;
mapping (address => bool) public frozenAccount;
event FrozenFunds(address target, bool frozen);
modifier isTrading {
require(trading == true || msg.sender == owner);
_;
}
modifier requirePaymentContract {
require(paymentContract != address(0));
_;
}
function () payable public {}
// constructor
function EtheremonToken(address _inGameRewardAddress, address _userGrowPoolAddress, address _developerAddress, address _paymentContract) public {
require(_inGameRewardAddress != address(0));
require(_userGrowPoolAddress != address(0));
require(_developerAddress != address(0));
inGameRewardAddress = _inGameRewardAddress;
userGrowPoolAddress = _userGrowPoolAddress;
developerAddress = _developerAddress;
balanceOf[inGameRewardAddress] = 14000000 * 10**uint(decimals);
balanceOf[userGrowPoolAddress] = 5000000 * 10**uint(decimals);
balanceOf[developerAddress] = 1000000 * 10**uint(decimals);
totalSupply = balanceOf[inGameRewardAddress] + balanceOf[userGrowPoolAddress] + balanceOf[developerAddress];
paymentContract = _paymentContract;
}
// moderators
function setAddress(address _inGameRewardAddress, address _userGrowPoolAddress, address _developerAddress, address _paymentContract) onlyModerators external {
inGameRewardAddress = _inGameRewardAddress;
userGrowPoolAddress = _userGrowPoolAddress;
developerAddress = _developerAddress;
paymentContract = _paymentContract;
}
// public
function withdrawEther(address _sendTo, uint _amount) onlyModerators external {
if (_amount > this.balance) {
revert();
}
_sendTo.transfer(_amount);
}
function _transfer(address _from, address _to, uint _value) internal {
require (_to != 0x0);
require (balanceOf[_from] >= _value);
require (balanceOf[_to] + _value > balanceOf[_to]);
require(!frozenAccount[_from]);
require(!frozenAccount[_to]);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
Transfer(_from, _to, _value);
}
function freezeAccount(address _target, bool _freeze) onlyOwner public {
frozenAccount[_target] = _freeze;
FrozenFunds(_target, _freeze);
}
function buy() payable isTrading public {
uint amount = msg.value / buyPrice;
_transfer(this, msg.sender, amount);
}
function sell(uint256 amount) isTrading public {
require(this.balance >= amount * sellPrice);
_transfer(msg.sender, this, amount);
msg.sender.transfer(amount * sellPrice);
}
// Etheremon
function createCastle(uint _tokens, string _name, uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3) isActive requirePaymentContract external {
if (_tokens > balanceOf[msg.sender])
revert();
PaymentInterface payment = PaymentInterface(paymentContract);
uint deductedTokens = payment.createCastle(msg.sender, _tokens, _name, _a1, _a2, _a3, _s1, _s2, _s3);
if (deductedTokens == 0 || deductedTokens > _tokens)
revert();
_transfer(msg.sender, inGameRewardAddress, deductedTokens);
}
function catchMonster(uint _tokens, uint32 _classId, string _name) isActive requirePaymentContract external {
if (_tokens > balanceOf[msg.sender])
revert();
PaymentInterface payment = PaymentInterface(paymentContract);
uint deductedTokens = payment.catchMonster(msg.sender, _tokens, _classId, _name);
if (deductedTokens == 0 || deductedTokens > _tokens)
revert();
_transfer(msg.sender, inGameRewardAddress, deductedTokens);
}
function payService(uint _tokens, uint32 _type, string _text, uint64 _param1, uint64 _param2, uint64 _param3, uint64 _param4, uint64 _param5, uint64 _param6) isActive requirePaymentContract external {
if (_tokens > balanceOf[msg.sender])
revert();
PaymentInterface payment = PaymentInterface(paymentContract);
uint deductedTokens = payment.payService(msg.sender, _tokens, _type, _text, _param1, _param2, _param3, _param4, _param5, _param6);
if (deductedTokens == 0 || deductedTokens > _tokens)
revert();
_transfer(msg.sender, inGameRewardAddress, deductedTokens);
}
}File 2 of 3: EtheremonCastleBattle
pragma solidity ^0.4.16;
// copyright contact@Etheremon.com
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
}
}
contract EtheremonCastleBattle is EtheremonEnum, BasicAccessControl, SafeMath {
uint8 constant public NO_BATTLE_LOG = 4;
struct CastleData {
uint index; // in active castle if > 0
string name;
address owner;
uint32 totalWin;
uint32 totalLose;
uint64[6] monsters; // 3 attackers, 3 supporters
uint64[4] battleList;
uint32 brickNumber;
uint createTime;
}
struct BattleDataLog {
uint32 castleId;
address attacker;
uint32[3] castleExps; // 3 attackers
uint64[6] attackerObjIds;
uint32[3] attackerExps;
uint8[3] randoms;
uint8 result;
}
struct TrainerBattleLog {
uint32 lastCastle;
uint32 totalWin;
uint32 totalLose;
uint64[4] battleList;
uint32 totalBrick;
}
mapping(uint64 => BattleDataLog) battles;
mapping(address => uint32) trainerCastle;
mapping(address => TrainerBattleLog) trannerBattleLog;
mapping(uint32 => CastleData) castleData;
uint32[] activeCastleList;
uint32 public totalCastle = 0;
uint64 public totalBattle = 0;
// 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 addCastle(address _trainer, string _name, uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3, uint32 _brickNumber) onlyModerators external returns(uint32 currentCastleId){
currentCastleId = trainerCastle[_trainer];
if (currentCastleId > 0)
return currentCastleId;
totalCastle += 1;
currentCastleId = totalCastle;
CastleData storage castle = castleData[currentCastleId];
castle.name = _name;
castle.owner = _trainer;
castle.monsters[0] = _a1;
castle.monsters[1] = _a2;
castle.monsters[2] = _a3;
castle.monsters[3] = _s1;
castle.monsters[4] = _s2;
castle.monsters[5] = _s3;
castle.brickNumber = _brickNumber;
castle.createTime = now;
castle.index = ++activeCastleList.length;
activeCastleList[castle.index-1] = currentCastleId;
// mark sender
trainerCastle[_trainer] = currentCastleId;
}
function renameCastle(uint32 _castleId, string _name) onlyModerators external {
CastleData storage castle = castleData[_castleId];
castle.name = _name;
}
function removeCastleFromActive(uint32 _castleId) onlyModerators external {
CastleData storage castle = castleData[_castleId];
if (castle.index == 0)
return;
trainerCastle[castle.owner] = 0;
if (castle.index <= activeCastleList.length) {
// Move an existing element into the vacated key slot.
castleData[activeCastleList[activeCastleList.length-1]].index = castle.index;
activeCastleList[castle.index-1] = activeCastleList[activeCastleList.length-1];
activeCastleList.length -= 1;
castle.index = 0;
}
trannerBattleLog[castle.owner].lastCastle = _castleId;
}
function addBattleLog(uint32 _castleId, address _attacker,
uint8 _ran1, uint8 _ran2, uint8 _ran3, uint8 _result, uint32 _castleExp1, uint32 _castleExp2, uint32 _castleExp3) onlyModerators external returns(uint64) {
totalBattle += 1;
BattleDataLog storage battleLog = battles[totalBattle];
battleLog.castleId = _castleId;
battleLog.attacker = _attacker;
battleLog.randoms[0] = _ran1;
battleLog.randoms[1] = _ran2;
battleLog.randoms[2] = _ran3;
battleLog.result = _result;
battleLog.castleExps[0] = _castleExp1;
battleLog.castleExps[1] = _castleExp2;
battleLog.castleExps[2] = _castleExp3;
//
CastleData storage castle = castleData[_castleId];
TrainerBattleLog storage trainerLog = trannerBattleLog[_attacker];
/*
CASTLE_WIN = 0
CASTLE_LOSE = 1
CASTLE_DESTROYED= 2
*/
if (_result == 0) { // win
castle.totalWin += 1;
trainerLog.totalLose += 1;
} else {
castle.totalLose += 1;
trainerLog.totalWin += 1;
if (_result == 2) { // destroy
trainerLog.totalBrick += castle.brickNumber / 2;
}
}
castle.battleList[(castle.totalLose + castle.totalWin - 1)%NO_BATTLE_LOG] = totalBattle;
trainerLog.battleList[(trainerLog.totalWin + trainerLog.totalLose - 1)%NO_BATTLE_LOG] = totalBattle;
return totalBattle;
}
function addBattleLogMonsterInfo(uint64 _battleId, uint64 _a1, uint64 _a2, uint64 _a3, uint64 _s1, uint64 _s2, uint64 _s3, uint32 _exp1, uint32 _exp2, uint32 _exp3) onlyModerators external {
BattleDataLog storage battleLog = battles[_battleId];
battleLog.attackerObjIds[0] = _a1;
battleLog.attackerObjIds[1] = _a2;
battleLog.attackerObjIds[2] = _a3;
battleLog.attackerObjIds[3] = _s1;
battleLog.attackerObjIds[4] = _s2;
battleLog.attackerObjIds[5] = _s3;
battleLog.attackerExps[0] = _exp1;
battleLog.attackerExps[1] = _exp2;
battleLog.attackerExps[2] = _exp3;
}
function deductTrainerBrick(address _trainer, uint32 _deductAmount) onlyModerators external returns(bool){
TrainerBattleLog storage trainerLog = trannerBattleLog[_trainer];
if (trainerLog.totalBrick < _deductAmount)
return false;
trainerLog.totalBrick -= _deductAmount;
return true;
}
// read access
function isCastleActive(uint32 _castleId) constant external returns(bool){
CastleData storage castle = castleData[_castleId];
return (castle.index > 0);
}
function countActiveCastle() constant external returns(uint) {
return activeCastleList.length;
}
function getActiveCastleId(uint index) constant external returns(uint32) {
return activeCastleList[index];
}
function getCastleBasicInfo(address _owner) constant external returns(uint32, uint, uint32) {
uint32 currentCastleId = trainerCastle[_owner];
if (currentCastleId == 0)
return (0, 0, 0);
CastleData memory castle = castleData[currentCastleId];
return (currentCastleId, castle.index, castle.brickNumber);
}
function getCastleBasicInfoById(uint32 _castleId) constant external returns(uint, address, uint32) {
CastleData memory castle = castleData[_castleId];
return (castle.index, castle.owner, castle.brickNumber);
}
function getCastleObjInfo(uint32 _castleId) constant external returns(uint64, uint64, uint64, uint64, uint64, uint64) {
CastleData memory castle = castleData[_castleId];
return (castle.monsters[0], castle.monsters[1], castle.monsters[2], castle.monsters[3], castle.monsters[4], castle.monsters[5]);
}
function getCastleWinLose(uint32 _castleId) constant external returns(uint32, uint32, uint32) {
CastleData memory castle = castleData[_castleId];
return (castle.totalWin, castle.totalLose, castle.brickNumber);
}
function getCastleStats(uint32 _castleId) constant external returns(string, address, uint32, uint32, uint32, uint) {
CastleData memory castle = castleData[_castleId];
return (castle.name, castle.owner, castle.brickNumber, castle.totalWin, castle.totalLose, castle.createTime);
}
function getBattleDataLog(uint64 _battleId) constant external returns(uint32, address, uint8, uint8, uint8, uint8, uint32, uint32, uint32) {
BattleDataLog memory battleLog = battles[_battleId];
return (battleLog.castleId, battleLog.attacker, battleLog.result, battleLog.randoms[0], battleLog.randoms[1],
battleLog.randoms[2], battleLog.castleExps[0], battleLog.castleExps[1], battleLog.castleExps[2]);
}
function getBattleAttackerLog(uint64 _battleId) constant external returns(uint64, uint64, uint64, uint64, uint64, uint64, uint32, uint32, uint32) {
BattleDataLog memory battleLog = battles[_battleId];
return (battleLog.attackerObjIds[0], battleLog.attackerObjIds[1], battleLog.attackerObjIds[2], battleLog.attackerObjIds[3], battleLog.attackerObjIds[4],
battleLog.attackerObjIds[5], battleLog.attackerExps[0], battleLog.attackerExps[1], battleLog.attackerExps[2]);
}
function getCastleBattleList(uint32 _castleId) constant external returns(uint64, uint64, uint64, uint64) {
CastleData storage castle = castleData[_castleId];
return (castle.battleList[0], castle.battleList[1], castle.battleList[2], castle.battleList[3]);
}
function getTrainerBattleInfo(address _trainer) constant external returns(uint32, uint32, uint32, uint32, uint64, uint64, uint64, uint64) {
TrainerBattleLog memory trainerLog = trannerBattleLog[_trainer];
return (trainerLog.totalWin, trainerLog.totalLose, trainerLog.lastCastle, trainerLog.totalBrick, trainerLog.battleList[0], trainerLog.battleList[1], trainerLog.battleList[2],
trainerLog.battleList[3]);
}
function getTrainerBrick(address _trainer) constant external returns(uint32) {
return trannerBattleLog[_trainer].totalBrick;
}
function isOnCastle(uint32 _castleId, uint64 _objId) constant external returns(bool) {
CastleData storage castle = castleData[_castleId];
if (castle.index > 0) {
for (uint i = 0; i < castle.monsters.length; i++)
if (castle.monsters[i] == _objId)
return true;
return false;
}
return false;
}
}File 3 of 3: EtheremonData
pragma solidity ^0.4.16;
// copyright contact@Etheremon.com
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));
}
}