Suppose you have a circle of friends who you meet with in a sports bar to drink beer, watch sports and make bets. You can make bets on the Nxt Blockchain and have a basic Python app automate it for you.
In my first article I introduced basics of a blockchain. As we learned, the most important value proposition of the blockchain is immutability of data submitted in transactions recorded into blocks, from which a blockchain is built.
Today I want to show how to build a simple but fully functional betting app in python. For the betting app that I present, immutability of data may be required, but in the case a bet should need to be canceled, the app can be modified to take into account this additional functionality.
Pre-requisites:
NRS (Nxt Reference software) 1.10.2: https://bitbucket.org/JeanLucPicard/nxt/downloads/, Python 3 (or Python 2 with slightest modification). A beer or two (optional).
Application logic
A user submits a bet (transfers any amount of NXT coins) to the betting account and adds a public unencrypted attachment. In the attachment he should write the id of the bet, a colon and a number indicating his choice in the corresponding bet. Let’s give an example: the sports bar runs a bet which football team wins. They assign an ID to this game, let’s say “30”.
The choices are:
“1” – home team wins. “2” – other team wins. “3” – tie.
To bet on the victory of the home team, the player must submit a transaction of any amount of NXT, and attach a public unencrypted (for auditability) message with the content: 30:1
When the time comes, the betting host runs the app to find winners and process payments. The host can take a small fee for the service.
Implementation
The Nxt Server listens for queries on port 7876. If you run it on the same machine as your python code by default you must submit queries to http://127.0.0.1:7876/nxt
For our app we will need to import a few modules and write the function to submit queries which will be used a few times through the app.
import sys, json, re def sendQuery(Query): from urllib import parse, request params = parse.urlencode(Query) headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} req = request.Request("http://127.0.0.1:7876/nxt", params.encode('utf-8')) response = request.urlopen(req) return response.read() myAccount = "NXT-AAAA-BBBB-CCCC-DDDDD" totalAmount = 0 serviceFee = 0.05 players = [] secretPhrase = "bla bla bla"
The function returns a JSON string to be decoded, with transactions and attachments to be parsed. Also a few variables are initialized.
Next we must query the betting account to fetch all incoming transactions.
This is the request you can send to the NXT server to execute this:
Query = {'requestType': 'getBlockchainTransactions', 'account': myAccount, 'type': '0', 'subtype': '0', 'executedOnly': 'true'}
decode JSON and load it to a variable for further processing.
output = sendQuery(Query) data = json.loads(output.decode('utf-8'))
As we have all the data now, we loop through the list and discard some of the transactions we don’t need. For instance, we don’t need to process outgoing transactions, so we continue the loop from the next item.
for i in data['transactions']: txAmount = i['amountNQT'] txSender = i['senderRS'] if txSender == myAccount: continue txRecipient = i['recipientRS'] if txRecipient != myAccount: continue
Next we pull out the attachment, check if it is not encrypted and strip whitespace.
line = i['attachment']['message'] lineIsText = i['attachment']['messageIsText'] if line.strip() != "" and lineIsText == True: line = line.strip()
Next step is to match the submitted message against the regular expression. It must satisfy the format “Number:Number”, the first number can be up to 3 digits.
matchLine = re.match(r'(\d{1,3}:\d{1})(.*)', line, re.M|re.I)
If the attached message is of correct format we process it further…
The betting app accepts up to 3 command-line arguments: id of the game, the choice number that has won, and third optional parameter in double quotes to name the winner choice for verbosity in the payout message.
For instance, the betting host must run it like this:
python3 bet.py 30 1 “Home team wins”
The app will process transactions with game id 30 and rewards players who chose ‘1’.
The third argument can be omitted: python3 bet.py 30 1
Next we must calculate the sum of money submitted for our game, make a list of dictionaries of players who guessed the correct number, and calculate the total sum for distribution after the betting host gets his optional service cut.
if matchLine: if matchLine.group(1).split(':')[0] == sys.argv[1]: totalAmount += int(txAmount) if matchLine.group(1).split(':')[1] == sys.argv[2]: d = {txSender: matchLine.group(1).split(':')[1], 'amount': txAmount} players.append(dict(d)) afterFee = float(totalAmount - totalAmount * serviceFee)
We have winners in the ‘players’ list of dictionaries, we have money to distribute in ‘afterFee’, let us now process payouts.
sumCorrect = 0 for i in players: for key in i: if i[key] == sys.argv[2]: sumCorrect += float(i['amount']) for i in players: for key in i: if i[key] == sys.argv[2]: t = float(i['amount']) * (afterFee / sumCorrect) if t > afterFee: strSendAmount = str(int(afterFee)) else: strSendAmount = str(int(t)) if len(sys.argv) > 3: reply = sys.argv[3] else: reply = sys.argv[2] message = "Payout for correct bet in poll " + sys.argv[1] + "; your reply: " + reply Query = {'requestType': 'sendMoney', 'recipient': key, 'amountNQT': strSendAmount, 'secretPhrase': secretPhrase, 'feeNQT': '100000000', 'deadline': '1440', 'broadcast': 'true', 'message': message, 'messageIsText': 'true', 'messageIsPrunable': 'true'} sendQuery(Query)
Needless to say the app can be improved to process errors, cancel bets or optionally allow other parameters in attached messages. Attached messages can be submitted with the Nxt Client (NRS) or from a web wallet that allows sending attachments.
To make transactions on the Nxt Blockchain you need NXT coins, which you can purchase directly, by exchanging Bitcoin for NXT or by attending the “Lucky Node” project by running a public Nxt node (Nxt server).
To learn how to participate in the Lucky node project, please visit https://nxtforum.org.
There are over a hundred API calls you can make to the Nxt server, a full list with mandatory and optional parameters and examples is available at https://nxtwiki.org/wiki/The_Nxt_API.
Cheers!