agentgate / tree / src/x402.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// Minimal helpers for x402 v2 HTTP headers.
// Spec: https://github.com/coinbase/x402 (PAYMENT-REQUIRED / PAYMENT-SIGNATURE / PAYMENT-RESPONSE,
// each a base64-encoded JSON document). These helpers only encode/decode; they never sign or settle.

export const HEADERS = {
  required: 'PAYMENT-REQUIRED',
  signature: 'PAYMENT-SIGNATURE',
  response: 'PAYMENT-RESPONSE',
  legacyPayment: 'X-PAYMENT', // x402 v1
};

export function encodeHeader(obj) {
  return Buffer.from(JSON.stringify(obj), 'utf8').toString('base64');
}

export function decodeHeader(value) {
  if (!value || typeof value !== 'string') return null;
  try { return JSON.parse(Buffer.from(value, 'base64').toString('utf8')); } catch { return null; }
}

/** Read the x402 payment payload a client sent (v2 PAYMENT-SIGNATURE, falling back to v1 X-PAYMENT). */
export function readPaymentPayload(req) {
  const h = getHeader(req, HEADERS.signature) || getHeader(req, HEADERS.legacyPayment);
  return decodeHeader(h);
}

/**
 * Best-effort extraction of the paying address from an x402 payment payload.
 * - EVM "exact" scheme: payload.authorization.from (EIP-3009)
 * - Other schemes/facilitators commonly expose `payer` or `from`.
 */
export function payerOf(payment) {
  if (!payment || typeof payment !== 'object') return null;
  const p = payment.payload || {};
  return p.authorization?.from || p.payer || p.from || payment.payer || null;
}

export function getHeader(req, name) {
  if (typeof req.get === 'function') return req.get(name) || undefined;
  const h = req.headers || {};
  return h[name.toLowerCase()] ?? h[name];
}

agentgate-source: code mirror on Cloudflare Pages. All repos