
Build an Algorand Web Wallet Interface Using Reach and React
The business value of this tutorial is to teach how to use the Reach frontend to connect to an Algorand wallet and sign transactions using MyAlgo Wallet and Algosigner with React.The reason for choosing Reach and React for this project is because Reach is the fastest and easiest way to create DApps which can be deployed on multiple platforms and React is one of the most popular frontend library of choice for most developers and organizations.
Connecting to a wallet is one important requirements most DApp developers will have to integrate in their application when creating a DApp on the Algorand Blockchain.
This tutorial will guide you in connecting your DApp to an Algorand wallet using either MyAlgo Wallet or AlgoSigner. The tutorial and code solution is divided into two sections. MyAlgo Wallet Connect with Reach and Algosigner independent of Reach.
Connecting to MyAlgo Wallet is part of the inbuilt integration in reach which provides a fallback to connect to the wallet. AlgoSigner is not integrated in reach and so integrating AlgoSigner in your DApp does not require Reach.
To get the complete code here is the github repo and here is the link to the hosted Demo on netlify.

Requirements
- Algorand JavaScript SDK for Algosigner
- Vs Code or any IDE of your choice
- Node Package Manager
- Create React App . This creates a react boilerplate app.
- The Reach JS stdlib, whose installation information is included below in Project Set-Up. The Reach stdlib provides a front-end interface to connect to wallets and deploy/attach to Reach smart contracts.
- Reach Executable.The Reach executable depends on make, Docker, and Docker Compose.The best way to install Docker on Mac and Windows is with Docker Desktop.
Background
Reach is a domain-specific language for building decentralized applications (DApps).Reach is a blockchain-agnostic programming language which has similar syntax as JavaScript. Reach automatically verify smart contracts at a lower cost, and compile them to multiple blockchains. Reach currently compiles to Algorand, Ethereum and Conflux, and plans to expand to more soon.
Reach also has created a front-end library to connect to devnet wallets or directly to Algosigner, MyAlgo Wallet or Metamask if deploying to Etherum blockchain. This project uses the front-end library with React to create a simple Algorand wallet interface. This tutorial makes use of the Algorand TestNet to enable the user to check account balance, fund account and transfer fund to another account using Reach and React. The user can connect to either MyAlgo Wallet or AlgoSigner.
MyAlgo Wallet is a web based wallet and AlgoSigner is chrome extension used for for connecting DApps for signing transactions on the Algorand blockchain.
Note
AlgoSigner is not integrated in Reach, we will add it manually if we want to Sign transactions with AlgoSigner.
For more information on Reach, check out the Reach site, docs, and Discord server.
At the end of this tutorial the UI should look like this.
Fig 0-1 App UI
Steps
1. Project Setup and React Installation
To create an App with React, first you need to have installed node and then install react globally if you are installing it for the first time to avoid installing react each time you need to create react app.
Fig 1-1 helps to confirm that node is installed.
Fig 1-1 Node npm version
npm install -g create-react-app
This will install react globally on your machine. The next thing to do is to enter this command
Fig 1-2 Create React App
Fig 1-3 Create React App Installation Files
create-react-app reach-react-wallet
. This will create a boilerplate React app with the project name as reach-react
. After that navigate into the project folder by doing cd reach-react
. Congratulations your boilerplate react app is all set you can run it by using this command npm start
Fig 1-4 React App UI
For this tutorial we will be using styled component to write our css. To use styled component we will need to install it.
From your terminal type npm install --save styled-components
. With this we can setup our css using styled component. Here is the link to learn more about styled component.
Note
Reach has React built in functionality. To have access to React while using Reach you simply need to do the following;
As a convenience for running the React development server, you can call:
./reach react
To run the React development server with Algorand, you can call:
REACH_CONNECTOR_MODE=ALGO ./reach react
But for this tutorial we are running react from scratch and we will delete some of the boilerplate files.
Fig 1-4 Boilerplate Project Structure
At this point your project structure currently looks like this.Delete everything from the source folder except App.js
and index.js
then on the public folder delete everything from the index.html
After deleting those files your file structure should look like this.
Fig 1-5 Modified Boilerplate Project Structure
To avoid running into errors after deleting those files. open index.js
and App.js
and remove the unused imports.
For now, your App.js
file should look like this
Fig 1-6 App.js
And index.js
file should look like this
Fig 1-7 index.js
The project structure will be updated in step 3.
2. Reach Installation
Note
This setup guide will be important when setting up Reach. Make sure the make, docker and docker compose are all installed. To be sure they are installed you can check up their version from the terminal by doing the following;
make --version
docker --version
docker-compose --version
Fig 2-1 make, docker and docker-compose
Fig 2-1 help to confirm that the above has been successfully installed.
Once you are sure that they are installed, next download Reach by running
curl https://docs.reach.sh/reach -o reach ; chmod +x reach
Fig 2-2 Reach download
To get started using Reach JavaScript standard library you need to install Reach using this command. First navigate/cd to the src folder to then run
npm install @reach-sh/stdlib
Fig 2-3 Reach JavaScript Library Installation
Then run ./reach update
(this will download the libraries)
3. Project Structure
Fig 3-1 Project Structure
For the tutorial, your project structure should look like Fig 3-1 above.
Here is a quick breakdown of the folder/file structure. In order to keep things neat and modular, I have decided to seperate the files. One aspect of clean coding involves seperation of concerns.
The Asset folder
takes care of images and css folder. The Component folder
takes care of the components which contains AlgoSigner folder, Header folder,MyAlgoWallet folder, Button.Styles.js and Form.style.js.
App.js, constants.js,index.js, Main.styles.js are directly inside the source folder. Assets and Components folder are also inside the src folder
. Reach is also inside the src folder.
4. Main Page and Style
App.js
/*global AlgoSigner*/
import React from 'react'
import Header from './components/Header/header'
import MyAlgoWallet from './components/MyAlgoWallet/MyAlgoWallet'
import AlgoSigner from './components/AlgoSigner/AlgoSigner'
import { Main, MainBody } from './Main.styles'
import './assets/css/app.css'
function App(){
return(
<MainBody>
<Header/>
<Main>
<MyAlgoWallet/>
<AlgoSigner/>
</Main>
</MainBody>
)
}
export default App
Main.styles.js
import styled from "styled-components"
export const Main = styled.div`
display : flex;
justify-content : space-evenly;
@media(max-width : 560px){
flex-direction : column;
align-content : center;
align-items : center;
}
`
export const MainBody = styled.div`
background-color : #F8F9FF;
height : 100vh;
`
index.js
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
header.js
import React from 'react'
import { MainHeader, HeaderText } from './MainHeader.styles'
const Header = () => {
return(
<MainHeader>
<HeaderText>Welcome to Algorand Wallet Connect</HeaderText>
</MainHeader>
)
}
export default Header
MainHeader.styles.js
import styled from "styled-components";
export const MainHeader = styled.header `
padding : 20px;
margin : 0;
background-color : #F4F1FE;
`
export const HeaderText = styled.h3`
text-align : center;
font-family : 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif
`
src/assets/css/app.css
body {
background: #F8F9FF;
}
constants.js
const ALGOD_SERVER = 'https://testnet-algorand.api.purestake.io/ps2'
const INDEXER_SERVER = 'https://testnet-algorand.api.purestake.io/idx2'
const TOKEN = { 'X-API-Key': 'YOUR PURESTAKE API KEY' }
const PORT = '443';
module.exports = {
ALGOD_SERVER,
INDEXER_SERVER,
TOKEN,
PORT,
}
5. MyAlgo Wallet
MyAlgo is an Algorand Wallet allowing you to freely interact with the Algorand blockchain.
MyAlgo provides the simplest and most secure way to send and receive Algos and tokens, organize and track all your Algorand wallets, manage your assets and much more.
This section will take care of connecting to My Algo Wallet and performing transactions using Reach. To get started using MyAlgo Wallet you will need to create account on the Algorand TestNet which you will connect to later on in the tutorial. Here is the link to get that setup.
5.1 Connect To MyAlgo Wallet
To connect to MyAlgo Wallet your code should look like this. This code covers the connection and retrieving of the account balance. This also includes the user interface for MyAlgo Wallet, which takes care of Funding and Transfering of Fund.
Note
Here are some things to note about useRef
and useState
and why it is used in this tutorial. The useRef
hook call returns an object that has a property current, which stores the actual value and the useState
Hook enables the development of component state for functional components.
To get the user account using Reach this method will be called reach.getDefaultAccount()
and to get the account balance of the user will be reach.balanceOf()
this takes in one argument the user account.
Fig 5-1-1 MyAlgo Wallet Connect
Fig 5-1-2 MyAlgo Wallet Account and Balance
import React, {useState, useRef} from 'react'
import { loadStdlib } from '@reach-sh/stdlib'
import MyAlgoConnect from '@reach-sh/stdlib/ALGO_MyAlgoConnect';
import ConnectWalletButton from './ConnectButton/ConnectWalletBtn';
import TransferFund from './Transferfund';
import FundAccount from './FundWallet';
import myalgo from '../../assets/images/myaglo-logo.png'
import { MyAlgoWalletMain } from './MyAlgoWallet.styles';
const reach = loadStdlib("ALGO")
reach.setWalletFallback(reach.walletFallback({
providerEnv: 'TestNet', MyAlgoConnect }));
const MyAlgoWallet = () => {
const account = useRef()
const balance = useRef()
const [accountBal, setAccountBal] = useState(0);
const [accountAddress, setAccountAddress] = useState('');
const connectWallet = async () =>{
try{
await getAccount()
await getBalance()
}catch(err){
console.log(err)
}
}
const getAccount = async () => {
try{
account.current = await reach.getDefaultAccount()
setAccountAddress(account.current.networkAccount.addr)
console.log("Account :" + account.current.networkAccount.addr)
}catch(err){
console.log(err)
}
}
const getBalance = async () => {
try{
let rawBalance = await reach.balanceOf(account.current)
balance.current = reach.formatCurrency(rawBalance, 4)
setAccountBal(balance.current)
console.log("Balance :" + balance.current)
}catch(err){
console.log(err)
}
}
return(
<MyAlgoWalletMain>
<img src= {myalgo} alt="My Algo" height= "70px"/>
<ConnectWalletButton accountAddress={accountAddress} connectWallet = {connectWallet} accountBal = {accountBal}/>
<TransferFund account = {account} getBalance = {getBalance} />
<FundAccount account = {account} getBalance = {getBalance}/>
</MyAlgoWalletMain>
)
}
export default MyAlgoWallet
Note
When using Reach it is important to specify the network you would want to connect to. Otherwise connection defaults to Metamask if you have it installed.
From the above code when trying to connect to the Algorand network using MyAlgo Wallet these lines are important.
import MyAlgoConnect from '@reach-sh/stdlib/ALGO_MyAlgoConnect';
const reach = loadStdlib("ALGO")
reach.setWalletFallback(reach.walletFallback({
providerEnv: 'TestNet', MyAlgoConnect }));
5.2 Transfer Fund
This handles transferring of fund to the specified account. To transfer fund this function will be called reach.transfer()
this takes in three arguments, the account, receiver and amount.
Fig 5-2-1 Transfer Fund With MyAlgo Wallet
Fig 5-2-2 Transfer Fund UI
import React, {useRef, useState} from "react";
import { loadStdlib } from '@reach-sh/stdlib'
import { FormStyle } from "../Form.style";
import { Button, TransactionButton } from "../Button.styles";
import { BodyText } from "./MyAlgoWallet.styles";
const reach = loadStdlib("ALGO")
const TransferFund = ({account, getBalance}) => {
const transferAmount = useRef()
const receiverAddress = useRef()
const [isLoading, setLoading] = useState(false)
const transferFund = async () =>{
try{
setLoading(true)
const receiver = await reach.connectAccount({
addr: receiverAddress.current
})
console.log(receiver)
await reach.transfer(account.current, receiver, reach.parseCurrency(transferAmount.current))
await getBalance()
setLoading(false)
}catch(err){
console.log(err)
setLoading(false)
}
}
return(
<div>
<br/>
<BodyText>Transfer Fund</BodyText>
<FormStyle onChange = {(e) => receiverAddress.current = e.target.value} placeholder="Receiver address" /><br/>
<FormStyle onChange = {(e) => transferAmount.current = e.target.value} placeholder="Amount" /><br/>
<TransactionButton onClick ={transferFund}>{isLoading ? "loading...": "Transfer Fund"}</TransactionButton>
</div>
)
}
export default TransferFund
5.3 Fund Wallet
This handles funding of account from the Reach Dev faucet. When using the Dev faceut to fund wallet this method will be called reach.fundFromFaucet()
this takes in two argument the account and amount.
Note
The account balance on the dev faceut is limited to fund wallet you can use the Algorand TestNet Dispenser to fund your wallet.
Fig 5-3-1 Fund Wallet
Fig 5-3-2 Fund Wallet UI
import React, {useState} from "react";
import { loadStdlib } from '@reach-sh/stdlib'
import { FormStyle } from "../Form.style";
import { TransactionButton } from "../Button.styles";
const reach = loadStdlib("ALGO")
const FundAccount = ({account, getBalance}) =>{
const [isLoading, setLoading] = useState(false)
const [amount, setAmount] = useState("")
const fundAccount = async () =>{
try{
setLoading(true)
await reach.fundFromFaucet(account.current, reach.parseCurrency(+amount))
await getBalance()
setLoading(false)
setAmount("")
}catch(err){
setLoading(false)
console.log(err)
}
}
return(
<div>
<FormStyle onChange = {(e) => setAmount(e.target.value)} placeholder="Enter amount" />
<TransactionButton onClick ={fundAccount} > {isLoading ? "loading...": "Fund Account"}
</TransactionButton>
</div>
)
}
export default FundAccount
6. Testing the Project
From the terminal run
REACH_CONNECTOR_MODE=ALGO ./reach/reach devnet
this will set the connector mode to Algo.
Next run npm start
on another terminal to run the application
7. MyAlgo Wallet Style
This section handles the UI styling of the MyAlgo Wallet page. Using styled component.
ConnectWalletBtn.js
import React from 'react'
import { loadStdlib } from '@reach-sh/stdlib'
import MyAlgoConnect from '@reach-sh/stdlib/ALGO_MyAlgoConnect';
import ConnectButton from '.';
import { BodyText } from '../MyAlgoWallet.styles';
const reach = loadStdlib("ALGO")
reach.setWalletFallback(reach.walletFallback({
providerEnv: 'TestNet', MyAlgoConnect }));
const ConnectWalletButton = ({connectWallet,accountAddress, accountBal }) => {
return(
<div>
<ConnectButton connectWallet = {connectWallet}/>
<BodyText>Account Address: {accountAddress} </BodyText>
<BodyText>Account Balance: {accountBal}</BodyText>
</div>
)
}
export default ConnectWalletButton
MyAlgoWallet/ConnectButton/index.js
import { Button } from "../../Button.styles";
const ConnectButton = ({connectWallet}) => {
return(
<Button onClick ={connectWallet}>
Connect MyAlgo Wallet
</Button>
)
}
export default ConnectButton
MyAlgoWallet.styles.js
import styled from "styled-components";
export const MyAlgoWalletMain = styled.div`
margin-top : 20px;
`
export const BodyText = styled.h5`
font-family : -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
`
Button.styles.js
import styled from "styled-components";
export const Button = styled.button`
background-color : ${({backgroundColor}) => backgroundColor ? '#E13E00' : '#245EC7' };
color: white;
padding : 16px;
border-radius: 10px;
border-color : transparent;
margin : 20px 0;
font-family : 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif
`
export const TransactionButton = styled.button`
background-color : #F8F9FF;
color: ${({backgroundColor}) => backgroundColor ? '#E13E00' : '#245EC7' };
padding : 10px;
border-radius: 5px;
border-color : ${({backgroundColor}) => backgroundColor ? '#E13E00' : '#245EC7' };
margin : 20px 10px;
font-family : 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif
`
Form.style.js
import styled from "styled-components";
export const FormStyle = styled.input`
margin-bottom : 20px;
width : 200px;
padding : 10px;
border-radius : 5px;
border-color : #245EC7;
`
8. AlgoSigner
The AlgoSigner performs similar function as the MyAlgo Wallet. The major difference is that AlgoSigner has a web extension like Metamask for signing of transactions on the Algorand blockchain.
AlgoSigner injects a JavaScript library into every web page the browser user visits, which allows the site to interact with the extension. The dApp can use the injected library to connect to the user’s Wallet, discover account addresses it holds, query the Network (make calls to AlgoD v2 or the Indexer) and request AlgoSigner to request for the user to sign a transaction initiated by the application. All methods of the injected library return a Promise that needs to be handled by the dApp.
To get started using AlgoSigner. You will need to install the AlgoSigner chrome extension and setup your TestNet account.Also go to the settings section of the extension to configure your network.
Fig 8-1 AlgoSigner Settings
8.1 AlgoSigner Main Page
Note
It is important to include /*global AlgoSigner*/
at the top level of your project to enable you have access to the Algod SDK to avoid running into errors.
/*global AlgoSigner*/
import React, {useRef} from "react";
import ConnectAlgoSigner from "./ConnectAlgoSigner";
import SignPayTransaction from "./SignPayTransaction";
import algoSignerlogo from '../../assets/images/algosigner.jpeg'
import { AlgoSignerMain } from "./AlgoSigner.styles";
import CreateAsset from "./CreateAsset";
import AssetOptin from "./AssetOptin"
const AlgoSigner = () =>{
const userAccount = useRef()
const receipient = useRef()
const amount = useRef()
return(
<AlgoSignerMain>
<img src= {algoSignerlogo} alt ="AlgoSigner Logo" height= "70px"/>
<ConnectAlgoSigner userAccount = {userAccount}/>
<SignPayTransaction userAccount = {userAccount} amount = {amount} receipient = {receipient} />
<CreateAsset userAccount = {userAccount} />
<AssetOptin userAccount = {userAccount} />
</AlgoSignerMain>
)
}
export default AlgoSigner
Fig 8-1-1 AlgoSigner Main UI
Fig 8-1-2 AlgoSigner Main UI
8.2 Connect to AlgoSigner
This handles connection to AlgoSigner web extension. This will fail if AlgoSigner is not installed.
The AlgoSigner.connect()
function is required to connect to the AlgoSigner, and the AlgoSigner.accounts({ledger: 'TestNet'})
function is used to get the user account in on the TestNet.
/*global AlgoSigner*/
import React from "react";
import { Button } from "../Button.styles";
const ConnectAlgoSigner = ({userAccount}) => {
const connectAlgoSigner = async () =>{
let resp = await AlgoSigner.connect()
console.log(resp)
getUserAccount()
}
const getUserAccount = async () =>{
userAccount.current = await AlgoSigner.accounts({
ledger: 'TestNet'
})
// console.log(userAccount.current[0]['address'])
console.log(userAccount.current)
}
return(
<div>
<Button backgroundColor='blue' onClick={connectAlgoSigner}>
Connect Algo Signer
</Button>
</div>
)
}
export default ConnectAlgoSigner
Fig 8-2-1 Connect to AlgoSigner
Fig 8-2-2 Grant Wallet Accesss
8.3 Sign Pay Transaction
This handles signing of payment transactions. To handle payment using the algosdk this function will be called algosdk.makePaymentTxnWithSuggestedParamsFromObject()
this takes in some arguments like from
account owner, to
the receipient, amount
the amount to be transfered note
description of the transfer which is optional and suggestedParams
this is gotten after setting up the client. This is gotten by calling this function client.getTransactionParams().do()
.
After making the payment the transaction will be signed and sent to the network.
/*global AlgoSigner*/
import React,{useState, useRef} from "react";
import { FormStyle } from "../Form.style";
import { TransactionButton } from "../Button.styles";
import { BodyText } from "../MyAlgoWallet/MyAlgoWallet.styles";
import { TOKEN, ALGOD_SERVER, PORT } from "../../constants";
const algosdk = require("algosdk");
const SignPayTransaction = ({userAccount, amount, receipient}) => {
const [isLoading, setLoading] = useState(false)
const MICROALGOS_TO_ALGOS_RATIO = 1e6;
const INVALID_MICROALGOS_ERROR_MSG =
'Microalgos should be positive and less than 2^53 - 1.';
/**
* microalgosToAlgos converts microalgos to algos
* @param microalgos - number
* @returns number
*/
const microalgosToAlgos = (microalgos ) => {
if (microalgos < 0 || !Number.isSafeInteger(microalgos)) {
throw new Error(INVALID_MICROALGOS_ERROR_MSG);
}
return microalgos / MICROALGOS_TO_ALGOS_RATIO;
}
/**
* algosToMicroalgos converts algos to microalgos
* @param algos - number
* @returns number
*/
const algosToMicroalgos = (algos) => {
const microalgos = algos * MICROALGOS_TO_ALGOS_RATIO;
return Math.round(microalgos);
}
const signPayTransaction = async () =>{
// await AlgoSigner.connect();
setLoading(true)
let client = new algosdk.Algodv2(TOKEN, ALGOD_SERVER, PORT)
//Query Algod to get testnet suggested params
let suggestedParams = await client.getTransactionParams().do()
try{
const txn = await new algosdk.makePaymentTxnWithSuggestedParamsFromObject({
from: userAccount.current[0].address,
to: receipient.current,
amount:parseInt(amount.current),
// note: "document.getElementById('note').value",
suggestedParams: {...suggestedParams}
});
// Use the AlgoSigner encoding library to make the transactions base64
let txn_b64 = AlgoSigner.encoding.msgpackToBase64(txn.toByte());
let signedTxs = await AlgoSigner.signTxn([{txn: txn_b64}])
// Get the base64 encoded signed transaction and convert it to binary
let binarySignedTx = AlgoSigner.encoding.base64ToMsgpack(signedTxs[0].blob);
// Send the transaction through the SDK client
let id = await client.sendRawTransaction(binarySignedTx).do();
console.log(id)
setLoading(false)
}catch(err){
console.log(err)
setLoading(false)
}
}
return(
<div>
<div>
<BodyText>Make Payment</BodyText>
<FormStyle onChange = {(e) => amount.current = e.target.value} placeholder="Amount" /><br/>
<FormStyle onChange = {(e) => receipient.current = e.target.value} placeholder="Receiver address" /><br/>
<TransactionButton backgroundColor onClick ={signPayTransaction}>{isLoading ? "loading...": "Sign Transaction"}</TransactionButton>
</div>
</div>
)
}
export default SignPayTransaction
Fig 8-3-1 Payment UI
Fig 8-3-2 Sign Pay Transaction
Once the transaction is signed and sent to the network you will get the transaction id
{txId: "5PHUOS7F6OAFGMFKOZIBURKWTH2CDYK6DGM7L44Q7QX6S7PZYQTA"}
Fig 8-3-2 Transaction Detail From AlgoExplorer
8.4 Create Algorand Standard Asset (ASA)
The below code is used to create an Asset from AlgoSigner. To create an asset this function will be called algosdk.makeAssetCreateTxnWithSuggestedParamsFromObject()
this takes in some arguments the assetName
the name of the asset, unitName
the name of the unit total
the total unit of the asset, decimals
the decimals, note
and suggestedParams
are as explained in 5.3.
After creating the asset the transaction will be signed and sent to the network.
/*global AlgoSigner*/
import React, {useRef, useState} from "react";
import { FormStyle } from "../Form.style";
import { TransactionButton } from "../Button.styles";
import { BodyText } from "../MyAlgoWallet/MyAlgoWallet.styles";
import { TOKEN, ALGOD_SERVER, PORT, RECEIVER } from "../../constants";
const algosdk = require("algosdk");
const CreateAsset = ({userAccount}) => {
const assetName = useRef()
const unitName = useRef()
const totalUnit = useRef()
const note = useRef()
const decimals = useRef()
const [isLoading, setLoading] = useState(false)
const createAsset = async () =>{
// await AlgoSigner.connect();
setLoading(true)
let client = new algosdk.Algodv2(TOKEN, ALGOD_SERVER, PORT)
//Query Algod to get testnet suggested params
let txParamsJS = await client.getTransactionParams().do()
try{
const txn = await new algosdk.makeAssetCreateTxnWithSuggestedParamsFromObject({
from: userAccount.current[0].address,
assetName: assetName.current,
unitName: unitName.current,
total: +totalUnit.current,
decimals: +decimals.current,
note: AlgoSigner.encoding.stringToByteArray(note.current),
suggestedParams: {...txParamsJS}
});
const txn_b64 = await AlgoSigner.encoding.msgpackToBase64(txn.toByte());
let signedTxs = await AlgoSigner.signTxn([{txn: txn_b64}])
console.log(signedTxs)
// Get the base64 encoded signed transaction and convert it to binary
let binarySignedTx = await AlgoSigner.encoding.base64ToMsgpack(signedTxs[0].blob);
// Send the transaction through the SDK client
let id = await client.sendRawTransaction(binarySignedTx).do();
console.log(id)
setLoading(false)
}catch(err){
console.log(err)
setLoading(false)
}
}
return(
<div>
<div>
<BodyText>Create Asset</BodyText>
<FormStyle onChange = {(e) => assetName.current = e.target.value} placeholder="Asset name" /><br/>
<FormStyle onChange = {(e) => unitName.current = e.target.value} placeholder="Unit name" /><br/>
<FormStyle onChange = {(e) => totalUnit.current = e.target.value} placeholder="Total units" /><br/>
<FormStyle onChange = {(e) => decimals.current = e.target.value} placeholder="Decimals" /><br/>
<FormStyle onChange = {(e) => note.current = e.target.value} placeholder="Enter note" /><br/>
<TransactionButton backgroundColor onClick ={createAsset}>{isLoading ? "loading...": "Sign Create Asset"}</TransactionButton>
</div>
</div>
)
}
export default CreateAsset
Fig 8-4-1 Create Asset UI
Fig 8-4-2 Sign Asset
Once the transaction is signed. It will return the transaction id to checkup the transaction details on the algoexplorer.io.
{txId: "BZSBJ2A2RAV22SNLQVR25BECX4GX3CTDIAJKJX73PU7DUHQ3SIZQ"}
8.5 Optin to An Asset
This function enables a user to optin to an assets. Only optin user/address can receive an asset.
To optin to an asset this function will be called algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject()
this takes in some arguments like from
the account creator, to
the receipient, assetIndex
the index number generated when the asset was created, note
, amount
and suggestedParams
are as explained in 5.3.
After Opt in the transaction will be signed and sent to the network.
/*global AlgoSigner*/
import React, { useRef, useState } from "react";
import { FormStyle } from "../Form.style";
import { TransactionButton } from "../Button.styles";
import { BodyText } from "../MyAlgoWallet/MyAlgoWallet.styles";
import { TOKEN, ALGOD_SERVER, PORT } from "../../constants";
const algosdk = require("algosdk");
const CreateAsset = ({userAccount}) => {
const receiver = useRef()
const assetIndex = useRef()
const note = useRef()
const [isLoading, setLoading] = useState(false)
const optInToAnAsset = async () =>{
setLoading(true)
let client = new algosdk.Algodv2(TOKEN, ALGOD_SERVER, PORT)
//Query Algod to get testnet suggested params
let txParamsJS = await client.getTransactionParams().do()
try{
const txn = await new algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
from: userAccount.current[0].address,
to: receiver.current,
assetIndex: +assetIndex.current,
note: AlgoSigner.encoding.stringToByteArray(note.current),
amount: 0,
suggestedParams: {...txParamsJS}
});
// Use the AlgoSigner encoding library to make the transactions base64
const txn_b64 = AlgoSigner.encoding.msgpackToBase64(txn.toByte());
const signedTxs = await AlgoSigner.signTxn([{txn: txn_b64}])
console.log(signedTxs)
// Get the base64 encoded signed transaction and convert it to binary
let binarySignedTx = await AlgoSigner.encoding.base64ToMsgpack(signedTxs[0].blob);
// Send the transaction through the SDK client
let id = await client.sendRawTransaction(binarySignedTx).do();
console.log(id)
setLoading(false)
}catch(err){
console.log(err)
setLoading(false)
}
}
return(
<div>
<div>
<BodyText>Asset Optin</BodyText>
<FormStyle onChange = {(e) => receiver.current = e.target.value} placeholder="Receiver address" /><br/>
<FormStyle onChange = {(e) => assetIndex.current = e.target.value} placeholder="Asset index" /><br/>
<FormStyle onChange = {(e) => note.current = e.target.value} placeholder="Note" /><br/>
<TransactionButton backgroundColor onClick ={optInToAnAsset}>{isLoading ? "loading...": "Sign Asset Optin"}</TransactionButton>
</div>
</div>
)
}
export default CreateAsset
Fig 8-5-1 AlgoSigner Asset Details
Fig 8-5-2 Asset Optin UI
Fig 8-5-3 Sign Optin Transaction
Asset optin transaction id {txId: "4AV3LRS743XBN4SSJG6M2MMSHXLZKLRUKKGYXBSGNW25MCSWESNA"}
9. AlgoSigner UI Styles
This handles the UI Styling of AlgoSigner using styled-component.
AlgoSigner.styles.js
import styled from "styled-components";
export const AlgoSignerMain = styled.div`
margin-top : 20px;
@media(max-width : 767px) {
width : 90%;
margin : 36px auto;
}
`
10. Next Step
- Areas not covered in this tutorial like other capabilities of ASA that can be done with AlgoSigner, including Atomic transfer and creating of multisig accounts. Will be worked on in future tutorial.
- Also a deeper look into Reach to create sample smart contracts using reach both on the backend and frontend.
11. Further Study
- https://docs.reach.sh/tut.html
- https://purestake.github.io/algosigner-dapp-example/index.html
- https://github.com/PureStake/algosigner/blob/develop/docs/dApp-integration.md
- https://developer.algorand.org/docs/get-details/asa/
Warning
This tutorial is intended for learning purposes only. It does not cover error checking and other edge cases. Therefore, it should not be used as a production application