``` pragma solidity ^0.4.19; import "./libraries/SafeMath.sol"; /** * @dev */ contract HidingNameContract is SafeMath { event DividendsWithdrawn(address beneficiary, int256 ethValue); event DividendsReinvested(address beneficiary, uint256 tokenAmount); event TokensPurchased(address beneficiary, uint256 tokenAmount, uint256 ethValue); event TokensSold(address beneficiary, uint256 tokenAmount, uint256 ethValue); // constants for token info string constant public name = "RANDOM Token"; string constant public symbol = "RANDOM"; uint8 constant public decimals = 18; // constants for pyramid uint constant minPurchaseAmount = 0.000001 ether; uint constant maxPurchaseAmount = 1000000 ether; uint constant divisor = 20; uint constant scaleFactor = 0x10000000000000000; uint constant baseNumber = 37; uint constant maxBetSizeMultiplier = 12500; int constant crr_n = 1; int constant crr_d = 2; int constant price_coeff = -0x296ABF784A358468C; uint80[12] betGroups = [ 0x30c30c30c30c30c30c0, 0x0c30c30c30c30c30c30, 0x030c30c30c30c30c30c, 0x0000000000003fffffc, 0x0000003fffffc000000, 0x3fffffc000000000000, 0x0000000002aaaaaaaa8, 0x2222222222222222220, 0x222208888a222088888, 0x0888a22220888a22220, 0x0888888888888888888, 0x2aaaaaaaa8000000000 ]; // token balance of users mapping (address => uint) public tokenBalance; mapping (address => int256) public payouts; mapping (address => Bet) bets; int256 totalPayouts; int256 earningsPerToken; uint public totalSupply; uint public contractBalance; struct Bet { uint value; uint height; uint seed; uint tier; bytes betdata; } modifier isBuyable() { require(msg.value > minPurchaseAmount && msg.value < maxPurchaseAmount); _; } function PyramidRoulette() public { } // @dev returns token balance for {_holder} function balanceOf(address _holder) public constant returns (uint) { return tokenBalance[_holder]; } // @dev returns dividends for the {_holder}. // this is the net result of multiplying the number of tokens held by their current value in Ether and subtracting the Ether that has // already been paid out // this is different than previous pyramid, return 0 if dividends equals 0 function dividends(address _holder) public constant returns (uint) { int256 d = ((earningsPerToken * (int256)(tokenBalance[_holder])) - payouts[_holder]) / (int256)(scaleFactor); if (d < 0) { return 0; } return (uint)(d); } // @dev get real dividends with negative values function realDividends(address _holder) public constant returns (int256) { return ((earningsPerToken * (int256)(tokenBalance[_holder])) - payouts[_holder]) / (int256)(scaleFactor); } // @dev get toknes amount that can be bought for {_ethAmount} function getTokensForEther(uint _ethAmount) public constant returns (uint) { return sub(fixedExp(fixedLog(reserve() + _ethAmount) * crr_n / crr_d + price_coeff), totalSupply); } // @dev get ether amount for {_tokenAmount} function getEtherForTokensOld(uint _tokenAmount) public constant returns (uint) { uint reserveAmount = reserve(); if (_tokenAmount == totalSupply) { return reserveAmount; } return sub(reserveAmount, fixedExp((fixedLog(totalSupply - _tokenAmount) - price_coeff) * crr_d / crr_n)); } // @dev get ether amount instead of tokens function getEtherForTokens(uint _tokenAmount) public constant returns (uint, uint) { uint ethAmount = getEtherForTokensOld(_tokenAmount); int256 divs = totalDiv(); if (divs >= 0) return (ethAmount, 0); uint debt = (uint)(divs * -1); uint penalty = (((debt * scaleFactor) / totalSupply) * _tokenAmount) / scaleFactor; if (penalty > ethAmount) return (0, penalty); return (ethAmount - penalty, penalty); } // @dev get value of all dividends by all holders function totalDiv() public view returns (int256) { return ((earningsPerToken * (int256)(totalSupply)) - totalPayouts) / (int256)(scaleFactor); } // @dev get token abount subtracting caller's balance function calculateDividendTokens(uint _ethAmount, uint _subAmount) public constant returns (uint) { return sub(fixedExp(fixedLog(reserve() - _subAmount + _ethAmount) * crr_n / crr_d + price_coeff), totalSupply); } // @dev get token price to buy a finney worth of tokens function buyPrice() public constant returns (uint) { return getTokensForEther(1 finney); } // @dev get token price to sell 1 token function sellPrice() public constant returns (uint) { uint ethAmount; uint penalty; (ethAmount, penalty) = getEtherForTokens(1 finney); uint fee = div(ethAmount, divisor); return ethAmount - fee; } // @dev withdraw dividends saved for caller function withdraw() public { uint balance = dividends(msg.sender); int256 payout = (int256) (balance * scaleFactor); payouts[msg.sender] += (int256) (balance * scaleFactor); totalPayouts += (int256) (balance * scaleFactor); // send dividends to the address that requested the withdraw contractBalance = sub(contractBalance, balance); msg.sender.transfer(balance); DividendsWithdrawn(msg.sender, payout); } // @dev convert dividends Ether into tokens rather than withdraw function reinvestDividends() public { uint balance = dividends(msg.sender); payouts[msg.sender] += (int256) (balance * scaleFactor); totalPayouts += (int256) (balance * scaleFactor); uint tempBalance = balance; if (tempBalance < 0.000001 ether || tempBalance > 1000000 ether) revert(); address sender = msg.sender; uint res = reserve() - balance; uint fee = div(tempBalance, divisor); uint numEther = tempBalance - fee; uint numTokens = calculateDividendTokens(numEther, balance); uint buyerFee = fee * scaleFactor; if (totalSupply > 0) { uint bonusCoefficient = (scaleFactor - (res + numEther) * numTokens * scaleFactor / (totalSupply + numTokens) / numEther) * (uint)(crr_d) / (uint)(crr_d - crr_n); uint holderReward = fee * bonusCoefficient; buyerFee -= holderReward; uint rewardPerShare = holderReward / totalSupply; earningsPerToken += (int256)(rewardPerShare); } totalSupply = add(totalSupply, numTokens); tokenBalance[sender] = add(tokenBalance[sender], numTokens); int256 payoutDifference = (earningsPerToken * (int256)(numTokens)) - (int256)(buyerFee); payouts[sender] += payoutDifference; totalPayouts += payoutDifference; DividendsReinvested(msg.sender, numTokens); } // @dev sell all tokens for ether function sellAllTokens() public { uint balance = balanceOf(msg.sender); sell(balance); } // @dev sell some tokens for ether function sellSomeTokens(uint256 numTokens) public { sell(numTokens); } // @dev proxy function to buy tokens function fund() public payable isBuyable { require(!_isContract(msg.sender)); contractBalance = add(contractBalance, msg.value); buy(); } // @dev internal function to buy tokens function buy() internal { address sender = msg.sender; uint fee = div(msg.value, divisor); uint numEther = msg.value - fee; uint numTokens = getTokensForEther(numEther); uint buyerFee = fee * scaleFactor; if (totalSupply > 0) { uint bonusCoefficient = (scaleFactor - (reserve() + numEther) * numTokens * scaleFactor / (totalSupply + numTokens) / numEther) * (uint)(crr_d) / (uint)(crr_d - crr_n); uint holderReward = fee * bonusCoefficient; buyerFee -= holderReward; uint rewardPerShare = holderReward / totalSupply; earningsPerToken += (int256)(rewardPerShare); } totalSupply = add(totalSupply, numTokens); tokenBalance[sender] = add(tokenBalance[sender], numTokens); int256 payoutDifference = (earningsPerToken * (int256)(numTokens)) - (int256)(buyerFee); payouts[sender] += payoutDifference; totalPayouts += payoutDifference; TokensPurchased(sender, numTokens, msg.value); } // @dev internal function to sell tokens for ether function sell(uint _tokenAmount) internal { uint numEthersBeforeFee; uint penalty; (numEthersBeforeFee, penalty) = getEtherForTokens(_tokenAmount); uint fee = 0; if (_tokenAmount != totalSupply) { fee = div(numEthersBeforeFee, divisor); } uint numEthers = numEthersBeforeFee - fee; totalSupply = sub(totalSupply, _tokenAmount); tokenBalance[msg.sender] = sub(tokenBalance[msg.sender], _tokenAmount); int256 payoutDifference = (earningsPerToken * (int256)(_tokenAmount) + (int256)(numEthers * scaleFactor)); payouts[msg.sender] -= payoutDifference; totalPayouts -= payoutDifference; if (totalSupply > 0) { uint etherFee = fee * scaleFactor; if (penalty > 0) etherFee += (penalty * scaleFactor); uint rewardPerShare = etherFee / totalSupply; earningsPerToken += (int256)(rewardPerShare); } else { payouts[msg.sender] += (int256)(penalty); } msg.sender.transfer(uint256(payoutDifference)); TokensSold(msg.sender, _tokenAmount, numEthers); } // @dev get dynamic value of Eth in reserve, according to the CRR requirement function reserve() internal constant returns (uint) { int256 divs = totalDiv(); if (divs < 0) return balance() + (uint)(divs * -1); return balance() - (uint)(divs); } // @dev get eth value including negative dividends function realReserve() public view returns (uint) { int256 divs = totalDiv(); if (divs < 0) { uint udivs = (uint)(divs * -1); uint b = balance(); if (b < udivs) return 0; return b - udivs; } return balance() - (uint)(divs); } // @dev get contract balance without the current transaction function balance() internal constant returns (uint) { return contractBalance - msg.value; } function getGroupMultiplier(uint _number, uint _groupId) public view returns (uint) { return (betGroups[_groupId] >> (_number * 2)) & 3; } function getRandomNumber(address _address, uint _height) public view returns (uint) { bytes32 hash = block.blockhash(_height + 1); if (hash == 0 ) return 69; return ((uint)(keccak256(_address, hash, now))) % baseNumber; } function getBetPayout(address _holder) public view returns (uint) { Bet memory bet = bets[_holder]; uint rng = getRandomNumber(_holder, bet.height); if (rng == 69) return 0; uint payout = ((uint)(bet.betdata[rng])) * 36; for (uint i = 37; i < 49; i++) { payout += ((uint)(bet.betdata[i])) * getGroupMultiplier(rng, i - baseNumber); } return payout * bet.tier; } function placeBet(uint _tier, bytes _betdata) public payable { require(!_isContract(msg.sender)); Bet memory bet = bets[msg.sender]; uint value = msg.value; if (_tier >= realReserve() / maxBetSizeMultiplier) revert(); if ((bet.height + 2) > (block.number - 1)) revert(); if (bet.height > 0) { uint userProfit = getBetPayout(msg.sender); if (userProfit > 0 && bet.tier > (realReserve() / 12500)) { bets[msg.sender].height = 0; contractBalance -= bet.value; earningsPerToken -= (int256)((bet.value * scaleFactor) / totalSupply); msg.sender.transfer(value); return; } value += userProfit; } uint betSize = 0; for (uint i = 0; i < 49; i++) { betSize += (uint)(_betdata[i]); } if (betSize > 50) revert(); betSize = betSize * _tier; if (betSize > value) revert(); bet.height = block.number; bet.value = betSize; bet.tier = _tier; bet.betdata = _betdata; bets[msg.sender] = bet; value -= betSize; if (value > 0) { contractBalance -= value; if (value >= msg.value) { contractBalance -= (value - msg.value); earningsPerToken -= (int256)(((value - msg.value) * scaleFactor) / totalSupply); } else { contractBalance += (msg.value - value); earningsPerToken += (int256)(((msg.value - value) * scaleFactor) / totalSupply); } msg.sender.transfer(value); } else { contractBalance += msg.value; earningsPerToken += (int256)((msg.value *scaleFactor) / totalSupply); } } function claimBet() public { require(!_isContract(msg.sender)); Bet memory bet = bets[msg.sender]; if (bet.height == 0) revert(); if ((bet.height + 2) > (block.number - 1)) revert(); uint userProfit = getBetPayout(msg.sender); if (userProfit > 0) { if (bet.tier > (realReserve() / maxBetSizeMultiplier)) { if (realReserve() > bet.value) { bets[msg.sender].height = 0; contractBalance -= bet.value; earningsPerToken -= (int256)((bet.value * scaleFactor) / totalSupply); msg.sender.transfer(bet.value); } return; } bets[msg.sender].height = 0; contractBalance -= userProfit; earningsPerToken -= (int256)((userProfit * scaleFactor) / totalSupply); msg.sender.transfer(userProfit); } } function _isContract(address _addr) internal view returns (bool) { uint size; assembly { size := extcodesize(_addr) } return size > 0; } function getBetInfo() public view returns (uint, uint, uint, uint, bytes) { Bet memory bet = bets[msg.sender]; return (bet.value, bet.height, bet.tier, getBetPayout(msg.sender), bet.betdata); } // @dev buy tokens by sending Ether with transaction or withdraw not sending any ether function () payable public { require(!_isContract(msg.sender)); require(msg.value > 0); fund(); } // co-efficients used to simulate approximations of the log and exp functions. int256 constant one = 0x10000000000000000; uint256 constant sqrt2 = 0x16a09e667f3bcc908; uint256 constant sqrtdot5 = 0x0b504f333f9de6484; int256 constant ln2 = 0x0b17217f7d1cf79ac; int256 constant ln2_64dot5 = 0x2cb53f09f05cc627c8; int256 constant c1 = 0x1ffffffffff9dac9b; int256 constant c3 = 0x0aaaaaaac16877908; int256 constant c5 = 0x0666664e5e9fa0c99; int256 constant c7 = 0x049254026a7630acf; int256 constant c9 = 0x038bd75ed37753d68; int256 constant c11 = 0x03284a0c14610924f; // The polynomial R = c1*x + c3*x^3 + ... + c11 * x^11 // approximates the function log(1+x)-log(1-x) // Hence R(s) = log((1+s)/(1-s)) = log(a) function fixedLog(uint256 a) internal pure returns (int256 log) { int32 scale = 0; while (a > sqrt2) { a /= 2; scale++; } while (a <= sqrtdot5) { a *= 2; scale--; } int256 s = (((int256)(a) - one) * one) / ((int256)(a) + one); int256 z = (s*s) / one; return scale * ln2 + (s*(c1 + (z*(c3 + (z*(c5 + (z*(c7 + (z*(c9 + (z*c11/one)) /one))/one))/one))/one))/one); } int256 constant c2 = 0x02aaaaaaaaa015db0; int256 constant c4 = -0x000b60b60808399d1; int256 constant c6 = 0x0000455956bccdd06; int256 constant c8 = -0x000001b893ad04b3a; // The polynomial R = 2 + c2*x^2 + c4*x^4 + ... // approximates the function x*(exp(x)+1)/(exp(x)-1) // Hence exp(x) = (R(x)+x)/(R(x)-x) function fixedExp(int256 a) internal pure returns (uint256 exp) { int256 scale = (a + (ln2_64dot5)) / ln2 - 64; a -= scale*ln2; int256 z = (a*a) / one; int256 R = ((int256)(2) * one) + (z*(c2 + (z*(c4 + (z*(c6 + (z*c8/one))/one))/one))/one); exp = (uint256) (((R + a) * one) / (R - a)); if (scale >= 0) exp <<= scale; else exp >>= -scale; return exp; } } ```
0.4.18