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

blocktrails

v0.0.11

Published

Trust through time — Nostr-native state anchoring on Bitcoin

Readme

blocktrails

Reference implementation of Blocktrails — Nostr-native state anchoring on Bitcoin.

Live Demo · Specification · Profiles (MRC20) · NATEOS Viewer

What is this?

Blocktrails lets you anchor off-chain state to Bitcoin using Taproot. Each state produces a unique P2TR address. Spending from that address proves a state transition. The chain of spends is the state history — immutably ordered by Bitcoin.

base_key + sha256(state) = derived_key → P2TR address

Use cases: token ledgers, audit trails, Nostr identity anchoring, verifiable logs.

Install

npm install blocktrails

Quick Start

import { Blocktrail } from 'blocktrails';

// Create a trail with your Nostr-compatible private key
const trail = new Blocktrail(privkey);

// Genesis — commit first state to a P2TR address
const genesis = trail.genesis(JSON.stringify({ balance: 1000 }));
console.log(genesis.p2trAddress); // bc1p...

// Advance — each state gets a new address
const next = trail.advance(JSON.stringify({ balance: 900 }));
console.log(next.newP2trAddress); // bc1p... (different!)

// Verify — anyone with pubkey + states can verify
const { valid } = trail.verify(witnessPrograms);

How It Works

┌─────────────┐    scalar()    ┌─────────────┐    P2TR    ┌─────────────┐
│   State 0   │ ────────────▶  │  Address 0  │ ─────────▶ │   UTXO 0    │
└─────────────┘                └─────────────┘    fund    └──────┬──────┘
                                                                 │ spend
┌─────────────┐    scalar()    ┌─────────────┐    P2TR    ┌──────▼──────┐
│   State 1   │ ────────────▶  │  Address 1  │ ◀───────── │   UTXO 1    │
└─────────────┘                └─────────────┘            └──────┬──────┘
                                                                 │ spend
                                    ...                          ▼

Each state transition is a Bitcoin transaction. No special opcodes, just key tweaking.

API

Blocktrail Class

import { Blocktrail } from 'blocktrails';

const trail = new Blocktrail(privkey);

trail.genesis('state 0');           // Initialize
trail.advance('state 1');           // Transition
trail.advance('state 2');           // Transition

trail.currentState();               // 'state 2'
trail.currentWitnessProgram();      // Uint8Array (32 bytes)
trail.export();                     // { pubkeyBase, states, witnessPrograms }

Standalone Functions

import { genesis, transition, verify } from 'blocktrails';

// Create genesis
const g = genesis(privkey, 'initial state');
// → { witnessProgram, p2trAddress, derivedPrivkey, derivedPubkey }

// Create transition
const t = transition(privkey, 'state 0', 'state 1');
// → { signingPrivkey, prevWitnessProgram, newWitnessProgram, newP2trAddress }

// Verify chain
const result = verify(pubkeyBase, states, witnessPrograms);
// → { valid: true } or { valid: false, error: '...' }

Low-Level Primitives

import {
  scalar,              // sha256(state) mod n — the core tweak function
  derivePrivkey,       // d + t (derive privkey for state)
  derivePubkey,        // P + t·G (derive pubkey for state)
  p2trXonly,           // Compress to 32-byte x-only
  adjustPrivkeyForSigning, // BIP-340 parity adjustment
} from 'blocktrails';

// Example: derive address from state
const t = scalar(JSON.stringify({ counter: 42 }));
const P = derivePubkey(pubkeyBase, state);
const witnessProgram = p2trXonly(P);

CLI

# Install globally
npm install -g blocktrails

# Initialize a new trail
blocktrails init

# Mark state (unified command - broadcasts by default)
blocktrails mark '{"balance": 1000}'     # genesis + fund
blocktrails mark '{"balance": 900}'      # advance + spend
blocktrails mark '{"balance": 800}' --dry  # dry run (no broadcast)

# Or use separate commands
blocktrails genesis '{"balance": 1000}'  # off-chain only
blocktrails advance '{"balance": 900}'   # off-chain only
blocktrails fund --broadcast             # base → GENESIS
blocktrails spend --broadcast            # GENESIS → State 1

# Exit trail - send funds to external address
blocktrails exodus tb1p... --broadcast

# Publish to Nostr (NATEOS)
blocktrails publish --relay wss://relay.damus.io

# View trail with on-chain status
blocktrails show --online

CLI Commands

| Command | Description | |---------|-------------| | init | Create new trail (generates key or uses git config nostr.privkey) | | mark <state> | Unified command — add state and broadcast (use --dry for dry run) | | genesis <state> | Create genesis state (off-chain only) | | advance <state> | Advance to new state (off-chain only) | | fund | Move funds from base address to GENESIS (on-chain) | | spend [state] | Advance on-chain (to next state, or new state if provided) | | exodus <address> | Send funds to external address (exit trail) | | publish | Publish trail to Nostr relay (NATEOS) | | show | Show trail status (add --online for on-chain status) | | export | Export trail with witness programs | | verify [file] | Verify a trail | | cache [clear\|path] | Show cache stats, clear cache, or show path |

Supported Networks

Use --network or -n to specify: btc, tbtc3, tbtc4 (default), ltc

Transaction API

import {
  buildTransaction,
  signTransaction,
  serializeTransaction,
  broadcast,
  getUtxos,
  getFeeRates
} from 'blocktrails';

// Fetch UTXOs and fee rate
const utxos = await getUtxos(address, 'tbtc4');
const { halfHour } = await getFeeRates('tbtc4');

// Build and sign P2TR transaction
const tx = buildTransaction({
  inputs: utxos.map(u => ({ ...u, witnessProgram })),
  outputs: [{ witnessProgram: newWP, value: amount }]
});
const signed = signTransaction(tx, [signingKey], utxos);
const txHex = bytesToHex(serializeTransaction(signed));

// Broadcast
const txid = await broadcast(txHex, 'tbtc4');

Local Cache

Transaction data is cached locally in ~/.spv/{network}/tx/ to reduce API calls and enable offline access to previously fetched data.

# View cache stats
blocktrails cache

# Clear cache
blocktrails cache clear

# Show cache directory
blocktrails cache path
import {
  getCachedTx,
  cacheTx,
  getCacheStats,
  clearCache
} from 'blocktrails';

// getTransaction() automatically uses cache
const tx = await getTransaction(txid, 'tbtc4');

// Manual cache access
const cached = getCachedTx(txid, 'tbtc4');
const stats = getCacheStats('tbtc4');  // { count, size, sizeHuman }

Run Demo

npm run demo

Or try the live interactive demo on testnet4.

Run Tests

npm test  # 107 tests

Specification

  • Core Spec — The primitive: key tweaking, state commitment, verification
  • Profiles — Application schemas: Monochrome (generic), MRC20 (fungible tokens)

License

MIT