Overview
Wallet management is at the heart of any Solana dApp. Hermis provides a comprehensive system for managing wallet connections, state, and interactions across all supported wallets.
Wallet Lifecycle
States
Unconnected No wallet is connected. User needs to select and connect a wallet.
Connecting Connection in progress. Waiting for user approval in wallet.
Connected Wallet successfully connected. Can perform transactions.
Disconnecting Disconnection in progress. Cleaning up resources.
Supported Wallets
Hermis supports any wallet that implements the Wallet Standard . This includes browser extension wallets, mobile wallets, and hardware wallets that conform to the standard.
Wallet Detection
The SDK automatically detects installed wallets and groups them by ready state:
import { useWalletAdapters } from '@hermis/solana-headless-react' ;
function WalletList () {
const { installed , loadable , notDetected , all } = useWalletAdapters ();
// installed: Wallets detected in browser
// loadable: Wallets that can be loaded on demand
// notDetected: Wallets not installed
// all: All adapters sorted by priority
return (
<>
{ installed . map ( adapter => (
< div key = {adapter. name } > {adapter. name } ( Installed ) </ div >
))}
</>
);
}
Ready States
Wallet is installed and detected in the user’s browser
Wallet can be loaded on demand (e.g., WalletConnect)
Wallet is not installed or detected
Wallet is not supported in current environment
Connection Management
Manual Connection
// React
import { useWallet } from '@hermis/solana-headless-react' ;
function ConnectButton () {
const { connect , select } = useWallet ();
const handleConnect = async () => {
select ( 'Phantom' ); // Select wallet
await connect (); // Connect to wallet
};
return < button onClick ={ handleConnect }> Connect </ button > ;
}
// Vanilla JS
import { WalletAdapterManager } from '@hermis/solana-headless-adapter-base' ;
const manager = new WalletAdapterManager ( adapters );
manager . selectAdapter ( 'Phantom' );
await manager . connect ();
Auto-Connect
Automatically reconnect to the last used wallet on page load:
< HermisProvider autoConnect = { true } >
{ children }
</ HermisProvider >
This provides a seamless experience for returning users.
Wallet Selection
Building a Wallet Selector
import { useWallet , useWalletAdapters } from '@hermis/solana-headless-react' ;
function WalletSelector () {
const { select , connect } = useWallet ();
const { installed , notDetected } = useWalletAdapters ();
return (
< div >
< h3 > Installed Wallets </ h3 >
{ installed . map ( adapter => (
< button
key = { adapter . name }
onClick = { () => {
select ( adapter . name );
connect ();
} }
>
{ adapter . icon && < img src = { adapter . icon } alt = { adapter . name } /> }
{ adapter . name }
</ button >
)) }
< h3 > Other Wallets </ h3 >
{ notDetected . map ( adapter => (
< button
key = { adapter . name }
onClick = { () => window . open ( adapter . url , '_blank' ) }
>
{ adapter . name } (Not Installed)
</ button >
)) }
</ div >
);
}
Persistence
Local Storage
Wallet selection is automatically persisted to local storage:
< HermisProvider
storageKey = "my-app-wallet" // Custom storage key
>
{ children }
</ HermisProvider >
Custom Storage
Implement custom storage (e.g., IndexedDB):
import { createIndexedDBStorageFactory } from '@hermis/solana-headless-react' ;
const storage = createIndexedDBStorageFactory ( 'db-name' , 'store-name' );
< HermisProvider storageFactory = { storage } >
{ children }
</ HermisProvider >
Multi-Wallet Support
Switching Wallets
Users can switch between wallets without refreshing:
const { wallet , select , disconnect , connect } = useWallet ();
const switchWallet = async ( newWalletName : string ) => {
await disconnect (); // Disconnect current wallet
select ( newWalletName ); // Select new wallet
await connect (); // Connect to new wallet
};
Wallet Events
React
Use hooks to react to wallet changes:
const { wallet , connected , publicKey } = useWallet ();
useEffect (() => {
if ( connected && publicKey ) {
console . log ( 'Wallet connected:' , publicKey . toBase58 ());
}
}, [ connected , publicKey ]);
Vanilla JS
Subscribe to wallet events:
manager . on ( 'connect' , ( publicKey ) => {
console . log ( 'Connected:' , publicKey . toBase58 ());
});
manager . on ( 'disconnect' , () => {
console . log ( 'Disconnected' );
});
manager . on ( 'error' , ( error ) => {
console . error ( 'Error:' , error );
});
manager . on ( 'walletChanged' , ( wallet ) => {
console . log ( 'Wallet changed to:' , wallet ?. name );
});
Error Handling
Hermis uses HermisError for type-safe error handling:
import { isHermisError , HERMIS_ERROR__WALLET_CONNECTION__FAILED } from '@hermis/errors' ;
try {
await connect ();
} catch ( error ) {
if ( isHermisError ( error , HERMIS_ERROR__WALLET_CONNECTION__FAILED )) {
console . log ( `Failed to connect: ${ error . context . walletName } ` );
} else if ( isHermisError ( error )) {
console . log ( `Error [ ${ error . code } ]: ${ error . message } ` );
}
}
Common Error Patterns
Handle wallet connection failures with context data: import { isHermisError , HERMIS_ERROR__WALLET_CONNECTION__FAILED } from '@hermis/errors' ;
if ( isHermisError ( error , HERMIS_ERROR__WALLET_CONNECTION__FAILED )) {
// Access typed context: walletName, reason, originalError
showToast ( `Failed to connect to ${ error . context . walletName } ` );
}
Check if wallet is not connected before operations: import { isHermisError , HERMIS_ERROR__WALLET_CONNECTION__NOT_CONNECTED } from '@hermis/errors' ;
if ( isHermisError ( error , HERMIS_ERROR__WALLET_CONNECTION__NOT_CONNECTED )) {
showToast ( 'Please connect your wallet first' );
}
Handle any HermisError with automatic message formatting: import { isHermisError } from '@hermis/errors' ;
if ( isHermisError ( error )) {
// HermisError provides formatted messages automatically
showToast ( error . message );
}
Global Error Handler
import { isHermisError } from '@hermis/errors' ;
< HermisProvider
onError = { ( error , adapter ) => {
if ( isHermisError ( error )) {
// HermisError provides formatted messages and typed context
console . error ( `[ ${ error . code } ] ${ error . message } ` );
showToast ( error . message );
} else {
// Handle non-Hermis errors
console . error ( `Error with ${ adapter ?. name } :` , error );
showToast ( `Error: ${ error . message } ` );
}
} }
>
{ children }
</ HermisProvider >
Best Practices
Always Handle Disconnection
Users can disconnect from their wallet extension at any time. Always handle this gracefully: useEffect (() => {
if ( ! connected ) {
// Clear user data, redirect, etc.
}
}, [ connected ]);
Ensure the wallet is connected to the correct network: const { network } = useConnection ();
if ( network !== 'mainnet-beta' ) {
showWarning ( 'Please switch to mainnet' );
}
Show clear states for connecting, connected, and errors: if ( connecting ) return < Spinner />;
if ( connected ) return < ConnectedUI />;
return < ConnectButton />;
Hermis automatically handles mobile wallet detection and deep linking. Simply ensure the Mobile Wallet Adapter is included in your adapters, and users can seamlessly connect from mobile devices. For best performance, remind users to disable battery/power saving mode on their devices to ensure reliable connections and smooth deep linking between your dApp and wallet apps.
What’s Next?