Skip to main content

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. Reown AppKit (formerly WalletConnect AppKit) provides a unified interface with broad wallet support including Unisat, Leather, Xverse, OKX, and more.

Installation

npm install @reown/appkit @reown/appkit-adapter-bitcoin

Setup

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(bob.id);

  const handleSwap = async () => {
    // Get quote
    const quote = await gatewaySDK.getQuote({
      fromChain: 'bitcoin',
      fromToken: 'BTC',
      fromUserAddress: btcAddress,
      toChain: 'bob',
      toToken: 'wBTC',
      toUserAddress: evmAddress,
      amount: parseBtc("0.1"),
    });

    // Execute with Reown adapter
    const txId = await gatewaySDK.executeQuote({
      quote,
      walletClient,
      publicClient,
      btcSigner: new ReownWalletAdapter(walletProvider, btcAddress),
    });
    
    console.log('Transaction:', txId);
  };

  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-wagmi

Setup

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(bob.id);
    
    const quote = await gatewaySDK.getQuote({
      fromChain: 'bitcoin',
      fromToken: 'BTC',
      fromUserAddress: address,
      toChain: 'bob',
      toToken: 'wBTC',
      toUserAddress: evmAddress,
      amount: parseBtc("0.1"),
    });

    // Create custom adapter
    const btcSigner = {
      sendBitcoin: async (params: any) => {
        return sendBitcoin(params);
      },
    };

    const txId = 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-wallet

Usage

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(bob.id);

    const quote = await gatewaySDK.getQuote({
      fromChain: 'bitcoin',
      fromToken: 'BTC',
      fromUserAddress: btcAddress,
      toChain: 'bob',
      toToken: 'wBTC',
      toUserAddress: evmAddress,
      amount: parseBtc("0.1"),
    });

    const txId = 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:
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> {
    // Use your wallet's API to create and broadcast transaction
    const txHex = await this.wallet.sendBitcoin({
      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 txId = 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(bob.id);
    
    const quote = await gatewaySDK.getQuote({
      fromChain: 'bitcoin',
      fromToken: 'BTC',
      fromUserAddress: btcAddress,
      toChain: 'bob',
      toToken: 'wBTC',
      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 txId = await gatewaySDK.executeQuote({
      quote,
      walletClient,
      publicClient,
      btcSigner,
    });
  };

  return <button onClick={handleSwap}>Swap</button>;
}

Best Practices

1

Wallet Detection

Detect which wallets are installed and show appropriate connection options
2

Network Validation

Verify user is on Bitcoin mainnet (or testnet for testing)
3

Address Validation

Validate Bitcoin addresses before submitting quotes
4

Error Handling

Handle wallet rejection, insufficient funds, and network errors gracefully
5

User Feedback

Show clear transaction status and confirmation states

Wallet Comparison

WalletTypeMobileDesktopIntegration Method
Reown AppKitMulti-walletRecommended
OKX WalletBrowser ExtensionDirect
UnisatBrowser Extensionsats-wagmi
LeatherBrowser Extensionsats-wagmi
XverseMobile + Extensionsats-wagmi
Dynamic.xyzEmbeddedSDK

Testing

Test your Bitcoin wallet integration on BOB Sepolia testnet:
import { bobSepolia } from 'viem/chains';

const gatewaySDK = new GatewaySDK(bobSepolia.id);

// Use Bitcoin testnet addresses (starting with tb1...)
const quote = await gatewaySDK.getQuote({
  fromChain: 'bitcoin-testnet',
  fromToken: 'BTC',
  fromUserAddress: 'tb1q...', // Testnet address
  // ... rest of params
});
Always test on testnet before deploying to mainnet. Use testnet BTC which has no real value.

Next Steps