Pages:
Author

Topic: [RLT][SMARTPLAY.TECH] 🎰 Vote for the design and get 100 RLT 🎰 - page 5. (Read 66983 times)

sr. member
Activity: 476
Merit: 253
Official representative
jr. member
Activity: 76
Merit: 1
sr. member
Activity: 476
Merit: 253
Official representative
How fair is the roulette on the Ethereum smart contract?  An independent audit of the game contract

We present to your attention a roulette audit from an independent developer Paul Rubin. Read, study and share your opinion about roulette!

Today it is very unlikely to meet a person who hasn't heard about cryptocurrencies and, in particular, about Bitcoin. In 2014, on a wave of interest in bitcoin, a new cryptocurrency - Ethereum, has been created. Today, in 2018, it has the largest capitalization after bitcoin. One of its most important differences from bitcoin is the use of a Turing virtual machine - EVM. More information about the Ethererum can be found in its Yellow Paper.

Today we will explore a game that works with Metamask wallet, a plugin for Google Chrome.

The game is the realization of the European roulette: there is the field with 37 cells numbered from 0 to 36. A player can bet on a specific number, or on a set of numbers: even/odd, red/black, 1-12, 1-18, etc. In each round, the player can make multiple bets (the minimum bet size is 0.01 ETH ≈ $ 7.26) on the corresponding field of the game table. Each field corresponds to a winning ratio. For example, the rate "to red" corresponds to a coefficient of 2 - placing a bet in amount of 0.01 ETH, in case of winning, the player will receive 0.02 ETH. And if the player bets on zero, the coefficient will be 36: paying the same 0.01 ETH for the bet the player will get 0.36.

Note
In the game contract, the coefficient for this bet is also listed as 35, and the bet amount is added to the amount of the win before the payment.

When all bets are made, the player presses the "Play" button and, via MetaMask, sends a bet to the Ethereum blockchain to the roulette contract address. The contract determines the random number, calculates the results of the bets and, if necessary, sends the winnings to the player.

In order to understand honestly whether the game is working (that is, if the casino does not manipulate when determining the random number for mercenary purposes), the work of the smart contract should be analyzed.

Its address is listed on the game website. In addition, before confirming the payment, you can check where the bet will be sent. The contract at the address 0xDfC328c19C8De45ac0117f836646378c10e0CdA3 will be analyzed as an example. Etherscan shows its code, and for convenient viewing, you can use Solidity Browser. The work of the contract begins with the placeBet() function:


Code:
function placeBet(uint256 bets, bytes32 values1,bytes32 values2) public payable
{
   if (ContractState == false)
   {
     ErrorLog(msg.sender, "ContractDisabled");
     if (msg.sender.send(msg.value) == false) throw;
     return;
   }
   var gamblesLength = gambles.length;

   if (gamblesLength > 0)
   {
      uint8 gamblesCountInCurrentBlock = 0;
      for(var i = gamblesLength - 1;i > 0; i--)
      {
        if (gambles[i].blockNumber == block.number)
        {
           if (gambles[i].player == msg.sender)
           {
               ErrorLog(msg.sender, "Play twice the same block");
               if (msg.sender.send(msg.value) == false) throw;
               return;
           }

           gamblesCountInCurrentBlock++;
           if (gamblesCountInCurrentBlock >= maxGamblesPerBlock)
           {
              ErrorLog(msg.sender, "maxGamblesPerBlock");
              if (msg.sender.send(msg.value) == false) throw;
              return;
           }
        }
        else
        {
           break;
        }
      }
   }
  
   var _currentMaxBet = currentMaxBet;

   if (msg.value < _currentMaxBet/256 || bets == 0)
   {
      ErrorLog(msg.sender, "Wrong bet value");
      if (msg.sender.send(msg.value) == false) throw;
      return;
   }

   if (msg.value > _currentMaxBet)
   {
      ErrorLog(msg.sender, "Limit for table");
      if (msg.sender.send(msg.value) == false) throw;
      return;
   }

   GameInfo memory g = GameInfo(msg.sender, block.number, 37, bets, values1,values2);

   if (totalBetValue(g) != msg.value)
   {
      ErrorLog(msg.sender, "Wrong bet value");
      if (msg.sender.send(msg.value) == false) throw;
      return;
   }      

   address affiliate = 0;
   uint16 coef_affiliate = 0;
   uint16 coef_player;
   if (address(smartAffiliateContract) > 0)
   {        
     (affiliate, coef_affiliate, coef_player) = smartAffiliateContract.getAffiliateInfo(msg.sender);  
   }
   else
   {
     coef_player = CoefPlayerEmission;
   }

   uint256 playerTokens;
   uint8 errorCodeEmission;
  
   (playerTokens, errorCodeEmission) = smartToken.emission(msg.sender, affiliate, msg.value, coef_player, coef_affiliate);
   if (errorCodeEmission != 0)
   {
      if (errorCodeEmission == 1)
        ErrorLog(msg.sender, "token operations stopped");
      else if (errorCodeEmission == 2)
        ErrorLog(msg.sender, "contract is not in a games list");
      else if (errorCodeEmission == 3)
        ErrorLog(msg.sender, "incorect player address");
      else if (errorCodeEmission == 4)
        ErrorLog(msg.sender, "incorect value bet");
      else if (errorCodeEmission == 5)
        ErrorLog(msg.sender, "incorect Coefficient emissions");
      
      if (msg.sender.send(msg.value) == false) throw;
      return;
   }

   gambles.push(g);

   PlayerBet(gamblesLength, playerTokens);
}



For Solidity newbies: the public and payable modifiers mean that the function is part of the API contract and when you call it, you can send ETH. In this case, information about the sender and the ETH amount will be available via the variable msg. The call parameters are the bit mask of bet types and two 32-byte arrays with the number of bets per type. You can guess this by looking at the definition of the GameInfo type and the functions getBetValueByGamble(), getBetValue ().


Code:
struct GameInfo
{
    address player;
    uint256 blockNumber;
    uint8 wheelResult;
    uint256 bets;
    bytes32 values;
    bytes32 values2;
}



// n - number player bet
// nBit - betIndex
function getBetValueByGamble(GameInfo memory gamble, uint8 n, uint8 nBit) private constant returns (uint256)
{
  if (n <= 32) return getBetValue(gamble.values , n, nBit);
  if (n <= 64) return getBetValue(gamble.values2, n - 32, nBit);
  // there are 64 maximum unique bets (positions) in one game
  throw;
}


// n form 1 <= to <= 32
function getBetValue(bytes32 values, uint8 n, uint8 nBit) private constant returns (uint256)
{
    // bet in credits (1..256)
    uint256 bet = uint256(values[32 - n]) + 1;

    if (bet < uint256(minCreditsOnBet[nBit]+1)) throw;   //default: bet < 0+1
    if (bet > uint256(256-maxCreditsOnBet[nBit])) throw; //default: bet > 256-0      

    return currentMaxBet * bet / 256;        
}


It is worth noting that getBetValue() returns the amount of the bet in wei.

The first thing placeBet() checks is that the contract is not turned off and then bet checks begin.
The gambles array is the repository of all the bets placed in this contract. placeBet() finds all the bets in its block and checks whether the current player has sent another bet in this block and whether the allowed amount of betting in the block is exceeded. Then, restrictions on the minimum and maximum amount of the bet are checked.

In the event of any error, the execution of the contract is terminated by the throw command, which rolls back the transaction, returning ETH to the player.

Further, the parameters passed to the function are stored in the GameInfo structure. It is important for us that the wheelResult field is initialized with the number 37.

After another check that the amount of bets coincides with the amount of ETH sent, the RLT tokens are distributed, the referral program is processed, the bet information is stored in gambles and a PlayerBet event is generated with the number and amount of the bet, which is seen in the game's web part.

RLT tokens
_At each bet, the player is given a certain number of RLT, ERC-20 tokens, which determine the right of the owner of tokens to receive the loyalty rewards from the profits received by the game creators. More information about this is given in White Paper.
The further life of the bet begins with calling the function ProcessGames(), which, after the appearance of a new bet, is being executed, at the present time, from the address 0xa92d36dc1ca4f505f1886503a0626c4aa8106497. Such calls are well visible when viewing the list of transactions of the game contract: they have Value=0.

ProcessGames code
Code:
function ProcessGames(uint256[] gameIndexes, bool simulate)
{
  if (!simulate)
  {
     if (lastBlockGamesProcessed == block.number)  return;
     lastBlockGamesProcessed = block.number;
  }

  uint8 delay = BlockDelay;
  uint256 length = gameIndexes.length;
  bool success = false;
  for(uint256 i = 0;i < length;i++)
  {      
     if (ProcessGame(gameIndexes[i], delay) == GameStatus.Success) success = true;        
  }      
  if (simulate && !success) throw;
}

In the call parameters, an array with the bet numbers requiring calculation is transmitted, and for each ProcessGame is called.

Code:
function ProcessGame(uint256 index, uint256 delay) private returns (GameStatus)
{            
  GameInfo memory g = gambles[index];
  if (block.number - g.blockNumber >= 256) return GameStatus.Stop;

  if (g.wheelResult == 37 && block.number > g.blockNumber + delay)
  {            
     gambles[index].wheelResult = getRandomNumber(g.player, g.blockNumber);
            
     uint256 playerWinnings = getGameResult(gambles[index]);
     if (playerWinnings > 0)
     {
        if (g.player.send(playerWinnings) == false) throw;
     }

     EndGame(g.player, gambles[index].wheelResult, index);
     return GameStatus.Success;
  }

  return GameStatus.Skipped;
}


The call parameters are the bet number and the number of blocks that must pass between the bet and its processing. When called from ProcessGames() or ProcessGameExt(), this parameter is currently 1, this value can be learned from the result of calling getSettings().

In the event that the number of the block in which processing takes place is more than 255 blocks apart from the betting block, it can not be processed: the block hash is available only for the last 256 blocks, and it is needed to determine the number dropped.

Next, the code checks whether the result of the game has already been calculated (remember, wheelResult was initialized with the number 37, which can't be the game result?) and whether the required number of blocks has already passed.

If the conditions are met, the call to getRandomNumber() is done to determine the random number, the win is calculated by calling getGameResult(). If it is not zero, ETH is sent to the player: g.player.send(playerWinnings). Then an EndGame event is created, which can be read from the web part of the game.

Let's see the most interesting part: how to determine the random number: the function getRandomNumber().


Code:
function getRandomNumber(address player, uint256 playerblock) private returns(uint8 wheelResult)
{
    // block.blockhash - hash of the given block - only works for 256 most recent blocks excluding current
    bytes32 blockHash = block.blockhash(playerblock+BlockDelay);
    
    if (blockHash==0)
    {
      ErrorLog(msg.sender, "Cannot generate random number");
      wheelResult = 200;
    }
    else
    {
      bytes32 shaPlayer = sha3(player, blockHash);

      wheelResult = uint8(uint256(shaPlayer)%37);
    }    
}


Its arguments are the player's address and the block number in which the bet was placed. The first thing the function gets is a block hash, which is separated from the bet block for BlockDelay blocks into the future.

This is an important point because if a player can somehow learn the hash of this block in advance, he can form a bet that is guaranteed to win. If you remember that there are Uncle blocks in Ethereum, there may be a problem and further analysis is required.

Next, SHA-3 is calculated from the gluing of the player's address and the received block hash. The dropped number is calculated by taking the remainder of dividing the result of SHA-3 by 37.

From my point of view, the algorithm is quite honest and the casino has no precedence over the player.

Why does the casino bring profit to its owners?

There are 37 cells on the field. For example, a player wants to make 100 000 bets on one particular field. Probably, about 2703 times the player will win, and all the other times he will lose. In this case, from the casino winnings, the player will receive 2703 * 36 = 97,308 RLT tokens. And 2692 RLT tokens, spent on bets, will go to the casino. Similar calculations can be made for all other types of bets.

It is also interesting to see, how the win is calculated. The getGameResult() function does this:

Code:
function getGameResult(GameInfo memory game) private constant returns (uint256 totalWin)
{
    totalWin = 0;
    uint8 nPlayerBetNo = 0;
    // we sent count bets at last byte
    uint8 betsCount = uint8(bytes32(game.bets)[0]);
    for(uint8 i=0; i    {                      
        if (isBitSet(game.bets, i))
        {              
          var winMul = winMatrix.getCoeff(getIndex(i, game.wheelResult)); // get win coef
          if (winMul > 0) winMul++; // + return player bet
          totalWin += winMul * getBetValueByGamble(game, nPlayerBetNo+1,i);
          nPlayerBetNo++;

          if (betsCount == 1) break;
          betsCount--;
        }
    }        
}


Parameter here is the structure of GameInfo with data about the calculated bet. And its wheelResult field is already filled with a random number.
Here is the cycle for all types of bets, in which the bit mask game.bets is checked and if the bit of the type being checked is installed, winMatrix.getCoeff() is requested. winMatrix is the contract with the address 0x073D6621E9150bFf9d1D450caAd3c790b6F071F2, loaded in the SmartRoulettee() constructor.
A parameter of this function is a combination of the bet type and the random number:



Code:
// unique combination of bet and wheelResult, used for access to WinMatrix
function getIndex(uint16 bet, uint16 wheelResult) private constant returns (uint16)
{
  return (bet+1)*256 + (wheelResult+1);
}



Have you played the Blockchain roulette by SmartPlay.tech? Don’t forget to share your opinion with other players, join the Telegram chat with the early project investors and ask you questions to the official representatives.
sr. member
Activity: 476
Merit: 253
Official representative
RLT was my very first investment. And it was a success. I am glad that the team is moving forward. Good luck, Smart Play !
Thank you for the words of support!

Join our Telegram group for the early investors and receive information about all the latest project news amont the first users!
sr. member
Activity: 476
Merit: 253
Official representative
It's hard to create a game that everyone loves to play. If you want to meet most of the requirements, you'd better ask the player's opinion to make it an excellent project content.

Thank you for your opinion  Smiley
Please, do not hesitate to contact us with your complaints and proposals, we are always open to your offers and comments on the project. You can leave it in this forum thread, in Telegram group or send it via email to [email protected].
full member
Activity: 185
Merit: 100
It's hard to create a game that everyone loves to play. If you want to meet most of the requirements, you'd better ask the player's opinion to make it an excellent project content.

You can always send an email to the devteam with your wishes, they always read emails and reply. By the way, what is your opinion about how to make the games and the project better? It's really interesting to read the different points of view  Smiley
member
Activity: 350
Merit: 10
It's hard to create a game that everyone loves to play. If you want to meet most of the requirements, you'd better ask the player's opinion to make it an excellent project content.
jr. member
Activity: 76
Merit: 1
Anyone here play at Bovada?
No actually, I like Win-Win roulette more. Have you played it?
jr. member
Activity: 360
Merit: 1
Anyone here play at Bovada?
jr. member
Activity: 360
Merit: 1
jr. member
Activity: 76
Merit: 1

b) expand the product line - we will announce the next game already this month


Whether a new game to use RLT? If not, will the holders of RLT be able to get a certain number of tokens of the new game through swapping?

I believe this game will be played on RLT, but let's wait for the official announcement.  Smiley
sr. member
Activity: 630
Merit: 250

b) expand the product line - we will announce the next game already this month


Whether a new game to use RLT? If not, will the holders of RLT be able to get a certain number of tokens of the new game through swapping?
jr. member
Activity: 76
Merit: 1
In one of the e-mails received from you, there was information about the new version of the site. When will it be available?
Thank you for your question.
Within a week we will demonstrate first drafts of the new site.
I will surely wait for that and will be the one of the firsts to try the new site and i am hoping that it's just another start of improving this project to stay and be more competitive alongside with the other project of the same concept.
Thank you for the words of support.

Subscribe to our Telegram group for the early investors, where the design of the new site was discussed today, and be along the first to receive the inside info from the devteam  Cheesy
I've created the Telegram account only to follow your news and updates  Grin
Guys, in case you haven't Telegram account, here is the latest info from the devs

First Ethereum fork support blockchain game with zero commissions and 291 ETZ winning pool launched.

🎮 Where to play:
https://smartroulette.io/blockchain
🎮  How to play:
https://steemit.com/blockchain/@smartplay.tech/faster-game-more-winnings-first-ethereum-fork-support-support-blockchain-game-with-zero-commissions-launched
🎮 Where to exchange:
Community build exchange https://t.co/VmsJrSYMSG is now open for the ETZ/ETH trading
sr. member
Activity: 476
Merit: 253
Official representative
In one of the e-mails received from you, there was information about the new version of the site. When will it be available?
Thank you for your question.
Within a week we will demonstrate first drafts of the new site.
I will surely wait for that and will be the one of the firsts to try the new site and i am hoping that it's just another start of improving this project to stay and be more competitive alongside with the other project of the same concept.
Thank you for the words of support.

Subscribe to our Telegram group for the early investors, where the design of the new site was discussed today, and be along the first to receive the inside info from the devteam  Cheesy
sr. member
Activity: 980
Merit: 294
In one of the e-mails received from you, there was information about the new version of the site. When will it be available?
Thank you for your question.
Within a week we will demonstrate first drafts of the new site.
I will surely wait for that and will be the one of the firsts to try the new site and i am hoping that it's just another start of improving this project to stay and be more competitive alongside with the other project of the same concept.
sr. member
Activity: 476
Merit: 253
Official representative
In one of the e-mails received from you, there was information about the new version of the site. When will it be available?
Thank you for your question.
Within a week we will demonstrate first drafts of the new site.
jr. member
Activity: 76
Merit: 1
In one of the e-mails received from you, there was information about the new version of the site. When will it be available?
sr. member
Activity: 476
Merit: 253
Official representative
Maybe airdrop no need? It can lead to a price drop, in my opinion. There are so many coins that airdrop has no effect on anything.
Let us tell you about our plans.
We understand that we've achieved stable turnover on a small exchange, and now for further growth, it is necessary to:
a) build a community
b) expand the product line - we will announce the next game already this month
c) access to larger stock exchanges

Airdrop is necessary to attract new investors, including the large ones.

Nice job, guys, hope your Airdrop will be a success.
Thank you for your support!
Join our Telegram chat for the early investors to discuss all the latest news with the official representatives  Wink
full member
Activity: 185
Merit: 100
Maybe airdrop no need? It can lead to a price drop, in my opinion. There are so many coins that airdrop has no effect on anything.
Let us tell you about our plans.
We understand that we've achieved stable turnover on a small exchange, and now for further growth, it is necessary to:
a) build a community
b) expand the product line - we will announce the next game already this month
c) access to larger stock exchanges

Airdrop is necessary to attract new investors, including the large ones.

Nice job, guys, hope your Airdrop will be a success.
sr. member
Activity: 476
Merit: 253
Official representative
Maybe airdrop no need? It can lead to a price drop, in my opinion. There are so many coins that airdrop has no effect on anything.
Airdrop on the other side is the simplest and easiest way of distribution, it's free and don't need too much task to get some and it is in favor of the recipient at the first glance but it would somewhat helps the dev or his project to have a large community of supporters and advertisers as well, yes it's FREE but it's a way of distribution, how would you get your coin into the market if you're the only one having all of them?
You are right, thank you for your comment.
The terms of participation will be published before the Airdrop start. Join our Telegram group to be the first to receive this information.
Pages:
Jump to: