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

@gloamtrade/mppx-gloam

v0.4.1

Published

Private payments for the Machine Payments Protocol (MPP). The "gloam" payment method for mppx: a charge settles as a shielded transfer through the Gloam pool, sealed to the payee's receive tag and swept before access, so the public sees a shielded transfe

Readme

@gloamtrade/mppx-gloam

Private payments for the Machine Payments Protocol (MPP).

MPP is HTTP 402 done properly: a server answers WWW-Authenticate: Payment …, the client pays and retries with Authorization: Payment …, and gets a Payment-Receipt. Every method so far (tempo, evm, stripe, solana) settles in public, so the ledger shows which agent paid which service, how much, how often.

This package adds the gloam method. A charge is paid with a private transfer inside a Gloam shielded pool on Tempo, Robinhood Chain, Base or Ethereum, on mainnet (beta) or testnet:

  • the payment note is sealed to the payee's receive tag, so only the payee can open it;
  • the server checks it binds the price, that it is the payment output of a Transferred event in the official pool, and that the credential is bound to this exact challenge;
  • the server sweeps the payment into a fresh note only it knows, and serves only after that sweep confirms (until then the payer, who created the note, could spend it back);
  • the public chain sees shielded transfers: a nullifier and two commitments each. No amount, no asset, no payer, no payee.

Spec: docs/mpp/draft-gloam-charge-00.md.

Server (mppx)

import { Mppx } from "mppx/server";
import { gloam } from "@gloamtrade/mppx-gloam/server";
import { gloamChargeChainFromClient } from "@gloamtrade/mppx-gloam/core";
import { artifactProver, circuitArtifactUrls, mainnetNetwork, relayIntent } from "@gloamtrade/sdk";

const tempo = mainnetNetwork("tempo")!;                   // Tempo mainnet; GLOAM_NETWORKS.tempo for the testnet
const mppx = Mppx.create({
  secretKey: process.env.MPP_SECRET_KEY!,
  methods: [
    gloam({
      network: "tempo-mainnet",                           // USDC.e by default; "tempo" for the testnet (PathUSD)
      receiveKey,                                         // from generateReceiveKey(), stored server side
      chain: gloamChargeChainFromClient(publicClient, { pool: tempo.pool, fromBlock: tempo.deployBlock }),
      prove: artifactProver(circuitArtifactUrls("transfer", tempo.chainId)), // final keys on mainnet
      submit: (intent) => relayIntent(intent),            // or your own wallet: writeContract(...)
      beforeSubmit: (freshNote) => saveNote(freshNote),   // the money: persist before the sweep goes out
    }),
  ],
});

export async function handler(request: Request) {
  const r = await mppx.charge({ amount: "0.01" })(request);
  if (r.status === 402) return r.challenge;
  return r.withReceipt(Response.json({ answer: 42 }));
}

With Hono: import { Mppx } from "mppx/hono" and app.get("/answer", mppx.charge({ amount: "0.01" }), handler).

Options: modes: ["push"] or ["pull"] to accept one submission mode (default both), replay for a shared replay store when several instances settle (default in memory), pools only for a private deployment you trust.

Client (mppx)

import { Mppx } from "mppx/client";
import { gloam } from "@gloamtrade/mppx-gloam/client";
import { artifactProver, circuitArtifactUrls, relayIntent, TEMPO_USDCE, TEMPO_MAINNET_CHAIN_ID } from "@gloamtrade/sdk";

const mppx = Mppx.create({
  polyfill: false,
  methods: [
    gloam({
      getNote: ({ amountWei, currency }) => wallet.noteCovering(amountWei, currency), // { secret, amountWei, path }
      prove: artifactProver(circuitArtifactUrls("transfer", TEMPO_MAINNET_CHAIN_ID)), // the keys of the chain you pay on
      mode: "auto",                                       // pull when offered, else push
      submit: (intent) => relayIntent(intent),            // only needed for push
      policy: { maxAmountWei: 50_000n, currencies: [TEMPO_USDCE], chainIds: [TEMPO_MAINNET_CHAIN_ID] },
      beforeSubmit: (built) => wallet.keep(built.changeNote),
    }),
  ],
});

const res = await mppx.fetch("https://api.example.com/answer");

The client refuses, before proving anything, a pool that is not Gloam's for that chain, a recipient that is not a receive tag, and anything outside policy.

Proofs must be made with the keys of the chain the payment settles on: the trusted setup's final keys on mainnet (Tempo 4217, Robinhood Chain 4663), the dev keys on testnet. circuitArtifactUrls("transfer", chainId) from the SDK returns the right files. A client that pays on more than one chain picks the prover per challenge. In Node, snarkjs reads local files only: download the files first, check them against CIRCUIT_SHA256, and pass their paths to artifactProver.

Without an MPP library

@gloamtrade/mppx-gloam/core has the whole method with no mppx dependency:

import { createGloamPaywall, createGloamChargeCredential, parsePaymentChallenges, isGloamChargeChallenge } from "@gloamtrade/mppx-gloam/core";

// Server: same handler shape as mppx.
const paywall = createGloamPaywall({ secretKey, server: { receiveKey, chain, prove, submit, beforeSubmit: (freshNote) => saveNote(freshNote) } });
const r = await paywall.charge({ amount: "0.01" })(request);

// Client.
const [challenge] = parsePaymentChallenges(res.headers.get("www-authenticate")).filter(isGloamChargeChallenge);
const { authorization } = await createGloamChargeCredential({ challenge, note, prove, mode: "pull" });
await fetch(url, { headers: { Authorization: authorization } });

It also exports the Payment scheme codec (challenges, credentials, receipts, the HMAC challenge id, byte compatible with mppx), validateGloamCharge (read-only checks) and settleGloamCharge (sweep and receipt).

Push or pull

| | push | pull | |---|---|---| | Who broadcasts the payer's transfer | the payer (its wallet or the Gloam relay) | the server | | Payer needs gas / a wallet on chain | yes (unless relayed) | no | | If the server refuses | the value already moved (sealed to the payee) | nothing moved | | What the server learns | the payer's sending address, unless relayed | nothing about the payer's wallet |

In pull mode the server checks the payer's transfer against the pool before it submits anything: gloamChargeChainFromClient makes an eth_call of transfer() (transferWouldLand), and a transfer the pool would refuse is refused with nothing sent. A custom GloamChargeChain can set transferWouldLand the same way (transferCheckFromCall builds it from any call function); without it the transfer is submitted as before.

Networks

| network | Chain | Default currency | Keys | | --- | --- | --- | --- | | "tempo-mainnet" | Tempo mainnet 4217 | USDC.e (also pathUSD, USDT0, OUSD) | Final ceremony keys | | "robinhood-mainnet" | Robinhood Chain mainnet 4663 | USDG (also GLOAM) | Final ceremony keys | | "tempo" | Tempo Moderato 42431 | PathUSD | Dev keys | | "robinhood" | Robinhood Chain testnet 46630 | ETH | Dev keys |

The default network is still "tempo" (the testnet), as in 0.0.x. Official pools come from the SDK this package is built with: a mainnet appears once that SDK has its pool, and a challenge naming any other pool is refused on both sides.

Base: "base" (Base Sepolia 84532, test USDC by default, also EURC and ETH, on the final keys) works with SDK 0.3.0, which has its pool. "base-mainnet" (Base 8453, USDC by default, also EURC, USDT and ETH), live since 26 October 2026, works when built with SDK 0.4.1 or later, which has its pool; built with an older SDK it is refused with a plain error.

Ethereum too (0.3.0): "ethereum-mainnet" (Ethereum 1, USDC by default, also USDT, USDG, PYUSD, EURC and ETH), live since 26 October 2026, works the same way with SDK 0.4.1 or later. Its testnet is Ethereum Sepolia, below.

Ethereum Sepolia: "ethereum" (11155111, test USDC by default, also USDG, PYUSD, EURC and ETH, on the final keys) is known to 0.3.0 and works with SDK 0.4.0, which has its pool (deployed 25 October 2026). Built with an older SDK it is refused with a plain error.

The chain reader must say which chain it reads

Gloam's vault has one address on every chain, and ETH is 0x0 on all of them. A server pricing a charge on one chain with a reader pointed at another (Base mainnet 8453 and Base Sepolia 84532, Ethereum 1 and Ethereum Sepolia 11155111) would otherwise see the other chain's payments as real.

  • gloamChargeChainFromClient asks the RPC for its chain id once (eth_chainId).
  • A charge is validated and settled only when that id is the charge's. Otherwise it gets a 402.
  • A custom GloamChargeChain should set chainId() the same way. Without it nothing can be checked, so set it on every Base and Ethereum chain especially.

Status

Mainnet (beta) on Tempo, Robinhood Chain, Base and Ethereum (Base and Ethereum need a build with SDK 0.4.1 or later), payments only, with the trusted setup's final keys and beta deposit limits on the pools; reviewed internally before launch, and Kann Audits reviewed the vault contracts (report, 1 November 2026: gloam.trade/security) and found no Critical, High or Medium issues. The testnets stay up.

Tests

pnpm --filter @gloamtrade/mppx-gloam test

Runs against an in-memory pool that applies the pool's transfer rules: wire codec (spec HMAC vectors, mppx interop both ways), push and pull end to end, replay, a credential lifted onto another challenge, wrong keys, amounts, assets, pools and events, a payer who spends the payment back, lost sweep receipts, concurrency, the Fetch paywall, and Mppx.create on both sides.