Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

x402-verify-client-base

Client-side verification SDK for x402 payment headers on Base (L2 on Ethereum). Built with TypeScript and ethers v6, compatible with Node.js and modern browsers.

Features

  • ECDSA signature verification via ethers.verifyMessage()
  • Cross-platform Base64 decoding (Browser atob() / Node Buffer)
  • EIP-55 checksum address normalization with ethers.getAddress()
  • Replay protection hooks: maxAgeMs (timestamp window) and nonceSeen (nonce reuse)
  • Strict typings with PaymentHeader and a minimal, ergonomic API

Installation

npm install x402-verify-client-base

Quick Start

import { verifyPayment } from "x402-verify-client-base";

// Base64-encoded JSON header conforming to the PaymentHeader interface
const header = "<Base64 PaymentHeader JSON>";

const verified = verifyPayment(
  header,
  "0.001", // expected amount (ETH, decimal string)
  "0xRecipientAddress",
  { maxAgeMs: 60_000, nonceSeen: () => false }
);

console.log("Verified:", verified);

API Reference

verifyPayment(paymentHeader: string, expectedAmount: string, expectedAddress: string, options?: { maxAgeMs?: number; nonceSeen?: (nonce: string) => boolean }): boolean

Verifies an x402 payment header by:

  • Decoding Base64 JSON (browser atob() or Node Buffer.from(..., "base64"))
  • Building the signed message including optional nonce and timestamp
  • Recovering the signer using ethers.verifyMessage()
  • Normalizing addresses via ethers.getAddress()
  • Comparing amounts as wei using ethers.parseUnits(amount, 18)
  • Applying replay checks with options.maxAgeMs and options.nonceSeen

Returns true only if all checks pass; otherwise false.

Types

export interface PaymentHeader {
  amount: string;       // decimal ETH string (e.g., "0.001")
  to: string;           // recipient address
  from: string;         // signer (sender) address
  signature: string;    // hex string, 65-byte ECDSA signature (130 hex chars)
  nonce?: string;       // optional, for replay protection
  timestamp?: number;   // optional, ms since epoch
}

Verification Workflow

  1. Decode: Base64 → UTF‑8 JSON using atob() (browser) or Buffer (Node).
  2. Validate: Ensure required fields exist and types are correct.
  3. Build Message: Include amount, to, from, and optionally nonce/timestamp.
  4. Recover Signer: ethers.verifyMessage(message, signature).
  5. Normalize Addresses: ethers.getAddress() for EIP‑55 checksum normalization.
  6. Compare Amounts: parseUnits(payment.amount, 18) === parseUnits(expectedAmount, 18).
  7. Replay Checks: Reject if timestamp is older than maxAgeMs, or if nonceSeen(nonce) returns true.

Cross‑Platform Notes

  • Base64 decoding: Uses atob() in browsers and Buffer.from(header, "base64").toString("utf8") in Node.
  • Address normalization: ethers.getAddress() produces checksummed addresses for consistent comparisons.
  • Amount verification: Convert decimal ETH strings to wei via ethers.parseUnits(..., 18) and compare numerically.

Testing

Run the test suite (Vitest):

npm run test

Scenarios covered: valid signature, wrong amount, wrong recipient, and invalid signature.

Requirements

  • Node.js 18+ or a modern browser runtime
  • ethers v6
  • TypeScript 5+

Contact

License

MIT — see the separate LICENSE file for details.

About

Client-side verification SDK for x402 payment headers on Base (L2 on Ethereum)

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages