npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

otx-btc-wallet-react

v0.1.0

Published

React hooks and components for otx-btc-wallet

Readme

otx-btc-wallet-react

React provider and hooks for the otx-btc-wallet library. Provides a complete set of hooks for connecting wallets, signing messages, signing PSBTs, and sending Bitcoin.

Installation

pnpm add otx-btc-wallet-react otx-btc-wallet-core otx-btc-wallet-connectors

Quick Start

1. Setup Provider

Wrap your app with BtcWalletProvider and pass a config created with createConfig():

import { createConfig } from 'otx-btc-wallet-core';
import { BtcWalletProvider } from 'otx-btc-wallet-react';
import { UnisatConnector, XverseConnector } from 'otx-btc-wallet-connectors';

const config = createConfig({
  connectors: [
    new UnisatConnector(),
    new XverseConnector(),
  ],
});

function App() {
  return (
    <BtcWalletProvider config={config}>
      <YourApp />
    </BtcWalletProvider>
  );
}

2. Use Hooks

import { useAccount, useConnect, useDisconnect } from 'otx-btc-wallet-react';

function WalletButton() {
  const { address, isConnected } = useAccount();
  const { connect, connectors, isLoading } = useConnect();
  const { disconnect } = useDisconnect();

  if (isConnected) {
    return (
      <div>
        <p>{address}</p>
        <button onClick={() => disconnect()}>Disconnect</button>
      </div>
    );
  }

  return (
    <div>
      {connectors.map((connector) => (
        <button
          key={connector.id}
          onClick={() => connect({ connector })}
          disabled={!connector.ready || isLoading}
        >
          {connector.name}
          {!connector.ready && ' (not installed)'}
        </button>
      ))}
    </div>
  );
}

Provider

BtcWalletProvider

Required wrapper component. Must be placed above any component that uses hooks.

import { BtcWalletProvider } from 'otx-btc-wallet-react';

<BtcWalletProvider config={config}>
  {children}
</BtcWalletProvider>

Props:

| Prop | Type | Description | |------|------|-------------| | config | ResolvedConfig | Config object from createConfig() | | children | ReactNode | Child components |

Behavior:

  • Provides the config context to all child hooks
  • Handles auto-reconnect on mount if autoConnect is enabled and a previous wallet session exists

Hooks

useConfig

Access the config object directly. Useful for advanced store operations.

import { useConfig } from 'otx-btc-wallet-react';

function Debug() {
  const config = useConfig();
  const state = config.store.getState();

  return <pre>{JSON.stringify(state, null, 2)}</pre>;
}

Returns: ResolvedConfig - The full config object including the Zustand store.


useAccount

Get the connected account information. Reactively updates when the account changes.

import { useAccount } from 'otx-btc-wallet-react';

function Account() {
  const {
    address,        // string | undefined
    publicKey,      // string | undefined
    addressType,    // AddressType | undefined ('legacy' | 'nested-segwit' | 'segwit' | 'taproot')
    account,        // WalletAccount | undefined
    connector,      // BitcoinConnector | undefined
    status,         // ConnectionStatus
    isConnected,    // boolean
    isConnecting,   // boolean
    isDisconnected, // boolean
    isReconnecting, // boolean
  } = useAccount();

  if (!isConnected) return <p>Not connected</p>;

  return (
    <div>
      <p>Address: {address}</p>
      <p>Type: {addressType}</p>
      <p>Public Key: {publicKey}</p>
    </div>
  );
}

Return Type: UseAccountReturn

| Field | Type | Description | |-------|------|-------------| | address | string \| undefined | Connected Bitcoin address | | publicKey | string \| undefined | Hex-encoded public key | | addressType | AddressType \| undefined | Address type | | account | WalletAccount \| undefined | Full account object | | connector | BitcoinConnector \| undefined | Active connector instance | | status | ConnectionStatus | 'connected' | 'connecting' | 'disconnected' | 'reconnecting' | | isConnected | boolean | true when status is 'connected' | | isConnecting | boolean | true when status is 'connecting' | | isDisconnected | boolean | true when status is 'disconnected' | | isReconnecting | boolean | true when status is 'reconnecting' |


useConnect

Connect to a wallet connector.

import { useConnect } from 'otx-btc-wallet-react';

function ConnectWallet() {
  const {
    connect,       // (args: ConnectArgs) => void
    connectAsync,  // (args: ConnectArgs) => Promise<WalletAccount>
    connectors,    // BitcoinConnector[]
    isLoading,     // boolean
    isSuccess,     // boolean
    isError,       // boolean
    error,         // Error | null
    reset,         // () => void
  } = useConnect();

  return (
    <div>
      {connectors.map((connector) => (
        <button
          key={connector.id}
          onClick={() => connect({ connector })}
          disabled={!connector.ready || isLoading}
        >
          {connector.name}
          {!connector.ready && ' (not installed)'}
        </button>
      ))}
      {isError && <p>Error: {error?.message}</p>}
    </div>
  );
}

Connect Args:

type ConnectArgs = {
  connector: BitcoinConnector; // The connector to use
  network?: BitcoinNetwork;    // Optional network override
};

Return Type: UseConnectReturn

| Field | Type | Description | |-------|------|-------------| | connect | (args: ConnectArgs) => void | Fire-and-forget connect | | connectAsync | (args: ConnectArgs) => Promise<WalletAccount> | Connect and await result | | connectors | BitcoinConnector[] | All registered connectors | | isLoading | boolean | Connection in progress | | isSuccess | boolean | Connection succeeded | | isError | boolean | Connection failed | | error | Error \| null | Error details | | reset | () => void | Reset loading/error/success state |

Async Usage:

const handleConnect = async () => {
  try {
    const account = await connectAsync({ connector, network: 'testnet' });
    console.log('Connected:', account.address);
  } catch (err) {
    console.error('Connection failed:', err);
  }
};

useDisconnect

Disconnect the current wallet.

import { useDisconnect } from 'otx-btc-wallet-react';

function DisconnectButton() {
  const {
    disconnect,      // () => void
    disconnectAsync, // () => Promise<void>
    isLoading,       // boolean
    isSuccess,       // boolean
    isError,         // boolean
    error,           // Error | null
  } = useDisconnect();

  return (
    <button onClick={() => disconnect()} disabled={isLoading}>
      Disconnect
    </button>
  );
}

Return Type: UseDisconnectReturn

| Field | Type | Description | |-------|------|-------------| | disconnect | () => void | Fire-and-forget disconnect | | disconnectAsync | () => Promise<void> | Disconnect and await completion | | isLoading | boolean | Disconnect in progress | | isSuccess | boolean | Disconnect succeeded | | isError | boolean | Disconnect failed | | error | Error \| null | Error details |


useNetwork

Get the current Bitcoin network.

import { useNetwork } from 'otx-btc-wallet-react';

function NetworkInfo() {
  const { network } = useNetwork();
  // 'mainnet' | 'testnet' | 'testnet4' | 'signet'

  return <p>Network: {network}</p>;
}

Return Type: UseNetworkReturn

| Field | Type | Description | |-------|------|-------------| | network | BitcoinNetwork | Current Bitcoin network |


useSignMessage

Sign a text message with the connected wallet.

import { useSignMessage } from 'otx-btc-wallet-react';

function SignMessage() {
  const {
    signMessage,      // (args: { message: string }) => void
    signMessageAsync, // (args: { message: string }) => Promise<string>
    data,             // string | undefined (signature)
    isLoading,        // boolean
    isSuccess,        // boolean
    isError,          // boolean
    error,            // Error | null
    reset,            // () => void
  } = useSignMessage();

  return (
    <div>
      <button
        onClick={() => signMessage({ message: 'Hello Bitcoin!' })}
        disabled={isLoading}
      >
        Sign Message
      </button>
      {data && <p>Signature: {data}</p>}
      {isError && <p>Error: {error?.message}</p>}
    </div>
  );
}

Return Type: UseSignMessageReturn

| Field | Type | Description | |-------|------|-------------| | signMessage | (args: { message: string }) => void | Fire-and-forget sign | | signMessageAsync | (args: { message: string }) => Promise<string> | Sign and await signature | | data | string \| undefined | The resulting signature | | isLoading | boolean | Signing in progress | | isSuccess | boolean | Signing succeeded | | isError | boolean | Signing failed | | error | Error \| null | Error details | | reset | () => void | Reset state |


useSignPsbt

Sign a single PSBT (Partially Signed Bitcoin Transaction).

import { useSignPsbt } from 'otx-btc-wallet-react';

function SignTransaction() {
  const {
    signPsbt,      // (args) => void
    signPsbtAsync, // (args) => Promise<string>
    data,          // string | undefined (signed PSBT hex)
    isLoading,
    isSuccess,
    isError,
    error,
    reset,
  } = useSignPsbt();

  const handleSign = () => {
    signPsbt({
      psbt: '70736274ff01...', // PSBT hex string
      options: {
        autoFinalize: true,
        broadcast: false,
        toSignInputs: [
          { index: 0, address: 'bc1q...' },
        ],
      },
    });
  };

  return (
    <div>
      <button onClick={handleSign} disabled={isLoading}>
        Sign PSBT
      </button>
      {data && <p>Signed: {data}</p>}
    </div>
  );
}

Return Type: UseSignPsbtReturn

| Field | Type | Description | |-------|------|-------------| | signPsbt | (args: { psbt: string; options?: SignPsbtOptions }) => void | Fire-and-forget sign | | signPsbtAsync | (args: { psbt: string; options?: SignPsbtOptions }) => Promise<string> | Sign and await result | | data | string \| undefined | Signed PSBT hex | | isLoading | boolean | Signing in progress | | isSuccess | boolean | Signing succeeded | | isError | boolean | Signing failed | | error | Error \| null | Error details | | reset | () => void | Reset state |


useSignPsbts

Sign multiple PSBTs in a batch. Not all wallets support this (check isSupported).

import { useSignPsbts } from 'otx-btc-wallet-react';

function BatchSign() {
  const {
    signPsbts,      // (args) => void
    signPsbtsAsync, // (args) => Promise<string[]>
    data,           // string[] | undefined (signed PSBT hex array)
    isLoading,
    isSuccess,
    isError,
    error,
    isSupported,    // boolean - does the wallet support batch signing?
    reset,
  } = useSignPsbts();

  if (!isSupported) {
    return <p>This wallet does not support batch signing.</p>;
  }

  return (
    <button
      onClick={() => signPsbts({
        psbts: [psbt1Hex, psbt2Hex],
        options: { autoFinalize: true },
      })}
      disabled={isLoading}
    >
      Sign {2} PSBTs
    </button>
  );
}

Return Type: UseSignPsbtsReturn

| Field | Type | Description | |-------|------|-------------| | signPsbts | (args: { psbts: string[]; options?: SignPsbtOptions }) => void | Fire-and-forget batch sign | | signPsbtsAsync | (args: { psbts: string[]; options?: SignPsbtOptions }) => Promise<string[]> | Sign and await results | | data | string[] \| undefined | Array of signed PSBT hex strings | | isLoading | boolean | Signing in progress | | isSuccess | boolean | Signing succeeded | | isError | boolean | Signing failed | | error | Error \| null | Error details | | isSupported | boolean | true if the connected wallet has signPsbts method | | reset | () => void | Reset state |

Supported wallets: Currently only Unisat supports batch PSBT signing.


useSendTransaction

Send Bitcoin to an address. Amount is specified in satoshis.

import { useSendTransaction } from 'otx-btc-wallet-react';

function SendBitcoin() {
  const {
    sendTransaction,      // (args: { to: string; amount: number }) => void
    sendTransactionAsync, // (args: { to: string; amount: number }) => Promise<string>
    data,                 // string | undefined (transaction ID)
    isLoading,
    isSuccess,
    isError,
    error,
    reset,
  } = useSendTransaction();

  return (
    <div>
      <button
        onClick={() => sendTransaction({
          to: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh',
          amount: 10000, // 10,000 satoshis
        })}
        disabled={isLoading}
      >
        Send 10,000 sats
      </button>
      {data && <p>TX ID: {data}</p>}
      {isError && <p>Error: {error?.message}</p>}
    </div>
  );
}

Return Type: UseSendTransactionReturn

| Field | Type | Description | |-------|------|-------------| | sendTransaction | (args: { to: string; amount: number }) => void | Fire-and-forget send | | sendTransactionAsync | (args: { to: string; amount: number }) => Promise<string> | Send and await txid | | data | string \| undefined | Transaction ID | | isLoading | boolean | Transaction in progress | | isSuccess | boolean | Transaction succeeded | | isError | boolean | Transaction failed | | error | Error \| null | Error details | | reset | () => void | Reset state |


useMultiAddress

Manage multiple addresses from a single wallet. Useful for wallets like Xverse that provide separate payment and ordinals addresses.

import { useMultiAddress } from 'otx-btc-wallet-react';

function MultiAddress() {
  const {
    addresses,       // WalletAccount[] - all addresses
    paymentAddress,  // WalletAccount | null - segwit/nested-segwit address
    ordinalsAddress, // WalletAccount | null - taproot address
    primaryAddress,  // WalletAccount | null - currently selected
    setPrimaryAddress, // (address: WalletAccount) => void
    isLoading,       // boolean
    refresh,         // () => Promise<void> - refetch from wallet
  } = useMultiAddress();

  return (
    <div>
      {paymentAddress && (
        <p>Payment: {paymentAddress.address} ({paymentAddress.type})</p>
      )}
      {ordinalsAddress && (
        <p>Ordinals: {ordinalsAddress.address} ({ordinalsAddress.type})</p>
      )}

      <h3>All Addresses:</h3>
      {addresses.map((addr) => (
        <button
          key={addr.address}
          onClick={() => setPrimaryAddress(addr)}
          style={{ fontWeight: addr === primaryAddress ? 'bold' : 'normal' }}
        >
          {addr.address} ({addr.type})
        </button>
      ))}

      <button onClick={refresh}>Refresh</button>
    </div>
  );
}

Return Type: UseMultiAddressReturn

| Field | Type | Description | |-------|------|-------------| | addresses | WalletAccount[] | All wallet addresses | | paymentAddress | WalletAccount \| null | First segwit or nested-segwit address (for payments) | | ordinalsAddress | WalletAccount \| null | First taproot address (for ordinals/inscriptions) | | primaryAddress | WalletAccount \| null | Currently selected address | | setPrimaryAddress | (address: WalletAccount) => void | Change the primary address | | isLoading | boolean | Fetching addresses | | refresh | () => Promise<void> | Re-fetch addresses from the wallet |

Address Selection Logic:

  • paymentAddress: First address with type 'segwit' or 'nested-segwit', falls back to the first address
  • ordinalsAddress: First address with type 'taproot'

Hook Patterns

All action hooks follow a consistent pattern:

Fire-and-Forget vs Async

Every action hook provides two versions:

  • action() - Fire-and-forget. Updates internal state (isLoading, isSuccess, isError, data).
  • actionAsync() - Returns a Promise. Use with try/catch for more control.
// Fire-and-forget (state updates automatically)
signMessage({ message: 'Hello' });

// Async (handle result directly)
try {
  const signature = await signMessageAsync({ message: 'Hello' });
  doSomethingWith(signature);
} catch (err) {
  handleError(err);
}

Reset State

All action hooks provide a reset() method to clear data, error, isSuccess, and isError back to their initial values.

const { signMessage, data, reset } = useSignMessage();

// After showing result, clear it
<button onClick={reset}>Clear</button>

Complete Example

import { createConfig } from 'otx-btc-wallet-core';
import {
  BtcWalletProvider,
  useAccount,
  useConnect,
  useDisconnect,
  useSignMessage,
  useSendTransaction,
  useNetwork,
} from 'otx-btc-wallet-react';
import { UnisatConnector, OKXConnector } from 'otx-btc-wallet-connectors';

const config = createConfig({
  connectors: [new UnisatConnector(), new OKXConnector()],
});

function Wallet() {
  const { address, isConnected, addressType } = useAccount();
  const { connect, connectors, isLoading: connecting } = useConnect();
  const { disconnect } = useDisconnect();
  const { signMessage, data: signature } = useSignMessage();
  const { sendTransaction, data: txid } = useSendTransaction();
  const { network } = useNetwork();

  if (!isConnected) {
    return (
      <div>
        <h2>Connect Wallet</h2>
        {connectors.map((c) => (
          <button
            key={c.id}
            onClick={() => connect({ connector: c })}
            disabled={!c.ready || connecting}
          >
            {c.name} {!c.ready ? '(not installed)' : ''}
          </button>
        ))}
      </div>
    );
  }

  return (
    <div>
      <p>Address: {address}</p>
      <p>Type: {addressType}</p>
      <p>Network: {network}</p>

      <button onClick={() => signMessage({ message: 'Hello!' })}>
        Sign Message
      </button>
      {signature && <p>Signature: {signature}</p>}

      <button onClick={() => sendTransaction({ to: 'bc1q...', amount: 10000 })}>
        Send 10,000 sats
      </button>
      {txid && <p>TX: {txid}</p>}

      <button onClick={() => disconnect()}>Disconnect</button>
    </div>
  );
}

function App() {
  return (
    <BtcWalletProvider config={config}>
      <Wallet />
    </BtcWalletProvider>
  );
}

Full Exports

// Provider
export { BtcWalletProvider } from './provider';
export type { BtcWalletProviderProps } from './provider';

// Context
export { useConfig, BtcWalletContext } from './context';

// Hooks
export { useAccount } from './hooks/useAccount';
export { useConnect } from './hooks/useConnect';
export { useDisconnect } from './hooks/useDisconnect';
export { useNetwork } from './hooks/useNetwork';
export { useSignMessage } from './hooks/useSignMessage';
export { useSignPsbt } from './hooks/useSignPsbt';
export { useSignPsbts } from './hooks/useSignPsbts';
export { useSendTransaction } from './hooks/useSendTransaction';
export { useMultiAddress } from './hooks/useMultiAddress';

// Return types
export type {
  UseAccountReturn,
  UseConnectReturn,
  ConnectArgs,
  UseDisconnectReturn,
  UseNetworkReturn,
  UseSignMessageReturn,
  UseSignPsbtReturn,
  UseSignPsbtsReturn,
  UseSendTransactionReturn,
  UseMultiAddressReturn,
} from './hooks';

License

MIT