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 Info | GET /v1/accounts/{address} |
Account Operations | GET /v1/accounts/{address}/operations |
Token Balances | GET /v1/tokens/balances?account={address} |
Contract Storage | GET /v1/contracts/{address}/storage |
Latest Blocks | GET /v1/blocks?limit=10 |
Search | GET /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 };
}
}