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

@perkos/scheme-deferred

v1.1.1

Published

EIP-712 Voucher-based deferred payment verification utilities for x402 deferred scheme

Readme

@perkos/scheme-deferred

EIP-712 voucher-based deferred payment verification utilities for x402 deferred scheme. Provides signature verification, escrow balance checking, and voucher validation for off-chain payment aggregation.

Installation

npm install @perkos/scheme-deferred

Overview

The deferred scheme enables off-chain voucher signing with on-chain batch settlement:

  1. Client deposits funds into escrow contract
  2. Client signs vouchers (EIP-712) for each payment
  3. Facilitator verifies signatures and escrow balance
  4. Seller claims vouchers via escrow contract

Usage

Basic Verification

import { DeferredSchemeVerifier } from '@perkos/scheme-deferred';
import type { DeferredPayload, PaymentRequirements } from '@perkos/scheme-deferred';

const verifier = new DeferredSchemeVerifier({
  network: 'base',
  escrowAddress: '0x...',
  rpcUrl: 'https://mainnet.base.org' // optional
});

const payload: DeferredPayload = {
  voucher: {
    id: '0x...',
    buyer: '0x...',
    seller: '0x...',
    valueAggregate: '5000000',
    asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
    timestamp: '1735689600',
    nonce: '1',
    escrow: '0x...',
    chainId: '8453'
  },
  signature: '0x...'
};

const requirements: PaymentRequirements = {
  scheme: 'deferred',
  network: 'base',
  maxAmountRequired: '1000000',
  resource: '/api/service',
  payTo: '0x...',
  maxTimeoutSeconds: 3600,
  asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
};

const result = await verifier.verify(payload, requirements);

if (result.isValid) {
  console.log('Valid voucher from:', result.payer);
} else {
  console.error('Invalid:', result.invalidReason);
}

Create Voucher for Signing

import {
  generateVoucherId,
  createVoucherMessage,
  createEIP712Domain,
  VOUCHER_TYPES
} from '@perkos/scheme-deferred';
import { signTypedData } from 'viem/accounts';

// Generate unique voucher ID
const voucherId = generateVoucherId();

// Create voucher message
const message = createVoucherMessage(
  voucherId,
  '0x...buyer',        // buyer
  '0x...seller',       // seller
  '5000000',           // valueAggregate
  '0x...usdc',         // asset
  Math.floor(Date.now() / 1000), // timestamp
  '1',                 // nonce
  '0x...escrow',       // escrow
  8453                 // chainId
);

// Create EIP-712 domain
const domain = createEIP712Domain(
  8453,                // chainId
  '0x...escrow'        // escrow contract address
);

// Sign the voucher (client-side)
const signature = await signTypedData({
  domain,
  types: VOUCHER_TYPES,
  primaryType: 'Voucher',
  message,
  privateKey: '0x...'
});

Check Escrow Balance

const verifier = new DeferredSchemeVerifier({
  network: 'base',
  escrowAddress: '0x...'
});

const balance = await verifier.getEscrowBalance(
  '0x...buyer',
  '0x...seller',
  '0x...asset'
);

console.log('Available balance:', balance.toString());

Check Voucher Status

const claimed = await verifier.isVoucherClaimed(
  '0x...voucherId',
  1n // nonce
);

if (claimed) {
  console.log('Voucher already claimed');
}

Recover Signer from Voucher

const signer = await verifier.recoverSigner(voucher, signature);

if (signer && signer.toLowerCase() === voucher.buyer.toLowerCase()) {
  console.log('Valid signature from buyer');
}

API Reference

DeferredSchemeVerifier

class DeferredSchemeVerifier {
  constructor(config: DeferredSchemeConfig);

  // Verification
  verify(payload: DeferredPayload, requirements: PaymentRequirements): Promise<VerifyResponse>;
  validateVoucher(voucher: Voucher, requirements: PaymentRequirements): boolean;
  recoverSigner(voucher: Voucher, signature: Hex): Promise<Address | null>;

  // Escrow operations
  getEscrowBalance(buyer: Address, seller: Address, asset: Address): Promise<bigint>;
  isVoucherClaimed(voucherId: Hex, nonce: bigint): Promise<boolean>;

  // Getters
  getNetwork(): SupportedNetwork;
  getChainId(): number;
  getEscrowAddress(): Address;
  getEIP712Domain(): EIP712Domain;
}

DeferredSchemeConfig

interface DeferredSchemeConfig {
  network: SupportedNetwork;
  escrowAddress: Address;
  rpcUrl?: string;
  domainName?: string;      // default: "X402DeferredEscrow"
  domainVersion?: string;   // default: "1"
}

EIP712Domain

interface EIP712Domain {
  name: string;
  version: string;
  chainId: number;
  verifyingContract: Address;
}

SignatureParts

interface SignatureParts {
  v: number;
  r: Hex;
  s: Hex;
}

Utility Functions

generateVoucherId

Generate a random bytes32 voucher ID.

import { generateVoucherId } from '@perkos/scheme-deferred';

const voucherId = generateVoucherId();
// => '0x1234...abcd' (32 bytes hex)

createVoucherMessage

Create a voucher message object for EIP-712 signing.

import { createVoucherMessage } from '@perkos/scheme-deferred';

const message = createVoucherMessage(
  '0x...',      // id
  '0x...',      // buyer
  '0x...',      // seller
  '5000000',    // valueAggregate
  '0x...',      // asset
  1735689600,   // timestamp
  '1',          // nonce
  '0x...',      // escrow
  8453          // chainId
);

createVoucherTuple

Convert a Voucher object to a tuple format for contract calls.

import { createVoucherTuple } from '@perkos/scheme-deferred';

const tuple = createVoucherTuple(voucher);
// Use with escrow contract claimVoucher function

createEIP712Domain

Create an EIP-712 domain for voucher signing.

import { createEIP712Domain } from '@perkos/scheme-deferred';

const domain = createEIP712Domain(
  8453,           // chainId
  '0x...',        // escrowAddress
  'CustomName',   // optional domain name
  '2'             // optional version
);

parseSignature

Parse a signature into v, r, s components.

import { parseSignature } from '@perkos/scheme-deferred';

const { v, r, s } = parseSignature('0x...');

EIP-712 Type Definition

The voucher type definition used for EIP-712 signing:

import { VOUCHER_TYPES, VOUCHER_TYPE_DEF } from '@perkos/scheme-deferred';

// VOUCHER_TYPE_DEF structure:
[
  { name: "id", type: "bytes32" },
  { name: "buyer", type: "address" },
  { name: "seller", type: "address" },
  { name: "valueAggregate", type: "uint256" },
  { name: "asset", type: "address" },
  { name: "timestamp", type: "uint64" },
  { name: "nonce", type: "uint256" },
  { name: "escrow", type: "address" },
  { name: "chainId", type: "uint256" }
]

Escrow Contract ABIs

The package exports ABIs for interacting with the deferred escrow contract:

import {
  DEFERRED_ESCROW_ABI,
  DEFERRED_ESCROW_GET_BALANCE_ABI,
  DEFERRED_ESCROW_VOUCHER_CLAIMED_ABI,
  DEFERRED_ESCROW_CLAIM_VOUCHER_ABI,
  ERC20_BALANCE_ABI
} from '@perkos/scheme-deferred';

Available Functions

| ABI | Function | Description | |-----|----------|-------------| | DEFERRED_ESCROW_GET_BALANCE_ABI | getAvailableBalance(buyer, seller, asset) | Get escrow balance | | DEFERRED_ESCROW_VOUCHER_CLAIMED_ABI | voucherClaimed(voucherId, nonce) | Check if claimed | | DEFERRED_ESCROW_CLAIM_VOUCHER_ABI | claimVoucher(voucher, signature) | Claim voucher |

Verification Flow

The verify() method performs these checks in order:

  1. Voucher Validation: Checks escrow address, chainId, seller, amount, and asset
  2. Signature Recovery: Recovers signer using EIP-712 typed data
  3. Signer Verification: Ensures signer matches voucher buyer
  4. Claim Status: Checks if voucher already claimed on-chain
  5. Balance Check: Verifies sufficient escrow balance

Re-exported Types

import type {
  DeferredPayload,
  Voucher,
  VerifyResponse,
  PaymentRequirements,
  Address,
  Hex
} from '@perkos/scheme-deferred';

// V2 helper
import { getPaymentAmount } from '@perkos/scheme-deferred';

Related Packages

License

MIT