uvd-x402-sdk 2.17.0 → 2.19.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.
@@ -1,5 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
3
10
  // src/types/index.ts
4
11
  var CAIP2_IDENTIFIERS = {
5
12
  // EVM chains
@@ -1901,15 +1908,66 @@ function escrowTimeRemaining(escrow) {
1901
1908
  return new Date(escrow.expiresAt).getTime() - Date.now();
1902
1909
  }
1903
1910
  var ERC8004_EXTENSION_ID = "8004-reputation";
1911
+ var MAINNET_IDENTITY = "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432";
1912
+ var MAINNET_REPUTATION = "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63";
1913
+ var TESTNET_IDENTITY = "0x8004A818BFB912233c491871b3d84c89A494BD9e";
1914
+ var TESTNET_REPUTATION = "0x8004B663056A597Dffe9eCcC1965A193B7388713";
1915
+ var TESTNET_VALIDATION = "0x8004Cb1BF31DAf7788923b405b754f57acEB4272";
1904
1916
  var ERC8004_CONTRACTS = {
1917
+ // Mainnets (7)
1905
1918
  ethereum: {
1906
- identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
1907
- reputationRegistry: "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63"
1919
+ identityRegistry: MAINNET_IDENTITY,
1920
+ reputationRegistry: MAINNET_REPUTATION
1921
+ },
1922
+ "base-mainnet": {
1923
+ identityRegistry: MAINNET_IDENTITY,
1924
+ reputationRegistry: MAINNET_REPUTATION
1925
+ },
1926
+ polygon: {
1927
+ identityRegistry: MAINNET_IDENTITY,
1928
+ reputationRegistry: MAINNET_REPUTATION
1908
1929
  },
1930
+ arbitrum: {
1931
+ identityRegistry: MAINNET_IDENTITY,
1932
+ reputationRegistry: MAINNET_REPUTATION
1933
+ },
1934
+ celo: {
1935
+ identityRegistry: MAINNET_IDENTITY,
1936
+ reputationRegistry: MAINNET_REPUTATION
1937
+ },
1938
+ bsc: {
1939
+ identityRegistry: MAINNET_IDENTITY,
1940
+ reputationRegistry: MAINNET_REPUTATION
1941
+ },
1942
+ monad: {
1943
+ identityRegistry: MAINNET_IDENTITY,
1944
+ reputationRegistry: MAINNET_REPUTATION
1945
+ },
1946
+ // Testnets (5)
1909
1947
  "ethereum-sepolia": {
1910
- identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
1911
- reputationRegistry: "0x8004B663056A597Dffe9eCcC1965A193B7388713",
1912
- validationRegistry: "0x8004Cb1BF31DAf7788923b405b754f57acEB4272"
1948
+ identityRegistry: TESTNET_IDENTITY,
1949
+ reputationRegistry: TESTNET_REPUTATION,
1950
+ validationRegistry: TESTNET_VALIDATION
1951
+ },
1952
+ "base-sepolia": {
1953
+ identityRegistry: TESTNET_IDENTITY,
1954
+ reputationRegistry: TESTNET_REPUTATION,
1955
+ validationRegistry: TESTNET_VALIDATION
1956
+ },
1957
+ "polygon-amoy": {
1958
+ identityRegistry: TESTNET_IDENTITY,
1959
+ reputationRegistry: TESTNET_REPUTATION,
1960
+ validationRegistry: TESTNET_VALIDATION
1961
+ },
1962
+ "arbitrum-sepolia": {
1963
+ identityRegistry: TESTNET_IDENTITY,
1964
+ reputationRegistry: TESTNET_REPUTATION,
1965
+ validationRegistry: TESTNET_VALIDATION
1966
+ },
1967
+ "celo-sepolia": {
1968
+ identityRegistry: TESTNET_IDENTITY,
1969
+ reputationRegistry: TESTNET_REPUTATION,
1970
+ validationRegistry: TESTNET_VALIDATION
1913
1971
  }
1914
1972
  };
1915
1973
  var Erc8004Client = class {
@@ -2241,15 +2299,389 @@ function buildErc8004PaymentRequirements(options) {
2241
2299
  }
2242
2300
  };
2243
2301
  }
2302
+ var PAYMENT_INFO_TYPEHASH = "0xae68ac7ce30c86ece8196b61a7c486d8f0061f575037fbd34e7fe4e2820c6591";
2303
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
2304
+ var DEPOSIT_LIMIT_USDC = "100000000";
2305
+ var BASE_MAINNET_CONTRACTS = {
2306
+ operator: "0xa06958D93135BEd7e43893897C0d9fA931EF051C",
2307
+ escrow: "0x320a3c35F131E5D2Fb36af56345726B298936037",
2308
+ tokenCollector: "0x32d6AC59BCe8DFB3026F10BcaDB8D00AB218f5b6",
2309
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
2310
+ };
2311
+ var TIER_TIMINGS = {
2312
+ micro: { pre: 3600, auth: 7200, refund: 86400 },
2313
+ standard: { pre: 7200, auth: 86400, refund: 604800 },
2314
+ premium: { pre: 14400, auth: 172800, refund: 1209600 },
2315
+ enterprise: { pre: 86400, auth: 604800, refund: 2592e3 }
2316
+ };
2317
+ var OPERATOR_ABI = [
2318
+ "function release(tuple(address operator, address payer, address receiver, address token, uint120 maxAmount, uint48 preApprovalExpiry, uint48 authorizationExpiry, uint48 refundExpiry, uint16 minFeeBps, uint16 maxFeeBps, address feeReceiver, uint256 salt) paymentInfo, uint256 amount)",
2319
+ "function refundInEscrow(tuple(address operator, address payer, address receiver, address token, uint120 maxAmount, uint48 preApprovalExpiry, uint48 authorizationExpiry, uint48 refundExpiry, uint16 minFeeBps, uint16 maxFeeBps, address feeReceiver, uint256 salt) paymentInfo, uint120 amount)",
2320
+ "function charge(tuple(address operator, address payer, address receiver, address token, uint120 maxAmount, uint48 preApprovalExpiry, uint48 authorizationExpiry, uint48 refundExpiry, uint16 minFeeBps, uint16 maxFeeBps, address feeReceiver, uint256 salt) paymentInfo, uint256 amount, address tokenCollector, bytes collectorData)",
2321
+ "function refundPostEscrow(tuple(address operator, address payer, address receiver, address token, uint120 maxAmount, uint48 preApprovalExpiry, uint48 authorizationExpiry, uint48 refundExpiry, uint16 minFeeBps, uint16 maxFeeBps, address feeReceiver, uint256 salt) paymentInfo, uint256 amount, address tokenCollector, bytes collectorData)"
2322
+ ];
2323
+ var AdvancedEscrowClient = class {
2324
+ facilitatorUrl;
2325
+ chainId;
2326
+ gasLimit;
2327
+ contracts;
2328
+ signer;
2329
+ // ethers.Signer
2330
+ payerAddress = "";
2331
+ constructor(signer, options = {}) {
2332
+ this.signer = signer;
2333
+ this.facilitatorUrl = (options.facilitatorUrl || "https://facilitator.ultravioletadao.xyz").replace(/\/$/, "");
2334
+ this.chainId = options.chainId || 8453;
2335
+ this.gasLimit = options.gasLimit || 3e5;
2336
+ this.contracts = options.contracts || BASE_MAINNET_CONTRACTS;
2337
+ }
2338
+ /**
2339
+ * Initialize the client (resolves signer address).
2340
+ * Call this before using any methods.
2341
+ */
2342
+ async init() {
2343
+ this.payerAddress = await this.signer.getAddress();
2344
+ }
2345
+ /**
2346
+ * Build a PaymentInfo struct with appropriate timing for the task tier.
2347
+ *
2348
+ * @param receiver - Worker's wallet address
2349
+ * @param amount - Amount in token atomic units (e.g., '5000000' for $5 USDC)
2350
+ * @param tier - Task tier determines timing parameters
2351
+ * @param salt - Random salt (auto-generated if not provided)
2352
+ */
2353
+ buildPaymentInfo(receiver, amount, tier = "standard", salt) {
2354
+ const now = Math.floor(Date.now() / 1e3);
2355
+ const t = TIER_TIMINGS[tier];
2356
+ let generatedSalt = salt;
2357
+ if (!generatedSalt) {
2358
+ const bytes = new Uint8Array(32);
2359
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) {
2360
+ globalThis.crypto.getRandomValues(bytes);
2361
+ } else {
2362
+ const nodeCrypto = __require("crypto");
2363
+ const buf = nodeCrypto.randomBytes(32);
2364
+ bytes.set(new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
2365
+ }
2366
+ generatedSalt = "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2367
+ }
2368
+ return {
2369
+ operator: this.contracts.operator,
2370
+ receiver,
2371
+ token: this.contracts.usdc,
2372
+ maxAmount: amount,
2373
+ preApprovalExpiry: now + t.pre,
2374
+ authorizationExpiry: now + t.auth,
2375
+ refundExpiry: now + t.refund,
2376
+ minFeeBps: 0,
2377
+ maxFeeBps: 800,
2378
+ feeReceiver: this.contracts.operator,
2379
+ salt: generatedSalt
2380
+ };
2381
+ }
2382
+ /**
2383
+ * Compute the correct nonce (with PAYMENT_INFO_TYPEHASH).
2384
+ * Matches the on-chain AuthCaptureEscrow nonce derivation.
2385
+ */
2386
+ async computeNonce(paymentInfo) {
2387
+ const { ethers } = await import('ethers');
2388
+ const piTuple = ethers.AbiCoder.defaultAbiCoder().encode(
2389
+ ["bytes32", "tuple(address,address,address,address,uint120,uint48,uint48,uint48,uint16,uint16,address,uint256)"],
2390
+ [
2391
+ PAYMENT_INFO_TYPEHASH,
2392
+ [
2393
+ paymentInfo.operator,
2394
+ ZERO_ADDRESS,
2395
+ // payer = 0 for payer-agnostic hash
2396
+ paymentInfo.receiver,
2397
+ paymentInfo.token,
2398
+ paymentInfo.maxAmount,
2399
+ paymentInfo.preApprovalExpiry,
2400
+ paymentInfo.authorizationExpiry,
2401
+ paymentInfo.refundExpiry,
2402
+ paymentInfo.minFeeBps,
2403
+ paymentInfo.maxFeeBps,
2404
+ paymentInfo.feeReceiver,
2405
+ paymentInfo.salt
2406
+ ]
2407
+ ]
2408
+ );
2409
+ const piHash = ethers.keccak256(piTuple);
2410
+ const finalEncoded = ethers.AbiCoder.defaultAbiCoder().encode(
2411
+ ["uint256", "address", "bytes32"],
2412
+ [this.chainId, this.contracts.escrow, piHash]
2413
+ );
2414
+ return ethers.keccak256(finalEncoded);
2415
+ }
2416
+ /**
2417
+ * Sign ReceiveWithAuthorization for ERC-3009.
2418
+ */
2419
+ async signErc3009(auth) {
2420
+ const domain = {
2421
+ name: "USD Coin",
2422
+ version: "2",
2423
+ chainId: this.chainId,
2424
+ verifyingContract: this.contracts.usdc
2425
+ };
2426
+ const types = {
2427
+ ReceiveWithAuthorization: [
2428
+ { name: "from", type: "address" },
2429
+ { name: "to", type: "address" },
2430
+ { name: "value", type: "uint256" },
2431
+ { name: "validAfter", type: "uint256" },
2432
+ { name: "validBefore", type: "uint256" },
2433
+ { name: "nonce", type: "bytes32" }
2434
+ ]
2435
+ };
2436
+ const message = {
2437
+ from: auth.from,
2438
+ to: auth.to,
2439
+ value: auth.value,
2440
+ validAfter: auth.validAfter,
2441
+ validBefore: auth.validBefore,
2442
+ nonce: auth.nonce
2443
+ };
2444
+ return this.signer.signTypedData(domain, types, message);
2445
+ }
2446
+ /**
2447
+ * Build the on-chain PaymentInfo tuple for contract calls.
2448
+ */
2449
+ buildTuple(pi) {
2450
+ return [
2451
+ pi.operator,
2452
+ this.payerAddress,
2453
+ pi.receiver,
2454
+ pi.token,
2455
+ pi.maxAmount,
2456
+ pi.preApprovalExpiry,
2457
+ pi.authorizationExpiry,
2458
+ pi.refundExpiry,
2459
+ pi.minFeeBps,
2460
+ pi.maxFeeBps,
2461
+ pi.feeReceiver,
2462
+ pi.salt
2463
+ ];
2464
+ }
2465
+ /**
2466
+ * AUTHORIZE: Lock funds in escrow via the facilitator.
2467
+ *
2468
+ * Sends an ERC-3009 ReceiveWithAuthorization to the facilitator,
2469
+ * which calls PaymentOperator.authorize() on-chain.
2470
+ */
2471
+ async authorize(paymentInfo) {
2472
+ if (!this.payerAddress) await this.init();
2473
+ try {
2474
+ const nonce = await this.computeNonce(paymentInfo);
2475
+ const auth = {
2476
+ from: this.payerAddress,
2477
+ to: this.contracts.tokenCollector,
2478
+ value: paymentInfo.maxAmount,
2479
+ validAfter: "0",
2480
+ validBefore: String(paymentInfo.preApprovalExpiry),
2481
+ nonce
2482
+ };
2483
+ const signature = await this.signErc3009(auth);
2484
+ const payload = {
2485
+ x402Version: 2,
2486
+ scheme: "escrow",
2487
+ payload: {
2488
+ authorization: auth,
2489
+ signature,
2490
+ paymentInfo
2491
+ },
2492
+ paymentRequirements: {
2493
+ scheme: "escrow",
2494
+ network: `eip155:${this.chainId}`,
2495
+ maxAmountRequired: paymentInfo.maxAmount,
2496
+ asset: this.contracts.usdc,
2497
+ payTo: paymentInfo.receiver,
2498
+ extra: {
2499
+ escrowAddress: this.contracts.escrow,
2500
+ operatorAddress: this.contracts.operator,
2501
+ tokenCollector: this.contracts.tokenCollector
2502
+ }
2503
+ }
2504
+ };
2505
+ const response = await fetch(`${this.facilitatorUrl}/settle`, {
2506
+ method: "POST",
2507
+ headers: { "Content-Type": "application/json" },
2508
+ body: JSON.stringify(payload)
2509
+ });
2510
+ const result = await response.json();
2511
+ if (result.success) {
2512
+ return {
2513
+ success: true,
2514
+ transactionHash: result.transaction,
2515
+ paymentInfo,
2516
+ salt: paymentInfo.salt
2517
+ };
2518
+ }
2519
+ return { success: false, error: result.errorReason };
2520
+ } catch (e) {
2521
+ return { success: false, error: e.message || String(e) };
2522
+ }
2523
+ }
2524
+ /**
2525
+ * RELEASE: Capture escrowed funds to receiver (worker gets paid).
2526
+ *
2527
+ * Calls PaymentOperator.release() -> escrow.capture()
2528
+ *
2529
+ * @param paymentInfo - PaymentInfo from the authorize step
2530
+ * @param amount - Amount to release (defaults to maxAmount)
2531
+ */
2532
+ async release(paymentInfo, amount) {
2533
+ if (!this.payerAddress) await this.init();
2534
+ try {
2535
+ const { ethers } = await import('ethers');
2536
+ const contract = new ethers.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
2537
+ const amt = amount || paymentInfo.maxAmount;
2538
+ const tuple = this.buildTuple(paymentInfo);
2539
+ const tx = await contract.release(tuple, amt, { gasLimit: this.gasLimit });
2540
+ const receipt = await tx.wait();
2541
+ return {
2542
+ success: receipt.status === 1,
2543
+ transactionHash: receipt.hash,
2544
+ gasUsed: Number(receipt.gasUsed),
2545
+ error: receipt.status !== 1 ? "Transaction reverted" : void 0
2546
+ };
2547
+ } catch (e) {
2548
+ return { success: false, error: e.message || String(e) };
2549
+ }
2550
+ }
2551
+ /**
2552
+ * REFUND IN ESCROW: Return escrowed funds to payer (cancel task).
2553
+ *
2554
+ * Calls PaymentOperator.refundInEscrow() -> escrow.partialVoid()
2555
+ *
2556
+ * @param paymentInfo - PaymentInfo from the authorize step
2557
+ * @param amount - Amount to refund (defaults to maxAmount)
2558
+ */
2559
+ async refundInEscrow(paymentInfo, amount) {
2560
+ if (!this.payerAddress) await this.init();
2561
+ try {
2562
+ const { ethers } = await import('ethers');
2563
+ const contract = new ethers.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
2564
+ const amt = amount || paymentInfo.maxAmount;
2565
+ const tuple = this.buildTuple(paymentInfo);
2566
+ const tx = await contract.refundInEscrow(tuple, amt, { gasLimit: this.gasLimit });
2567
+ const receipt = await tx.wait();
2568
+ return {
2569
+ success: receipt.status === 1,
2570
+ transactionHash: receipt.hash,
2571
+ gasUsed: Number(receipt.gasUsed),
2572
+ error: receipt.status !== 1 ? "Transaction reverted" : void 0
2573
+ };
2574
+ } catch (e) {
2575
+ return { success: false, error: e.message || String(e) };
2576
+ }
2577
+ }
2578
+ /**
2579
+ * CHARGE: Direct instant payment (no escrow hold).
2580
+ *
2581
+ * Calls PaymentOperator.charge() -> escrow.charge()
2582
+ * Funds go directly from payer to receiver.
2583
+ *
2584
+ * @param paymentInfo - PaymentInfo with receiver and amount
2585
+ * @param amount - Amount to charge (defaults to maxAmount)
2586
+ */
2587
+ async charge(paymentInfo, amount) {
2588
+ if (!this.payerAddress) await this.init();
2589
+ try {
2590
+ const { ethers } = await import('ethers');
2591
+ const nonce = await this.computeNonce(paymentInfo);
2592
+ const amt = amount || paymentInfo.maxAmount;
2593
+ const auth = {
2594
+ from: this.payerAddress,
2595
+ to: this.contracts.tokenCollector,
2596
+ value: String(amt),
2597
+ validAfter: "0",
2598
+ validBefore: String(paymentInfo.preApprovalExpiry),
2599
+ nonce
2600
+ };
2601
+ const signature = await this.signErc3009(auth);
2602
+ const collectorData = ethers.getBytes(signature);
2603
+ const contract = new ethers.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
2604
+ const tuple = this.buildTuple(paymentInfo);
2605
+ const tx = await contract.charge(
2606
+ tuple,
2607
+ amt,
2608
+ this.contracts.tokenCollector,
2609
+ collectorData,
2610
+ { gasLimit: this.gasLimit }
2611
+ );
2612
+ const receipt = await tx.wait();
2613
+ return {
2614
+ success: receipt.status === 1,
2615
+ transactionHash: receipt.hash,
2616
+ gasUsed: Number(receipt.gasUsed),
2617
+ error: receipt.status !== 1 ? "Transaction reverted" : void 0
2618
+ };
2619
+ } catch (e) {
2620
+ return { success: false, error: e.message || String(e) };
2621
+ }
2622
+ }
2623
+ /**
2624
+ * REFUND POST ESCROW: Dispute refund after funds were released.
2625
+ *
2626
+ * Calls PaymentOperator.refundPostEscrow() -> escrow.refund()
2627
+ *
2628
+ * WARNING: NOT FUNCTIONAL IN PRODUCTION (as of 2026-02-03).
2629
+ * The protocol team has not implemented the required tokenCollector
2630
+ * contract. This call will fail on-chain.
2631
+ *
2632
+ * For dispute resolution, use refundInEscrow() instead: keep funds
2633
+ * in escrow and refund before releasing. This guarantees funds are
2634
+ * available and under arbiter control.
2635
+ *
2636
+ * Kept for future use when tokenCollector is implemented.
2637
+ *
2638
+ * @param paymentInfo - PaymentInfo from the original authorization
2639
+ * @param amount - Amount to refund (defaults to maxAmount)
2640
+ * @param tokenCollector - Address of token collector for refund sourcing
2641
+ * @param collectorData - Data for the token collector
2642
+ */
2643
+ async refundPostEscrow(paymentInfo, amount, tokenCollector, collectorData) {
2644
+ if (!this.payerAddress) await this.init();
2645
+ try {
2646
+ const { ethers } = await import('ethers');
2647
+ const contract = new ethers.Contract(this.contracts.operator, OPERATOR_ABI, this.signer);
2648
+ const amt = amount || paymentInfo.maxAmount;
2649
+ const tuple = this.buildTuple(paymentInfo);
2650
+ const tx = await contract.refundPostEscrow(
2651
+ tuple,
2652
+ amt,
2653
+ tokenCollector || ZERO_ADDRESS,
2654
+ collectorData || "0x",
2655
+ { gasLimit: this.gasLimit }
2656
+ );
2657
+ const receipt = await tx.wait();
2658
+ return {
2659
+ success: receipt.status === 1,
2660
+ transactionHash: receipt.hash,
2661
+ gasUsed: Number(receipt.gasUsed),
2662
+ error: receipt.status !== 1 ? "Transaction reverted" : void 0
2663
+ };
2664
+ } catch (e) {
2665
+ return { success: false, error: e.message || String(e) };
2666
+ }
2667
+ }
2668
+ };
2244
2669
 
2670
+ exports.AdvancedEscrowClient = AdvancedEscrowClient;
2671
+ exports.BASE_MAINNET_CONTRACTS = BASE_MAINNET_CONTRACTS;
2245
2672
  exports.BazaarClient = BazaarClient;
2673
+ exports.DEPOSIT_LIMIT_USDC = DEPOSIT_LIMIT_USDC;
2246
2674
  exports.ERC8004_CONTRACTS = ERC8004_CONTRACTS;
2247
2675
  exports.ERC8004_EXTENSION_ID = ERC8004_EXTENSION_ID;
2248
2676
  exports.Erc8004Client = Erc8004Client;
2249
2677
  exports.EscrowClient = EscrowClient;
2250
2678
  exports.FacilitatorClient = FacilitatorClient;
2679
+ exports.OPERATOR_ABI = OPERATOR_ABI;
2680
+ exports.PAYMENT_INFO_TYPEHASH = PAYMENT_INFO_TYPEHASH;
2681
+ exports.TIER_TIMINGS = TIER_TIMINGS;
2251
2682
  exports.X402_CORS_HEADERS = X402_CORS_HEADERS;
2252
2683
  exports.X402_HEADER_NAMES = X402_HEADER_NAMES;
2684
+ exports.ZERO_ADDRESS = ZERO_ADDRESS;
2253
2685
  exports.buildErc8004PaymentRequirements = buildErc8004PaymentRequirements;
2254
2686
  exports.buildPaymentRequirements = buildPaymentRequirements;
2255
2687
  exports.buildSettleRequest = buildSettleRequest;