1. Solidity Smart Contract code

The first step is to modify our existing Smart Contract called “Dice.sol” to add the needed functions to finish the game. If you remember, this is the code that we developed previously in the last episode:

As you can see, the contract is really simple. It only has 2 functions. The constructor to setup the first player address and escrow and the setupPlayer2() function to store the address and escrow of the second user.

Before creating the finish function, I want you to understand how it will work.

We are using a state channel between 2 users where they exchange encrypted messages that contain the latest balance of the past games combined, the nonce, the dice selected, the bet for the current game, the sequence and the address of the player.

So the way that we create the finish functionality is by taking the 2 latests messages, one per player and uncrypt them with the original data to recognize how much ether each player gets.

The 2 lastest messages contain all the information that we need to recall the final outcome of the game.

Let’s create a verifyPlayerBalance() function which is our finish function. It’s called that way because we will actually verify that the message is valid and then send the corresponding ether to both players. Here’s how it looks like:

And here’s the breakdown. Pay attention to it because it’s quite a complex function and you want to get it right:

First, notice that the function receives 7 arguments:

function verifyPlayerBalance(bytes playerMessage, uint256 playerCall, uint256 playerBet, uint256 playerBalance, uint256 playerNonce, uint256 playerSequence, address addressOfMessage) public {}

We need the signed message, the call, the bet, balance, nonce, sequence and address of the player. Turns out that we have all that information stored on the server so it won’t be a problem.

We require all those parameters because you have to have them to uncrypt the signed message and check if it’s valid.

Then we define some simple require checks with error messages. We make sure that the player 2 is setup, that the signed message is valid with the required length of 65 bytes and that the address of the player used is a valid address set up before.

Next we generate a new encrypted message with the parameters used on the client: the nonce, call, bet, balance and sequence.

After that we use an assembly block to get the values of r, v and s . Those are special variables used for signing a message with your ethereum address. You need them to check if the original signer of the message is the user that you specified. You can copy it as it is since it won’t change soon.

. Those are special variables used for signing a message with your ethereum address. You need them to check if the original signer of the message is the user that you specified. You can copy it as it is since it won’t change soon. Then we simply retrieve the address used in that message with the global function ecrecover() . We do this to check if the signer is the address that you sent to the function addressOfMessage .

. We do this to check if the signer is the address that you sent to the function . Then, we store in the contract’s state variables the balance, bet and call of the player that signed that message. We need to store that information in the contract because we’ll need it later for distributing the funds.

The thing is that we are using 2 separate calls to the function verifyPlayerBalance() for uncrypting the data of both messages. We can’t uncrypt both messages in 1 single function since the contract would revert because of the size of the function. There would be just too many computations in one execution.

for uncrypting the data of both messages. We can’t uncrypt both messages in 1 single function since the contract would revert because of the size of the function. There would be just too many computations in one execution. Finally we determine if both balances are setup and if so, we distribute the funds after calculating the outcome of this final game. Remember that each message contained the latest balance and the call of the dice but we didn’t calculate the outcome of that final game so we have to do it in the contract.

Congratulations if you made it all the way here! It’s difficult to understand all those blocks immediately so take your time to understand how this finish function works. The major things that we did inside can be resumed in 3 simple actions or steps:

Check that the parameters are valid.

Generate a new encrypted message to see if the one that you sent is valid.

Distribute the ether of the game balances after both have verified their balance with this function.

Here’s how the final smart contract looks like. Note that we added several state variables at the top so be sure to incorporate them to your code:

I also encourage you to check the final code in my github to learn to see how it all fits together here: https://github.com/merlox/dice/tree/master/5/src