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

@bbridge/authorizer

v0.3.0

Published

Reference implementation of the bbridge Authorizer service core: deposit confirmation with vault UTXO quarantine, and withdrawal postage co-signing

Readme

@bbridge/authorizer

Reference implementation of the bbridge Authorizer service core, per docs/authorizer-spec.md and docs/SPEC.md. Two pipelines: deposit confirmation with vault UTXO quarantine, and withdrawal postage co-signing. Plus the discretionary-issuance headroom arithmetic that bounds them.

Transport-free and storage-free. No HTTP, no database, no key material, no chain client — a host application supplies all of that behind the ports in ports.ts. That is what keeps the quarantine state machine testable against plain fakes, and what lets the same core run against whatever a deployment already operates.

Status

Functional and tested: npm test compiles and runs 82 passing cases against in-memory fakes. Covers the deposit state machine and every one of its edges, authorization message construction and signing, headroom reservation and reconciliation, burn OP_RETURN parsing, and postage co-signing including each refusal path. Does not include a scheduler, an HTTP layer, or any port implementation — see Ports below.

Installation

npm install @bbridge/authorizer

@hansekontor/checkout-components is a peer dependency. It is not bundled deliberately: this package and its host exchange that library's own objects (Script, TX, Coin), and a second copy in the tree breaks instanceof across the boundary. Install one copy and let both resolve to it.

What this package is responsible for

Four obligations, from authorizer-spec.md §2. Each exists because nothing else in the system covers it:

Vault UTXO quarantine. A vault UTXO named in a confirmation must not exist on XEC until that confirmation is final on Ethereum (SPEC.md §III.7). While it exists, the deposit's refund path is open on one chain and its mint is live on the other. states.ts enforces this structurally rather than by convention — assertTransition refuses any edge that would let a funding transaction reach the chain early, so a future edit cannot route around it by accident.

SLP burn validity. SLP is an overlay protocol with no consensus validation, so a transaction declaring a billion tokens while spending one confirms on XEC perfectly normally. BridgeLock.release() pays out the quantity the OP_RETURN declares and has no way to check it. The Authorizer's postage signature is the only thing in the entire system that attests a burn is real, which is why SlpValidator must fail closed and why this package refuses rather than assumes on every ambiguous verdict.

Issuance headroom. If a deployment enables minting that no Ethereum deposit backs, the bound on it lives only here. issuance/headroom.ts treats an atomic compare-and-decrement as the check itself; reading a balance and then deciding is not equivalent and is not safe.

Headroom is collateral − supply − burned-but-unreleased. The third term is not a refinement: a withdrawal's burn and its release() settle at different moments, release() is user-submitted so the burner picks the gap, and collateral − supply alone reads that gap as free headroom equal to the burn. Issuing against it before submitting the release proof leaves supply backed by less collateral, with every individual step valid.

Postage deduplication. Two concurrent honest stamps for one burn declaration are sufficient for a second full release (SPEC.md §IV.6). The claim is therefore taken before signing, never after.

Ports

The host implements these. Hex conventions are fixed in ports.ts because getting them wrong is silent: Ethereum values are 0x-prefixed, eCash txids are the conventional big-endian display form without a prefix, hash160s are 40 bare hex chars.

| Port | Responsibility | |---|---| | EthereumReader | Block height, logs, deposit state, locked collateral | | EthereumWriter | Nonce reservation and confirmDeposit submission | | EcashClient | UTXO lookup, broadcast, transaction lookup | | SlpValidator | Burn validity and circulating supply — part of the trusted computing base | | Signer | Signs 32-byte digests. Never sees a transaction, holds no funds, so it can sit behind a KMS or HSM | | Store | Durable state. Three methods carry atomicity requirements the spec calls out | | ReserveWallet | Builds vault funding transactions. Must not broadcast them | | StampSource | Withdrawal postage. One coin covering a whole fee, not several fixed denominations | | Minter | Optional convenience minting | | Logger | — |

BroadcastRejectedError is the one class a host must throw rather than merely implement: it distinguishes a definitive node refusal from an unknown outcome, and that distinction decides whether releasing a dedup claim is safe.

For a worked set of implementations against a bcash node, MariaDB and ethers, see lotto-api's lib/bridge/.

Usage

import { tick, coSignPostage, validateConfig } from '@bbridge/authorizer'

validateConfig(config)

// Deposit side: one pass over every actionable deposit. Safe to call on an interval;
// CONFIRMED_FINAL is drained first, because that broadcast is the only edge whose
// failure cannot be undone.
await tick({ config, mintFeeSats, eth, ethWriter, ecash, reserve, signer, store, minter, logger })

// Withdrawal side: validate a user-submitted burn, stamp it, broadcast it.
const { txid, burnQuantity } = await coSignPostage(
  { config, ecash, slp, stamps, store, logger },
  rawTxHex
)

coSignPostage throws PostageError with a code on every refusal (MALFORMED, WRONG_DEPLOYMENT, BAD_BURN_INPUT, BAD_BURN_OUTPUTS, SCHNORR_SIGNATURE, UNKNOWN_PREVOUT, SLP_INVALID, BELOW_MINIMUM, ALREADY_STAMPED, NO_STAMP_AVAILABLE, REJECTED). None of them leak anything the caller did not already submit, so they are safe to report back to a user.

A burn must carry exactly one input, and at most two outputs. release() reads the burn from inputs[0] and the postage from inputs[1] by index, so the stamp has to land at index 1 — a second token input would push it to index 2 and leave the contract checking the requester's own input for the Authorizer's signature. A holder consolidating dust UTXOs does so in a separate transaction first, which needs no postage: each 546-sat input adds about 148 bytes of fee but brings 546 sats with it.

The output limit is the BURN OP_RETURN plus one change output. release() parses the whole raw transaction on chain — it walks every output copying each script byte by byte, then serialises the output set again for the sighash — so gas grows with the transaction while the payout does not. Nothing in the contract bounds it, and by the time a burner discovers their transaction is too expensive to release, the tokens are already destroyed.

It returns a txid, never the raw stamped bytes. The service broadcasts, and the completed transaction never leaves it unbroadcast — a stamp over a burn XEC would reject is enough for a full release under a self-mined header, and consensus rejecting it at the node is what keeps it out of an attacker's hands (SPEC.md §IV.2.1).

Deposit state machine

OBSERVED -> DEPTH_MET -> FUNDING_PREPARED -> AUTHORIZED -> CONFIRM_SENT
         -> CONFIRMED_FINAL -> FUNDING_BROADCAST -> MINTED

with ABANDONED_REFUNDED and HALTED as terminals. Crash recovery is defined per edge (authorizer-spec.md §4.3), which is why each has its own independently reachable step function.

Two invariants are worth stating outright:

  • The funding transaction is broadcast in exactly one place, advanceConfirmedFinal. Nothing else calls ecash.broadcast on it.
  • The Ethereum nonce is reserved and persisted before the confirmation is sent. A transaction hash does not exist until after sending, leaving a crash window nothing could otherwise interpret; the nonce is knowable in advance, so it is what recovery resolves against.

Known limitations

  • No scheduler. tick is a single pass; the host decides cadence.
  • No HTTP layer.
  • Reorg handling below finalityDepth is the host's to configure, not this package's to detect.
  • getCirculatingSupply is required by headroom reconciliation but not every indexer can answer it; a deployment that cannot should leave discretionary issuance off, which is the default.

Testing

npm test        # compile + run
npm run build   # compile only