Transaction Hash:
Block:
6172303 at Aug-18-2018 11:38:50 PM +UTC
Transaction Fee:
0.000313041 ETH
$0.67
Gas Used:
104,347 Gas / 3 Gwei
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x4F92e00F...d333D7a98 |
0.077495947 Eth
Nonce: 74
|
0.077182906 Eth
Nonce: 75
| 0.000313041 | ||
| 0x8F4D305a...634E85143 | |||||
|
0xEA674fdD...16B898ec8
Miner
| (Ethermine) | 1,102.260015755909544987 Eth | 1,102.260328796909544987 Eth | 0.000313041 |
Execution Trace
SpaceWar.Attack( defenderAddr=0xdFb55A79761102f07115A82266e78Ef56E8AD002 )
Attack[SpaceWar (ln:539)]
UpdateMoneyAt[SpaceWar (ln:572)]GetProductionPerSecond[SpaceWar (ln:443)]HasBooster[SpaceWar (ln:228)]
sub[SpaceWar (ln:598)]
pragma solidity ^0.4.18;
/**
* SpaceWar
* ETH Idle Game
* spacewar.etherfun.net
*/
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
require(c >= a);
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b <= a);
c = a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a * b;
require(a == 0 || c / a == b);
}
}
library NumericSequence
{
using SafeMath for uint256;
function sumOfN(uint256 basePrice, uint256 pricePerLevel, uint256 owned, uint256 count) internal pure returns (uint256 price)
{
require(count > 0);
price = 0;
price += SafeMath.mul((basePrice + pricePerLevel * owned), count);
price += pricePerLevel * (count.mul((count-1))) / 2;
}
}
//-----------------------------------------------------------------------
contract SpaceWar {
using NumericSequence for uint;
using SafeMath for uint;
struct MinerData
{
uint256[9] spaces; // space types and their upgrades
uint8[3] hasUpgrade;
uint256 money;
uint256 lastUpdateTime;
uint256 premamentMineBonusPct;
uint256 unclaimedPot;
uint256 lastPotClaimIndex;
}
struct SpaceData
{
uint256 basePrice;
uint256 baseOutput;
uint256 pricePerLevel;
uint256 priceInETH;
uint256 limit;
}
struct BoostData
{
uint256 percentBonus;
uint256 priceInWEI;
}
struct PVPData
{
uint256[6] troops;
uint256 immunityTime;
uint256 exhaustTime;
}
struct TroopData
{
uint256 attackPower;
uint256 defensePower;
uint256 priceGold;
uint256 priceETH;
}
uint8 private constant NUMBER_OF_RIG_TYPES = 9;
SpaceData[9] private spaceData;
uint8 private constant NUMBER_OF_UPGRADES = 3;
BoostData[3] private boostData;
uint8 private constant NUMBER_OF_TROOPS = 6;
uint8 private constant ATTACKER_START_IDX = 0;
uint8 private constant ATTACKER_END_IDX = 3;
uint8 private constant DEFENDER_START_IDX = 3;
uint8 private constant DEFENDER_END_IDX = 6;
TroopData[6] private troopData;
// honey pot variables
uint256 private honeyPotAmount;
uint256 private honeyPotSharePct; // 90%
uint256 private jackPot;
uint256 private devFund;
uint256 private nextPotDistributionTime;
mapping(address => mapping(uint256 => uint256)) private minerICOPerCycle;
uint256[] private honeyPotPerCycle;
uint256[] private globalICOPerCycle;
uint256 private cycleCount;
//booster info
uint256 private constant NUMBER_OF_BOOSTERS = 5;
uint256 private boosterIndex;
uint256 private nextBoosterPrice;
address[5] private boosterHolders;
mapping(address => MinerData) private miners;
mapping(address => PVPData) private pvpMap;
mapping(uint256 => address) private indexes;
uint256 private topindex;
address private owner;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
function SpaceWar() public {
owner = msg.sender;
// price, prod. upgrade, priceETH, limit
spaceData[0] = SpaceData(500, 1, 5, 0, 999);
spaceData[1] = SpaceData(50000, 10, 500, 0, 999);
spaceData[2] = SpaceData(5000000, 100, 50000, 0, 999);
spaceData[3] = SpaceData(80000000, 1000, 800000, 0, 999);
spaceData[4] = SpaceData(500000000, 20000, 5000000, 0.01 ether, 999);
spaceData[5] = SpaceData(10000000000, 100000, 100000000, 0, 999);
spaceData[6] = SpaceData(100000000000, 1000000, 1000000000, 0, 999);
spaceData[7] = SpaceData(1000000000000, 50000000, 10000000000, 0.1 ether, 999);
spaceData[8] = SpaceData(10000000000000, 100000000,100000000000, 0, 999);
boostData[0] = BoostData(30, 0.01 ether);
boostData[1] = BoostData(50, 0.1 ether);
boostData[2] = BoostData(100, 1 ether);
topindex = 0;
honeyPotAmount = 0;
devFund = 0;
jackPot = 0;
nextPotDistributionTime = block.timestamp;
honeyPotSharePct = 90;
// has to be set to a value
boosterHolders[0] = owner;
boosterHolders[1] = owner;
boosterHolders[2] = owner;
boosterHolders[3] = owner;
boosterHolders[4] = owner;
boosterIndex = 0;
nextBoosterPrice = 0.1 ether;
//pvp
troopData[0] = TroopData(10, 0, 100000, 0);
troopData[1] = TroopData(1000, 0, 80000000, 0);
troopData[2] = TroopData(100000, 0, 1000000000, 0.01 ether);
troopData[3] = TroopData(0, 15, 100000, 0);
troopData[4] = TroopData(0, 1500, 80000000, 0);
troopData[5] = TroopData(0, 150000, 1000000000, 0.01 ether);
honeyPotPerCycle.push(0);
globalICOPerCycle.push(1);
cycleCount = 0;
}
//--------------------------------------------------------------------------
// Data access functions
//--------------------------------------------------------------------------
function GetMinerData(address minerAddr) public constant returns
(uint256 money, uint256 lastupdate, uint256 prodPerSec,
uint256[9] spaces, uint[3] upgrades, uint256 unclaimedPot, bool hasBooster, uint256 unconfirmedMoney)
{
uint8 i = 0;
money = miners[minerAddr].money;
lastupdate = miners[minerAddr].lastUpdateTime;
prodPerSec = GetProductionPerSecond(minerAddr);
for(i = 0; i < NUMBER_OF_RIG_TYPES; ++i)
{
spaces[i] = miners[minerAddr].spaces[i];
}
for(i = 0; i < NUMBER_OF_UPGRADES; ++i)
{
upgrades[i] = miners[minerAddr].hasUpgrade[i];
}
unclaimedPot = miners[minerAddr].unclaimedPot;
hasBooster = HasBooster(minerAddr);
unconfirmedMoney = money + (prodPerSec * (now - lastupdate));
}
function GetTotalMinerCount() public constant returns (uint256 count)
{
count = topindex;
}
function GetMinerAt(uint256 idx) public constant returns (address minerAddr)
{
require(idx < topindex);
minerAddr = indexes[idx];
}
function GetPotInfo() public constant returns (uint256 _honeyPotAmount, uint256 _devFunds, uint256 _jackPot, uint256 _nextDistributionTime)
{
_honeyPotAmount = honeyPotAmount;
_devFunds = devFund;
_jackPot = jackPot;
_nextDistributionTime = nextPotDistributionTime;
}
function GetProductionPerSecond(address minerAddr) public constant returns (uint256 personalProduction)
{
MinerData storage m = miners[minerAddr];
personalProduction = 0;
uint256 productionSpeed = 100 + m.premamentMineBonusPct;
if(HasBooster(minerAddr)) // 100% bonus
productionSpeed += 100;
for(uint8 j = 0; j < NUMBER_OF_RIG_TYPES; ++j)
{
personalProduction += m.spaces[j] * spaceData[j].baseOutput;
}
personalProduction = personalProduction * productionSpeed / 100;
}
function GetGlobalProduction() public constant returns (uint256 globalMoney, uint256 globalHashRate)
{
globalMoney = 0;
globalHashRate = 0;
uint i = 0;
for(i = 0; i < topindex; ++i)
{
MinerData storage m = miners[indexes[i]];
globalMoney += m.money;
globalHashRate += GetProductionPerSecond(indexes[i]);
}
}
function GetBoosterData() public constant returns (address[5] _boosterHolders, uint256 currentPrice, uint256 currentIndex)
{
for(uint i = 0; i < NUMBER_OF_BOOSTERS; ++i)
{
_boosterHolders[i] = boosterHolders[i];
}
currentPrice = nextBoosterPrice;
currentIndex = boosterIndex;
}
function HasBooster(address addr) public constant returns (bool hasBoost)
{
for(uint i = 0; i < NUMBER_OF_BOOSTERS; ++i)
{
if(boosterHolders[i] == addr)
return true;
}
return false;
}
function GetPVPData(address addr) public constant returns (uint256 attackpower, uint256 defensepower, uint256 immunityTime, uint256 exhaustTime,
uint256[6] troops)
{
PVPData storage a = pvpMap[addr];
immunityTime = a.immunityTime;
exhaustTime = a.exhaustTime;
attackpower = 0;
defensepower = 0;
for(uint i = 0; i < NUMBER_OF_TROOPS; ++i)
{
attackpower += a.troops[i] * troopData[i].attackPower;
defensepower += a.troops[i] * troopData[i].defensePower;
troops[i] = a.troops[i];
}
}
function GetCurrentICOCycle() public constant returns (uint256)
{
return cycleCount;
}
function GetICOData(uint256 idx) public constant returns (uint256 ICOFund, uint256 ICOPot)
{
require(idx <= cycleCount);
ICOFund = globalICOPerCycle[idx];
if(idx < cycleCount)
{
ICOPot = honeyPotPerCycle[idx];
} else
{
ICOPot = honeyPotAmount / 10; // actual day estimate
}
}
function GetMinerICOData(address miner, uint256 idx) public constant returns (uint256 ICOFund, uint256 ICOShare, uint256 lastClaimIndex)
{
require(idx <= cycleCount);
ICOFund = minerICOPerCycle[miner][idx];
if(idx < cycleCount)
{
ICOShare = (honeyPotPerCycle[idx] * minerICOPerCycle[miner][idx]) / globalICOPerCycle[idx];
} else
{
ICOShare = (honeyPotAmount / 10) * minerICOPerCycle[miner][idx] / globalICOPerCycle[idx];
}
lastClaimIndex = miners[miner].lastPotClaimIndex;
}
function GetMinerUnclaimedICOShare(address miner) public constant returns (uint256 unclaimedPot)
{
MinerData storage m = miners[miner];
require(m.lastUpdateTime != 0);
require(m.lastPotClaimIndex < cycleCount);
uint256 i = m.lastPotClaimIndex;
uint256 limit = cycleCount;
if((limit - i) > 30) // more than 30 iterations(days) afk
limit = i + 30;
unclaimedPot = 0;
for(; i < cycleCount; ++i)
{
if(minerICOPerCycle[miner][i] > 0)
unclaimedPot += (honeyPotPerCycle[i] * minerICOPerCycle[miner][i]) / globalICOPerCycle[i];
}
}
// -------------------------------------------------------------------------
// SpaceWars game handler functions
// -------------------------------------------------------------------------
function StartNewMiner() external
{
require(miners[msg.sender].lastUpdateTime == 0);
miners[msg.sender].lastUpdateTime = block.timestamp;
miners[msg.sender].money = 0;
miners[msg.sender].spaces[0] = 1;
miners[msg.sender].unclaimedPot = 0;
miners[msg.sender].lastPotClaimIndex = cycleCount;
pvpMap[msg.sender].immunityTime = block.timestamp + 14400;
pvpMap[msg.sender].exhaustTime = block.timestamp;
indexes[topindex] = msg.sender;
++topindex;
}
function UpgradeSpace(uint8 spaceIdx, uint16 count) external
{
require(spaceIdx < NUMBER_OF_RIG_TYPES);
require(count > 0);
require(count <= 999);
require(spaceData[spaceIdx].priceInETH == 0);
MinerData storage m = miners[msg.sender];
require(spaceData[spaceIdx].limit >= (m.spaces[spaceIdx] + count));
UpdateMoney();
// the base of geometrical sequence
uint256 price = NumericSequence.sumOfN(spaceData[spaceIdx].basePrice, spaceData[spaceIdx].pricePerLevel, m.spaces[spaceIdx], count);
require(m.money >= price);
m.spaces[spaceIdx] = m.spaces[spaceIdx] + count;
if(m.spaces[spaceIdx] > spaceData[spaceIdx].limit)
m.spaces[spaceIdx] = spaceData[spaceIdx].limit;
m.money -= price;
}
function UpgradeSpaceETH(uint8 spaceIdx, uint256 count) external payable
{
require(spaceIdx < NUMBER_OF_RIG_TYPES);
require(count > 0);
require(count <= 999);
require(spaceData[spaceIdx].priceInETH > 0);
MinerData storage m = miners[msg.sender];
require(spaceData[spaceIdx].limit >= (m.spaces[spaceIdx] + count));
uint256 price = (spaceData[spaceIdx].priceInETH).mul(count);
uint256 priceCoin = NumericSequence.sumOfN(spaceData[spaceIdx].basePrice, spaceData[spaceIdx].pricePerLevel, m.spaces[spaceIdx], count);
UpdateMoney();
require(msg.value >= price);
require(m.money >= priceCoin);
BuyHandler(msg.value);
m.spaces[spaceIdx] = m.spaces[spaceIdx] + count;
if(m.spaces[spaceIdx] > spaceData[spaceIdx].limit)
m.spaces[spaceIdx] = spaceData[spaceIdx].limit;
m.money -= priceCoin;
}
function UpdateMoney() private
{
require(miners[msg.sender].lastUpdateTime != 0);
require(block.timestamp >= miners[msg.sender].lastUpdateTime);
MinerData storage m = miners[msg.sender];
uint256 diff = block.timestamp - m.lastUpdateTime;
uint256 revenue = GetProductionPerSecond(msg.sender);
m.lastUpdateTime = block.timestamp;
if(revenue > 0)
{
revenue *= diff;
m.money += revenue;
}
}
function UpdateMoneyAt(address addr) private
{
require(miners[addr].lastUpdateTime != 0);
require(block.timestamp >= miners[addr].lastUpdateTime);
MinerData storage m = miners[addr];
uint256 diff = block.timestamp - m.lastUpdateTime;
uint256 revenue = GetProductionPerSecond(addr);
m.lastUpdateTime = block.timestamp;
if(revenue > 0)
{
revenue *= diff;
m.money += revenue;
}
}
function BuyUpgrade(uint256 idx) external payable
{
require(idx < NUMBER_OF_UPGRADES);
require(msg.value >= boostData[idx].priceInWEI);
require(miners[msg.sender].hasUpgrade[idx] == 0);
require(miners[msg.sender].lastUpdateTime != 0);
BuyHandler(msg.value);
UpdateMoney();
miners[msg.sender].hasUpgrade[idx] = 1;
miners[msg.sender].premamentMineBonusPct += boostData[idx].percentBonus;
}
//--------------------------------------------------------------------------
// BOOSTER handlers
//--------------------------------------------------------------------------
function BuyBooster() external payable
{
require(msg.value >= nextBoosterPrice);
require(miners[msg.sender].lastUpdateTime != 0);
for(uint i = 0; i < NUMBER_OF_BOOSTERS; ++i)
if(boosterHolders[i] == msg.sender)
revert();
address beneficiary = boosterHolders[boosterIndex];
MinerData storage m = miners[beneficiary];
// 20% interest after 5 buys
m.unclaimedPot += (msg.value * 9403) / 10000;
// distribute the rest
honeyPotAmount += (msg.value * 597) / 20000;
devFund += (msg.value * 597) / 20000;
// increase price by 5%
nextBoosterPrice += nextBoosterPrice / 20;
UpdateMoney();
UpdateMoneyAt(beneficiary);
// transfer ownership
boosterHolders[boosterIndex] = msg.sender;
// increase booster index
boosterIndex += 1;
if(boosterIndex >= 5)
boosterIndex = 0;
}
//--------------------------------------------------------------------------
// PVP handler
//--------------------------------------------------------------------------
// 0 for attacker 1 for defender
function BuyTroop(uint256 idx, uint256 count) external payable
{
require(idx < NUMBER_OF_TROOPS);
require(count > 0);
require(count <= 1000);
PVPData storage pvp = pvpMap[msg.sender];
MinerData storage m = miners[msg.sender];
uint256 owned = pvp.troops[idx];
uint256 priceGold = NumericSequence.sumOfN(troopData[idx].priceGold, troopData[idx].priceGold / 100, owned, count);
uint256 priceETH = (troopData[idx].priceETH).mul(count);
UpdateMoney();
require(m.money >= priceGold);
require(msg.value >= priceETH);
if(priceGold > 0)
m.money -= priceGold;
if(msg.value > 0)
BuyHandler(msg.value);
pvp.troops[idx] += count;
}
function Attack(address defenderAddr) external
{
require(msg.sender != defenderAddr);
require(miners[msg.sender].lastUpdateTime != 0);
require(miners[defenderAddr].lastUpdateTime != 0);
PVPData storage attacker = pvpMap[msg.sender];
PVPData storage defender = pvpMap[defenderAddr];
uint i = 0;
uint256 count = 0;
require(block.timestamp > attacker.exhaustTime);
require(block.timestamp > defender.immunityTime);
// the aggressor loses immunity
if(attacker.immunityTime > block.timestamp)
attacker.immunityTime = block.timestamp - 1;
attacker.exhaustTime = block.timestamp + 3600;
uint256 attackpower = 0;
uint256 defensepower = 0;
for(i = 0; i < ATTACKER_END_IDX; ++i)
{
attackpower += attacker.troops[i] * troopData[i].attackPower;
defensepower += defender.troops[i + DEFENDER_START_IDX] * troopData[i + DEFENDER_START_IDX].defensePower;
}
if(attackpower > defensepower)
{
if(defender.immunityTime < block.timestamp + 14400)
defender.immunityTime = block.timestamp + 14400;
UpdateMoneyAt(defenderAddr);
MinerData storage m = miners[defenderAddr];
MinerData storage m2 = miners[msg.sender];
uint256 moneyStolen = m.money / 2;
for(i = DEFENDER_START_IDX; i < DEFENDER_END_IDX; ++i)
{
defender.troops[i] = defender.troops[i]/2;
}
for(i = ATTACKER_START_IDX; i < ATTACKER_END_IDX; ++i)
{
if(troopData[i].attackPower > 0)
{
count = attacker.troops[i];
// if the troops overpower the total defense power only a fraction is lost
if((count * troopData[i].attackPower) > defensepower)
{
count = count * defensepower / attackpower / 2;
}
else
{
count = count/2;
}
attacker.troops[i] = SafeMath.sub(attacker.troops[i],count);
defensepower -= count * troopData[i].attackPower;
}
}
m.money -= moneyStolen;
m2.money += moneyStolen;
} else
{
for(i = ATTACKER_START_IDX; i < ATTACKER_END_IDX; ++i)
{
attacker.troops[i] = attacker.troops[i] / 2;
}
for(i = DEFENDER_START_IDX; i < DEFENDER_END_IDX; ++i)
{
if(troopData[i].defensePower > 0)
{
count = defender.troops[i];
// if the troops overpower the total defense power only a fraction is lost
if((count * troopData[i].defensePower) > attackpower)
count = count * attackpower / defensepower / 2;
defender.troops[i] -= count;
attackpower -= count * troopData[i].defensePower;
}
}
}
}
//--------------------------------------------------------------------------
// ICO/Pot share functions
//--------------------------------------------------------------------------
function ReleaseICO() external
{
require(miners[msg.sender].lastUpdateTime != 0);
require(nextPotDistributionTime <= block.timestamp);
require(honeyPotAmount > 0);
require(globalICOPerCycle[cycleCount] > 0);
nextPotDistributionTime = block.timestamp + 86400;
honeyPotPerCycle[cycleCount] = honeyPotAmount / 10; // 10% of the pot
honeyPotAmount -= honeyPotAmount / 10;
honeyPotPerCycle.push(0);
globalICOPerCycle.push(0);
cycleCount = cycleCount + 1;
MinerData storage jakpotWinner = miners[msg.sender];
jakpotWinner.unclaimedPot += jackPot;
jackPot = 0;
}
function FundICO(uint amount) external
{
require(miners[msg.sender].lastUpdateTime != 0);
require(amount > 0);
MinerData storage m = miners[msg.sender];
UpdateMoney();
require(m.money >= amount);
m.money = (m.money).sub(amount);
globalICOPerCycle[cycleCount] = globalICOPerCycle[cycleCount].add(uint(amount));
minerICOPerCycle[msg.sender][cycleCount] = minerICOPerCycle[msg.sender][cycleCount].add(uint(amount));
}
function WithdrawICOEarnings() external
{
MinerData storage m = miners[msg.sender];
require(miners[msg.sender].lastUpdateTime != 0);
require(miners[msg.sender].lastPotClaimIndex < cycleCount);
uint256 i = m.lastPotClaimIndex;
uint256 limit = cycleCount;
if((limit - i) > 30) // more than 30 iterations(days) afk
limit = i + 30;
m.lastPotClaimIndex = limit;
for(; i < cycleCount; ++i)
{
if(minerICOPerCycle[msg.sender][i] > 0)
m.unclaimedPot += (honeyPotPerCycle[i] * minerICOPerCycle[msg.sender][i]) / globalICOPerCycle[i];
}
}
//--------------------------------------------------------------------------
// ETH handler functions
//--------------------------------------------------------------------------
function BuyHandler(uint amount) private
{
// add 90% to honeyPot
honeyPotAmount += (amount * honeyPotSharePct) / 100;
jackPot += amount / 100;
devFund += (amount * (100-(honeyPotSharePct+1))) / 100;
}
function WithdrawPotShare() public
{
MinerData storage m = miners[msg.sender];
require(m.unclaimedPot > 0);
require(m.lastUpdateTime != 0);
uint256 amntToSend = m.unclaimedPot;
m.unclaimedPot = 0;
if(msg.sender.send(amntToSend))
{
m.unclaimedPot = 0;
}
}
function WithdrawDevFunds() public
{
require(msg.sender == owner);
if(owner.send(devFund))
{
devFund = 0;
}
}
// fallback payment to pot
function() public payable {
devFund += msg.value;
}
}