Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Beginner · 15 minutes or less

Algorand Payment App

This tutorial will teach us how to:
Build/Develop Mobile (Android/iOS) applications, Install Packages (Algorand SDK) to our Application, Process Payments for sending/transferring Algos from one account to another, Store/Save transaction history in a database on our Application and, Get or View Account Balance of the Account Address.

Requirements

Visual Studio IDE (install here ) with .NET Core Framework installed
Check the system requirements before you begin.
Download Visual Studio 2019 Community, Visual Studio Professional, or Visual Studio Enterprise from the Visual Studio Website
Select the Mobile development with .NET workload from the installation screen.
Algorand .NET SDK Package

Background

This tutorial will teach us how to: Build a DeFi Mobile Application on the Algorand Network to process payments/transactions Online.
This solution was built using the Xamarin Framework.

Steps

Step 1: Create Project

Open Visual Studio and create a new Project and select the (Mobile Application) as shown in Fig 1-1 and Fig 1-2 below:
EditorImages/2021/03/25 21:38/2021-03-10_19_59_08-Window.png
Fig 1-1

EditorImages/2021/03/25 21:39/2021-03-10_20_04_06-Microsoft_Visual_Studio.png

Fig 1-2
Configure the project as shown in Fig 1-2 above and click on Create.

Step 2: After successfully creating the project, the next step is to install the Algorand SDK into our application.

To do that, right click on the Project Name and click on the “Manage NuGet Packages” shown below in Fig 2-1

EditorImages/2021/03/25 21:41/2021-03-10_20_12_25-.png

Fig 2-1

EditorImages/2021/03/25 21:43/2021-03-10_20_22_04-AlgorandPayments_-_Microsoft_Visual_Studio.png
Fig 2-2

Click on the “Browse” Window and Search for Algorand, Click on Install to Install the Algorand Package into our Application as shown in Fig 2-2 above.

Step 3: Install SQLite Package into the Application to save/store transactions

EditorImages/2021/03/25 21:43/2021-03-10_20_29_55-AlgorandPayments_-_Microsoft_Visual_Studio.png
Fig 3-1

Install the Xamarin Essentials package also for secure storage use.
EditorImages/2021/04/18 22:24/2021-04-18_22_13_53-Window.png
Fig 3-2

Step 4: Create the Transfer Model

Right Click on the Models Folder and Create a class “Transfer.cs” and add the following code snippets below

using SQLite;

namespace AlgorandPayments.Models
{
    public class Transfer
    {
        [PrimaryKey]
        public int Id { get; set; }
        public string SenderAddress { get; set; }
        public string ReceiverAddress { get; set; }
        public int Amount { get; set; }
        public override string ToString()
        {
            return this.Amount + " algos to " + this.ReceiverAddress;
        }
    }
}

Step 5: Create the Views/Pages

Right Click on the Views Page and add three content pages as shown below in Fig 5-1
EditorImages/2021/03/25 21:46/2021-03-10_20_41_34-AlgorandPayments_-_Microsoft_Visual_Studio.png

Fig 5-1
EditorImages/2021/03/25 21:49/2021-03-10_20_41_34-AlgorandPayments_-_Microsoft_Visual_Studio.png
Fig 5-2

Create: “HomePage, TransactionsPage, and PaymentPage” as shown in Fig 5-1 and Fig 5-2 above.
In Figure 5-2, we can see the three newly created pages (Content Pages).

Step 6: Configure the Pages

Having created the Pages Step 5 we will now configure them to build up our application and its functionalities.

Configure the HomePage with the following code snippets:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Algorand.Client;
using Algorand;
using Algorand.V2.Model;
using Algorand.V2;
using Account = Algorand.Account;

using Xamarin.Forms;

namespace AlgorandPayments.Views
{
    public class HomePage : ContentPage
    {
        public HomePage()
        {
            this.Title = "Algorand Payment App";
            StackLayout stackLayout = new StackLayout();
            Button button = new Button();
            button.BackgroundColor = Color.Black;
            button.Text = "Make Payment";
            button.Clicked += Button_Clicked;
            stackLayout.Children.Add(button);
            //Second Button
            button = new Button();
            button.BackgroundColor = Color.Black;
            button.Text = "View Transactions";
            button.Clicked += Button_Clicked1;
            stackLayout.Children.Add(button);
            //Third Button
            button = new Button();
            button.BackgroundColor = Color.Black;
            button.Text = "Get Account Balance";
            button.Clicked += Button_Clicked2;
            stackLayout.Children.Add(button);
            Content = stackLayout;
        }

        private async void Button_Clicked2(object sender, EventArgs e)
        {
            string ALGOD_API_ADDR = "https://testnet-algorand.api.purestake.io/ps2"; //find in algod.net
            string ALGOD_API_TOKEN = "B3SU4KcVKi94Jap2VXkK83xx38bsv95K5UZm2lab"; //find in algod.token          
            var key = "pet rabbit charge admit cake chapter coyote mandate provide travel victory stamp sleep lizard absurd toward galaxy place kiwi economy indoor innocent grit abandon rose";
            string SRC_ACCOUNT = key;
            Account src = new Account(SRC_ACCOUNT);
            AlgodApi algodApiInstance = new AlgodApi(ALGOD_API_ADDR, ALGOD_API_TOKEN);
            var accountInfo = algodApiInstance.AccountInformation(src.Address.ToString());
            await DisplayAlert("Account Balance", $"{accountInfo.Address} has {accountInfo.Amount} Microalgos", "Balance", "Ok");
        }

        private async void Button_Clicked1(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new PaymentPage());
        }

        private async void Button_Clicked(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new TransactionsPage());
        }
    }
}

NOTE: This is for demo/testing purposes on the TestNet and will not work on MainNet/BetaNet.
DO NOT USE THIS FOR PRODUCTION.
The Mnemonic key of this account address is being displayed to show us how it looks like. !
Update the code snippets of the HomePage with the one above to create the buttons and that will handle events when clicked on.
Make Payment Button: This will take us to the TransactionsPage where the Transfer/Payment of Algos functionality will be processed.
View Transactions Button: This will take us to the page where we can view our transaction history which will be stored into our application database.
Get Account Balance Button: This will notify us of the balance available in our account address.

Step 7: Configure TransactionsPage

Open the TransactionsPage and update it with the code snippets below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using SQLite;
using Algorand.Client;
using Algorand;
using Algorand.V2.Model;
using Algorand.V2;
using Account = Algorand.Account;
using Xamarin.Forms;
using AlgorandPayments.Models;
using Xamarin.Essentials;

namespace AlgorandPayments.Views
{
    public class TransactionsPage : ContentPage
    {
        private Entry _AddressEntry;
        private Entry _AmountEntry;
        private Button _SaveEntry;
        //Database
        string _dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "Mydbs.db3");
        public TransactionsPage()
        {
            this.Title = "Process Transaction";
            StackLayout stackLayout = new StackLayout();
            //Receiver Address Entry
            _AddressEntry = new Entry();
            _AddressEntry.Keyboard = Keyboard.Text;
            _AddressEntry.Placeholder = "Receiver Address";
            stackLayout.Children.Add(_AddressEntry);
            //Amount Entry
            _AmountEntry = new Entry();
            _AmountEntry.Keyboard = Keyboard.Text;
            _AmountEntry.Placeholder = "Amount";
            stackLayout.Children.Add(_AmountEntry);
            //Save Button
            _SaveEntry = new Button();
            _SaveEntry.Text = "Proceed with Transfer";
            _SaveEntry.Clicked += _SaveEntry_Clicked;
            stackLayout.Children.Add(_SaveEntry);
            Content = stackLayout;
        }

        private async void _SaveEntry_Clicked(object sender, EventArgs e)
        {
            var db = new SQLiteConnection(_dbPath);
            db.CreateTable<Transfer>();
            var maxpk = db.Table<Transfer>().OrderByDescending(i => i.Id).FirstOrDefault();
            Transfer payment = new Transfer()
            {
                Id = (maxpk == null ? 1 : maxpk.Id + 1),
                SenderAddress = "4GIK2BGHFB3BTD2URC4FQLK7TO5XDJ6TYU7NSOZOHL7HZVUHDFFWUIOTNA",
                ReceiverAddress = _AddressEntry.Text,
                Amount = Convert.ToInt32(_AmountEntry.Text)
            };
            var key = "pet rabbit charge admit cake chapter coyote mandate provide travel victory stamp sleep lizard absurd toward galaxy place kiwi economy indoor innocent grit abandon rose";
            try
            {
                await SecureStorage.SetAsync("token", key);
            }
            catch (Exception ex)
            {
                // Possible that device doesn't support secure storage on device.
            }
            try
            {
                var Token = await SecureStorage.GetAsync("token");
                db.Insert(payment);
                key = Token;
                FundMethod(Token, payment.ReceiverAddress, payment.Amount, payment.SenderAddress);
                await DisplayAlert("Success", "Transfer of " + payment.Amount + " algos to " + payment.ReceiverAddress + " was successfull.", $"Successfully Transfered {payment.Amount} Algos", "Ok");
                await Navigation.PopAsync();
            }
            catch (Exception ex)
            {
                // Possible that device doesn't support secure storage on device.
            }

        }
        public static void FundMethod(string key, string receiver, int amount, string senderAddr)
        {
            string ALGOD_API_ADDR = "https://testnet-algorand.api.purestake.io/ps2"; //find in algod.net
            string ALGOD_API_TOKEN = "B3SU4KcVKi94Jap2VXkK83xx38bsv95K5UZm2lab"; //find in algod.token          
            string SRC_ACCOUNT = key;
            string DEST_ADDR = receiver;
            Account src = new Account(SRC_ACCOUNT);
            AlgodApi algodApiInstance = new AlgodApi(ALGOD_API_ADDR, ALGOD_API_TOKEN);
            try
            {
                var trans = algodApiInstance.TransactionParams();
            }
            catch (ApiException e)
            {
                Console.WriteLine("Exception when calling algod#getSupply:" + e.Message);
            }

            TransactionParametersResponse transParams;
            try
            {
                transParams = algodApiInstance.TransactionParams();
            }
            catch (ApiException e)
            {
                throw new Exception("Could not get params", e);
            }
            var amountsent = Utils.AlgosToMicroalgos(amount);
            var tx = Utils.GetPaymentTransaction(src.Address, new Address(DEST_ADDR), amountsent, "pay message", transParams);
            var signedTx = src.SignTransaction(tx);

            Console.WriteLine("Signed transaction with txid: " + signedTx.transactionID);

            // send the transaction to the network
            try
            {
                var id = Utils.SubmitTransaction(algodApiInstance, signedTx);
                Console.WriteLine("Successfully sent tx with id: " + id.TxId);
                Console.WriteLine(Utils.WaitTransactionToComplete(algodApiInstance, id.TxId));
            }
            catch (ApiException e)
            {
                // This is generally expected, but should give us an informative error message.
                Console.WriteLine("Exception when calling algod#rawTransaction: " + e.Message);
            }
        }
    }
}

The _SaveEntry_Clicked event handler uses the Xamarin Essentials with the Secure Storage to save and retrieve the key (mnemonic key) in the program.
The following code below in the above program handles the secure storage functionality in the code snippet below:

var key = "pet rabbit charge admit cake chapter coyote mandate provide travel victory stamp sleep lizard absurd toward galaxy place kiwi economy indoor innocent grit abandon rose";
            try
            {
                await SecureStorage.SetAsync("token", key);
            }
            catch (Exception ex)
            {
                // Possible that device doesn't support secure storage on device.
            }
            try
            {
                var Token = await SecureStorage.GetAsync("token");
                db.Insert(payment);
                key = Token;
                FundMethod(Token, payment.ReceiverAddress, payment.Amount, payment.SenderAddress);
                await DisplayAlert("Success", "Transfer of " + payment.Amount + " algos to " + payment.ReceiverAddress + " was successfull.", $"Successfully Transfered {payment.Amount} Algos", "Ok");
                await Navigation.PopAsync();
            }
            catch (Exception ex)
            {
                // Possible that device doesn't support secure storage on device.
            }

This will handle the processes involved when transferring Algos from one your account address to another.

The FundMethod contains the functionality of the transfer of algos from one account to another.
Transaction Details will be stored in our application database created in this step.

NOTE: This is for demo/testing purposes on the TestNet and will not work on MainNet/BetaNet. The Mnemonic key of this account address is being displayed to show us how it looks like. Never share or publicly display your account key with anyone!
Use the https://testnet.algoexplorer.io/ to check your live transactions as shown below running on the TestNet in Fig 7-1
EditorImages/2021/03/25 21:58/2021-02-28_12_07_36-Window.png

Fig 7-1

To fund an account address on the TestNet, visit https://bank.testnet.algorand.network/
EditorImages/2021/03/25 21:59/2021-02-26_22_39_25-Window.png

Additional Resource/Tip: If you wish to invoke the dispenser pragmatically from the code, you can pass the address as a parameter on the call to the dispenser site. https://bank.testnet.algorand.network?account=xxxxx

Fig 7-2

Step 8: Configure PaymentPage

Open the PaymentPage and update it with the code snippets shown below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SQLite;
using AlgorandPayments.Models;
using Xamarin.Forms;
using System.IO;

namespace AlgorandPayments.Views
{
    public class PaymentPage : ContentPage
    {
        private ListView _listView;
        string _dbPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "Mydbs.db3");
        public PaymentPage()
        {
            this.Title = "Transactions";
            var db = new SQLiteConnection(_dbPath);
            StackLayout stackLayout = new StackLayout();
            _listView = new ListView();
            _listView.ItemsSource = db.Table<Transfer>().OrderBy(n => n.Id).ToList();
            stackLayout.Children.Add(_listView);
            Content = stackLayout;
        }
    }
}

This page will display the list of transactions that have been made and stored in our database.

Step 9: Configure Startup Page

Open the App.xaml.cs file and update the MainPage as shown below in Fig 8-1.
This will configure the page that will first display when the application opens.
EditorImages/2021/03/25 22:01/2021-03-11_21_14_46-Window.png

Fig 9-1

Step 10: Live Application Screenshots/Demo

Homepage:
EditorImages/2021/03/25 22:06/2021-03-25_23_04_11-Algorand_Payment_App_-_Google_Docs.png
Fig 10-1

Get Account Balance:
EditorImages/2021/03/25 22:06/2021-03-25_23_05_05-Algorand_Payment_App_-_Google_Docs.png
Fig 10-2

TransactionsPage:
EditorImages/2021/03/25 22:06/2021-03-25_23_05_20-Algorand_Payment_App_-_Google_Docs.png
Fig 10-3

PaymentPage:
EditorImages/2021/03/25 22:06/2021-03-25_23_05_34-Algorand_Payment_App_-_Google_Docs.png

Fig 10-4

Conclusion

In this solution, we have learnt how to create a Mobile App with a database and also learnt how to interact with the Algorand Network from our application to handle and process transactions by sending algos from one account address to another.
Source Code: GitHub