Tezos LogoTezos Boilerplate

Tezos Wallet Boilerplate Docs

Examples

Working examples and code patterns for common Tezos dApp functionality.

Modern Wallet Connection

Using the new wallet system with automatic initialization and state restoration.

Using the useTezos Hook

"use client";

import { useTezos } from "@/lib/tezos/useTezos";
import { Button } from "@/components/ui/button";

export function WalletExample() {
  const { 
    address, 
    isInitialized, 
    connectWallet, 
    connectKukai, 
    disconnectWallet 
  } = useTezos();

  // Show loading while initializing wallets
  if (!isInitialized) {
    return <div>Initializing wallets...</div>;
  }

  return (
    <div className="space-y-4">
      {address ? (
        <div className="space-y-2">
          <p>Connected: {address}</p>
          <Button onClick={disconnectWallet} variant="outline">
            Disconnect
          </Button>
        </div>
      ) : (
        <div className="space-x-2">
          <Button onClick={connectWallet}>
            Connect Beacon Wallet
          </Button>
          <Button onClick={connectKukai} variant="outline">
            Connect Kukai
          </Button>
        </div>
      )}
    </div>
  );
}

// The hook automatically:
// - Checks for existing connections on page load
// - Restores wallet state on refresh  
// - Handles multiple wallet providers
// - Manages connection persistence

✨ Key Benefits

  • Auto-restoration: Wallet state persists across page refreshes
  • Multi-wallet support: Beacon SDK + Kukai Embed simultaneously
  • Zero configuration: Works out of the box with environment variables
  • Type safety: Full TypeScript support with proper error handling

Smart Transaction Sending

Modern transaction handling with automatic gas estimation and retry logic.

Transaction with Auto Gas Estimation

import { useTezos } from "@/lib/tezos/useTezos";

export async function sendTransactionWithGas(
  recipient: string, 
  amount: number
) {
  const { Tezos } = useTezos();
  
  try {
    // Validate inputs
    if (!recipient.match(/^(tz1|tz2|tz3|KT1)/)) {
      throw new Error('Invalid recipient address');
    }

    // Get gas estimation with retries
    const getEstimate = async (retries = 3) => {
      for (let i = 0; i < retries; i++) {
        try {
          return await Tezos.estimate.transfer({
            to: recipient,
            amount: amount
          });
        } catch (error) {
          if (i === retries - 1) throw error;
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
    };

    const estimate = await getEstimate();
    
    // Send transaction with estimated gas
    const operation = await Tezos.wallet.transfer({
      to: recipient,
      amount: amount,
      gasLimit: estimate.gasLimit,
      storageLimit: estimate.storageLimit,
      fee: estimate.suggestedFeeMutez
    }).send();

    // Wait for confirmation
    await operation.confirmation();
    
    return {
      success: true,
      opHash: operation.opHash,
      gasUsed: estimate.gasLimit,
      fee: estimate.suggestedFeeMutez
    };

  } catch (error) {
    console.error('Transaction failed:', error);
    return {
      success: false,
      error: error.message
    };
  }
}

SmartPy Contract Interaction

Example of calling SmartPy contract methods and handling parameters. This shows interacting with classic SmartPy contracts like counters.

SmartPy Counter Contract

import { TezosToolkit } from "@taquito/taquito";

export async function callContract(
  contractAddress: string, 
  entrypoint: string, 
  params: any,
  tezos: TezosToolkit
) {
  try {
    const contract = await tezos.wallet.at(contractAddress);
    
    // Call the contract method
    const operation = await contract.methods[entrypoint](params).send();
    
    console.log('Operation hash:', operation.opHash);

    // Wait for confirmation
    await operation.confirmation();
    
    return {
      success: true,
      opHash: operation.opHash
    };

  } catch (error) {
    console.error('Contract call failed:', error);
    return {
      success: false,
      error: error.message
    };
  }
}

// Example: Calling a SmartPy counter contract
export async function incrementCounter(
  contractAddress: string,
  incrementValue: number,
  tezos: TezosToolkit
) {
  return callContract(contractAddress, 'increment', incrementValue, tezos);
}

export async function decrementCounter(
  contractAddress: string,
  decrementValue: number,
  tezos: TezosToolkit
) {
  return callContract(contractAddress, 'decrement', decrementValue, tezos);
}

Fetching NFT Data

Example of fetching FA2 token data with metadata from IPFS.

NFT Data Fetcher

interface NFTMetadata {
  name: string;
  description: string;
  image: string;
  attributes?: Array<{ trait_type: string; value: string }>;
}

export async function fetchNFTsForAddress(
  address: string,
  contractAddress: string
): Promise<Array<{ tokenId: number; metadata: NFTMetadata }>> {
  try {
    // Fetch tokens from TzKT API
    const response = await fetch(
      `https://api.ghostnet.tzkt.io/v1/tokens/balances?` +
      `account=${address}&token.contract=${contractAddress}`
    );
    
    const tokens = await response.json();
    
    // Fetch metadata for each token
    const nftsWithMetadata = await Promise.all(
      tokens.map(async (token: any) => {
        try {
          // Get token metadata from contract storage
          const metadataResponse = await fetch(
            `https://api.ghostnet.tzkt.io/v1/contracts/${contractAddress}/storage`
          );
          const storage = await metadataResponse.json();
          
          // Parse metadata URI (usually IPFS)
          const metadataUri = storage.token_metadata[token.token.tokenId];
          let metadata: NFTMetadata = {
            name: `Token #${token.token.tokenId}`,
            description: '',
            image: ''
          };

          if (metadataUri) {
            // Fetch from IPFS
            const ipfsResponse = await fetch(metadataUri.replace('ipfs://', 'https://ipfs.io/ipfs/'));
            metadata = await ipfsResponse.json();
          }

          return {
            tokenId: token.token.tokenId,
            balance: token.balance,
            metadata
          };
        } catch (error) {
          console.error(`Failed to fetch metadata for token ${token.token.tokenId}:`, error);
          return {
            tokenId: token.token.tokenId,
            balance: token.balance,
            metadata: {
              name: `Token #${token.token.tokenId}`,
              description: 'Metadata unavailable',
              image: ''
            }
          };
        }
      })
    );

    return nftsWithMetadata;

  } catch (error) {
    console.error('Failed to fetch NFTs:', error);
    return [];
  }
}

TzKT API Integration

Examples of using the TzKT API for blockchain data exploration.

Account InfoGET /v1/accounts/{address}
Account OperationsGET /v1/accounts/{address}/operations
Token BalancesGET /v1/tokens/balances?account={address}
Contract StorageGET /v1/contracts/{address}/storage
Latest BlocksGET /v1/blocks?limit=10
SearchGET /v1/search?query={term}

TzKT API Helper Functions

const TZKT_API = 'https://api.ghostnet.tzkt.io/v1';

export class TzKTClient {
  static async getAccount(address: string) {
    const response = await fetch(`${TZKT_API}/accounts/${address}`);
    return response.json();
  }

  static async getAccountOperations(address: string, limit = 20) {
    const response = await fetch(
      `${TZKT_API}/accounts/${address}/operations?limit=${limit}`
    );
    return response.json();
  }

  static async getTokenBalances(address: string) {
    const response = await fetch(
      `${TZKT_API}/tokens/balances?account=${address}`
    );
    return response.json();
  }

  static async getLatestBlocks(limit = 10) {
    const response = await fetch(`${TZKT_API}/blocks?limit=${limit}`);
    return response.json();
  }

  static async searchBlockchain(query: string) {
    const response = await fetch(`${TZKT_API}/search?query=${query}`);
    return response.json();
  }

  static async getContractStorage(address: string) {
    const response = await fetch(`${TZKT_API}/contracts/${address}/storage`);
    return response.json();
  }
}

Error Handling Patterns

Best practices for handling errors in Tezos dApp development.

Comprehensive Error Handler

export enum TezosErrorType {
  WALLET_NOT_CONNECTED = 'WALLET_NOT_CONNECTED',
  INSUFFICIENT_BALANCE = 'INSUFFICIENT_BALANCE',
  INVALID_ADDRESS = 'INVALID_ADDRESS',
  TRANSACTION_FAILED = 'TRANSACTION_FAILED',
  CONTRACT_NOT_FOUND = 'CONTRACT_NOT_FOUND',
  NETWORK_ERROR = 'NETWORK_ERROR',
  USER_REJECTED = 'USER_REJECTED'
}

export class TezosError extends Error {
  constructor(
    public type: TezosErrorType,
    message: string,
    public originalError?: any
  ) {
    super(message);
    this.name = 'TezosError';
  }
}

export function handleTezosError(error: any): TezosError {
  // Beacon SDK errors
  if (error.message?.includes('Request aborted')) {
    return new TezosError(
      TezosErrorType.USER_REJECTED,
      'Transaction was cancelled by user',
      error
    );
  }

  // Taquito errors
  if (error.message?.includes('balance_too_low')) {
    return new TezosError(
      TezosErrorType.INSUFFICIENT_BALANCE,
      'Insufficient balance for this transaction',
      error
    );
  }

  if (error.message?.includes('invalid_address')) {
    return new TezosError(
      TezosErrorType.INVALID_ADDRESS,
      'The provided address is not valid',
      error
    );
  }

  // Network errors
  if (error.message?.includes('fetch')) {
    return new TezosError(
      TezosErrorType.NETWORK_ERROR,
      'Network connection failed. Please try again.',
      error
    );
  }

  // Default error
  return new TezosError(
    TezosErrorType.TRANSACTION_FAILED,
    error.message || 'An unexpected error occurred',
    error
  );
}

// Usage example
export async function safeTransactionCall<T>(
  operation: () => Promise<T>
): Promise<{ success: true; data: T } | { success: false; error: TezosError }> {
  try {
    const data = await operation();
    return { success: true, data };
  } catch (error) {
    const tezosError = handleTezosError(error);
    console.error('Transaction failed:', tezosError);
    return { success: false, error: tezosError };
  }
}

Next Steps

🏠 Try the Demo

See these examples in action on the home page

Go to demo →

📖 Read the Docs

Learn more about configuration and components

Back to docs →