Bitcoin Wallets
BOB Gateway requires Bitcoin wallet integration to allow users to sign Bitcoin transactions. This guide covers the different wallet integration options available for your application.
Wallet Integration Optionsโ
Reown AppKit (Recommended)โ
Reown AppKit provides a unified interface for Bitcoin wallet connections with broad wallet support.
Installation:
- npm
- Yarn
- pnpm
- Bun
npm install @reown/appkit @reown/appkit-adapter-bitcoin
yarn add @reown/appkit @reown/appkit-adapter-bitcoin
pnpm add @reown/appkit @reown/appkit-adapter-bitcoin
bun add @reown/appkit @reown/appkit-adapter-bitcoin
Usage with Gateway SDK:
import { useAppKitProvider, useAppKitAccount } from '@reown/appkit/react';
import type { BitcoinConnector } from "@reown/appkit-adapter-bitcoin";
import { ReownWalletAdapter } from '@gobob/bob-sdk';
const { walletProvider } = useAppKitProvider<BitcoinConnector>('bip122');
const { address: btcAddress } = useAppKitAccount();
const txId = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner: new ReownWalletAdapter(walletProvider, btcAddress),
});
sats-wagmiโ
sats-wagmi is a library with Bitcoin wallet connectors that abstracts wallet integration complexity. It provides React hooks similar to the EVM wagmi library.
Supported Wallets:
- Metamask Snap
- Unisat
- Leather
- Xverse
- Bitget
- OKX Wallet
Features:
- React hooks for wallet management
- PSBT signing
- BTC transaction sending
Installation:
- npm
- Yarn
- pnpm
- Bun
npm install @gobob/sats-wagmi
yarn add @gobob/sats-wagmi
pnpm add @gobob/sats-wagmi
bun add @gobob/sats-wagmi
Usage with Gateway SDK:
import { Network, XverseConnector } from '@gobob/sats-wagmi';
const btcSigner = new XverseConnector(Network.mainnet);
const txId = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner,
});
Other Wallet Optionsโ
OKX Wallet Direct Integrationโ
For OKX wallet, you can use their direct send API:
import { OkxWalletAdapter } from '@gobob/bob-sdk';
const txId = await gatewaySDK.executeQuote({
quote,
walletClient,
publicClient,
btcSigner: new OkxWalletAdapter(window.okxwallet.bitcoin),
});
Dynamic.xyzโ
Dynamic provides Bitcoin wallet support. See their PSBT signing guide for implementation details.
UI Integration Guideโ
sats-wagmi provides the most comprehensive React integration for Bitcoin wallets.
Installationโ
- npm
- Yarn
- pnpm
- Bun
npm install @gobob/sats-wagmi
yarn add @gobob/sats-wagmi
pnpm add @gobob/sats-wagmi
bun add @gobob/sats-wagmi
Connect Walletโ
1. Wrap App in Context Providerโ
To start, we will need to wrap our React App with Context so that our application is aware of sats-wagmi & React Query's reactive state and in-memory caching:
// 1. Import modules
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { SatsWagmiConfig } from "@gobob/sats-wagmi";
// 2. Set up a React Query client.
const queryClient = new QueryClient()
function App() {
// 3. Wrap app with sats-wagmi and React Query context.
return (
<QueryClientProvider client={queryClient}>
<SatsWagmiConfig network="testnet" queryClient={queryClient}>
{/** ... */}
</SatsWagmiConfig>
</QueryClientProvider>
)
}
2. Display Wallet Optionsโ
After that, we will create a WalletOptions
component that will display our connectors. This will allow users to select a wallet and connect.
Below, we are rendering a list of connectors
retrieved from useConnect
. When the user clicks on a connector, the connect
function will connect the users' wallet.
import * as React from 'react'
import { useConnect, SatsConnector } from "@gobob/sats-wagmi";
export function WalletOptions() {
const { connectors, connect } = useConnect()
return connectors.map((connector) => (
<button key={connector.name} onClick={() => connect({ connector })}>
{connector.name}
</button>
))
}
3. Display Connected Accountโ
Lastly, if an account is connected, we want to show the connected address.
We are utilizing useAccount
to extract the account and useDisconnect
to show a "Disconnect" button so a user can disconnect their wallet.
import { useAccount, useDisconnect } from "@gobob/sats-wagmi";
function Account() {
const { address } = useAccount()
const { disconnect } = useDisconnect()
return (
<div>
<p>Address: {address}</p>
<button onClick={() => disconnect()}>Disconnect</button>
</div>
);
}
Send Transactionโ
Create your SendTransaction
component that will contain the send transaction logic.
import type { FormEvent } from 'react';
import { type Hex, parseUnits } from 'viem';
import { useSendTransaction } from "@gobob/sats-wagmi";
function SendTransaction() {
const { data: hash, error, isPending, sendTransaction } = useSendTransaction();
async function submit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const to = formData.get('address') as Hex;
const value = formData.get('value') as string;
sendTransaction({ to, value: parseUnits(value, 8) });
}
const { isLoading: isConfirming, isSuccess: isConfirmed } =
useWaitForTransactionReceipt({
hash,
})
return (
<div>
<h2>Send Transaction</h2>
<form onSubmit={submit}>
<input required name='address' placeholder='Address' />
<input required name='value' placeholder='Amount (BTC)' step='0.00000001' type='number' />
<button disabled={isPending} type='submit'>
{isPending ? 'Confirming...' : 'Send'}
</button>
</form>
{hash && <div>Transaction Hash: {hash}</div>}
{isConfirming && 'Waiting for confirmation...'}
{isConfirmed && 'Transaction confirmed.'}
{error && <div>Error: {error.message}</div>}
</div>
);
}
Gateway Integration Hookโ
sats-wagmi provides a convenient hook for Gateway transactions:
import { useSendGatewayTransaction } from '@gobob/sats-wagmi';
function GatewayExample() {
const {
mutate: sendGatewayTransaction,
data: txHash,
error,
isPending
} = useSendGatewayTransaction();
const handleGatewayTransaction = async () => {
const quote = await gatewaySDK.getQuote({
fromChain: 'bitcoin',
fromToken: 'BTC',
fromUserAddress: 'bc1q...',
toChain: 'bob',
toUserAddress: '0x...',
toToken: 'wBTC',
amount: parseBtc("0.1"),
gasRefill: parseEther("0.00001"),
});
sendGatewayTransaction({
gatewaySDK,
quote,
quoteParams: {
fromUserAddress: 'bc1q...',
// ... other params
}
});
};
return (
<div>
<button
onClick={handleGatewayTransaction}
disabled={isPending}
>
{isPending ? 'Processing...' : 'Send Gateway Transaction'}
</button>
{txHash && <p>Transaction: {txHash}</p>}
{error && <p>Error: {error.message}</p>}
</div>
);
}