Determining how Prizes Work
We have now arrived at the penultimate part of our series exploring how to launch HTML5 games in the Desktop Wallet using an ARK Core plugin and Construct 3 . If you’ve been following all the previous parts of this series, you will have successfully built a fully working blockchain game from scratch using smartbridge messages to make moves with an integrated lobby to make bets and match wagers.
While our game is fully functional, we haven’t yet implemented any prize logic aside from the initial wager matching. That is to say, winners, don’t get paid a prize and bets are not refunded in the case of a tie. However, that will be the subject of today’s tutorial.
Information
If this is your first time joining us, make sure to check out Part One of our tutorial series.
This tutorial is entirely based on the ARK Core plugin, so we will not be making any changes to our Construct 3 project at all this time. To get started, open up manager.ts in your text editor of choice!
Implementing Prize Logic
Before we start, we have to import Transactions from ARK’s crypto library. To do this, find:
1import { Identities } from "@arkecosystem/crypto";
Replace it with:
1import { Identities, Transactions } from "@arkecosystem/crypto";2 3// Now, we’ll examine the relevant part of our existing generateState function to see what happens when a game is won or tied:4 5if (outcome !== "ongoing") {6 break;7}
Let’s remember that in the event of a tie, the outcome variable value will be “tie” and if someone has won, the value of the outcome variable will be either 1 or 2, depending on if the winner was player 1 or player 2. Otherwise, the value will be “ongoing”.
From this code snippet, we can see at the moment, if the value of the outcome variable is not “ongoing” (i.e. the game was won or tied) then our loop ends, but nothing else happens. Let’s go ahead and revise this code now to include logic to pay our players. Since the code only ever executes if the game has been won or tied, we should check if it was in fact tied. If so, we return the wager to both players. If not, it means a player has won the game so should receive the whole prize, which is the sum of both wagers:
1if (outcome !== "ongoing") {2 if (outcome === "tie") {3 this.pay(address, players, wager);4 } else {5 this.pay(address, players[outcome], wager * 2);6 }7 break;8}
Of course, we must still write our pay function. In the event of a tie, the players’ object (which contains the addresses of both players) is sent to our function. When a game is won outright, just the address of the winner is sent to our function as a string. This means that our pay function will know which scenario is happening by checking if the data passed to it is an object of addresses (tie) or a single address string (win).
ARK Core 2.6 introduced a wide variety of useful features that we can take advantage of here. The first is sequential nonces. Simply put, each transaction from a sending wallet must have a nonce value that is unique and strictly one greater than the nonce value of the most recent transaction sent from the wallet. We can use this to check the nonce value of our game wallet — if the value is zero, it means we’ve not paid anybody yet, so we should do so. If the nonce value is not 0, we’ve already paid out for this game. This prevents a case where players are paid multiple times (e.g. when you restart your plugin and the game state is regenerated).
The second feature is multipayments. This means, in the event of a tie, we can pay both players in a single transaction. This helps to limit network congestion and since there is only one transaction, it means there is only one nonce.
Putting this together, our logic for the pay function is as follows:
- If the wallet’s nonce is non-zero, we’ve already paid, so we should exit our routine.
- We fetch the passphrase for the game wallet and its public key.
- If the data supplied to the function is a single string, we generate a standard transfer transaction for the amount specified, less the transaction fee, and send it to the address in the string.
- If the data supplied is an object containing multiple addresses, we generate a multipayment transaction for both of the players, with the amount specified, less the transaction fee.
- Once our transaction has been generated, we sign it and broadcast it to the network.
We can accomplish this in the following way:
1private pay(sender: string, recipient: string | object, amount: number) { 2 const wallet = app.resolvePlugin("database").walletManager.findById(sender); 3 if (wallet.nonce.toString() !== "0") { 4 return; 5 } 6 7 const passphrase = this.addresses[sender]; 8 const publicKey = Identities.PublicKey.fromPassphrase(passphrase); 9 const fee = "1000000";10 const payAmount = (amount — parseInt(fee)).toString();11 let transaction;12 13 if (typeof recipient === "string") {14 transaction = Transactions.BuilderFactory.transfer().nonce("1").senderPublicKey(publicKey).recipientId(recipient).fee(fee).amount(payAmount).vendorField("You won the game, congratulations!");15 } else {16 transaction = Transactions.BuilderFactory.multiPayment().nonce("1").senderPublicKey(publicKey).fee(fee).vendorField("The game was tied. Here is your wager!");17 transaction.addPayment(recipient[1], payAmount);18 transaction.addPayment(recipient[2], payAmount);19 }20 21 const signedTransaction = transaction.sign(passphrase).build();22 app.resolvePlugin("p2p").getMonitor().broadcastTransactions([signedTransaction]);23}
Run yarn build to compile our plugin, then restart ARK Core and enjoy!
Next Steps
Congratulations, our blockchain game can now calculate, award and pay out prizes or refund entry fees in the event of a tie. Our standalone game is now complete! In the final part of our tutorial series, we will set up our game as a plugin inside of the ARK Desktop Wallet.
If you become stuck at any point make sure to consult our documents on our Core Developer Docs. In addition, you can reach out via our contact form.
Check out previous posts in this series for reference here: