Transaction Hash:
Block:
7253135 at Feb-22-2019 12:56:24 PM +UTC
Transaction Fee:
0.00579251 ETH
$11.25
Gas Used:
579,251 Gas / 10 Gwei
Emitted Events:
| 92 |
EtheremonMonsterToken.Transfer( _from=[Receiver] AuctionityDepositEth, _to=0x8ACC1421...48Dc6d643, _tokenId=34718 )
|
| 93 |
AuctionityDepositEth.LogSentEthToWinner( auction=0xA3aB9fDD...b3a0B6EA9, user=[Sender] 0xf5aee6d7b838d5ede8aa65d31dbc11116545180c, amount=76500000000000000 )
|
| 94 |
AuctionityDepositEth.LogSentEthToAuctioneer( auction=0xA3aB9fDD...b3a0B6EA9, user=0xe18cf576cdb5fc79f9f47f6d733efe3ef2fae907, amount=1700000000000000 )
|
| 95 |
AuctionityDepositEth.LogSentRewardsDepotEth( user=[0xF5AeE6d7B838D5edE8AA65d31dBC11116545180C, 0xF5AeE6d7B838D5edE8AA65d31dBC11116545180C], amount=[1700000000000000, 5100000000000000] )
|
| 96 |
AuctionityDepositEth.LogAuctionEndVoucherSubmitted( tokenHash=5166A3DE94AFCB7AD7ED02610503FC201097993A867F0A4E8CAB76B419511B41, tokenContractAddress=EtheremonMonsterToken, tokenId=34718, seller=[Sender] 0xf5aee6d7b838d5ede8aa65d31dbc11116545180c, winner=0x8ACC1421...48Dc6d643, amount=85000000000000000, auctionEndVoucherHash=FF23E937B447336D8AC39BBA9C355AC3DA21FFDB8F947ACF601390818C10FB1D )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
|
0x52bc44d5...b7d7bE3b5
Miner
| (Nanopool) | 9,118.650856241686870818 Eth | 9,118.656648751686870818 Eth | 0.00579251 | |
| 0xABC1c404...81D18Eb3E | (Etheremon: Data) | ||||
| 0xD01c9293...aa47Ae72a | (Auctionity: Old Address) | 132.733210040487243103 Eth | 132.655010040487243103 Eth | 0.0782 | |
| 0xE18cf576...EF2fae907 | 5.689160055844981 Eth | 5.690860055844981 Eth | 0.0017 | ||
| 0xF5AeE6d7...16545180C |
0.47412473249984 Eth
Nonce: 311
|
0.54483222249984 Eth
Nonce: 312
| 0.07070749 |
Execution Trace
AuctionityDepositEth.auctionEndVoucher( _data=0xAF62A293D28C65BA77E562AE51183B0CDD44AA94CCDDF130955B3FB49ECDAEEAA5F301E73AEF266B819CD1E149B7AD950665C2BB2ACA6F698B5F111D2C9561E43A7350078FBF28213BD6B7DA8E74802922B603B5B3A52F18FFA039D40EA1950A1B01B86423B872DD000000000000000000000000D01C92937400DD1ECE24992B1DC44AEAA47AE72A0000000000000000000000008ACC1421EC98689461FF5777DE8AD6648DC6D643000000000000000000000000000000000000000000000000000000000000879E, _signedRawTxCreateAuction=0xF902AA82030B80841DCD65009430E8080940E2DEED1326ABD8AA9D89ED3AB93E4780B90244FFD6D82800000000000000000000000000000000000000000000000000000000000000C00000000000000000000000005D00D312E171BE5342067C09BAE883F9BCB2003B000000000000000000000000000000000000000000000000000000000000879E00000000000000000000000000000000000000000000000000000000000001C0000000000000000000000000F5AEE6D7B838D5EDE8AA65D31DBC11116545180C000000000000000000000000000000000000000000000000000000000000000A00000000000000000000000000000000000000000000000000000000000000CEF8CC82013585037E11D60083030D40945D00D312E171BE5342067C09BAE883F9BCB2003B80B86423B872DD000000000000000000000000F5AEE6D7B838D5EDE8AA65D31DBC11116545180C000000000000000000000000D01C92937400DD1ECE24992B1DC44AEAA47AE72A000000000000000000000000000000000000000000000000000000000000879E25A0A501A097E394D3F635D33AE808FB403179D2ECA6D3AE7672901436B6351BD73AA005C26957BB7E52BADC88A4CF1E4A6162FE13B2C8255A143D1E8BFB7DEA518866000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004D00000000000000000000000000000000000000000000000000B1A2BC2EC500005C6FE0BC5C6FEECC00001E001E0000000000000000000000000000000000000000000000000011C37937E080000000000000000000000000000000000000000081A2A0B4C3E7C5DA7F1D56AC4FA81C1BB7BF44780E84EC741EFA347039E66701E58647A06A966602C5C5B04566E8282924E3351DA7BEF8C69CD1B8FFA5BA5908B5AEF1B2, _signedRawTxBidding=0xF8C982030380841DCD650094A3AB9FDD7E1744F4A3B0E5A2F867AABB3A0B6EA980B8641D03AE68000000000000000000000000000000000000000000000000012DFB0CB5E88000000000000000000000000000F5AEE6D7B838D5EDE8AA65D31DBC11116545180C5166A3DE94AFCB7AD7ED02610503FC201097993A867F0A4E8CAB76B419511B4181A2A0B3CE8EAF150C77DEDD5CB116FF4E5596105FC0C7A975DEA70F75331F510D0EE1A041DEC6D235257143F79D5721F34FC9F578D5E807411664B9B952FD5317D60434, _send=0xF5AEE6D7B838D5EDE8AA65D31DBC11116545180C000000000000000000000000000000000000000000000000010FC8583D514000E18CF576CDB5FC79F9F47F6D733EFE3EF2FAE90700000000000000000000000000000000000000000000000000060A24181E40000002F5AEE6D7B838D5EDE8AA65D31DBC11116545180C00000000000000000019F0A0F5AEE6D7B838D5EDE8AA65D31DBC11116545180C0000000000000000004DD1E0 )
-
Null: 0x000...001.f7531cc9( ) -
Null: 0x000...001.1b62f1d1( ) -
Null: 0x000...001.fff72ec0( )
EtheremonMonsterToken.transferFrom( _from=0xD01c92937400DD1ecE24992B1dc44Aeaa47Ae72a, _to=0x8ACC1421eC98689461fF5777DE8Ad6648Dc6d643, _tokenId=34718 )
-
EtheremonData.getMonsterObj( _objId=34718 ) => ( objId=34718, classId=53, trainer=0xD01c92937400DD1ecE24992B1dc44Aeaa47Ae72a, exp=82056, createIndex=31, lastClaimIndex=31, createTime=1532130789 ) EtheremonRankBattle.isOnBattle( _objId=34718 ) => ( False )-
EtheremonData.getMonsterObj( _objId=34718 ) => ( objId=34718, classId=53, trainer=0xD01c92937400DD1ecE24992B1dc44Aeaa47Ae72a, exp=82056, createIndex=31, lastClaimIndex=31, createTime=1532130789 ) -
EtheremonRankData.isOnBattle( _trainer=0xD01c92937400DD1ecE24992B1dc44Aeaa47Ae72a, _objId=34718 ) => ( False )
-
EtheremonTradingVerifier.isOnTrading( _objId=34718 ) => ( False )-
EtheremonTradeData.isOnTrade( _objId=34718 ) => ( False )
-
-
EtheremonData.removeMonsterIdMapping( _trainer=0xD01c92937400DD1ecE24992B1dc44Aeaa47Ae72a, _monsterId=34718 ) -
EtheremonData.addMonsterIdMapping( _trainer=0x8ACC1421eC98689461fF5777DE8Ad6648Dc6d643, _monsterId=34718 )
-
- ETH 0.0765
0xf5aee6d7b838d5ede8aa65d31dbc11116545180c.CALL( ) - ETH 0.0017
0xe18cf576cdb5fc79f9f47f6d733efe3ef2fae907.CALL( )
auctionEndVoucher[AuctionityDepositEth (ln:955)]
LogError[AuctionityDepositEth (ln:964)]getInfoFromCreateAuction[AuctionityDepositEth (ln:968)]decodeRawTxGetCreateAuctionInfo[AuctionityDepositEth (ln:1033)]toList[AuctionityLibraryDecodeRawTx (ln:452)]toRlpItem[AuctionityLibraryDecodeRawTx (ln:452)]toAddress[AuctionityLibraryDecodeRawTx (ln:455)]toBytes[AuctionityLibraryDecodeRawTx (ln:456)]getSignerFromSignedRawTxRLPItemp[AuctionityLibraryDecodeRawTx (ln:459)]explodeSignedRawTxRLPItem[AuctionityLibraryDecodeRawTx (ln:564)]toRlp[AuctionityLibraryDecodeRawTx (ln:572)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:572)]toRlp[AuctionityLibraryDecodeRawTx (ln:573)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:573)]toRlp[AuctionityLibraryDecodeRawTx (ln:574)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:574)]toRlp[AuctionityLibraryDecodeRawTx (ln:575)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:575)]toRlp[AuctionityLibraryDecodeRawTx (ln:576)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:576)]toRlp[AuctionityLibraryDecodeRawTx (ln:577)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:577)]toRlp[AuctionityLibraryDecodeRawTx (ln:579)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:580)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:581)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:583)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toUint[AuctionityLibraryDecodeRawTx (ln:588)]toUint[AuctionityLibraryDecodeRawTx (ln:593)]toUint[AuctionityLibraryDecodeRawTx (ln:599)]
ecrecoverSigner[AuctionityLibraryDecodeRawTx (ln:565)]
decodeRawTxGetCreateAuctionInfoData[AuctionityLibraryDecodeRawTx (ln:463)]
getInfoFromBidding[AuctionityDepositEth (ln:977)]decodeRawTxGetBiddingInfo[AuctionityDepositEth (ln:1044)]toList[AuctionityLibraryDecodeRawTx (ln:418)]toRlpItem[AuctionityLibraryDecodeRawTx (ln:418)]toAddress[AuctionityLibraryDecodeRawTx (ln:420)]toBytes[AuctionityLibraryDecodeRawTx (ln:421)]getSignerFromSignedRawTxRLPItemp[AuctionityLibraryDecodeRawTx (ln:426)]explodeSignedRawTxRLPItem[AuctionityLibraryDecodeRawTx (ln:564)]toRlp[AuctionityLibraryDecodeRawTx (ln:572)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:572)]toRlp[AuctionityLibraryDecodeRawTx (ln:573)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:573)]toRlp[AuctionityLibraryDecodeRawTx (ln:574)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:574)]toRlp[AuctionityLibraryDecodeRawTx (ln:575)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:575)]toRlp[AuctionityLibraryDecodeRawTx (ln:576)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:576)]toRlp[AuctionityLibraryDecodeRawTx (ln:577)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toBytes[AuctionityLibraryDecodeRawTx (ln:577)]toRlp[AuctionityLibraryDecodeRawTx (ln:579)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:580)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:581)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toRlp[AuctionityLibraryDecodeRawTx (ln:583)]copy[RLPWriter (ln:297)]uintMinimalSize[RLPWriter (ln:302)]copy[RLPWriter (ln:311)]
toUint[AuctionityLibraryDecodeRawTx (ln:588)]toUint[AuctionityLibraryDecodeRawTx (ln:593)]toUint[AuctionityLibraryDecodeRawTx (ln:599)]
ecrecoverSigner[AuctionityLibraryDecodeRawTx (ln:565)]
LogError[AuctionityDepositEth (ln:1047)]LogError[AuctionityDepositEth (ln:1052)]
verifyWinnerDepot[AuctionityDepositEth (ln:979)]LogError[AuctionityDepositEth (ln:1061)]
auctionEndVoucherOracleSignatureVerification[AuctionityDepositEth (ln:984)]getTransferDataHash[AuctionityDepositEth (ln:1176)]ecrecoverSigner[AuctionityDepositEth (ln:1179)]
LogError[AuctionityDepositEth (ln:990)]sendTransfer[AuctionityDepositEth (ln:994)]isContract[AuctionityLibraryDeposit (ln:608)]decodeTransferCall[AuctionityLibraryDeposit (ln:618)]bytesToUint[AuctionityLibraryDeposit (ln:651)]sendCallData[AuctionityLibraryDeposit (ln:660)]
revert[AuctionityDepositEth (ln:996)]LogError[AuctionityDepositEth (ln:998)]sendExchange[AuctionityDepositEth (ln:1004)]LogError[AuctionityDepositEth (ln:1074)]LogError[AuctionityDepositEth (ln:1090)]send[AuctionityDepositEth (ln:1097)]revert[AuctionityDepositEth (ln:1098)]LogSentEthToWinner[AuctionityDepositEth (ln:1101)]send[AuctionityDepositEth (ln:1112)]revert[AuctionityDepositEth (ln:1113)]LogSentEthToAuctioneer[AuctionityDepositEth (ln:1116)]revert[AuctionityDepositEth (ln:1140)]LogSentRewardsDepotEth[AuctionityDepositEth (ln:1147)]revert[AuctionityDepositEth (ln:1151)]
push[AuctionityDepositEth (ln:1010)]LogAuctionEndVoucherSubmitted[AuctionityDepositEth (ln:1012)]
File 1 of 7: AuctionityDepositEth
File 2 of 7: EtheremonMonsterToken
File 3 of 7: EtheremonData
File 4 of 7: EtheremonRankBattle
File 5 of 7: EtheremonRankData
File 6 of 7: EtheremonTradingVerifier
File 7 of 7: EtheremonTradeData
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) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
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;
}
}
library RLPReader {
uint8 constant STRING_SHORT_START = 0x80;
uint8 constant STRING_LONG_START = 0xb8;
uint8 constant LIST_SHORT_START = 0xc0;
uint8 constant LIST_LONG_START = 0xf8;
uint8 constant WORD_SIZE = 32;
struct RLPItem {
uint len;
uint memPtr;
}
/*
* @param item RLP encoded bytes
*/
function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
if (item.length == 0)
return RLPItem(0, 0);
uint memPtr;
assembly {
memPtr := add(item, 0x20)
}
return RLPItem(item.length, memPtr);
}
/*
* @param item RLP encoded list in bytes
*/
function toList(RLPItem memory item) internal pure returns (RLPItem[] memory result) {
require(isList(item));
uint items = numItems(item);
result = new RLPItem[](items);
uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint dataLen;
for (uint i = 0; i < items; i++) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
}
/*
* Helpers
*/
// @return indicator whether encoded payload is a list. negate this function call for isData.
function isList(RLPItem memory item) internal pure returns (bool) {
uint8 byte0;
uint memPtr = item.memPtr;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START)
return false;
return true;
}
// @return number of payload items inside an encoded list.
function numItems(RLPItem memory item) internal pure returns (uint) {
uint count = 0;
uint currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr); // skip over an item
count++;
}
return count;
}
// @return entire rlp item byte length
function _itemLength(uint memPtr) internal pure returns (uint len) {
uint byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START)
return 1;
else if (byte0 < STRING_LONG_START)
return byte0 - STRING_SHORT_START + 1;
else if (byte0 < LIST_SHORT_START) {
assembly {
let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
memPtr := add(memPtr, 1) // skip over the first byte
/* 32 byte word size */
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
len := add(dataLen, add(byteLen, 1))
}
}
else if (byte0 < LIST_LONG_START) {
return byte0 - LIST_SHORT_START + 1;
}
else {
assembly {
let byteLen := sub(byte0, 0xf7)
memPtr := add(memPtr, 1)
let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
len := add(dataLen, add(byteLen, 1))
}
}
}
// @return number of bytes until the data
function _payloadOffset(uint memPtr) internal pure returns (uint) {
uint byte0;
assembly {
byte0 := byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START)
return 0;
else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START))
return 1;
else if (byte0 < LIST_SHORT_START) // being explicit
return byte0 - (STRING_LONG_START - 1) + 1;
else
return byte0 - (LIST_LONG_START - 1) + 1;
}
/** RLPItem conversions into data types **/
function toBoolean(RLPItem memory item) internal pure returns (bool) {
require(item.len == 1, "Invalid RLPItem. Booleans are encoded in 1 byte");
uint result;
uint memPtr = item.memPtr;
assembly {
result := byte(0, mload(memPtr))
}
return result == 0 ? false : true;
}
function toAddress(RLPItem memory item) internal pure returns (address) {
// 1 byte for the length prefix according to RLP spec
require(item.len == 21, "Invalid RLPItem. Addresses are encoded in 20 bytes");
uint memPtr = item.memPtr + 1; // skip the length prefix
uint addr;
assembly {
addr := div(mload(memPtr), exp(256, 12)) // right shift 12 bytes. we want the most significant 20 bytes
}
return address(addr);
}
function toUint(RLPItem memory item) internal pure returns (uint) {
uint offset = _payloadOffset(item.memPtr);
uint len = item.len - offset;
uint memPtr = item.memPtr + offset;
uint result;
assembly {
result := div(mload(memPtr), exp(256, sub(32, len))) // shift to the correct location
}
return result;
}
function toBytes(RLPItem memory item) internal pure returns (bytes) {
uint offset = _payloadOffset(item.memPtr);
uint len = item.len - offset; // data length
bytes memory result = new bytes(len);
uint destPtr;
assembly {
destPtr := add(0x20, result)
}
copy(item.memPtr + offset, destPtr, len);
return result;
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/
function copy(uint src, uint dest, uint len) internal pure {
// copy as many word sizes as possible
for (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
// left over bytes
uint mask = 256 ** (WORD_SIZE - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
library RLPWriter {
function toRlp(bytes memory _value) internal pure returns (bytes memory _bytes) {
uint _valuePtr;
uint _rplPtr;
uint _valueLength = _value.length;
assembly {
_valuePtr := add(_value, 0x20)
_bytes := mload(0x40) // Free memory ptr
_rplPtr := add(_bytes, 0x20) // RLP first byte ptr
}
// [0x00, 0x7f]
if (_valueLength == 1 && _value[0] <= 0x7f) {
assembly {
mstore(_bytes, 1) // Bytes size is 1
mstore(_rplPtr, mload(_valuePtr)) // Set value as-is
mstore(0x40, add(_rplPtr, 1)) // Update free ptr
}
return;
}
// [0x80, 0xb7]
if (_valueLength <= 55) {
assembly {
mstore(_bytes, add(1, _valueLength)) // Bytes size
mstore8(_rplPtr, add(0x80, _valueLength)) // RLP small string size
mstore(0x40, add(add(_rplPtr, 1), _valueLength)) // Update free ptr
}
copy(_valuePtr, _rplPtr + 1, _valueLength);
return;
}
// [0xb8, 0xbf]
uint _lengthSize = uintMinimalSize(_valueLength);
assembly {
mstore(_bytes, add(add(1, _lengthSize), _valueLength)) // Bytes size
mstore8(_rplPtr, add(0xb7, _lengthSize)) // RLP long string "size size"
mstore(add(_rplPtr, 1), mul(_valueLength, exp(256, sub(32, _lengthSize)))) // Bitshift to store the length only _lengthSize bytes
mstore(0x40, add(add(add(_rplPtr, 1), _lengthSize), _valueLength)) // Update free ptr
}
copy(_valuePtr, _rplPtr + 1 + _lengthSize, _valueLength);
return;
}
function toRlp(uint _value) internal pure returns (bytes memory _bytes) {
uint _size = uintMinimalSize(_value);
bytes memory _valueBytes = new bytes(_size);
assembly {
mstore(add(_valueBytes, 0x20), mul(_value, exp(256, sub(32, _size))))
}
return toRlp(_valueBytes);
}
function toRlp(bytes[] memory _values) internal pure returns (bytes memory _bytes) {
uint _ptr;
uint _size;
uint i;
// compute data size
for(; i < _values.length; ++i)
_size += _values[i].length;
// create rlp header
assembly {
_bytes := mload(0x40)
_ptr := add(_bytes, 0x20)
}
if (_size <= 55) {
assembly {
mstore8(_ptr, add(0xc0, _size))
_ptr := add(_ptr, 1)
}
} else {
uint _size2 = uintMinimalSize(_size);
assembly {
mstore8(_ptr, add(0xf7, _size2))
_ptr := add(_ptr, 1)
mstore(_ptr, mul(_size, exp(256, sub(32, _size2))))
_ptr := add(_ptr, _size2)
}
}
// copy data
for(i = 0; i < _values.length; ++i) {
bytes memory _val = _values[i];
uint _valPtr;
assembly {
_valPtr := add(_val, 0x20)
}
copy(_valPtr, _ptr, _val.length);
_ptr += _val.length;
}
assembly {
mstore(0x40, _ptr)
mstore(_bytes, sub(sub(_ptr, _bytes), 0x20))
}
}
function uintMinimalSize(uint _value) internal pure returns (uint _size) {
for (; _value != 0; _size++)
_value /= 256;
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/
function copy(uint src, uint dest, uint len) internal pure {
// copy as many word sizes as possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
src += 32;
dest += 32;
}
// left over bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask)) // zero out src
let destpart := and(mload(dest), mask) // retrieve the bytes
mstore(dest, or(destpart, srcpart))
}
}
}
library AuctionityLibraryDecodeRawTx {
using RLPReader for RLPReader.RLPItem;
using RLPReader for bytes;
function decodeRawTxGetBiddingInfo(bytes memory _signedRawTxBidding, uint8 _chainId) internal pure returns (bytes32 _hashRawTxTokenTransfer, address _auctionContractAddress, uint256 _bidAmount, address _signerBid) {
bytes memory _auctionBidlData;
RLPReader.RLPItem[] memory _signedRawTxBiddingRLPItem = _signedRawTxBidding.toRlpItem().toList();
_auctionContractAddress = _signedRawTxBiddingRLPItem[3].toAddress();
_auctionBidlData = _signedRawTxBiddingRLPItem[5].toBytes();
bytes4 _selector;
assembly { _selector := mload(add(_auctionBidlData,0x20))}
_signerBid = getSignerFromSignedRawTxRLPItemp(_signedRawTxBiddingRLPItem,_chainId);
// 0x1d03ae68 : bytes4(keccak256('bid(uint256,address,bytes32)'))
if(_selector == 0x1d03ae68 ) {
assembly {
_bidAmount := mload(add(_auctionBidlData,add(4,0x20)))
_hashRawTxTokenTransfer := mload(add(_auctionBidlData,add(68,0x20)))
}
}
}
function decodeRawTxGetCreateAuctionInfo(bytes memory _signedRawTxCreateAuction, uint8 _chainId) internal pure returns (
bytes32 _tokenHash,
address _auctionFactoryContractAddress,
address _signerCreate,
address _tokenContractAddress,
uint256 _tokenId,
uint8 _rewardPercent
) {
bytes memory _createAuctionlData;
RLPReader.RLPItem[] memory _signedRawTxCreateAuctionRLPItem = _signedRawTxCreateAuction.toRlpItem().toList();
_auctionFactoryContractAddress = _signedRawTxCreateAuctionRLPItem[3].toAddress();
_createAuctionlData = _signedRawTxCreateAuctionRLPItem[5].toBytes();
_signerCreate = getSignerFromSignedRawTxRLPItemp(_signedRawTxCreateAuctionRLPItem,_chainId);
bytes memory _signedRawTxTokenTransfer;
(_signedRawTxTokenTransfer, _tokenContractAddress,_tokenId,_rewardPercent) = decodeRawTxGetCreateAuctionInfoData( _createAuctionlData);
_tokenHash = keccak256(_signedRawTxTokenTransfer);
}
function decodeRawTxGetCreateAuctionInfoData(bytes memory _createAuctionlData) internal pure returns(
bytes memory _signedRawTxTokenTransfer,
address _tokenContractAddress,
uint256 _tokenId,
uint8 _rewardPercent
) {
bytes4 _selector;
assembly { _selector := mload(add(_createAuctionlData,0x20))}
uint _positionOfSignedRawTxTokenTransfer;
uint _sizeOfSignedRawTxTokenTransfer;
// 0xffd6d828 : bytes4(keccak256('create(bytes,address,uint256,bytes,address,uint8)'))
if(_selector == 0xffd6d828) {
assembly {
_positionOfSignedRawTxTokenTransfer := mload(add(_createAuctionlData,add(4,0x20)))
_sizeOfSignedRawTxTokenTransfer := mload(add(_createAuctionlData,add(add(_positionOfSignedRawTxTokenTransfer,4),0x20)))
// tokenContractAddress : get 2th param
_tokenContractAddress := mload(add(_createAuctionlData,add(add(mul(1,32),4),0x20)))
// tockenId : get 3th param
_tokenId := mload(add(_createAuctionlData,add(add(mul(2,32),4),0x20)))
// rewardPercent : get 6th param
_rewardPercent := mload(add(_createAuctionlData,add(add(mul(5,32),4),0x20)))
}
_signedRawTxTokenTransfer = new bytes(_sizeOfSignedRawTxTokenTransfer);
for (uint i = 0; i < _sizeOfSignedRawTxTokenTransfer; i++) {
_signedRawTxTokenTransfer[i] = _createAuctionlData[i + _positionOfSignedRawTxTokenTransfer + 4 + 32 ];
}
}
}
function ecrecoverSigner(
bytes32 _hashTx,
bytes _rsvTx,
uint offset
) internal pure returns (address ecrecoverAddress){
bytes32 r;
bytes32 s;
bytes1 v;
assembly {
r := mload(add(_rsvTx,add(offset,0x20)))
s := mload(add(_rsvTx,add(offset,0x40)))
v := mload(add(_rsvTx,add(offset,0x60)))
}
ecrecoverAddress = ecrecover(
_hashTx,
uint8(v),
r,
s
);
}
function decodeRawTxGetWithdrawalInfo(bytes memory _signedRawTxWithdrawal, uint8 _chainId) internal pure returns (address withdrawalSigner, uint256 withdrawalAmount) {
bytes4 _selector;
bytes memory _withdrawalData;
RLPReader.RLPItem[] memory _signedRawTxWithdrawalRLPItem = _signedRawTxWithdrawal.toRlpItem().toList();
_withdrawalData = _signedRawTxWithdrawalRLPItem[5].toBytes();
assembly { _selector := mload(add(_withdrawalData,0x20))}
withdrawalSigner = getSignerFromSignedRawTxRLPItemp(_signedRawTxWithdrawalRLPItem,_chainId);
// 0x835fc6ca : bytes4(keccak256('withdrawal(uint256)'))
if(_selector == 0x835fc6ca ) {
assembly {
withdrawalAmount := mload(add(_withdrawalData,add(4,0x20)))
}
}
}
function getSignerFromSignedRawTxRLPItemp(RLPReader.RLPItem[] memory _signedTxRLPItem, uint8 _chainId) internal pure returns (address ecrecoverAddress) {
bytes memory _rawTx;
bytes memory _rsvTx;
(_rawTx, _rsvTx ) = explodeSignedRawTxRLPItem(_signedTxRLPItem, _chainId);
return ecrecoverSigner(keccak256(_rawTx), _rsvTx,0);
}
function explodeSignedRawTxRLPItem(RLPReader.RLPItem[] memory _signedTxRLPItem, uint8 _chainId) internal pure returns (bytes memory _rawTx,bytes memory _rsvTx){
bytes[] memory _signedTxRLPItemRaw = new bytes[](9);
_signedTxRLPItemRaw[0] = RLPWriter.toRlp(_signedTxRLPItem[0].toBytes());
_signedTxRLPItemRaw[1] = RLPWriter.toRlp(_signedTxRLPItem[1].toBytes());
_signedTxRLPItemRaw[2] = RLPWriter.toRlp(_signedTxRLPItem[2].toBytes());
_signedTxRLPItemRaw[3] = RLPWriter.toRlp(_signedTxRLPItem[3].toBytes());
_signedTxRLPItemRaw[4] = RLPWriter.toRlp(_signedTxRLPItem[4].toBytes());
_signedTxRLPItemRaw[5] = RLPWriter.toRlp(_signedTxRLPItem[5].toBytes());
_signedTxRLPItemRaw[6] = RLPWriter.toRlp(_chainId);
_signedTxRLPItemRaw[7] = RLPWriter.toRlp(0);
_signedTxRLPItemRaw[8] = RLPWriter.toRlp(0);
_rawTx = RLPWriter.toRlp(_signedTxRLPItemRaw);
uint8 i;
_rsvTx = new bytes(65);
bytes32 tmp = bytes32(_signedTxRLPItem[7].toUint());
for (i = 0; i < 32; i++) {
_rsvTx[i] = tmp[i];
}
tmp = bytes32(_signedTxRLPItem[8].toUint());
for (i = 0; i < 32; i++) {
_rsvTx[i + 32] = tmp[i];
}
_rsvTx[64] = bytes1(_signedTxRLPItem[6].toUint() - uint(_chainId * 2) - 8);
}
}
library AuctionityLibraryDeposit{
function sendTransfer(address _tokenContractAddress, bytes memory _transfer, uint _offset) internal returns (bool){
if(!isContract(_tokenContractAddress)){
return false;
}
uint8 _numberOfTransfer = uint8(_transfer[_offset]);
_offset += 1;
bool _success;
for (uint8 i = 0; i < _numberOfTransfer; i++){
(_offset,_success) = decodeTransferCall(_tokenContractAddress, _transfer,_offset);
if(!_success) {
return false;
}
}
return true;
}
function decodeTransferCall(address _tokenContractAddress, bytes memory _transfer, uint _offset) internal returns (uint, bool) {
bytes memory _sizeOfCallBytes;
bytes memory _callData;
uint _sizeOfCallUint;
if(_transfer[_offset] == 0xb8) {
_sizeOfCallBytes = new bytes(1);
_sizeOfCallBytes[0] = bytes1(_transfer[_offset + 1]);
_offset+=2;
}
if(_transfer[_offset] == 0xb9) {
_sizeOfCallBytes = new bytes(2);
_sizeOfCallBytes[0] = bytes1(_transfer[_offset + 1]);
_sizeOfCallBytes[1] = bytes1(_transfer[_offset + 2]);
_offset+=3;
}
_sizeOfCallUint = bytesToUint(_sizeOfCallBytes);
_callData = new bytes(_sizeOfCallUint);
for (uint j = 0; j < _sizeOfCallUint; j++) {
_callData[j] = _transfer[(j + _offset)];
}
_offset+=_sizeOfCallUint;
return (_offset, sendCallData(_tokenContractAddress, _sizeOfCallUint, _callData));
}
function sendCallData(address _tokenContractAddress, uint _sizeOfCallUint, bytes memory _callData) internal returns (bool) {
bool _success;
bytes4 sig;
assembly {
let _ptr := mload(0x40)
sig := mload(add(_callData,0x20))
mstore(_ptr,sig) //Place signature at begining of empty storage
for { let i := 0x04 } lt(i, _sizeOfCallUint) { i := add(i, 0x20) } {
mstore(add(_ptr,i),mload(add(_callData,add(0x20,i)))) //Add each param
}
_success := call( //This is the critical change (Pop the top stack value)
sub (gas, 10000), // gas
_tokenContractAddress, //To addr
0, //No value
_ptr, //Inputs are stored at location _ptr
_sizeOfCallUint, //Inputs _size
_ptr, //Store output over input (saves space)
0x20) //Outputs are 32 bytes long
}
return _success;
}
function isContract(address _contractAddress) internal view returns (bool) {
uint _size;
assembly { _size := extcodesize(_contractAddress) }
return _size > 0;
}
function bytesToUint(bytes b) internal pure returns (uint256){
uint256 _number;
for(uint i=0;i<b.length;i++){
_number = _number + uint(b[i])*(2**(8*(b.length-(i+1))));
}
return _number;
}
}
contract AuctionityDepositEth {
using SafeMath for uint256;
string public version = "deposit-eth-v1";
address public owner;
address public oracle;
uint8 public ethereumChainId;
uint8 public auctionityChainId;
bool public migrationLock;
bool public maintenanceLock;
mapping (address => uint256) public depotEth; // Depot for users (concatenate struct into uint256)
bytes32[] public withdrawalVoucherList; // List of withdrawal voucher
mapping (bytes32 => bool) public withdrawalVoucherSubmitted; // is withdrawal voucher is already submitted
bytes32[] public auctionEndVoucherList; // List of auction end voucher
mapping (bytes32 => bool) public auctionEndVoucherSubmitted; // is auction end voucher is already submitted
struct InfoFromCreateAuction {
bytes32 tokenHash;
address tokenContractAddress;
address auctionSeller;
uint8 rewardPercent;
uint256 tokenId;
}
struct InfoFromBidding {
address auctionContractAddress;
address signer;
uint256 amount;
}
// events
event LogDeposed(address user, uint256 amount);
event LogWithdrawalVoucherSubmitted(address user, uint256 amount, bytes32 withdrawalVoucherHash);
event LogAuctionEndVoucherSubmitted(
bytes32 tokenHash,
address tokenContractAddress,
uint256 tokenId,
address indexed seller,
address indexed winner,
uint256 amount,
bytes32 auctionEndVoucherHash
);
event LogSentEthToWinner(address auction, address user, uint256 amount);
event LogSentEthToAuctioneer(address auction, address user, uint256 amount);
event LogSentDepotEth(address user, uint256 amount);
event LogSentRewardsDepotEth(address[] user, uint256[] amount);
event LogError(string version,string error);
event LogErrorWithData(string version, string error, bytes32[] data);
constructor(uint8 _ethereumChainId, uint8 _auctionityChainId) public {
ethereumChainId = _ethereumChainId;
auctionityChainId = _auctionityChainId;
owner = msg.sender;
}
// Modifier
modifier isOwner() {
require(msg.sender == owner, "Sender must be owner");
_;
}
modifier isOracle() {
require(msg.sender == oracle, "Sender must be oracle");
_;
}
function setOracle(address _oracle) public isOwner {
oracle = _oracle;
}
modifier migrationLockable() {
require(!migrationLock || msg.sender == owner, "MIGRATION_LOCKED");
_;
}
function setMigrationLock(bool _lock) public isOwner {
migrationLock = _lock;
}
modifier maintenanceLockable() {
require(!maintenanceLock || msg.sender == owner, "MAINTENANCE_LOCKED");
_;
}
function setMaintenanceLock(bool _lock) public isOwner {
maintenanceLock = _lock;
}
// add depot from user
function addDepotEth(address _user, uint256 _amount) private returns (bool) {
depotEth[_user] = depotEth[_user].add(_amount);
return true;
}
// sub depot from user
function subDepotEth(address _user, uint256 _amount) private returns (bool) {
if(depotEth[_user] < _amount){
return false;
}
depotEth[_user] = depotEth[_user].sub(_amount);
return true;
}
// get amount of user's deposit
function getDepotEth(address _user) public view returns(uint256 _amount) {
return depotEth[_user];
}
// fallback payable function , with revert if is deactivated
function() public payable {
return depositEth();
}
// payable deposit eth
function depositEth() public payable migrationLockable maintenanceLockable {
bytes32[] memory _errorData;
uint256 _amount = uint256(msg.value);
require(_amount > 0, "Amount must be greater than 0");
if(!addDepotEth(msg.sender, _amount)) {
_errorData = new bytes32[](1);
_errorData[0] = bytes32(_amount);
emit LogErrorWithData(version, "DEPOSED_ADD_DATA_FAILED", _errorData);
return;
}
emit LogDeposed(msg.sender, _amount);
}
/**
* withdraw
* @dev Param
* bytes32 r ECDSA signature
* bytes32 s ECDSA signature
* uint8 v ECDSA signature
* address user
* uint256 amount
* bytes32 key : anti replay
* @dev Log
* LogWithdrawalVoucherSubmitted : successful
*/
function withdrawalVoucher(
bytes memory _data,
bytes memory _signedRawTxWithdrawal
) public maintenanceLockable {
bytes32 _withdrawalVoucherHash = keccak256(_signedRawTxWithdrawal);
// if withdrawal voucher is already submitted
if(withdrawalVoucherSubmitted[_withdrawalVoucherHash] == true) {
emit LogError(version, "WITHDRAWAL_VOUCHER_ALREADY_SUBMITED");
return;
}
address _withdrawalSigner;
uint _withdrawalAmount;
(_withdrawalSigner, _withdrawalAmount) = AuctionityLibraryDecodeRawTx.decodeRawTxGetWithdrawalInfo(_signedRawTxWithdrawal, auctionityChainId);
if(_withdrawalAmount == uint256(0)) {
emit LogError(version,'WITHDRAWAL_VOUCHER_AMOUNT_INVALID');
return;
}
if(_withdrawalSigner == address(0)) {
emit LogError(version,'WITHDRAWAL_VOUCHER_SIGNER_INVALID');
return;
}
// if depot is smaller than amount
if(depotEth[_withdrawalSigner] < _withdrawalAmount) {
emit LogError(version,'WITHDRAWAL_VOUCHER_DEPOT_AMOUNT_TOO_LOW');
return;
}
if(!withdrawalVoucherOracleSignatureVerification(_data, _withdrawalSigner, _withdrawalAmount, _withdrawalVoucherHash)) {
emit LogError(version,'WITHDRAWAL_VOUCHER_ORACLE_INVALID_SIGNATURE');
return;
}
// send amount
if(!_withdrawalSigner.send(_withdrawalAmount)) {
emit LogError(version, "WITHDRAWAL_VOUCHER_ETH_TRANSFER_FAILED");
return;
}
subDepotEth(_withdrawalSigner,_withdrawalAmount);
withdrawalVoucherList.push(_withdrawalVoucherHash);
withdrawalVoucherSubmitted[_withdrawalVoucherHash] = true;
emit LogWithdrawalVoucherSubmitted(_withdrawalSigner,_withdrawalAmount, _withdrawalVoucherHash);
}
function withdrawalVoucherOracleSignatureVerification(
bytes memory _data,
address _withdrawalSigner,
uint256 _withdrawalAmount,
bytes32 _withdrawalVoucherHash
) internal view returns (bool)
{
// if oracle is the signer of this auction end voucher
return oracle == AuctionityLibraryDecodeRawTx.ecrecoverSigner(
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(
abi.encodePacked(
address(this),
_withdrawalSigner,
_withdrawalAmount,
_withdrawalVoucherHash
)
)
)
),
_data,
0
);
}
/**
* auctionEndVoucher
* @dev Param
* bytes _data is a concatenate of :
* bytes64 biddingHashProof
* bytes130 rsv ECDSA signature of oracle validation AEV
* bytes transfer token
* bytes _signedRawTxCreateAuction raw transaction with rsv of bidding transaction on auction smart contract
* bytes _signedRawTxBidding raw transaction with rsv of bidding transaction on auction smart contract
* bytes _send list of sending eth
* @dev Log
* LogAuctionEndVoucherSubmitted : successful
*/
function auctionEndVoucher(
bytes memory _data,
bytes memory _signedRawTxCreateAuction,
bytes memory _signedRawTxBidding,
bytes memory _send
) public maintenanceLockable {
bytes32 _auctionEndVoucherHash = keccak256(_signedRawTxCreateAuction);
// if auction end voucher is already submitted
if(auctionEndVoucherSubmitted[_auctionEndVoucherHash] == true) {
emit LogError(version, "AUCTION_END_VOUCHER_ALREADY_SUBMITED");
return;
}
InfoFromCreateAuction memory _infoFromCreateAuction = getInfoFromCreateAuction(_signedRawTxCreateAuction);
address _auctionContractAddress;
address _winnerSigner;
uint256 _winnerAmount;
InfoFromBidding memory _infoFromBidding;
if(_signedRawTxBidding.length > 1) {
_infoFromBidding = getInfoFromBidding(_signedRawTxBidding, _infoFromCreateAuction.tokenHash);
if(!verifyWinnerDepot(_infoFromBidding)) {
return;
}
}
if(!auctionEndVoucherOracleSignatureVerification(
_data,
keccak256(_send),
_infoFromCreateAuction,
_infoFromBidding
)) {
emit LogError(version, "AUCTION_END_VOUCHER_ORACLE_INVALID_SIGNATURE");
return;
}
if(!AuctionityLibraryDeposit.sendTransfer(_infoFromCreateAuction.tokenContractAddress, _data, 97)){
if(_data[97] > 0x01) {// if more than 1 transfer function to call
revert("More than one transfer function to call");
} else {
emit LogError(version, "AUCTION_END_VOUCHER_TRANSFER_FAILED");
return;
}
}
if(_signedRawTxBidding.length > 1) {
if(!sendExchange(_send, _infoFromCreateAuction, _infoFromBidding)) {
return;
}
}
auctionEndVoucherList.push(_auctionEndVoucherHash);
auctionEndVoucherSubmitted[_auctionEndVoucherHash] = true;
emit LogAuctionEndVoucherSubmitted(
_infoFromCreateAuction.tokenHash,
_infoFromCreateAuction.tokenContractAddress,
_infoFromCreateAuction.tokenId,
_infoFromCreateAuction.auctionSeller,
_infoFromBidding.signer,
_infoFromBidding.amount,
_auctionEndVoucherHash
);
}
function getInfoFromCreateAuction(bytes _signedRawTxCreateAuction) internal view returns
(InfoFromCreateAuction memory _infoFromCreateAuction)
{
(
_infoFromCreateAuction.tokenHash,
,
_infoFromCreateAuction.auctionSeller,
_infoFromCreateAuction.tokenContractAddress,
_infoFromCreateAuction.tokenId,
_infoFromCreateAuction.rewardPercent
) = AuctionityLibraryDecodeRawTx.decodeRawTxGetCreateAuctionInfo(_signedRawTxCreateAuction,auctionityChainId);
}
function getInfoFromBidding(bytes _signedRawTxBidding, bytes32 _hashSignedRawTxTokenTransfer) internal returns (InfoFromBidding memory _infoFromBidding) {
bytes32 _hashRawTxTokenTransferFromBid;
(
_hashRawTxTokenTransferFromBid,
_infoFromBidding.auctionContractAddress,
_infoFromBidding.amount,
_infoFromBidding.signer
) = AuctionityLibraryDecodeRawTx.decodeRawTxGetBiddingInfo(_signedRawTxBidding,auctionityChainId);
if(_hashRawTxTokenTransferFromBid != _hashSignedRawTxTokenTransfer) {
emit LogError(version, "AUCTION_END_VOUCHER_hashRawTxTokenTransfer_INVALID");
return;
}
if(_infoFromBidding.amount == uint256(0)){
emit LogError(version, "AUCTION_END_VOUCHER_BIDDING_AMOUNT_INVALID");
return;
}
}
function verifyWinnerDepot(InfoFromBidding memory _infoFromBidding) internal returns(bool) {
// if depot is smaller than amount
if(depotEth[_infoFromBidding.signer] < _infoFromBidding.amount) {
emit LogError(version, "AUCTION_END_VOUCHER_DEPOT_AMOUNT_TOO_LOW");
return false;
}
return true;
}
function sendExchange(
bytes memory _send,
InfoFromCreateAuction memory _infoFromCreateAuction,
InfoFromBidding memory _infoFromBidding
) internal returns(bool) {
if(!subDepotEth(_infoFromBidding.signer, _infoFromBidding.amount)){
emit LogError(version, "AUCTION_END_VOUCHER_DEPOT_AMOUNT_TOO_LOW");
return false;
}
uint offset;
address _sendAddress;
uint256 _sendAmount;
bytes12 _sendAmountGwei;
uint256 _sentAmount;
assembly {
_sendAddress := mload(add(_send,add(offset,0x14)))
_sendAmount := mload(add(_send,add(add(offset,20),0x20)))
}
if(_sendAddress != _infoFromCreateAuction.auctionSeller){
emit LogError(version, "AUCTION_END_VOUCHER_SEND_TO_SELLER_INVALID");
return false;
}
_sentAmount += _sendAmount;
offset += 52;
if(!_sendAddress.send(_sendAmount)) {
revert("Failed to send funds");
}
emit LogSentEthToWinner(_infoFromBidding.auctionContractAddress, _sendAddress, _sendAmount);
if(_infoFromCreateAuction.rewardPercent > 0) {
assembly {
_sendAddress := mload(add(_send,add(offset,0x14)))
_sendAmount := mload(add(_send,add(add(offset,20),0x20)))
}
_sentAmount += _sendAmount;
offset += 52;
if(!_sendAddress.send(_sendAmount)) {
revert("Failed to send funds");
}
emit LogSentEthToAuctioneer(_infoFromBidding.auctionContractAddress, _sendAddress, _sendAmount);
bytes2 _numberOfSendDepositBytes2;
assembly {
_numberOfSendDepositBytes2 := mload(add(_send,add(offset,0x20)))
}
offset += 2;
address[] memory _rewardsAddress = new address[](uint16(_numberOfSendDepositBytes2));
uint256[] memory _rewardsAmount = new uint256[](uint16(_numberOfSendDepositBytes2));
for (uint16 i = 0; i < uint16(_numberOfSendDepositBytes2); i++){
assembly {
_sendAddress := mload(add(_send,add(offset,0x14)))
_sendAmountGwei := mload(add(_send,add(add(offset,20),0x20)))
}
_sendAmount = uint96(_sendAmountGwei) * 1000000000;
_sentAmount += _sendAmount;
offset += 32;
if(!addDepotEth(_sendAddress, _sendAmount)) {
revert("Can't add deposit");
}
_rewardsAddress[i] = _sendAddress;
_rewardsAmount[i] = uint256(_sendAmount);
}
emit LogSentRewardsDepotEth(_rewardsAddress, _rewardsAmount);
}
if(uint256(_infoFromBidding.amount) != _sentAmount) {
revert("Bidding amount is not equal to sent amount");
}
return true;
}
function getTransferDataHash(bytes memory _data) internal returns (bytes32 _transferDataHash){
bytes memory _transferData = new bytes(_data.length - 97);
for (uint i = 0; i < (_data.length - 97); i++) {
_transferData[i] = _data[i + 97];
}
return keccak256(_transferData);
}
function auctionEndVoucherOracleSignatureVerification(
bytes memory _data,
bytes32 _sendDataHash,
InfoFromCreateAuction memory _infoFromCreateAuction,
InfoFromBidding memory _infoFromBidding
) internal returns (bool) {
bytes32 _biddingHashProof;
assembly { _biddingHashProof := mload(add(_data,add(0,0x20))) }
bytes32 _transferDataHash = getTransferDataHash(_data);
// if oracle is the signer of this auction end voucher
return oracle == AuctionityLibraryDecodeRawTx.ecrecoverSigner(
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(
abi.encodePacked(
address(this),
_infoFromCreateAuction.tokenContractAddress,
_infoFromCreateAuction.tokenId,
_infoFromCreateAuction.auctionSeller,
_infoFromBidding.signer,
_infoFromBidding.amount,
_biddingHashProof,
_infoFromCreateAuction.rewardPercent,
_transferDataHash,
_sendDataHash
)
)
)
),
_data,
32
);
}
}File 2 of 7: 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 3 of 7: 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));
}
}File 4 of 7: 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 5 of 7: EtheremonRankData
pragma solidity ^0.4.16;
// copyright contact@Etheremon.com
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 6 of 7: 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 7 of 7: EtheremonTradeData
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 = 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;
}
}