Build a decentralized voting app with Choice Coin and Javascript algorand SDK using NodeJS📨
Choice Coin is an Algorand Standard Asset that powers Decentralized Decisions, a voting and governance software built directly on the Algorand Blockchain.
Requirements
NPM and Node installed: Download Here
A PureStake Account: See Tutorial
A Funded Testnet Account : See Tutorial
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 = "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 = "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