/** * Source Code first verified at https://etherscan.io on Wednesday, May 8, 2019 (UTC) */ pragma solidity ^0.4.24; // https://www.ethereum.org/token interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; } /** * @title SpinWinInterface */ interface SpinWinInterface { function refundPendingBets() external returns (bool); } /** * @title SettingInterface */ interface SettingInterface { function uintSettings(bytes32 name) external constant returns (uint256); function boolSettings(bytes32 name) external constant returns (bool); function isActive() external constant returns (bool); function canBet(uint256 rewardValue, uint256 betValue, uint256 playerNumber, uint256 houseEdge) external constant returns (bool); function isExchangeAllowed(address playerAddress, uint256 tokenAmount) external constant returns (bool); /******************************************/ /* SPINWIN ONLY METHODS */ /******************************************/ function spinwinSetUintSetting(bytes32 name, uint256 value) external; function spinwinIncrementUintSetting(bytes32 name) external; function spinwinSetBoolSetting(bytes32 name, bool value) external; function spinwinAddFunds(uint256 amount) external; function spinwinUpdateTokenToWeiExchangeRate() external; function spinwinRollDice(uint256 betValue) external; function spinwinUpdateWinMetric(uint256 playerProfit) external; function spinwinUpdateLoseMetric(uint256 betValue, uint256 tokenRewardValue) external; function spinwinUpdateLotteryContributionMetric(uint256 lotteryContribution) external; function spinwinUpdateExchangeMetric(uint256 exchangeAmount) external; /******************************************/ /* SPINLOTTERY ONLY METHODS */ /******************************************/ function spinlotterySetUintSetting(bytes32 name, uint256 value) external; function spinlotteryIncrementUintSetting(bytes32 name) external; function spinlotterySetBoolSetting(bytes32 name, bool value) external; function spinlotteryUpdateTokenToWeiExchangeRate() external; function spinlotterySetMinBankroll(uint256 _minBankroll) external returns (bool); } /** * @title TokenInterface */ interface TokenInterface { function getTotalSupply() external constant returns (uint256); function getBalanceOf(address account) external constant returns (uint256); function transfer(address _to, uint256 _value) external returns (bool); function transferFrom(address _from, address _to, uint256 _value) external returns (bool); function approve(address _spender, uint256 _value) external returns (bool success); function approveAndCall(address _spender, uint256 _value, bytes _extraData) external returns (bool success); function burn(uint256 _value) external returns (bool success); function burnFrom(address _from, uint256 _value) external returns (bool success); function mintTransfer(address _to, uint _value) external returns (bool); function burnAt(address _at, uint _value) external returns (bool); } // https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol /** * @title SafeMath * @dev Math operations with safety checks that throw on error */ 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) { // 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; } 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; } } // https://github.com/ethereum/ethereum-org/blob/master/solidity/token-advanced.sol contract TokenERC20 { // Public variables of the token string public name; string public symbol; uint8 public decimals = 18; // 18 decimals is the strongly suggested default, avoid changing it uint256 public totalSupply; // This creates an array with all balances mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; // This generates a public event on the blockchain that will notify clients event Transfer(address indexed from, address indexed to, uint256 value); // This generates a public event on the blockchain that will notify clients event Approval(address indexed _owner, address indexed _spender, uint256 _value); // This notifies clients about the amount burnt event Burn(address indexed from, uint256 value); /** * Constructor function * * Initializes contract with initial supply tokens to the creator of the contract */ constructor( uint256 initialSupply, string tokenName, string tokenSymbol ) public { totalSupply = initialSupply * 10 ** uint256(decimals); // Update total supply with the decimal amount balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes } /** * Internal transfer, only can be called by this contract */ function _transfer(address _from, address _to, uint _value) internal { // Prevent transfer to 0x0 address. Use burn() instead require(_to != 0x0); // Check if the sender has enough require(balanceOf[_from] >= _value); // Check for overflows require(balanceOf[_to] + _value > balanceOf[_to]); // Save this for an assertion in the future uint previousBalances = balanceOf[_from] + balanceOf[_to]; // Subtract from the sender balanceOf[_from] -= _value; // Add the same to the recipient balanceOf[_to] += _value; emit Transfer(_from, _to, _value); // Asserts are used to use static analysis to find bugs in your code. They should never fail assert(balanceOf[_from] + balanceOf[_to] == previousBalances); } /** * Transfer tokens * * Send `_value` tokens to `_to` from your account * * @param _to The address of the recipient * @param _value the amount to send */ function transfer(address _to, uint256 _value) public returns (bool success) { _transfer(msg.sender, _to, _value); return true; } /** * Transfer tokens from other address * * Send `_value` tokens to `_to` in behalf of `_from` * * @param _from The address of the sender * @param _to The address of the recipient * @param _value the amount to send */ function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(_value <= allowance[_from][msg.sender]); // Check allowance allowance[_from][msg.sender] -= _value; _transfer(_from, _to, _value); return true; } /** * Set allowance for other address * * Allows `_spender` to spend no more than `_value` tokens in your behalf * * @param _spender The address authorized to spend * @param _value the max amount they can spend */ function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } /** * Set allowance for other address and notify * * Allows `_spender` to spend no more than `_value` tokens in your behalf, and then ping the contract about it * * @param _spender The address authorized to spend * @param _value the max amount they can spend * @param _extraData some extra information to send to the approved contract */ function approveAndCall(address _spender, uint256 _value, bytes _extraData) public returns (bool success) { tokenRecipient spender = tokenRecipient(_spender); if (approve(_spender, _value)) { spender.receiveApproval(msg.sender, _value, this, _extraData); return true; } } /** * Destroy tokens * * Remove `_value` tokens from the system irreversibly * * @param _value the amount of money to burn */ function burn(uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); // Check if the sender has enough balanceOf[msg.sender] -= _value; // Subtract from the sender totalSupply -= _value; // Updates totalSupply emit Burn(msg.sender, _value); return true; } /** * Destroy tokens from other account * * Remove `_value` tokens from the system irreversibly on behalf of `_from`. * * @param _from the address of the sender * @param _value the amount of money to burn */ function burnFrom(address _from, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // Check if the targeted balance is enough require(_value <= allowance[_from][msg.sender]); // Check allowance balanceOf[_from] -= _value; // Subtract from the targeted balance allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance totalSupply -= _value; // Update totalSupply emit Burn(_from, _value); return true; } } contract developed { address public developer; /** * Constructor */ constructor() public { developer = msg.sender; } /** * @dev Checks only developer address is calling */ modifier onlyDeveloper { require(msg.sender == developer); _; } /** * @dev Allows developer to switch developer address * @param _developer The new developer address to be set */ function changeDeveloper(address _developer) public onlyDeveloper { developer = _developer; } /** * @dev Allows developer to withdraw ERC20 Token */ function withdrawToken(address tokenContractAddress) public onlyDeveloper { TokenERC20 _token = TokenERC20(tokenContractAddress); if (_token.balanceOf(this) > 0) { _token.transfer(developer, _token.balanceOf(this)); } } } contract escaped { address public escapeActivator; /** * Constructor */ constructor() public { escapeActivator = 0xB15C54b4B9819925Cd2A7eE3079544402Ac33cEe; } /** * @dev Checks only escapeActivator address is calling */ modifier onlyEscapeActivator { require(msg.sender == escapeActivator); _; } /** * @dev Allows escapeActivator to switch escapeActivator address * @param _escapeActivator The new escapeActivator address to be set */ function changeAddress(address _escapeActivator) public onlyEscapeActivator { escapeActivator = _escapeActivator; } } /** * @title GameSetting */ contract GameSetting is developed, escaped, SettingInterface { using SafeMath for uint256; address public spinwinAddress; address public spinlotteryAddress; mapping(bytes32 => uint256) internal _uintSettings; // Array containing all uint256 settings mapping(bytes32 => bool) internal _boolSettings; // Array containing all bool settings uint256 constant public PERCENTAGE_DIVISOR = 10 ** 6; // 1000000 = 100% uint256 constant public HOUSE_EDGE_DIVISOR = 1000; uint256 constant public CURRENCY_DIVISOR = 10**18; uint256 constant public TWO_DECIMALS = 100; uint256 constant public MAX_NUMBER = 99; uint256 constant public MIN_NUMBER = 2; uint256 constant public MAX_HOUSE_EDGE = 1000; // 0% House Edge uint256 constant public MIN_HOUSE_EDGE = 0; // 100% House edge TokenInterface internal _spintoken; SpinWinInterface internal _spinwin; /** * @dev Log dev sets uint setting */ event LogSetUintSetting(address indexed who, bytes32 indexed name, uint256 value); /** * @dev Log dev sets bool setting */ event LogSetBoolSetting(address indexed who, bytes32 indexed name, bool value); /** * @dev Log when dev adds some funds */ event LogAddBankRoll(uint256 amount); /** * @dev Log when the token to Wei exchange rate is updated */ event LogUpdateTokenToWeiExchangeRate(uint256 exchangeRate, uint256 exchangeRateBlockNumber); /** * @dev Log when developer set spinwin contract to emergency mode */ event LogSpinwinEscapeHatch(); /** * Constructor */ constructor(address _spintokenAddress) public { _spintoken = TokenInterface(_spintokenAddress); devSetUintSetting('minBet', CURRENCY_DIVISOR.div(100)); // init min bet (0.01 ether) devSetUintSetting('maxProfitAsPercentOfHouse', 200000); // init 200000 = 20% commission devSetUintSetting('minBankroll', CURRENCY_DIVISOR.mul(20)); // init min bank roll (20 eth) devSetTokenExchangeMinBankrollPercent(900000); // init token exchange min bank roll percentage (90%) devSetUintSetting('referralPercent', 10000); // init referral percentage (1%) devSetUintSetting('gasForLottery', 250000); // init gas for lottery devSetUintSetting('maxBlockSecurityCount', 256); // init max block security count (256) devSetUintSetting('blockSecurityCount', 3); // init block security count (3) devSetUintSetting('tokenExchangeBlockSecurityCount', 3); // init token exchange block security count (3) devSetUintSetting('maxProfitBlockSecurityCount', 3); // init max profit block security count (3) devSetUintSetting('spinEdgeModifier', 80); // init spin edge modifier (0.8) devSetUintSetting('spinBankModifier', 50); // init spin bank modifier (0.5) devSetUintSetting('spinNumberModifier', 5); // init spin number modifier (0.05) devSetUintSetting('maxMinBankroll', CURRENCY_DIVISOR.mul(5000)); // init max value for min bankroll (5,000 eth) devSetUintSetting('lastProcessedBetInternalId', 1); // init lastProcessedBetInternalId = 1 devSetUintSetting('exchangeAmountDivisor', 2); // init exchangeAmountDivisor = 2 devSetUintSetting('tokenExchangeRatio', 10); // init tokenExchangeRatio = 0.1 (divided by TWO_DECIMALS) devSetUintSetting('spinToWeiRate', CURRENCY_DIVISOR); // init spinToWeiRate = 1 devSetUintSetting('blockToSpinRate', CURRENCY_DIVISOR); // init blockToSpinRate = 1 devSetUintSetting('blockToWeiRate', CURRENCY_DIVISOR); // init blockToWeiRate = 1 devSetUintSetting('gasForClearingBet', 320000); // init gasForClearingBet = 320000 gas devSetUintSetting('gasPrice', 40000000000); // init gasPrice = 40 gwei devSetUintSetting('clearSingleBetMultiplier', 200); // init clearSingleBetMultiplier = 2x (divided by TWO_DECIMALS) devSetUintSetting('clearMultipleBetsMultiplier', 100); // init clearMultipleBetMultiplier = 1x (divided by TWO_DECIMALS) devSetUintSetting('maxNumClearBets', 4); // init maxNumClearBets = 4 devSetUintSetting('lotteryTargetMultiplier', 200); // init lotteryTargetMultiplier = 2x (divided by TWO_DECIMALS) _setMaxProfit(true); } /** * @dev Checks only spinwinAddress is calling */ modifier onlySpinwin { require(msg.sender == spinwinAddress); _; } /** * @dev Checks only spinlotteryAddress is calling */ modifier onlySpinlottery { require(msg.sender == spinlotteryAddress); _; } /******************************************/ /* DEVELOPER ONLY METHODS */ /******************************************/ /** * @dev Allows developer to set spinwin contract address * @param _address The contract address to be set */ function devSetSpinwinAddress(address _address) public onlyDeveloper { require (_address != address(0)); spinwinAddress = _address; _spinwin = SpinWinInterface(spinwinAddress); } /** * @dev Allows developer to set spinlottery contract address * @param _address The contract address to be set */ function devSetSpinlotteryAddress(address _address) public onlyDeveloper { require (_address != address(0)); spinlotteryAddress = _address; } /** * @dev Allows dev to set uint setting * @param name The setting name to be set * @param value The value to be set */ function devSetUintSetting(bytes32 name, uint256 value) public onlyDeveloper { _uintSettings[name] = value; emit LogSetUintSetting(developer, name, value); } /** * @dev Allows dev to set bool setting * @param name The setting name to be set * @param value The value to be set */ function devSetBoolSetting(bytes32 name, bool value) public onlyDeveloper { _boolSettings[name] = value; emit LogSetBoolSetting(developer, name, value); } /** * @dev Allows developer to set min bank roll * @param minBankroll The new min bankroll value to be set */ function devSetMinBankroll(uint256 minBankroll) public onlyDeveloper { _uintSettings['minBankroll'] = minBankroll; _uintSettings['tokenExchangeMinBankroll'] = _uintSettings['minBankroll'].mul(_uintSettings['tokenExchangeMinBankrollPercent']).div(PERCENTAGE_DIVISOR); } /** * @dev Allows developer to set token exchange min bank roll percent * @param tokenExchangeMinBankrollPercent The new value to be set */ function devSetTokenExchangeMinBankrollPercent(uint256 tokenExchangeMinBankrollPercent) public onlyDeveloper { _uintSettings['tokenExchangeMinBankrollPercent'] = tokenExchangeMinBankrollPercent; _uintSettings['tokenExchangeMinBankroll'] = _uintSettings['minBankroll'].mul(_uintSettings['tokenExchangeMinBankrollPercent']).div(PERCENTAGE_DIVISOR); } /******************************************/ /* ESCAPE ACTIVATOR ONLY METHODS */ /******************************************/ /** * @dev Allows escapeActivator to trigger spinwin emergency mode. Will disable all bets and only allow token exchange at a fixed rate */ function spinwinEscapeHatch() public onlyEscapeActivator { _spinwin.refundPendingBets(); _boolSettings['contractKilled'] = true; _uintSettings['contractBalanceHonor'] = _uintSettings['contractBalance']; _uintSettings['tokenExchangeMinBankroll'] = 0; _uintSettings['tokenExchangeMinBankrollHonor'] = 0; /** * tokenToWeiExchangeRate is ETH in 36 decimals or WEI in 18 decimals to account for * the state when token's totalSupply is 10^18 more than contractBalance. * Otherwise the tokenToWeiExchangeRate will always be 0. * This means, in the exchange token function, we need to divide * tokenToWeiExchangeRate with CURRENCY_DIVISOR */ _uintSettings['tokenToWeiExchangeRate'] = _spintoken.getTotalSupply() > 0 ? _uintSettings['contractBalance'].mul(CURRENCY_DIVISOR).mul(CURRENCY_DIVISOR).div(_spintoken.getTotalSupply()) : 0; _uintSettings['tokenToWeiExchangeRateHonor'] = _uintSettings['tokenToWeiExchangeRate']; _uintSettings['tokenToWeiExchangeRateBlockNum'] = block.number; emit LogUpdateTokenToWeiExchangeRate(_uintSettings['tokenToWeiExchangeRateHonor'], _uintSettings['tokenToWeiExchangeRateBlockNum']); emit LogSpinwinEscapeHatch(); } /******************************************/ /* SPINWIN ONLY METHODS */ /******************************************/ /** * @dev Allows spinwin to set uint setting * @param name The setting name to be set * @param value The value to be set */ function spinwinSetUintSetting(bytes32 name, uint256 value) public onlySpinwin { _uintSettings[name] = value; emit LogSetUintSetting(spinwinAddress, name, value); } /** * @dev Allows spinwin to increment existing uint setting value * @param name The setting name to be set */ function spinwinIncrementUintSetting(bytes32 name) public onlySpinwin { _uintSettings[name] = _uintSettings[name].add(1); emit LogSetUintSetting(spinwinAddress, name, _uintSettings[name]); } /** * @dev Allows spinwin to set bool setting * @param name The setting name to be set * @param value The value to be set */ function spinwinSetBoolSetting(bytes32 name, bool value) public onlySpinwin { _boolSettings[name] = value; emit LogSetBoolSetting(spinwinAddress, name, value); } /** * @dev Add funds to the spinwin contract * @param amount The amount of eth sent */ function spinwinAddFunds(uint256 amount) public onlySpinwin { // Safely update contract balance _uintSettings['contractBalance'] = _uintSettings['contractBalance'].add(amount); // Update max profit _setMaxProfit(false); emit LogAddBankRoll(amount); } /** * @dev Allow spinwin to update token to Wei exchange rate. */ function spinwinUpdateTokenToWeiExchangeRate() public onlySpinwin { _updateTokenToWeiExchangeRate(); } /** * @dev Allow spinwin to update settings when roll dice * Increment totalBets * Add betValue to totalWeiWagered * * @param betValue The bet value * @return The internal bet ID */ function spinwinRollDice(uint256 betValue) public onlySpinwin { _uintSettings['totalBets']++; _uintSettings['totalWeiWagered'] = _uintSettings['totalWeiWagered'].add(betValue); } /** * @dev Allows spinwin to update uint setting when player wins * @param playerProfit The player profit to be subtracted from contractBalance and added to totalWeiWon */ function spinwinUpdateWinMetric(uint256 playerProfit) public onlySpinwin { _uintSettings['contractBalance'] = _uintSettings['contractBalance'].sub(playerProfit); _uintSettings['totalWeiWon'] = _uintSettings['totalWeiWon'].add(playerProfit); _setMaxProfit(false); } /** * @dev Allows spinwin to update uint setting when player loses * @param betValue The original wager * @param tokenRewardValue The amount of token to be rewarded */ function spinwinUpdateLoseMetric(uint256 betValue, uint256 tokenRewardValue) public onlySpinwin { _uintSettings['contractBalance'] = _uintSettings['contractBalance'].add(betValue).sub(1); _uintSettings['totalWeiWon'] = _uintSettings['totalWeiWon'].add(1); _uintSettings['totalWeiLost'] = _uintSettings['totalWeiLost'].add(betValue).sub(1); _uintSettings['totalTokenPayouts'] = _uintSettings['totalTokenPayouts'].add(tokenRewardValue); _setMaxProfit(false); } /** * @dev Allows spinwin to update uint setting when there is a lottery contribution * @param lotteryContribution The amount to be contributed to lottery */ function spinwinUpdateLotteryContributionMetric(uint256 lotteryContribution) public onlySpinwin { _uintSettings['contractBalance'] = _uintSettings['contractBalance'].sub(lotteryContribution); _setMaxProfit(true); } /** * @dev Allows spinwin to update uint setting when there is a token exchange transaction * @param exchangeAmount The converted exchange amount */ function spinwinUpdateExchangeMetric(uint256 exchangeAmount) public onlySpinwin { _uintSettings['contractBalance'] = _uintSettings['contractBalance'].sub(exchangeAmount); _setMaxProfit(false); } /******************************************/ /* SPINLOTTERY ONLY METHODS */ /******************************************/ /** * @dev Allows spinlottery to set uint setting * @param name The setting name to be set * @param value The value to be set */ function spinlotterySetUintSetting(bytes32 name, uint256 value) public onlySpinlottery { _uintSettings[name] = value; emit LogSetUintSetting(spinlotteryAddress, name, value); } /** * @dev Allows spinlottery to increment existing uint setting value * @param name The setting name to be set */ function spinlotteryIncrementUintSetting(bytes32 name) public onlySpinlottery { _uintSettings[name] = _uintSettings[name].add(1); emit LogSetUintSetting(spinwinAddress, name, _uintSettings[name]); } /** * @dev Allows spinlottery to set bool setting * @param name The setting name to be set * @param value The value to be set */ function spinlotterySetBoolSetting(bytes32 name, bool value) public onlySpinlottery { _boolSettings[name] = value; emit LogSetBoolSetting(spinlotteryAddress, name, value); } /** * @dev Allow spinlottery to update token to Wei exchange rate. */ function spinlotteryUpdateTokenToWeiExchangeRate() public onlySpinlottery { _updateTokenToWeiExchangeRate(); } /** * @dev Allows lottery to set spinwin minBankroll value * @param _minBankroll The new value to be set * @return Return true if success */ function spinlotterySetMinBankroll(uint256 _minBankroll) public onlySpinlottery returns (bool) { if (_minBankroll > _uintSettings['maxMinBankroll']) { _minBankroll = _uintSettings['maxMinBankroll']; } else if (_minBankroll < _uintSettings['contractBalance']) { _minBankroll = _uintSettings['contractBalance']; } _uintSettings['minBankroll'] = _minBankroll; _uintSettings['tokenExchangeMinBankroll'] = _uintSettings['minBankroll'].mul(_uintSettings['tokenExchangeMinBankrollPercent']).div(PERCENTAGE_DIVISOR); // Update max profit _setMaxProfit(false); return true; } /******************************************/ /* PUBLIC ONLY METHODS */ /******************************************/ /** * @dev Gets uint setting value * @param name The name of the uint setting * @return The value of the setting */ function uintSettings(bytes32 name) public constant returns (uint256) { return _uintSettings[name]; } /** * @dev Gets bool setting value * @param name The name of the bool setting * @return The value of the setting */ function boolSettings(bytes32 name) public constant returns (bool) { return _boolSettings[name]; } /** * @dev Check if contract is active * @return Return true if yes, false otherwise. */ function isActive() public constant returns (bool) { if (_boolSettings['contractKilled'] == false && _boolSettings['gamePaused'] == false) { return true; } else { return false; } } /** * @dev Check whether current bet is valid * @param rewardValue The winning amount * @param betValue The original wager * @param playerNumber The player chosen number * @param houseEdge The house edge * @return Return true if yes, false otherwise. */ function canBet(uint256 rewardValue, uint256 betValue, uint256 playerNumber, uint256 houseEdge) public constant returns (bool) { if (_boolSettings['contractKilled'] == false && _boolSettings['gamePaused'] == false && rewardValue <= _uintSettings['maxProfitHonor'] && betValue >= _uintSettings['minBet'] && houseEdge >= MIN_HOUSE_EDGE && houseEdge <= MAX_HOUSE_EDGE && playerNumber >= MIN_NUMBER && playerNumber <= MAX_NUMBER) { return true; } else { return false; } } /** * @dev Check whether token exchange is allowed * @param playerAddress The player address to be checked * @param tokenAmount The amount of token to be exchanged * @return Return true if yes, false otherwise. */ function isExchangeAllowed(address playerAddress, uint256 tokenAmount) public constant returns (bool) { if (_boolSettings['gamePaused'] == false && _boolSettings['tokenExchangePaused'] == false && _uintSettings['contractBalanceHonor'] >= _uintSettings['tokenExchangeMinBankrollHonor'] && _uintSettings['tokenToWeiExchangeRateHonor'] > 0 && _spintoken.getBalanceOf(playerAddress) >= tokenAmount) { return true; } else { return false; } } /******************************************/ /* INTERNAL ONLY METHODS */ /******************************************/ /** * @dev Calculates and sets the latest max profit a bet can possibly earn. Also update the honor variables that we are going to promise players. * @param force If true, bypass the block security check and update honor settings */ function _setMaxProfit(bool force) internal { _uintSettings['maxProfit'] = _uintSettings['contractBalance'].mul(_uintSettings['maxProfitAsPercentOfHouse']).div(PERCENTAGE_DIVISOR); if (force || block.number > _uintSettings['maxProfitBlockNum'].add(_uintSettings['maxProfitBlockSecurityCount'])) { if (_uintSettings['contractBalance'] < 10 ether) { _uintSettings['maxProfitAsPercentOfHouse'] = 200000; // 20% } else if (_uintSettings['contractBalance'] >= 10 ether && _uintSettings['contractBalance'] < 100 ether) { _uintSettings['maxProfitAsPercentOfHouse'] = 100000; // 10% } else if (_uintSettings['contractBalance'] >= 100 ether && _uintSettings['contractBalance'] < 1000 ether) { _uintSettings['maxProfitAsPercentOfHouse'] = 50000; // 5% } else { _uintSettings['maxProfitAsPercentOfHouse'] = 10000; // 1% } _uintSettings['maxProfitHonor'] = _uintSettings['maxProfit']; _uintSettings['contractBalanceHonor'] = _uintSettings['contractBalance']; _uintSettings['minBankrollHonor'] = _uintSettings['minBankroll']; _uintSettings['tokenExchangeMinBankrollHonor'] = _uintSettings['tokenExchangeMinBankroll']; _uintSettings['totalWeiLostHonor'] = _uintSettings['totalWeiLost']; _uintSettings['maxProfitBlockNum'] = block.number; } } /** * @dev Updates token to Wei exchange rate. * The exchange rate will be updated everytime there is a transaction happens in spinwin. * If contract is killed, we don't need to do anything */ function _updateTokenToWeiExchangeRate() internal { if (!_boolSettings['contractKilled']) { if (_uintSettings['contractBalance'] >= _uintSettings['tokenExchangeMinBankroll'] && _spintoken.getTotalSupply() > 0) { /** * tokenToWeiExchangeRate is ETH in 36 decimals or WEI in 18 decimals to account for * the state when token's totalSupply is 10^18 more than contractBalance. * Otherwise the tokenToWeiExchangeRate will always be 0. * This means, in the exchange token function, we need to divide * tokenToWeiExchangeRate with CURRENCY_DIVISOR */ _uintSettings['tokenToWeiExchangeRate'] = ((_uintSettings['contractBalance'].sub(_uintSettings['tokenExchangeMinBankroll'])).mul(CURRENCY_DIVISOR).mul(CURRENCY_DIVISOR).div(_uintSettings['exchangeAmountDivisor'])).div(_spintoken.getTotalSupply().mul(_uintSettings['tokenExchangeRatio']).div(TWO_DECIMALS)); } else { _uintSettings['tokenToWeiExchangeRate'] = 0; } if (block.number > _uintSettings['tokenToWeiExchangeRateBlockNum'].add(_uintSettings['tokenExchangeBlockSecurityCount'])) { _uintSettings['tokenToWeiExchangeRateHonor'] = _uintSettings['tokenToWeiExchangeRate']; _uintSettings['tokenToWeiExchangeRateBlockNum'] = block.number; emit LogUpdateTokenToWeiExchangeRate(_uintSettings['tokenToWeiExchangeRateHonor'], _uintSettings['tokenToWeiExchangeRateBlockNum']); } } } }