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

@ldgr/client

v0.5.0

Published

`@ldgr/client` is the transport and verification SDK for backend services and trading systems. It reads authoritative LDGR Worker state, verifies exact payments, and submits envelopes signed by a caller-owned signer or KMS.

Downloads

275

Readme

LDGR client

@ldgr/client is the transport and verification SDK for backend services and trading systems. It reads authoritative LDGR Worker state, verifies exact payments, and submits envelopes signed by a caller-owned signer or KMS.

It does not create a hosted wallet, persist a private key, or replace the browser extension. Use @ldgr/wallet-sdk when a website needs an explicit user confirmation in the LDGR extension.

Service wallets and recovery keys

generateLocalWallet() creates caller-owned key material for a service wallet. Save its recovery key directly to your secret manager exactly once, then use loadLocalWallet() on service startup to recreate the signer. The recovery key is bearer private-key material: never log, commit, pass it in arguments or browser storage, send it to LDGR, or use it for a customer wallet.

import { generateLocalWallet, loadLocalWallet } from "@ldgr/client";

// Provision once. `secretStore` represents your secret-manager or HSM workflow.
const created = await generateLocalWallet({ ledgerId: 1 });
await secretStore.writeOnce("ldgr-service-wallet", created.recoveryKey);

// On each service startup, recover the same signer without printing the key.
const serviceWallet = await loadLocalWallet({
  ledgerId: 1,
  recoveryKey: await secretStore.read("ldgr-service-wallet"),
});

console.log(serviceWallet.address); // safe to identify the service wallet

This is for backend/Bun service wallets only. Websites should use @ldgr/wallet-sdk and an extension-confirmed customer wallet instead.

Send a native or user-issued asset

transfers.send() resolves the asset metadata, fetches the current nonce, builds and signs the transfer, submits it to the selected network, and retries once if another process consumed the nonce first. Use LEDRA_TESTNET_ASSET_ID / LEDRA_MAINNET_ASSET_ID from @ldgr/protocol for the native asset or pass a user-token code.

import { createLdgrClient } from "@ldgr/client";
import { LEDRA_MAINNET_ASSET_ID } from "@ldgr/protocol";

const client = createLdgrClient({ network: "mainnet" });
const result = await client.transfers.send({
  wallet: serviceWallet,
  asset: LEDRA_MAINNET_ASSET_ID,
  amount: "2.50",
  to: recipientAddress,
  memo: "Order 1234",
});

if (result.status === "settled") {
  console.log(result.transactionHash, result.fee, result.feeAsset);
} else {
  console.error(result.code, result.error);
}

Settlement failures return status: "failed"; they do not have a transaction hash or fee because the ledger rejected them before appending a transaction. Transport and unexpected response errors still throw.

Silent payments

silentPayments.send() accepts a reusable LDGR payment code and a LocalLdgrWallet. It signs and publishes the wallet's immutable sender-DH public key, fetches the asset nonce, derives a fresh one-time destination, and submits an ordinary transfer. A NONCE_MISMATCH causes one fresh derivation; an ambiguous transport failure retries the exact signed request instead.

import {
  createLdgrClient,
  deriveLocalSilentPaymentIdentity,
  loadLocalWallet,
} from "@ldgr/client";

const client = createLdgrClient({ network: "testnet" });
const senderWallet = await loadLocalWallet({
  ledgerId: 0,
  recoveryKey: await secretStore.read("ldgr-testnet-sender"),
});
// The receiver shares this code out of band; their recovery key never leaves
// their own wallet.
const receiver = deriveLocalSilentPaymentIdentity({
  ledgerId: 0,
  recoveryKey: await receiverSecretStore.read("ldgr-testnet-receiver"),
});
const result = await client.silentPayments.send({
  wallet: senderWallet,
  paymentCode: receiver.paymentCode,
  asset: "t0",
  amount: "2.50",
});

If two byte-identical transport attempts both remain ambiguous, SilentPaymentSubmissionUnknownError exposes the exact submission. Pass it to client.silentPayments.retry(error.submission); do not start a fresh send, which would use the next nonce and could duplicate a payment that already settled.

silentPayments.scan(after, limit) returns a bounded ascending page, its raw ledger-sequence nextAfter checkpoint, and moreAvailable. Matching requires the receiver scan secret and belongs in wallet code such as @ldgr/wallet-core, never on a server that does not own the recovery key. This LDGR-specific construction is not BIP-352-compatible and remains experimental. Wallet discovery is available on both ledgers, while reusable-code display, first-party sending, and private-output spending remain gated pending testnet-first operational testing and external cryptographic review.

import { createLdgrClient } from "@ldgr/client";

const client = createLdgrClient({ network: "testnet" });
const payment = await client.payments.verifyTransfer(transactionHash, {
  to: merchantAddress,
  asset: "t0",
  amount: "2.50",
});

Pass network: "testnet" | "mainnet" or the matching ledger id (0 / 1). The client selects https://tst.ldgr.ltd or https://ldgr.ltd by default; pass apiBase alongside network for a local deployment or proxy. Use public native asset id t0 on testnet and t1 on mainnet. Legacy dng remains accepted for compatibility, while raw authoritative transactions retain their signed wire code dng.

Only fulfil an order after payment.status === "confirmed", and store the transaction hash as the idempotency key. AMM quotes are estimates: pass an explicit minimum output in the signed swap payload and re-quote immediately before signing.

LDGR402 merchant verification

For a persisted LDGR402 requirement and the browser's LDGR402-Payment header, use the protocol-aware verifier:

const verification = await client.payments.verifyLdgr402(
  request.headers.get("LDGR402-Payment") ?? "",
  expectedRequirement,
);

if (verification.status === "confirmed") {
  // Atomically fulfill the challenge using verification.transactionHash.
}

verifyLdgr402 checks the proof's ledger and challenge, rejects expired requirements, and verifies the exact settled transfer through the authoritative Worker. The merchant still owns challenge persistence and idempotent fulfillment.