Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions specs/schemes/exact/scheme_exact_evm.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ This is implemented via one of two asset transfer methods, depending on the toke

| AssetTransferMethod | Use Case | Recommendation |
| :------------------ | :----------------------------------------------------------- | :--------------------------------------------- |
| **1. EIP-3009** | Tokens with native `transferWithAuthorization` (e.g., USDC). | **Recommended** (Simplest, truly gasless). |
| **2. Permit2** | Tokens without EIP-3009. Uses a Proxy + Permit2. | **Universal Fallback** (Works for any ERC-20). |
| **1. EIP-3009** | Tokens with native `transferWithAuthorization` (e.g., USDC). | **Standard** (EOA only, truly gasless). |
| **2. Permit2** | Tokens without EIP-3009 or **Smart Wallets**. | **Universal** (Works for any ERC-20 & Wallets). |

**Note**: EIP-3009 (AssetTransferMethod 1) typically only supports ECDSA (EOA) signatures and may fail for contract-based wallets (e.g., Coinbase Smart Wallet). If you are building for AI agents using CDP or Smart Wallets, use **Permit2**.

If no `assetTransferMethod` is specified in the payload, the implementation should prioritize `eip3009` (if compatible) and then `permit2`.

Expand Down
8 changes: 8 additions & 0 deletions typescript/.changeset/tough-balloons-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@x402/extensions": minor
"@x402/evm": minor
---

Added support for ERC-8004 Trustless Agents reputation extension in `@x402/extensions`. This enables AI agents to advertise their on-chain identity and reputation registry, supporting both EVM and Solana (SATI) standards. Includes server-side declaration helpers, client-side bidirectional reputation support, and an automated feedback tool for generating CAIP-220 compliant reputation signals from payment settlements.

Enhanced `@x402/evm` with automatic EIP-712 domain discovery for EIP-3009 tokens. This improves verification robustness for tokens with misconfigured domain parameters (like USDC on Base Sepolia) and provides better support for contract-based wallets.
63 changes: 63 additions & 0 deletions typescript/packages/extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,69 @@ Extension identifier constant (`"sign-in-with-x"`).
| `eip6492` | Counterfactual smart wallet verification |
| `siws` | Sign-In-With-Solana |

## ERC-8004 Reputation Extension

The ERC-8004 Reputation extension enables autonomous AI agents to build and verify on-chain reputation based on payment outcomes. It links the x402 payment protocol with the [ERC-8004: Trustless Agents](https://eips.ethereum.org/EIPS/eip-8004) standard.

### How It Works

1. **Discovery**: Servers advertise their on-chain agent identity in the `PaymentRequired` response.
2. **Identification**: Clients (other agents) can optionally provide their own identity in the `PaymentPayload`.
3. **Feedback**: After settlement, either party can submit reputation feedback to an ERC-8004 Reputation Registry (on EVM or Solana).
4. **Trust**: Reputation signals are weighted by payment proofs, ensuring high-integrity "proof-of-service" ratings.

### Server Usage

Declare your agent identity and reputation registry:

```typescript
import { declareReputation, reputationResourceServerExtension } from "@x402/extensions/8004-reputation";

const routes = {
"GET /service": {
accepts: [{ scheme: "exact", price: "$0.01", network: "eip155:8453", payTo }],
extensions: {
...declareReputation({
identity: {
agentRegistry: "eip155:8453:0xIdentityRegistryAddress",
agentId: "42" // NFT Token ID
},
reputationRegistry: "0xReputationRegistryAddress",
endpoint: "https://my-agent.com"
})
}
}
};

const resourceServer = new x402ResourceServer(facilitatorClient)
.registerExtension(reputationResourceServerExtension);
```

### Client Usage

Identify as an agent when making a payment:

```typescript
import { withClientReputation } from "@x402/extensions/8004-reputation";

// When server requests payment
const serverReputation = paymentRequired.extensions["8004-reputation"].info;

const payload = {
...paymentPayload,
extensions: {
...withClientReputation(serverReputation, {
agentRegistry: "eip155:8453:0xMyRegistry",
agentId: "99"
})
}
};
```

### `ERC8004_REPUTATION`

The extension identifier constant (`"8004-reputation"`).

## Troubleshooting

### Bazaar Extension Not Being Extracted
Expand Down
10 changes: 10 additions & 0 deletions typescript/packages/extensions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@
"types": "./dist/cjs/payment-identifier/index.d.ts",
"default": "./dist/cjs/payment-identifier/index.js"
}
},
"./8004-reputation": {
"import": {
"types": "./dist/esm/8004-reputation/index.d.mts",
"default": "./dist/esm/8004-reputation/index.mjs"
},
"require": {
"types": "./dist/cjs/8004-reputation/index.d.ts",
"default": "./dist/cjs/8004-reputation/index.js"
}
}
},
"files": [
Expand Down
34 changes: 34 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { ERC8004_REPUTATION, type AgentIdentity, type ReputationInfo } from "./types";

/**
* Creates client-side reputation info to be included in PaymentPayload.
* Allows the client (agent) to advertise their own identity to the server.
*
* @param serverInfo - The server's reputation info from the PaymentRequired response
* @param clientIdentity - The client's own agent identity
* @returns The consolidated reputation info
*/
export function createClientReputationInfo(
serverInfo: ReputationInfo,
clientIdentity: AgentIdentity,
): ReputationInfo {
return {
...serverInfo,
client: {
agentIdentity: clientIdentity,
},
};
}

/**
* Helper to wrap the reputation info for inclusion in PaymentPayload extensions.
*
* @param serverInfo - The server's reputation info from the PaymentRequired response
* @param clientIdentity - The client's own agent identity
* @returns An extension object containing the reputation info
*/
export function withClientReputation(serverInfo: ReputationInfo, clientIdentity: AgentIdentity) {
return {
[ERC8004_REPUTATION]: createClientReputationInfo(serverInfo, clientIdentity),
};
}
47 changes: 47 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/declare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { type DeclareReputationOptions, type ReputationExtension } from "./types";

/**
* Creates an ERC-8004 reputation extension declaration for x402 resource servers.
*
* @param options - Configuration options for the reputation declaration.
* @returns The reputation extension declaration for ERC-8004.
*/
export function declareReputation(options: DeclareReputationOptions): ReputationExtension {
return {
info: {
identity: options.identity,
reputationRegistry: options.reputationRegistry,
...(options.endpoint ? { endpoint: options.endpoint } : {}),
},
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
identity: {
type: "object",
properties: {
agentRegistry: { type: "string" },
agentId: { type: "string" },
},
required: ["agentRegistry", "agentId"],
},
reputationRegistry: { type: "string" },
endpoint: { type: "string" },
client: {
type: "object",
properties: {
agentIdentity: {
type: "object",
properties: {
agentRegistry: { type: "string" },
agentId: { type: "string" },
},
required: ["agentRegistry", "agentId"],
},
},
},
},
required: ["identity", "reputationRegistry"],
},
};
}
46 changes: 46 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/feedback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { z } from "zod";

/**
* CAIP-220 format for task reference (e.g., eip155:1:tx/0x...)
*/
export const TaskReferenceSchema = z.string().regex(/^[a-z0-9]+:[a-z0-9]+:tx\/[a-zA-Z0-9]+$/);

/**
* Proof of participation for verified interactions.
*/
export const ProofOfParticipationSchema = z.object({
/**
* Reference to the payment transaction.
*/
taskRef: TaskReferenceSchema,
/**
* Optional signature from the agent to prove service was delivered.
*/
agentSignature: z.string().optional(),
});

/**
* Feedback file structure following ERC-8004.
*/
export const FeedbackFileSchema = z.object({
agentRegistry: z.string(),
agentId: z.string(),
clientAddress: z.string(),
createdAt: z.string(), // ISO 8601
value: z.number(),
valueDecimals: z.number().min(0).max(18),
tag1: z.string().optional(),
tag2: z.string().optional(),
endpoint: z.string().optional(),
proofOfPayment: z
.object({
fromAddress: z.string(),
toAddress: z.string(),
chainId: z.string(),
txHash: z.string(),
})
.optional(),
participation: ProofOfParticipationSchema.optional(),
});

export type FeedbackFile = z.infer<typeof FeedbackFileSchema>;
77 changes: 77 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/feedbackTool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { type SettleResponse } from "@x402/core/types";
import { type ReputationInfo, ERC8004_REPUTATION } from "./types";
import { type FeedbackFile, FeedbackFileSchema } from "./feedback";

/**
* Options for creating a feedback file.
*/
export interface CreateFeedbackOptions {
/** The settlement response from the facilitator */
settleResponse: SettleResponse;
/** The server's reputation info (containing its identity) */
serverReputation: ReputationInfo;
/** The reputation score (0-100 or specific to valueDecimals) */
value: number;
/** Decimals for the value (default: 0) */
valueDecimals?: number;
/** Optional tags for filtering */
tag1?: string;
/** Optional tags for filtering */
tag2?: string;
/** Optional comment/detailed feedback */
comment?: string;
}

/**
* Helper to create a standardized ERC-8004 feedback file from an x402 settlement.
*
* This tool automates the extraction of network identifiers and transaction
* hashes into the CAIP-220 compliant taskRef format.
*
* @param options - Options for creating the feedback file.
* @returns A validated feedback file for standardized reporting.
*/
export function createFeedbackFile(options: CreateFeedbackOptions): FeedbackFile {
const { settleResponse, serverReputation, value, valueDecimals = 0, tag1, tag2 } = options;

// Construct CAIP-220 taskRef: {namespace}:{chainId}:tx/{hash}
// settleResponse.network is already CAIP-2 (e.g., eip155:8453)
const taskRef = `${settleResponse.network}:tx/${settleResponse.transaction}`;

const feedback: FeedbackFile = {
agentRegistry: serverReputation.identity.agentRegistry,
agentId: serverReputation.identity.agentId,
clientAddress: settleResponse.payer || "unknown",
createdAt: new Date().toISOString(),
value,
valueDecimals,
tag1,
tag2,
endpoint: serverReputation.endpoint,
proofOfPayment: {
fromAddress: settleResponse.payer || "unknown",
toAddress: "unknown", // Normally extracted from paymentRequirements if available
chainId: settleResponse.network.split(":")[1] || "unknown",
txHash: settleResponse.transaction,
},
participation: {
taskRef,
},
};

// Validate against schema
return FeedbackFileSchema.parse(feedback);
}

/**
* Extracts ERC-8004 identity from a PaymentRequired response.
*
* @param extensions - The extensions object from the PaymentRequired response.
* @returns The reputation info if present, otherwise undefined.
*/
export function getAgentReputation(
extensions: Record<string, unknown>,
): ReputationInfo | undefined {
const extension = extensions[ERC8004_REPUTATION] as { info: ReputationInfo } | undefined;
return extension?.info;
}
6 changes: 6 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from "./types";
export * from "./declare";
export * from "./server";
export * from "./client";
export * from "./feedback";
export * from "./feedbackTool";
18 changes: 18 additions & 0 deletions typescript/packages/extensions/src/8004-reputation/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { ResourceServerExtension } from "@x402/core/types";
import { ERC8004_REPUTATION } from "./types";

/**
* Resource server extension for ERC-8004 Reputation.
*
* This extension allows agents to advertise their ERC-8004 identity
* and reputation registry in 402 PaymentRequired responses.
*/
export const reputationResourceServerExtension: ResourceServerExtension = {
key: ERC8004_REPUTATION,

enrichPaymentRequiredResponse: async declaration => {
// Return the extension declaration as-is.
// The declaration is created via declareReputation() and contains info + schema.
return declaration;
},
};
Loading