Skip to main content

sats-wagmi - Reactive primitives for Bitcoin apps

sats-wagmi is a library with a handful of BTC wallet connectors, leaving aside the need of the developer to integrate each one individually. The library also exports useful React hooks that mimic the standard followed in the EVM wagmi library.

Features

  • BTC Wallet connectors:
    • Metamask Snap
    • Unisat
    • Leather
    • Xverse
    • Bitget
    • OKX Wallet
  • BTC functionality:
    • send BTC
    • sign PSBTs
  • React hooks

Installation

To use sats-wagmi, all you need to do is install @gobob/sats-wagmi:

npm install @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>
);
}