Skip to content

Support for alternative x402 payment schemes (escrow / commerce) #75

@A1igator

Description

@A1igator

Summary

x402r adds escrow-backed refunds to x402 payments. The Ampersend SDK currently hardcodes scheme: "exact" at every layer — type definitions, adapters, wallets, and the hosted API schema. This makes it impossible for agents to pay for resources protected by alternative x402 schemes like "commerce" (escrow-based payments with refund eligibility).

We'd like to integrate x402r commerce-protected resources with Ampersend agents and are documenting the specific blockers below.

Blockers

1. Scheme dispatch is hardcoded to "exact"

Four places enforce the exact scheme:

Location File Issue
TreasurerSchemeClientV1/V2 x402/http/adapter.ts readonly scheme = "exact" — x402Client can't find a handler for other schemes
AccountWallet.createPayment() x402/wallets/account/wallet.ts Throws WalletError if requirements.scheme !== "exact"
SmartAccountWallet.createPayment() x402/wallets/smart-account/wallet.ts Same throw on non-exact
PaymentRequirements schema ampersend/types.ts Schema.Literal("exact") with annotation "starting with exact only for MVP" — the hosted treasurer rejects non-exact requirements before they reach the wallet

Suggested fix: Allow wrapWithAmpersend() to accept a Map<string, SchemeClient> (or similar registry) so callers can register additional scheme handlers. The x402 x402Client already has scheme dispatch built in — the wallet layer just needs to stop short-circuiting it. The API schema would also need to be relaxed for the hosted treasurer.

2. No ReceiveWithAuthorization signing path

The commerce/escrow scheme uses ERC-3009 ReceiveWithAuthorization instead of TransferWithAuthorization. This is required because the escrow contract must be msg.sender when calling receiveWithAuthorization() on the token contract — transferWithAuthorization allows anyone to submit, which breaks the escrow security model.

Currently the SDK only defines TransferWithAuthorization EIP-712 types and signing. There are zero references to ReceiveWithAuthorization in the codebase.

Suggested fix: Add ReceiveWithAuthorization as an alternate EIP-712 signing path, selected by the scheme handler. The struct fields are identical to TransferWithAuthorization — only the primaryType string differs.

3. v2 adapter silently coerces scheme

x402/http/v2-adapter.ts contains:

scheme: v2Req.scheme as "exact",

This casts any scheme value to "exact" at the type level rather than failing or passing it through. A "commerce" requirement would be silently mistyped.

Suggested fix: Remove the cast — pass scheme through as-is and let the scheme dispatch handle validation.

4. Python SDK has the same pattern

The Python SDK (smart_account/exact.py, cosigned.py) has equivalent hardcoding — ValueError on non-exact schemes. Same fixes would apply there.

What integration looks like

With these changes, an Ampersend EOA agent paying for a commerce-protected resource would look like:

import { wrapWithAmpersend } from "@ampersend_ai/ampersend-sdk";
import { commerceSchemeClient } from "@x402r/evm/commerce/client";

const client = wrapWithAmpersend(httpClient, {
  wallet: accountWallet,
  schemes: new Map([
    // exact scheme registered by default
    ["commerce", commerceSchemeClient],
  ]),
});

// Agent fetches commerce-protected resource — 402 → escrow payment → response
const response = await client.get("https://api.example.com/protected");

No changes are required on the x402r side. The extra field passthrough has been confirmed working — commerce-specific keys (operatorAddress, escrowAddress, tokenCollector, fee bounds) don't collide with Ampersend's extra usage.

Validated assumptions

  • Treasurer interface is scheme-agnostic (approves based on amount, not scheme) — only the API schema blocks non-exact
  • extra field is preserved throughout the pipeline with no stripping or collisions
  • MCP/A2A transports delegate to the wallet layer — no transport changes needed
  • x402 v2 protocol is natively supported

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions