Skip to content

Create Publication

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

WalletConnect

What is WalletConnect protocol?

WalletConnect is an open protocol to communicate securely between mobile wallets and decentralized applications (dApps) using QR code scanning (desktop) or deep linking (mobile); It’s not an app, not a blockchain and has no token. The protocol is implemented directly within the official Algorand Wallet and allows any dApp developer to add it to their application workflows.

Why should I care?

From an end user standpoint, they really don’t need to understand how it works, but they will need to accept the connection request initiated by the dApp within their mobile wallet. As a dApp developer you’ll want to understand some basics about the protocol for a successful integration and provide a seamless user experience. Algorand provides a custom WalletConnect schema and a quick start guide for accelerating integrations.

WalletConnect Header

The official Algorand Wallet is among the leading crypto wallets supporting the WalletConnect protocol as the industry standard for secure payment prompts and application call transactions. Importantly, user's private keys never leave their mobile device and are never exposed to connected dApps. Adding a Ledger Nano device to the Algorand Wallet further extends the user's security profile while maintaining connection simplicity enabled by the WalletConnect integration.

How it works

Communication between the dApp and the mobile wallet (peers) happens over a bridge server that relays messages without access to their content. Message contents are symmetrically encrypted through a shared key between the two peers using session data. The connection is initiated by the dApp displaying a QR Code or deep link with a standard WalletConnect URI and is established when the user approves this connection request within their Algorand Wallet. Public bridge servers are maintained by WalletConnect and dApp developers may also deploy their own.

Information exchange between the peers typically consists of an unsigned atomic transaction group from the dApp to the mobile wallet, which is then inspected by the user, signed and returned back to the dApp. The dApp will submit the signed object for confirmation by the Algorand network which will effect balances and state accordingly.

WalletConnect Header

Quick start for dApp devs

The TypeScript sample code below should allow a dApp developer to establish a connection and request a simple payment transaction for signature.

Install

yarn add @walletconnect/client algorand-walletconnect-qrcode-modal algosdk @json-rpc-tools/utils
npm install --save @walletconnect/client algorand-walletconnect-qrcode-modal algosdk @json-rpc-tools/utils

Info

Developers are encouraged to watch the walletconnect-monorepo for new releases. Rebuild and deploy your dApp to utilize new features and performance enhancements.

Initiate Connection

import WalletConnect from "@walletconnect/client";
import QRCodeModal from "algorand-walletconnect-qrcode-modal";
import algosdk from "algosdk";
import { formatJsonRpcRequest } from "@json-rpc-tools/utils";

// Create a connector
const connector = new WalletConnect({
  bridge: "https://bridge.walletconnect.org", // Required
  qrcodeModal: QRCodeModal,
});

// Check if connection is already established
if (!connector.connected) {
  // create new session
  connector.createSession();
}

// Subscribe to connection events
connector.on("connect", (error, payload) => {
  if (error) {
    throw error;
  }

  // Get provided accounts
  const { accounts } = payload.params[0];
});

connector.on("session_update", (error, payload) => {
  if (error) {
    throw error;
  }

  // Get updated accounts 
  const { accounts } = payload.params[0];
});

connector.on("disconnect", (error, payload) => {
  if (error) {
    throw error;
  }
});

Sign Transaction

// Draft transaction
const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
    from: "ALICEU3WMO5XYJVSODKJSYLFILIXXBEXHKIVSMX7GMGXJAYGFCJKVSQTUE",
    to: "HZ57J3K46JIJXILONBBZOHX6BKPXEM2VVXNRFSUED6DKFD5ZD24PMJ3MVA",
    amount: 100000,
    suggestedParams,
});

// Sign transaction
// txns is an array of algosdk.Transaction like below
// i.e txns = [txn, ...someotherTxns], but we've only built one transaction in our case
const txns = [txn]
const txnsToSign = txns.map(txn => {
  const encodedTxn = Buffer.from(algosdk.encodeUnsignedTransaction(txn)).toString("base64");

  return {
    txn: encodedTxn,
    message: 'Description of transaction being signed',
    // Note: if the transaction does not need to be signed (because it's part of an atomic group
    // that will be signed by another party), specify an empty singers array like so:
    // signers: [],
  };
});

const requestParams = [txnsToSign];

const request = formatJsonRpcRequest("algo_signTxn", requestParams);
const result: Array<string | null> = await this.connector.sendCustomRequest(request);
const decodedResult = result.map(element => {
  return element ? new Uint8Array(Buffer.from(element, "base64")) : null;
});

Close Connection

// Delete connector
connector.killSession();

Next Steps

A detailed example is offered in React and a live demo is available on TestNet.