Skip to main content

Quick start

This guide will get you up and running with wallet connections in just a few minutes. We’ll walk through a React example, but the concepts apply to all frameworks.

Step 1: Install dependencies

First, install the React adapter and algosdk:
npm install @txnlab/use-wallet-react algosdk
Then install wallet provider packages for the wallets you want to support. For this example, we’ll use Pera and Defly:
npm install @perawallet/connect @blockshake/defly-connect

Step 2: Create a wallet manager

Create a WalletManager instance and configure which wallets to support:
App.tsx
import { NetworkId, WalletId, WalletManager, WalletProvider } from '@txnlab/use-wallet-react'

const walletManager = new WalletManager({
  wallets: [
    WalletId.PERA,
    WalletId.DEFLY,
    {
      id: WalletId.WALLETCONNECT,
      options: { projectId: 'YOUR_PROJECT_ID' }
    }
  ],
  defaultNetwork: NetworkId.TESTNET
})

function App() {
  return (
    <WalletProvider manager={walletManager}>
      <YourApp />
    </WalletProvider>
  )
}
The WalletProvider automatically calls resumeSessions() to restore wallet connections when your app loads.

Configuration options

The WalletManager constructor accepts:
OptionTypeDescription
walletsSupportedWallet[]Array of wallet IDs or config objects
defaultNetworkstringNetwork to use on initialization (default: 'testnet')
networksRecord<string, NetworkConfig>Custom network configurations
options.resetNetworkbooleanReset to defaultNetwork on each load
options.logLevelLogLevelControl console output
options.debugbooleanEnable debug logging

Step 3: Use the wallet hook

Use the useWallet() hook to access wallet state and methods:
Connect.tsx
import { useWallet } from '@txnlab/use-wallet-react'

export function Connect() {
  const { wallets, activeAccount } = useWallet()

  return (
    <div>
      <h2>Connect Wallet</h2>
      
      {wallets.map((wallet) => (
        <div key={wallet.id}>
          <h4>{wallet.metadata.name}</h4>
          
          <button 
            onClick={() => wallet.connect()}
            disabled={wallet.isConnected}
          >
            Connect
          </button>
          
          <button 
            onClick={() => wallet.disconnect()}
            disabled={!wallet.isConnected}
          >
            Disconnect
          </button>
          
          {wallet.isConnected && !wallet.isActive && (
            <button onClick={() => wallet.setActive()}>
              Set Active
            </button>
          )}
        </div>
      ))}
      
      {activeAccount && (
        <div>
          <p>Active Account: {activeAccount.address}</p>
        </div>
      )}
    </div>
  )
}

Hook return values

The useWallet() hook returns:
interface UseWalletReturn {
  // Status
  isReady: boolean
  
  // Wallets
  wallets: Wallet[]
  activeWallet: Wallet | null
  
  // Accounts
  activeWalletAccounts: WalletAccount[] | null
  activeWalletAddresses: string[] | null
  activeAccount: WalletAccount | null
  activeAddress: string | null
  
  // Algod client
  algodClient: algosdk.Algodv2
  setAlgodClient: (client: algosdk.Algodv2) => void
  
  // Transaction signing
  signTransactions: (txns: Transaction[] | Uint8Array[]) => Promise<(Uint8Array | null)[]>
  transactionSigner: algosdk.TransactionSigner
  
  // Data signing (ARC-0076)
  signData: (data: string, metadata: SignMetadata) => Promise<SignDataResponse>
  
  // Private key access (for specific wallets)
  withPrivateKey: <T>(callback: (key: Uint8Array) => Promise<T>) => Promise<T>
}

Step 4: Sign and send transactions

Use the transactionSigner with AlgoSDK’s AtomicTransactionComposer:
SendTransaction.tsx
import { useWallet } from '@txnlab/use-wallet-react'
import algosdk from 'algosdk'
import { useState } from 'react'

export function SendTransaction() {
  const { algodClient, activeAddress, transactionSigner } = useWallet()
  const [txId, setTxId] = useState<string>()

  const sendTransaction = async () => {
    if (!activeAddress) {
      throw new Error('No active account')
    }

    // Create a transaction
    const suggestedParams = await algodClient.getTransactionParams().do()
    const transaction = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
      sender: activeAddress,
      receiver: activeAddress,
      amount: 1_000_000, // 1 ALGO
      suggestedParams
    })

    // Use AtomicTransactionComposer
    const atc = new algosdk.AtomicTransactionComposer()
    atc.addTransaction({ txn: transaction, signer: transactionSigner })

    // Execute transaction
    const result = await atc.execute(algodClient, 4)
    
    console.log('Transaction successful!', result.txIDs)
    setTxId(result.txIDs[0])
  }

  return (
    <div>
      <button onClick={sendTransaction} disabled={!activeAddress}>
        Send 1 ALGO to self
      </button>
      
      {txId && (
        <p>
          Transaction ID: <code>{txId}</code>
        </p>
      )}
    </div>
  )
}
The transactionSigner automatically handles wallet-specific signing and only signs transactions that require the active account’s signature.

Step 5: Switch networks

Use the useNetwork() hook to manage network configuration:
NetworkSelector.tsx
import { useNetwork } from '@txnlab/use-wallet-react'
import { NetworkId } from '@txnlab/use-wallet-react'

export function NetworkSelector() {
  const { activeNetwork, setActiveNetwork } = useNetwork()

  return (
    <div>
      <label>Network:</label>
      <select 
        value={activeNetwork} 
        onChange={(e) => setActiveNetwork(e.target.value)}
      >
        <option value={NetworkId.MAINNET}>MainNet</option>
        <option value={NetworkId.TESTNET}>TestNet</option>
        <option value={NetworkId.BETANET}>BetaNet</option>
        <option value={NetworkId.LOCALNET}>LocalNet</option>
      </select>
    </div>
  )
}

Complete example

Here’s a complete working example combining all the pieces:
main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
App.tsx
import {
  NetworkId,
  WalletId,
  WalletManager,
  WalletProvider,
  useWallet
} from '@txnlab/use-wallet-react'
import algosdk from 'algosdk'

// Create wallet manager
const walletManager = new WalletManager({
  wallets: [
    WalletId.DEFLY,
    WalletId.PERA,
    {
      id: WalletId.WALLETCONNECT,
      options: { projectId: 'fcfde0713d43baa0d23be0773c80a72b' }
    }
  ],
  defaultNetwork: NetworkId.TESTNET
})

function WalletInterface() {
  const { 
    wallets, 
    activeAddress, 
    activeAccount,
    algodClient,
    transactionSigner 
  } = useWallet()

  const sendPayment = async () => {
    if (!activeAddress) return

    const suggestedParams = await algodClient.getTransactionParams().do()
    const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
      sender: activeAddress,
      receiver: activeAddress,
      amount: 0,
      suggestedParams
    })

    const atc = new algosdk.AtomicTransactionComposer()
    atc.addTransaction({ txn, signer: transactionSigner })

    const result = await atc.execute(algodClient, 4)
    console.log('Success!', result.txIDs)
  }

  return (
    <div>
      <h1>Algorand Wallet Demo</h1>
      
      {/* Wallet Connection */}
      <div>
        <h2>Wallets</h2>
        {wallets.map((wallet) => (
          <div key={wallet.id} style={{ margin: '1rem 0' }}>
            <strong>
              {wallet.metadata.name}
              {wallet.isActive && ' [active]'}
            </strong>
            <div>
              <button
                onClick={() => wallet.connect()}
                disabled={wallet.isConnected}
              >
                Connect
              </button>
              <button
                onClick={() => wallet.disconnect()}
                disabled={!wallet.isConnected}
              >
                Disconnect
              </button>
              {wallet.isConnected && !wallet.isActive && (
                <button onClick={() => wallet.setActive()}>
                  Set Active
                </button>
              )}
            </div>
            
            {/* Account Selection */}
            {wallet.isActive && wallet.accounts.length > 0 && (
              <select 
                onChange={(e) => wallet.setActiveAccount(e.target.value)}
                value={activeAccount?.address}
              >
                {wallet.accounts.map((account) => (
                  <option key={account.address} value={account.address}>
                    {account.address.slice(0, 8)}...
                  </option>
                ))}
              </select>
            )}
          </div>
        ))}
      </div>
      
      {/* Transaction */}
      {activeAddress && (
        <div>
          <h2>Active Account</h2>
          <p><code>{activeAddress}</code></p>
          <button onClick={sendPayment}>
            Send 0 ALGO transaction
          </button>
        </div>
      )}
    </div>
  )
}

function App() {
  return (
    <WalletProvider manager={walletManager}>
      <WalletInterface />
    </WalletProvider>
  )
}

export default App

Other frameworks

The API is similar across all framework adapters:
<script setup lang="ts">
import { useWallet } from '@txnlab/use-wallet-vue'

const { wallets, activeAddress } = useWallet()
</script>

<template>
  <div>
    <div v-for="wallet in wallets" :key="wallet.id">
      <h4>{{ wallet.metadata.name }}</h4>
      <button @click="wallet.connect()" :disabled="wallet.isConnected">
        Connect
      </button>
    </div>
    
    <p v-if="activeAddress">
      Active: {{ activeAddress }}
    </p>
  </div>
</template>

Next steps

Wallet configuration

Learn about wallet-specific configuration options and features

Network configuration

Configure custom networks and algod clients

Transaction signing

Deep dive into signing single and grouped transactions

API reference

Explore the complete API documentation

Build docs developers (and LLMs) love