KeepKey Hardware Wallet Integration
KeepKey is a premium hardware wallet that provides secure cryptocurrency storage with a large OLED display for transaction verification. SwapDK SDK v4 supports KeepKey devices across multiple blockchain networks through the KeepKey SDK integration.
Supported Chains
Section titled “Supported Chains”SwapDK supports KeepKey devices on these chains:
- EVM Compatible: Ethereum, Arbitrum, Avalanche, Base, BinanceSmartChain, Optimism, Polygon
- UTXO Chains: Bitcoin, Bitcoin Cash, Dash, Dogecoin, Litecoin
- Cosmos Ecosystem: Cosmos, THORChain, Maya
- Other Chains: Ripple
Installation and Setup
Section titled “Installation and Setup”1. Hardware Requirements
Section titled “1. Hardware Requirements”- KeepKey hardware wallet device
- USB connection
- KeepKey Desktop application installed
2. Install KeepKey Desktop
Section titled “2. Install KeepKey Desktop”- Download KeepKey Desktop from keepkey.com
- Install and run the desktop application
- The desktop app provides the bridge service required for web integration
- Ensure the KeepKey Desktop is running in the background
3. Device Setup
Section titled “3. Device Setup”Using KeepKey Desktop:
- Initialize your device with a recovery seed
- Set up a PIN for device access
- Update to the latest firmware
- Enable supported cryptocurrencies
4. Browser Requirements
Section titled “4. Browser Requirements”KeepKey works with modern browsers through the desktop bridge:
- Chrome/Chromium: Full support
- Firefox: Full support
- Safari: Full support
- Edge: Full support
SwapDK Integration
Section titled “SwapDK Integration”Configuration Setup
Section titled “Configuration Setup”Before using KeepKey, you need to configure the integration settings:
import { SwapKit, keepkeyWallet, Chain } from "@swapdk/sdk";
const swapDK = SwapKit({ config: { apiKeys: { swapKit: "your-api-key", keepKey: "your-keepkey-api-key", }, integrations: { keepKey: {
serviceName: "SwapKit", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet },});Basic Connection
Section titled “Basic Connection”Single Chain Connection
Section titled “Single Chain Connection”import { SwapKit, keepkeyWallet, Chain, NetworkDerivationPath } from "@swapdk/sdk";
const swapDK = SwapKit({ config: { integrations: { keepKey: { serviceName: "My DApp", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet },});
async function connectKeepKeyBitcoin() { try {
await swapDK.connectKeepkey([Chain.Bitcoin]);
const address = swapDK.getAddress(Chain.Bitcoin); const balance = await swapDK.getBalance(Chain.Bitcoin, true);
console.log("Bitcoin address:", address); console.log("Balance:", balance);
return { success: true, address, balance }; } catch (error) { console.error("Failed to connect KeepKey:", error); return { success: false, error }; }}Multi-Chain Connection
Section titled “Multi-Chain Connection”import { SwapKit, keepkeyWallet, Chain, NetworkDerivationPath, type DerivationPathArray } from "@swapdk/sdk";
const swapDK = SwapKit({ config: { integrations: { keepKey: { serviceName: "Multi-Chain DApp", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet },});
async function connectMultipleChains() { const chains = [Chain.Bitcoin, Chain.Ethereum, Chain.Cosmos];
try {
await swapDK.connectKeepkey(chains);
const addresses = {}; for (const chain of chains) { addresses[chain] = swapDK.getAddress(chain); console.log(`${chain} address:`, addresses[chain]); }
return { success: true, addresses }; } catch (error) { console.error("Multi-chain connection failed:", error); return { success: false, error }; }}Custom Derivation Paths
Section titled “Custom Derivation Paths”import { SwapKit, keepkeyWallet, Chain, type DerivationPathArray,} from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet },});
async function connectWithCustomPaths() { const derivationPaths: Record<Chain, DerivationPathArray> = { [Chain.Bitcoin]: [84, 0, 0, 0, 0], [Chain.Ethereum]: [44, 60, 0, 0, 0], [Chain.Cosmos]: [44, 118, 0, 0, 0], };
const chains = [Chain.Bitcoin, Chain.Ethereum, Chain.Cosmos];
try { await swapDK.connectKeepkey(chains, derivationPaths);
const results = chains.map((chain) => ({ chain, address: swapDK.getAddress(chain), derivationPath: derivationPaths[chain], }));
console.log("Connected chains:", results); return { success: true, connections: results }; } catch (error) { return { success: false, error }; }}Transaction Examples
Section titled “Transaction Examples”Bitcoin Transaction
Section titled “Bitcoin Transaction”import { SwapKit, keepkeyWallet, Chain, AssetValue } from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet },});
await swapDK.connectKeepkey([Chain.Bitcoin]);
async function sendBitcoin() { const recipient = "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"; const amount = AssetValue.fromChainOrSignature("BTC.BTC", 0.001);
try { console.log("Preparing Bitcoin transaction..."); console.log("Amount:", amount.toSignificant(6), "BTC"); console.log("Recipient:", recipient);
const txHash = await swapDK.transfer({ assetValue: amount, recipient, memo: "KeepKey Transaction", });
console.log("✅ Transaction sent:", txHash); return txHash; } catch (error) { console.error("❌ Bitcoin transaction failed:", error); throw error; }}Ethereum Transaction
Section titled “Ethereum Transaction”import { SwapKit, keepkeyWallet, Chain, AssetValue } from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet },});
await swapDK.connectKeepkey([Chain.Ethereum]);
async function sendEthereum() { const recipient = "0x742d35Cc6632C0532c718C5E6F99d7E89b12c9bC"; const amount = AssetValue.fromChainOrSignature("ETH.ETH", 0.01);
try { const txHash = await swapDK.transfer({ assetValue: amount, recipient, });
console.log("ETH transaction sent:", txHash); return txHash; } catch (error) { console.error("ETH transaction failed:", error); throw error; }}
async function sendERC20Token() { const recipient = "0x742d35Cc6632C0532c718C5E6F99d7E89b12c9bC"; const amount = AssetValue.fromChainOrSignature( "ETH.USDC-0xA0B86A33E6441E89D5E4C4EDF4C8DF4C0E6C62F6", 100 );
try { const txHash = await swapDK.transfer({ assetValue: amount, recipient, });
console.log("USDC transaction sent:", txHash); return txHash; } catch (error) { console.error("USDC transaction failed:", error); throw error; }}Cosmos Transaction
Section titled “Cosmos Transaction”import { SwapKit, keepkeyWallet, Chain, AssetValue } from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet },});
await swapDK.connectKeepkey([Chain.Cosmos]);
async function sendCosmos() { const recipient = "cosmos1xy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"; const amount = AssetValue.fromChainOrSignature("GAIA.ATOM", 1);
try { const txHash = await swapDK.transfer({ assetValue: amount, recipient, memo: "KeepKey Cosmos transaction", });
console.log("ATOM transaction sent:", txHash); return txHash; } catch (error) { console.error("ATOM transaction failed:", error); throw error; }}THORChain Transaction
Section titled “THORChain Transaction”import { SwapKit, keepkeyWallet, Chain, AssetValue } from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet },});
await swapDK.connectKeepkey([Chain.THORChain]);
async function sendThorchain() { const recipient = "thor1xy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"; const amount = AssetValue.fromChainOrSignature("THOR.RUNE", 10);
try { const txHash = await swapDK.transfer({ assetValue: amount, recipient, memo: "KeepKey THORChain transaction", });
console.log("RUNE transaction sent:", txHash); return txHash; } catch (error) { console.error("RUNE transaction failed:", error); throw error; }}
async function depositToThorchain() { const amount = AssetValue.fromChainOrSignature("THOR.RUNE", 100); const memo = "ADD:BTC.BTC:bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh";
try { const wallet = await swapDK.getWalletWithBalance(Chain.THORChain); const txHash = await wallet.deposit({ assetValue: amount, memo, });
console.log("THORChain deposit sent:", txHash); return txHash; } catch (error) { console.error("THORChain deposit failed:", error); throw error; }}Chain-Specific Setup
Section titled “Chain-Specific Setup”EVM Chains Configuration
Section titled “EVM Chains Configuration”import { SwapKit, keepkeyWallet, Chain } from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet } });
async function setupEVMChains() { const evmChains = [ Chain.Ethereum, Chain.Arbitrum, Chain.Avalanche, Chain.Polygon, Chain.BinanceSmartChain, Chain.Optimism, Chain.Base, ];
try { await swapDK.connectKeepkey(evmChains);
const evmAddress = swapDK.getAddress(Chain.Ethereum); console.log("EVM address (same on all EVM chains):", evmAddress);
const balances = await Promise.all( evmChains.map(async (chain) => { const balance = await swapDK.getBalance(chain, true); return { chain, balance }; }) );
return { success: true, address: evmAddress, balances }; } catch (error) { return { success: false, error }; }}UTXO Chains Configuration
Section titled “UTXO Chains Configuration”import { SwapKit, keepkeyWallet, Chain, type DerivationPathArray,} from "@swapdk/sdk";
const swapDK = SwapKit({ wallets: { ...keepkeyWallet } });
async function setupUTXOChains() { const utxoChains = [ Chain.Bitcoin, Chain.Litecoin, Chain.Dogecoin, Chain.Dash, ];
const derivationPaths: Record<Chain, DerivationPathArray> = { [Chain.Bitcoin]: [84, 0, 0, 0, 0], [Chain.Litecoin]: [84, 2, 0, 0, 0], [Chain.Dogecoin]: [84, 3, 0, 0, 0], [Chain.Dash]: [84, 5, 0, 0, 0], };
try { await swapDK.connectKeepkey(utxoChains, derivationPaths);
const addresses = {}; for (const chain of utxoChains) { addresses[chain] = swapDK.getAddress(chain); console.log(`${chain} address:`, addresses[chain]); }
return { success: true, addresses }; } catch (error) { return { success: false, error }; }}Common Troubleshooting
Section titled “Common Troubleshooting”Connection Issues
Section titled “Connection Issues”import { SwapKit, keepkeyWallet, Chain } from "@swapdk/sdk";
async function diagnosticConnection() { try { console.log("🔍 Checking KeepKey Desktop availability...");
const isAvailable = await checkKeepkeyAvailability(); if (!isAvailable) { console.log("❌ KeepKey Desktop not running"); console.log("🔧 Troubleshooting steps:"); console.log("1. Install KeepKey Desktop from https://keepkey.com/desktop"); console.log("2. Launch KeepKey Desktop application"); console.log("3. Ensure it's running in the background"); return { success: false, error: "KeepKey Desktop not available" }; }
console.log("✅ KeepKey Desktop is available");
const swapDK = SwapKit({ config: { integrations: { keepKey: { serviceName: "Diagnostic Test", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet }, });
console.log("🔗 Attempting to connect to KeepKey..."); await swapDK.connectKeepkey([Chain.Bitcoin]);
const address = swapDK.getAddress(Chain.Bitcoin); console.log("✅ KeepKey connected successfully"); console.log("Address:", address);
return { success: true, address }; } catch (error) { console.error("❌ Connection failed:", error);
if (error.message.includes("Device not found")) { console.log("🔧 Device troubleshooting:"); console.log("1. Connect KeepKey via USB"); console.log("2. Unlock your KeepKey device"); console.log("3. Ensure KeepKey Desktop recognizes the device"); }
if (error.message.includes("Pairing")) { console.log("🔧 Pairing issues:"); console.log("1. Complete initial pairing in KeepKey Desktop"); console.log("2. Ensure pairing info is correctly configured"); }
return { success: false, error }; }}
async function checkKeepkeyAvailability(): Promise<boolean> { try { const response = await fetch("http://localhost:1646/"); return response.status === 200; } catch (error) { return false; }}Pairing Issues
Section titled “Pairing Issues”async function handleFirstTimePairing() { try { const swapDK = SwapKit({ config: { apiKeys: { keepKey: "1234", }, integrations: { keepKey: { serviceName: "My DApp", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet }, });
console.log("🔗 Initiating first-time pairing..."); console.log("📱 Please follow instructions on your KeepKey device");
await swapDK.connectKeepkey([Chain.Bitcoin]);
console.log("✅ Pairing successful!"); console.log("💾 Pairing information has been saved for future sessions");
return { success: true }; } catch (error) { console.error("❌ Pairing failed:", error);
if (error.message.includes("User cancelled")) { console.log("🔧 User cancelled pairing - please try again"); }
if (error.message.includes("Timeout")) { console.log("🔧 Pairing timed out - please ensure device is unlocked"); }
return { success: false, error }; }}Transaction Failures
Section titled “Transaction Failures”async function handleTransactionErrors() { try { const amount = AssetValue.fromChainOrSignature("BTC.BTC", 0.001); const txHash = await swapDK.transfer({ assetValue: amount, recipient: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh", }); return txHash; } catch (error) { if (error.message.includes("insufficient funds")) { console.error("❌ Insufficient balance for transaction + fees");
const balance = await swapDK.getBalance(Chain.Bitcoin, true); console.log("Current balance:", balance); }
if (error.message.includes("User rejected")) { console.error("❌ Transaction rejected on KeepKey device"); console.log("Please approve the transaction on your device screen"); }
if (error.message.includes("Device disconnected")) { console.error("❌ KeepKey disconnected during transaction"); console.log("Please reconnect your device and try again"); }
if (error.message.includes("Invalid fee")) { console.error("❌ Invalid fee rate"); console.log( "Fee rate may be too low or too high for current network conditions" ); }
throw error; }}Security Considerations
Section titled “Security Considerations”Best Practices
Section titled “Best Practices”const secureConfig = { config: { apiKeys: { keepKey: process.env.KEEPKEY_API_KEY, }, integrations: { keepKey: { serviceName: "Your App Name", serviceImageUrl: "https://example.com" }, },
rpcUrls: { [Chain.Ethereum]: "https://example.com" [Chain.Bitcoin]: "https://example.com" }, }, wallets: { ...keepkeyWallet },};
async function verifyAddressOnDevice() { const swapDK = SwapKit(secureConfig); await swapDK.connectKeepkey([Chain.Bitcoin]);
const address = swapDK.getAddress(Chain.Bitcoin);
console.log("Address from swapDK:", address); console.log("⚠️ Please verify this address on your KeepKey screen");
return address;}
async function secureTransaction() { const amount = AssetValue.fromChainOrSignature("BTC.BTC", 0.001); const recipient = "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh";
console.log("📋 Transaction Details:"); console.log("Amount:", amount.toSignificant(6), "BTC"); console.log("Recipient:", recipient); console.log("⚠️ Please verify these details on your KeepKey screen");
const txHash = await swapDK.transfer({ assetValue: amount, recipient, });
return txHash;}
async function secureErrorHandling() { try {
} catch (error) {
console.error("Transaction failed:", error.message);
throw new Error("Transaction failed. Please check your device and try again."); }}Network Security
Section titled “Network Security”const secureSwapDK = SwapKit({ config: { rpcUrls: {
[Chain.Ethereum]: "https://example.com" [Chain.Bitcoin]: "https://example.com" [Chain.Cosmos]: "https://example.com" },
allowInsecureConnection: false, }, wallets: { ...keepkeyWallet },});Advanced Usage
Section titled “Advanced Usage”Multi-Account Support
Section titled “Multi-Account Support”class KeepKeyAccountManager { private swapDK: any; private accounts: Map<number, Record<Chain, string>> = new Map();
constructor() { this.swapDK = SwapKit({ config: { integrations: { keepKey: { serviceName: "Multi-Account Manager", serviceImageUrl: "https://example.com" }, }, }, wallets: { ...keepkeyWallet }, }); }
async connectAccount(accountIndex: number, chains: Chain[]) {
const derivationPaths: Record<Chain, DerivationPathArray> = {};
for (const chain of chains) { switch (chain) { case Chain.Bitcoin: derivationPaths[chain] = [84, 0, accountIndex, 0, 0]; break; case Chain.Ethereum: derivationPaths[chain] = [44, 60, accountIndex, 0, 0]; break; case Chain.Cosmos: derivationPaths[chain] = [44, 118, accountIndex, 0, 0]; break; default: throw new Error(`Unsupported chain: ${chain}`); } }
await this.swapDK.connectKeepkey(chains, derivationPaths);
const accountAddresses: Record<Chain, string> = {}; for (const chain of chains) { accountAddresses[chain] = this.swapDK.getAddress(chain); }
this.accounts.set(accountIndex, accountAddresses); return accountAddresses; }
getAccount(accountIndex: number) { return this.accounts.get(accountIndex); }
getAllAccounts() { return Array.from(this.accounts.entries()); }}React Integration
Section titled “React Integration”import React, { useState, useEffect } from "react";import { SwapKit, keepkeyWallet, Chain, AssetValue } from "@swapdk/sdk";
interface KeepKeyWalletProps { onConnect: (addresses: Record<Chain, string>) => void; onError: (error: Error) => void;}
export function KeepKeyWallet({ onConnect, onError }: KeepKeyWalletProps) { const [isConnecting, setIsConnecting] = useState(false); const [isConnected, setIsConnected] = useState(false); const [addresses, setAddresses] = useState<Record<Chain, string>>({}); const [selectedChains, setSelectedChains] = useState<Chain[]>([ Chain.Bitcoin, ]);
const swapDK = SwapKit({ config: { integrations: { keepKey: { serviceName: "React DApp", serviceImageUrl: `${window.location.origin}/icon.png`, }, }, }, wallets: { ...keepkeyWallet }, });
const connectKeepKey = async () => { setIsConnecting(true);
try { await swapDK.connectKeepkey(selectedChains);
const connectedAddresses: Record<Chain, string> = {}; for (const chain of selectedChains) { connectedAddresses[chain] = swapDK.getAddress(chain); }
setAddresses(connectedAddresses); setIsConnected(true); onConnect(connectedAddresses); } catch (error) { onError(error as Error); } finally { setIsConnecting(false); } };
const disconnect = () => { swapDK.disconnectAll(); setIsConnected(false); setAddresses({}); };
const toggleChain = (chain: Chain) => { if (isConnected) return;
setSelectedChains((prev) => prev.includes(chain) ? prev.filter((c) => c !== chain) : [...prev, chain] ); };
return ( <div> <h3>KeepKey Wallet</h3>
{!isConnected ? ( <div> <h4>Select Chains:</h4> {[Chain.Bitcoin, Chain.Ethereum, Chain.Cosmos].map((chain) => ( <label key={chain}> <input type="checkbox" checked={selectedChains.includes(chain)} onChange={() => toggleChain(chain)} disabled={isConnecting} /> {chain} </label> ))}
<button onClick={connectKeepKey} disabled={isConnecting || selectedChains.length === 0} > {isConnecting ? "Connecting..." : "Connect KeepKey"} </button> </div> ) : ( <div> <h4>Connected Addresses:</h4> {Object.entries(addresses).map(([chain, address]) => ( <div key={chain}> <strong>{chain}:</strong> {address} </div> ))} <button onClick={disconnect}>Disconnect</button> </div> )} </div> );}This comprehensive guide covers all aspects of KeepKey integration with SwapDK SDK v4, including setup, usage, troubleshooting, and advanced features. The KeepKey integration provides secure hardware wallet functionality with support for multiple blockchain networks through a user-friendly interface.