@exe-pay/react-hooks
React hooks for seamless integration of ExePay features into your React applications. Built on top of Solana Wallet Adapter.
Installation
npm install @exe-pay/react-hooks @solana/wallet-adapter-reactAvailable Hooks
useWallet
Core wallet connection hook from Solana Wallet Adapter.
import { useWallet } from '@solana/wallet-adapter-react';
export function MyComponent() {
const {
publicKey, // User's wallet address
connected, // Connection status
connecting, // Loading state
disconnect, // Disconnect function
signMessage, // Sign arbitrary message
signTransaction, // Sign transaction
sendTransaction // Sign and send transaction
} = useWallet();
return (
<div>
{connected ? (
<p>Connected: {publicKey?.toBase58()}</p>
) : (
<button onClick={() => {}}>Connect Wallet</button>
)}
</div>
);
}useConnection
Access Solana RPC connection for blockchain queries.
import { useConnection } from '@solana/wallet-adapter-react';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
export function BalanceDisplay() {
const { connection } = useConnection();
const { publicKey } = useWallet();
const [balance, setBalance] = useState(0);
useEffect(() => {
if (!publicKey) return;
// Fetch balance
connection.getBalance(publicKey).then(lamports => {
setBalance(lamports / LAMPORTS_PER_SOL);
});
// Subscribe to balance changes
const subscriptionId = connection.onAccountChange(
publicKey,
(accountInfo) => {
setBalance(accountInfo.lamports / LAMPORTS_PER_SOL);
}
);
return () => {
connection.removeAccountChangeListener(subscriptionId);
};
}, [publicKey, connection]);
return <p>Balance: {balance.toFixed(4)} SOL</p>;
}Custom Hook: useStealthAddress
Hook for managing stealth addresses and private payments.
import { useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';
import { generateStealthAddress, generateStealthMetaAddress } from '@exe-pay/privacy';
export function useStealthAddress() {
const { publicKey, signMessage } = useWallet();
const [metaAddress, setMetaAddress] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const generateMeta = async () => {
if (!publicKey || !signMessage) throw new Error('Wallet not connected');
setLoading(true);
try {
const message = new TextEncoder().encode('Generate Stealth Meta-Address');
const signature = await signMessage(message);
const meta = await generateStealthMetaAddress(publicKey, signature);
setMetaAddress(meta);
return meta;
} finally {
setLoading(false);
}
};
const generateStealth = async (recipientMeta: string) => {
const { stealthAddress, ephemeralPubkey, viewTag } =
await generateStealthAddress(recipientMeta);
return { stealthAddress, ephemeralPubkey, viewTag };
};
return { metaAddress, generateMeta, generateStealth, loading };
}Custom Hook: useViewKeys
Hook for generating and managing view keys.
import { useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';
import { generateViewKeys, encodeViewKeys } from '@exe-pay/privacy';
export function useViewKeys() {
const { publicKey, signMessage } = useWallet();
const [viewKeys, setViewKeys] = useState(null);
const [loading, setLoading] = useState(false);
const generate = async () => {
if (!publicKey || !signMessage) throw new Error('Wallet not connected');
setLoading(true);
try {
const message = new TextEncoder().encode(
`Generate View Keys - ${Date.now()}`
);
const signature = await signMessage(message);
const keys = await generateViewKeys(publicKey, signature);
const encoded = encodeViewKeys(keys);
setViewKeys(encoded);
return encoded;
} finally {
setLoading(false);
}
};
const exportKeys = () => {
if (!viewKeys) return;
const data = JSON.stringify(viewKeys, null, 2);
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'exepay-view-keys.json';
a.click();
URL.revokeObjectURL(url);
};
return { viewKeys, generate, exportKeys, loading };
}Custom Hook: usePaymentScanner
Hook for scanning blockchain for stealth payments.
import { useState, useCallback } from 'react';
import { useWallet, useConnection } from '@solana/wallet-adapter-react';
import { scanForPayments } from '@exe-pay/privacy';
export function usePaymentScanner() {
const { publicKey } = useWallet();
const { connection } = useConnection();
const [payments, setPayments] = useState([]);
const [scanning, setScanning] = useState(false);
const scan = useCallback(async () => {
if (!publicKey) throw new Error('Wallet not connected');
setScanning(true);
try {
const found = await scanForPayments(connection, publicKey, {
limit: 100,
useViewTags: true,
onProgress: (count) => console.log(`Found ${count} payments`)
});
setPayments(found);
return found;
} finally {
setScanning(false);
}
}, [publicKey, connection]);
return { payments, scan, scanning };
}Provider Setup
import { WalletProvider } from '@solana/wallet-adapter-react';
import { WalletModalProvider } from '@solana/wallet-adapter-react-ui';
import { PhantomWalletAdapter, SolflareWalletAdapter } from '@solana/wallet-adapter-wallets';
import { ConnectionProvider } from '@solana/wallet-adapter-react';
import '@solana/wallet-adapter-react-ui/styles.css';
const wallets = [
new PhantomWalletAdapter(),
new SolflareWalletAdapter(),
];
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ConnectionProvider endpoint="https://api.mainnet-beta.solana.com">
<WalletProvider wallets={wallets} autoConnect>
<WalletModalProvider>
{children}
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
);
}Best Practices
- Always check wallet connection before transactions
- Handle loading states to improve user experience
- Implement error boundaries for transaction failures
- Use confirmation strategy appropriate for your use case
- Cache RPC calls to reduce API usage
- Implement retry logic for failed transactions
✅ Production Ready
All hooks are tested on Solana mainnet and ready for production use. Visit our examples page for complete implementations.
