Bitcoin Wallets
Integrate Bitcoin wallet support for Gateway transactions
Overview
To use BOB Gateway, your application needs to integrate Bitcoin wallet support so users can sign Bitcoin transactions. This guide covers the most popular integration methods.
Recommended: Reown AppKit
Reown AppKit (formerly WalletConnect AppKit) provides a unified interface with broad wallet support including Unisat, Leather, Xverse, OKX, and more.
BOB has partnered with Reown to improve Bitcoin wallet support tooling for WalletConnect / Reown.
Installation
npm install @reown/appkit @reown/appkit-adapter-bitcoinSetup
import { createAppKit } from '@reown/appkit/react';
import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin';
import { bob } from 'viem/chains';
// 1. Get projectId from https://cloud.reown.com
const projectId = 'YOUR_PROJECT_ID';
// 2. Configure Bitcoin networks
const bitcoinAdapter = new BitcoinAdapter({
networks: [
{
chainId: 'bip122:000000000019d6689c085ae165831e93', // Bitcoin mainnet
name: 'Bitcoin',
currency: 'BTC',
explorerUrl: 'https://blockstream.info',
rpcUrl: 'https://blockstream.info/api',
},
],
});
// 3. Create AppKit instance
const metadata = {
name: 'Your App Name',
description: 'Your App Description',
url: 'https://yourapp.com',
icons: ['https://yourapp.com/icon.png'],
};
createAppKit({
adapters: [bitcoinAdapter],
networks: [bob],
metadata,
projectId,
features: {
analytics: true,
},
});Usage with Gateway SDK
import { useAppKitProvider, useAppKitAccount } from '@reown/appkit/react';
import { ReownWalletAdapter, GatewaySDK } from '@gobob/bob-sdk';
import type { BitcoinConnector } from '@reown/appkit-adapter-bitcoin';
function GatewayComponent() {
const { walletProvider } = useAppKitProvider<BitcoinConnector>('bip122');
const { address: btcAddress } = useAppKitAccount();
const gatewaySDK = new GatewaySDK();
const handleSwap = async () => {
// Get quote
const quote = await gatewaySDK.getQuote({
fromChain: 'bitcoin',
fromToken: '0x0000000000000000000000000000000000000000',
fromUserAddress: btcAddress,
refundAddress: btcAddress, // Bitcoin refund address required for V4 execution
toChain: 'bob',
toToken: '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c',
toUserAddress: evmAddress,
amount: parseBtc("0.1"),
});
// Execute with Reown adapter
const { order, tx } = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner: new ReownWalletAdapter(walletProvider, btcAddress),
});
console.log('Order:', order, 'Transaction:', tx);
};
return (
<div>
<appkit-button />
<button onClick={handleSwap}>Swap BTC</button>
</div>
);
}Alternative: sats-wagmi
sats-wagmi provides React hooks for Bitcoin wallets with support for Unisat, Leather, Xverse, and more.
Installation
npm install sats-wagmiSetup
import { SatsWagmiConfig, SatsConnectProvider } from 'sats-wagmi';
function App() {
return (
<SatsConnectProvider network="mainnet">
<SatsWagmiConfig>
<YourApp />
</SatsWagmiConfig>
</SatsConnectProvider>
);
}Usage
import { useConnect, useAccount, useSendBitcoin } from 'sats-wagmi';
import { GatewaySDK } from '@gobob/bob-sdk';
function GatewayComponent() {
const { connect, connectors } = useConnect();
const { address, isConnected } = useAccount();
const { sendBitcoin } = useSendBitcoin();
const handleSwap = async () => {
if (!isConnected) {
await connect({ connector: connectors[0] }); // Connect first
}
const gatewaySDK = new GatewaySDK();
const quote = await gatewaySDK.getQuote({
fromChain: 'bitcoin',
fromToken: '0x0000000000000000000000000000000000000000',
fromUserAddress: address,
refundAddress: address, // Bitcoin refund address required for V4 execution
toChain: 'bob',
toToken: '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c',
toUserAddress: evmAddress,
amount: parseBtc("0.1"),
});
// Create custom adapter
const btcSigner = {
sendBitcoin: async (params: any) => {
return sendBitcoin(params);
},
};
const { order, tx } = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner,
});
};
return <button onClick={handleSwap}>Connect & Swap</button>;
}OKX Wallet
Direct integration with OKX Wallet for users who prefer this wallet.
Installation
npm install @okxweb3/bitcoin-walletUsage
import { OkxWalletAdapter, GatewaySDK } from '@gobob/bob-sdk';
function GatewayComponent() {
const handleSwap = async () => {
// Check if OKX wallet is installed
if (!window.okxwallet) {
alert('Please install OKX Wallet');
return;
}
const gatewaySDK = new GatewaySDK();
const quote = await gatewaySDK.getQuote({
fromChain: 'bitcoin',
fromToken: '0x0000000000000000000000000000000000000000',
fromUserAddress: btcAddress,
refundAddress: btcAddress, // Bitcoin refund address required for V4 execution
toChain: 'bob',
toToken: '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c',
toUserAddress: evmAddress,
amount: parseBtc("0.1"),
});
const { order, tx } = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner: new OkxWalletAdapter(window.okxwallet),
});
};
return <button onClick={handleSwap}>Swap with OKX</button>;
}Custom Bitcoin Signer
Implement the BitcoinSigner interface for any Bitcoin wallet. Return finalized raw transaction hex from either method, not a txid or PSBT. Gateway validates and broadcasts it through V4 register-tx. Prefer a signing-only wallet method; if the wallet broadcasts, retrieve the raw hex before returning (as the built-in OKX adapter does).
import { BitcoinSigner } from '@gobob/bob-sdk';
class CustomWalletAdapter implements BitcoinSigner {
constructor(private wallet: any) {}
// Option 1: Implement sendBitcoin for wallets that handle transaction creation
async sendBitcoin(params: {
from: string;
to: string;
value: string; // BTC amount as string
opReturn?: string; // OP_RETURN data
}): Promise<string> {
// Build and sign without broadcasting; return raw transaction hex
const txHex = await this.wallet.signBitcoin({
to: params.to,
amount: params.value,
data: params.opReturn,
});
return txHex; // Return signed transaction hex
}
// Option 2: Implement signAllInputs for PSBT-based wallets
async signAllInputs(psbtHex: string): Promise<string> {
// Sign the PSBT using your wallet
const signedPsbt = await this.wallet.signPsbt(psbtHex);
// Finalize and extract transaction
const finalTx = await this.wallet.finalizePsbt(signedPsbt);
return finalTx; // Return signed transaction hex
}
}
// Usage
const btcSigner = new CustomWalletAdapter(yourWalletInstance);
const { order, tx } = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner,
});Dynamic.xyz Integration
Dynamic provides embedded wallet support including Bitcoin.
import { useDynamicContext } from '@dynamic-labs/sdk-react-core';
import { GatewaySDK } from '@gobob/bob-sdk';
function GatewayComponent() {
const { primaryWallet } = useDynamicContext();
const handleSwap = async () => {
if (!primaryWallet) return;
// Get Bitcoin address
const btcAddress = await primaryWallet.getAddress('bitcoin');
const gatewaySDK = new GatewaySDK();
const quote = await gatewaySDK.getQuote({
fromChain: 'bitcoin',
fromToken: '0x0000000000000000000000000000000000000000',
fromUserAddress: btcAddress,
refundAddress: btcAddress, // Bitcoin refund address required for V4 execution
toChain: 'bob',
toToken: '0x0555E30da8f98308EdB960aa94C0Db47230d2B9c',
toUserAddress: evmAddress,
amount: parseBtc("0.1"),
});
// Create adapter for Dynamic wallet
const btcSigner = {
sendBitcoin: async (params: any) => {
return primaryWallet.connector.signTransaction({
chain: 'bitcoin',
...params,
});
},
};
const { order, tx } = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner,
});
};
return <button onClick={handleSwap}>Swap</button>;
}Best Practices
Wallet Detection
Detect which wallets are installed and show appropriate connection options
Network Validation
Verify user is on Bitcoin mainnet (or testnet for testing)
Address Validation
Validate Bitcoin addresses before submitting quotes
Error Handling
Handle wallet rejection, insufficient funds, and network errors gracefully
User Feedback
Show clear transaction status and confirmation states
Wallet Comparison
| Wallet | Type | Mobile | Desktop | Integration Method |
|---|---|---|---|---|
| Reown AppKit | Multi-wallet | ✅ | ✅ | Recommended |
| OKX Wallet | Browser Extension | ✅ | ✅ | Direct |
| Unisat | Browser Extension | ❌ | ✅ | sats-wagmi |
| Leather | Browser Extension | ❌ | ✅ | sats-wagmi |
| Xverse | Mobile + Extension | ✅ | ✅ | sats-wagmi |
| Dynamic.xyz | Embedded | ✅ | ✅ | SDK |
Testing
Use staging to test your integration against the available routes:
import { GatewaySDK, STAGING_GATEWAY_BASE_URL } from '@gobob/bob-sdk';
const gatewaySDK = new GatewaySDK({ basePath: STAGING_GATEWAY_BASE_URL });
const routes = await gatewaySDK.getRoutes();Discover chains and tokens from getRoutes() before requesting a quote. Staging is an API environment; do not assume it uses Bitcoin testnet or BOB Sepolia. Use addresses and funds appropriate to the route's actual networks, and include a source-chain refundAddress before execution.