wallet-brc100

SKILL.md

BRC-100 Wallet Implementation Guide

This skill provides comprehensive guidance for implementing BRC-100 conforming wallets using the @bsv/wallet-toolbox package (v1.7.18+).

Getting Started: Before implementing, review the Strategic Questionnaire to determine the right architecture for your wallet type.

Quick Reference

Core Dependencies

{
  "@bsv/wallet-toolbox": "^1.7.18",
  "@bsv/sdk": "^1.9.29"
}

WalletClient vs Wallet — Choose the Right Class

This is the most important distinction in the BSV wallet stack:

Class Package Use When
WalletClient @bsv/sdk Your app connects to a user's existing wallet (browser extension, MetaNet Client, etc.) — you don't control the keys
Wallet @bsv/wallet-toolbox You are building the wallet — you own the keys, storage, and services
// WalletClient — thin client, no key management
import { WalletClient } from '@bsv/sdk'
const wallet = new WalletClient() // connects to user's wallet environment

// Wallet — full wallet you build and control
import { Wallet } from '@bsv/wallet-toolbox'
const wallet = new Wallet({ chain, keyDeriver, storage, services })

Most apps (dApps, payment integrations) should use WalletClient. Only wallet builders need Wallet from @bsv/wallet-toolbox.

Main Classes

Class Purpose Use When
WalletClient Thin BRC-100 client Apps connecting to user's external wallet
Wallet Full BRC-100 wallet Building production wallet apps
SimpleWalletManager Lightweight wrapper Simple key-based authentication
CWIStyleWalletManager Multi-profile wallet Advanced UMP token flows
WalletSigner Transaction signing Custom signing logic

Table of Contents

  1. Installation & Setup
  2. Wallet Initialization
  3. Transaction Operations
  4. Key Management
  5. Storage Configuration
  6. Certificate Operations
  7. Error Handling
  8. Production Patterns

1. Installation & Setup

Install Dependencies

npm install @bsv/wallet-toolbox @bsv/sdk
# Optional storage backends:
npm install knex sqlite3          # SQLite
npm install knex mysql2           # MySQL
npm install idb                   # IndexedDB (browser)

Basic Imports

import {
  Wallet,
  WalletStorageManager,
  StorageKnex,
  StorageIdb,
  Services,
  WalletServices,
  PrivilegedKeyManager
} from '@bsv/wallet-toolbox'

import {
  PrivateKey,
  KeyDeriver,
  Random,
  Utils
} from '@bsv/sdk'

2. Wallet Initialization

Pattern A: Simple Wallet (Node.js with SQLite)

import { Wallet, StorageKnex, Services } from '@bsv/wallet-toolbox'
import { PrivateKey, Random } from '@bsv/sdk'
import Knex from 'knex'

async function createSimpleWallet() {
  // 1. Create root private key (or derive from mnemonic)
  const rootKey = new PrivateKey(Random(32))
  // Use KeyDeriver from @bsv/sdk for proper BRC-42 key derivation
  const keyDeriver = new KeyDeriver(rootKey)

  // 2. Configure SQLite storage
  const knex = Knex({
    client: 'sqlite3',
    connection: { filename: './wallet.db' },
    useNullAsDefault: true
  })

  const storage = new StorageKnex({
    knex,
    storageIdentityKey: rootKey.toPublicKey().toString(),
    storageName: 'my-wallet-storage'
  })

  await storage.makeAvailable()

  // 3. Configure services (mainnet)
  const services = new Services({
    chain: 'main',
    bsvExchangeRate: { timestamp: new Date(), base: 'USD', rate: 50 },
    bsvUpdateMsecs: 15 * 60 * 1000,
    fiatExchangeRates: {
      timestamp: new Date(),
      base: 'USD',
      rates: { EUR: 0.85, GBP: 0.73 }
    },
    fiatUpdateMsecs: 24 * 60 * 60 * 1000,
    arcUrl: 'https://arc.taal.com',
    arcConfig: {}
  })

  // 4. Create wallet
  const wallet = new Wallet({
    chain: 'main',
    keyDeriver,
    storage,
    services
  })

  return wallet
}

Pattern B: Browser Wallet (IndexedDB)

import { Wallet, StorageIdb, Services } from '@bsv/wallet-toolbox'
import { PrivateKey, Random } from '@bsv/sdk'

async function createBrowserWallet() {
  const rootKey = new PrivateKey(Random(32))

  // Use IndexedDB for browser storage
  const storage = new StorageIdb({
    idb: await openDB('my-wallet-db', 1),
    storageIdentityKey: rootKey.toPublicKey().toString(),
    storageName: 'browser-wallet'
  })

  await storage.makeAvailable()

  const services = new Services({
    chain: 'main',
    // ... services config
  })

  const wallet = new Wallet({
    chain: 'main',
    keyDeriver: createKeyDeriver(rootKey),
    storage,
    services
  })

  return wallet
}

Pattern C: Multi-Profile Wallet

import { CWIStyleWalletManager, OverlayUMPTokenInteractor } from '@bsv/wallet-toolbox'

async function createMultiProfileWallet() {
  const manager = new CWIStyleWalletManager(
    'example.com', // Admin originator
    async (profilePrimaryKey, profilePrivilegedKeyManager, profileId) => {
      // Build wallet for specific profile
      const keyDeriver = createKeyDeriver(new PrivateKey(profilePrimaryKey))
      const storage = await createStorage(profileId)
      const services = new Services({ chain: 'main', /* ... */ })

      return new Wallet({
        chain: 'main',
        keyDeriver,
        storage,
        services,
        privilegedKeyManager: profilePrivilegedKeyManager
      })
    },
    new OverlayUMPTokenInteractor(), // UMP token interactor
    async (recoveryKey) => {
      // Save recovery key (e.g., prompt user to write it down)
      console.log('SAVE THIS RECOVERY KEY:', Utils.toBase64(recoveryKey))
      return true
    },
    async (reason, test) => {
      // Retrieve password from user
      const password = prompt(`Enter password for: ${reason}`)
      if (!password) throw new Error('Password required')
      if (!test(password)) throw new Error('Invalid password')
      return password
    }
  )

  // Provide presentation key (e.g., from QR code scan)
  const presentationKey = Random(32)
  await manager.providePresentationKey(presentationKey)

  // Provide password
  await manager.providePassword('user-password')

  // Now authenticated and ready to use
  return manager
}

3. Transaction Operations

Create a Transaction

import { CreateActionArgs, CreateActionResult } from '@bsv/sdk'

async function sendBSV(
  wallet: Wallet,
  recipientAddress: string,
  satoshis: number
) {
  const args: CreateActionArgs = {
    description: 'Send BSV payment',
    outputs: [{
      lockingScript: Script.fromAddress(recipientAddress).toHex(),
      satoshis,
      outputDescription: `Payment to ${recipientAddress}`,
      basket: 'default',
      tags: ['payment']
    }],
    options: {
      acceptDelayedBroadcast: false, // Broadcast immediately
      randomizeOutputs: true          // Privacy
    }
  }

  const result: CreateActionResult = await wallet.createAction(args)

  if (result.txid) {
    console.log('Transaction created:', result.txid)
    return result.txid
  } else {
    console.log('Transaction pending signature')
    return result.signableTransaction
  }
}

Spending Existing Outputs (inputBEEF Required)

CRITICAL: When spending known wallet outputs via createAction, you MUST provide inputBEEF. The wallet needs the full BEEF proof chain (merkle proofs back to confirmed ancestors) for every input being spent. Without it, createAction will fail with "missing full proof in the inputBEEF".

Two ways to obtain BEEF for inputs:

1. From listOutputs with include: 'entire transactions' — for wallet-owned outputs:

// Fetch outputs WITH their BEEF proof chain
const result = await wallet.listOutputs({
  basket: 'my-basket',
  include: 'entire transactions',  // Returns result.BEEF
  includeTags: true,
})

// Pass the BEEF when spending those outputs
const createResult = await wallet.createAction({
  description: 'Spend basket outputs',
  inputBEEF: result.BEEF,  // Full proof chain for inputs
  inputs: result.outputs.map(o => ({
    outpoint: o.outpoint,
    inputDescription: 'Basket output',
    unlockingScriptLength: 180,
    sequenceNumber: 0xffffffff,
  })),
  outputs: [],
  options: { signAndProcess: false },
})

2. From a service BEEF lookup — for external inputs (sweep, purchase):

// Fetch BEEF from chain services
const beef = await services.getBeefForTxid(txid)
// Merge multiple if needed
for (const additionalTxid of otherTxids) {
  beef.mergeBeef(await services.getBeefForTxid(additionalTxid))
}

const createResult = await wallet.createAction({
  description: 'Spend external inputs',
  inputBEEF: beef.toBinary(),
  inputs: [...],
  outputs: [...],
})

Never call createAction with inputs but without inputBEEF — even if the wallet "owns" the outputs.

noSend + BEEF Relay Pattern

Use noSend: true when you want to create and sign a transaction but let a backend service validate and/or broadcast it. The result is returned as BEEF (Background Evaluation Extended Format) — a bundle of the transaction plus merkle proofs of its inputs, enabling SPV verification without a full node.

import { WalletClient, P2PKH, Transaction } from '@bsv/sdk'

const wallet = new WalletClient()

// Build and sign, but don't broadcast
const { tx } = await wallet.createAction({
  description: 'Payment to service',
  outputs: [{
    lockingScript: new P2PKH().lock(recipientAddress).toHex(),
    satoshis: 1000,
    outputDescription: 'Service payment',
  }],
  options: { noSend: true },
})

// tx is BEEF bytes — convert to hex for JSON transport
const beefHex = Transaction.fromBEEF(tx).toHexBEEF()

// Send to backend — it can SPV-verify and broadcast
await fetch(`https://your-service.example.com/pay?session=${sessionId}`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ beefHex }),
})

Why this pattern?

  • The receiving service can verify the payment is valid via SPV before granting access or broadcasting
  • Useful for payment-gated APIs, content unlocking, and atomic service flows
  • BEEF includes merkle proofs so the server doesn't need a full node

Common mistake: forgetting the $ in template literals — {session} is a literal string, ${session} interpolates the variable.

Sign a Transaction (Two-Phase with completeSignedAction)

For two-phase actions (signAndProcess: false), use the completeSignedAction helper from @1sat/actions instead of calling signAction directly:

import { completeSignedAction } from '@1sat/actions'

const result = await completeSignedAction(
  wallet,
  createResult,           // from createAction with signAndProcess: false
  inputBEEF as number[],  // BEEF from listOutputs (full SPV proof chain)
  async (tx) => {
    // tx is a fully-wired Transaction; return unlocking scripts by input index
    return { 0: { unlockingScript: myScript.toHex() } }
  },
)

The helper handles BEEF merge, script verification, signAction, and abortAction on failure.

signableTransaction BEEF Stripping

makeSignableTransactionBeef in wallet-toolbox intentionally strips merkle proofs (uses mergeRawTx). The completeSignedAction helper fixes this by merging the unsigned tx into the original inputBEEF:

import { Beef } from '@bsv/sdk'  // Beef IS exported from @bsv/sdk

const beef = Beef.fromBinary(inputBEEF)
beef.mergeRawTx(unsignedTx.toBinary())
const atomicTx = beef.findAtomicTransaction(txid)

This reconstructs the full BEEF with merkle proofs intact.

abortAction Scope

abortAction({ reference }) works on these statuses only:

  • nosend, unsigned, unprocessed

Does NOT work on: completed, failed, sending, unproven.

Server-side processAction verifies unlocking scripts independently after signAction. On verification failure, the server sets status to failed and releases inputs automatically.

Sign a Transaction (Direct signAction)

For simple cases where you need raw signAction:

async function signTransaction(
  wallet: Wallet,
  reference: string,
  unlockingScripts: Record<number, { unlockingScript: string }>
) {
  const result = await wallet.signAction({
    reference,
    spends: unlockingScripts
  })

  console.log('Transaction signed:', result.txid)
  return result
}

Check Wallet Balance

async function getWalletBalance(wallet: Wallet) {
  // Method 1: Quick balance (uses special operation)
  const balance = await wallet.balance()
  console.log(`Balance: ${balance} satoshis`)

  // Method 2: Detailed balance with UTXOs
  const detailed = await wallet.balanceAndUtxos('default')
  console.log(`Total: ${detailed.total} satoshis`)
  console.log(`UTXOs: ${detailed.utxos.length}`)
  detailed.utxos.forEach(utxo => {
    console.log(`  ${utxo.outpoint}: ${utxo.satoshis} sats`)
  })

  return balance
}

List Outputs

import { ListOutputsArgs, ListOutputsResult } from '@bsv/sdk'

async function listSpendableOutputs(wallet: Wallet) {
  const args: ListOutputsArgs = {
    basket: 'default',  // Change basket
    spendable: true,    // Only spendable outputs
    limit: 100,
    offset: 0,
    tags: ['payment']   // Optional: filter by tags
  }

  const result: ListOutputsResult = await wallet.listOutputs(args)

  console.log(`Found ${result.totalOutputs} outputs`)
  result.outputs.forEach(output => {
    console.log(`  ${output.outpoint}: ${output.satoshis} sats`)
  })

  return result
}

List Actions (Transactions)

async function listTransactionHistory(wallet: Wallet) {
  const result = await wallet.listActions({
    labels: [],
    labelQueryMode: 'any',
    limit: 50,
    offset: 0
  })

  console.log(`Found ${result.totalActions} actions`)
  result.actions.forEach(action => {
    console.log(`  ${action.txid}: ${action.status} - ${action.description}`)
  })

  return result
}

4. Key Management

Get Public Key

async function getIdentityKey(wallet: Wallet) {
  // Get wallet's identity key
  const result = await wallet.getPublicKey({ identityKey: true })
  console.log('Identity Key:', result.publicKey)
  return result.publicKey
}

async function getDerivedKey(wallet: Wallet) {
  // Get derived key for specific protocol
  const result = await wallet.getPublicKey({
    protocolID: [2, 'my-app'],
    keyID: 'encryption-key-1',
    counterparty: 'recipient-identity-key'
  })

  return result.publicKey
}

Encrypt/Decrypt Data

async function encryptMessage(
  wallet: Wallet,
  plaintext: string,
  recipientPubKey: string
) {
  const result = await wallet.encrypt({
    plaintext: Utils.toArray(plaintext, 'utf8'),
    protocolID: [2, 'secure-messaging'],
    keyID: 'msg-key',
    counterparty: recipientPubKey
  })

  return Utils.toBase64(result.ciphertext)
}

async function decryptMessage(
  wallet: Wallet,
  ciphertext: string,
  senderPubKey: string
) {
  const result = await wallet.decrypt({
    ciphertext: Utils.toArray(ciphertext, 'base64'),
    protocolID: [2, 'secure-messaging'],
    keyID: 'msg-key',
    counterparty: senderPubKey
  })

  return Utils.toUTF8(result.plaintext)
}

Create Signature

async function signData(wallet: Wallet, data: string) {
  const result = await wallet.createSignature({
    data: Utils.toArray(data, 'utf8'),
    protocolID: [2, 'document-signing'],
    keyID: 'sig-key',
    counterparty: 'self'
  })

  return Utils.toBase64(result.signature)
}

5. Storage Configuration

SQLite Storage (Node.js)

import Knex from 'knex'
import { StorageKnex } from '@bsv/wallet-toolbox'

async function setupSQLiteStorage() {
  const knex = Knex({
    client: 'sqlite3',
    connection: { filename: './wallet.db' },
    useNullAsDefault: true
  })

  const storage = new StorageKnex({
    knex,
    storageIdentityKey: 'your-identity-key',
    storageName: 'main-storage'
  })

  await storage.makeAvailable()
  return storage
}

MySQL Storage

async function setupMySQLStorage() {
  const knex = Knex({
    client: 'mysql2',
    connection: {
      host: 'localhost',
      user: 'wallet_user',
      password: 'secure_password',
      database: 'wallet_db'
    }
  })

  const storage = new StorageKnex({
    knex,
    storageIdentityKey: 'your-identity-key',
    storageName: 'mysql-storage'
  })

  await storage.makeAvailable()
  return storage
}

IndexedDB Storage (Browser)

import { openDB, DBSchema } from 'idb'
import { StorageIdb } from '@bsv/wallet-toolbox'

interface WalletDB extends DBSchema {
  // Storage schema is managed by StorageIdb
}

async function setupIndexedDBStorage() {
  const db = await openDB<WalletDB>('wallet-db', 1, {
    upgrade(db) {
      // StorageIdb creates necessary object stores
    }
  })

  const storage = new StorageIdb({
    idb: db,
    storageIdentityKey: 'your-identity-key',
    storageName: 'browser-storage'
  })

  await storage.makeAvailable()
  return storage
}

Multi-Storage Manager

import { WalletStorageManager } from '@bsv/wallet-toolbox'

async function setupMultiStorage() {
  const primaryStorage = await setupSQLiteStorage()
  const backupStorage = await setupMySQLStorage()

  const manager = new WalletStorageManager(
    primaryStorage,
    [backupStorage]
  )

  return manager
}

6. Certificate Operations

Acquire Certificate (Direct Protocol)

import { AcquireCertificateArgs } from '@bsv/sdk'

async function acquireDirectCertificate(wallet: Wallet) {
  const args: AcquireCertificateArgs = {
    acquisitionProtocol: 'direct',
    type: 'https://example.com/user-certificate',
    certifier: 'certifier-identity-key',
    serialNumber: Utils.toArray('cert-serial-123', 'utf8'),
    subject: await wallet.getIdentityKey(),
    revocationOutpoint: 'txid.vout',
    fields: {
      name: Utils.toArray('Alice Smith', 'utf8'),
      email: Utils.toArray('alice@example.com', 'utf8')
    },
    keyringForSubject: { /* master keyring */ },
    signature: Utils.toArray('signature-bytes', 'base64')
  }

  const result = await wallet.acquireCertificate(args)
  console.log('Certificate acquired:', result.certificateId)
  return result
}

Acquire Certificate (Issuance Protocol)

async function requestCertificateIssuance(wallet: Wallet) {
  const args: AcquireCertificateArgs = {
    acquisitionProtocol: 'issuance',
    type: 'https://example.com/kyc-certificate',
    certifier: 'certifier-identity-key',
    certifierUrl: 'https://certifier.example.com',
    fields: {
      name: 'Alice Smith',
      birthdate: '1990-01-01',
      country: 'US'
    }
  }

  const result = await wallet.acquireCertificate(args)
  console.log('Certificate issued:', result.certificateId)
  return result
}

List Certificates

async function listMyCertificates(wallet: Wallet) {
  const result = await wallet.listCertificates({
    certifiers: ['certifier-identity-key'],
    types: ['https://example.com/user-certificate'],
    limit: 50,
    offset: 0
  })

  console.log(`Found ${result.totalCertificates} certificates`)
  result.certificates.forEach(cert => {
    console.log(`  Type: ${cert.type}, Certifier: ${cert.certifier}`)
  })

  return result
}

Prove Certificate

async function proveCertificate(wallet: Wallet, certificateId: string) {
  const result = await wallet.proveCertificate({
    certificateId,
    fieldsToReveal: ['name', 'email'],
    verifier: 'verifier-identity-key',
    privileged: false
  })

  console.log('Certificate proof:', result.keyringForVerifier)
  return result
}

7. Error Handling

Standard Error Types

import {
  WalletError,
  WERR_INVALID_PARAMETER,
  WERR_INTERNAL,
  WERR_REVIEW_ACTIONS
} from '@bsv/wallet-toolbox'

try {
  const result = await wallet.createAction({
    description: 'Test transaction',
    outputs: [/* ... */]
  })
} catch (eu: unknown) {
  const error = WalletError.fromUnknown(eu)

  if (error.name === 'WERR_INVALID_PARAMETER') {
    console.error('Invalid parameter:', error.message)
    console.error('Stack:', error.stack)
  } else if (error.name === 'WERR_REVIEW_ACTIONS') {
    // Handle transaction review errors
    console.error('Review required:', error.details)
  } else {
    console.error('Wallet error:', error.message)
  }
}

Review Actions Error (Transaction Failed)

async function handleCreateAction(wallet: Wallet) {
  try {
    return await wallet.createAction({
      description: 'Payment',
      outputs: [/* ... */]
    })
  } catch (eu: unknown) {
    const error = WalletError.fromUnknown(eu)

    if (error.name === 'WERR_REVIEW_ACTIONS') {
      // Access detailed failure info
      const details = error as any
      console.error('Delayed results:', details.notDelayedResults)
      console.error('Send results:', details.sendWithResults)
      console.error('Failed txid:', details.txid)

      // Handle double-spend
      if (details.notDelayedResults?.some(r => r.status === 'doubleSpend')) {
        console.error('Double-spend detected!')
        console.error('Competing txs:', details.notDelayedResults[0].competingTxs)
      }
    }

    throw error
  }
}

8. Production Patterns

Pattern: Wallet State Management

class WalletManager {
  private wallet: Wallet | null = null

  async initialize(rootKey: PrivateKey) {
    if (this.wallet) {
      throw new Error('Wallet already initialized')
    }

    const storage = await this.setupStorage()
    const services = this.setupServices()
    const keyDeriver = this.createKeyDeriver(rootKey)

    this.wallet = new Wallet({
      chain: 'main',
      keyDeriver,
      storage,
      services
    })

    return this.wallet
  }

  async destroy() {
    if (this.wallet) {
      await this.wallet.destroy()
      this.wallet = null
    }
  }

  getWallet(): Wallet {
    if (!this.wallet) {
      throw new Error('Wallet not initialized')
    }
    return this.wallet
  }

  private async setupStorage() {
    // Storage setup logic
    return await setupSQLiteStorage()
  }

  private setupServices() {
    return new Services({
      chain: 'main',
      // ... config
    })
  }

  private createKeyDeriver(rootKey: PrivateKey) {
    // Key derivation logic
    return {
      rootKey,
      identityKey: rootKey.toPublicKey().toString(),
      // ... derivation methods
    }
  }
}

Pattern: Transaction Retry Logic

async function sendWithRetry(
  wallet: Wallet,
  args: CreateActionArgs,
  maxRetries = 3
): Promise<string> {
  let lastError: Error | null = null

  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await wallet.createAction(args)

      if (result.txid) {
        return result.txid
      }

      // Handle signature if needed
      if (result.signableTransaction) {
        const signed = await wallet.signAction({
          reference: result.signableTransaction.reference,
          spends: {} // Provide unlocking scripts
        })
        return signed.txid!
      }

      throw new Error('Unexpected result format')

    } catch (error) {
      lastError = error as Error
      console.error(`Attempt ${attempt} failed:`, error)

      if (attempt < maxRetries) {
        await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
      }
    }
  }

  throw lastError || new Error('All retries failed')
}

Pattern: Background Transaction Monitor

import { Monitor } from '@bsv/wallet-toolbox'

async function setupMonitor(wallet: Wallet) {
  const monitor = new Monitor({
    storage: wallet.storage,
    services: wallet.services,
    chain: 'main'
  })

  monitor.on('transaction', (status) => {
    console.log('Transaction update:', status.txid, status.blockHeight)
  })

  monitor.on('error', (error) => {
    console.error('Monitor error:', error)
  })

  await monitor.start()

  return monitor
}

Related Skills

For comprehensive wallet development, also reference these skills:

Skill Relationship
encrypt-decrypt-backup Standard backup formats (.bep files, AES-256-GCM)
junglebus Populate UTXO set from blockchain, real-time streaming
key-derivation Type42/BRC-42 and BIP32 key derivation details
wallet-encrypt-decrypt ECDH message encryption patterns
wallet-send-bsv Basic transaction creation (simpler than BRC-100)

For 1Sat Ordinals / Token Support:

If your BRC-100 wallet needs to handle 1Sat Ordinals, BSV-20/BSV-21 tokens, or inscriptions, use @1sat/wallet-toolbox which wraps the core wallet-toolbox with ordinals capabilities.

See 1sat-skills for:

  • wallet-create-ordinals - Mint ordinals/NFTs
  • extract-blockchain-media - Extract inscribed media from transactions
  • ordinals-marketplace - List/buy/cancel ordinals (OrdLock)
  • token-operations - BSV21 token send/receive/deploy
  • wallet-setup - BRC-100 wallet creation and sync
  • transaction-building - Action-based tx building (sendBsv, signBsm)
  • sweep-import - Import from external wallets via WIF
  • opns-names - OpNS name registration
  • dapp-connect - dApp wallet connection (@1sat/connect, @1sat/react)
  • timelock - CLTV time-locked BSV

Additional Resources

Research: For deep dives into BRC specifications or implementation patterns, use the browser-agent to fetch current documentation from bsv.brc.dev.


Platform Guides

Platform-specific implementation guides:

Platform Guide Reference Implementation
Browser Extension extension-guide.md yours-wallet
Desktop (Electron) desktop-guide.md bsv-desktop
Web Application web-guide.md -
Mobile (React Native) mobile-guide.md -
Node.js Service/CLI nodejs-guide.md -

See references/key-concepts.md for BRC-100 unique concepts:

  • Actions vs Transactions
  • Baskets and Tags
  • Certificate system (BRC-52/53/64/65)
  • Background Monitoring

Common Patterns Summary

Task Method Key Args
Send BSV createAction() outputs, options
Check balance balance() None
List UTXOs listOutputs() basket, spendable
Get history listActions() labels, limit
Get pubkey getPublicKey() protocolID, keyID
Encrypt data encrypt() plaintext, counterparty
Get certificate acquireCertificate() type, certifier

Remember: Always handle errors properly, use privileged keys securely, and follow BRC-100 security levels for sensitive operations!

Weekly Installs
15
GitHub Stars
1
First Seen
Feb 8, 2026
Installed on
claude-code15
cursor14
gemini-cli14
antigravity14
opencode14
amp13