文件 1 的 1:Minewar.sol
pragma solidity ^0.4.2;
library SafeMath {
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;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a / b;
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
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;
}
}
contract Minewar {
uint256 round = 0;
uint256 public deadline;
uint256 public CRTSTAL_MINING_PERIOD = 86400;
uint256 public SHARE_CRYSTAL = 10 * CRTSTAL_MINING_PERIOD;
uint256 public HALF_TIME = 12 hours;
uint256 public ROUND_TIME = 7 days;
uint256 BASE_PRICE = 0.005 ether;
uint256 RANK_LIST_LIMIT = 1000;
mapping(uint256 => MinerData) private minerData;
uint256 private numberOfMiners;
mapping(address => PlyerData) private players;
uint256 private numberOfBoosts;
mapping(uint256 => BoostData) private boostData;
uint256 private numberOfOrders;
mapping(uint256 => BuyOrderData) private buyOrderData;
mapping(uint256 => SellOrderData) private sellOrderData;
uint256 private numberOfRank;
address[21] rankList;
address public sponsor;
uint256 public sponsorLevel;
address public administrator;
struct PlyerData {
uint256 round;
mapping(uint256 => uint256) minerCount;
uint256 hashrate;
uint256 crystals;
uint256 lastUpdateTime;
}
struct MinerData {
uint256 basePrice;
uint256 baseProduct;
uint256 limit;
}
struct BoostData {
address owner;
uint256 boostRate;
uint256 startingLevel;
uint256 startingTime;
uint256 halfLife;
}
struct BuyOrderData {
address owner;
string title;
string description;
uint256 unitPrice;
uint256 amount;
}
struct SellOrderData {
address owner;
string title;
string description;
uint256 unitPrice;
uint256 amount;
}
function Minewar() public
{
administrator = msg.sender;
numberOfMiners = 8;
numberOfBoosts = 5;
numberOfOrders = 5;
numberOfRank = 21;
minerData[0] = MinerData(10, 10, 10);
minerData[1] = MinerData(100, 200, 2);
minerData[2] = MinerData(400, 800, 4);
minerData[3] = MinerData(1600, 3200, 8);
minerData[4] = MinerData(6400, 12800, 16);
minerData[5] = MinerData(25600, 51200, 32);
minerData[6] = MinerData(204800, 409600, 64);
minerData[7] = MinerData(1638400, 1638400, 65536);
startNewRound();
}
function startNewRound() private
{
deadline = SafeMath.add(now, ROUND_TIME);
round = SafeMath.add(round, 1);
initData();
}
function initData() private
{
sponsor = administrator;
sponsorLevel = 5;
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);
uint256 idx;
for (idx = 0; idx < numberOfOrders; idx++) {
buyOrderData[idx] = BuyOrderData(0, "title", "description", 0, 0);
sellOrderData[idx] = SellOrderData(0, "title", "description", 0, 0);
}
for (idx = 0; idx < numberOfRank; idx++) {
rankList[idx] = 0;
}
}
function lottery() public
{
require(now >= deadline);
uint256 balance = SafeMath.div(SafeMath.mul(this.balance, 90), 100);
administrator.transfer(SafeMath.div(SafeMath.mul(this.balance, 5), 100));
uint8[10] memory profit = [30,20,10,8,7,5,5,5,5,5];
for(uint256 idx = 0; idx < 10; idx++){
if(rankList[idx] != 0){
rankList[idx].transfer(SafeMath.div(SafeMath.mul(balance,profit[idx]),100));
}
}
startNewRound();
}
function getRankList() public view returns(address[21])
{
return rankList;
}
function becomeSponsor() public payable
{
require(now <= deadline);
require(msg.value >= getSponsorFee());
sponsor.transfer(getCurrentPrice(sponsorLevel));
sponsor = msg.sender;
sponsorLevel = SafeMath.add(sponsorLevel, 1);
}
function getSponsorFee() public view returns(uint256 sponsorFee)
{
sponsorFee = getCurrentPrice(SafeMath.add(sponsorLevel, 1));
}
function getFreeMiner(address ref) public
{
require(now <= deadline);
PlyerData storage p = players[msg.sender];
require(p.round != round);
if(p.hashrate > 0){
for (uint idx = 1; idx < numberOfMiners; idx++) {
p.minerCount[idx] = 0;
}
}
p.crystals = 0;
p.round = round;
p.lastUpdateTime = now;
p.minerCount[0] = 1;
MinerData storage m0 = minerData[0];
p.hashrate = m0.baseProduct;
if (ref != msg.sender) {
PlyerData storage referral = players[ref];
if(referral.round == round){
p.crystals = SafeMath.add(p.crystals, SHARE_CRYSTAL);
referral.crystals = SafeMath.add(referral.crystals, SHARE_CRYSTAL);
}
}
}
function buyMiner(uint256[] minerNumbers) public
{
require(now <= deadline);
require(players[msg.sender].round == round);
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();
}
}
updateCrytal(msg.sender);
PlyerData 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();
}
for (minerIdx = 0; minerIdx < numberOfMiners; minerIdx++) {
minerNumber = minerNumbers[minerIdx];
if (minerNumber > 0) {
m = minerData[minerIdx];
p.minerCount[minerIdx] = SafeMath.min(m.limit, SafeMath.add(p.minerCount[minerIdx], minerNumber));
}
}
p.crystals = SafeMath.sub(p.crystals, price);
updateHashrate(msg.sender);
}
function getPlayerData(address addr) public view returns (uint256 crystals, uint256 lastupdate, uint256 hashratePerDay,
uint256[8] miners, uint256 hasBoost)
{
PlyerData storage p = players[addr];
if(p.round != round){
p = players[0];
}
crystals = SafeMath.div(p.crystals, CRTSTAL_MINING_PERIOD);
lastupdate = p.lastUpdateTime;
hashratePerDay = p.hashrate;
uint256 i = 0;
for(i = 0; i < numberOfMiners; i++)
{
miners[i] = p.minerCount[i];
}
hasBoost = hasBooster(addr);
}
function getHashratePerDay(address minerAddr) public view returns (uint256 personalProduction)
{
PlyerData storage p = players[minerAddr];
personalProduction = p.hashrate;
uint256 boosterIdx = hasBooster(minerAddr);
if (boosterIdx != 999) {
BoostData storage b = boostData[boosterIdx];
personalProduction = SafeMath.div(SafeMath.mul(personalProduction, b.boostRate), 100);
}
}
function buyBooster(uint256 idx) public payable
{
require(now <= deadline);
require(players[msg.sender].round == round);
require(idx < numberOfBoosts);
BoostData storage b = boostData[idx];
if(msg.value < getBoosterPrice(idx) || msg.sender == b.owner){
revert();
}
address beneficiary = b.owner;
sponsor.transfer(devFee(getBoosterPrice(idx)));
beneficiary.transfer(getBoosterPrice(idx) / 2);
updateCrytal(msg.sender);
updateCrytal(beneficiary);
uint256 level = getCurrentLevel(b.startingLevel, b.startingTime, b.halfLife);
b.startingLevel = SafeMath.add(level, 1);
b.startingTime = now;
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;
}
}
}
function buyCrystalDemand(uint256 amount, uint256 unitPrice,string title, string description) public payable
{
require(now <= deadline);
require(players[msg.sender].round == round);
require(unitPrice > 0);
require(amount >= 1000);
require(amount * unitPrice <= msg.value);
uint256 lowestIdx = getLowestUnitPriceIdxFromBuy();
BuyOrderData storage o = buyOrderData[lowestIdx];
if(o.amount > 10 && unitPrice <= o.unitPrice){
revert();
}
uint256 balance = SafeMath.mul(o.amount, o.unitPrice);
if (o.owner != 0){
o.owner.transfer(balance);
}
o.owner = msg.sender;
o.unitPrice = unitPrice;
o.title = title;
o.description = description;
o.amount = amount;
}
function sellCrystal(uint256 amount, uint256 index) public
{
require(now <= deadline);
require(players[msg.sender].round == round);
require(index < numberOfOrders);
require(amount > 0);
BuyOrderData storage o = buyOrderData[index];
require(amount <= o.amount);
updateCrytal(msg.sender);
PlyerData storage seller = players[msg.sender];
PlyerData storage buyer = players[o.owner];
require(seller.crystals >= amount * CRTSTAL_MINING_PERIOD);
uint256 price = SafeMath.mul(amount, o.unitPrice);
uint256 fee = devFee(price);
sponsor.transfer(fee);
administrator.transfer(fee);
buyer.crystals = SafeMath.add(buyer.crystals, amount * CRTSTAL_MINING_PERIOD);
seller.crystals = SafeMath.sub(seller.crystals, amount * CRTSTAL_MINING_PERIOD);
o.amount = SafeMath.sub(o.amount, amount);
msg.sender.transfer(SafeMath.div(price, 2));
}
function withdrawBuyDemand(uint256 index) public
{
require(now <= deadline);
require(index < numberOfOrders);
require(players[msg.sender].round == round);
BuyOrderData storage o = buyOrderData[index];
require(o.owner == msg.sender);
if(o.amount > 0){
uint256 balance = SafeMath.mul(o.amount, o.unitPrice);
o.owner.transfer(balance);
}
o.unitPrice = 0;
o.amount = 0;
o.title = "title";
o.description = "description";
o.owner = 0;
}
function getBuyDemand(uint256 index) public view returns(address owner, string title, string description,
uint256 amount, uint256 unitPrice)
{
require(index < numberOfOrders);
BuyOrderData storage o = buyOrderData[index];
owner = o.owner;
title = o.title;
description = o.description;
amount = o.amount;
unitPrice = o.unitPrice;
}
function getLowestUnitPriceIdxFromBuy() public returns(uint256 lowestIdx)
{
uint256 lowestPrice = 2**256 - 1;
for (uint256 idx = 0; idx < numberOfOrders; idx++) {
BuyOrderData storage o = buyOrderData[idx];
if (o.unitPrice == 0 || o.amount < 10) {
return idx;
}else if (o.unitPrice < lowestPrice) {
lowestPrice = o.unitPrice;
lowestIdx = idx;
}
}
}
function sellCrystalDemand(uint256 amount, uint256 unitPrice, string title, string description) public
{
require(now <= deadline);
require(players[msg.sender].round == round);
require(amount >= 1000);
require(unitPrice > 0);
updateCrytal(msg.sender);
PlyerData storage seller = players[msg.sender];
if(seller.crystals < amount * CRTSTAL_MINING_PERIOD){
revert();
}
uint256 highestIdx = getHighestUnitPriceIdxFromSell();
SellOrderData storage o = sellOrderData[highestIdx];
if(o.amount > 10 && unitPrice >= o.unitPrice){
revert();
}
if (o.owner != 0){
PlyerData storage prev = players[o.owner];
prev.crystals = SafeMath.add(prev.crystals, o.amount * CRTSTAL_MINING_PERIOD);
}
o.owner = msg.sender;
o.unitPrice = unitPrice;
o.title = title;
o.description = description;
o.amount = amount;
seller.crystals = SafeMath.sub(seller.crystals, amount * CRTSTAL_MINING_PERIOD);
}
function buyCrystal(uint256 amount, uint256 index) public payable
{
require(now <= deadline);
require(players[msg.sender].round == round);
require(index < numberOfOrders);
require(amount > 0);
SellOrderData storage o = sellOrderData[index];
require(amount <= o.amount);
require(msg.value >= amount * o.unitPrice);
PlyerData storage buyer = players[msg.sender];
uint256 price = SafeMath.mul(amount, o.unitPrice);
uint256 fee = devFee(price);
sponsor.transfer(fee);
administrator.transfer(fee);
buyer.crystals = SafeMath.add(buyer.crystals, amount * CRTSTAL_MINING_PERIOD);
o.amount = SafeMath.sub(o.amount, amount);
o.owner.transfer(SafeMath.div(price, 2));
}
function withdrawSellDemand(uint256 index) public
{
require(now <= deadline);
require(index < numberOfOrders);
require(players[msg.sender].round == round);
SellOrderData storage o = sellOrderData[index];
require(o.owner == msg.sender);
if(o.amount > 0){
PlyerData storage p = players[o.owner];
p.crystals = SafeMath.add(p.crystals, o.amount * CRTSTAL_MINING_PERIOD);
}
o.unitPrice = 0;
o.amount = 0;
o.title = "title";
o.description = "description";
o.owner = 0;
}
function getSellDemand(uint256 index) public view returns(address owner, string title, string description,
uint256 amount, uint256 unitPrice)
{
require(index < numberOfOrders);
SellOrderData storage o = sellOrderData[index];
owner = o.owner;
title = o.title;
description = o.description;
amount = o.amount;
unitPrice = o.unitPrice;
}
function getHighestUnitPriceIdxFromSell() public returns(uint256 highestIdx)
{
uint256 highestPrice = 0;
for (uint256 idx = 0; idx < numberOfOrders; idx++) {
SellOrderData storage o = sellOrderData[idx];
if (o.unitPrice == 0 || o.amount < 10) {
return idx;
}else if (o.unitPrice > highestPrice) {
highestPrice = o.unitPrice;
highestIdx = idx;
}
}
}
function devFee(uint256 amount) public view returns(uint256)
{
return SafeMath.div(SafeMath.mul(amount, 5), 100);
}
function getBalance() public view returns(uint256)
{
return this.balance;
}
function updateHashrate(address addr) private
{
PlyerData storage p = players[addr];
uint256 hashrate = 0;
for (uint idx = 0; idx < numberOfMiners; idx++) {
MinerData storage m = minerData[idx];
hashrate = SafeMath.add(hashrate, SafeMath.mul(p.minerCount[idx], m.baseProduct));
}
p.hashrate = hashrate;
if(hashrate > RANK_LIST_LIMIT){
updateRankList(addr);
}
}
function updateCrytal(address addr) private
{
require(now > players[addr].lastUpdateTime);
if (players[addr].lastUpdateTime != 0) {
PlyerData 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 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;
PlyerData storage insert = players[addr];
PlyerData 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 returns(bool)
{
for(uint256 idx = 0;idx < 20; idx++){
if(addr == rankList[idx]){
return true;
}
}
return false;
}
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)];
PlyerData 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);
}
}