Interacting with Smart Contracts with AlgoSigner and WalletConnect

Do repost and rate:

This is the fourth tutorial introducing smart contracts and blockchain development on Algorand. In this article we will look at the user experience when interacting with smart contracts on the Algorand blockchain, using Algosigner and WalletConnect. 

In this tutorial, you’ll learn how to interact with smart contracts on the Algorand blockchain from a user perspective. Therefore, you’ll learn to use AlgoSigner and WalletConnect to create interfaces users can use to sign transactions quickly without using any code or tools.

In this fourth post, you’ll learn the following skills:

  1. A quick introduction to smart contracts (and how to deploy/interact with them)
  2. Introduction to AlgoSigner and WalletConnect
  3. How to set up AlgoSigner to interact with a smart contract
  4. How to set up WalletConnect to interact with a smart contract
  5. Conclusion
  6. Demo code

Requirements

  • A running Algorand sandbox or Algorand node. More information can be found here
  • At least one funded addresses in the sandbox
  • `goal` ((part of the Algorand sandbox by default))
  • `python3`
  • `Chrome` webbrowser
  • `Algorand Wallet` installed on your smartphone

Background 

Algorand and the ecosystem surrounding it provide many tools and development libraries which make interfacing with Algorand easy for a software developer. However, it is likely that the end user of a given Algorand application will not be a software engineer, but rather a normal individual, possibly with limited technical knowledge. 

The tools and libraries that are easy for a software engineer to use may be confusing and even prohibitive for the average user. For this reason, there are several practical and intuitive Algorand user interfaces (UIs) to interact with the Algorand blockchain and its smart contracts. Two that will be explored in this tutorial are AlgoSigner and WalletConnect.

AlgoSigner is a Chrome browser-extension which implements a minimal Algorand wallet in-browser — like METAMASK for Algorand. AlgoSigner also provides a developer API to be integrated into a websites’s source code. The website displays a simplistic UI and uses the AlgoSigner API to connect to the in-browser wallet and perform Algorand operations such as sending transactions and performing smart contract calls. To the end user, they only have to interface with a sleek web-UI in order to use an Algorand DApp.

WalletConnect is slightly different than AlgoSigner in that it is just a set of developer APIs. These APIs enable a website to integrate WalletConnect into its source code and communicate with the official Algorand smartphone wallet. Now, similarly like with AlgoSigner, a website would provide a UI and then uses the WalletConnect API to perform the various desired Algorand operations. 

When an Algorand dapp uses either AlgoSigner or WalletConnect, the end user’s experience can be as simple as clicking a few buttons on a website and authorizing the transaction. Contrasting that with the user experience using developer tools such as `goal`, which are certainly more versatile and advanced, the barrier to entry would certainly dissuade many non-technical users from using Algorand or Algorand dapps.

Stateful Counter Smart Contract Example

This tutorial will showcase AlgoSigner and WalletConnect by interacting with a basic stateful counter dapp. The dapp is extremely simple. It has a global counter which, upon every invocation of the smart contract, gets incremented by one.

Note: This example is provided for informational purposes only. Therefore, for simplicity purposes and cleanliness, it contains only essential code blocks and lacks many of the necessary security checks listed here.

Make sure to create a new file in the assets directory in your sandbox (`/sandbox/assets`) called `stateful_counter.py` and add the below code.

```pyfrom pyteal import *def counter_program():    """    This smart contract implements a stateful counter    """    var_counter = Bytes("counter")    counter = App.globalGet(var_counter)    init_counter = Seq([        App.globalPut(var_counter, Int(0)),        Return(Int(1))    ])    add_one = Seq([        App.globalPut(var_counter, counter + Int(1)),        Return(Int(1))    ])    program = Cond(        [Txn.application_id() == Int(0), init_counter],        [Txn.on_completion() == OnComplete.NoOp, add_one],        [Int(1), Return(Int(1))]    )    return programif __name__ == "__main__":    print(compileTeal(counter_program(), Mode.Application, version=5))```

Since this program requires persistent variables, it is compiled with the mode set to `Mode.Application` indicating that it is a smart contract. In a previous tutorial explaining PyTEAL, smart signatures were incorporated in the code examples. These are slightly different and should not be confused with smart contracts like the one above. Most crucially, smart contracts can maintain a persistent state, global and local variables that remember their values between application calls. 

This tutorial will explain the main components of the above smart contract in order to better understand how it works. More detailed information regarding the life cycle of an Algorand smart contract may be found here. The global variable is called `”counter”` and can be easily accessed with `App.globalGet` and assigned with `App.globalPut`. The Python variable named `counter` conveniently maps to the getter function. 

The entire smart contract is encapsulated in the `Cond` expression assigned to `program`. When a smart contract is initially created, it is invoked with a `Txn.application_id()` of 0. The first condition in the `Cond` catches this case and redirects the program to `init_counter`. This is a simple code block which first sets the counter to its initial value of 0 and then returns 1, indicating success. In later invocations, the smart contract will have its ID already set to some non-zero value, so the first condition will never be invoked again.

In order to call this smart contract, a user would submit a so-called `NoOp` transaction. One can pass arguments in this `NoOp` transaction, but for this particular use case, they are not necessary. The second condition in the `Cond` catches this case and runs the `add_one` code block. As its name implies, the `add_one` code block increments the counter’s value by 1 and exits indicating success.

The third condition of the `Cond` is a catch-all case where if neither of the two preceding cases were triggered, then the smart contract just exits successfully. Warning: Doing this is very dangerous and introduces many security vulnerabilities. There are other application calls possible within the life cycle of a smart contract and this condition will gladly execute and accept all of them.

**Note:** The below `clear_program.py` is a necessary helper application required by all Algorand smart contracts in order to be deployed. It should contain any clean up code to execute whenever a user wants to opt-out from a smart contract. In this example, there is nothing to clean up, so the clear program simply returns successfully and no more. More information on clear programs and the overall smart contract lifecycle can be found here.

Make a new file called `clear_program.py` in your assets directory and add the below code.

```pyfrom pyteal import *def clear_program():    """    Nothing to clear. Simply exit successfully.    """    return Return(Int(1))if __name__ == '__main__':    print(compileTeal(clear_program(), Mode.Application, version=5))```

Even though this smart contract is very simple to understand, let’s understand what is its expected behavior better by using `goal` to deploy and call it.

Goal Demo: Compile the Smart Contract

Let’s first compile the contracts from PyTeal to TEAL (from the root of your sandbox)

```shpython3 ./assets/stateful_counter.py > ./artifacts/stateful_counter.tealpython3 ./assets/clear_program.py > ./artifacts/clear_program.teal```

Next, we need to deploy it to the sandbox.

Goal Demo: Deploy the Smart Contract

To access the TEAL contracts in the node, we have to copy them into our sandbox.

```sh./sandbox copyTo ./artifacts/stateful_counter.teal./sandbox copyTo ./artifacts/clear_program.teal```

In order to deploy a smart contract, the creator and data requirements of the smart contract must be specified to `goal`. None of these parameters may be changed once the smart contract has been deployed. This is important since nothing can be done if more global or local data is needed in an updated release of the smart contract code. The current smart contract only requires one global integer value, the counter. The creator is a funded address imported into `goal` with the address “XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE”. You can use any account from the previous tutorials that has sufficient funds. To list all accounts for your sandbox, use `./sandbox goal account list`.

```sh./sandbox goal app create --creator XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE --global-byteslices 0 --global-ints 1 --local-byteslices 0 --local-ints 0 --approval-prog stateful_counter.teal --clear-prog clear_program.teal```

The output of the deployment includes the application ID (also known as application index) of this smart contract. This is important to remember since it is a required parameter of an application call in order to invoke the appropriate smart contract.

An example output from deploying this smart contract is:

```shAttempting to create app (approval size 49, hash P3JCINPYNWCX54B6OCN4HWXTLJ2ZUPORDFMBPHPJECVIZNHRS4VQ; clear size 4, hash BJATCHES5YJZJ7JITYMVLSSIQAVAWBQRVGPQUDT5AZ2QSLDSXWWA)Issued transaction from account XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE, txid OMURGA4H5E7EDQPRWQDUEGX53CDVQEDNUOEZVOIOBYJH6H54QSKQ (fee 1000)Transaction OMURGA4H5E7EDQPRWQDUEGX53CDVQEDNUOEZVOIOBYJH6H54QSKQ still pending as of round 17876540Transaction OMURGA4H5E7EDQPRWQDUEGX53CDVQEDNUOEZVOIOBYJH6H54QSKQ still pending as of round 17876540Transaction OMURGA4H5E7EDQPRWQDUEGX53CDVQEDNUOEZVOIOBYJH6H54QSKQ committed in round 17876540Created app with app index 43987809```

The application index used during this tutorial for the “Add One” smart contract is `43987809`.

Goal Demo: Call the Smart Contract

Any funded user can invoke this smart contract to increment the counter. In this example, since the creator is already funded, that account will be the one which will invoke the smart contract.

```sh./sandbox goal app call --from XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE --app-id 43987809```

An example output showing this application call be accepted into the Algorand network is:

```Issued transaction from account XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE, txid XUH4EQYT6YQVBBOH5JZ2RTZ74BV7JOUUMGTEP653BL2YAJOAHT6A (fee 1000)Transaction XUH4EQYT6YQVBBOH5JZ2RTZ74BV7JOUUMGTEP653BL2YAJOAHT6A still pending as of round 17876594Transaction XUH4EQYT6YQVBBOH5JZ2RTZ74BV7JOUUMGTEP653BL2YAJOAHT6A still pending as of round 17876595Transaction XUH4EQYT6YQVBBOH5JZ2RTZ74BV7JOUUMGTEP653BL2YAJOAHT6A committed in round 17876596```

Goal Demo: Read the Global Counter Value

To confirm that the “Add One” smart contract is exhibiting its correct behavior, the global state can be queried from the Algorand network.

```sh./sandbox goal app read --global --app-id 43987809```

An example output showing the counter value is:


```json{  "counter": {    "tt": 2,    "ui": 1  }}```

The value is in the “ui” field which stands for unsigned integer. You may call the smart contract a few more times and re-read the global counter state to see whether it has been incremented correctly.

AlgoSigner

To reiterate AlgoSigner and its purpose, it is a browser-based Algorand wallet which also provides a developer API to websites. Websites use the API to interface with the in-browser wallet in order to sign transactions and perform any requested dapp operations. To the end user, they would be simply clicking buttons on a website’s UI and authorize any transaction in the extension itself.

This section will explain how to use AlgoSigner to integrate the above smart contract into a website DApp. It will cover how the website uses the AlgoSigner API to invoke the smart contract and will show screenshots of what the end user sees in the process. This tutorial will utilize the TestNet for all of the smart contract operations. If you are following this tutorial, be sure to also be utilizing the TestNet, so that you do not accidentally spend real Algos.

The full source code of the AlgoSigner demo app which you can run on your won can be found on GitHub.

AlgoSigner User Setup

In order to use an AlgoSigner enabled website dapp, the end user must set up AlgoSigner on their Chrome web-browser. This process is simple and intuitive. The Chrome browser add-on may be downloaded from here

Once installed, you can set up a password for the AlgoSigner Browser Wallet.

![Algosigner set up password](./algosigner_setup_password.png)

Since this tutorial uses the TestNet, be sure to change the wallet to utilize the TestNet.

![setup testnet algosigner](./algosigner_setup_testnet.png)

Then, you may add an account by clicking the orange button displaying “Add account”. Here, you will be presented with several options, from creating a new account to importing an existing one. If you already have an Algorand testnet account, such as via the sandbox setup, all you need to do is enter the 25 word wallet passphrase into AlgoSigner.

To get the wallet passphrase via `goal`, in this example for an account with the address “XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE”, run:

```sh./sandbox goal account export -a XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE```

The output should be:

```shExported key for account XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE: "<25 WORD PASSPHRASE HERE>".```

These words can be copied into AlgoSigner’s respective text box here:

![AlgoSigner Setup Import Account](./algosigner_setup_import_account.png)

AlgoSigner Website API

Connecting to the API

The first step a website which uses AlgoSigner needs to do is connect to the AlgoSigner API.

```jsAlgoSigner.connect().then((d) => {  ...}).catch((e) => {  console.error(e);});```

The user will be presented with a pop-up to authorize the connection to AlgoSigner.

![Connect algosigner](./algosigner_connect.png)

Once connected successfully, the website may use the other AlgoSigner API calls to interact with AlgoSigner and issue transactions to the Algorand network.

Setting up the Algod Client

The next step is to connect to a remote Algorand node. Since the AlgoSigner is a lightweight wallet, any requests regarding the current status of the Algorand network, such as what the current round is or whether a transaction has been confirmed, must be queried through Algod and go through a remote Algorand server. If you are using the Algorand sandbox with a connection to the TestNet network, then Algod can connect with this node.

This tutorial uses the sandbox to connect to the TestNet. The sandbox node exposes an address and token for the Algod to connect to. Normally, the default address value is “http://localhost” at port 4001 and the default token value is “aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa”.

To double-check, you can see the actual values of the node from within the sandbox:

```sh# Enter the sanbox algod environment./sandbox enter algod# List the exposed address and portcat ~/testnetwork/Node/algod.net# Outputs: [::]:4001 (equivalent to http://localhost:4001)# List the tokencat ~/testnetwork/Node/algod.token# Outputs: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa```

The code to connect to Algod is as follows:

```jsconst algodServer = 'http://localhost';const token = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';const port = '4001';algodClient = new algosdk.Algodv2(token, algodServer, port);algodClient.healthCheck().do().then(d => {   ... }).catch(e => {   console.error(e); });```

Alternatively, there are services that provide access to an Algorand node, oftentimes for free. To use them, you would need to follow their instructions and input the appropriate `algodServer`, `token` and `port` values.

Get TestNet Accounts

This step is not strictly required for the simple smart contract DApp. Nevertheless, it is helpful to retrieve the current accounts maintained by the installed AlgoSigner wallet to pre-populate the later parts of the DApp UI.

```jsAlgoSigner.accounts({  ledger: 'TestNet'}).then((accounts) => {  console.log(accounts);}).catch((e) => {  console.error(e);});```

At the time of writing this tutorial, there were three accounts already imported into the wallet. The console output shows the three distinct addresses.

```sh[  {    "address": "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE"  },  {    "address": "TJMHAAEFTWVZNA2O52AA57BWVCJOBSEIU2OEWNWADVM5F5Y2DRJDWMDGRQ"  },  {    "address": "KJKRDF4RHNRBYHZXMPTCBNFU64B6KVF3RD3446YAAFTXF6ICTQ3WT5F7UE"  }]```

Get the Suggested Transaction Parameters

Every Algorand transaction has a few parameters that for most use-cases, should just be set to their suggested values. This smart contract does not require any specific parameters and so will use the suggested ones. One part of the suggested parameters is the transaction validity window — from which round until which round is this transaction valid to be accepted by the Algorand network. This data requires knowledge of the current Algorand network’s state and thus must be queried with the Algod client.

```jsalgodClient.getTransactionParams().do().then((d) => {  suggestedTxParams = d;})      .catch((e) => {  console.error(e);});```

This is an example of suggested transaction parameters output from the above code block when you execute the JavaScript file.

```json{  "flatFee": false,  "fee": 0,  "firstRound": 17877161,  "lastRound": 17878161,  "genesisID": "testnet-v1.0",  "genesisHash": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cookie="}```

There you can see the `firstRound` and `lastRound` parameters which indicate the rounds in between which this transaction must be submitted in order to be committed into the Algorand network. If the transaction is sent in a current round which is outside that window, it will be rejected automatically.

Sign a Transaction Invoking the Smart Contract

The next step is to create a transaction object and have it signed by AlgoSigner. In order for AlgoSigner to sign the transaction, it displays to the user a popup window asking for explicitly authorization before any signing proceeds.

The transaction object is created with the Algorand Javascript SDK, not AlgoSigner itself. In this case, since the smart contract accepted application calls with no arguments, the transaction must only include which account is issuing it (the `from` field) and which smart contract to invoke (the `app-index` field).

```jsconst txn = algosdk.makeApplicationNoOpTxnFromObject({  from: document.getElementById('from').value,  appIndex: +document.getElementById('app-index').value,  suggestedParams: {...suggestedTxParams}});// Use the AlgoSigner encoding library to make the transactions base64let txn_b64 = AlgoSigner.encoding.msgpackToBase64(txn.toByte());```

In order to input these fields, the user could see a UI as such:

![sign input](./algosigner_sign_input.png)In this case, the `from` is "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE" and the `app-index` is "43987809".AlgoSigner can understand the base64 encoded transaction object about to be signed.```jsAlgoSigner.signTxn([{txn: txn_b64}]).then((d) => {  signedTxs = d;}).catch((e) => {  console.error(e);});```

Before the signing proceeds, the user is presented a pop-up window where they must authorize the operation.

![authorize](./algosigner_sign_authorize.png)

Once signed, the transaction is ready to be sent into the network. A signed transaction is not human intelligible, but an example signed transaction is as follows:

```sh[  {    "txID": "FQ2WKTQ5ZOXY4XV3B6VKST2JSFQIGP3WTFCJNYPB4S7FU2LO37HA",    "blob": "gqNzaWfEQEhmYVoAVy4+KJhFZo+JFSpjdnXaKERXXmrWp26qQerxWaY7dItTAji2BiwBTQlZkY5dai3Wqp1HEF+6U2pJ2QWjdHhuiKRhcGlkzgKfM2GjZmVlzQPoomZ2zgEQyKmjZ2VurHRlc3RuZXQtdjEuMKJnaMQgSGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiKibHbOARDMkaNzbmTEILkZAGApbf98yjKXhEr57DD1j4Vo56pYZ0yi4sIaM4UppHR5cGWkYXBwbA=="  }]```

Send the Signed Transaction

The next logical step is to send the signed transaction into the Algorand network. The AlgoSigner provides a helper function for this.

```jsAlgoSigner.send({  ledger: 'TestNet',  tx: signedTxs[0].blob }).then((d) => {  tx = d;}).catch((e) => {  console.error(e);});```The result is the transaction ID, simply confirming that the transaction was sent into the network. ```json{  "txId": "FQ2WKTQ5ZOXY4XV3B6VKST2JSFQIGP3WTFCJNYPB4S7FU2LO37HA"}```

Note: a transaction being sent into the network does not mean that it will be ultimately accepted. That must be checked by querying the status of the pending transaction.

Check the Pending Transaction Status

It may be useful as feedback to the end user to inquire about the status of the sent transaction from the prior step. This utilizes the Algod client since this is an operation which relies on the Algorand network’s state.

```jsalgodClient.pendingTransactionInformation(tx.txId).do().then((status) => {  console.log(status);}).catch((e) => {  console.error(e);});

Before the transaction has been confirmed, only the transaction metadata will be included in the status output.

```json{  "pool-error": "",  "txn": {    "sig": "NzIsMTAyLDk3LDkwLDAsODcsNDYsNjIsNDAsMTUyLDY5LDEwMiwxNDMsMTM3LDIxLDQyLDk5LDExOCwxMTcsMjE4LDQwLDY4LDg3LDk0LDEwNiwyMTQsMTY3LDExMCwxNzAsNjUsMjM0LDI0MSw4OSwxNjYsNTksMTE2LDEzOSw4MywyLDU2LDE4Miw2LDQ0LDEsNzcsOSw4OSwxNDUsMTQyLDkzLDEwNiw0NSwyMTQsMTcwLDE1Nyw3MSwxNiw5NSwxODYsODMsMTA2LDczLDIxNyw1",    "txn": {      "apid": 43987809,      "fee": 1000,      "fv": 17877161,      "gen": "testnet-v1.0",      "gh": "NzIsOTksMTgxLDI0LDE2NCwxNzksMjAwLDc4LDIwMCwxNiwyNDIsNDUsNzksMTYsMTI5LDIwMywxNSwxMTMsMjQwLDg5LDE2NywxNzIsMzIsMjIyLDE5OCw0NywxMjcsMTEyLDIyOSw5LDU4LDM0",      "lv": 17878161,      "snd": "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE",      "type": "appl"    }  }}```

Once the transaction has been confirmed, the status output will include the `confirmed-round`. As long as this value is non-zero, that means that the transaction has been accepted into the Algorand network at that given round in the Algorand blockchain.

```json{  "confirmed-round": 17877359,  "global-state-delta": [    {      "key": "Y291bnRlcg==",      "value": {        "action": 2,        "uint": 12      }    }  ],  "pool-error": "",  "txn": {    "sig": "NzIsMTAyLDk3LDkwLDAsODcsNDYsNjIsNDAsMTUyLDY5LDEwMiwxNDMsMTM3LDIxLDQyLDk5LDExOCwxMTcsMjE4LDQwLDY4LDg3LDk0LDEwNiwyMTQsMTY3LDExMCwxNzAsNjUsMjM0LDI0MSw4OSwxNjYsNTksMTE2LDEzOSw4MywyLDU2LDE4Miw2LDQ0LDEsNzcsOSw4OSwxNDUsMTQyLDkzLDEwNiw0NSwyMTQsMTcwLDE1Nyw3MSwxNiw5NSwxODYsODMsMTA2LDczLDIxNyw1",    "txn": {      "apid": 43987809,      "fee": 1000,      "fv": 17877161,      "gen": "testnet-v1.0",      "gh": "NzIsOTksMTgxLDI0LDE2NCwxNzksMjAwLDc4LDIwMCwxNiwyNDIsNDUsNzksMTYsMTI5LDIwMywxNSwxMTMsMjQwLDg5LDE2NywxNzIsMzIsMjIyLDE5OCw0NywxMjcsMTEyLDIyOSw5LDU4LDM0",      "lv": 17878161,      "snd": "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE",      "type": "appl"    }  }}```

Read the Smart Contract State

The purpose of the “Add One” smart contract used in this example is to store a global counter variable and increment it every time the smart contract is invoked. This step uses the Algod client to read the global state of the counter variable directly from the Algorand network. This way, one can be sure that sending the transaction application call from above is actually having some effect.

```jsalgodClient.getApplicationByID(appIndex).do().then((d) => {  const globalState = d['params']['global-state'];}).catch((e) => {  console.error(e);})```An example output is:```sh[  {    "key": "Y291bnRlcg==",    "value": {      "bytes": "",      "type": 2,      "uint": 12    }  }]```

This shows that the counter variable’s value is 12. Sending a new application call transaction again by following the above steps will show that the counter has been incremented. This is inline with the expected behavior of the smart contract.

```sh[  {    "key": "Y291bnRlcg==",    "value": {      "bytes": "",      "type": 2,      "uint": 13    }  }]```

WalletConnect

WalletConnect serves a similar end goal as AlgoSigner of providing an easy-to-use interface to interacting with Algorand DApps. WalletConnect is an API to enable website DApps to connect to and interact with the official Algorand smartphone wallet. Similarly like with AlgoSigner, a website would provide a UI and use the WalletConnect API to perform the various Algorand operations. These operations, such as signing a transaction, are all actually executed on the Algorand smartphone application. To the end user, they would be prompted on their smartphone to authorize the various requested operations.

This section will explain how to use WalletConnect to integrate the “Add One” smart contract example from above into a sample website DApp. It will also show screenshots of what the end user would see and do in order to interact with the DApp.

The full source code of the WalletConnect demo app which you can run on your won can be found on GitHub.

WalletConnect User Setup

In order to use a WalletConnect enabled website, the end user must have an Algorand wallet setup on their smartphone. This process is simple and intuitive. The wallet application may be downloaded from both the Google and Apple app stores for free.

This tutorial uses accounts on the TestNet. If you are following along, it is recommended to also use the TestNet since you will not be using real Algos when experimenting and playing around. To set up a TestNet account on the Algorand smartphone wallet, you will need to go to the “Developer Settings” -> “Node Settings” and select the TestNet network.

![setup testnet waleltconnect](./walletconnect_setup_testnet.png)

Once selected, you can create a TestNet account and populate it with a few TestNet Algos for free. TestNet Algos may be acquired from the TestNet dispenser here.

![algod dispenser](./walletconnect_algodispenser.png)

WalletConnect Website API

Many of the steps in integrating the “Add One” smart contract with WalletConnect parallel those of AlgoSigner. Therefore, some of the steps here will simply reference the AlgoSigner’s respective steps in order to avoid unnecessary repetition.

Initializing the API

The first step is to initialize the WalletConnect API. This setup provides WalletConnect with the appropriate parameters in order to communicate with the Algorand smartphone wallet.

```js// Create a `walletConnector`walletConnector = new WalletConnect({  bridge: "https://bridge.walletconnect.org",  qrcodeModal: WalletConnectQRCodeModal,});// Check if this is a new connectionif (!walletConnector.connected) {  // Create new session  walletConnector.createSession();}```

The above code will generate a QR code and display it to the user. For the user to connect the Algorand smartphone wallet to WalletConnect, they simply must scan this QR code from within the app.

![connect QR code](walletconnect_QR.png)

Once connected successfully, the website DApp may use WalletConnect to connect to the user’s smartphone wallet in order to perform signing and other privileged operations.

Setting up the Algod Client

This section is identical to the respective section for AlgoSigner.

For reference, the code to connect to Algod is as follows:

```jsconst algodServer = 'http://localhost';const token = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';const port = '4001';algodClient = new algosdk.Algodv2(token, algodServer, port);algodClient.healthCheck().do().then(d => {   ... }).catch(e => {   console.error(e); });```

Get TestNet Accounts

This section is similar to the respective section for AlgoSigner. Retrieving the TestNet accounts is not strictly necessary for this simple smart contract DApp. Nevertheless, it is helpful to have in order to pre-populate the later parts of the DApp UI.

Once the WalletConnect API was initialized and connected to the Algorand smartphone wallet, the returned object, contains the connected TestNet accounts from the smartphone wallet. In the above step, the WalletConnect object is saved to a variable named `walletConnector`. The addresses may be extracted as follows:

```jsif (walletConnector.connected) {  const { accounts } = walletConnector;  console.log(accounts);}```

At the time of writing this tutorial, there was one account in the Algorand smartphone wallet. Therefore, the console output shows this address.

```sh[  "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE"]```

Get the Suggested Transaction Parameters

This section is identical to the respective section for AlgoSigner.

For reference, the code to get the suggested transaction parameters is as follows:

```jsalgodClient.getTransactionParams().do().then((d) => {  suggestedTxParams = d;})      .catch((e) => {  console.error(e);});```A sample output of suggested transaction parameters is:```json{  "flatFee": false,  "fee": 0,  "firstRound": 17877161,  "lastRound": 17878161,  "genesisID": "testnet-v1.0",  "genesisHash": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cookie="}```

Sign a Transaction Invoking the Smart Contract

The first step in signing a transaction is to create the transaction object. Part of the transaction object includes a message that is displayed to the user on their smartphone wallet. Ideally, this message would be a description of the transaction to be signed.

```jsconst txn = algosdk.makeApplicationNoOpTxnFromObject({  from: document.getElementById('from').value,  appIndex: appIndex,  suggestedParams: {...suggestedTxParams}});        txns_b64 = [  {    txn: arrayBufferToBase64(algosdk.encodeUnsignedTransaction(txn)),    message: 'Invoke smart contract call to add one',  },];```

This transaction object is then encapsulated as a JSON RPC request with the identifying tag “algo_signTxn”. This request is simply sent using the WalletConnect and is interpreted by the smartphone wallet.

```jsconst requestParams = [txns_b64];const request = JsonRpcUtils.formatJsonRpcRequest("algo_signTxn", requestParams);signedTxns = await walletConnector.sendCustomRequest(request);```

The Algorand wallet sees the tag and initiates the transaction signing processes. The first step of this processes, before the wallet performs any signing, is to seek authorization from the user.

![sign authorize](./walletconnect_sign_authorize.png)

A signed transaction is not human intelligible, but an example signed transaction is as follows:

```sh[  "MTMwLDE2MywxMTUsMTA1LDEwMywxOTYsNjQsNDgsMTQ4LDQ5LDM1LDEyOSwxMjYsNDUsMTkyLDIzNiwyMDUsMjAsNTEsMTQsMjE5LDEyLDEyLDUsMTMzLDE4NSwxNjAsMjQ2LDEzNywyNDgsOTAsMjM4LDEyNywxNCwxOTUsMjU1LDQ1LDEzMyw2NSwyMjgsOTksMTk1LDE1LDM2LDg2LDUwLDAsMTg5LDE5NiwxNjgsMTUxLDIyNSwxMjUsNTMsODAsMTk3LDk4LDQzLDM5LDMwLDE0MCwyMDAsMjQsMzQsMTMsNzAsNzEsOTAsMTc2LDYwLDgsMTYzLDExNiwxMjAsMTEwLDEzNiwxNjQsOTcsMTEyLDEwNSwxMDAsMjA2LDIsMTU5LDUxLDk3LDE2MywxMDIsMTAxLDEwMSwyMDUsMywyMzIsMTYyLDEwMiwxMTgsMjA2LDEsMTcsMTgsMjEyLDE2MywxMDMsMTAxLDExMCwxNzIsMTE2LDEwMSwxMTUsMTE2LDExMCwxMDEsMTE2LDQ1LDExOCw0OSw0Niw0OCwxNjIsMTAzLDEwNCwxOTYsMzIsNzIsOTksMTgxLDI0LDE2NCwxNzksMjAwLDc4LDIwMCwxNiwyNDIsNDUsNzksMTYsMTI5LDIwMywxNSwxMTMsMjQwLDg5LDE2NywxNzIsMzIsMjIyLDE5OCw0NywxMjcsMTEyLDIyOSw5LDU4LDM0LDE2MiwxMDgsMTE4LDIwNiwxLDE3LDIyLDE4OCwxNjMsMTE1LDExMCwxMDAsMTk2LDMyLDE4NSwyNSwwLDk2LDQxLDEwOSwyNTUsMTI0LDIwMiw1MCwxNTEsMTMyLDc0LDI0OSwyMzYsNDgsMjQ1LDE0MywxMzMsMTA0LDIzMSwxNzAsODgsMTAzLDc2LDE2MiwyMjYsMTk0LDI2LDUxLDEzMyw0MSwxNjQsMTE2LDEyMSwxMTIsMTAxLDE2NCw5NywxMTIsMTEyLDEwOA=="]```

Send the Signed Transaction

The returned signed transaction can be interpreted and sent into the Algorand network directly with the Algod client.

```jsalgodClient.sendRawTransaction(new Uint8Array(signedTxns[0])).do().then((d) => {  tx = d;}).catch((e) => {  console.error(e);});```

The result is the transaction ID, simply confirming that the transaction was sent into the network.

```{  "txId": "L4SRYCZ47WD6IPG4KHII6AZE3YUOIZVTPLVR3UCFMA7CA37M4JZQ"}```

Note: a transaction being sent into the network does not mean that it will be ultimately accepted. That must be checked by querying the status of the pending transaction.

Check the Pending Transaction Status

This section is identical to the respective section for AlgoSigner.

For reference, the code to check the pending transaction status is as follows:

```jsalgodClient.pendingTransactionInformation(tx.txId).do().then((status) => {  console.log(status);}).catch((e) => {  console.error(e);});```

A sample output of a pending transaction yet to be confirmed is:

```json{  "pool-error": "",  "txn": {    "sig": "NzIsMTAyLDk3LDkwLDAsODcsNDYsNjIsNDAsMTUyLDY5LDEwMiwxNDMsMTM3LDIxLDQyLDk5LDExOCwxMTcsMjE4LDQwLDY4LDg3LDk0LDEwNiwyMTQsMTY3LDExMCwxNzAsNjUsMjM0LDI0MSw4OSwxNjYsNTksMTE2LDEzOSw4MywyLDU2LDE4Miw2LDQ0LDEsNzcsOSw4OSwxNDUsMTQyLDkzLDEwNiw0NSwyMTQsMTcwLDE1Nyw3MSwxNiw5NSwxODYsODMsMTA2LDczLDIxNyw1",    "txn": {      "apid": 43987809,      "fee": 1000,      "fv": 17877161,      "gen": "testnet-v1.0",      "gh": "NzIsOTksMTgxLDI0LDE2NCwxNzksMjAwLDc4LDIwMCwxNiwyNDIsNDUsNzksMTYsMTI5LDIwMywxNSwxMTMsMjQwLDg5LDE2NywxNzIsMzIsMjIyLDE5OCw0NywxMjcsMTEyLDIyOSw5LDU4LDM0",      "lv": 17878161,      "snd": "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE",      "type": "appl"    }  }}```

A sample output of a confirmed transaction is:

```json{  "confirmed-round": 17877359,  "global-state-delta": [    {      "key": "Y291bnRlcg==",      "value": {        "action": 2,        "uint": 12      }    }  ],  "pool-error": "",  "txn": {    "sig": "NzIsMTAyLDk3LDkwLDAsODcsNDYsNjIsNDAsMTUyLDY5LDEwMiwxNDMsMTM3LDIxLDQyLDk5LDExOCwxMTcsMjE4LDQwLDY4LDg3LDk0LDEwNiwyMTQsMTY3LDExMCwxNzAsNjUsMjM0LDI0MSw4OSwxNjYsNTksMTE2LDEzOSw4MywyLDU2LDE4Miw2LDQ0LDEsNzcsOSw4OSwxNDUsMTQyLDkzLDEwNiw0NSwyMTQsMTcwLDE1Nyw3MSwxNiw5NSwxODYsODMsMTA2LDczLDIxNyw1",    "txn": {      "apid": 43987809,      "fee": 1000,      "fv": 17877161,      "gen": "testnet-v1.0",      "gh": "NzIsOTksMTgxLDI0LDE2NCwxNzksMjAwLDc4LDIwMCwxNiwyNDIsNDUsNzksMTYsMTI5LDIwMywxNSwxMTMsMjQwLDg5LDE2NywxNzIsMzIsMjIyLDE5OCw0NywxMjcsMTEyLDIyOSw5LDU4LDM0",      "lv": 17878161,      "snd": "XEMQAYBJNX7XZSRSS6CEV6PMGD2Y7BLI46VFQZ2MULRMEGRTQUUS6ZXRFE",      "type": "appl"    }  }}```

Read the Smart Contract State

This section is identical to the respective section for AlgoSigner.

For reference, the code to read the smart contract’s counter variable is:

```jsalgodClient.getApplicationByID(appIndex).do().then((d) => {  const globalState = d['params']['global-state'];}).catch((e) => {  console.error(e);})```

A sample output is:

```json[  {    "key": "Y291bnRlcg==",    "value": {      "bytes": "",      "type": 2,      "uint": 12    }  }]```

Conclusion

AlgoSigner and WalletConnect are both tools for a website dapp to easily integrate user interaction with a deployed Algorand smart contract. In addition to a developer API to be used on the website, AlgoSigner also provides an Algorand wallet in the form of a browser add-on. These tools eliminate any complexity for non-technical users to use an Algorand application. Lowering the barrier of entry is critical for an Algorand application to achieve mass adoption. In order to garner these benefits, dapp developers need to simply create a website with a user-friendly UI and, under the hood, follow the simple steps and code snippets listed in this tutorial. Integrating both AlgoSigner and WalletConnect into a website dapp is intuitive for the developer and a crucial step for the end user’s overall positive experience.

Credits: Created by Damian Barabonkov, [email protected], GitHub: @DamianB-BitFlipper

Complete Code of Demo Application

This tutorial was developed in parallel with a demo application showcasing both AlgoSigner and WalletConnect. This demo application provides two simple UIs, one which uses AlgoSigner to interact with the “Add One” smart contract and the other using WalletConnect. The full repository is publicly accessible on Github with instructions on how to serve and run the application on your own.

For quick reference, the demo application code is copy-pasted in this tutorial as well. Note: These demo code samples may not be up-to-date with any changes made after this tutorial is published.

AlgoSigner Demo Code

```html      AlgoSigner Example DApp  [email protected]/css/bulma.min.css">    [email protected]/build/styles/tomorrow.min.css">          

Connect to AlgoSigner

response
AlgoSigner.connect().then((d) => {  ...}).catch((e) => {  console.error(e);});

Setup a client for algosdk

response
const algodServer = 'http://localhost';const token = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';const port = '4001';algodClient = new algosdk.Algodv2(token, algodServer, port);algodClient.healthCheck().do().then(d => {   ... }).catch(e => {   console.error(e); });

Get TestNet Accounts See code on GitHub

Gets the TestNet accounts in this wallet

response
AlgoSigner.accounts({  ledger: 'TestNet'}).then((d) => {  accounts = d;  ...}).catch((e) => {  console.error(e);});

Get Params See code on GitHub

Query Algod to get TestNet suggested TX Params

response
algodClient.getTransactionParams().do().then((d) => {  suggestedTxParams = d;  ...}).catch((e) => {  console.error(e);});

Sign Application Call Transaction See code on GitHub

Ask the user to sign a smart contract application call transaction using AlgoSigner's Sign method

response
const txn = algosdk.makeApplicationNoOpTxnFromObject({        from: document.getElementById('from').value,        appIndex: +document.getElementById('app-index').value,        suggestedParams: {...suggestedTxParams}      });// Use the AlgoSigner encoding library to make the transactions base64let txn_b64 = AlgoSigner.encoding.msgpackToBase64(txn.toByte());AlgoSigner.signTxn([{txn: txn_b64}]).then((d) => {  signedTxs = d;  ...}).catch((e) => {  console.error(e);});

Send Signed Transaction See code on GitHub

Send the previously signed transaction using Algod

response
AlgoSigner.send({  ledger: 'TestNet',  tx: signedTxs[0].blob}).then((d) => {  tx = d;  ...}).catch((e) => {  console.error(e);});

Check Pending Transaction See code on GitHub

Query the pending transaction endpoint to check the sent transaction status

response
algodClient.pendingTransactionInformation(tx.txId).do().then((d) => {  txStatus = d;  ...}).catch((e) => {  console.error(e);});

Read State See code on GitHub

Read the global variable state of the smart contract

response
algodClient.getApplicationByID(appIndex).do().then((d) => {  globalState = d['params']['global-state'];  ...}).catch((e) => {  console.error(e);});
Demo app adapted from
By: Damian Barabonkov, damianb[at]mit[dot]edu, @DamianB-BitFlipper
```

WalletConnect Demo Code

```html      WalletConnect Example DApp  [email protected]/css/bulma.min.css">    [email protected]/build/styles/tomorrow.min.css">          

Connect See code on GitHub

Connect to the Algorand smartphone wallet using WalletConnect

response
// Create a walletConnectorwalletConnector = new WalletConnect.default({  bridge: "https://bridge.walletconnect.org", // Required  qrcodeModal: WalletConnectQRCodeModal.default,});// Check if this is a new connectionif (!walletConnector.connected) {  // Create new session  walletConnector.createSession();  ...}

SDK Setup See code on GitHub

Setup client for algosdk

response
const algodServer = 'http://localhost';const token = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';const port = '4001';algodClient = new algosdk.Algodv2(token, algodServer, port);algodClient.healthCheck().do().then(d => {   ... }).catch(e => {   console.error(e); });

Get TestNet Accounts See code on GitHub

Gets the TestNet accounts in this wallet

response
if (walletConnector.connected) {  const { accounts } = walletConnector;  ...}

Get Params See code on GitHub

Query Algod to get TestNet suggested TX Params

response
algodClient.getTransactionParams().do().then((d) => {  suggestedTxParams = d;  ...}).catch((e) => {  console.error(e);});

Sign Application Call Transaction See code on GitHub

Ask the user to sign a smart contract application call transaction using the Algorand wallet

response
const txn = algosdk.makeApplicationNoOpTxnFromObject({  from: document.getElementById('from').value,  appIndex: appIndex,  suggestedParams: {...suggestedTxParams}});        txns_b64 = [  {    txn: arrayBufferToBase64(algosdk.encodeUnsignedTransaction(txn)),    message: 'Invoke smart contract call to add one', // Description of transaction to be signed  },];const requestParams = [txns_b64];const request = JsonRpcUtils.formatJsonRpcRequest("algo_signTxn", requestParams);signedTxns = await walletConnector.sendCustomRequest(request);

Send Signed Transaction See code on GitHub

Send the previously signed transaction using AlgoSigner's Send method

response
algodClient.sendRawTransaction(new Uint8Array(signedTxns[0])).do().then((d) => {  tx = d;  ...}).catch((e) => {  console.error(e);});

Check pending transaction See code on GitHub

Query the pending transaction endpoint to check the sent transaction status

response
algodClient.pendingTransactionInformation(tx.txId).do().then((d) => {  txStatus = d;  ...}).catch((e) => {  console.error(e);});

Read State See code on GitHub

Read the global variable state of the smart contract

response
algodClient.getApplicationByID(appIndex).do().then((d) => {  globalState = d['params']['global-state'];  ...}).catch((e) => {  console.error(e);});

Disconnect See code on GitHub

Terminate the current WalletConnect session

response
// Kill the current `walletConnector` sessionwalletConnector.killSession();
Demo app adapted from
By: Damian Barabonkov, damianb[at]mit[dot]edu, @DamianB-BitFlipper
```

Disclaimer

This solution is intended for learning purposes only. It does not cover error checking and other edge cases therefore, should not be used as a production application.

Credits: Created by Damian Barabonkov, [email protected], GitHub: @DamianB-BitFlipper

Disclaimer — This is a sponsored article. DappRadar does not endorse any content or product on this page. DappRadar aims to provide accurate information, but readers should always do their own research before taking action. Articles by DappRadar can not be considered as investment advice.

Regulation and Society adoption

Ждем новостей

Нет новых страниц

Следующая новость