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

@mrdn-finance/topup-client

v0.1.1

Published

TypeScript client for Meridian merchant top-ups

Readme

@mrdn-finance/topup-client

TypeScript client for funding a merchant balance through the Meridian top-up gateway. The client uses the payment options advertised by the gateway and does not require source-chain RPC endpoints.

Inside the Meridian monorepo it is the workspace package @meridian/topup-client.

Install

pnpm add @mrdn-finance/topup-client

One-call flow

An ethers v6 Wallet or Signer can be passed directly.

import { MeridianTopupClient } from "@mrdn-finance/topup-client";

const client = new MeridianTopupClient({
  baseUrl: "https://api-antseed.mrdn.finance",
  merchant: "antseed",
});

const result = await client.topup({
  // This can be AntSeed's generated buyer address. It does not need to be the
  // address holding the funds.
  buyer: antseedBuyerAddress,
  amount: "5",
  network: "arbitrum",
  signer: fundingWallet,
  wait: true,
});

console.log(result.topupId, result.state);

amount is expressed in token units and supports up to six decimal places. Integrations that already work in base units can pass amountBaseUnits instead.

When fundingWallet (payer A) differs from antseedBuyerAddress (buyer B), the client automatically binds the EIP-3009 nonce to B and the exact gateway quote. There is still only one wallet signature. The gateway rejects the payment if the buyer, merchant, source network, asset, amount, facilitator, destination, or validity window is changed after signing. Self top-ups remain compatible: omit buyer to credit the signer.

This makes the same call suitable for a CLI with a local signer or a payment portal with a connected browser wallet.

Browser wallets (wagmi)

The package accepts the small TopupSigner interface, so an integration does not need to depend on ethers:

import { MeridianTopupClient, type TopupSigner } from "@mrdn-finance/topup-client";

const signer: TopupSigner = {
  getAddress: async () => connectedAddress,
  signTypedData: async (domain, types, message) =>
    signTypedDataAsync({
      domain,
      types,
      primaryType: "TransferWithAuthorization",
      message,
    }),
};

await client.topup({
  buyer: antseedBuyerAddress,
  amount: "5",
  network: "base",
  signer,
});

AntSeed should obtain antseedBuyerAddress from its authenticated local node configuration, not from a user-editable URL alone. The funding wallet remains the payer and receives any Base-side refund.

Lower-level flow

const challenge = await client.createTopup({
  buyer: antseedBuyerAddress,
  amount: "5",
});

const option = client.selectPaymentOption(challenge, "arbitrum");
const payment = await client.sign({ option, signer: fundingWallet });
// Persist the complete payment, including payment.beneficiary.
const submitted = await client.submit({ payment });

const result = await client.waitForTopup(submitted.topupId, {
  initialStatus: submitted,
  onStatus: (status) => updateProgress(status.state),
});

challenge.paymentOptions contains the networks currently offered by the gateway. Each option includes its source chain ID, asset, amount, facilitator, and EIP-712 token domain.

onStatus runs after every successful poll, including the terminal response, so interfaces can show settlement, bridging, and merchant-credit progress as it happens.

If submission is interrupted, save and resubmit the same payment. Do not create a second signature while the first payment may still settle.

Crash-safe submission

topup() keeps the signed payment in memory, so integrations that must recover from a process crash or an ambiguous network failure should use the lower-level flow. Persist the complete SignedTopupPayment before calling submit(), then retry that exact payment until the gateway returns a status. Never generate a replacement signature while the original payment might have settled.

The signed payment and paymentHeader are bearer credentials. Do not log them, and if they are stored, use application-private storage with restrictive permissions. The integration is responsible for deciding when a saved payment can be removed.

Terminal outcomes

submit(), waitForTopup(), and topup() return a TopupStatus for every recorded outcome. They do not throw merely because the terminal state is unsuccessful. Callers must inspect status.state:

  • deposited means the merchant balance was credited.
  • refunded means the settled funds were returned to the payer.
  • failed means the top-up did not complete.
  • needs_review means operator investigation or recovery is required.

Treat only deposited as a successful top-up. Transport errors, malformed responses, rejected requests, aborts, and polling timeouts still reject with an error.

Configuration

const client = new MeridianTopupClient({
  baseUrl: "https://api-antseed.mrdn.finance",
  merchant: "antseed",
  pollIntervalMs: 2_000,
  timeoutMs: 10 * 60_000,
  allowedFacilitators: ["0x..."],
});

The client verifies that payment resources point to the configured gateway endpoint.

Facilitator pinning

The facilitator is the address every signed EIP-3009 authorization names as its recipient. A signed authorization is a bearer instrument, so the client never trusts the facilitator address a gateway response supplies at runtime: by default, payTo must be one of the Meridian facilitator addresses vendored in this package (MERIDIAN_FACILITATORS), and any challenge naming another address is rejected before signing.

  • Default — omit allowedFacilitators to pin to Meridian's published facilitators. Recommended for anything paying real funds.
  • Custom deployment — pass your own list of facilitator addresses (self-hosted gateway, local fork).
  • Disable — pass the literal "any" to trust the gateway response. Only appropriate in tests or throwaway environments.