uvd-x402-sdk 2.16.1 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -8
- package/dist/adapters/index.d.mts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +103 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +103 -0
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/backend/index.d.mts +393 -3
- package/dist/backend/index.d.ts +393 -3
- package/dist/backend/index.js +448 -0
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +445 -1
- package/dist/backend/index.mjs.map +1 -1
- package/dist/{index-BYsQM8ga.d.ts → index-BDLgm-Sg.d.mts} +4 -3
- package/dist/{index-B_reIs-L.d.mts → index-BE5cH7oS.d.mts} +4 -2
- package/dist/{index-B_reIs-L.d.ts → index-BE5cH7oS.d.ts} +4 -2
- package/dist/{index-1CWNFuXP.d.mts → index-DDrvK4em.d.ts} +4 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -0
- package/dist/index.mjs.map +1 -1
- package/dist/providers/algorand/index.d.mts +1 -1
- package/dist/providers/algorand/index.d.ts +1 -1
- package/dist/providers/algorand/index.js +103 -0
- package/dist/providers/algorand/index.js.map +1 -1
- package/dist/providers/algorand/index.mjs +103 -0
- package/dist/providers/algorand/index.mjs.map +1 -1
- package/dist/providers/evm/index.d.mts +1 -1
- package/dist/providers/evm/index.d.ts +1 -1
- package/dist/providers/evm/index.js +103 -0
- package/dist/providers/evm/index.js.map +1 -1
- package/dist/providers/evm/index.mjs +103 -0
- package/dist/providers/evm/index.mjs.map +1 -1
- package/dist/providers/near/index.d.mts +1 -1
- package/dist/providers/near/index.d.ts +1 -1
- package/dist/providers/near/index.js +103 -0
- package/dist/providers/near/index.js.map +1 -1
- package/dist/providers/near/index.mjs +103 -0
- package/dist/providers/near/index.mjs.map +1 -1
- package/dist/providers/solana/index.d.mts +1 -1
- package/dist/providers/solana/index.d.ts +1 -1
- package/dist/providers/solana/index.js +103 -0
- package/dist/providers/solana/index.js.map +1 -1
- package/dist/providers/solana/index.mjs +103 -0
- package/dist/providers/solana/index.mjs.map +1 -1
- package/dist/providers/stellar/index.d.mts +1 -1
- package/dist/providers/stellar/index.d.ts +1 -1
- package/dist/providers/stellar/index.js +103 -0
- package/dist/providers/stellar/index.js.map +1 -1
- package/dist/providers/stellar/index.mjs +103 -0
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/providers/sui/index.d.mts +1 -1
- package/dist/providers/sui/index.d.ts +1 -1
- package/dist/providers/sui/index.js +105 -1
- package/dist/providers/sui/index.js.map +1 -1
- package/dist/providers/sui/index.mjs +105 -1
- package/dist/providers/sui/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +103 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +103 -0
- package/dist/react/index.mjs.map +1 -1
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +103 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +103 -0
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +9 -3
- package/src/backend/index.ts +695 -1
- package/src/chains/index.ts +102 -2
- package/src/providers/sui/index.ts +2 -0
- package/src/types/index.ts +7 -2
package/src/backend/index.ts
CHANGED
|
@@ -746,10 +746,14 @@ export type BazaarNetwork =
|
|
|
746
746
|
| 'hyperevm'
|
|
747
747
|
| 'unichain'
|
|
748
748
|
| 'monad'
|
|
749
|
+
| 'scroll'
|
|
750
|
+
| 'skale'
|
|
749
751
|
| 'solana'
|
|
750
752
|
| 'fogo'
|
|
751
753
|
| 'stellar'
|
|
752
|
-
| 'near'
|
|
754
|
+
| 'near'
|
|
755
|
+
| 'algorand'
|
|
756
|
+
| 'sui';
|
|
753
757
|
|
|
754
758
|
/**
|
|
755
759
|
* Token/asset filter for discovery
|
|
@@ -2129,3 +2133,693 @@ export function isEscrowExpired(escrow: EscrowPayment): boolean {
|
|
|
2129
2133
|
export function escrowTimeRemaining(escrow: EscrowPayment): number {
|
|
2130
2134
|
return new Date(escrow.expiresAt).getTime() - Date.now();
|
|
2131
2135
|
}
|
|
2136
|
+
|
|
2137
|
+
// ============================================================================
|
|
2138
|
+
// ERC-8004 TRUSTLESS AGENTS
|
|
2139
|
+
// ============================================================================
|
|
2140
|
+
|
|
2141
|
+
/**
|
|
2142
|
+
* ERC-8004 extension identifier
|
|
2143
|
+
*/
|
|
2144
|
+
export const ERC8004_EXTENSION_ID = '8004-reputation';
|
|
2145
|
+
|
|
2146
|
+
/**
|
|
2147
|
+
* ERC-8004 contract addresses per network
|
|
2148
|
+
*/
|
|
2149
|
+
export const ERC8004_CONTRACTS: Record<string, {
|
|
2150
|
+
identityRegistry?: string;
|
|
2151
|
+
reputationRegistry?: string;
|
|
2152
|
+
validationRegistry?: string;
|
|
2153
|
+
}> = {
|
|
2154
|
+
ethereum: {
|
|
2155
|
+
identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',
|
|
2156
|
+
reputationRegistry: '0x8004BAa17C55a88189AE136b182e5fdA19dE9b63',
|
|
2157
|
+
},
|
|
2158
|
+
'ethereum-sepolia': {
|
|
2159
|
+
identityRegistry: '0x8004A818BFB912233c491871b3d84c89A494BD9e',
|
|
2160
|
+
reputationRegistry: '0x8004B663056A597Dffe9eCcC1965A193B7388713',
|
|
2161
|
+
validationRegistry: '0x8004Cb1BF31DAf7788923b405b754f57acEB4272',
|
|
2162
|
+
},
|
|
2163
|
+
};
|
|
2164
|
+
|
|
2165
|
+
/**
|
|
2166
|
+
* Network type for ERC-8004 operations
|
|
2167
|
+
*/
|
|
2168
|
+
export type Erc8004Network = 'ethereum' | 'ethereum-sepolia';
|
|
2169
|
+
|
|
2170
|
+
/**
|
|
2171
|
+
* Proof of payment returned when settling with ERC-8004 extension
|
|
2172
|
+
*/
|
|
2173
|
+
export interface ProofOfPayment {
|
|
2174
|
+
/** Transaction hash of the settled payment */
|
|
2175
|
+
transactionHash: string;
|
|
2176
|
+
/** Block number where the transaction was included */
|
|
2177
|
+
blockNumber: number;
|
|
2178
|
+
/** Network where the payment was settled */
|
|
2179
|
+
network: string;
|
|
2180
|
+
/** The payer (consumer/client) address */
|
|
2181
|
+
payer: string;
|
|
2182
|
+
/** The payee (agent/resource owner) address */
|
|
2183
|
+
payee: string;
|
|
2184
|
+
/** Amount paid in token base units */
|
|
2185
|
+
amount: string;
|
|
2186
|
+
/** Token contract address */
|
|
2187
|
+
token: string;
|
|
2188
|
+
/** Unix timestamp of the block */
|
|
2189
|
+
timestamp: number;
|
|
2190
|
+
/** Keccak256 hash of the payment data for verification */
|
|
2191
|
+
paymentHash: string;
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
/**
|
|
2195
|
+
* Extended settle response with ERC-8004 proof of payment
|
|
2196
|
+
*/
|
|
2197
|
+
export interface SettleResponseWithProof extends SettleResponse {
|
|
2198
|
+
/** Proof of payment for ERC-8004 reputation submission */
|
|
2199
|
+
proofOfPayment?: ProofOfPayment;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
/**
|
|
2203
|
+
* Agent identity from the Identity Registry
|
|
2204
|
+
*/
|
|
2205
|
+
export interface AgentIdentity {
|
|
2206
|
+
/** The agent's ID (ERC-721 tokenId) */
|
|
2207
|
+
agentId: number;
|
|
2208
|
+
/** Owner address of the agent NFT */
|
|
2209
|
+
owner: string;
|
|
2210
|
+
/** URI pointing to agent registration file */
|
|
2211
|
+
agentUri: string;
|
|
2212
|
+
/** Payment wallet address (if set) */
|
|
2213
|
+
agentWallet?: string;
|
|
2214
|
+
/** Network where the agent is registered */
|
|
2215
|
+
network: Erc8004Network;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
/**
|
|
2219
|
+
* Agent registration file structure (resolved from agentURI)
|
|
2220
|
+
*/
|
|
2221
|
+
export interface AgentRegistrationFile {
|
|
2222
|
+
/** Type identifier */
|
|
2223
|
+
type: string;
|
|
2224
|
+
/** Agent name */
|
|
2225
|
+
name: string;
|
|
2226
|
+
/** Agent description */
|
|
2227
|
+
description: string;
|
|
2228
|
+
/** Image URL */
|
|
2229
|
+
image?: string;
|
|
2230
|
+
/** List of services the agent provides */
|
|
2231
|
+
services: AgentService[];
|
|
2232
|
+
/** Whether x402 payments are supported */
|
|
2233
|
+
x402Support: boolean;
|
|
2234
|
+
/** Whether the agent is active */
|
|
2235
|
+
active: boolean;
|
|
2236
|
+
/** List of registrations across chains */
|
|
2237
|
+
registrations: AgentRegistration[];
|
|
2238
|
+
/** Supported trust models */
|
|
2239
|
+
supportedTrust: string[];
|
|
2240
|
+
}
|
|
2241
|
+
|
|
2242
|
+
/**
|
|
2243
|
+
* Agent service entry
|
|
2244
|
+
*/
|
|
2245
|
+
export interface AgentService {
|
|
2246
|
+
name: string;
|
|
2247
|
+
endpoint: string;
|
|
2248
|
+
version?: string;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
/**
|
|
2252
|
+
* Agent registration reference
|
|
2253
|
+
*/
|
|
2254
|
+
export interface AgentRegistration {
|
|
2255
|
+
agentId: number;
|
|
2256
|
+
agentRegistry: string; // Format: {namespace}:{chainId}:{address}
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
/**
|
|
2260
|
+
* Reputation summary for an agent
|
|
2261
|
+
*/
|
|
2262
|
+
export interface ReputationSummary {
|
|
2263
|
+
/** Agent ID */
|
|
2264
|
+
agentId: number;
|
|
2265
|
+
/** Number of feedback entries */
|
|
2266
|
+
count: number;
|
|
2267
|
+
/** Aggregated value */
|
|
2268
|
+
summaryValue: number;
|
|
2269
|
+
/** Decimal places for summaryValue */
|
|
2270
|
+
summaryValueDecimals: number;
|
|
2271
|
+
/** Network */
|
|
2272
|
+
network: Erc8004Network;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
/**
|
|
2276
|
+
* Individual feedback entry
|
|
2277
|
+
*/
|
|
2278
|
+
export interface FeedbackEntry {
|
|
2279
|
+
/** Client who submitted the feedback */
|
|
2280
|
+
client: string;
|
|
2281
|
+
/** Feedback index (1-indexed) */
|
|
2282
|
+
feedbackIndex: number;
|
|
2283
|
+
/** Feedback value */
|
|
2284
|
+
value: number;
|
|
2285
|
+
/** Value decimals */
|
|
2286
|
+
valueDecimals: number;
|
|
2287
|
+
/** Primary tag */
|
|
2288
|
+
tag1: string;
|
|
2289
|
+
/** Secondary tag */
|
|
2290
|
+
tag2: string;
|
|
2291
|
+
/** Whether this feedback was revoked */
|
|
2292
|
+
isRevoked: boolean;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
/**
|
|
2296
|
+
* Parameters for submitting reputation feedback
|
|
2297
|
+
*/
|
|
2298
|
+
export interface FeedbackParams {
|
|
2299
|
+
/** The agent's ID (tokenId in Identity Registry) */
|
|
2300
|
+
agentId: number;
|
|
2301
|
+
/** Feedback value (e.g., 87 for 87/100) */
|
|
2302
|
+
value: number;
|
|
2303
|
+
/** Decimal places for value interpretation (0-18) */
|
|
2304
|
+
valueDecimals?: number;
|
|
2305
|
+
/** Primary categorization tag (e.g., "starred", "uptime") */
|
|
2306
|
+
tag1?: string;
|
|
2307
|
+
/** Secondary categorization tag */
|
|
2308
|
+
tag2?: string;
|
|
2309
|
+
/** Service endpoint that was used */
|
|
2310
|
+
endpoint?: string;
|
|
2311
|
+
/** URI to off-chain feedback file (IPFS, HTTPS) */
|
|
2312
|
+
feedbackUri?: string;
|
|
2313
|
+
/** Keccak256 hash of feedback content (for integrity) */
|
|
2314
|
+
feedbackHash?: string;
|
|
2315
|
+
/** Proof of payment (required for authorized feedback) */
|
|
2316
|
+
proof?: ProofOfPayment;
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
/**
|
|
2320
|
+
* Feedback request body for POST /feedback
|
|
2321
|
+
*/
|
|
2322
|
+
export interface FeedbackRequest {
|
|
2323
|
+
/** x402 protocol version */
|
|
2324
|
+
x402Version: 1 | 2;
|
|
2325
|
+
/** Network where feedback will be submitted */
|
|
2326
|
+
network: Erc8004Network;
|
|
2327
|
+
/** Feedback parameters */
|
|
2328
|
+
feedback: FeedbackParams;
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
/**
|
|
2332
|
+
* Feedback response from POST /feedback
|
|
2333
|
+
*/
|
|
2334
|
+
export interface FeedbackResponse {
|
|
2335
|
+
/** Whether the feedback was successfully submitted */
|
|
2336
|
+
success: boolean;
|
|
2337
|
+
/** Transaction hash of the feedback submission */
|
|
2338
|
+
transaction?: string;
|
|
2339
|
+
/** Feedback index assigned (1-indexed) */
|
|
2340
|
+
feedbackIndex?: number;
|
|
2341
|
+
/** Error message (if failed) */
|
|
2342
|
+
error?: string;
|
|
2343
|
+
/** Network where feedback was submitted */
|
|
2344
|
+
network: Erc8004Network;
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
/**
|
|
2348
|
+
* Reputation query response
|
|
2349
|
+
*/
|
|
2350
|
+
export interface ReputationResponse {
|
|
2351
|
+
agentId: number;
|
|
2352
|
+
summary: ReputationSummary;
|
|
2353
|
+
feedback?: FeedbackEntry[];
|
|
2354
|
+
network: Erc8004Network;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
/**
|
|
2358
|
+
* Options for the ERC8004Client
|
|
2359
|
+
*/
|
|
2360
|
+
export interface Erc8004ClientOptions {
|
|
2361
|
+
/** Base URL of the facilitator (default: https://facilitator.ultravioletadao.xyz) */
|
|
2362
|
+
baseUrl?: string;
|
|
2363
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
2364
|
+
timeout?: number;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
/**
|
|
2368
|
+
* Client for ERC-8004 Trustless Agents API
|
|
2369
|
+
*
|
|
2370
|
+
* Provides methods for:
|
|
2371
|
+
* - Querying agent identity
|
|
2372
|
+
* - Querying agent reputation
|
|
2373
|
+
* - Submitting reputation feedback
|
|
2374
|
+
* - Revoking feedback
|
|
2375
|
+
*
|
|
2376
|
+
* @example
|
|
2377
|
+
* ```ts
|
|
2378
|
+
* const client = new Erc8004Client();
|
|
2379
|
+
*
|
|
2380
|
+
* // Get agent identity
|
|
2381
|
+
* const identity = await client.getIdentity('ethereum', 42);
|
|
2382
|
+
* console.log(identity.agentUri);
|
|
2383
|
+
*
|
|
2384
|
+
* // Get agent reputation
|
|
2385
|
+
* const reputation = await client.getReputation('ethereum', 42);
|
|
2386
|
+
* console.log(`Score: ${reputation.summary.summaryValue}`);
|
|
2387
|
+
*
|
|
2388
|
+
* // Submit feedback after payment
|
|
2389
|
+
* const result = await client.submitFeedback({
|
|
2390
|
+
* x402Version: 1,
|
|
2391
|
+
* network: 'ethereum',
|
|
2392
|
+
* feedback: {
|
|
2393
|
+
* agentId: 42,
|
|
2394
|
+
* value: 95,
|
|
2395
|
+
* valueDecimals: 0,
|
|
2396
|
+
* tag1: 'quality',
|
|
2397
|
+
* proof: settleResponse.proofOfPayment,
|
|
2398
|
+
* },
|
|
2399
|
+
* });
|
|
2400
|
+
* ```
|
|
2401
|
+
*/
|
|
2402
|
+
export class Erc8004Client {
|
|
2403
|
+
private readonly baseUrl: string;
|
|
2404
|
+
private readonly timeout: number;
|
|
2405
|
+
|
|
2406
|
+
constructor(options: Erc8004ClientOptions = {}) {
|
|
2407
|
+
this.baseUrl = options.baseUrl || 'https://facilitator.ultravioletadao.xyz';
|
|
2408
|
+
this.timeout = options.timeout || 30000;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
/**
|
|
2412
|
+
* Get agent identity from the Identity Registry
|
|
2413
|
+
*
|
|
2414
|
+
* @param network - Network where agent is registered
|
|
2415
|
+
* @param agentId - Agent's tokenId
|
|
2416
|
+
* @returns Agent identity information
|
|
2417
|
+
*/
|
|
2418
|
+
async getIdentity(network: Erc8004Network, agentId: number): Promise<AgentIdentity> {
|
|
2419
|
+
const url = `${this.baseUrl}/identity/${network}/${agentId}`;
|
|
2420
|
+
|
|
2421
|
+
const controller = new AbortController();
|
|
2422
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2423
|
+
|
|
2424
|
+
try {
|
|
2425
|
+
const response = await fetch(url, {
|
|
2426
|
+
method: 'GET',
|
|
2427
|
+
headers: { 'Accept': 'application/json' },
|
|
2428
|
+
signal: controller.signal,
|
|
2429
|
+
});
|
|
2430
|
+
|
|
2431
|
+
clearTimeout(timeoutId);
|
|
2432
|
+
|
|
2433
|
+
if (!response.ok) {
|
|
2434
|
+
const errorText = await response.text();
|
|
2435
|
+
throw new Error(`ERC-8004 API error: ${response.status} - ${errorText}`);
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
return await response.json();
|
|
2439
|
+
} catch (error) {
|
|
2440
|
+
clearTimeout(timeoutId);
|
|
2441
|
+
throw error;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
/**
|
|
2446
|
+
* Resolve agent registration file from agentURI
|
|
2447
|
+
*
|
|
2448
|
+
* @param agentUri - URI pointing to agent registration file
|
|
2449
|
+
* @returns Resolved agent registration file
|
|
2450
|
+
*/
|
|
2451
|
+
async resolveAgentUri(agentUri: string): Promise<AgentRegistrationFile> {
|
|
2452
|
+
const controller = new AbortController();
|
|
2453
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2454
|
+
|
|
2455
|
+
try {
|
|
2456
|
+
// Handle IPFS URIs
|
|
2457
|
+
let url = agentUri;
|
|
2458
|
+
if (agentUri.startsWith('ipfs://')) {
|
|
2459
|
+
const cid = agentUri.replace('ipfs://', '');
|
|
2460
|
+
url = `https://ipfs.io/ipfs/${cid}`;
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
const response = await fetch(url, {
|
|
2464
|
+
method: 'GET',
|
|
2465
|
+
headers: { 'Accept': 'application/json' },
|
|
2466
|
+
signal: controller.signal,
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
clearTimeout(timeoutId);
|
|
2470
|
+
|
|
2471
|
+
if (!response.ok) {
|
|
2472
|
+
throw new Error(`Failed to resolve agentURI: ${response.status}`);
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
return await response.json();
|
|
2476
|
+
} catch (error) {
|
|
2477
|
+
clearTimeout(timeoutId);
|
|
2478
|
+
throw error;
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
/**
|
|
2483
|
+
* Get agent reputation from the Reputation Registry
|
|
2484
|
+
*
|
|
2485
|
+
* @param network - Network where agent is registered
|
|
2486
|
+
* @param agentId - Agent's tokenId
|
|
2487
|
+
* @param options - Query options (tag filters, include individual feedback)
|
|
2488
|
+
* @returns Reputation summary and optionally individual feedback entries
|
|
2489
|
+
*/
|
|
2490
|
+
async getReputation(
|
|
2491
|
+
network: Erc8004Network,
|
|
2492
|
+
agentId: number,
|
|
2493
|
+
options: {
|
|
2494
|
+
tag1?: string;
|
|
2495
|
+
tag2?: string;
|
|
2496
|
+
includeFeedback?: boolean;
|
|
2497
|
+
} = {}
|
|
2498
|
+
): Promise<ReputationResponse> {
|
|
2499
|
+
const params = new URLSearchParams();
|
|
2500
|
+
if (options.tag1) params.set('tag1', options.tag1);
|
|
2501
|
+
if (options.tag2) params.set('tag2', options.tag2);
|
|
2502
|
+
if (options.includeFeedback) params.set('includeFeedback', 'true');
|
|
2503
|
+
|
|
2504
|
+
const url = `${this.baseUrl}/reputation/${network}/${agentId}${params.toString() ? `?${params}` : ''}`;
|
|
2505
|
+
|
|
2506
|
+
const controller = new AbortController();
|
|
2507
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2508
|
+
|
|
2509
|
+
try {
|
|
2510
|
+
const response = await fetch(url, {
|
|
2511
|
+
method: 'GET',
|
|
2512
|
+
headers: { 'Accept': 'application/json' },
|
|
2513
|
+
signal: controller.signal,
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
clearTimeout(timeoutId);
|
|
2517
|
+
|
|
2518
|
+
if (!response.ok) {
|
|
2519
|
+
const errorText = await response.text();
|
|
2520
|
+
throw new Error(`ERC-8004 API error: ${response.status} - ${errorText}`);
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
return await response.json();
|
|
2524
|
+
} catch (error) {
|
|
2525
|
+
clearTimeout(timeoutId);
|
|
2526
|
+
throw error;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
/**
|
|
2531
|
+
* Submit reputation feedback for an agent
|
|
2532
|
+
*
|
|
2533
|
+
* Requires proof of payment for authorized feedback submission.
|
|
2534
|
+
*
|
|
2535
|
+
* @param request - Feedback request with agent ID, value, and proof
|
|
2536
|
+
* @returns Feedback response with transaction hash
|
|
2537
|
+
*
|
|
2538
|
+
* @example
|
|
2539
|
+
* ```ts
|
|
2540
|
+
* // After settling a payment with ERC-8004 extension
|
|
2541
|
+
* const settleResult = await facilitator.settle(payment, {
|
|
2542
|
+
* ...requirements,
|
|
2543
|
+
* extra: { '8004-reputation': { includeProof: true } },
|
|
2544
|
+
* });
|
|
2545
|
+
*
|
|
2546
|
+
* // Submit feedback with proof of payment
|
|
2547
|
+
* const feedback = await erc8004.submitFeedback({
|
|
2548
|
+
* x402Version: 1,
|
|
2549
|
+
* network: 'ethereum',
|
|
2550
|
+
* feedback: {
|
|
2551
|
+
* agentId: 42,
|
|
2552
|
+
* value: 95, // 95/100
|
|
2553
|
+
* valueDecimals: 0,
|
|
2554
|
+
* tag1: 'quality',
|
|
2555
|
+
* tag2: 'response-time',
|
|
2556
|
+
* proof: settleResult.proofOfPayment,
|
|
2557
|
+
* },
|
|
2558
|
+
* });
|
|
2559
|
+
* ```
|
|
2560
|
+
*/
|
|
2561
|
+
async submitFeedback(request: FeedbackRequest): Promise<FeedbackResponse> {
|
|
2562
|
+
const url = `${this.baseUrl}/feedback`;
|
|
2563
|
+
|
|
2564
|
+
const controller = new AbortController();
|
|
2565
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2566
|
+
|
|
2567
|
+
try {
|
|
2568
|
+
const response = await fetch(url, {
|
|
2569
|
+
method: 'POST',
|
|
2570
|
+
headers: {
|
|
2571
|
+
'Content-Type': 'application/json',
|
|
2572
|
+
'Accept': 'application/json',
|
|
2573
|
+
},
|
|
2574
|
+
body: JSON.stringify(request),
|
|
2575
|
+
signal: controller.signal,
|
|
2576
|
+
});
|
|
2577
|
+
|
|
2578
|
+
clearTimeout(timeoutId);
|
|
2579
|
+
|
|
2580
|
+
if (!response.ok) {
|
|
2581
|
+
const errorText = await response.text();
|
|
2582
|
+
return {
|
|
2583
|
+
success: false,
|
|
2584
|
+
error: `Facilitator error: ${response.status} - ${errorText}`,
|
|
2585
|
+
network: request.network,
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
return await response.json();
|
|
2590
|
+
} catch (error) {
|
|
2591
|
+
clearTimeout(timeoutId);
|
|
2592
|
+
return {
|
|
2593
|
+
success: false,
|
|
2594
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
2595
|
+
network: request.network,
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
/**
|
|
2601
|
+
* Revoke previously submitted feedback
|
|
2602
|
+
*
|
|
2603
|
+
* Only the original submitter can revoke their feedback.
|
|
2604
|
+
*
|
|
2605
|
+
* @param network - Network where feedback was submitted
|
|
2606
|
+
* @param agentId - Agent ID
|
|
2607
|
+
* @param feedbackIndex - Index of feedback to revoke
|
|
2608
|
+
* @returns Revocation result
|
|
2609
|
+
*/
|
|
2610
|
+
async revokeFeedback(
|
|
2611
|
+
network: Erc8004Network,
|
|
2612
|
+
agentId: number,
|
|
2613
|
+
feedbackIndex: number
|
|
2614
|
+
): Promise<FeedbackResponse> {
|
|
2615
|
+
const url = `${this.baseUrl}/feedback/revoke`;
|
|
2616
|
+
|
|
2617
|
+
const controller = new AbortController();
|
|
2618
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2619
|
+
|
|
2620
|
+
try {
|
|
2621
|
+
const response = await fetch(url, {
|
|
2622
|
+
method: 'POST',
|
|
2623
|
+
headers: {
|
|
2624
|
+
'Content-Type': 'application/json',
|
|
2625
|
+
'Accept': 'application/json',
|
|
2626
|
+
},
|
|
2627
|
+
body: JSON.stringify({
|
|
2628
|
+
x402Version: 1,
|
|
2629
|
+
network,
|
|
2630
|
+
agentId,
|
|
2631
|
+
feedbackIndex,
|
|
2632
|
+
}),
|
|
2633
|
+
signal: controller.signal,
|
|
2634
|
+
});
|
|
2635
|
+
|
|
2636
|
+
clearTimeout(timeoutId);
|
|
2637
|
+
|
|
2638
|
+
if (!response.ok) {
|
|
2639
|
+
const errorText = await response.text();
|
|
2640
|
+
return {
|
|
2641
|
+
success: false,
|
|
2642
|
+
error: `Facilitator error: ${response.status} - ${errorText}`,
|
|
2643
|
+
network,
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
return await response.json();
|
|
2648
|
+
} catch (error) {
|
|
2649
|
+
clearTimeout(timeoutId);
|
|
2650
|
+
return {
|
|
2651
|
+
success: false,
|
|
2652
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
2653
|
+
network,
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
/**
|
|
2659
|
+
* Get ERC-8004 contract addresses for a network
|
|
2660
|
+
*
|
|
2661
|
+
* @param network - Network to get contracts for
|
|
2662
|
+
* @returns Contract addresses or undefined if not deployed
|
|
2663
|
+
*/
|
|
2664
|
+
getContracts(network: Erc8004Network): typeof ERC8004_CONTRACTS[Erc8004Network] | undefined {
|
|
2665
|
+
return ERC8004_CONTRACTS[network];
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
/**
|
|
2669
|
+
* Check if ERC-8004 is available on a network
|
|
2670
|
+
*
|
|
2671
|
+
* @param network - Network to check
|
|
2672
|
+
* @returns True if ERC-8004 contracts are deployed
|
|
2673
|
+
*/
|
|
2674
|
+
isAvailable(network: string): network is Erc8004Network {
|
|
2675
|
+
return network in ERC8004_CONTRACTS;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
/**
|
|
2679
|
+
* Get feedback endpoint metadata
|
|
2680
|
+
*
|
|
2681
|
+
* @returns Endpoint information for /feedback
|
|
2682
|
+
*/
|
|
2683
|
+
async getFeedbackMetadata(): Promise<{
|
|
2684
|
+
endpoint: string;
|
|
2685
|
+
supportedNetworks: Erc8004Network[];
|
|
2686
|
+
version: string;
|
|
2687
|
+
}> {
|
|
2688
|
+
const url = `${this.baseUrl}/feedback`;
|
|
2689
|
+
|
|
2690
|
+
const controller = new AbortController();
|
|
2691
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2692
|
+
|
|
2693
|
+
try {
|
|
2694
|
+
const response = await fetch(url, {
|
|
2695
|
+
method: 'GET',
|
|
2696
|
+
headers: { 'Accept': 'application/json' },
|
|
2697
|
+
signal: controller.signal,
|
|
2698
|
+
});
|
|
2699
|
+
|
|
2700
|
+
clearTimeout(timeoutId);
|
|
2701
|
+
|
|
2702
|
+
if (!response.ok) {
|
|
2703
|
+
throw new Error(`Failed to get feedback metadata: ${response.status}`);
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
return await response.json();
|
|
2707
|
+
} catch (error) {
|
|
2708
|
+
clearTimeout(timeoutId);
|
|
2709
|
+
throw error;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
/**
|
|
2714
|
+
* Append a response to existing feedback
|
|
2715
|
+
*
|
|
2716
|
+
* Allows agents to respond to feedback they received.
|
|
2717
|
+
* Only the agent (identity owner) can append responses.
|
|
2718
|
+
*
|
|
2719
|
+
* @param network - Network where feedback was submitted
|
|
2720
|
+
* @param agentId - Agent ID
|
|
2721
|
+
* @param feedbackIndex - Index of feedback to respond to
|
|
2722
|
+
* @param response - Response content
|
|
2723
|
+
* @param responseUri - Optional URI to off-chain response file
|
|
2724
|
+
* @returns Response result
|
|
2725
|
+
*
|
|
2726
|
+
* @example
|
|
2727
|
+
* ```ts
|
|
2728
|
+
* // Agent responds to feedback
|
|
2729
|
+
* const result = await erc8004.appendResponse(
|
|
2730
|
+
* 'ethereum',
|
|
2731
|
+
* 42,
|
|
2732
|
+
* 1,
|
|
2733
|
+
* 'Thank you for your feedback! We have addressed the issue.',
|
|
2734
|
+
* );
|
|
2735
|
+
* ```
|
|
2736
|
+
*/
|
|
2737
|
+
async appendResponse(
|
|
2738
|
+
network: Erc8004Network,
|
|
2739
|
+
agentId: number,
|
|
2740
|
+
feedbackIndex: number,
|
|
2741
|
+
response: string,
|
|
2742
|
+
responseUri?: string
|
|
2743
|
+
): Promise<FeedbackResponse> {
|
|
2744
|
+
const url = `${this.baseUrl}/feedback/response`;
|
|
2745
|
+
|
|
2746
|
+
const controller = new AbortController();
|
|
2747
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
2748
|
+
|
|
2749
|
+
try {
|
|
2750
|
+
const fetchResponse = await fetch(url, {
|
|
2751
|
+
method: 'POST',
|
|
2752
|
+
headers: {
|
|
2753
|
+
'Content-Type': 'application/json',
|
|
2754
|
+
'Accept': 'application/json',
|
|
2755
|
+
},
|
|
2756
|
+
body: JSON.stringify({
|
|
2757
|
+
x402Version: 1,
|
|
2758
|
+
network,
|
|
2759
|
+
agentId,
|
|
2760
|
+
feedbackIndex,
|
|
2761
|
+
response,
|
|
2762
|
+
responseUri,
|
|
2763
|
+
}),
|
|
2764
|
+
signal: controller.signal,
|
|
2765
|
+
});
|
|
2766
|
+
|
|
2767
|
+
clearTimeout(timeoutId);
|
|
2768
|
+
|
|
2769
|
+
if (!fetchResponse.ok) {
|
|
2770
|
+
const errorText = await fetchResponse.text();
|
|
2771
|
+
return {
|
|
2772
|
+
success: false,
|
|
2773
|
+
error: `Facilitator error: ${fetchResponse.status} - ${errorText}`,
|
|
2774
|
+
network,
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
return await fetchResponse.json();
|
|
2779
|
+
} catch (error) {
|
|
2780
|
+
clearTimeout(timeoutId);
|
|
2781
|
+
return {
|
|
2782
|
+
success: false,
|
|
2783
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
2784
|
+
network,
|
|
2785
|
+
};
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
/**
|
|
2791
|
+
* Build payment requirements with ERC-8004 extension
|
|
2792
|
+
*
|
|
2793
|
+
* Adds the 8004-reputation extension to include proof of payment
|
|
2794
|
+
* in settlement responses for reputation submission.
|
|
2795
|
+
*
|
|
2796
|
+
* @param options - Base payment requirements options
|
|
2797
|
+
* @returns Payment requirements with ERC-8004 extension
|
|
2798
|
+
*
|
|
2799
|
+
* @example
|
|
2800
|
+
* ```ts
|
|
2801
|
+
* const requirements = buildErc8004PaymentRequirements({
|
|
2802
|
+
* amount: '1.00',
|
|
2803
|
+
* recipient: '0x...',
|
|
2804
|
+
* resource: 'https://api.example.com/service',
|
|
2805
|
+
* chainName: 'ethereum',
|
|
2806
|
+
* });
|
|
2807
|
+
*
|
|
2808
|
+
* // Settlement will include proofOfPayment
|
|
2809
|
+
* const result = await facilitator.settle(payment, requirements);
|
|
2810
|
+
* console.log(result.proofOfPayment);
|
|
2811
|
+
* ```
|
|
2812
|
+
*/
|
|
2813
|
+
export function buildErc8004PaymentRequirements(
|
|
2814
|
+
options: PaymentRequirementsOptions
|
|
2815
|
+
): PaymentRequirements & { extra: { '8004-reputation': { includeProof: boolean } } } {
|
|
2816
|
+
const base = buildPaymentRequirements(options);
|
|
2817
|
+
return {
|
|
2818
|
+
...base,
|
|
2819
|
+
extra: {
|
|
2820
|
+
[ERC8004_EXTENSION_ID]: {
|
|
2821
|
+
includeProof: true,
|
|
2822
|
+
},
|
|
2823
|
+
},
|
|
2824
|
+
};
|
|
2825
|
+
}
|