Wallet Adapter
Wallet Adapter Specification
Section titled “Wallet Adapter Specification”The wallet adapter provides a unified interface for interacting with different blockchain wallets.
Interface
Section titled “Interface”interface WalletAdapter { // Identity readonly chain: ChainId readonly address: string | null readonly connected: boolean
// Connection connect(): Promise<void> disconnect(): Promise<void>
// Signing signMessage(message: Uint8Array): Promise<Uint8Array> signTransaction(transaction: unknown): Promise<unknown>
// Events on(event: WalletEvent, handler: EventHandler): void off(event: WalletEvent, handler: EventHandler): void}Events
Section titled “Events”| Event | Description |
|---|---|
connect | Wallet connected |
disconnect | Wallet disconnected |
accountChange | Active account changed |
chainChange | Active chain changed |
error | Error occurred |
Implementations
Section titled “Implementations”EthereumWalletAdapter
Section titled “EthereumWalletAdapter”For MetaMask, WalletConnect, and EIP-1193 providers:
import { createEthereumAdapter, getEthereumProvider } from '@sip-protocol/sdk'
const provider = getEthereumProvider()const adapter = createEthereumAdapter(provider)
await adapter.connect()console.log('Connected:', adapter.address)
// Sign messageconst signature = await adapter.signMessage( new TextEncoder().encode('Hello SIP'))
// Sign transactionconst signedTx = await adapter.signTransaction({ to: '0x...', value: '0x...', data: '0x...'})SolanaWalletAdapter
Section titled “SolanaWalletAdapter”For Phantom, Solflare, and Solana wallets:
import { createSolanaAdapter, getSolanaProvider } from '@sip-protocol/sdk'
const provider = getSolanaProvider()const adapter = createSolanaAdapter(provider)
await adapter.connect()console.log('Connected:', adapter.address)
// Sign messageconst signature = await adapter.signMessage(message)
// Sign all transactions (Solana-specific)const signedTxs = await adapter.signAllTransactions(transactions)MockWalletAdapter
Section titled “MockWalletAdapter”For testing:
import { MockWalletAdapter } from '@sip-protocol/sdk'
const adapter = new MockWalletAdapter({ chain: 'ethereum', address: '0xtest...', privateKey: '0x...'})
await adapter.connect()// Works like real adapter for testingBase Class
Section titled “Base Class”abstract class BaseWalletAdapter implements WalletAdapter { protected state: ConnectionState = 'disconnected' protected eventHandlers: Map<WalletEvent, EventHandler[]>
abstract connect(): Promise<void> abstract disconnect(): Promise<void> abstract signMessage(message: Uint8Array): Promise<Uint8Array> abstract signTransaction(tx: unknown): Promise<unknown>
emit(event: WalletEvent, data?: unknown): void { this.eventHandlers.get(event)?.forEach(h => h(data)) }
on(event: WalletEvent, handler: EventHandler): void { const handlers = this.eventHandlers.get(event) || [] handlers.push(handler) this.eventHandlers.set(event, handlers) }
off(event: WalletEvent, handler: EventHandler): void { const handlers = this.eventHandlers.get(event) || [] this.eventHandlers.set(event, handlers.filter(h => h !== handler)) }}Usage with SIP
Section titled “Usage with SIP”import { SIP, createEthereumAdapter, getEthereumProvider } from '@sip-protocol/sdk'
const sip = new SIP({ network: 'testnet' })
// Connect walletconst provider = getEthereumProvider()const adapter = createEthereumAdapter(provider)await adapter.connect()
// Attach to SIPsip.connect(adapter)
// Now SIP can sign intentsconst intent = await sip .intent() .input('ethereum', 'ETH', 1_000_000_000_000_000_000n) .output('solana', 'SOL') .build() // Will sign with connected walletError Handling
Section titled “Error Handling”try { await adapter.connect()} catch (error) { if (error.code === 4001) { // User rejected console.log('User rejected connection') } else if (error.code === -32002) { // Already pending console.log('Connection already pending') } else { throw error }}Chain-Specific Features
Section titled “Chain-Specific Features”Ethereum
Section titled “Ethereum”interface EthereumWalletAdapter extends WalletAdapter { switchChain(chainId: number): Promise<void> addToken(token: TokenInfo): Promise<void> getBalance(): Promise<bigint>}Solana
Section titled “Solana”interface SolanaWalletAdapter extends WalletAdapter { signAllTransactions(txs: Transaction[]): Promise<Transaction[]> sendTransaction(tx: Transaction): Promise<string>}Provider Detection
Section titled “Provider Detection”// Ethereumfunction getEthereumProvider(): EIP1193Provider | null { if (typeof window !== 'undefined') { return window.ethereum || null } return null}
// Solanafunction getSolanaProvider(): SolanaProvider | null { if (typeof window !== 'undefined') { return window.solana || window.phantom?.solana || null } return null}Security Considerations
Section titled “Security Considerations”- Never store private keys - Only use for signing
- Validate addresses - Check format before use
- Clear on disconnect - Remove references to sensitive data
- Handle timeouts - Set reasonable timeouts for signing
- Validate signatures - Verify before submission