ETH Price: $2,103.13 (+0.49%)

Transaction Decoder

Block:
6975182 at Dec-29-2018 05:51:15 PM +UTC
Transaction Fee:
0.0008939563 ETH $1.88
Gas Used:
288,373 Gas / 3.1 Gwei

Emitted Events:

55 HDX20.onBuyEvent( from=0xAeC539A1...5bC1af93b, tokens=530543416354412 )
56 HDX20.onBuyEvent( from=0x8F7C64C3...bFa45b7fB, tokens=343084742575853 )
57 HDX20.onBuyEvent( from=[Sender] 0x20ca0d6fe51d06946f5cc90f9f4f297d398dd6db, tokens=34485322063036785 )
58 EtherKnightGame.onNewRound( gRND=2, turnRound=98, eventType=131078, eventTarget=64, persoEnergy=[0, 0, 118, 118], persoDistance=[1439, 3176, 18693, 20260], powerUpSpeed=[0, 0, 0, 0], powerUpShield=[0, 0, 0, 0], blockNumberTimeout=6980942, treasureAmountFind=0, customerAddress=[Sender] 0x20ca0d6fe51d06946f5cc90f9f4f297d398dd6db )
59 EtherKnightGame.onBuyShare( customerAddress=[Sender] 0x20ca0d6fe51d06946f5cc90f9f4f297d398dd6db, gRND=2, perso=2, nbToken=34485322063036785, actionType=0, actionValue=0 )

Account State Difference:

  Address   Before After State Difference Code
0x20CA0D6F...D398dD6DB
0.311240700317362423 Eth
Nonce: 2306
0.309346744017362423 Eth
Nonce: 2307
0.0018939563
(F2Pool Old)
3,204.573115073883199824 Eth3,204.574009030183199824 Eth0.0008939563
0x8942a599...9a064F882 344.460933011453454714 Eth344.460983011453454714 Eth0.00005
0xd9Ff8cc0...D6A40387f 3.065142369490847934 Eth3.066092369490847934 Eth0.00095

Execution Trace

ETH 0.001 EtherKnightGame.BuyShare( perso=2, action=0, _referrer_address=0xAeC539A116fa75E8BdcF016D3C146a25bC1af93b )
  • ETH 0.00005 HDX20.buyTokenFromGame( _customerAddress=0x20CA0D6FE51d06946f5cC90F9F4f297D398dD6DB, _referrer_address=0xAeC539A116fa75E8BdcF016D3C146a25bC1af93b ) => ( 34485322063036785 )
    BuyShare[EtherKnightGame (ln:722)]
    File 1 of 2: EtherKnightGame
    /*
    
    Introducing "ETHERKNIGHT" 3.1 our first HDX20 POWERED GAME running on the Ethereum Blockchain got a 2nd upgrade 
    "ETHERKNIGHT" is playable @ http://etherknightgame.io
    
    About the game :
    4 Knight Characters racing against each other to be the first to reach the goal and win the pot of gold.
    
    How to play ETHERKNIGHT:
    The Race will start after at least 1 player has bought shares of any Knight Racer then for every new item activated
    a 24H countdown will reset. At the end of the countdown, the players on the first Racer will share the Treasure and
    everybody else will receive their payout (no one is leaving the table without values).
    In addition, when you buy shares of your favorite Racer 5% of the price will buy you HDX20 Token earning you Ethereum
    from the volume of any HDX20 POWERED GAMES (visit https://hdx20.io/ for details).
    Please remember, at every new buy, the price of the share is increasing a little and so will be your payout even
    if you are not the winner, buying shares at the beginning of the race is highly advised.
    
    Play for the big WIN, Play for the TREASURE, Play for staking HDX20 TOKEN or Play for all at once...Your Choice!
    
    We wish you Good Luck!
    
    PAYOUTS DISTRIBUTION:
    .60% to the winners of the race distributed proportionally to their shares.
    .25% to the community of HDX20 gamers/holders distributed as price appreciation.
    .5% to developer for running, developing and expanding the platform.
    .10% for provisioning the TREASURE for the next Race.
    
    UPDATE:
    
    we updated:
    .from 1 eth played 40%(50% before) will charge the treasure, 40% (30% before) will buy shares, 5% will buy HDX20 for the player and 15% will appreciate the share price.
    .adjusted the item price increase function. 
    
    This product is copyrighted. Any unauthorized copy, modification, or use without express written consent from HyperDevbox is prohibited.
    
    Copyright 2018 HyperDevbox
    
    */
    
    
    pragma solidity ^0.4.25;
    
    
    interface HDX20Interface
    {
        function() payable external;
        
        
        function buyTokenFromGame( address _customerAddress , address _referrer_address ) payable external returns(uint256);
      
        function payWithToken( uint256 _eth , address _player_address ) external returns(uint256);
      
        function appreciateTokenPrice() payable external;
       
        function totalSupply() external view returns(uint256); 
        
        function ethBalanceOf(address _customerAddress) external view returns(uint256);
      
        function balanceOf(address _playerAddress) external view returns(uint256);
        
        function sellingPrice( bool includeFees) external view returns(uint256);
      
    }
    
    contract EtherKnightGame
    {
         HDX20Interface private HDXcontract = HDX20Interface(0x8942a5995bd168f347f7ec58f25a54a9a064f882);
         
         using SafeMath for uint256;
          using SafeMath128 for uint128;
         
         /*==============================
        =            EVENTS            =
        ==============================*/
        event OwnershipTransferred(
            
             address previousOwner,
             address nextOwner,
              uint256 timeStamp
             );
             
        event HDXcontractChanged(
            
             address previous,
             address next,
             uint256 timeStamp
             );
     
       
        
         event onWithdrawGains(
            address customerAddress,
            uint256 ethereumWithdrawn,
            uint256 timeStamp
        );
        
        event onNewRound(
            uint256       gRND,
            uint32        turnRound,
            uint32        eventType,
            uint32        eventTarget,
            uint32[4]     persoEnergy,
            uint32[4]     persoDistance,
            uint32[4]     powerUpSpeed,
            uint32[4]     powerUpShield,
            uint256       blockNumberTimeout,
            uint256       treasureAmountFind,
            address       customerAddress
            
           
           
        );
        
        
        event onNewRace(
            
            uint256 gRND,
            uint8[4] persoType,
            uint256  blockNumber
            
            );
            
        event onBuyShare(
            address     customerAddress,
            uint256     gRND,
            uint32      perso,
            uint256     nbToken,
            uint32      actionType,
            uint32      actionValue
            );    
            
            
         event onMaintenance(
            bool        mode,
            uint256     timeStamp
    
            );    
            
        event onRefund(
            address     indexed customerAddress,
            uint256     eth,
            uint256     timeStamp
             
            );   
            
        event onCloseEntry(
            
             uint256 gRND
             
            );    
            
        event onChangeBlockTimeAverage(
            
             uint256 blocktimeavg
             
            );    
            
        /*==============================
        =            MODIFIERS         =
        ==============================*/
        modifier onlyOwner
        {
            require (msg.sender == owner );
            _;
        }
        
        modifier onlyFromHDXToken
        {
            require (msg.sender == address( HDXcontract ));
            _;
        }
       
         modifier onlyDirectTransaction
        {
            require (msg.sender == tx.origin);
            _;
        }
       
       
         modifier isPlayer
        {
            require (PlayerData[ msg.sender].gRND !=0);
            _;
        }
        
        modifier isMaintenance
        {
            require (maintenanceMode==true);
            _;
        }
        
         modifier isNotMaintenance
        {
            require (maintenanceMode==false);
            _;
        }
       
        // Changing ownership of the contract safely
        address public owner;
      
        
       
        
         /// Contract governance.
    
        constructor () public
        {
            owner = msg.sender;
           
            
            if ( address(this).balance > 0)
            {
                owner.transfer( address(this).balance );
            }
        }
        
        function changeOwner(address _nextOwner) public
        onlyOwner
        {
            require (_nextOwner != owner);
            require(_nextOwner != address(0));
             
            emit OwnershipTransferred(owner, _nextOwner , now);
             
            owner = _nextOwner;
        }
        
        function changeHDXcontract(address _next) public
        onlyOwner
        {
            require (_next != address( HDXcontract ));
            require( _next != address(0));
             
            emit HDXcontractChanged(address(HDXcontract), _next , now);
             
            HDXcontract  = HDX20Interface( _next);
        }
      
      
        
        function changeBlockTimeAverage( uint256 blocktimeavg) public
        onlyOwner
        {
            require ( blocktimeavg>0 );
            
           
            blockTimeAverage = blocktimeavg;
            
            emit onChangeBlockTimeAverage( blockTimeAverage );
             
        }
        
        function enableMaintenance() public
        onlyOwner
        {
            maintenanceMode = true;
            
            emit onMaintenance( maintenanceMode , now);
            
        }
    
        function disableMaintenance() public
        onlyOwner
        {
            uint8[4] memory perso =[0,1,2,3];
            
            maintenanceMode = false;
            
            emit onMaintenance( maintenanceMode , now);
            
            //reset with a new race
            initRace( perso );
        }
        
      
        
        
       
        function refundMe() public
        isMaintenance
        {
            address _playerAddress = msg.sender;
             
            
          
            require( this_gRND>0 && GameRoundData[ this_gRND].extraData[0]>0 && GameRoundData[ this_gRND].extraData[0]<(1<<30) && PlayerData[ _playerAddress ].gRND==this_gRND);
            
            uint256 _eth = 0;
    
            for( uint i=0;i<4;i++)
            {
                _eth = _eth.add( PlayerGameRound[ _playerAddress][this_gRND].shares[i] * GameRoundData[ this_gRND].sharePrice);
                
                PlayerGameRound[ _playerAddress][this_gRND].shares[i] = 0;
            }
            
            if (_eth>0)
            {
                   _playerAddress.transfer( _eth );  
                   
                   emit onRefund( _playerAddress , _eth , now );
            }
            
        }
        
         /*================================
        =       GAMES VARIABLES         =
        ================================*/
        
        struct PlayerData_s
        {
       
            uint256 chest;  
            uint256 payoutsTo;
            uint256 gRND;  
           
        }
        
        struct PlayerGameRound_s
        {
            uint256[4]      shares;
            uint128         treasure_payoutsTo;    
            uint128         token;
          
           
        }
        
        struct GameRoundData_s
        {
           uint256              blockNumber;
           uint256              blockNumberTimeout;
           uint256              sharePrice;
           uint256[4]           sharePots;
           uint256              shareEthBalance;
           uint256              shareSupply;
           uint256              treasureSupply;
          
         
           //this time we want to stream the HDX20 apprecition and dev fees on the way
           uint256              allFeeSupply;       //to separate the fees from the actual treasure
           uint256              hdx20AppreciationPayout;
           uint256              devAppreciationPayout;
           //
           
           uint256              totalTreasureFound;
           uint256[6]           actionBlockNumber;
          
           uint128[4]           treasurePerShare; 
           uint32[8]            persoData; //energy[4] distance[4]
           uint32[8]            powerUpData; //Speed[4] Shield[4]
           
           uint32[6]            actionValue;
           
           uint32[6]            extraData;//[0]==this_TurnRound , [1]==winner , [2-5] totalPlayers
      
        }
        
      
       
        
     
        
       
        mapping (address => PlayerData_s)   private PlayerData;
        
       
        mapping (address => mapping (uint256 => PlayerGameRound_s)) private PlayerGameRound;
        
       
        mapping (uint256 => GameRoundData_s)   private GameRoundData;
        
       
        bool        private maintenanceMode=false;     
       
        uint256     private this_gRND =0;
      
     
      
      
        //85 , missing 15% for shares appreciation eg:share price increase
        uint8 constant private HDX20BuyFees = 5;
        uint8 constant private TREASUREBuyFees = 40;
        uint8 constant private BUYPercentage = 40;
        
        
        //the part to keep from the treasure for next round treasure + hdx20 appreciation + dev 
        uint8 constant private DevFees = 5;
        uint8 constant private TreasureFees = 10;
        uint8 constant private AppreciationFees = 25;
        uint8 constant private AddedFees = DevFees+TreasureFees+AppreciationFees;
      
       
        uint256 constant internal magnitude = 1e18;
      
        uint256 private genTreasure = 0;
       
        uint256 constant private minimumSharePrice = 0.001 ether;
        
        uint256 private blockTimeAverage = 15;  //seconds per block                          
        
     
        uint8[4]    private this_Perso_Type;
        
       
          
        /*================================
        =       PUBLIC FUNCTIONS         =
        ================================*/
        
        //fallback will be called only from the HDX token contract to fund the game from customers's HDX20
        
         function()
         payable
         public
         onlyFromHDXToken 
        {
           
          
          
              
        }
        
        
        function ChargeTreasure() public payable
        {
            genTreasure = SafeMath.add( genTreasure , msg.value);     
        }
        
        
        function buyTreasureShares(GameRoundData_s storage  _GameRoundData , uint256 _eth ) private
        returns( uint256)
        {
            uint256 _nbshares = (_eth.mul( magnitude)) / _GameRoundData.sharePrice;
            uint256 _nbsharesForTreasure = (_nbshares.mul( 100-DevFees-TreasureFees-AppreciationFees)) / 100;
           
            //now we do separate for streamline payment
            _GameRoundData.treasureSupply = _GameRoundData.treasureSupply.add( _nbsharesForTreasure );
            //the difference is for the allFeeSupply
            _GameRoundData.allFeeSupply = _GameRoundData.allFeeSupply.add( _nbshares - _nbsharesForTreasure);
            
            
            _GameRoundData.shareSupply =   _GameRoundData.shareSupply.add( _nbshares );
            
            return( _nbshares);
        }
       
        
        function initRace( uint8[4] p ) public
        onlyOwner
        isNotMaintenance
        {
     
            
            this_gRND++;
            
            GameRoundData_s storage _GameRoundData = GameRoundData[ this_gRND ];
           
            for( uint i=0;i<4;i++)
            {
               this_Perso_Type[i] = p[i];
           
                _GameRoundData.persoData[i] = 100;
                _GameRoundData.persoData[4+i] = 25;
                
            }
           
            _GameRoundData.blockNumber = block.number;
            
            _GameRoundData.blockNumberTimeout = block.number + (360*10*24*3600); 
            
            uint256 _sharePrice = 0.001 ether; // minimumSharePrice;
            
            _GameRoundData.sharePrice = _sharePrice;
            
            uint256 _nbshares = buyTreasureShares(_GameRoundData, genTreasure );
         
            //convert into ETH
            _nbshares = _nbshares.mul( _sharePrice ) / magnitude;
            
            //start balance   
            _GameRoundData.shareEthBalance = _nbshares;
            
            genTreasure = genTreasure.sub( _nbshares);
         
           
            emit onNewRace( this_gRND , p , block.number);
            
        }
        
        
       
        function get_TotalPayout(  GameRoundData_s storage  _GameRoundData ) private view
        returns( uint256)
        {
          
           uint256 _payout = 0;
            
           uint256 _sharePrice = _GameRoundData.sharePrice;
         
           for(uint i=0;i<4;i++)
           {
               uint256 _bet = _GameRoundData.sharePots[i];
               
               _payout = _payout.add( _bet.mul (_sharePrice) / magnitude );
           }           
             
           //from the whole treasure now since new version         
           uint256 _potValue = (_GameRoundData.treasureSupply.mul( _sharePrice )) / magnitude;
           
           
           _payout = _payout.add( _potValue ).add(_GameRoundData.totalTreasureFound );
           
       
           return( _payout );
            
        }
        
        
      
        function get_PendingGains( address _player_address , uint256 _gRND) private view
        returns( uint256)
        {
           
           //did not play 
           if (PlayerData[ _player_address].gRND != _gRND || _gRND==0) return( 0 );
           
           GameRoundData_s storage  _GameRoundData = GameRoundData[ _gRND ];
           
         
           uint32 _winner = _GameRoundData.extraData[1];
           
           uint256 _gains = 0;
           uint256 _treasure = 0;
           uint256 _sharePrice = _GameRoundData.sharePrice;
           uint256 _shares;
           
           PlayerGameRound_s storage  _PlayerGameRound = PlayerGameRound[ _player_address][_gRND];
           
           for(uint i=0;i<4;i++)
           {
               _shares = _PlayerGameRound.shares[ i ];
                
               _gains = _gains.add( _shares.mul( _sharePrice) / magnitude );
            
               
               _treasure = _treasure.add(_shares.mul( _GameRoundData.treasurePerShare[ i ] ) / magnitude);
               
           }
           
            if (_treasure >=  _PlayerGameRound.treasure_payoutsTo) _treasure = _treasure.sub(_PlayerGameRound.treasure_payoutsTo );
           else _treasure = 0;
               
           _gains = _gains.add(_treasure );
           
           //if the race payment is made (race is over) then we add also the winner prize
           if (_winner>0 && _GameRoundData.extraData[0] >= (1<<30))
           {
               _shares = _PlayerGameRound.shares[ _winner-1 ];
               
               if (_shares>0)
               {
                   //from the whole treasure now since new version   
                   _treasure = (_GameRoundData.treasureSupply.mul( _sharePrice )) / magnitude;
           
                   
                   _gains = _gains.add(  _treasure.mul( _shares ) / _GameRoundData.sharePots[ _winner-1]  );
                   
               }
               
           }
        
           
            return( _gains );
            
        }
        
        
        //only for the Result Data Screen on the game not used for the payout
        
        function get_PendingGainsAll( address _player_address , uint256 _gRND) private view
        returns( uint256)
        {
           
           //did not play 
           if (PlayerData[ _player_address].gRND != _gRND || _gRND==0) return( 0 );
           
           GameRoundData_s storage  _GameRoundData = GameRoundData[ _gRND ];
           
         
           uint32 _winner = _GameRoundData.extraData[1];
           
           uint256 _gains = 0;
           uint256 _treasure = 0;
           uint256 _sharePrice = _GameRoundData.sharePrice;
           uint256 _shares;
           
           PlayerGameRound_s storage  _PlayerGameRound = PlayerGameRound[ _player_address][_gRND];
           
           for(uint i=0;i<4;i++)
           {
               _shares = _PlayerGameRound.shares[ i ];
                
               _gains = _gains.add( _shares.mul( _sharePrice) / magnitude );
            
               
               _treasure = _treasure.add(_shares.mul( _GameRoundData.treasurePerShare[ i ] ) / magnitude);
               
           }
           
            if (_treasure >=  _PlayerGameRound.treasure_payoutsTo) _treasure = _treasure.sub(_PlayerGameRound.treasure_payoutsTo );
           else _treasure = 0;
               
           _gains = _gains.add(_treasure );
           
         
           if (_winner>0)
           {
               _shares = _PlayerGameRound.shares[ _winner-1 ];
               
               if (_shares>0)
               {
                   //from the whole treasure now since new version 
                   _treasure = (_GameRoundData.treasureSupply.mul( _sharePrice )) / magnitude;
           
                   
                   _gains = _gains.add(  _treasure.mul( _shares ) / _GameRoundData.sharePots[ _winner-1]  );
                   
               }
               
           }
        
           
            return( _gains );
            
        }
        
           //process streaming HDX20 appreciation and dev fees appreciation
        function process_sub_Taxes(  GameRoundData_s storage _GameRoundData , uint256 minimum) private
        {
            uint256 _sharePrice = _GameRoundData.sharePrice;
                 
            uint256 _potValue = _GameRoundData.allFeeSupply.mul( _sharePrice ) / magnitude;
                
            uint256 _appreciation = SafeMath.mul( _potValue , AppreciationFees) / AddedFees; 
              
            uint256 _dev = SafeMath.mul( _potValue , DevFees) / AddedFees;   
            
            if (_dev > _GameRoundData.devAppreciationPayout)
            {
                _dev -= _GameRoundData.devAppreciationPayout;
                
                if (_dev>minimum)
                {
                  _GameRoundData.devAppreciationPayout = _GameRoundData.devAppreciationPayout.add( _dev );
                  
                   HDXcontract.buyTokenFromGame.value( _dev )( owner , address(0));
                  
                }
            }
            
            if (_appreciation> _GameRoundData.hdx20AppreciationPayout)
            {
                _appreciation -= _GameRoundData.hdx20AppreciationPayout;
                
                if (_appreciation>minimum)
                {
                    _GameRoundData.hdx20AppreciationPayout = _GameRoundData.hdx20AppreciationPayout.add( _appreciation );
                    
                     HDXcontract.appreciateTokenPrice.value( _appreciation )();
                    
                }
            }
            
        }
        
        //process the fees, hdx20 appreciation, calcul results at the end of the race
        function process_Taxes(  GameRoundData_s storage _GameRoundData ) private
        {
            uint32 turnround = _GameRoundData.extraData[0];
            
            if (turnround>0 && turnround<(1<<30))
            {  
                _GameRoundData.extraData[0] = turnround | (1<<30);
                
                uint256 _sharePrice = _GameRoundData.sharePrice;
                 
                uint256 _potValue = _GameRoundData.allFeeSupply.mul( _sharePrice ) / magnitude;
         
               
                uint256 _treasure = SafeMath.mul( _potValue , TreasureFees) / AddedFees; 
             
               
                genTreasure = genTreasure.add( _treasure );
                
                //take care of any left over
                process_sub_Taxes( _GameRoundData , 0);
                
                
            }
         
        }
        
        
        
        function BuyShareWithDividends( uint32 perso , uint256 eth , uint32 action, address _referrer_address ) public
        onlyDirectTransaction
        {
      
            require( maintenanceMode==false  && this_gRND>0 && (eth>=minimumSharePrice) && (eth <=100 ether) &&  perso<=3 && action <=5 && block.number <GameRoundData[ this_gRND ].blockNumberTimeout );
      
            address _customer_address = msg.sender;
            
            eth = HDXcontract.payWithToken( eth , _customer_address );
           
            require( eth>0 );
             
            CoreBuyShare( _customer_address , perso , eth , action , _referrer_address );
            
           
        }
        
        function BuyShare(   uint32 perso , uint32 action , address _referrer_address ) public payable
        onlyDirectTransaction
        {
         
             
            address _customer_address = msg.sender;
            uint256 eth = msg.value;
            
            require( maintenanceMode==false  && this_gRND>0 && (eth>=minimumSharePrice) &&(eth <=100 ether) && perso<=3 && action <=5 && block.number <GameRoundData[ this_gRND ].blockNumberTimeout);
       
             
            CoreBuyShare( _customer_address , perso , eth , action , _referrer_address);
         
        }
        
        /*================================
        =       CORE BUY FUNCTIONS       =
        ================================*/
        
        function CoreBuyShare( address _player_address , uint32 perso , uint256 eth , uint32 action ,  address _referrer_address ) private
        {
        
            PlayerGameRound_s storage  _PlayerGameRound = PlayerGameRound[ _player_address][ this_gRND];
            
            GameRoundData_s storage  _GameRoundData = GameRoundData[ this_gRND ];
            
          
            if (PlayerData[ _player_address].gRND != this_gRND)
            {
               
                if (PlayerData[_player_address].gRND !=0)
                {
                    uint256 _gains = get_PendingGains( _player_address , PlayerData[ _player_address].gRND  );
                
                     PlayerData[ _player_address].chest = PlayerData[ _player_address].chest.add( _gains);
                }
              
              
                PlayerData[ _player_address ].gRND = this_gRND;
               
       
            }
            
            //HDX20BuyFees
            uint256 _tempo = (eth.mul(HDX20BuyFees)) / 100;
            
            _GameRoundData.shareEthBalance =  _GameRoundData.shareEthBalance.add( eth-_tempo );  //minus the hdx20 fees
            
            uint256 _nb_token =   HDXcontract.buyTokenFromGame.value( _tempo )( _player_address , _referrer_address);
            
             //keep track for result UI screen how many token bought in this game round
            _PlayerGameRound.token += uint128(_nb_token);
            
            //increase the treasure shares
            buyTreasureShares(_GameRoundData , (eth.mul(TREASUREBuyFees)) / 100 );
       
            //what is left for the player
            eth = eth.mul( BUYPercentage) / 100;
            
            uint256 _nbshare =  (eth.mul( magnitude)) / _GameRoundData.sharePrice;
            
            _GameRoundData.shareSupply =  _GameRoundData.shareSupply.add( _nbshare );
            _GameRoundData.sharePots[ perso ] =  _GameRoundData.sharePots[ perso ].add( _nbshare);
            
            _tempo =  _PlayerGameRound.shares[ perso ];
            
            if (_tempo==0)
            {
                _GameRoundData.extraData[ 2+perso ]++; 
            }
            
            _PlayerGameRound.shares[ perso ] =  _tempo.add( _nbshare);
       
            //this will always raise the price after 1 share
            if (_GameRoundData.shareSupply>magnitude)
            {
                _GameRoundData.sharePrice = (_GameRoundData.shareEthBalance.mul( magnitude)) / _GameRoundData.shareSupply;
            }
           
           
            _PlayerGameRound.treasure_payoutsTo = _PlayerGameRound.treasure_payoutsTo.add( uint128(_nbshare.mul(   _GameRoundData.treasurePerShare[ perso ]  ) / magnitude) );
         
            //HDX20 streaming appreciation
            process_sub_Taxes( _GameRoundData , 0.2 ether);
            
            uint32 actionValue = ApplyAction( perso , action , _nbshare , _player_address);
            
            _GameRoundData.actionValue[ action] = actionValue;
            
            emit onBuyShare( _player_address , this_gRND , perso , _nb_token , action, actionValue  );
                             
            
        }
        
         struct GameVar_s
        {
            uint32[4]   perso_energy;
            uint32[4]   perso_distance;
            uint32[4]   powerUpShield;
            uint32[4]   powerUpSpeed;
            
            uint32      event_type;
            uint32      event_target;
         
            uint32      winner;
            
            uint256     this_gRND;
            
            uint256     treasureAmountFind;
            
            bytes32     seed;
            
            uint256     blockNumberTimeout;
            
            uint32      turnround;
          
        }
        
        function actionPowerUpShield( uint32 perso , GameVar_s gamevar) pure private
        {
            
            gamevar.powerUpShield[ perso ] = 100;
            
        }
        
        function actionPowerUpSpeed( uint32 perso , GameVar_s gamevar) pure private
        {
            
            gamevar.powerUpSpeed[ perso ] = 100;
            
        }
        
       
        
        function actionApple( uint32 perso , GameVar_s gamevar) pure private
        {
            
            gamevar.event_type = 6;     //apple / banana etc...
            
            gamevar.event_target = 1<<(perso*3);
            
            gamevar.perso_energy[ perso ] += 20; 
            
            if (gamevar.perso_energy[ perso] > 150) gamevar.perso_energy[ perso ] = 150;
            
        }
        
        function actionBanana(  GameVar_s gamevar ) pure private
        {
            
            gamevar.event_type = 6;     //apple / banana etc...
            
            uint32 result = 2;
            
            uint32 target = get_modulo_value(gamevar.seed,18, 4);
            
            if (gamevar.winner>0) target = gamevar.winner-1;
        
            
            uint32 shield = uint32(gamevar.powerUpShield[ target ]);
            
            if (shield>20) result = 5; //jumping banana
            else
            {
                        uint32 dd = 4 * (101 - shield);
                                       
                      
                        
                        if (gamevar.perso_distance[ target ]>=dd)  gamevar.perso_distance[ target ] -= dd;
                        else  gamevar.perso_distance[ target ] = 0;
                        
            }
            
            gamevar.event_target = result<<(target*3);
            
           
            
        }
        
        function getTreasureProbabilityType( bytes32 seed ) private pure
        returns( uint32 )
        {
               uint8[22] memory this_TreasureProbability =[
        
            1,1,1,1,1,1,1,1,1,1,1,1,    //12 chances to have 10%
            2,2,2,2,2,2,                //6 chances to have 15%
            3,3,3,                      //3 chances to have 20%
            4                           //1 chance to have 25%
           
            ];       
            
            return( this_TreasureProbability[ get_modulo_value(seed,24, 22) ] );
        }
        
       
        
        function distribute_treasure( uint32 type2 , uint32 target , GameVar_s gamevar) private
        {
            uint8[5] memory this_TreasureValue =[
            
            1,
            10,
            15,
            20,
            25
          
            ];  
            
            //from the whole treasure now since new version 
            uint256 _treasureSupply = GameRoundData[ gamevar.this_gRND].treasureSupply;
          
            
            uint256 _sharePrice = GameRoundData[ gamevar.this_gRND].sharePrice;
            uint256 _shareSupply = GameRoundData[ gamevar.this_gRND].shareSupply;
           
            //how many shares to sell
            uint256  _amount = _treasureSupply.mul(this_TreasureValue[ type2 ] )  / 100;
           
            GameRoundData[ gamevar.this_gRND].treasureSupply = _treasureSupply.sub( _amount );
            GameRoundData[ gamevar.this_gRND].shareSupply =  _shareSupply.sub( _amount );
            
            //in eth
            _amount = _amount.mul( _sharePrice ) / magnitude;
            
            //price of shares should not change
            GameRoundData[ gamevar.this_gRND].shareEthBalance =  GameRoundData[ gamevar.this_gRND].shareEthBalance.sub( _amount );
            
            gamevar.treasureAmountFind = _amount;
           
            GameRoundData[ gamevar.this_gRND].totalTreasureFound =   GameRoundData[ gamevar.this_gRND].totalTreasureFound.add( _amount );
           
            uint256 _shares = GameRoundData[ gamevar.this_gRND].sharePots[ target ];
        
            if (_shares>0)
            {
               
                GameRoundData[ gamevar.this_gRND].treasurePerShare[ target ] =  GameRoundData[ gamevar.this_gRND].treasurePerShare[ target ].add( uint128(((_amount.mul(magnitude)) / _shares)));
            }
            
        }
        
        function actionTreasure( uint32 perso, GameVar_s gamevar ) private
        {
            gamevar.event_target =  get_modulo_value(gamevar.seed,18,  14);
            gamevar.event_type = getTreasureProbabilityType( gamevar.seed );
                                                        
            if (gamevar.event_target==perso)
            {
    
                    distribute_treasure( gamevar.event_type , gamevar.event_target, gamevar);
            }
            
           
        }
        
        function apply_attack( uint32 perso, uint32 target , GameVar_s gamevar) pure private
        {
            for(uint i=0;i<4;i++)
            {
                uint32 damage = (1+(target % 3)) * 10;
                
                uint32 shield = uint32(  gamevar.powerUpShield[i] );
                
                if (damage<= shield || i==perso) damage = 0;
                else damage -=  shield;
                
                if (damage<gamevar.perso_energy[i]) gamevar.perso_energy[i] -= damage;
                else gamevar.perso_energy[i] = 1;   //minimum
                
                target >>= 2;
                
            }
            
        }
        
        
        function actionAttack( uint32 perso , GameVar_s gamevar ) pure private
        {
                gamevar.event_type =  5; 
                gamevar.event_target = get_modulo_value(gamevar.seed,24,256);     //8 bits 4x2
                
                apply_attack( perso , gamevar.event_target , gamevar);    
        }
        
        function ApplyAction( uint32 perso ,  uint32 action , uint256 nbshare , address _player_address) private
        returns( uint32)
        {
            uint32 actionValue = GameRoundData[ this_gRND].actionValue[ action ];
            
            //only the last one is activating within the same block
            if (block.number<= GameRoundData[ this_gRND].actionBlockNumber[ action]) return( actionValue);
            
            GameVar_s memory gamevar;
              
            gamevar.turnround = GameRoundData[ this_gRND ].extraData[0];
            
            //now we introduce a new price increase for the items
            nbshare = nbshare.mul(100*100);
            nbshare /= (100+(gamevar.turnround/6));
            
            nbshare /= magnitude;
          
            nbshare += 10;
            
            if (nbshare>5000) nbshare = 5000;
            
            actionValue += uint32( nbshare );
            
        
             uint16[6] memory actionPrice =[
            
            1000,   //apple
            4000,   //powerup shield
            5000,   //powerup speed 
            2000,   //chest
            1000,   //banana action
            3000   //attack
          
            ];  
            
            if (actionValue<actionPrice[action] && gamevar.turnround>0)
            {
               
                return( actionValue );
            }
            
            if (actionValue>=actionPrice[action])
            {
                GameRoundData[ this_gRND].actionBlockNumber[ action] = block.number;
                 
                actionValue = 0;
            }
            else action = 100; //this is the first action
            
            gamevar.turnround++;
         
            
          
            
            gamevar.this_gRND = this_gRND;
            gamevar.winner = GameRoundData[ gamevar.this_gRND].extraData[1];
          
            
            uint i;
                
            for( i=0;i<4;i++)
            {
                    gamevar.perso_energy[i] = GameRoundData[ gamevar.this_gRND].persoData[i];
                    gamevar.perso_distance[i] = GameRoundData[ gamevar.this_gRND].persoData[4+i];
                    gamevar.powerUpSpeed[i] = GameRoundData[ gamevar.this_gRND].powerUpData[i] / 2;
                    gamevar.powerUpShield[i] = GameRoundData[ gamevar.this_gRND].powerUpData[4+i] / 2;
        
            }
            
            
            
            //a little boost for the fist action maker 
            if (gamevar.turnround==1) gamevar.perso_energy[ perso ] += 5;
            
            getSeed( gamevar);
        
          
            if (action==0) actionApple( perso , gamevar );
            if (action==1) actionPowerUpShield( perso , gamevar);
            if (action==2) actionPowerUpSpeed( perso , gamevar );
            if (action==3) actionTreasure( perso, gamevar);
            if (action==4) actionBanana(  gamevar);
            if (action==5) actionAttack( perso , gamevar);
            
            gamevar.event_type |= (perso<<16);
    
            uint32 CurrentWinnerXpos = 0; //gamevar.perso_distance[0]; //this.Racers[n].perso_distance;
           
            for( i=0; i<4;i++)
            {
          
                    //tiredness
                    gamevar.perso_energy[ i ] *= 95;
                    gamevar.perso_energy[ i ] /= 100;
                    
                                               
                    uint32 spd1 =  (gamevar.perso_energy[ i ]*10) + (gamevar.powerUpSpeed[ i ]*10); 
                                           
                    gamevar.perso_distance[ i ] = (  (gamevar.perso_distance[ i ]*95) + (spd1*100)  )/100; 
                             
                   if (gamevar.perso_distance[i] > CurrentWinnerXpos)
                   {
                       CurrentWinnerXpos = gamevar.perso_distance[i];
                       gamevar.winner = uint8(i);
                   }
                   
                    GameRoundData[ gamevar.this_gRND].persoData[i] = gamevar.perso_energy[i];
                    GameRoundData[ gamevar.this_gRND].persoData[4+i] = gamevar.perso_distance[i];
                    GameRoundData[ gamevar.this_gRND].powerUpData[i] = gamevar.powerUpSpeed[i];
                    GameRoundData[ gamevar.this_gRND].powerUpData[4+i] = gamevar.powerUpShield[i];
            
            }
             
            GameRoundData[ gamevar.this_gRND ].extraData[0] = gamevar.turnround;
            
            GameRoundData[ gamevar.this_gRND].extraData[1] = 1+gamevar.winner;
            
            gamevar.blockNumberTimeout = block.number + ((24*3600) / blockTimeAverage);
            
            GameRoundData[ gamevar.this_gRND].blockNumberTimeout = gamevar.blockNumberTimeout;
            
        
            
            emitRound( gamevar , _player_address);
            
            return( actionValue );
        }
      
        function emitRound(GameVar_s gamevar , address _player_address) private
        {
               emit onNewRound(
                gamevar.this_gRND,   
                gamevar.turnround,
                gamevar.event_type,
                gamevar.event_target,
                gamevar.perso_energy,
                gamevar.perso_distance,
                gamevar.powerUpSpeed,
                gamevar.powerUpShield,
                gamevar.blockNumberTimeout,
                gamevar.treasureAmountFind,
                _player_address
               
            );
            
        }
       
        
        function get_Gains(address _player_address) private view
        returns( uint256)
        {
           
            uint256 _gains = PlayerData[ _player_address ].chest.add( get_PendingGains( _player_address , PlayerData[ _player_address].gRND ) );
            
            if (_gains > PlayerData[ _player_address].payoutsTo)
            {
                _gains -= PlayerData[ _player_address].payoutsTo;
            }
            else _gains = 0;
         
        
            return( _gains );
            
        }
        
        
        function WithdrawGains() public 
        isPlayer
        {
            address _customer_address = msg.sender;
            
            uint256 _gains = get_Gains( _customer_address );
            
            require( _gains>0);
            
            PlayerData[ _customer_address ].payoutsTo = PlayerData[ _customer_address ].payoutsTo.add( _gains );
            
          
            emit onWithdrawGains( _customer_address , _gains , now);
            
            _customer_address.transfer( _gains );
            
            
        }
        
        function getSeed(GameVar_s gamevar) private view
       
        {
                uint256 _seed =  uint256( blockhash( block.number-1) );
                _seed ^= uint256( blockhash( block.number-2) );
                _seed ^= uint256(block.coinbase) / now;
                _seed += gamevar.perso_distance[0];
                _seed += gamevar.perso_distance[1];
                _seed += gamevar.perso_distance[2];
                _seed += gamevar.perso_distance[3];
                
                _seed += gasleft();
                
                gamevar.seed = keccak256(abi.encodePacked( _seed));
            
                
        }
        
        function CloseEntry() public
        onlyOwner
        isNotMaintenance
        {
        
            GameRoundData_s storage  _GameRoundData = GameRoundData[ this_gRND ];
             
            process_Taxes( _GameRoundData);
              
            emit onCloseEntry( this_gRND );
          
        }
        
       
        
        
        function get_probability( bytes32 seed ,  uint32 bytepos , uint32 percentage) pure private
        returns( bool )
        {
           uint32 v = uint32(seed[bytepos]);
           
           if (v<= ((255*percentage)/100)) return( true );
           else return( false );
         
        }
        
        function get_modulo_value( bytes32 seed , uint32 bytepos, uint32 mod) pure private
        returns( uint32 )
        {
          
            return( ((uint32(seed[ bytepos])*256)+(uint32(seed[ bytepos+1]))) % mod);
        }
        
      
        
      
      
        
         /*================================
        =  VIEW AND HELPERS FUNCTIONS    =
        ================================*/
      
        
        function view_get_Treasure() public
        view
        returns(uint256)
        {
          
          return( genTreasure);  
        }
        
        function view_get_allFees() public
        view
        returns(uint256)
        {
          
          return( (GameRoundData[ this_gRND].allFeeSupply * GameRoundData[ this_gRND].sharePrice) / magnitude);  
        }
     
        function view_get_gameData() public
        view
        returns( uint256 sharePrice, uint256[4] sharePots, uint256 shareSupply , uint256 shareEthBalance, uint128[4] treasurePerShare, uint32[4] totalPlayers , uint32[6] actionValue , uint256[4] shares , uint256 treasure_payoutsTo ,uint256 treasureSupply  )
        {
            address _player_address = msg.sender;
             
            sharePrice = GameRoundData[ this_gRND].sharePrice;
            sharePots = GameRoundData[ this_gRND].sharePots;
            shareSupply = GameRoundData[ this_gRND].shareSupply;
            shareEthBalance = GameRoundData[ this_gRND].shareEthBalance;
            treasurePerShare = GameRoundData[ this_gRND].treasurePerShare;
            
            treasureSupply = GameRoundData[ this_gRND].treasureSupply;
            
            uint32[4] memory totalPlayersm;
           
            totalPlayersm[0] = GameRoundData[ this_gRND].extraData[2];
            totalPlayersm[1] = GameRoundData[ this_gRND].extraData[3];
            totalPlayersm[2] = GameRoundData[ this_gRND].extraData[4];
            totalPlayersm[3] = GameRoundData[ this_gRND].extraData[5];
            
           
            totalPlayers = totalPlayersm;
            actionValue = GameRoundData[ this_gRND].actionValue;
            
            shares = PlayerGameRound[_player_address][this_gRND].shares;
            
            treasure_payoutsTo = PlayerGameRound[_player_address][this_gRND].treasure_payoutsTo;
        }
      
        
        function view_get_Gains()
        public
        view
        returns( uint256 gains)
        {
            
            address _player_address = msg.sender;
       
          
            uint256 _gains = PlayerData[ _player_address ].chest.add( get_PendingGains( _player_address , PlayerData[ _player_address].gRND) );
            
            if (_gains > PlayerData[ _player_address].payoutsTo)
            {
                _gains -= PlayerData[ _player_address].payoutsTo;
            }
            else _gains = 0;
         
        
            return( _gains );
            
        }
      
      
        
        function view_get_gameStates() public 
        view
        returns(uint8[4] types, uint256 grnd, uint32 turnround, uint256 minimumshare , uint256 blockNumber , uint256 blockNumberTimeout, uint32[6] actionValue , uint32[8] persoData , uint32[8] powerUpData , uint256 blockNumberCurrent , uint256 blockTimeAvg)
        {
            return( this_Perso_Type, this_gRND , GameRoundData[ this_gRND].extraData[0] , minimumSharePrice , GameRoundData[ this_gRND].blockNumber,GameRoundData[ this_gRND].blockNumberTimeout, GameRoundData[ this_gRND].actionValue , GameRoundData[ this_gRND].persoData , GameRoundData[ this_gRND].powerUpData, block.number , blockTimeAverage /*, view_get_MyRacer()*/);
        }
        
        function view_get_ResultData() public
        view
        returns(uint32 TotalPlayer, uint256 TotalPayout ,uint256 MyTokenValue, uint256 MyToken, uint256 MyGains , uint256 MyTreasureFound )
        {
            address _player_address = msg.sender;
            
            GameRoundData_s storage  _GameRoundData = GameRoundData[ this_gRND ];
            
            TotalPlayer = _GameRoundData.extraData[2]+_GameRoundData.extraData[3]+_GameRoundData.extraData[4]+_GameRoundData.extraData[5];
         
            TotalPayout = get_TotalPayout( _GameRoundData );
          
            MyToken =  PlayerGameRound[ _player_address][ this_gRND].token;
              
            MyTokenValue = MyToken * HDXcontract.sellingPrice( true );
            MyTokenValue /= magnitude;
          
            MyGains = 0;
            MyTreasureFound = 0;
            
            if (PlayerData[ _player_address].gRND == this_gRND)
            {
           
               MyGains =  get_PendingGainsAll( _player_address , this_gRND ); //just here for the view function so not used for any payout
            
               
               for(uint i=0;i<4;i++)
               {
                 MyTreasureFound += PlayerGameRound[_player_address][ this_gRND].shares[ i ].mul( _GameRoundData.treasurePerShare[ i ] ) / magnitude;
               }
           
           
                if (MyTreasureFound >=  PlayerGameRound[_player_address][this_gRND].treasure_payoutsTo) MyTreasureFound = MyTreasureFound.sub(  PlayerGameRound[_player_address][this_gRND].treasure_payoutsTo );
                else MyTreasureFound = 0;
                  
               
                
            }
            
            
        }    
     
     
        function totalEthereumBalance()
        public
        view
        returns(uint256)
        {
            return address(this).balance;
        }
        
        function view_get_maintenanceMode()
        public
        view
        returns(bool)
        {
            return( maintenanceMode);
        }
        
        function view_get_blockNumbers()
        public
        view
        returns( uint256 b1 , uint256 b2 )
        {
            return( block.number , GameRoundData[ this_gRND ].blockNumberTimeout);
            
        }
        
       
    }
    
    
    library SafeMath {
        
       
        function mul(uint256 a, uint256 b) 
            internal 
            pure 
            returns (uint256 c) 
        {
            if (a == 0) {
                return 0;
            }
            c = a * b;
            require(c / a == b);
            return c;
        }
    
       
        function sub(uint256 a, uint256 b)
            internal
            pure
            returns (uint256) 
        {
            require(b <= a);
            return a - b;
        }
    
       
        function add(uint256 a, uint256 b)
            internal
            pure
            returns (uint256 c) 
        {
            c = a + b;
            require(c >= a);
            return c;
        }
        
       
        
      
        
       
    }
    
    
    library SafeMath128 {
        
       
        function mul(uint128 a, uint128 b) 
            internal 
            pure 
            returns (uint128 c) 
        {
            if (a == 0) {
                return 0;
            }
            c = a * b;
            require(c / a == b);
            return c;
        }
    
       
        function sub(uint128 a, uint128 b)
            internal
            pure
            returns (uint128) 
        {
            require(b <= a);
            return a - b;
        }
    
       
        function add(uint128 a, uint128 b)
            internal
            pure
            returns (uint128 c) 
        {
            c = a + b;
            require(c >= a);
            return c;
        }
        
       
        
      
        
       
    }

    File 2 of 2: HDX20
    /*
    'We are a gaming and entertainment network our blockChain launch product is HDX20 (http://hdx20.io)'
    
    HDX20 tokens can be bought & sold on our exchange and are distributed every time someone is playing a HDX20 POWERED GAME. 
    With 4% IN and 4% OUT fee only, price of the HDX20 can only go up by design, cannot be dumped on holders and is fueled
    by both the volume of transactions and HDX20 POWERED GAMES.
    
    The 4 principles of the HDX20 are :
    
    1) Buy it, its price will increase.
    2) Sell it, its price will increase.
    3) Transfer it, its price will increase.
    4) Play our HDX20 powered games, its price will increase.
    
    Our Blockchain SmartContract IS the market and makes sure that the HDX20 Price never fall below its current selling price
    thus offering an unique CONTEXT where risk is known at all time and limited to the IN and OUT fees only.
    
    We have designed a vault where your HDX20 value while still indexed on the Ethereum Price will appreciate automatically over time.
    
    This product is copyrighted. Any unauthorized copy, modification, or use without express written consent from HyperDevbox is prohibited.
    
    Copyright 2018 HyperDevbox
    
    fees distribution:
    .1% for developer / 3% for HDX20 price appreciation during BUY and SELL
    .1% for developer / 1% for HDX20 price appreciation during token Transfer
    
    */
    
    pragma solidity ^0.4.25;
    
    
    interface HDX20Interface
    {
       
        function moveAccountIn( address _customerAddress ) payable external;
      
    }
    
    contract HDX20
    {
         using SafeMath for uint256;
         
         //address of a future contract to move in, by default set to 0
         HDX20Interface private NewHDX20Contract = HDX20Interface(0);
         
        /*==============================
        =            EVENTS            =
        ==============================*/
        event OwnershipTransferred(
             address indexed previousOwner,
             address indexed nextOwner
             );
             
       
             
             
        event Transfer(
            address indexed from,
            address indexed to,
            uint256 tokens
        );
        
      
             
        event onBuyEvent(
            address from,
            uint256 tokens
        );
       
         event onSellEvent(
            address from,
            uint256 tokens
        );
        
        
             
        event onAccountMovedOut(
            address indexed from,
            address to,
            uint256 tokens,
            uint256 eth
        );
        
        event onAccountMovedIn(
            address indexed from,
            address to,
            uint256 tokens,
            uint256 eth
        );
        
        event HDXcontractChanged(
            
             address previous,
             address next,
             uint256 timeStamp
             );
        
        /*==============================
        =            MODIFIERS         =
        ==============================*/
        modifier onlyOwner
        {
            require (msg.sender == owner);
            _;
        }
        
        modifier onlyFromGameWhiteListed
        {
            require (gameWhiteListed[ msg.sender ] == true);
            _;
        }
        
      
        
        modifier onlyGameWhiteListed(address who)
        {
            require (gameWhiteListed[ who ] == true);
            _;
        }
        
        
        modifier onlyTokenHolders() {
            require(myTokens() > 0);
            _;
        }
        
      
     
      
        address public owner;
        
         /// Contract governance.
    
        constructor () public
        {
            owner = msg.sender;
           
            
            if ( address(this).balance > 0)
            {
                owner.transfer( address(this).balance );
            }
        }
    
      
       
    
        /*==============================
        =       TOKEN VARIABLES        =
        ==============================*/
    
        string public name = "HDX20 token";
        string public symbol = "HDX20";
        uint8 constant public decimals = 18;
        uint256 constant internal magnitude = 1e18;
        
        
        
        uint8 constant internal referrerFee = 50;    //that is 50% of the buyInFee fee 
        uint8 constant internal transferFee = 2;     //50% for the community 50% for developer
        uint8 constant internal buyInFee = 3;        
        uint8 constant internal sellOutFee = 3;      
        uint8 constant internal devFee = 1;          //actually since dev is receiving fees in HDX20 exclusively, he is also taxed on the buyinfee so this not 1%
        
        
        mapping(address => uint256) private tokenBalanceLedger;
      
        
        uint256 private tokenSupply = 0;  
        uint256 private contractValue = 0;
        uint256 private tokenPrice = 0.001 ether;   //starting price
      
      
       /*================================
        =       HDX20 VARIABLES         =
        ================================*/
        
        mapping(address => bool)   private gameWhiteListed;
        mapping(address => uint8)  private superReferrerRate;
       
        
        /*================================
        =       PUBLIC FUNCTIONS         =
        ================================*/
        
         /**
         * Fallback function to process ethereum 
         */
        function()
            payable
            public
        {
            buyToken(address(0));
        }
        
        
        
        function changeOwner(address _nextOwner) public
        onlyOwner
        {
            require (_nextOwner != owner);
            require(_nextOwner != address(0));
             
            emit OwnershipTransferred(owner, _nextOwner);
             
            owner = _nextOwner;
        }
        
        
     
        
        function changeName(string _name) public
        onlyOwner
        {
            name = _name;
        }
        
      
        function changeSymbol(string _symbol) public
        onlyOwner
        {
            symbol = _symbol;
        }
     
        
        function addGame(address _contractAddress ) public
        onlyOwner
        {
            gameWhiteListed[ _contractAddress ] = true;
        }
        
        function addSuperReferrer(address _contractAddress , uint8 extra_rate) public
        onlyOwner
        {
           superReferrerRate[ _contractAddress ] = extra_rate;
        }
        
        function removeGame(address _contractAddress ) public
        onlyOwner
        {
            gameWhiteListed[ _contractAddress ] = false;
        }
        
        function changeNewHDX20Contract(address _next) public
        onlyOwner
        {
            require (_next != address( NewHDX20Contract ));
            require( _next != address(0));
             
            emit HDXcontractChanged(address(NewHDX20Contract), _next , now);
             
            NewHDX20Contract  = HDX20Interface( _next);
        }
        
        function buyTokenSub( uint256 _eth , address _customerAddress ) private
        returns(uint256)
        {
            
            uint256 _nb_token = (_eth.mul( magnitude)) / tokenPrice;
            
            
            tokenBalanceLedger[ _customerAddress ] =  tokenBalanceLedger[ _customerAddress ].add( _nb_token);
            tokenSupply = tokenSupply.add(_nb_token);
            
            emit onBuyEvent( _customerAddress , _nb_token);
            
            return( _nb_token );
         
        }
        
        function buyTokenFromGame( address _customerAddress , address _referrer_address ) public payable
        onlyFromGameWhiteListed
        returns(uint256)
        {
            uint256 _eth = msg.value;
            
            if (_eth==0) return(0);
            
            
            uint256 _devfee = (_eth.mul( devFee )) / 100;
            
            uint256 _fee = (_eth.mul( buyInFee )) / 100;
            
            if (_referrer_address != address(0) && _referrer_address != _customerAddress )
            {
                 uint256 _ethReferrer = (_fee.mul(referrerFee + superReferrerRate[_referrer_address])) / 100;
    
                 buyTokenSub( _ethReferrer , _referrer_address);
                 
                 //substract what is given to referrer
                 _fee = _fee.sub( _ethReferrer );
                 
            }
            
            //for the developer as HDX20 token and also help to increase the price because taxed also on his own share like everybody else
            
            buyTokenSub( (_devfee.mul(100-buyInFee)) / 100 , owner );
            
            //finally buy for the buyer
         
            uint256 _nb_token = buyTokenSub( _eth - _fee -_devfee , _customerAddress);
            
            //add the value to the contract
            contractValue = contractValue.add( _eth );
            
          
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
           
            
            return( _nb_token );
            
        }
      
      
        function buyToken( address _referrer_address ) public payable
        returns(uint256)
        {
            uint256 _eth = msg.value;
            address _customerAddress = msg.sender;
            
            require( _eth>0);
            
            uint256 _devfee = (_eth.mul( devFee )) / 100;
             
            uint256 _fee = (_eth.mul( buyInFee )) / 100;
            
            if (_referrer_address != address(0) && _referrer_address != _customerAddress )
            {
                 uint256 _ethReferrer = (_fee.mul(referrerFee + superReferrerRate[_referrer_address])) / 100;
    
                 buyTokenSub( _ethReferrer , _referrer_address);
                 
                //substract what is given to referrer
                 _fee = _fee.sub( _ethReferrer );
                 
            }
    
            //for the developer as HDX20 token and also help to increase the price because taxed also on his own share like everybody else
    
            buyTokenSub( (_devfee.mul(100-buyInFee)) / 100 , owner );
            
            //finally buy for the buyer
          
            uint256 _nb_token = buyTokenSub( _eth - _fee -_devfee , _customerAddress);
            
            //add the value to the contract
            contractValue = contractValue.add( _eth );
            
         
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
            return( _nb_token );
            
        }
        
        function sellToken( uint256 _amount ) public
        onlyTokenHolders
        {
            address _customerAddress = msg.sender;
            
            uint256 balance = tokenBalanceLedger[ _customerAddress ];
            
            require( _amount <= balance);
            
            uint256 _eth = (_amount.mul( tokenPrice )) / magnitude;
            
            uint256 _fee = (_eth.mul( sellOutFee)) / 100;
            
            uint256 _devfee = (_eth.mul( devFee)) / 100;
            
            tokenSupply = tokenSupply.sub( _amount );
           
         
            balance = balance.sub( _amount );
            
            tokenBalanceLedger[ _customerAddress] = balance;
            
            //for the developer as HDX20 token and also help to increase the price because taxed also on his own share like everybody else
            buyTokenSub(  (_devfee.mul(100-buyInFee)) / 100 , owner );
            
            
            //calculate what is really leaving the contract, basically _eth - _fee -devfee
            _eth = _eth - _fee - _devfee; 
            
            contractValue = contractValue.sub( _eth );
            
           
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
             emit onSellEvent( _customerAddress , _amount);
            
             //finally transfer the money
            _customerAddress.transfer( _eth );
            
        }
       
        //there is no fee using token to play HDX20 powered games 
      
        function payWithToken( uint256 _eth , address _player_address ) public
        onlyFromGameWhiteListed
        returns(uint256)
        {
            require( _eth>0 && _eth <= ethBalanceOfNoFee(_player_address ));
            
            address _game_contract = msg.sender;
            
            uint256 balance = tokenBalanceLedger[ _player_address ];
            
            uint256 _nb_token = (_eth.mul( magnitude) ) / tokenPrice;
            
            require( _nb_token <= balance);
            
            //confirm the ETH value
            _eth = (_nb_token.mul( tokenPrice)) / magnitude;
            
            balance = balance.sub(_nb_token);
            
            tokenSupply = tokenSupply.sub( _nb_token);
            
            tokenBalanceLedger[ _player_address ] = balance;
            
            contractValue = contractValue.sub( _eth );
            
           
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
            //send the money to the game contract   
            _game_contract.transfer( _eth );
          
          
            return( _eth );
        }
        
        function moveAccountOut() public
        onlyTokenHolders
        {
            address _customerAddress = msg.sender;
            
            require( ethBalanceOfNoFee( _customerAddress )>0 && address(NewHDX20Contract) != address(0));
        
            uint256 balance = tokenBalanceLedger[ _customerAddress ];
        
            uint256 _eth = (balance.mul( tokenPrice )) / magnitude;
            
           
            tokenSupply = tokenSupply.sub( balance );
            
            tokenBalanceLedger[ _customerAddress ] = 0;
            
            contractValue = contractValue.sub( _eth );
            
         
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
            emit onAccountMovedOut( _customerAddress , address(NewHDX20Contract), balance , _eth );
          
            //send the money to the new HDX20 contract which will buy on customer behalf at no fee converting eth for eth
            //notice this could give more or less HDX20 however the eth value should be preserved
            NewHDX20Contract.moveAccountIn.value(_eth)(_customerAddress);
          
        }
        
        function moveAccountIn(address _customerAddress) public
        payable
        onlyFromGameWhiteListed
        {
            
            
            uint256 _eth = msg.value;
          
            //buy token at no fee
            uint256 _nb_token = buyTokenSub( _eth , _customerAddress );
            
            contractValue = contractValue.add( _eth );
        
          
            if (tokenSupply>magnitude)
            {
                tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
            emit onAccountMovedIn( msg.sender, _customerAddress , _nb_token , _eth );
         
        }
        
        
        function appreciateTokenPrice() public payable
        onlyFromGameWhiteListed
        {
            uint256 _eth =  msg.value;
           
            contractValue = contractValue.add( _eth );
                
            //we need a minimum of 1 HDX20 before appreciation is activated    
            if (tokenSupply>magnitude)
            {
                    tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
            }
           
            
        }
        
      
        
        function transferSub(address _customerAddress, address _toAddress, uint256 _amountOfTokens)
        private
        returns(bool)
        {
           
            require( _amountOfTokens <= tokenBalanceLedger[_customerAddress] );
            
            //actually a transfer of 0 token is valid in ERC20
            if (_amountOfTokens>0)
            {
                
               
                {
                
                    uint256 _token_fee =  (_amountOfTokens.mul( transferFee )) / 100;
                   
                    _token_fee /= 2;
                   
                    
                    //now proceed the transfer
                    tokenBalanceLedger[ _customerAddress] = tokenBalanceLedger[ _customerAddress].sub( _amountOfTokens );
                    tokenBalanceLedger[ _toAddress] = tokenBalanceLedger[ _toAddress].add( _amountOfTokens - (_token_fee*2) );
                  
                    //half fee in HDX20 directly credited to developer
                    tokenBalanceLedger[ owner ] += _token_fee;
                    
                    //burning the other half of token to drive the price up
                    tokenSupply = tokenSupply.sub( _token_fee );
                  
                 
                    if (tokenSupply>magnitude)
                    {
                        tokenPrice = (contractValue.mul( magnitude)) / tokenSupply;
                    }
                   
                }
               
               
              
            
            }
          
          
            // fire event
            emit Transfer(_customerAddress, _toAddress, _amountOfTokens);
            
            // ERC20
            return true;
           
        }
        
        function transfer(address _toAddress, uint256 _amountOfTokens)
        public
        returns(bool)
        {
            
            return( transferSub( msg.sender ,  _toAddress, _amountOfTokens));
           
        }
        
      
        
        
        /*================================
        =  VIEW AND HELPERS FUNCTIONS    =
        ================================*/
        
      
        function totalEthereumBalance()
            public
            view
            returns(uint)
        {
            return address(this).balance;
        }
        
        function totalContractBalance()
            public
            view
            returns(uint)
        {
            return contractValue;
        }
        
      
        function totalSupply()
            public
            view
            returns(uint256)
        {
            return tokenSupply;
        }
        
      
        function myTokens()
            public
            view
            returns(uint256)
        {
            address _customerAddress = msg.sender;
            return balanceOf(_customerAddress);
        }
        
       
        function balanceOf(address _customerAddress)
            view
            public
            returns(uint256)
        {
            return tokenBalanceLedger[_customerAddress];
        }
        
        function sellingPrice( bool includeFees)
            view
            public
            returns(uint256)
        {
            uint256 _fee = 0;
            uint256 _devfee=0;
            
            if (includeFees)
            {
                _fee = (tokenPrice.mul( sellOutFee ) ) / 100;
                _devfee = (tokenPrice.mul( devFee ) ) / 100;
            }
            
            return( tokenPrice - _fee - _devfee );
            
        }
        
        function buyingPrice( bool includeFees)
            view
            public
            returns(uint256)
        {
            uint256 _fee = 0;
            uint256 _devfee=0;
            
            if (includeFees)
            {
                _fee = (tokenPrice.mul( buyInFee ) ) / 100;
                _devfee = (tokenPrice.mul( devFee ) ) / 100;
            }
            
            return( tokenPrice + _fee + _devfee );
            
        }
        
        function ethBalanceOf(address _customerAddress)
            view
            public
            returns(uint256)
        {
            
            uint256 _price = sellingPrice( true );
            
            uint256 _balance = tokenBalanceLedger[ _customerAddress];
            
            uint256 _value = (_balance.mul( _price )) / magnitude;
            
            
            return( _value );
        }
        
      
       
        function myEthBalanceOf()
            public
            view
            returns(uint256)
        {
            address _customerAddress = msg.sender;
            return ethBalanceOf(_customerAddress);
        }
       
       
        function ethBalanceOfNoFee(address _customerAddress)
            view
            public
            returns(uint256)
        {
            
            uint256 _price = sellingPrice( false );
            
            uint256 _balance = tokenBalanceLedger[ _customerAddress];
            
            uint256 _value = (_balance.mul( _price )) / magnitude;
            
            
            return( _value );
        }
        
      
       
        function myEthBalanceOfNoFee()
            public
            view
            returns(uint256)
        {
            address _customerAddress = msg.sender;
            return ethBalanceOfNoFee(_customerAddress);
        }
        
        function checkGameListed(address _contract)
            view
            public
            returns(bool)
        {
          
          return( gameWhiteListed[ _contract]);
        }
        
        function getSuperReferrerRate(address _customerAddress)
            view
            public
            returns(uint8)
        {
          
          return( referrerFee+superReferrerRate[ _customerAddress]);
        }
        
      
        
    }
    
    
    library SafeMath {
        
        /**
        * @dev Multiplies two numbers, throws on overflow.
        */
        function mul(uint256 a, uint256 b) 
            internal 
            pure 
            returns (uint256 c) 
        {
            if (a == 0) {
                return 0;
            }
            c = a * b;
            require(c / a == b);
            return c;
        }
    
        /**
        * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
        */
        function sub(uint256 a, uint256 b)
            internal
            pure
            returns (uint256) 
        {
            require(b <= a);
            return a - b;
        }
    
        /**
        * @dev Adds two numbers, throws on overflow.
        */
        function add(uint256 a, uint256 b)
            internal
            pure
            returns (uint256 c) 
        {
            c = a + b;
            require(c >= a);
            return c;
        }
        
       
        
      
        
       
    }