useWallet Hook
⚠️ Development Version - Not Production ReadyThis documentation reflects the latest development version. Some features may be incomplete or subject to change. Do not use in production environments.
The useWallet
hook is the primary interface for interacting with LazorKit wallets in React applications.
Import
import { useWallet } from '@lazorkit/wallet';
Quick Start
import { useWallet } from '@lazorkit/wallet';
import { SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
function WalletComponent() {
const {
account,
isConnected,
connect,
disconnect,
signAndSendTransaction
} = useWallet();
const handleConnect = () => connect();
const handleSend = async () => {
if (!account) return;
const instruction = SystemProgram.transfer({
fromPubkey: account.smartWallet,
toPubkey: 'RECIPIENT_ADDRESS',
lamports: 0.1 * LAMPORTS_PER_SOL,
});
const signature = await signAndSendTransaction(instruction);
console.log('Sent:', signature);
};
return (
<div>
{!isConnected ? (
<button onClick={handleConnect}>Connect Wallet</button>
) : (
<div>
<p>Connected: {account.smartWallet}</p>
<button onClick={handleSend}>Send SOL</button>
<button onClick={disconnect}>Disconnect</button>
</div>
)}
</div>
);
}
Complete Interface
const {
// State
account, // WalletAccount | null
smartWalletPubkey, // PublicKey | null
isConnected, // boolean
isConnecting, // boolean
isSigning, // boolean
error, // Error | null
// Core Actions
connect, // () => Promise<WalletAccount>
disconnect, // () => Promise<void>
signAndSendTransaction, // (instruction) => Promise<string>
// Advanced Actions
signTransaction, // (instruction) => Promise<Transaction>
buildSmartWalletTransaction, // (payer, instruction) => Promise<{...}>
createPasskeyOnly, // () => Promise<ConnectResponse>
createSmartWalletOnly, // (passkey) => Promise<{...}>
} = useWallet();
State Properties
Property | Type | Description |
---|---|---|
account | WalletAccount | null | Complete wallet info when connected |
smartWalletPubkey | PublicKey | null | Smart wallet public key |
isConnected | boolean | !!account - connection status |
isConnecting | boolean | Connection operation in progress |
isSigning | boolean | Transaction signing in progress |
error | Error | null | Last error that occurred |
WalletAccount Type
interface WalletAccount {
publicKey: string; // Passkey public key (base64)
smartWallet: string; // Smart wallet address (base58)
isConnected: boolean; // Always true when account exists
isCreated: boolean; // True if just created
}
Core Actions
connect()
Returns: Promise<WalletAccount>
Throws: Error
with specific error codes
Connects wallet with auto-reconnection fallback.
try {
const account: WalletAccount = await connect();
// account = {
// publicKey: "base64-encoded-passkey-public-key",
// smartWallet: "base58-wallet-address",
// isConnected: true,
// isCreated: boolean // true if just created
// }
console.log('Connected:', account.smartWallet);
} catch (error: Error) {
// error.code will be one of:
// 'NO_STORED_CREDENTIALS' | 'USER_CANCELLED' | 'CONNECTION_FAILED'
console.error('Connection failed:', error.code, error.message);
}
disconnect()
Returns: Promise<void>
Throws: Rarely throws, logs errors internally
Disconnects wallet but preserves session for reconnection.
try {
await disconnect(); // Always resolves
// State after disconnect:
// account = null, isConnected = false
} catch (error) {
// Usually logs internally, rarely throws
}
signAndSendTransaction()
Returns: Promise<string>
(transaction signature)
Throws: Error
with transaction-specific codes
Signs and sends transaction, returns signature.
try {
const signature: string = await signAndSendTransaction(instruction);
// signature = "base58-transaction-signature"
console.log('Transaction sent:', signature);
// Verify on explorer:
// https://explorer.solana.com/tx/${signature}?cluster=devnet
} catch (error: Error) {
// error.code possibilities:
// 'NOT_CONNECTED' - no wallet connected
// 'USER_CANCELLED' - user cancelled signing
// 'TRANSACTION_FAILED' - network/execution error
// 'INSUFFICIENT_FUNDS' - not enough SOL/tokens
switch (error.code) {
case 'NOT_CONNECTED':
console.log('Please connect wallet first');
break;
case 'USER_CANCELLED':
console.log('User cancelled transaction');
break;
case 'INSUFFICIENT_FUNDS':
console.log('Not enough balance');
break;
default:
console.error('Transaction failed:', error.message);
}
}
Advanced Actions
signTransaction()
Returns: Promise<Transaction>
(signed but not sent)
Throws: Error
with signing-specific codes
Signs transaction without sending to network.
try {
const signedTx: Transaction = await signTransaction(instruction);
// signedTx is a fully signed Solana Transaction object
// You can inspect: signedTx.signatures, signedTx.instructions
// Send later manually if needed:
// const signature = await connection.sendTransaction(signedTx);
} catch (error: Error) {
// Same error codes as signAndSendTransaction except 'TRANSACTION_FAILED'
console.error('Signing failed:', error.code);
}
buildSmartWalletTransaction()
Returns: Promise<{createSessionTx: VersionedTransaction, executeSessionTx: VersionedTransaction}>
Throws: Error
if wallet not connected or instruction invalid
Creates unsigned transactions for external payer integration.
try {
const externalPayer = new PublicKey('EXTERNAL_PAYER_ADDRESS');
const result = await buildSmartWalletTransaction(externalPayer, instruction);
// result = {
// createSessionTx: VersionedTransaction, // Creates session account
// executeSessionTx: VersionedTransaction // Executes your instruction
// }
// Both transactions are UNSIGNED - external payer must sign
const serializedSessionTx = result.createSessionTx.serialize();
const serializedExecuteTx = result.executeSessionTx.serialize();
// Send to backend service that controls external payer
await sendToBackend({
sessionTx: Buffer.from(serializedSessionTx).toString('base64'),
executeTx: Buffer.from(serializedExecuteTx).toString('base64')
});
} catch (error: Error) {
// error.code: 'NOT_CONNECTED' | 'INVALID_INSTRUCTION'
console.error('Build failed:', error.message);
}
createPasskeyOnly()
Returns: Promise<ConnectResponse>
Throws: Error
if WebAuthn fails
Creates passkey without deploying smart wallet.
try {
const passkeyData: ConnectResponse = await createPasskeyOnly();
// passkeyData = {
// publicKey: "base64-encoded-public-key",
// credentialId: "webauthn-credential-id",
// isCreated: true, // true = new, false = existing
// connectionType: "create" | "get",
// timestamp: 1640995200000
// }
// Store passkeyData for later wallet deployment
localStorage.setItem('tempPasskey', JSON.stringify(passkeyData));
} catch (error: Error) {
// error.code: 'USER_CANCELLED' | 'PASSKEY_CREATION_FAILED'
console.error('Passkey creation failed:', error.code);
}
createSmartWalletOnly()
Returns: Promise<{smartWalletAddress: string, account: WalletAccount}>
Throws: Error
if deployment fails
Deploys smart wallet using existing passkey data.
try {
const result = await createSmartWalletOnly(passkeyData);
// result = {
// smartWalletAddress: "base58-wallet-address",
// account: WalletAccount // Same as connect() return
// }
console.log('Wallet deployed at:', result.smartWalletAddress);
// Now account.isConnected = true and hook state updates
} catch (error: Error) {
// error.code: 'INVALID_PASSKEY_DATA' | 'SMART_WALLET_CREATION_FAILED'
console.error('Wallet deployment failed:', error.code);
}
Common Examples
Error Handling
try {
const account = await connect();
} catch (error) {
switch (error.code) {
case 'NO_STORED_CREDENTIALS':
console.log('First time user');
break;
case 'USER_CANCELLED':
console.log('User cancelled authentication');
break;
default:
console.error('Connection failed:', error);
}
}
Step-by-Step Creation
// Step 1: Create passkey
const passkeyData = await createPasskeyOnly();
// Step 2: Deploy wallet (can be done later)
const { account } = await createSmartWalletOnly(passkeyData);
console.log('Wallet ready:', account.smartWallet);
External Payer Pattern
const { createSessionTx, executeSessionTx } = await buildSmartWalletTransaction(
externalPayerPubkey,
instruction
);
// Send serialized transactions to backend for signing
Loading States
<button
onClick={handleTransfer}
disabled={!isConnected || isSigning}
>
{isSigning ? 'Sending...' : 'Transfer SOL'}
</button>
Complete Error Reference
All LazorKit errors extend the base Error
class with an additional code
property:
interface LazorkitError extends Error {
code: string; // Specific error code
message: string; // Human-readable message
details?: any; // Additional error context
}
Connection Errors
Code | Method | Description | Action |
---|---|---|---|
NO_STORED_CREDENTIALS | connect() | First time user | Show onboarding |
USER_CANCELLED | connect() | User cancelled WebAuthn | Retry or alternative |
INVALID_CREDENTIALS | connect() | Corrupted stored data | Auto-cleared, retry |
CONNECTION_FAILED | connect() | Network/service error | Check network, retry |
Transaction Errors
Code | Method | Description | Action |
---|---|---|---|
NOT_CONNECTED | signAndSendTransaction() | No wallet connected | Call connect() first |
USER_CANCELLED | signAndSendTransaction() | User cancelled signing | User choice, no action |
INSUFFICIENT_FUNDS | signAndSendTransaction() | Not enough balance | Show balance, request funds |
TRANSACTION_FAILED | signAndSendTransaction() | Network/execution error | Check network, retry |
Creation Errors
Code | Method | Description | Action |
---|---|---|---|
PASSKEY_CREATION_FAILED | createPasskeyOnly() | WebAuthn device error | Check device, retry |
SMART_WALLET_CREATION_FAILED | createSmartWalletOnly() | Deployment failed | Check network, retry |
INVALID_PASSKEY_DATA | createSmartWalletOnly() | Bad passkey input | Recreate passkey |
Error Handling Pattern
const handleWalletError = (error: LazorkitError) => {
switch (error.code) {
case 'NO_STORED_CREDENTIALS':
return 'Welcome! Let\'s create your first wallet.';
case 'USER_CANCELLED':
return 'Authentication cancelled. Try again when ready.';
case 'INSUFFICIENT_FUNDS':
return `Not enough balance. Need ${error.details?.required} SOL.`;
case 'CONNECTION_FAILED':
return 'Network error. Please check connection and retry.';
default:
return `Unexpected error: ${error.message}`;
}
};
// Usage
try {
await connect();
} catch (error) {
const userMessage = handleWalletError(error);
setErrorMessage(userMessage);
}
See Type Definitions for complete interfaces.