@klever/connect-wallet
v0.1.3
Published
Wallet implementations for Klever Connect SDK
Readme
@klever/connect-wallet
Wallet implementations for Klever Connect SDK - manage keys and sign transactions.
Overview
@klever/connect-wallet provides secure wallet management for the Klever Blockchain with support for multiple environments and wallet types. Choose the right wallet implementation for your use case.
Key Features
- Multi-Environment Support - Node.js, Browser, and React Native (coming soon)
- Dual-Mode BrowserWallet - Extension mode (secure) or private key mode (testing)
- NodeWallet - Server-side operations with PEM file support
- WalletFactory - Automatic environment detection for cross-platform apps
- Transaction Signing - Ed25519 signature scheme for all transaction types
- Message Signing - Sign arbitrary messages for authentication
- Event System - Listen for account changes and connection events
- PEM Support - Import encrypted/unencrypted PEM files
- TypeScript First - Full type safety and IntelliSense support
Installation
npm install @klever/connect-walletPeer Dependencies:
npm install @klever/connect-core @klever/connect-crypto @klever/connect-provider @klever/connect-transactionsQuick Start
Browser Extension Mode (Recommended for dApps)
import { BrowserWallet } from '@klever/connect-wallet'
import { KleverProvider } from '@klever/connect-provider'
const provider = new KleverProvider({ network: 'mainnet' })
const wallet = new BrowserWallet(provider)
await wallet.connect() // Opens Klever Extension
console.log('Connected:', wallet.address)
// Send a transaction (user confirms in extension)
const result = await wallet.transfer({
receiver: 'klv1...',
amount: 1000000, // 1 KLV (6 decimals)
})
console.log('Transaction hash:', result.hash)Node.js Server (Backend/CLI)
import { NodeWallet } from '@klever/connect-wallet'
import { KleverProvider } from '@klever/connect-provider'
const provider = new KleverProvider({ network: 'mainnet' })
const wallet = new NodeWallet(provider, process.env.PRIVATE_KEY)
await wallet.connect()
console.log('Connected:', wallet.address)
const result = await wallet.transfer({
receiver: 'klv1...',
amount: 1000000,
})Wallet Comparison
| Feature | BrowserWallet (Extension) | BrowserWallet (Private Key) | NodeWallet | | ----------------------------- | ------------------------- | --------------------------- | ---------- | | Environment | Browser only | Browser only | Node.js | | Security | High (extension vault) | Medium (memory) | Medium | | User Confirmation | Yes (extension UI) | No | No | | Private Key Storage | Extension manages | Developer manages | Developer | | Best For | Production dApps | Testing/Development | Backends | | Klever Extension Required | Yes | No | No | | Account Switching | Yes (automatic) | No | No | | Network Switching | Yes (extension) | Manual | Manual | | PEM File Support | Yes (via extension) | Yes | Yes |
When to Use Each Wallet Type
BrowserWallet (Extension Mode):
- Production dApps and web applications
- When users control their own keys
- Multi-account support needed
- Best user experience with confirmation dialogs
BrowserWallet (Private Key Mode):
- Testing and development
- Browser-based tools or demos
- When extension is not available
- NOT recommended for production with real funds
NodeWallet:
- Backend services and automation
- CLI tools and scripts
- Server-side transaction signing
- Batch operations and scheduled tasks
Usage Examples
BrowserWallet - Extension Mode
Basic Connection
import { BrowserWallet } from '@klever/connect-wallet'
import { KleverProvider } from '@klever/connect-provider'
const provider = new KleverProvider({ network: 'mainnet' })
const wallet = new BrowserWallet(provider)
try {
await wallet.connect()
console.log('Connected to:', wallet.address)
console.log('Public key:', wallet.publicKey)
} catch (error) {
if (error.message.includes('Extension not found')) {
alert('Please install Klever Extension: https://klever.io/extension')
}
}Listening to Account Changes
const wallet = new BrowserWallet(provider)
await wallet.connect()
// User switches accounts in extension
wallet.on('accountChanged', ({ address }) => {
console.log('Account switched to:', address)
// Update UI, reload balances, etc.
})
// User switches to different blockchain
wallet.on('disconnect', () => {
console.log('User disconnected or switched chains')
// Show connection UI
})Signing Messages for Authentication
const wallet = new BrowserWallet(provider)
await wallet.connect()
// Sign authentication message
const message = `Sign in to MyDapp\nNonce: ${Date.now()}`
const signature = await wallet.signMessage(message) // User confirms in extension
// Send to backend for verification
const response = await fetch('/api/auth', {
method: 'POST',
body: JSON.stringify({
address: wallet.address,
message,
signature: signature.toHex(),
}),
})BrowserWallet - Private Key Mode
WARNING: Only use private key mode for testing. Never use with real funds in production.
import { BrowserWallet } from '@klever/connect-wallet'
// Testing only - DO NOT use in production
const wallet = new BrowserWallet(provider, {
privateKey: '0x123...', // Your test private key
})
await wallet.connect() // No extension needed
const result = await wallet.transfer({
receiver: 'klv1...',
amount: 1000000,
})Using PEM Files in Browser
// Load PEM file content (e.g., from file input)
const pemContent = await file.text()
const wallet = new BrowserWallet(provider, {
pemContent,
pemPassword: 'your-password', // Optional, for encrypted PEMs
})
await wallet.connect()
console.log('Loaded from PEM:', wallet.address)NodeWallet - Server Side
Basic Usage
import { NodeWallet } from '@klever/connect-wallet'
import { KleverProvider } from '@klever/connect-provider'
const provider = new KleverProvider({ network: 'mainnet' })
const wallet = new NodeWallet(provider, process.env.PRIVATE_KEY)
await wallet.connect()
// Check balance
const balance = await wallet.getBalance()
console.log('Balance:', balance / 1000000n, 'KLV') // Convert to KLV
// Get nonce
const nonce = await wallet.getNonce()
console.log('Next nonce:', nonce)Loading from PEM Files
import { NodeWallet } from '@klever/connect-wallet'
import { cryptoProvider } from '@klever/connect-crypto'
const provider = new KleverProvider({ network: 'mainnet' })
// Load encrypted PEM file
const pemResult = await cryptoProvider.importPrivateKeyFromPemFile('./wallet.pem', {
password: process.env.PEM_PASSWORD,
})
const wallet = new NodeWallet(provider, pemResult.toHex())
await wallet.connect()
console.log('Loaded wallet:', wallet.address)Generating New Wallets
import { NodeWallet } from '@klever/connect-wallet'
// Generate a new random wallet
const newWallet = await NodeWallet.generate(provider)
await newWallet.connect()
console.log('New wallet created!')
console.log('Address:', newWallet.address)
console.log('IMPORTANT: Save your private key securely!')Secure Disconnect
const wallet = new NodeWallet(provider, privateKey)
await wallet.connect()
// ... perform operations ...
// Clear private key from memory (recommended)
await wallet.disconnect(true)
// Cannot reconnect - need new wallet instance
// await wallet.connect() // ❌ Throws errorWalletFactory - Cross-Platform
import { WalletFactory } from '@klever/connect-wallet'
import { KleverProvider } from '@klever/connect-provider'
const provider = new KleverProvider({ network: 'mainnet' })
const factory = new WalletFactory(provider)
// Automatically creates NodeWallet in Node.js, BrowserWallet in browser
const wallet = await factory.createWallet({
privateKey: process.env.PRIVATE_KEY, // Required in Node.js, optional in browser
})
await wallet.connect()
console.log('Wallet type auto-detected:', wallet.constructor.name)Convenience Function:
import { createWallet } from '@klever/connect-wallet'
const wallet = await createWallet({
network: 'testnet',
privateKey: process.env.PRIVATE_KEY,
})
await wallet.connect()Common Use Cases
1. Generate New Wallet and Save Securely
import { NodeWallet } from '@klever/connect-wallet'
import { hexEncode } from '@klever/connect-encoding'
import fs from 'fs/promises'
// Generate new wallet
const wallet = await NodeWallet.generate(provider)
await wallet.connect()
console.log('New address:', wallet.address)
// IMPORTANT: Save private key securely
// Option 1: Environment variable (recommended)
console.log('Add to .env file:')
console.log(`PRIVATE_KEY=${process.env.PRIVATE_KEY}`)
// Option 2: Encrypted storage (production)
// Use proper key management system, HSM, or vault2. Load Wallet from PEM File
Node.js:
import { NodeWallet } from '@klever/connect-wallet'
import { cryptoProvider } from '@klever/connect-crypto'
const pemResult = await cryptoProvider.importPrivateKeyFromPemFile('./wallet.pem', {
password: process.env.PEM_PASSWORD, // Optional for unencrypted
})
const wallet = new NodeWallet(provider, pemResult.toHex())
await wallet.connect()Browser:
import { BrowserWallet } from '@klever/connect-wallet'
// From file input
const fileInput = document.querySelector('input[type="file"]')
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0]
const pemContent = await file.text()
const wallet = new BrowserWallet(provider, {
pemContent,
pemPassword: prompt('Enter PEM password:'),
})
await wallet.connect()
console.log('Loaded:', wallet.address)
})3. Connect Browser Extension Wallet
import { BrowserWallet } from '@klever/connect-wallet'
const wallet = new BrowserWallet(provider)
// Check if extension is available
if (typeof window.kleverWeb === 'undefined') {
alert('Please install Klever Extension')
window.open('https://klever.io/extension', '_blank')
} else {
await wallet.connect()
console.log('Connected via extension:', wallet.address)
}4. Sign Messages for Authentication
// Frontend - Sign message
const message = `Welcome to MyDapp!\nSign to authenticate.\nNonce: ${Date.now()}`
const signature = await wallet.signMessage(message)
// Send to backend
await fetch('/api/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
address: wallet.address,
message,
signature: signature.toHex(),
}),
})
// Backend - Verify signature
import { verifySignature } from '@klever/connect-crypto'
import { hexDecode } from '@klever/connect-encoding'
const messageBytes = new TextEncoder().encode(message)
const signatureBytes = hexDecode(signature)
const publicKeyBytes = hexDecode(publicKey)
const isValid = await verifySignature(messageBytes, signatureBytes, publicKeyBytes)
if (!isValid) {
throw new Error('Invalid signature')
}5. Build and Sign Transactions
import { TransactionBuilder } from '@klever/connect-transactions'
import { TXType } from '@klever/connect-core'
// Build transaction
const builder = new TransactionBuilder(provider)
builder
.addContract({
contractType: TXType.Transfer,
receiver: 'klv1...',
amount: '1000000',
})
.sender(wallet.address)
const unsignedTx = await builder.build()
// Sign transaction
const signedTx = await wallet.signTransaction(unsignedTx)
// Broadcast
const hash = await wallet.broadcastTransaction(signedTx)
console.log('Transaction hash:', hash)6. Verify Signatures
const message = 'Hello, Klever!'
const signature = await wallet.signMessage(message)
// Verify with Signature object
const isValid = await wallet.verifyMessage(message, signature)
console.log('Valid:', isValid) // true
// Verify with hex string
const isValidHex = await wallet.verifyMessage(message, signature.toHex())
// Verify with base64 string
const isValidBase64 = await wallet.verifyMessage(message, signature.toBase64())7. Switch Between Accounts (Extension Only)
const wallet = new BrowserWallet(provider)
await wallet.connect()
// Listen for account changes
wallet.on('accountChanged', ({ address, chain }) => {
console.log('Switched to account:', address)
console.log('Chain:', chain) // 'KLV' or chain ID
// Reload application state for new account
loadBalances(address)
loadTransactionHistory(address)
})
// User switches account in extension
// Event automatically firesSecurity Best Practices
Critical Security Warnings
NEVER EXPOSE PRIVATE KEYS
- Never hardcode private keys in source code
- Never commit private keys to version control
- Never log private keys to console or files
- Never share private keys via insecure channels
ALWAYS VERIFY BEFORE SIGNING
- Check recipient address before signing transactions
- Verify amounts and contract types
- Review transaction details carefully
- Be cautious of phishing attempts
USE EXTENSION MODE IN PRODUCTION
- Extension mode keeps keys secure in extension vault
- Private key mode should only be used for testing
- Never use private key mode with real funds in browsers
Secure Storage Recommendations
Node.js Environments
Environment Variables (Recommended):
# .env file (add to .gitignore!)
PRIVATE_KEY=your_private_key_here
PEM_PASSWORD=your_pem_password_hereimport 'dotenv/config'
const wallet = new NodeWallet(provider, process.env.PRIVATE_KEY)File Permissions for PEM Files:
# Restrict PEM file access (Unix/Linux/macOS)
chmod 600 wallet.pem
# Only owner can read/write
ls -la wallet.pem
# Output: -rw------- 1 user group 256 Jan 1 12:00 wallet.pemKey Management Services (Production):
// AWS Secrets Manager
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
const client = new SecretsManagerClient({ region: 'us-east-1' })
const response = await client.send(new GetSecretValueCommand({ SecretId: 'klever/private-key' }))
const privateKey = response.SecretString
const wallet = new NodeWallet(provider, privateKey)// HashiCorp Vault
import Vault from 'node-vault'
const vault = Vault({ endpoint: 'http://vault:8200' })
const secret = await vault.read('secret/data/klever')
const privateKey = secret.data.data.privateKey
const wallet = new NodeWallet(provider, privateKey)Browser Environments
Extension Mode (Recommended):
// Keys never enter your application code
const wallet = new BrowserWallet(provider) // No private key needed
await wallet.connect() // Extension manages keys securelyPrivate Key Mode (Testing Only):
// ⚠️ WARNING: Only for testing/development
// Keys are in browser memory - vulnerable to XSS attacks
// Option 1: Session Storage (cleared on tab close)
sessionStorage.setItem('test-key', testPrivateKey)
const key = sessionStorage.getItem('test-key')
const wallet = new BrowserWallet(provider, { privateKey: key })
// Clear after use
await wallet.disconnect(true)
sessionStorage.removeItem('test-key')
// Option 2: Never store - prompt user each time
const key = prompt('Enter private key (TESTING ONLY):')
const wallet = new BrowserWallet(provider, { privateKey: key })React Native (Coming Soon)
// Secure storage for mobile apps
import * as SecureStore from 'expo-secure-store'
// Save encrypted
await SecureStore.setItemAsync('privateKey', privateKey)
// Load when needed
const key = await SecureStore.getItemAsync('privateKey')
const wallet = new ReactNativeWallet(provider, key)PEM File Encryption
Creating Encrypted PEM Files:
# Use Klever CLI or tools to generate encrypted PEM
klever-cli wallet create --encrypt --password "strong-password-123"Loading Encrypted PEMs:
import { cryptoProvider } from '@klever/connect-crypto'
// Strong password requirements:
// - Minimum 12 characters
// - Mix of uppercase, lowercase, numbers, symbols
// - No dictionary words
// - Use password manager to generate
const pemResult = await cryptoProvider.importPrivateKeyFromPemFile('./wallet.pem', {
password: process.env.PEM_PASSWORD, // Store password securely
})
const wallet = new NodeWallet(provider, pemResult.toHex())Password Security:
- Use password manager (1Password, LastPass, Bitwarden)
- Minimum 12 characters, 16+ recommended
- Never reuse passwords across systems
- Store passwords in environment variables or vaults
- Never commit passwords to version control
Extension Wallet Benefits
Why Extension Mode is More Secure:
- Private keys never leave extension - Your dApp code never sees the keys
- User confirmation required - Every transaction needs user approval
- Phishing protection - Extension shows transaction details clearly
- Hardware wallet support - Extension can integrate with Ledger/Trezor
- Account isolation - Each dApp has isolated storage
- Auto-lock - Extension locks after inactivity
// Extension mode - maximum security
const wallet = new BrowserWallet(provider)
await wallet.connect()
// Private key never enters your code
// User confirms every transaction
// Extension can integrate with hardware walletsAdvanced Usage
WalletFactory for Environment Detection
import { WalletFactory } from '@klever/connect-wallet'
const factory = new WalletFactory()
// Same code works in Node.js and Browser
const wallet = await factory.createWallet({
privateKey: process.env.PRIVATE_KEY, // Optional in browser
network: 'mainnet',
})
await wallet.connect()
// Check wallet type
if (wallet.constructor.name === 'NodeWallet') {
console.log('Running in Node.js')
} else if (wallet.constructor.name === 'BrowserWallet') {
console.log('Running in Browser')
}Dual-Mode BrowserWallet
BrowserWallet automatically chooses mode based on configuration:
// Extension mode (no config)
const extensionWallet = new BrowserWallet(provider)
await extensionWallet.connect() // Uses extension
// Private key mode (with privateKey)
const pkWallet = new BrowserWallet(provider, {
privateKey: '0x123...',
})
await pkWallet.connect() // No extension needed
// PEM mode (with pemContent)
const pemWallet = new BrowserWallet(provider, {
pemContent: pemFileContent,
pemPassword: 'optional-password',
})
await pemWallet.connect()Event Handling
Available Events:
connect- Wallet successfully connecteddisconnect- Wallet disconnected or user switched chainsaccountChanged- User switched accounts (extension only)
const wallet = new BrowserWallet(provider)
wallet.on('connect', ({ address }) => {
console.log('Connected:', address)
// Initialize app, load balances, etc.
})
wallet.on('disconnect', () => {
console.log('Disconnected')
// Show connection UI, clear state, etc.
})
wallet.on('accountChanged', ({ address, chain }) => {
console.log('Account changed:', address)
// Reload data for new account
})
// Remove specific listener
const handler = ({ address }) => console.log(address)
wallet.on('accountChanged', handler)
wallet.off('accountChanged', handler)
// Remove all listeners for an event
wallet.removeAllListeners('accountChanged')
// Remove all listeners
wallet.removeAllListeners()Multi-Signature Workflows
import { TransactionBuilder } from '@klever/connect-transactions'
// Build transaction
const builder = new TransactionBuilder(provider)
const tx = await builder
.transfer({ receiver: 'klv1...', amount: '1000000' })
.sender(wallet1.address)
.build()
// Sign with multiple wallets
await wallet1.signTransaction(tx)
await wallet2.signTransaction(tx)
await wallet3.signTransaction(tx)
// Broadcast multi-signed transaction
const hash = await wallet1.broadcastTransaction(tx)Batch Transactions
import { TXType } from '@klever/connect-core'
const wallet = new BrowserWallet(provider)
await wallet.connect()
// Build multiple transactions
const tx1 = await wallet.buildTransaction([
{ contractType: TXType.Transfer, receiver: 'klv1...', amount: '1000000' },
])
const tx2 = await wallet.buildTransaction([{ contractType: TXType.Claim, claimType: 0 }])
// Sign all
await wallet.signTransaction(tx1)
await wallet.signTransaction(tx2)
// Broadcast as batch
const hashes = await wallet.broadcastTransactions([tx1, tx2])
console.log('Transaction hashes:', hashes)API Reference
BaseWallet (Abstract)
Base class for all wallet implementations. Do not instantiate directly.
Properties:
address: string- Wallet address (bech32 format)publicKey: string- Public key (hex format)provider: IProvider- Provider instance
Methods:
connect(): Promise<void>- Connect to walletdisconnect(clearPrivateKey?: boolean): Promise<void>- Disconnect from walletisConnected(): boolean- Check connection statussignMessage(message: string | Uint8Array): Promise<Signature>- Sign messagesignTransaction(tx: Transaction): Promise<Transaction>- Sign transactionverifyMessage(message: string | Uint8Array, signature: Signature | string): Promise<boolean>- Verify signaturegetBalance(): Promise<bigint>- Get wallet balancegetNonce(): Promise<number>- Get current noncebroadcastTransaction(tx: Transaction): Promise<TransactionHash>- Broadcast single transactionbroadcastTransactions(txs: Transaction[]): Promise<TransactionHash[]>- Broadcast multiple transactionssendTransaction(contract: ContractRequestData): Promise<TransactionSubmitResult>- Build, sign, and broadcasttransfer(params: TransferRequest): Promise<TransactionSubmitResult>- Transfer tokenson(event: WalletEvent, handler: WalletEventHandler): void- Register event listeneroff(event: WalletEvent, handler: WalletEventHandler): void- Remove event listenerremoveAllListeners(event?: WalletEvent): void- Remove all listeners
NodeWallet
Node.js wallet implementation with private key support.
Constructor:
new NodeWallet(provider: IProvider, privateKey?: string)Parameters:
provider- Provider instance for blockchain communicationprivateKey- Optional private key as hex string (can be set later)
Static Methods:
static generate(provider: IProvider): Promise<NodeWallet>- Generate new random wallet
Methods:
setPrivateKey(privateKey: string): void- Set/change private key (only when disconnected)- All methods from BaseWallet
Example:
const wallet = new NodeWallet(provider, privateKey)
await wallet.connect()
// Or generate new
const newWallet = await NodeWallet.generate(provider)
await newWallet.connect()BrowserWallet
Browser wallet implementation with extension and private key modes.
Constructor:
new BrowserWallet(provider: IProvider, config?: WalletConfig)Parameters:
provider- Provider instanceconfig- Optional wallet configurationprivateKey?: string- Private key for private key modepemContent?: string- PEM file contentpemPassword?: string- Password for encrypted PEM
Additional Methods (Extension Mode):
buildTransaction(contracts: ContractRequestData[], txData?: string[], options?: { nonce?: number; kdaFee?: string }): Promise<Transaction>- Build unsigned transactionbuildTransfer(to: string, amount: string | number, token?: string): Promise<Transaction>- Build and sign transfergetExtensionProvider(): NetworkURI- Get extension's provider configupdateProvider(provider: NetworkURI): void- Update extension's providercreateAccount(): Promise<{ privateKey: string; address: string }>- Create new account in extensiongetAccount(address?: string): Promise<AccountInfo>- Get account informationparsePemFileData(pemData: string): Promise<{ privateKey: string; address: string }>- Parse PEM via extensionsetWalletAddress(address: string): Promise<void>- Set wallet address in extensionsetPrivateKey(privateKey: string): Promise<void>- Set private key in extensionvalidateSignature(payload: string): Promise<{ isValid: boolean; signer?: string }>- Validate signature
Example:
// Extension mode
const wallet = new BrowserWallet(provider)
await wallet.connect()
// Private key mode
const wallet = new BrowserWallet(provider, { privateKey: '0x123...' })
await wallet.connect()WalletFactory
Factory for creating environment-appropriate wallets.
Constructor:
new WalletFactory(provider?: IProvider)Methods:
createWallet(config?: WalletConfig): Promise<Wallet>- Create wallet for current environment
Convenience Function:
createWallet(config?: WalletConfig): Promise<Wallet>Example:
const factory = new WalletFactory(provider)
const wallet = await factory.createWallet({
privateKey: process.env.PRIVATE_KEY,
})
// Or use convenience function
const wallet = await createWallet({
network: 'testnet',
privateKey: process.env.PRIVATE_KEY,
})Types
WalletConfig:
interface WalletConfig {
privateKey?: string // Private key hex string
pemContent?: string // PEM file content
pemPassword?: string // PEM password
network?: Network // Network to connect to
provider?: IProvider // Custom provider
}TransferRequest:
interface TransferRequest {
receiver: string // Recipient address
amount: string | number // Amount in smallest units
kda?: string // Optional token ID (defaults to KLV)
}WalletEvent:
type WalletEvent = 'connect' | 'disconnect' | 'accountChanged'WalletEventHandler:
type WalletEventHandler = (data: unknown) => voidTroubleshooting
Extension Not Found
Problem: Klever Extension not found error when connecting.
Solutions:
- Install Klever Extension from https://klever.io/extension
- Check if extension is enabled in browser
- Refresh page after installing extension
- Use private key mode for testing without extension
// Check before connecting
if (typeof window.kleverWeb === 'undefined') {
console.error('Extension not installed')
} else {
await wallet.connect()
}No Wallet Address in Extension
Problem: No wallet address set in Klever Extension error.
Solutions:
- Open Klever Extension
- Create or import a wallet
- Ensure wallet is unlocked
- Select an account if multiple exist
Private Key Format Invalid
Problem: Invalid private key error when creating NodeWallet.
Solutions:
- Ensure private key is hex format (64 characters)
- Remove
0xprefix if present - Check for whitespace or newlines
// Correct format
const privateKey = 'a1b2c3d4...' // 64 hex characters
// Common mistakes
const wrong1 = '0xa1b2c3d4...' // ❌ Remove 0x prefix
const wrong2 = 'a1b2c3d4\n' // ❌ Remove newlinesPEM Decryption Failed
Problem: Failed to decrypt PEM block error.
Solutions:
- Verify password is correct
- Check PEM file is not corrupted
- Ensure PEM file is in correct format
- Try with different password encoding
// Trim password to remove whitespace
const password = process.env.PEM_PASSWORD?.trim()
const pemResult = await cryptoProvider.importPrivateKeyFromPemFile('./wallet.pem', {
password,
})Transaction Signing Failed
Problem: Transaction signing fails or is rejected.
Solutions:
- Extension Mode:
- User may have rejected in extension UI
- Extension may be locked - user needs to unlock
- Check extension is on correct network
- Private Key Mode:
- Ensure wallet is connected
- Verify private key is valid
- Check transaction is properly built
try {
const signedTx = await wallet.signTransaction(tx)
} catch (error) {
if (error.message.includes('rejected')) {
console.log('User rejected transaction')
} else if (error.message.includes('not connected')) {
await wallet.connect()
}
}Account Changed Events Not Firing
Problem: accountChanged events not received.
Solutions:
- Ensure using BrowserWallet in extension mode
- Check KleverHub is initialized (requires newer extension version)
- Event only fires for KLV chain switches
- Events are debounced (100ms delay)
// Check if hub is available
if (window.kleverHub) {
wallet.on('accountChanged', ({ address }) => {
console.log('Account changed:', address)
})
} else {
console.log('KleverHub not available - using legacy extension')
}Cross-Origin Errors
Problem: CORS errors when connecting to provider.
Solutions:
- Configure provider with correct CORS headers
- Use proxy for development
- Ensure API endpoint allows browser requests
const provider = new KleverProvider({
network: 'mainnet',
// Or custom node with CORS enabled
nodeUrl: 'https://your-node-with-cors.com',
})Memory Leaks with Event Listeners
Problem: Application slows down with many wallet instances.
Solution: Always clean up event listeners when unmounting.
// React example
useEffect(() => {
const handler = ({ address }) => setAddress(address)
wallet.on('accountChanged', handler)
return () => {
wallet.off('accountChanged', handler)
}
}, [wallet])
// Or remove all
wallet.removeAllListeners()Related Packages
- @klever/connect-core - Core types, errors, and constants
- @klever/connect-crypto - Cryptographic operations and key management
- @klever/connect-provider - Blockchain communication and RPC
- @klever/connect-transactions - Transaction building and encoding
- @klever/connect-react - React hooks and components for wallet integration
Contributing
Contributions welcome! Please read the contributing guidelines first.
License
MIT
