The original link

Playing Rock-paper-Scissors is fun, but adding your life savings is even more fun. Let’s modify the program so that Alice can bet with Bob, and the winner of the guessing game wins the prize. This time, we’ll start with the JavaScript front end and then go back to the code in Reach to add the new methods. Since we’re moving money, we need to keep track of each participant’s balance before the game starts so that we can show more clearly how much money they ultimately won. We will add code between account creation and contract deployment. tut-4/index.mjs

.// ...
5    const stdlib = await loadStdlib();  
6    const startingBalance = stdlib.parseCurrency(10);  
7    const accAlice = await stdlib.newTestAccount(startingBalance);  
8    const accBob = await stdlib.newTestAccount(startingBalance);  
9    
10    const fmt = (x) = > stdlib.formatCurrency(x, 4);  
11    const getBalance = async (who) => fmt(await stdlib.balanceOf(who));    
12    const beforeAlice = await getBalance(accAlice);  
13    const beforeBob = awaitgetBalance(accBob); .// ...
Copy the code
  • Line 10 makes use of a nice function that displays the token amount (up to 4 decimal places).
  • Line 11 makes use of the function used to get the actor’s balance and display it in up to four decimal places.
  • Lines 12 and 13 retrieve Alice’s and Bob’s balances before the game begins.

Next we update Alice’s user interface to let her place bets. tut-4/index.mjs

.// ...  
32    backend.Alice(ctcAlice, {  
33. Player('Alice'),  
34      wager: stdlib.parseCurrency(5),  
35}),..// ...
Copy the code
  • Line 33 connects the general player interface to Alice’s interface.
  • Line 34 sets her bet to five network tokens, which is an example of using concrete values rather than functions in the participant interface.

As for Bob, we modify his interface to display the bet and accept it immediately by returning the value. tut-4/index.mjs

.// ...
36    backend.Bob(ctcBob, {
37. Player('Bob'),
38      acceptWager: (amt) = > {
39        console.log(`Bob accepts the wager of ${fmt(amt)}. `);
40      },
41}),..// ...
Copy the code
  • Lines 38 through 40 define acceptWager, the wager accepting function.

Finally, after the calculation, we will get the balance again and display a summary message. tut-4/index.mjs

.// ...  
44    const afterAlice = await getBalance(accAlice);  
45    const afterBob = await getBalance(accBob);  
46    
47    console.log(`Alice went from ${beforeAlice} to ${afterAlice}. `);  
48    console.log(`Bob went from ${beforeBob} to ${afterBob}. `); .// ...
Copy the code
  • Lines 44 and 45 fetch the final balance.
  • Lines 47 and 48 print the results.

These changes to the front end only deal with output and interface issues; the actual operation of betting and transferring tokens is implemented in the code of Reach. Let’s move on to the code. First, we need to update the participant interface. tut-4/index.rsh

1    'reach 0.1';  
2    
3    const Player =  
4          { getHand: Fun([], UInt),  
5            seeOutcome: Fun([UInt], Null) };  
6    const Alice =  
7          { ...Player,   
8            wager: UInt };  
9    const Bob =  
10          { ...Player,  
11            acceptWager: Fun([UInt], Null) };  
12    
13    export const main =   
14      Reach.App(   
15        {},  
16        [Participant('Alice', Alice), Participant('Bob', Bob)],  
17        (A, B) => {  
..          // ...  
42          exit(); });
Copy the code
  • Lines 6 through 8 define Alice’s interface, plus an integer value called wager.
  • Bob’s interface is similar in lines 9 through 11, where he has a method called acceptWager to check the value of the wager.
  • Line 16 associates these interfaces with the corresponding actors. This line of code is formatted as a tuple of the actor constructor, where the first argument is a string named the back-end actor and the second argument is the actor interaction interface, which is customically named with similar names.

Each of the three parts of the application had to be modified to make the bet work. Let’s look at Alice’s first step. tut-4/index.rsh

.// ...  
18    A.only(() = > {   
19      const wager = declassify(interact.wager);  
20      const handA = declassify(interact.getHand()); });   
21    A.publish(wager, handA)  
22      .pay(wager);  
23commit(); .// ...
Copy the code
  • Line 19 tells Alice to decrypt the bet for transmission.
  • Line 21 updates that Alice sends Bob the amount of her bet.
  • Line 22 Alice transfers the bet as part of her broadcast. You can try that if the wager appears on line 22 instead of line 21, the Reach compiler will throw an exception. This is because the consensus network must be able to verify that the number of network tokens contained in an Alice broadcast matches some calculations available to the consensus network.

Next, You need to let Bob know about the bet and give him the opportunity to accept the bet and transfer the token. tut-4/index.rsh

.// ...    
25    B.only(() = > {   
26      interact.acceptWager(wager);   
27      const handB = declassify(interact.getHand()); });  
28    B.publish(handB)  
29.pay(wager); .// ...
Copy the code
  • Line 26 tells Bob to accept the bet. If he does not accept, then his front-end can not reply to the method, and the DApp will stop.
  • Line 29 tells Bob to pay the bet, as before.

The DApp is running in the consensus step, and the contract itself now has twice the bet. In the previous example, it evaluates the result and then commits the status. But now it needs to look at the results and process the bet money. tut-4/index.rsh

.// ...  
31    const outcome = (handA + (4 - handB)) % 3;  
32    const [forA, forB] =  
33          outcome == 2 ? [2.0] :  
34          outcome == 0 ? [0.2] :  
35          [1.1];  
36    transfer(forA * wager).to(A);  
37    transfer(forB * wager).to(B);  
38commit(); .// ...
Copy the code
  • Lines 33 through 35 determine the amount of each party’s bet and calculate the amount given to each participant based on the results. If the result is 2, Alice wins, then she doubles her bet; If it is 0, Bob wins, and he doubles his bet; Otherwise, they would each have doubled their bet.
  • Lines 36 and 37 transfer the corresponding tokens. This transfer is a transfer from the contract to the participants, not from the participants to each other, because all the money is currently inside the contract.
  • Line 38 submits the state of the application and allows the participant to view the results and execute.

Now we can run the program and see its output. $ ./reach run Since the players act randomly, the results will be different every time. When I ran the program three times, this is the output I got: $ ./reach run Alice played Paper Bob accepts the wager of 5. Bob played Rock Alice saw outcome Alice wins Bob saw Outcome Alice wins Alice went from 10 to 14.9999. Bob went from 10 to 4.9999. $./reach run Alice played Paper Bob accepts the wager of 5. Bob played Scissors Alice saw outcome Bob wins Bob saw outcome Bob wins Alice went from 10 to 4.9999. Bob went from 10 to 14.9999. $./reach run Alice played Rock Bob accepts the wager of 5. Bob played Scissors Alice saw outcome Alice wins Bob saw outcome Alice wins Alice went from 10 to 14.9999. Bob went from 10 to 4.9999.

Why do Alice’s and Bob’s balances go back to 10 every time? This is because every time we run “./ Reach Run “, it starts a new instance of the test network and registers an account for each player. Why aren’t the balances 10,15 and 5? This is because running ethereum transactions consumes gas. If all the decimal points were displayed, it would look something like this:

Alice went from 10 to 14.9999999999687163.

Bob went from 10 to 4.999999999999978229.

Alice went from 10 to 4.999999999999687163.

Bob went from 10 to 14.999999999999978246.

Why does Alice win less money when she wins than Bob? Because she has to pay to deploy the contract because she called acc.deploy on the front end. The deployment guide section discusses how to avoid this difference.

Alice has a bright future ahead of her. If she keeps gambling, it looks like she can make a fortune in rock-paper-Scissors!

If your version doesn’t work correctly, check the full versions of Tu-4 /index.rsh and tu-4 /index.mjs and make sure you copy everything correctly.

There is, however, a major security concern with the application. We’ll fix it next; Don’t release with this version or Alice will go bankrupt!

Do you know:

How does the Reach program manage tokens?

  1. They don’t manage, you need to explicitly manage tokens in the Reach program;

  2. The pay primitive can be added to the publish primitive to send funds to the Reach program, so that the transfer primitive can then be used to send funds back to participants and other addresses.

The answer:

2; The pay and transfer primitives will take care of this for you.

2.3 Rock paper Scissors

2.5 Trust and Engagement