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

@anywalletkit/wallet-btc

v0.4.0

Published

Bitcoin wallet for Any Wallet Kit on @scure/btc-signer: BIP-84 p2wpkh and BIP-86 taproot accounts, own coin selection, RBF, Blockbook/Esplora transports.

Readme

@anywalletkit/wallet-btc

npm

Bitcoin accounts on @scure/btc-signer (audited by Cure53; pure Uint8Array, no Buffer, no Node shims):

Install

npm install @anywalletkit/wallet-btc
# or: pnpm add @anywalletkit/wallet-btc  ·  yarn add @anywalletkit/wallet-btc

On npm: @anywalletkit/wallet-btc, published from the release workflow with provenance.

| addressType | Path | Address | Standard | |---|---|---|---| | p2wpkh (default) | m/84'/0'/0'/0/i | bc1q… | BIP-84 native segwit | | p2tr | m/86'/0'/0'/0/i | bc1p… | BIP-86 key-path taproot |

Test networks use coin type 1' (tb1… / bcrt1…). Both paths are pinned by the official BIP-84 / BIP-86 test vectors.

import WalletManagerBtc from '@anywalletkit/wallet-btc'

const wallet = new WalletManagerBtc(seedPhrase, {
  network: 'bitcoin',
  addressType: 'p2wpkh',                       // or 'p2tr'
  client: [
    { type: 'blockbook-http', clientConfig: { url: 'https://btc1.trezor.io' } },
    { type: 'esplora-http', clientConfig: { url: 'https://mempool.space/api' } }, // fails over in order
  ],
  maxFeeRate: 200,                             // sat/vB ceiling (default 500)
})
const account = await wallet.getAccount(0)

const preview = await account.describeTransaction({ to: 'bc1q…', value: 50_000n })
//   { kind: 'btc-transfer', inputs, outputs: [{ role: 'recipient' | 'change' }], fee, feeRate, vsize, rbf, lockTime, warnings }

await account.transfer({ recipient: 'bc1q…', amount: 50_000n })             // sats
await account.sendTransaction({ to: 'bc1q…', value: 50_000n, feeRate: 12n }) // explicit sat/vB
const hex = await account.signTransaction({ to: 'bc1q…', value: 50_000n })   // sign only
const max = await account.getMaxSpendable()                                  // sweep amount after fee
wallet.dispose()

What a spend is

Coin selection is our own (selectCoins, coinselect.ts): effective-value accumulation, largest first; inputs that cannot pay for themselves are skipped; change below dust (294 sat p2wpkh / 330 sat p2tr) is folded into the fee; at most maxInputs (200) inputs. Fees are feeRate × vsize with the standard segwit weights, estimated with 72-byte signatures so the quote is never below the fee actually paid.

Transactions signal replace-by-fee (rbf, default on) and set nLockTime to the current tip (antiFeeSniping, default on when the transport can report the height).

Safety checks

A broadcast with no definitive answer (fetch threw, a timeout, a 5xx or 408, an unreadable body) throws BroadcastUnknownError (maybeSent, hash = the txid computed before sending): the transaction may be in the mempool, so do not build another spend. A node's refusal (4xx with a reason, an error body) stays an error marked answered (isAnsweredRefusal); with several clients it is a refusal only when every one refused. "Already in the mempool / block chain" returns the txid. A custom BtcClient should mark refusals answered: true. Outputs are matched to recipient and change by script.

Before signing and before broadcasting — also for caller-supplied raw hex — every transaction is resolved into a BtcTxDescription and must pass:

  • fee rate ≤ maxFeeRate (UnsafeTransactionError('fee-rate-too-high'));
  • exactly one output equals the requested recipient + amount, every other output is our own change ('unexpected-output', 'recipient-mismatch', 'change-not-ours');
  • transactionMaxFee / transferMaxFee absolute caps.

Warnings that do not block: high-fee-rate, fee-over-10pct-of-amount, dust-output, no-change.

Message signing

sign() / verify() are BIP-137 for p2wpkh accounts (header 39 + recovery, base64 — the Electrum / Bitcoin Core encoding). Taproot accounts have no BIP-137 form; sign() throws UnsupportedAddressTypeError (BIP-322 is not implemented).

Transports

blockbook-http (Trezor Blockbook REST, QuickNode's add-on) and esplora-http (mempool.space, blockstream.info). Requests time out after timeoutMs (15 s) and responses are shape-checked (NetworkError otherwise). Pass your own object implementing BtcClient for anything else.

Activity history

createBtcHistory is the chain's HistorySource (@anywalletkit/core) over Blockbook, reusing BlockbookClient (getAddressPage, getTransactionDetails).

import { createBtcHistory } from '@anywalletkit/wallet-btc/history'

const history = createBtcHistory({ blockbookUrls: ['https://btc1.trezor.io', 'https://bitcoin.atomicwallet.io'] })
const page = await history.listActivity('bc1q3x8yszvcvjjxqragsh0l6j8rxnhk7pay9hnj5h', { limit: 25 })
const older = await history.listActivity(address, { cursor: page.cursor })
const one = await history.getTransaction(page.items[0].hash, address)
history.explorerTxUrl(one.hash) // https://mempool.space/tx/…

| option | default | notes | |---|---|---| | blockbookUrl / blockbookUrls | — | Blockbook roots, tried in order (Cloudflare 403, 5xx, network → next). The Trezor instances (btc1…5.trezor.io) sit behind a Cloudflare challenge that blocks non-browser user agents; bitcoin.atomicwallet.io and blockbook.btc.zelcore.io answered on 2026-10-14. QuickNode's Blockbook add-on speaks the same API. | | network | bitcoin | testnet / regtest CAIP-2 ids; mempool.space testnet links. | | pageSize | the query limit, ≤ 100 | Rows per Blockbook page (its max is 1000). | | fetch, timeoutMs | global, 15 000 | |

Endpoint. GET /api/v2/address/{a}?details=txs&page=&pageSize= — Blockbook returns transactions newest first with inputs and outputs (hex is dropped). The cursor is base64 JSON { v: 1, p, s }: the next page and the page size the pagination started with (Blockbook clamps out-of-range pages to the last one, so paging stops at totalPages). since is applied client-side; unconfirmed rows are always kept.

Mapping. Inputs the address spent (ownIn) and outputs it received (ownOut) are summed. Spent inputs → a send: from = address, to = the first output that is not ours, nativeValue = what left to non-own outputs (change ignored, fee separate); every output ours → a consolidation to itself. No spent inputs → a receive: from = the first input address (coinbase when none), nativeValue = ownOut. transfers is that one native leg, fee = fees, status = confirmed once confirmations ≥ 1 (else pending, no block), block = blockHeight, raw = the Blockbook transaction plus ownIn / ownOut.

Fixtures in test/fixtures/history/ were captured on 2026-10-14 from bitcoin.atomicwallet.io for the test address (its 4 transactions: two receives, two sends with change) and GET /api/v2/tx/{txid} of one send. No protocol module recognizes Bitcoin transactions, so there is no recognizer cross-check.