Tutorials
No Results
Tutorial

Intermediate · 1 hour

Using ASA as Monopoly Money

250 million copies of Monopoly have been sold since 1935 (in 103 Countries and 37 languages) and today averages 3.3 million copies sold annually. This classic game includes paper Monopoly money and each year Parker Brothers prints more Monopoly money than the US government prints real currency.

Using this tutorial, you will upgrade your Monopoly gameplay with blockchain-based digital money! A live version is running on the Algorand TestNet at TheMonopolyBank.com and shortly you will have this web application replicated on your localhost and connected to the network as well.

Requirements

Background

My main goals are to show the ability of the Algorand blockchain to quickly create digital tokens, make very fast transactions, and use the Algorand Mobile Wallet to enhance gameplay for our digital world.

To interact with the web application, at least two people or two devices are required, which is logical since Monopoly is played by four to eight participants.

Steps

1. Development

The source code for this tutorial can be found on GitHub. Start by cloning the repository:

git clone https://github.com/dashboardblock/themonopolybank.git

Change into the project directory:

cd themonopolybank

The repository contains the following:

  • algo_handler.py - contains main functions.
  • index.py - contains Flask settings.
  • /templates - contains site templates.
  • /static - contains static files (site images, css, js).

2. Environment Setup

Install all dependencies in your environment:

pip3 install py-algorand-sdk
pip3 install Flask

Install pyqrcode module to generate QR-codes.

$ pip3 install pyqrcode

Install pypng module to save images in png format.

$ pip3 install pypng

3. Flask

Flask is a web framework for Python. It’s easy to get started with because it doesn’t have a huge learning curve. It is designed to keep the core of the application simple and scalable. On top of that it’s very explicit, which increases readability.

Open the index.py file with your favorite editor. The first couple of lines import the Flask framework, some helpers and our Algorand handlers.

from flask import Flask, request, render_template
from algo_handler import create_account, fund_transaction

We use the request method to work with forms. Web applications use different HTTP methods when accessing URLs. By default, a route only answers to GET requests. Use the methods argument of the route() decorator to handle POST methods.

To render a template you can use the render_template method. All you have to do is provide the name of the template and the variables you want to pass to the template engine as keyword arguments.

Two methods from algo_handler are responsible for the main functions of the web application.

The first create_account creates a new address and supplements it with tokens.

The second fund_transaction supplements the existing address with tokens.

Both methods need a role to determine the size of the deposit, we get it from the POST request and forms published from the corresponding templates.

Following the imports section is the instantiation of our Flask application. Just below are the definitions for each route the application contains.

application = Flask(__name__)


@application.route("/")
def start():
    """ Start page """
    return render_template('index.html')


@application.route('/new/')
def new():
    """ New account """
    return render_template('new.html')


@application.route('/create/', methods=['POST', 'GET'])
def create():
    """ Create new account """
    if request.method == 'POST':
        role = request.form.get('role')
        qr_file, message = create_account(role)
        return render_template('create.html', qr_file=qr_file, message=message)
    return render_template('create.html')


@application.route('/deposit/', methods=['POST', 'GET'])
def deposit():
    """deposit"""
    message = ''
    error = ''
    if request.method == 'POST':
        send_to_address = request.form.get('wallet')
        role = request.form.get('role')
        message, error = fund_transaction(send_to_address, role)
    return render_template('deposit.html', message=message, error=error)


@application.route('/refund/')
def refund():
    """refund"""
    return render_template('refund.html')


@application.route('/about/')
def about():
    """about"""
    return render_template('about.html')


if __name__ == "__main__":
    application.run(host='127.0.0.1', debug=True)

The last few lines launch our application on our localhost.

4. Jinja templates

Flask comes packaged with the powerful Jinja templating language.

For those who have not been exposed to a templating language before, such languages essentially contain variables as well as some programming logic, which when evaluated (or rendered into HTML) are replaced with actual values.

The variables and/or logic are placed between tags or delimiters. For example, Jinja templates use {% ... %} for expressions or logic (like for loops), while {{ ... }} is used for outputting the results of an expression or a variable to the end user. The latter tag, when rendered, is replaced with a value or values, and is seen by the end user.

Flask will look for templates in the /templates folder.

For example create.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="/static/css/mystyle.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script src="/static/js/menu.js"></script>
  <title>The Monopoly&reg; Bank</title>
</head>
<body>
{% include 'header.html' %}
<article>
{% if qr_file %}
        <center><h3><p style="color:green">{{ message }}</p></h3>
        <img src="../{{ qr_file }}"/ width="300" height="300"></center>
{% else %}
<center>
<h3>
<form action="" method="POST">
Choose your role:
    <p>
<input type="radio" name="role" id="option1" value="player" checked> Player </input><br>
<input type="radio" name="role" id="option2" value="banker"> Banker </input><br>
    </p>
    <p>
        <input type="submit">
    </p>
</form></h3>
{% endif %}
</center>
</article>  
{% include 'footer.html' %}
</body>
</html>

In this template, we use the construction with the condition.

if the qr_file variable is defined then display the QR-code image and the corresponding message.
else, we display a form for requesting the player’s role in the game.

Here qr_file is the path to the PNG file that contains the QR-code with the passphrase for the new address.

The {% include} command allows you to insert other templates into the current template, which we will use for the header and footer blocks that are repeated on each page.

5. Python Code

Let’s now look at the source code of Algo_handler.py to review the functions to create wallet, opt-in and send assets.

5.1 Set Configuration Values

The first part of this file defines your specific variables. Be sure to set the following values accordingly:

ALGOD_ADDRESS = "https://testnet-algorand.api.purestake.io/ps1"
ALGOD_TOKEN = ""
HEADERS = {"X-API-Key": ALGOD_TOKEN}
ALGODCLIENT = algod.AlgodClient(ALGOD_TOKEN, ALGOD_ADDRESS, HEADERS)
SENDER_ADDRESS = ""
SENDER_MNEMONIC = ""
SENDER_PRIVATE_KEY = mnemonic.to_private_key(SENDER_MNEMONIC)
ASSET_ID = ""

Info

Asset details to supply at AlgoDesk.io

Asset Name : Monopoly Money
Unit Name : MM
Total Supply : 1,000,000,000
Decimals : 0
Asset URL : https://themonopolybank.com
Metadata Hash : empty
Manager, Reserve, Clawback, Freeze Adresses : (use defaults)

5.2 Functions for Algo and assets transfer.

def algo_transaction(sender, private_key, receiver, amount):
    """Function for Algos transfer"""
    params = ALGODCLIENT.suggested_params()
    txn = PaymentTxn(sender, params, receiver, amount, None)
    signed_tx = txn.sign(private_key)
    ALGODCLIENT.send_transaction(signed_tx)
    return True

def asset_transfer(sender, private_key, receiver, amount, index):
    """Function for asset transfer"""
    params = ALGODCLIENT.suggested_params()
    txn = AssetTransferTxn(sender, params, receiver, amount, index)
    signed_tx = txn.sign(private_key)
    ALGODCLIENT.send_transaction(signed_tx)
    return True

Two key functions for working with the blockchain are algo_transaction for sending a certain amount from one address sender with a private_key to another receiver.

For the asset_transfer function, the asset ID number index is also added to the parameters.

5.3 Check account information for opt-in Monopoly Money asset

def check_optin(address):
    """ Check account information for opt-in Monopoly Money asset"""
    account_info = ALGODCLIENT.account_info(address)
    try:
        account_info['assets'][str(ASSET_ID)]['amount']
    except KeyError:
        return False
    return True

In order to transfer the token to the address, the owner of the address must give his consent (opt-in) to this. This is done on the Algorand blockchain network to avoid massive spam by sending tokens to existing addresses.

The check_optin function checks this condition by requesting details by address.

For new addresses that the application creates, this check is not needed, since we are performing the opt-in operation instead of the user.

6.5 Fund existing account with Monopoly Money

def fund_transaction(address, role):
    """ Fund account with Monopoly Money """
    amount = 0
    message_text = ''
    error_text = ''
    if encoding.is_valid_address(address):
        if check_optin(address):
            if role == 'player':
                amount = 1500
                message_text = 'Your account has been funded with 1,500 Monopoly Money'

            elif role == 'banker':
                amount = 20000
                message_text = 'Your account has been funded with 20,000 Monopoly Money'

            asset_transfer(SENDER_ADDRESS, SENDER_PRIVATE_KEY, address, amount, ASSET_ID)
        else:
            error_text = "Your account not opt-in to Monopoly Money asset"
    else:
        error_text = "Enter correct Algorand address"
    return message_text, error_text

The fund_transaction function checks whether the correct Algorand address was received through the form, whether sending our asset to this address is allowed (opt-in done) and, according to the specified role, fund the balance by 1500 MM or 20000 MM.

5.5 Create new account, send a few Algo for opt-in and fund this account with Monopoly Money

def create_account(role):
    """ Create new account """
    RECEIVER_PRIVATE_KEY, RECEIVER_ADDRESS = account.generate_account()
    amount = 0
    algo_amount = 301000
    message = ''
    if role == 'player':
        amount = 1500
        message = 'Your account has been created with 1,500 Monopoly Money. Scan QR code.'

    elif role == 'banker':
        amount = 20000
        message = 'Your account has been created with 20,000 Monopoly Money. Scan QR code. '

    # Send 0.301 Algo to new account (for opt-in and transaction fees)
    algo_transaction(SENDER_ADDRESS, SENDER_PRIVATE_KEY, RECEIVER_ADDRESS, algo_amount)

    # Opt-in Monopoly Money Asset
    asset_transfer(RECEIVER_ADDRESS, RECEIVER_PRIVATE_KEY, RECEIVER_ADDRESS, 0, ASSET_ID)

    # Send Monopoly Money Asset
    asset_transfer(SENDER_ADDRESS, SENDER_PRIVATE_KEY, RECEIVER_ADDRESS, amount, ASSET_ID)

The create_account function includes several operations.

First, we create a new account and get the values RECEIVER_PRIVATE_KEY, RECEIVER_ADDRESS for it.

Second, we fund the new account with 0.301 Algo. The minimum wallet balance to add ASA to it must be 0.2 Algo, and another 0.1 Algo must be enough for 100 game transactions. In any case, since the application is powered by TestNet, you can top up your balance with free Algo through the Algorand Testnet Dispenser.

Third, In order to subscribe to an asset, a transaction is made to your own wallet with the amount of the asset equal to zero and the ID number of the asset ASSET_ID.

Fourth, we fund the wallet balance with our token based on the selected role.

Finally, let’s look at the generation of a QR code separately.

5.6 Create QR with passphrase

passphrase = '{{"version":"1.0", "mnemonic":"{}"}}'.format(mnemonic.from_private_key(RECEIVER_PRIVATE_KEY))
qr_code = pyqrcode.create(passphrase)
rnd = random.random()
qr_file = 'static/{}{}.png'.format(RECEIVER_ADDRESS, str(rnd))
qr_code.png(qr_file, scale=6)
return qr_file, message

In order for the user to start using the address that we generated for him and have fun playing monopoly with Monopoly Money ASA instead of paper banknotes, he needs to install the Algorand Wallet application. It has a great wallet import feature using a 25-word passphrase.

Therefore, to begin with, we get a list of these 25 words from the RECEIVER_PRIVATE_KEY and compile in the format in which this phrase is contained in a QR-code suitable for import into Algorand Wallet:

'{"version": "1.0", "mnemonic": "atom smart zero sleep ... etc."}'

passphrase = '{{"version":"1.0", "mnemonic":"{}"}}'.format(mnemonic.from_private_key(RECEIVER_PRIVATE_KEY))

Using the pyqrcode module, create from this string a QR object.

qr_code = pyqrcode.create(passphrase)

Create a unique qr_file path to save the file using the address and a random number rnd.

For example:

static / VQKSRSJDVAHRDYH67EW2X7J4ROPFVNU7DAZJPTKSRHLR5FD4DKUTUBYITQ0.304577052485252.png

rnd = random.random()
qr_file = 'static/{}{}.png'.format(RECEIVER_ADDRESS, str(rnd))

Lastly, create a file from a QR object with the specified parameters, the path and size of the image and return create_account function results .

qr_code.png(qr_file, scale=6)
return qr_file, message

6. Let’s Play

Start by installing the Algorand Mobile Wallet. Be sure to switch your wallet to TestNet. Open Algorand Wallet >> Settings >> Developer Settings >> Node Settings >> Select the Node “TestNet”

Next, use your web browser to navigate to the “Create account” tab on your localhost version of TheMonopolyBank website. This will prompt you to create a new account which generates a QR-code with a 25-word passphrase.

Within your Mobile Wallet click the “Recover from Passphrase” button and scan the QR code from the website to import your new account.

If you already have an Algorand account on TestNet, use the Top-Up tab to add Monopoly money.

Depending on your chosen role within the Monopoly game, your digital wallet will be funded with 1,500MM or 20,000MM and minimum amount of Algo for making transactions.

7. What’s next

The source code for this web app can be found at themonopolybank on GitHub. This is an open source project, demonstrating the capabilities of the Algorand blockchain. Contributions are welcome if you find it an use interesting case.

python

flask

Jinja

December 30, 2020