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

nanopay

v0.2.0

Published

Nano toolkit with granular cryptography, mnemonic wallets, block building, proof of work, RPC and payment workflows.

Readme

nanopay

Nano for JavaScript and TypeScript: create or recover accounts, send and receive funds, build blocks, sign locally, generate work, and query a node.

Use the client for complete workflows. Use the exported functions when you want control over each step. Both use the same Nano cryptography and block builders.

Complete API reference · Runtime support · Performance · Release status

Version 0.2.0 uses BerryPay's public Nano mainnet RPC when you call createClient() or createRpcClient() without a URL. 0.1.0 requires an explicit URL. See the documentation, node configuration and deployment guide.

Install

npm install nanopay

To develop from source, use npm ci && npm run build and import from ./dist/index.js. Node.js 22+, ESM, CommonJS, TypeScript and modern browsers are supported. A browser script bundle exposes NanoPay.

Create or recover accounts

import {
  createWallet,
  walletFromSeed,
  accountFromPrivateKey,
  walletFromMnemonic,
} from 'nanopay'

const wallet = createWallet()
const first = wallet.account() // index 0
const second = wallet.account(1)

// Each account has { privateKey, publicKey, address }.
console.log(first.address)

const recovered = walletFromSeed(savedSeed).account(1)
const imported = accountFromPrivateKey(savedPrivateKey)
const mnemonicWallet = await walletFromMnemonic(savedWords, {
  passphrase: savedPassphrase,
})
const mnemonicAccount = mnemonicWallet.account()

Back up wallet.seed, or your mnemonic and its passphrase, according to how the wallet was created. A private key controls one account; it cannot recover the wallet's seed or other accounts. Keep seeds and private keys out of logs and RPC requests.

Native Nano hex seeds and BIP39 mnemonic seeds follow different derivation schemes. walletFromSeed uses Nano's BLAKE2b derivation. walletFromMnemonic follows BIP39 and the Nano SLIP-0010 path m/44'/165'/index'. It matches the official Nano key-management vectors.

Send, receive, and confirm

import { createClient, walletFromSeed } from 'nanopay'

const client = createClient({ rpcUrl: 'http://127.0.0.1:7076' })
const account = walletFromSeed(savedSeed).account()

const balance = await client.getBalance(account.address)
console.log(balance.balance) // confirmed Nano, exact decimal string

const sent = await client.send({
  account,
  to: recipientAddress,
  amount: '0.125', // Nano; alternatively use amountRaw: '1'
})
await client.waitForConfirmation(sent.hash)

const received = await client.receiveAll({
  account,
  representative: chosenRepresentative,
  maxBlocks: 100,
})
for (const transaction of received.transactions) {
  await client.waitForConfirmation(transaction.hash)
}

await client.changeRepresentative({
  account,
  representative: chosenRepresentative,
})

The client reads account state, builds a block, signs locally, requests work, verifies it, and submits once. Choose a representative for the first receive; existing accounts keep theirs unless you supply another. receive({ account, hash }) receives one confirmed incoming send. receiveAll processes a bounded snapshot and reports hasMore when that snapshot contains additional blocks.

In 0.2.0, use createClient() for BerryPay or pass rpcUrl as above to use your own node. BerryPay receives the RPC queries and signed blocks you send to it; local account creation and signing do not make network requests. The public service can apply rate limits and action restrictions.

Writes to the same account queue inside a client instance. Different accounts and independent reads run concurrently. Coordinate writers yourself when using multiple clients, processes, devices, or the granular prepare/publish methods.

status: 'submitted' means the node accepted the block. Use waitForConfirmation before treating it as settled. If submission fails, TransactionError.transaction retains the exact hash and signed block; inspect that hash before trying again. ReceiveAllError.completed preserves earlier successful submissions, and its cause identifies the failed step. Writes are never retried automatically.

A submission failure blocks further writes to that account with AccountBlockedError, including already queued writes. After reconciling the failed transaction with the node, call client.resumeAccount(address, transactionHash) to allow new writes; rejected writes are never replayed. A missing hash alone does not prove the node stopped processing it.

Full control, one step at a time

import {
  generateSeed,
  derivePrivateKey,
  derivePublicKey,
  deriveAddress,
  buildSendBlock,
  hashBlock,
  signHash,
  attachSignature,
  getWorkRoot,
  attachWork,
  createRpcClient,
} from 'nanopay'

const seed = generateSeed()
const privateKey = derivePrivateKey(seed, 0)
const publicKey = derivePublicKey(privateKey)
const address = deriveAddress(publicKey)

// Use a funded account's state here; a fresh account cannot send yet.
const rpc = createRpcClient('http://127.0.0.1:7076')
const state = await rpc.getAccountInfo(address)
if (!state) throw new Error('Receive funds into this account first')

const unsigned = buildSendBlock({
  account: address,
  previous: state.frontier,
  representative: state.representative,
  balanceRaw: state.balanceRaw,
  to: recipientAddress,
  amountRaw: '1',
})
const hash = hashBlock(unsigned)
const signature = signHash(hash, privateKey)
const signed = attachSignature(unsigned, signature)
const work = await rpc.generateWork(getWorkRoot(signed))
const block = attachWork(signed, work)
await rpc.publishBlock(block, 'send')

build* functions need no private keys. signBlock(unsigned, privateKey) combines hashing and signing. createSendBlock, createReceiveBlock and createChangeBlock combine building and signing, returning { hash, block }. None of those functions contacts a node. client.prepareSend, prepareReceive and prepareChangeRepresentative add ledger reads and return unsigned transactions for your own signing flow.

External signers implement { publicKey, sign(hash) }; pass that object as account. Signatures must use Nano's Ed25519-BLAKE2b, not standard Ed25519-SHA512. Work providers implement work({ root, threshold, signal }). You can use local WASM, a GPU service, or a separate work node. See signer and work examples.

Exact amounts

import { nanoToRaw, rawToNano } from 'nanopay/amounts'

nanoToRaw('1.25') // '1250000000000000000000000000000'
rawToNano('1') // '0.000000000000000000000000000001'

Amounts use strings, never floating-point numbers. amount means Nano; amountRaw and balanceRaw mean raw. One Nano is 10^30 raw. Fractional raw and uint128 overflow are rejected. General convert and Unit remain available; the historical Unit.nano means 10^24 raw, so use nanoToRaw for ordinary Nano amounts.

Payment links and live confirmations

import { createPaymentUri, parsePaymentUri, watchConfirmations } from 'nanopay'

const uri = createPaymentUri({
  address: account.address,
  amount: '1.25',
  label: 'Coffee',
})
const request = parsePaymentUri(uri)

for await (const event of watchConfirmations('ws://127.0.0.1:7078', {
  accounts: [account.address],
  signal: controller.signal,
})) {
  console.log(event.hash, event.amount)
}

Payment URIs encode raw as required by Nano. WebSocket notifications can repeat; deduplicate by hash. A disconnect, malformed message, or full buffer raises an error. Reconcile history and receivables through RPC after reconnecting. This stream has no automatic reconnect or persistent payment accounting.

Small imports and local work

Focused entry points avoid loading unrelated modules:

import { derivePrivateKey, deriveAddress } from 'nanopay/keys'
import { buildReceiveBlock, signBlock } from 'nanopay/blocks'
import { generateWork, RECEIVE_WORK_THRESHOLD } from 'nanopay/work'

const work = await generateWork(root, {
  threshold: RECEIVE_WORK_THRESHOLD,
  signal: AbortSignal.timeout(30_000),
  maxIterations: 10_000_000,
})
// A 16-character hex nonce, or null when the attempt range is exhausted.

Also available: nanopay/amounts, /mnemonic, /rpc, /payments, and /confirmations. Each supports ESM, CommonJS, and TypeScript. The keys entry point contains neither WASM nor the mnemonic word list.

The WASM engine compiles once per realm, isolates concurrent calls, and yields between batches. workerIndex and workerCount partition the nonce space; run those calls in separate Workers to use multiple cores. They do not create Workers. Mainnet work is probabilistic; use a GPU work service for sustained workloads. See measured performance and tradeoffs.

Scope and compatibility

The toolkit covers local accounts, native and mnemonic derivation, state blocks, signing, work, ledger reads, send/receive/change workflows, confirmation tracking and payment links. client.request(action, params) and rpc.request(...) expose every additional Nano RPC command supported and enabled by your node.

It does not run a consensus node, choose a representative, persist or encrypt secrets, manage exchange accounting, or provide a hardware-device transport. External signer hooks allow you to supply your own transport. New blocks use state format; RPC block reads also support historical block contents.

The original upstream function names and call signatures are preserved under nanopay/legacy, including deriveSecretKey and the hash-based signBlock({ hash, secretKey }). Main imports use privateKey consistently and distinguish signing a hash from signing a block. The old nanopay payment-wrapper API is replaced.

Development and license

npm ci
npm run check
npm run bench

Checks cover protocol vectors, workflows, browser/Worker execution, formatting, and installation into a clean npm project. Install a browser with npx playwright install chromium if Chrome is unavailable. npm run build:wasm rebuilds the checked-in binary with LLVM clang and wasm-ld; ordinary builds use the existing binary.

GPL-3.0-only. Based on nanocurrency-js. Source, build scripts, original notices, and bundled dependency licenses ship with the package. See LICENSE, NOTICE, and CHANGELOG.