Transaction Hash:
Block:
6533100 at Oct-17-2018 05:17:06 PM +UTC
Transaction Fee:
0.000082398 ETH
$0.20
Gas Used:
41,199 Gas / 2 Gwei
Emitted Events:
113 |
CryptoMiningWar.eventDoQuest( clientNumber=2, randomNumber=2 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x829BD824...93333A830
Miner
| (F2Pool Old) | 4,039.203982892333948567 Eth | 4,039.204065290333948567 Eth | 0.000082398 | |
0x8bCb14c7...4567380dd |
0.063167308694797872 Eth
Nonce: 272
|
0.063084910694797872 Eth
Nonce: 273
| 0.000082398 | ||
0xF84C61bB...Fffb89059 |
Execution Trace
CryptoMiningWar.doQuest( clientNumber=2 )
doQuest[CryptoMiningWar (ln:369)]
add[CryptoMiningWar (ln:372)]
getRandomNumber[CryptoMiningWar (ln:373)]
add[CryptoMiningWar (ln:375)]
eventDoQuest[CryptoMiningWar (ln:377)]
pragma solidity ^0.4.24; /* * CryptoMiningWar - Mining Contest Game * Author: InspiGames * Website: https://cryptominingwar.github.io/ */ library SafeMath { /** * @dev Multiplies two numbers, throws on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; assert(c / a == b); return c; } /** * @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 c; } /** * @dev Substracts 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) { uint256 c = a + b; assert(c >= a); return c; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } } /** * @title PullPayment * @dev Base contract supporting async send for pull payments. Inherit from this * contract and use asyncSend instead of send or transfer. */ contract PullPayment { using SafeMath for uint256; mapping(address => uint256) public payments; uint256 public totalPayments; /** * @dev Withdraw accumulated balance, called by payee. */ function withdrawPayments() public { address payee = msg.sender; uint256 payment = payments[payee]; require(payment != 0); require(address(this).balance >= payment); totalPayments = totalPayments.sub(payment); payments[payee] = 0; payee.transfer(payment); } /** * @dev Called by the payer to store the sent amount as credit to be pulled. * @param dest The destination address of the funds. * @param amount The amount to transfer. */ function asyncSend(address dest, uint256 amount) internal { payments[dest] = payments[dest].add(amount); totalPayments = totalPayments.add(amount); } } interface MiniGameInterface { function setupMiniGame(uint256 _miningWarRoundNumber, uint256 _miningWarDeadline) external; function isContractMiniGame() external pure returns( bool _isContractMiniGame ); } contract CryptoMiningWar is PullPayment { bool public initialized = false; uint256 public roundNumber = 0; uint256 public deadline; uint256 public CRTSTAL_MINING_PERIOD = 86400; uint256 public HALF_TIME = 8 hours; uint256 public ROUND_TIME = 86400 * 7; uint256 public prizePool = 0; uint256 BASE_PRICE = 0.005 ether; uint256 RANK_LIST_LIMIT = 10000; uint256 randNonce = 0; uint256 public totalContractMiniGame = 0; mapping(uint256 => address) public contractsMiniGameAddress; //miner info mapping(uint256 => MinerData) private minerData; uint256 private numberOfMiners; // plyer info mapping(address => PlayerData) public players; //booster info uint256 private numberOfBoosts; mapping(uint256 => BoostData) private boostData; //mini game contract info mapping(address => bool) public miniGames; uint256 private numberOfRank; address[21] rankList; address public sponsor; uint256 public sponsorLevel; address public administrator; /*** DATATYPES ***/ struct PlayerData { uint256 roundNumber; mapping(uint256 => uint256) minerCount; uint256 hashrate; uint256 crystals; uint256 lastUpdateTime; uint256 referral_count; uint256 noQuest; } struct MinerData { uint256 basePrice; uint256 baseProduct; uint256 limit; } struct BoostData { address owner; uint256 boostRate; uint256 startingLevel; uint256 startingTime; uint256 halfLife; } modifier isNotOver() { require(now <= deadline); _; } modifier disableContract() { require(tx.origin == msg.sender); _; } modifier isCurrentRound() { require(players[msg.sender].roundNumber == roundNumber); _; } modifier onlyContractsMiniGame() { require(miniGames[msg.sender] == true); _; } event eventDoQuest( uint clientNumber, uint randomNumber ); constructor() public { administrator = msg.sender; numberOfMiners = 8; numberOfBoosts = 5; numberOfRank = 21; //init miner data // price, prod. limit minerData[0] = MinerData(10, 10, 10); //lv1 minerData[1] = MinerData(100, 200, 2); //lv2 minerData[2] = MinerData(400, 800, 4); //lv3 minerData[3] = MinerData(1600, 3200, 8); //lv4 minerData[4] = MinerData(6400, 9600, 16); //lv5 minerData[5] = MinerData(25600, 38400, 32); //lv6 minerData[6] = MinerData(204800, 204800, 64); //lv7 minerData[7] = MinerData(1638400, 819200, 65536); //lv8 } function () public payable { prizePool = SafeMath.add(prizePool, msg.value); } function startGame() public { require(msg.sender == administrator); require(!initialized); startNewRound(); initialized = true; } /** * @dev add crystals to a player * msg.sender should be in the list of mini game */ function addCrystal( address _addr, uint256 _value ) public onlyContractsMiniGame { require(players[_addr].roundNumber == roundNumber); uint256 crystals = SafeMath.mul(_value, CRTSTAL_MINING_PERIOD); PlayerData storage p = players[_addr]; p.crystals = SafeMath.add( p.crystals, crystals ); } /** * @dev sub player's crystals * msg.sender should be in the list of mini game * @param _addr player address */ function subCrystal( address _addr, uint256 _value ) public onlyContractsMiniGame { require(players[_addr].roundNumber == roundNumber); updateCrystal( _addr ); uint256 crystals = SafeMath.mul(_value,CRTSTAL_MINING_PERIOD); require(crystals <= players[_addr].crystals); PlayerData storage p = players[_addr]; p.crystals = SafeMath.sub( p.crystals, crystals ); } /** * @dev add hashrate to a player. * msg.sender should be in the list of mini game */ function addHashrate( address _addr, uint256 _value ) public onlyContractsMiniGame { require(players[_addr].roundNumber == roundNumber); PlayerData storage p = players[_addr]; p.hashrate = SafeMath.add( p.hashrate, _value ); } /** * @dev sub player's hashrate * msg.sender should be in the list of mini game */ function subHashrate( address _addr, uint256 _value ) public onlyContractsMiniGame { require(players[_addr].roundNumber == roundNumber && players[_addr].hashrate >= _value); PlayerData storage p = players[_addr]; p.hashrate = SafeMath.sub( p.hashrate, _value ); } function setContractsMiniGame( address _contractMiniGameAddress ) public { require(administrator == msg.sender); MiniGameInterface MiniGame = MiniGameInterface( _contractMiniGameAddress ); bool isContractMiniGame = MiniGame.isContractMiniGame(); require( isContractMiniGame == true ); if ( miniGames[_contractMiniGameAddress] == false ) { miniGames[_contractMiniGameAddress] = true; contractsMiniGameAddress[totalContractMiniGame] = _contractMiniGameAddress; totalContractMiniGame = totalContractMiniGame + 1; } } /** * @dev remove mini game contract from main contract * @param _contractMiniGameAddress mini game contract address */ function removeContractMiniGame(address _contractMiniGameAddress) public { require(administrator == msg.sender); miniGames[_contractMiniGameAddress] = false; } function startNewRound() private { deadline = SafeMath.add(now, ROUND_TIME); roundNumber = SafeMath.add(roundNumber, 1); initData(); setupMiniGame(); } function setupMiniGame() private { for ( uint256 index = 0; index < totalContractMiniGame; index++ ) { if (miniGames[contractsMiniGameAddress[index]] == true) { MiniGameInterface MiniGame = MiniGameInterface( contractsMiniGameAddress[index] ); MiniGame.setupMiniGame(roundNumber,deadline); } } } function initData() private { sponsor = administrator; sponsorLevel = 6; //init booster data boostData[0] = BoostData(0, 150, 1, now, HALF_TIME); boostData[1] = BoostData(0, 175, 1, now, HALF_TIME); boostData[2] = BoostData(0, 200, 1, now, HALF_TIME); boostData[3] = BoostData(0, 225, 1, now, HALF_TIME); boostData[4] = BoostData(msg.sender, 250, 2, now, HALF_TIME); for (uint256 idx = 0; idx < numberOfRank; idx++) { rankList[idx] = 0; } } function lottery() public disableContract { require(now > deadline); uint256 balance = SafeMath.div(SafeMath.mul(prizePool, 90), 100); uint256 devFee = SafeMath.div(SafeMath.mul(prizePool, 5), 100); asyncSend(administrator, devFee); uint8[10] memory profit = [30,20,10,8,7,5,5,5,5,5]; uint256 totalPayment = 0; uint256 rankPayment = 0; for(uint256 idx = 0; idx < 10; idx++){ if(rankList[idx] != 0){ rankPayment = SafeMath.div(SafeMath.mul(balance, profit[idx]),100); asyncSend(rankList[idx], rankPayment); totalPayment = SafeMath.add(totalPayment, rankPayment); } } prizePool = SafeMath.add(devFee, SafeMath.sub(balance, totalPayment)); startNewRound(); } function getRankList() public view returns(address[21]) { return rankList; } //sponser function becomeSponsor() public isNotOver payable { require(msg.value >= getSponsorFee()); require(msg.sender != sponsor); uint256 sponsorPrice = getCurrentPrice(sponsorLevel); asyncSend(sponsor, sponsorPrice); prizePool = SafeMath.add(prizePool, SafeMath.sub(msg.value, sponsorPrice)); sponsor = msg.sender; sponsorLevel = SafeMath.add(sponsorLevel, 1); } function getSponsorFee() public view returns(uint256 sponsorFee) { sponsorFee = getCurrentPrice(SafeMath.add(sponsorLevel, 1)); } //-------------------------------------------------------------------------- // Miner //-------------------------------------------------------------------------- /** * @dev get a free miner */ function getFreeMiner() public disableContract isNotOver { require(players[msg.sender].roundNumber != roundNumber); PlayerData storage p = players[msg.sender]; //reset player data if(p.hashrate > 0){ for (uint idx = 1; idx < numberOfMiners; idx++) { p.minerCount[idx] = 0; } } MinerData storage m0 = minerData[0]; p.crystals = 0; p.roundNumber = roundNumber; //free miner p.lastUpdateTime = now; p.referral_count = 0; p.noQuest = 0; p.minerCount[0] = 1; p.hashrate = m0.baseProduct; } function doQuest(uint256 clientNumber) disableContract isCurrentRound isNotOver public { PlayerData storage p = players[msg.sender]; p.noQuest = SafeMath.add(p.noQuest, 1); uint256 randomNumber = getRandomNumber(msg.sender); if(clientNumber == randomNumber) { p.referral_count = SafeMath.add(p.referral_count, 1); } emit eventDoQuest(clientNumber, randomNumber); } function buyMiner(uint256[] minerNumbers) public isNotOver isCurrentRound { require(minerNumbers.length == numberOfMiners); uint256 minerIdx = 0; MinerData memory m; for (; minerIdx < numberOfMiners; minerIdx++) { m = minerData[minerIdx]; if(minerNumbers[minerIdx] > m.limit || minerNumbers[minerIdx] < 0){ revert(); } } updateCrystal(msg.sender); PlayerData storage p = players[msg.sender]; uint256 price = 0; uint256 minerNumber = 0; for (minerIdx = 0; minerIdx < numberOfMiners; minerIdx++) { minerNumber = minerNumbers[minerIdx]; if (minerNumber > 0) { m = minerData[minerIdx]; price = SafeMath.add(price, SafeMath.mul(m.basePrice, minerNumber)); } } price = SafeMath.mul(price, CRTSTAL_MINING_PERIOD); if(p.crystals < price){ revert(); } p.crystals = SafeMath.sub(p.crystals, price); uint256 hashrate = 0; for (minerIdx = 0; minerIdx < numberOfMiners; minerIdx++) { minerNumber = minerNumbers[minerIdx]; if (minerNumber > 0) { m = minerData[minerIdx]; uint256 currentMinerCount = p.minerCount[minerIdx]; p.minerCount[minerIdx] = SafeMath.min(m.limit, SafeMath.add(p.minerCount[minerIdx], minerNumber)); // calculate no hashrate you want buy hashrate = SafeMath.add(hashrate, SafeMath.mul(SafeMath.sub(p.minerCount[minerIdx],currentMinerCount), minerData[minerIdx].baseProduct)); } } updateHashrate(msg.sender, hashrate); } function getPlayerData(address addr) public view returns (uint256 crystals, uint256 lastupdate, uint256 hashratePerDay, uint256[8] miners, uint256 hasBoost, uint256 referral_count, uint256 playerBalance, uint256 noQuest ) { PlayerData storage p = players[addr]; if(p.roundNumber != roundNumber){ p = players[0]; } crystals = SafeMath.div(p.crystals, CRTSTAL_MINING_PERIOD); lastupdate = p.lastUpdateTime; hashratePerDay = addReferralHashrate(addr, p.hashrate); uint256 i = 0; for(i = 0; i < numberOfMiners; i++) { miners[i] = p.minerCount[i]; } hasBoost = hasBooster(addr); referral_count = p.referral_count; noQuest = p.noQuest; playerBalance = payments[addr]; } function getHashratePerDay(address minerAddr) public view returns (uint256 personalProduction) { PlayerData storage p = players[minerAddr]; personalProduction = addReferralHashrate(minerAddr, p.hashrate); uint256 boosterIdx = hasBooster(minerAddr); if (boosterIdx != 999) { BoostData storage b = boostData[boosterIdx]; personalProduction = SafeMath.div(SafeMath.mul(personalProduction, b.boostRate), 100); } } //-------------------------------------------------------------------------- // BOOSTER //-------------------------------------------------------------------------- function buyBooster(uint256 idx) public isNotOver isCurrentRound payable { require(idx < numberOfBoosts); BoostData storage b = boostData[idx]; if(msg.value < getBoosterPrice(idx) || msg.sender == b.owner){ revert(); } address beneficiary = b.owner; uint256 devFeePrize = devFee(getBoosterPrice(idx)); asyncSend(sponsor, devFeePrize); uint256 refundPrize = 0; if(beneficiary != 0){ refundPrize = SafeMath.div(SafeMath.mul(getBoosterPrice(idx), 55), 100); asyncSend(beneficiary, refundPrize); } prizePool = SafeMath.add(prizePool, SafeMath.sub(msg.value, SafeMath.add(devFeePrize, refundPrize))); updateCrystal(msg.sender); updateCrystal(beneficiary); uint256 level = getCurrentLevel(b.startingLevel, b.startingTime, b.halfLife); b.startingLevel = SafeMath.add(level, 1); b.startingTime = now; // transfer ownership b.owner = msg.sender; } function getBoosterData(uint256 idx) public view returns (address owner,uint256 boostRate, uint256 startingLevel, uint256 startingTime, uint256 currentPrice, uint256 halfLife) { require(idx < numberOfBoosts); owner = boostData[idx].owner; boostRate = boostData[idx].boostRate; startingLevel = boostData[idx].startingLevel; startingTime = boostData[idx].startingTime; currentPrice = getBoosterPrice(idx); halfLife = boostData[idx].halfLife; } function getBoosterPrice(uint256 index) public view returns (uint256) { BoostData storage booster = boostData[index]; return getCurrentPrice(getCurrentLevel(booster.startingLevel, booster.startingTime, booster.halfLife)); } function hasBooster(address addr) public view returns (uint256 boostIdx) { boostIdx = 999; for(uint256 i = 0; i < numberOfBoosts; i++){ uint256 revert_i = numberOfBoosts - i - 1; if(boostData[revert_i].owner == addr){ boostIdx = revert_i; break; } } } //-------------------------------------------------------------------------- // Other //-------------------------------------------------------------------------- function devFee(uint256 amount) public pure returns(uint256) { return SafeMath.div(SafeMath.mul(amount, 5), 100); } function getBalance() public view returns(uint256) { return address(this).balance; } //@dev use this function in case of bug function upgrade(address addr) public { require(msg.sender == administrator); selfdestruct(addr); } //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * @param addr is player address you want add hash rate * @param _hashrate is no hashrate you want add for this player */ function updateHashrate(address addr, uint256 _hashrate) private { PlayerData storage p = players[addr]; p.hashrate = SafeMath.add(p.hashrate, _hashrate); if(p.hashrate > RANK_LIST_LIMIT){ updateRankList(addr); } } function updateCrystal(address addr) private { require(now > players[addr].lastUpdateTime); if (players[addr].lastUpdateTime != 0) { PlayerData storage p = players[addr]; uint256 secondsPassed = SafeMath.sub(now, p.lastUpdateTime); uint256 revenue = getHashratePerDay(addr); p.lastUpdateTime = now; if (revenue > 0) { revenue = SafeMath.mul(revenue, secondsPassed); p.crystals = SafeMath.add(p.crystals, revenue); } } } function addReferralHashrate(address addr, uint256 hashrate) private view returns(uint256 personalProduction) { PlayerData storage p = players[addr]; if(p.referral_count < 5){ personalProduction = SafeMath.add(hashrate, SafeMath.mul(p.referral_count, 10)); }else if(p.referral_count < 10){ personalProduction = SafeMath.add(hashrate, SafeMath.add(50, SafeMath.mul(p.referral_count, 10))); }else{ personalProduction = SafeMath.add(hashrate, 200); } } function getCurrentLevel(uint256 startingLevel, uint256 startingTime, uint256 halfLife) private view returns(uint256) { uint256 timePassed=SafeMath.sub(now, startingTime); uint256 levelsPassed=SafeMath.div(timePassed, halfLife); if (startingLevel < levelsPassed) { return 0; } return SafeMath.sub(startingLevel, levelsPassed); } function getCurrentPrice(uint256 currentLevel) private view returns(uint256) { return SafeMath.mul(BASE_PRICE, 2**currentLevel); } function updateRankList(address addr) private returns(bool) { uint256 idx = 0; PlayerData storage insert = players[addr]; PlayerData storage lastOne = players[rankList[19]]; if(insert.hashrate < lastOne.hashrate) { return false; } address[21] memory tempList = rankList; if(!inRankList(addr)){ tempList[20] = addr; quickSort(tempList, 0, 20); }else{ quickSort(tempList, 0, 19); } for(idx = 0;idx < 21; idx++){ if(tempList[idx] != rankList[idx]){ rankList[idx] = tempList[idx]; } } return true; } function inRankList(address addr) internal view returns(bool) { for(uint256 idx = 0;idx < 20; idx++){ if(addr == rankList[idx]){ return true; } } return false; } function getRandomNumber(address playerAddress) internal returns(uint256 randomNumber) { randNonce++; randomNumber = uint256(keccak256(abi.encodePacked(now, playerAddress, randNonce))) % 3; } function quickSort(address[21] list, int left, int right) internal { int i = left; int j = right; if(i == j) return; address addr = list[uint(left + (right - left) / 2)]; PlayerData storage p = players[addr]; while (i <= j) { while (players[list[uint(i)]].hashrate > p.hashrate) i++; while (p.hashrate > players[list[uint(j)]].hashrate) j--; if (i <= j) { (list[uint(i)], list[uint(j)]) = (list[uint(j)], list[uint(i)]); i++; j--; } } if (left < j) quickSort(list, left, j); if (i < right) quickSort(list, i, right); } }