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

@bsv/wallet-helper

v0.0.3

Published

Wallet-compatible utilities and script templates for Bitcoin SV (BSV) that support BRC-100 wallet interfaces instead of requiring direct private key access.

Readme

BSV Wallet Helper

Wallet-compatible utilities and script templates for Bitcoin SV (BSV) that support BRC-100 wallet interfaces instead of requiring direct private key access.

Features

  • BRC-100 Compatible - Works with BRC-100 wallet interfaces
  • Hierarchical Key Derivation - Supports protocolID, keyID, and counterparty parameters
  • 1Sat Ordinals Support - Create ordinal inscriptions with file data and MAP metadata
  • Type Safe - Full TypeScript support with comprehensive types
  • Secure - Never exposes private keys to application layer

Installation

npm install bsv-wallet-helper

Exported API

Transaction Builder

TransactionBuilder

Fluent transaction builder that simplifies creating BSV transactions with a clean, chainable API.

import { TransactionBuilder } from 'bsv-wallet-helper';

// Simple P2PKH transaction with metadata
const result = await new TransactionBuilder(wallet, "Payment to Bob")
  .addP2PKHOutput({ publicKey: bobPublicKey, satoshis: 1000, description: "Payment" })
    .addOpReturn(['APP_ID', JSON.stringify({ memo: 'Thanks!' })])
  .build();

console.log(`Transaction created: ${result.txid}`);

// Preview mode - see what will be sent without executing
const preview = await new TransactionBuilder(wallet)
  .addP2PKHOutput({ publicKey: alicePublicKey, satoshis: 5000 })
  .build({ preview: true });

console.log('Transaction preview:', preview);

Features:

  • Fluent API with method chaining
  • Support for P2PKH, Ordinal P2PKH, and custom outputs
  • Automatic BRC-29 derivation - omit addressOrParams to use secure random key derivation
  • Automatic change outputs with fee calculation
  • Per-output OP_RETURN metadata
  • Per-output basket and customInstructions fields
  • Transaction-level options (randomizeOutputs, trustSelf, etc.)
  • Preview mode to inspect before execution
  • Input support for spending UTXOs

📖 Complete Documentation

Example with automatic change:

// Change is automatically calculated: inputs - outputs - fees
await new TransactionBuilder(wallet, "Payment with change")
  .addP2PKHInput({ sourceTransaction, sourceOutputIndex: 0, walletParams, description: "UTXO" })
  .addP2PKHOutput({ publicKey: recipientPublicKey, satoshis: 5000, description: "Payment" })
  .addChangeOutput({ walletParams, description: "Change" }) // Satoshis calculated automatically!
  .build();

Example with BRC-29 auto-derivation, basket, and customInstructions:

// Omit publicKey/walletParams to use automatic BRC-29 derivation
// Derivation info is automatically added to customInstructions
await new TransactionBuilder(wallet, "Auto-derived transaction")
  .addP2PKHOutput({ satoshis: 1000, description: "Payment" })  // Uses BRC-29 derivation
    .basket("my-basket")  // Set basket for this output
    .customInstructions("app-specific-data")  // Append custom instructions
  .build();

// The output will have customInstructions with both app data and derivation info

Script Templates

WalletP2PKH

Wallet-compatible Pay-to-Public-Key-Hash template.

import { WalletP2PKH, type WalletDerivationParams } from 'bsv-wallet-helper';

// Option 1: Direct public key
const p2pkh = new WalletP2PKH();
const lockingScript = await p2pkh.lock({ publicKey: publicKeyHex });

// Option 2: With BRC-100 wallet
const p2pkh = new WalletP2PKH(wallet);
const lockingScript = await p2pkh.lock({
  walletParams: {
    protocolID: [2, 'p2pkh'],
    keyID: '0',
    counterparty: 'self'
  }
});

// Unlocking (requires wallet)
const unlockingTemplate = p2pkh.unlock({
  protocolID: [2, 'p2pkh'],
  keyID: '0',
  counterparty: 'self'
});

WalletOrdP2PKH

Wallet-compatible template for 1Sat Ordinals with inscription and MAP metadata support.

import { WalletOrdP2PKH, type Inscription, type MAP } from 'bsv-wallet-helper';

// Create ordinal with inscription and metadata
const ordP2pkh = new WalletOrdP2PKH(wallet);

const inscription: Inscription = {
  dataB64: Buffer.from('Hello, Ordinals!').toString('base64'),
  contentType: 'text/plain'
};

const metadata: MAP = {
  app: 'my-app',
  type: 'greeting',
  author: 'Satoshi'
};

const lockingScript = await ordP2pkh.lock({
  walletParams: {
    protocolID: [2, 'p2pkh'],
    keyID: '0',
    counterparty: 'self'
  },
  inscription,
  metadata
});

Note: For wallet compatible multisig scripts see 'https://github.com/bsv-blockchain/ts-templates'.

Types

WalletDerivationParams

Parameters for deriving keys from a BRC-100 wallet.

type WalletDerivationParams = {
  protocolID: WalletProtocol;  // e.g., [2, 'p2pkh']
  keyID: string;               // e.g., '0'
  counterparty: WalletCounterparty;  // e.g., 'self'
};

Note: When wallet derivation parameters are omitted, the library uses the BRC-29 derivation scheme by default (using brc29ProtocolID from @bsv/wallet-toolbox-client and a randomly generated keyID), with counterparty defaulting to 'self'.

Inscription

1Sat Ordinal inscription data.

type Inscription = {
  dataB64: string;      // Base64 encoded file data
  contentType: string;  // MIME type (e.g., 'image/png', 'text/plain')
};

MAP

MAP (Magic Attribute Protocol) metadata for ordinals.

type MAP = {
  app: string;          // Application identifier (required)
  type: string;         // Data type identifier (required)
  [key: string]: string;  // Additional custom fields
};

Utilities

Helper functions for wallet creation, transaction signing, script manipulation, validation, and data extraction.

📖 Complete Utilities Documentation

Includes:

  • Wallet Creation: makeWallet() for creating BRC-100 wallets
  • Transaction Signing: calculatePreimage() for signature generation
  • Script Utilities: addOpReturnData() for adding metadata
  • Script Validation: isP2PKH(), isOrdinal(), hasOrd(), hasOpReturnData()
  • Script Type Detection: getScriptType() to identify script types
  • Data Extraction: extractOpReturnData(), extractMapMetadata(), extractInscriptionData()
  • Key Derivation: getDerivation() for BRC-29 key derivation

⚠️ Important: Lock and Unlock Key Consistency

You MUST use matching derivation parameters for lock and unlock operations.

✅ Correct Usage

const wallet = await makeWallet('test', storageURL, privateKeyHex);
const p2pkh = new WalletP2PKH(wallet);

const walletParams = {
  protocolID: [2, 'p2pkh'] as WalletProtocol,
  keyID: '0',
  counterparty: 'self' as WalletCounterparty
};

// Lock with wallet derivation
const lockingScript = await p2pkh.lock({ walletParams });

// Unlock with SAME derivation params
const unlockingTemplate = p2pkh.unlock({
  protocolID: walletParams.protocolID,
  keyID: walletParams.keyID,
  counterparty: walletParams.counterparty
});

❌ Incorrect Usage

// Lock with direct public key
const lockingScript = await p2pkh.lock({ publicKey: publicKeyHex });

// Try to unlock with different derivation params
// This WILL FAIL even if from same private key!
const unlockingTemplate = p2pkh.unlock({
  protocolID: [2, 'different-protocol'],  // Different protocol
  keyID: '1',                              // Different keyID
  counterparty: 'counterparty'             // Different counterparty
});

Why? Each set of derivation parameters produces a different private key from the seed key -> different public key. The unlocking signature must match the exact public key hash used in the locking script.

Best Practices

  1. Store derivation parameters alongside the locking script
  2. Use the same parameters when unlocking
  3. Or use direct public key for both lock and unlock if not using wallet derivation
// Recommended: Store params with your UTXO
type MyUTXO = {
  lockingScript: LockingScript;
  satoshis: number;
  derivationParams: WalletDerivationParams;  // Store these!
};

// Later when spending
const unlockingTemplate = p2pkh.unlock({
  protocolID: utxo.derivationParams.protocolID,
  keyID: utxo.derivationParams.keyID,
  counterparty: utxo.derivationParams.counterparty
});

Examples

For complete working examples, see the test files:

Reinscriptions (Metadata-Only Updates)

Update ordinal metadata without re-uploading file data:

// Original inscription with file
const original = await ordP2pkh.lock({
  walletParams,
  inscription: { dataB64: largeImage, contentType: 'image/png' },
  metadata: { app: 'gallery', type: 'art', owner: 'alice' }
});

// Later: Update metadata only (saves transaction fees)
const updated = await ordP2pkh.lock({
  walletParams,
  // No inscription field = no file data
  metadata: { app: 'gallery', type: 'art', owner: 'bob', sold: 'true' }
});

License

See LICENSE.md

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Disclaimer

This project is a work in progress and may change at any time. It is provided as-is, without any guarantees. Use at your own risk.