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

@gasfree-kit/pay

v0.3.0

Published

Drop-in React payment button component for chain-abstracted USDT checkouts — powered by gasfree-kit

Downloads

229

Readme

@gasfree-kit/pay

Drop-in React payment button for chain-abstracted USDT checkouts.

One component, one CSS import, one prop set. The modal handles preview, confirmation, cross-chain routing, and receipt automatically. Built on top of @gasfree-kit/react, @gasfree-kit/intent, and @gasfree-kit/bridge.

How It Works

 ┌──────────────────────────────────────────────────────────┐
 │                        Your app                          │
 │                                                          │
 │   <GasfreePay to="0x…" amount="50.00" onSuccess={…} />   │
 └────────────────────────────┬─────────────────────────────┘
                              │
                              v
 ┌──────────────────────────────────────────────────────────┐
 │                  @gasfree-kit/pay                        │
 │                                                          │
 │   ┌────────┐   ┌──────┐   ┌──────┐   ┌─────────┐         │
 │   │ button │ → │ open │ → │ plan │ → │ preview │ ┐       │
 │   └────────┘   └──────┘   └──────┘   └─────────┘ │       │
 │                                                  v       │
 │                            ┌──────────────────────────┐  │
 │                            │ confirm → execute → done │  │
 │                            └──────────────────────────┘  │
 │                                                          │
 │  Flow state machine · idempotency · timeout · onEvent    │
 └────────┬──────────────────┬──────────────────┬───────────┘
          │                  │                  │
          v                  v                  v
 ┌────────────────┐ ┌────────────────┐ ┌────────────────────┐
 │ @gasfree-kit/  │ │ @gasfree-kit/  │ │ React context      │
 │ react          │ │ intent         │ │ (signer, address)  │
 │                │ │                │ │                    │
 │ useGasfree     │ │ planIntent     │ │ from               │
 │ useExecute     │ │ executeIntent  │ │ <GasfreeProvider>  │
 │ Intent         │ │   ↓            │ │                    │
 │                │ │ @gasfree-kit/  │ │                    │
 │                │ │ bridge (auto)  │ │                    │
 └────────────────┘ └────────────────┘ └────────────────────┘

The modal walks the user through five phases — preview → confirm → executing → success / error — driven by an internal state machine. Cross-chain routes auto-bridge via @gasfree-kit/intent's planner; signing comes from whatever signer (passkey by default, seedPhrase as alternate) the surrounding <GasfreeProvider> is configured with.

What you get

  • Drop-in <GasfreePay /> component — button + modal flow, no other UI work required
  • Cross-chain auto-routing — if the recipient is on a different chain than the user's USDT balance, pay bridges automatically (Base → Arbitrum, etc.)
  • Themed defaults + CSS variable overrides — looks good out of the box, customizable via --gasfree-* variables
  • Accessibility built inrole="dialog", focus trap, ESC dismissal, aria-live step updates, keyboard-navigable
  • Idempotent by design — auto-generates an idempotency key per session; double-clicks and remounts can't double-charge
  • Signer-agnostic — uses whatever signer the surrounding <GasfreeProvider> is configured with (typically passkey)

Install

pnpm add @gasfree-kit/pay @gasfree-kit/react @gasfree-kit/core

Your package manager will prompt you to install the required peer dependencies (react, react-dom, @tanstack/react-query).

Quick start

import { GasfreeProvider } from '@gasfree-kit/react';
import { GasfreePay } from '@gasfree-kit/pay';
import '@gasfree-kit/pay/styles.css';

function Checkout() {
  return (
    <GasfreeProvider
      config={{
        evm: {
          chains: ['base', 'arbitrum'],
          signer: { type: 'passkey', credential },
          bundlerUrl: process.env.BUNDLER_URL!,
          paymasterUrl: process.env.PAYMASTER_URL!,
          isSponsored: true,
          sponsorshipPolicyId: process.env.SPONSORSHIP_POLICY_ID!,
        },
      }}
      address={userAddress}
    >
      <GasfreePay
        to="0xMerchant..."
        amount="50.00"
        destinationChain="arbitrum"
        metadata={{ orderId: 'inv-42' }}
        onSuccess={(receipt) => console.log('paid', receipt)}
      />
    </GasfreeProvider>
  );
}

That's it. One component renders the button; clicking it opens the modal and walks the user through preview → confirm → execute → receipt.

Props

| Prop | Type | Required | Description | | ------------------ | ---------------------------------- | -------- | ---------------------------------------------------------------------- | | to | string | yes | Recipient EVM address (0x-prefixed, 40 hex chars). | | amount | string | yes | Human-readable amount, e.g. "50.00". | | token | "USDT" | no | Token to transfer. Defaults to "USDT". | | destinationChain | EvmChain | no | Preferred destination chain. Auto-routed when omitted. | | metadata | Record<string, unknown> | no | App-specific metadata stored alongside the payment (invoice id, etc.). | | buttonLabel | string | no | Custom button text. Defaults to "Pay {amount} {token}". | | theme | "light" \| "dark" \| "auto" | no | Theme override. Defaults to "auto" (follows prefers-color-scheme). | | className | string | no | Extra class on the root button + modal. | | onSuccess | (receipt: IntentReceipt) => void | no | Fired on terminal success. | | onError | (error: Error) => void | no | Fired on terminal failure. | | onCancel | () => void | no | Fired when the user dismisses the modal before completion. |

Theming

The component scopes its styles under a [data-gasfree-pay] root with data-theme set to light, dark, or auto-detected. Override any of the CSS variables on an ancestor or on the root itself:

[data-gasfree-pay] {
  --gasfree-primary: #6c5ce7; /* button & accent color */
  --gasfree-primary-foreground: #fff;
  --gasfree-radius: 8px; /* corner rounding */
  --gasfree-bg: #fafafa; /* modal background */
  --gasfree-fg: #111; /* modal foreground */
  --gasfree-muted: #888; /* secondary text */
  --gasfree-border: #ddd;
  --gasfree-success: #16a34a;
  --gasfree-error: #dc2626;
  --gasfree-font: 'Inter', sans-serif;
  --gasfree-spacing: 8px;
}

Full token reference:

| Variable | Default (light) | Purpose | | ------------------------------ | --------------- | -------------------------------- | | --gasfree-primary | #0a84ff | Button background, accents | | --gasfree-primary-foreground | #ffffff | Button text | | --gasfree-radius | 12px | Border radius for button + modal | | --gasfree-font | system stack | Font family | | --gasfree-bg | #ffffff | Modal background | | --gasfree-fg | #0f0f10 | Modal foreground text | | --gasfree-muted | #6b6b70 | Secondary text | | --gasfree-border | #e5e5e8 | Modal + step indicator borders | | --gasfree-success | #16a34a | Success state accent | | --gasfree-error | #dc2626 | Error state accent | | --gasfree-spacing | 8px | Base spacing unit |

For dark mode, override the same variables under [data-gasfree-pay][data-theme='dark'].

Cross-chain routing

If the destination chain has insufficient USDT, pay auto-bridges from another chain using @gasfree-kit/intent's planner. The preview shows the bridge route explicitly:

To              0xMerc…0123
Amount          50.00 USDT
Route           Base → Arbitrum
Estimated fee   ~$0.40
Estimated time  ~120s

Bridge progress surfaces as a separate step in the executing state. No additional configuration required — just declare your chains in the provider config.

Accessibility

  • Modal renders with role="dialog", aria-modal="true", and aria-labelledby pointing at the title
  • Focus trap (Tab / Shift+Tab cycle inside the dialog)
  • ESC closes the modal (suppressed during signing/submission)
  • Initial focus on the Confirm button when the preview opens
  • Step indicator uses aria-live="polite" so screen readers announce transitions
  • All interactive elements are keyboard-reachable
  • Color contrast meets WCAG AA on the default token set

Idempotency

Pay auto-generates an idempotency key per session. The underlying bridge layer uses this key to deduplicate retries — a double-click on Confirm, a network blip during submission, or a remount in the middle of the flow can't cause a double-submit.

If you want server-side persistence, supply your own idempotencyStore via the bridge layer (see @gasfree-kit/bridge README).

Advanced

Lower-level hooks are exported for integrators who want to roll their own UI but reuse pay's flow logic:

  • usePayFlow() — the state machine
  • usePayPreview() — wraps intent.planIntent and returns a PayPreview + plan

These are not required for the standard <GasfreePay /> usage.

License

MIT