Wallet Adapters
This guide covers the wallet adapters available in the Privacy Boost SDK.Overview
Wallet adapters provide a standard interface for connecting different wallets to the SDK. The SDK includes several built-in adapters and supports custom implementations.WalletAdapter Interface
All adapters implement this interface:Copy
interface WalletAdapter {
connect(): Promise<{ address: string; chainId: number }>;
disconnect(): Promise<void>;
signMessage(message: string): Promise<string>;
signTypedData(typedData: string): Promise<string>;
sendTransaction(tx: TransactionRequest): Promise<string>;
getAddress(): Promise<string>;
getChainId(): Promise<number>;
}
Built-in Adapters
EIP-1193 Adapter
For MetaMask and other EIP-1193 compatible wallets:Copy
import { Eip1193WalletAdapter } from '@testinprod-io/privacy-boost';
// Using window.ethereum
const adapter = new Eip1193WalletAdapter(window.ethereum);
await sdk.auth.connect(adapter);
// Using a specific provider
const provider = getProvider(); // Your EIP-1193 provider
const adapter = new Eip1193WalletAdapter(provider);
WalletConnect Adapter
For WalletConnect v2, use the Wallet Registry:Copy
import { createWalletRegistry } from '@testinprod-io/privacy-boost';
const registry = createWalletRegistry({
chains: [1, 137, 42161],
walletConnect: {
projectId: 'your-walletconnect-project-id',
metadata: {
name: 'Your App',
description: 'Your app description',
url: 'https://yourapp.com',
icons: ['https://yourapp.com/icon.png'],
},
},
});
const adapter = registry.getAdapter('walletconnect');
await sdk.auth.connect(adapter);
Coinbase Wallet Adapter
For Coinbase Wallet, use the Wallet Registry:Copy
import { createWalletRegistry } from '@testinprod-io/privacy-boost';
const registry = createWalletRegistry({
chains: [1],
coinbase: {
appName: 'Your App',
jsonRpcUrl: 'https://mainnet.infura.io/v3/...',
},
});
const adapter = registry.getAdapter('coinbase');
await sdk.auth.connect(adapter);
Private Key Adapter (Testing Only)
For development and testing:Copy
import { PrivateKeyWalletAdapter } from '@testinprod-io/privacy-boost';
// WARNING: Never use in production!
const adapter = new PrivateKeyWalletAdapter({
privateKey: '0x...',
chainId: 1,
rpcUrl: 'https://mainnet.infura.io/v3/...',
});
await sdk.auth.connect(adapter);
Wallet Registry
Manage multiple wallet options:Copy
import { createWalletRegistry } from '@testinprod-io/privacy-boost';
const registry = createWalletRegistry({
chains: [1, 137],
walletConnect: {
projectId: 'your-project-id',
},
coinbase: {
appName: 'Your App',
jsonRpcUrl: 'https://mainnet.infura.io/v3/...',
},
});
// Get available wallets
const wallets = registry.getAvailableWallets();
// Returns: ['injected', 'walletconnect', 'coinbase']
// Get adapter for specific wallet
const adapter = registry.getAdapter('walletconnect');
await sdk.auth.connect(adapter);
Detecting Available Wallets
Copy
function getAvailableWallets(): string[] {
const wallets: string[] = [];
if (typeof window.ethereum !== 'undefined') {
wallets.push('metamask');
// Check for specific wallets
if (window.ethereum.isMetaMask) wallets.push('metamask');
if (window.ethereum.isCoinbaseWallet) wallets.push('coinbase');
if (window.ethereum.isBraveWallet) wallets.push('brave');
}
// WalletConnect is always available
wallets.push('walletconnect');
return wallets;
}
Custom Wallet Adapter
Create your own adapter for unsupported wallets:Copy
import { WalletAdapter, TransactionRequest } from '@testinprod-io/privacy-boost';
class MyCustomWalletAdapter implements WalletAdapter {
private wallet: MyWalletSDK;
constructor(wallet: MyWalletSDK) {
this.wallet = wallet;
}
async connect(): Promise<{ address: string; chainId: number }> {
await this.wallet.connect();
return {
address: await this.wallet.getAddress(),
chainId: await this.wallet.getChainId(),
};
}
async disconnect(): Promise<void> {
await this.wallet.disconnect();
}
async signMessage(message: string): Promise<string> {
return await this.wallet.signPersonalMessage(message);
}
async signTypedData(typedData: string): Promise<string> {
const data = JSON.parse(typedData);
return await this.wallet.signTypedDataV4(data);
}
async sendTransaction(tx: TransactionRequest): Promise<string> {
const txHash = await this.wallet.sendTransaction({
to: tx.to,
value: tx.value,
data: tx.data,
gasLimit: tx.gasLimit,
});
return txHash;
}
async getAddress(): Promise<string> {
return await this.wallet.getAddress();
}
async getChainId(): Promise<number> {
return await this.wallet.getChainId();
}
}
// Usage
const adapter = new MyCustomWalletAdapter(myWallet);
await sdk.auth.connect(adapter);
UI Example: Wallet Selection
Copy
function WalletSelector({ onConnect }: { onConnect: () => void }) {
const [connecting, setConnecting] = useState(false);
const connectWallet = async (type: string) => {
setConnecting(true);
try {
let adapter: WalletAdapter;
const registry = createWalletRegistry({
chains: [1],
walletConnect: { projectId: 'your-project-id' },
coinbase: { appName: 'Your App', jsonRpcUrl: 'https://...' },
});
switch (type) {
case 'metamask':
adapter = new Eip1193WalletAdapter(window.ethereum);
break;
case 'walletconnect':
adapter = registry.getAdapter('walletconnect');
break;
case 'coinbase':
adapter = registry.getAdapter('coinbase');
break;
default:
throw new Error('Unknown wallet type');
}
await sdk.auth.connect(adapter);
await sdk.auth.login();
onConnect();
} catch (error) {
console.error('Connection failed:', error);
} finally {
setConnecting(false);
}
};
return (
<div>
<h2>Connect Wallet</h2>
<button
onClick={() => connectWallet('metamask')}
disabled={connecting || !window.ethereum}
>
MetaMask
</button>
<button
onClick={() => connectWallet('walletconnect')}
disabled={connecting}
>
WalletConnect
</button>
<button
onClick={() => connectWallet('coinbase')}
disabled={connecting}
>
Coinbase Wallet
</button>
</div>
);
}
Handling Connection Events
Copy
// MetaMask account change
window.ethereum?.on('accountsChanged', (accounts: string[]) => {
if (accounts.length === 0) {
console.log('Disconnected');
sdk.auth.disconnect();
} else {
console.log('Account changed to:', accounts[0]);
// Reconnect with new account
}
});
// MetaMask chain change
window.ethereum?.on('chainChanged', (chainId: string) => {
console.log('Chain changed to:', parseInt(chainId, 16));
// Reload or reconnect
});
// MetaMask disconnect
window.ethereum?.on('disconnect', (error: { code: number; message: string }) => {
console.log('Wallet disconnected:', error.message);
sdk.auth.disconnect();
});
Best Practices
1. Check Wallet Availability
Copy
function isWalletAvailable(): boolean {
return typeof window.ethereum !== 'undefined';
}
function getInjectedWalletName(): string {
if (!window.ethereum) return 'None';
if (window.ethereum.isMetaMask) return 'MetaMask';
if (window.ethereum.isCoinbaseWallet) return 'Coinbase Wallet';
if (window.ethereum.isBraveWallet) return 'Brave Wallet';
return 'Unknown Wallet';
}
2. Handle User Rejection
Copy
try {
await sdk.auth.connect(adapter);
} catch (error) {
if (error.code === 4001) {
console.log('User rejected connection');
} else {
console.log('Connection failed:', error.message);
}
}
3. Support Multiple Wallets
Copy
import {
Eip1193WalletAdapter,
createWalletRegistry,
} from '@testinprod-io/privacy-boost';
// Built-in registry includes WalletConnect and Coinbase (lazy-loaded)
const registry = createWalletRegistry();
function getAdapter(walletType: string) {
if (walletType === 'metamask') {
return new Eip1193WalletAdapter(window.ethereum);
}
// WalletConnect, Coinbase, etc. are resolved from the registry
const entry = registry.get(walletType);
if (!entry) throw new Error(`Unknown wallet: ${walletType}`);
return entry.create({ projectId: '...', appName: '...' });
}