/
Write
Start a team blog
NEW ✨
Start a team blog, invite your team, and start publishing.
Build a decentralized voting app with Choice Coin and Javascript algorand SDK using NodeJS📨

Build a decentralized voting app with Choice Coin and Javascript algorand SDK using NodeJS📨

Samuel Tosin's photo
Samuel Tosin
·Jan 20, 2022·

7 min read

Choice Coin is an Algorand Standard Asset that powers Decentralized Decisions, a voting and governance software built directly on the Algorand Blockchain.

Requirements

In this Tutorial, we are going to build a decentralized voting application with javascript algorand sdk using NodeJs.

1. Set up project folder and install algosdk

Create a new project folder, this can be done in the terminal with :

$ mkdir choice-coin-voting-app

After creating the project folder, enter the directory in your terminal

$ cd choice-coin-voting-app

To install dependencies in the project, you need to start an NPM instances using:

$ npm init -y

Create a new file, I will name mine index.js. This can also be done in the terminal with:

$ touch index.js

In the terminal, npm install both AlgoSDK and Prompt-Sync

$ npm install algosdk prompt-sync

AlgoSDK is the official JavaScript library for communicating with the Algorand network. It's designed for modern browsers and Node.js. Prompt-Sync module is a function that creates prompting functions, this is the same thing with browsers' prompt but this works with NodeJs environment

In index.js file, import both modules

const algosdk = require('algosdk'); 
const prompt = require('prompt-sync')();

2. Configure Purestake API and Create client

Register for a Purestake developer account and get your API key to interact with algorand network.

const server = "https://testnet-algorand.api.purestake.io/ps2";
const port = "";
const token = {
  "X-API-Key": "YOUR API KEY", 
};

Create AlgodClient variable to start connection

const algodClient = new algosdk.Algodv2(token, server, port)

3. Recover Account And Enter Choice Coin Asset ID

  • Create new testnet wallet address from either myAlgoWallet or Algosigner, Copy and save your 25 mnemonic passphrase and do not share with anyone.
  • Fund the wallet address with some testnet algos HERE.
  • Opt In to $Choice Coin asset using ID 21364625 using myAlgoWallet or Algosigner
  • Swap the testnet Algos to $choice on Tinyman.

In index.js


const mnemonic = "The mmemonic 25 characters seperated by a whitespace should be imported here"; 

const recoveredAccount = algosdk.mnemonicToSecretKey(mnemonic); 

const ASSET_ID = 21364625

const voting_address = ""

In the constant voting_address input a newly created voting address wallet different from the one recovered that $choice voting amount can be sent to, make sure $choice is opt-in to receive votes just like earlier

4. Choosing Voting Option and Sending Vote

Create a voting function and send the voted amount from the recoveredAccount to the voting_address wallet depending on the candidate option being voted.

const chooseVotingOption = async () => {
    const candidateOption = prompt("Press 0 for candidate Zero or Press 1 for candidate One:") 

     const amount = prompt("Please enter Amount to commit to voting:");


    const params =  await algodClient.getTransactionParams().do()
    const encoder = new TextEncoder()

     if (!(candidateOption)) {
         console.log('Please select a valid candidate option');
     } else if (!Number(amount)) {
         console.log("Please Enter A valid Choice token amount to vote")
     }
      else  if (candidateOption == "0") {
            try {
                let txn = algosdk.makeAssetTransferTxnWithSuggestedParams(
                    recoveredAccount.addr,
                    voting_address,
                    undefined,
                    undefined,
                    Number(amount),
                    encoder.encode("Voting with Choice coin"),
                    ASSET_ID,
                    params

                )

        let signedTxn = txn.signTxn(recoveredAccount.sk);
        const response =  await algodClient.sendRawTransaction(signedTxn).do();
            if(response) {
              console.log(`You just voted for candidate Zero,Your voting ID: ${response.txId}`);

                waitForConfirmation(algodClient, response.txId);
            } else {
                console.log('error voting for candidate Zero, try again later')
            }

        }
        catch(error) {
            console.log("error voting for candidate Zero, Try again later");
        }

 } 


     else  if(candidateOption == "1"){
        try {
            let txn = algosdk.makeAssetTransferTxnWithSuggestedParams(
                recoveredAccount.addr,
                voting_address,
                undefined,
                undefined,
                Number(amount),
                encoder.encode("Voting with Choice coin"),
                ASSET_ID,
                params
            )
       let signedTxn = txn.signTxn(recoveredAccount.sk);
       const response =  await algodClient.sendRawTransaction(signedTxn).do();
            if(response) {
               console.log(`You just voted for candidate One,Your voting ID: ${response.txId}`);

                waitForConfirmation(algodClient, response.txId);
            } else {
               console.log('error voting for candidate one, try again later')
            }

        }
        catch(error) {
            console.log("Error voting for candidate One, Try again later");
        }

        }
        }

5. Wait For Confirmation To Sync Vote From Algorand Blockchain

const waitForConfirmation = async function (algodClient, txId) {
    let lastround = (await algodClient.status().do())['last-round'];
     while (true) {
        const pendingInfo = await algodClient.pendingTransactionInformation(txId).do();
        if (pendingInfo['confirmed-round'] !== null && pendingInfo['confirmed-round'] > 0) {
          //Got the completed Transaction
          console.log('Voting confirmed in round ' + pendingInfo['confirmed-round']);
          break;
        }
        lastround++;
        await algodClient.statusAfterBlock(lastround).do();
     }
 };

This function verify when the vote is being confirmed from algorand network.

6. Check $Choice Balance After Voting

const checkBalance = async () => {

  //get the account information
    const accountInfo =  await algodClient.accountInformation(recoveredAccount.addr).do();
    const assets =  accountInfo["assets"];

    //get choice amount from assets
     assets.map(asset => {
        if (asset['asset-id'] === ASSET_ID) {
            const amount = asset["amount"];
            const choiceAmount = amount / 100;
            console.log(
                `Account ${recoveredAccount.addr} has ${choiceAmount} $choice`
              );
              return;
        }  else {
            console.log(`Account ${recoveredAccount.addr} must opt in to Choice Coin Asset ID ${ASSET_ID}`);
          }
     })

  };

Check $Choice balance after voting has ended, if There is no choice asset ID in the account information. the function is stopped using return and a console message is shown to add choice asset ID to the account.

7. Run The Full Code

The index.js would look like.

const algosdk = require('algosdk'); //importing algosdk
const prompt = require('prompt-sync')(); //importing nodeJs  prompt to enable prompt in a nodeJs environment

// open a purestaker api and get a unique API KEY
const server = "https://testnet-algorand.api.purestake.io/ps2";
const port = "";
const token = {
  "X-API-Key": "" //your API key gotten from purestake API, 
};
const algodClient = new algosdk.Algodv2(token, server, port); //connecting to algodclient

// create a testnet account with myalgowallet, keep the mmemonic key;
const mnemonic = "The mmemonic 25 characters seperated by a whitespace should be imported here";

// get account from mmemonic key;
const recoveredAccount = algosdk.mnemonicToSecretKey(mnemonic); 

//choice coin asset ID 
const ASSET_ID = 21364625

// voting address
const voting_address = "" //input a voting address wallet you can send choice to, make sure choice is opt-in to receive votes

//Press 1 to vote for candidate one and 0 to vote for candidate Zero

const chooseVotingOption = async () => {
    const candidateOption = prompt("Press 0 for candidate Zero or Press 1 for candidate One:") 
     const amount = prompt("Please enter Amount to commit to voting:");


    const params =  await algodClient.getTransactionParams().do(); //get params
    const encoder = new TextEncoder();  //message encoder

    // if there is no valid option 
     if (!(candidateOption)) {
         console.log('Please select a valid candidate option');
     } else if (!Number(amount)) {
         console.log("Please Enter A valid Choice token amount to vote")
     }
     // if your option is candidate zero
      else  if (candidateOption == "0") {
            try {
                let txn = algosdk.makeAssetTransferTxnWithSuggestedParams(
                    recoveredAccount.addr,
                    voting_address,
                    undefined,
                    undefined,
                    Number(amount),
                    encoder.encode("Voting with Choice coin"),
                    ASSET_ID,
                    params

                )

            let signedTxn = txn.signTxn(recoveredAccount.sk);
            const response =  await algodClient.sendRawTransaction(signedTxn).do();
            if(response) {
                console.log(`You just voted for candidate Zero,Your voting ID: ${response.txId}`);
                // wait for confirmation
                waitForConfirmation(algodClient, response.txId);
            } else {
                console.log('error voting for candidate Zero, try again later')
            }

        }
        catch(error) {
            console.log("error voting for candidate Zero, Try again later");
        }

 } 
 // if your option is candidate one

 else  if(candidateOption == "1"){
    try {
        let txn = algosdk.makeAssetTransferTxnWithSuggestedParams(
            recoveredAccount.addr,
            voting_address,
            undefined,
            undefined,
            Number(amount),
            encoder.encode("Voting with Choice coin"),
            ASSET_ID,
            params
        )
        let signedTxn = txn.signTxn(recoveredAccount.sk);
        const response =  await algodClient.sendRawTransaction(signedTxn).do();
        if(response) {
            console.log(`You just voted for candidate One,Your voting ID: ${response.txId}`);
            // wait for confirmation
            waitForConfirmation(algodClient, response.txId);
        } else {
            console.log('error voting for candidate one, try again later')
        }

    }
    catch(error) {
        console.log("Error voting for candidate One, Try again later");
    }

    }
    }

chooseVotingOption();

//verification function
const waitForConfirmation = async function (algodClient, txId) {
    let lastround = (await algodClient.status().do())['last-round'];
     while (true) {
        const pendingInfo = await algodClient.pendingTransactionInformation(txId).do();
        if (pendingInfo['confirmed-round'] !== null && pendingInfo['confirmed-round'] > 0) {
          //Got the completed Transaction
          console.log('Voting confirmed in round ' + pendingInfo['confirmed-round']);
          break;
        }
        lastround++;
        await algodClient.statusAfterBlock(lastround).do();
     }
 };


// check account balance
const checkBalance = async () => {


  //get the account information
    const accountInfo =  await algodClient.accountInformation(recoveredAccount.addr).do();
    const assets =  accountInfo["assets"];

    //get choice amount from assets
     assets.map(asset => {
        if (asset['asset-id'] === ASSET_ID) {
            const amount = asset["amount"];
            const choiceAmount = amount / 100;
            console.log(
                `Account ${recoveredAccount.addr} has ${choiceAmount} $choice`
              );
              return;
        }  else {
            console.log(`Account ${recoveredAccount.addr} must opt in to Choice Coin Asset ID ${ASSET_ID}`);
          }
     })

  };

checkBalance();

In Conclusion, We made a voting application with choice coin and JavaScript algorand SDK using NodeJS. You can check the full code on Github