otx-btc-wallet-connectors
v0.1.0
Published
Bitcoin wallet connectors for otx-btc-wallet
Maintainers
Readme
otx-btc-wallet-connectors
Bitcoin wallet connectors, blockchain services, and PSBT utilities for the otx-btc-wallet library.
Installation
pnpm add otx-btc-wallet-connectors otx-btc-wallet-coreSupported Wallets
| Wallet | Connector | Type | Sign PSBT | Batch PSBT | Send BTC | Network Switch |
|--------|-----------|------|-----------|------------|----------|----------------|
| Unisat | UnisatConnector | Extension | Yes | Yes | Yes | Yes |
| Xverse | XverseConnector | Extension | Yes | No | Yes | Yes |
| OKX | OKXConnector | Extension | Yes | No | Yes | No* |
| Phantom | PhantomConnector | Extension | Yes | No | Yes | No** |
| Bitget | BitgetConnector | Extension | Yes | No | Yes | Yes |
| Binance | BinanceConnector | Extension | Yes | No | Yes | Yes |
| imToken | ImTokenConnector | Mobile | Yes | No | Yes | Yes |
| Ledger | LedgerConnector | Hardware | No*** | No | Yes | N/A |
| Trezor | TrezorConnector | Hardware | No*** | No | Yes | N/A |
* OKX: Users switch network in the extension manually.
** Phantom: Only supports mainnet for Bitcoin.
*** Hardware wallets use sendTransaction() directly with built-in PSBT construction.
Quick Start
import {
UnisatConnector,
XverseConnector,
OKXConnector,
PhantomConnector,
BitgetConnector,
BinanceConnector,
ImTokenConnector,
LedgerConnector,
TrezorConnector,
} from 'otx-btc-wallet-connectors';
// Create a connector
const unisat = new UnisatConnector();
// Check if wallet is installed
if (unisat.ready) {
// Connect
const account = await unisat.connect('mainnet');
console.log(account.address, account.publicKey, account.type);
// Sign message
const signature = await unisat.signMessage('Hello Bitcoin!');
// Sign PSBT
const signedPsbt = await unisat.signPsbt(psbtHex, {
autoFinalize: true,
});
// Batch sign PSBTs (Unisat only)
const signedPsbts = await unisat.signPsbts([psbt1, psbt2], {
autoFinalize: true,
});
// Send Bitcoin (amount in satoshis)
const txid = await unisat.sendTransaction('bc1q...', 10000);
// Disconnect
await unisat.disconnect();
}Connector Interface
All connectors implement the BitcoinConnector interface from otx-btc-wallet-core:
interface BitcoinConnector {
readonly id: string; // Unique identifier (e.g. 'unisat')
readonly name: string; // Display name (e.g. 'Unisat')
readonly icon: string; // Base64 SVG/PNG icon
ready: boolean; // Is the wallet installed/available?
connect(network?: BitcoinNetwork): Promise<WalletAccount>;
disconnect(): Promise<void>;
getAccounts(): Promise<WalletAccount[]>;
signMessage(message: string): Promise<string>;
signPsbt(psbtHex: string, options?: SignPsbtOptions): Promise<string>;
signPsbts?(psbtHexs: string[], options?: SignPsbtOptions): Promise<string[]>;
sendTransaction(to: string, satoshis: number): Promise<string>;
getNetwork(): Promise<BitcoinNetwork>;
switchNetwork?(network: BitcoinNetwork): Promise<void>;
onAccountsChanged(callback: (accounts: WalletAccount[]) => void): () => void;
onNetworkChanged(callback: (network: BitcoinNetwork) => void): () => void;
}Event Listeners
All connectors support account and network change events:
// Listen for account changes
const unsubscribe = connector.onAccountsChanged((accounts) => {
if (accounts.length === 0) {
console.log('Wallet disconnected');
} else {
console.log('Account changed:', accounts[0].address);
}
});
// Listen for network changes
const unsubNetwork = connector.onNetworkChanged((network) => {
console.log('Network changed to:', network);
});
// Cleanup listeners
unsubscribe();
unsubNetwork();Hardware Wallets
Ledger
Connects via WebUSB. Requires a Chromium-based browser (Chrome, Edge, Brave).
import { LedgerConnector } from 'otx-btc-wallet-connectors';
import type { LedgerConnectorOptions } from 'otx-btc-wallet-connectors';
const ledger = new LedgerConnector({
addressType: 'segwit', // 'legacy' | 'nested-segwit' | 'segwit' | 'taproot'
});
// Connect - opens USB device picker
const account = await ledger.connect('mainnet');
// Send Bitcoin (PSBT is built and signed internally)
const txid = await ledger.sendTransaction('bc1q...', 50000);
// Get multiple addresses from the device
const addresses = await ledger.getAddresses(0, 5); // indices 0-4
// Get extended public key
const xpub = await ledger.getExtendedPublicKey();
// Disconnect (closes USB transport)
await ledger.disconnect();Ledger Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| addressType | AddressType | 'segwit' | Address derivation type |
Trezor
Connects via Trezor Connect.
import { TrezorConnector } from 'otx-btc-wallet-connectors';
import type { TrezorConnectorOptions } from 'otx-btc-wallet-connectors';
const trezor = new TrezorConnector({
addressType: 'segwit',
manifest: {
email: '[email protected]',
appUrl: 'https://your-app.com',
},
});
// Connect - opens Trezor Connect popup
const account = await trezor.connect('mainnet');
// Send Bitcoin
const txid = await trezor.sendTransaction('bc1q...', 50000);
// Get multiple addresses
const addresses = await trezor.getAddresses(0, 5);
// Get extended public key
const xpub = await trezor.getExtendedPublicKey();
// Verify address on device screen
const verified = await trezor.getAddressWithVerification();
await trezor.disconnect();Trezor Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| addressType | AddressType | 'segwit' | Address derivation type |
| manifest.email | string | '[email protected]' | Contact email for Trezor |
| manifest.appUrl | string | 'https://optimex.com' | App URL for Trezor |
Custom Connectors
Extend BaseConnector to add support for any Bitcoin wallet:
import { BaseConnector } from 'otx-btc-wallet-connectors';
import type {
WalletAccount,
BitcoinNetwork,
SignPsbtOptions,
} from 'otx-btc-wallet-core';
export class MyWalletConnector extends BaseConnector {
readonly id = 'my-wallet';
readonly name = 'My Wallet';
readonly icon = 'data:image/svg+xml;base64,...';
// Return the wallet's injected provider, or null if not installed
protected getProvider() {
return (window as any).myWallet ?? null;
}
async connect(network: BitcoinNetwork = 'mainnet'): Promise<WalletAccount> {
this.ensureInstalled(); // Throws if getProvider() returns null
const provider = this.getProvider()!;
const accounts = await provider.requestAccounts();
const publicKey = await provider.getPublicKey();
return {
address: accounts[0],
publicKey,
type: this.inferAddressType(accounts[0]), // Auto-detect from address prefix
};
}
async disconnect(): Promise<void> {
this.cleanup(); // Removes event listeners
}
async getAccounts(): Promise<WalletAccount[]> {
const provider = this.getProvider()!;
const accounts = await provider.getAccounts();
const publicKey = await provider.getPublicKey();
return accounts.map((addr: string) => ({
address: addr,
publicKey,
type: this.inferAddressType(addr),
}));
}
async signMessage(message: string): Promise<string> {
return this.getProvider()!.signMessage(message);
}
async signPsbt(psbtHex: string, options?: SignPsbtOptions): Promise<string> {
return this.getProvider()!.signPsbt(psbtHex, options);
}
async sendTransaction(to: string, satoshis: number): Promise<string> {
return this.getProvider()!.sendBitcoin(to, satoshis);
}
async getNetwork(): Promise<BitcoinNetwork> {
return this.getProvider()!.getNetwork();
}
}BaseConnector Protected Methods
| Method | Description |
|--------|-------------|
| getProvider() | Abstract. Return the wallet's injected provider object |
| ensureInstalled() | Throws error if getProvider() returns null/undefined |
| inferAddressType(address) | Detects address type from prefix (1... = legacy, 3... = nested-segwit, bc1q... = segwit, bc1p... = taproot) |
| handleError(error) | Wraps errors with connector context |
| emitAccountsChanged(accounts) | Notify listeners of account changes |
| emitNetworkChanged(network) | Notify listeners of network changes |
| cleanup() | Remove all registered event listeners |
BtcService
BtcService provides a unified API for querying Bitcoin blockchain data. It uses a dual-provider architecture with Mempool.space and Blockstream.info for reliability.
Basic Usage
import { BtcService } from 'otx-btc-wallet-connectors';
const service = new BtcService('mainnet');
// Get UTXOs for an address
const utxos = await service.getUtxos('bc1q...');
// Get transaction hex
const txHex = await service.getTxHex('txid...');
// Get full transaction details
const tx = await service.getTransaction('txid...');
// Broadcast a signed transaction
const txid = await service.broadcastTransaction(signedTxHex);
// Get address balance
const balance = await service.getBalance('bc1q...');
// Get current fee rates (sat/vB)
const fees = await service.getFeeRates();
// { fastest: number, halfHour: number, hour: number, economy: number, minimum: number }Standalone Functions
For convenience, you can also use standalone functions without creating an instance:
import {
getUtxos,
getTxHex,
getTransaction,
broadcastTransaction,
getBalance,
getFeeRates,
} from 'otx-btc-wallet-connectors';
const utxos = await getUtxos('mainnet', 'bc1q...');
const fees = await getFeeRates('mainnet');Custom RPC Endpoints
Configure custom Mempool.space or Blockstream.info endpoints globally:
import { configureBtcService } from 'otx-btc-wallet-connectors';
configureBtcService({
mempool: {
mainnet: 'https://my-mempool.example.com/api',
testnet: 'https://my-mempool.example.com/testnet/api',
},
blockstream: {
mainnet: 'https://my-blockstream.example.com/api',
},
preferredProvider: 'mempool', // 'mempool' | 'blockstream' | 'race' (default)
});Provider Modes:
| Mode | Description |
|------|-------------|
| 'race' | (Default) Sends requests to both providers simultaneously, uses whichever responds first |
| 'mempool' | Only use Mempool.space |
| 'blockstream' | Only use Blockstream.info |
Per-Instance Configuration
You can also pass config when creating a BtcService instance:
const service = new BtcService('mainnet', {
mempool: { mainnet: 'https://my-mempool.example.com/api' },
preferredProvider: 'mempool',
});Configuration Types
import type { BtcServiceConfig, NetworkEndpoints } from 'otx-btc-wallet-connectors';
interface NetworkEndpoints {
mainnet?: string;
testnet?: string;
testnet4?: string;
signet?: string;
}
interface BtcServiceConfig {
mempool?: NetworkEndpoints;
blockstream?: NetworkEndpoints;
preferredProvider?: 'mempool' | 'blockstream' | 'race';
}Get Current Config
import { getBtcServiceConfig } from 'otx-btc-wallet-connectors';
const currentConfig = getBtcServiceConfig();Service Types
import type {
Utxo,
UtxoWithTx,
FeeRates,
Transaction,
FullTransaction,
AddressBalance,
IBtcService,
} from 'otx-btc-wallet-connectors';
interface Utxo {
txid: string;
vout: number;
value: number;
status: { confirmed: boolean; block_height?: number };
}
interface FeeRates {
fastest: number;
halfHour: number;
hour: number;
economy: number;
minimum: number;
}
interface AddressBalance {
confirmed: number;
unconfirmed: number;
total: number;
}PSBT Builder Utilities
Low-level utilities for building Bitcoin transactions:
import {
deriveAddressFromPublicKey,
detectAddressType,
estimateVBytes,
selectUtxos,
buildPsbt,
} from 'otx-btc-wallet-connectors';Derive Address from Public Key
import { deriveAddressFromPublicKey } from 'otx-btc-wallet-connectors';
const address = deriveAddressFromPublicKey(
publicKeyHex, // Hex-encoded public key
'segwit', // 'legacy' | 'nested-segwit' | 'segwit' | 'taproot'
'mainnet', // Bitcoin network
);Individual Service Classes
You can use Mempool or Blockstream services directly:
import { MempoolService, BlockstreamService } from 'otx-btc-wallet-connectors';
// Use Mempool.space directly
const mempool = new MempoolService('mainnet');
const utxos = await mempool.getUtxos('bc1q...');
// Use Blockstream.info directly
const blockstream = new BlockstreamService('mainnet');
const balance = await blockstream.getBalance('bc1q...');
// With custom endpoints
const customMempool = new MempoolService('mainnet', {
mainnet: 'https://my-mempool.example.com/api',
});Default API Endpoints
Mempool.space
| Network | Endpoint |
|---------|----------|
| mainnet | https://mempool.space/api |
| testnet | https://mempool.space/testnet/api |
| testnet4 | https://mempool.space/testnet4/api |
| signet | https://mempool.space/signet/api |
Blockstream.info
| Network | Endpoint |
|---------|----------|
| mainnet | https://blockstream.info/api |
| testnet | https://blockstream.info/testnet/api |
| testnet4 | https://mempool.space/testnet4/api (fallback) |
| signet | https://mempool.space/signet/api (fallback) |
Full Exports
// Connectors
export { UnisatConnector } from './unisat';
export { XverseConnector } from './xverse';
export { OKXConnector } from './okx';
export { PhantomConnector } from './phantom';
export { BitgetConnector } from './bitget';
export { BinanceConnector } from './binance';
export { ImTokenConnector } from './imtoken';
export { LedgerConnector } from './ledger';
export type { LedgerConnectorOptions } from './ledger';
export { TrezorConnector } from './trezor';
export type { TrezorConnectorOptions } from './trezor';
// Base class for custom connectors
export { BaseConnector } from './base';
// Services
export { BtcService } from './utils/btc-service';
export { MempoolService } from './utils/mempool';
export { BlockstreamService } from './utils/blockstream';
// Configuration
export { configureBtcService, getBtcServiceConfig } from './utils/btc-service';
// PSBT Builder
export { deriveAddressFromPublicKey } from './utils/psbt-builder';
// Standalone functions
export {
getUtxos,
getTxHex,
getTransaction,
broadcastTransaction,
getBalance,
getFeeRates,
} from './utils/btc-service';
// Types
export type {
Utxo,
UtxoWithTx,
FeeRates,
Transaction,
FullTransaction,
AddressBalance,
IBtcService,
BtcServiceConfig,
NetworkEndpoints,
} from './utils/types';License
MIT
