@dcentralab/d402-client 0.2.0 → 0.2.2

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/dist/index.d.mts CHANGED
@@ -6,9 +6,9 @@ import { Hash, Address } from 'viem';
6
6
  */
7
7
 
8
8
  /**
9
- * Supported blockchain networks
9
+ * Supported blockchain networks (where IATP contracts are deployed)
10
10
  */
11
- type SupportedNetwork = 'mainnet' | 'sepolia' | 'base' | 'polygon';
11
+ type SupportedNetwork = 'sepolia';
12
12
  /**
13
13
  * D402 Client configuration
14
14
  */
@@ -34,9 +34,9 @@ interface EIP712Domain {
34
34
  verifyingContract: `0x${string}`;
35
35
  }
36
36
  /**
37
- * Payment requirement from 402 response
37
+ * Payment requirement from 402 response.
38
38
  *
39
- * Matches Python: PaymentRequirements (types.py lines 97-108)
39
+ * Describes the payment details required by a 402-protected API.
40
40
  */
41
41
  interface PaymentRequirement {
42
42
  /** D402 protocol version */
@@ -128,7 +128,7 @@ interface PaymentSelectorOptions {
128
128
  /**
129
129
  * Select payment requirement from a list based on filters and preferences
130
130
  *
131
- * This function implements the same logic as Python's default_payment_requirements_selector
131
+ * This function implements the same logic as
132
132
  *
133
133
  * @param requirements - List of accepted payment requirements from 402 response
134
134
  * @param options - Selection options and filters
@@ -177,20 +177,23 @@ declare function sortPaymentRequirements(requirements: PaymentRequirement[], pre
177
177
  /**
178
178
  * D402 Client - Main client class for handling HTTP 402 payments
179
179
  *
180
- * Matches Python implementation: IATP/src/traia_iatp/d402/clients/base.py d402Client
181
180
  */
182
181
 
183
182
  /**
184
183
  * D402 Client configuration.
185
184
  *
186
- * Matches Python: d402Client.__init__ parameters (base.py lines 66-72)
185
+ * The client uses the user's wallet to sign payment authorizations for 402-protected APIs.
187
186
  */
188
187
  interface D402ClientConfig {
189
- /** Operator account with private key for signing payments (EOA) */
188
+ /**
189
+ * User's account for signing payments.
190
+ * Typically from wagmi: `walletClient.account`
191
+ */
190
192
  operatorAccount: Account;
191
193
  /**
192
- * IATPWallet contract address.
193
- * If not provided, uses operatorAccount.address for testing.
194
+ * IATPWallet contract address (optional).
195
+ * If not provided, uses operatorAccount.address directly.
196
+ * Get from `createIATPWallet()` or `getWalletsByOwner()`.
194
197
  */
195
198
  iatpWalletAddress?: `0x${string}`;
196
199
  /**
@@ -227,8 +230,6 @@ interface D402ClientConfig {
227
230
  /**
228
231
  * D402 Client for handling HTTP 402 Payment Required responses.
229
232
  *
230
- * Matches Python: d402Client class (base.py lines 63-219)
231
- *
232
233
  * This client automatically:
233
234
  * 1. Detects HTTP 402 responses
234
235
  * 2. Parses payment requirements
@@ -267,15 +268,23 @@ declare class D402Client {
267
268
  /**
268
269
  * Create a new D402 Client.
269
270
  *
270
- * Matches Python: d402Client.__init__ (base.py lines 66-95)
271
- *
272
271
  * @param config - Client configuration
272
+ *
273
+ * @example
274
+ * ```ts
275
+ * const client = new D402Client({
276
+ * operatorAccount: walletClient.account, // User's wallet from wagmi
277
+ * iatpWalletAddress: userWallet, // From createIATPWallet() or getWalletsByOwner()
278
+ * maxValue: 1000000n // Safety limit: 1 USDC max
279
+ * })
280
+ * ```
273
281
  */
274
282
  constructor(config: D402ClientConfig);
275
283
  /**
276
284
  * Select payment requirement from list of options.
277
285
  *
278
- * Matches Python: select_payment_requirements (base.py lines 152-174)
286
+ * Applies configured filters (network, scheme, maxValue) to choose
287
+ * the appropriate payment option from the server's requirements list.
279
288
  *
280
289
  * @param requirements - List of payment requirements from 402 response
281
290
  * @returns Selected payment requirement
@@ -284,13 +293,13 @@ declare class D402Client {
284
293
  /**
285
294
  * Get the IATP wallet address used for payments.
286
295
  *
287
- * @returns IATPWallet contract address or operator EOA address
296
+ * @returns IATPWallet contract address, or user's EOA address if no wallet configured
288
297
  */
289
298
  getIATPWalletAddress(): `0x${string}`;
290
299
  /**
291
- * Get the operator account used for signing.
300
+ * Get the user's account used for signing payments.
292
301
  *
293
- * @returns Operator account
302
+ * @returns User's wallet account
294
303
  */
295
304
  getOperatorAccount(): Account;
296
305
  /**
@@ -302,7 +311,6 @@ declare class D402Client {
302
311
  /**
303
312
  * Fetch with automatic 402 payment handling.
304
313
  *
305
- * Matches Python: HttpxHooks.on_response() (httpx.py lines 33-117)
306
314
  *
307
315
  * Flow:
308
316
  * 1. Make request without payment
@@ -334,34 +342,37 @@ declare class D402Client {
334
342
 
335
343
  /**
336
344
  * EIP-712 payment signing utilities
337
- *
338
- * Matches Python implementation: IATP/src/traia_iatp/d402/payment_signing.py
339
345
  */
340
346
 
341
347
  /**
342
348
  * Sign a D402 payment using EIP-712 signature.
343
349
  *
344
- * Matches Python: sign_payment_header(operator_account, payment_requirements, header, wallet_address, request_path)
345
- * (payment_signing.py lines 54-155)
350
+ * Signs a payment authorization with the user's wallet (MetaMask/WalletConnect).
351
+ * This creates a PullFundsForSettlement signature that authorizes the payment.
346
352
  *
347
- * This creates a PullFundsForSettlement signature that matches IATPWallet.sol validation.
353
+ * The user will see a MetaMask popup to approve the signature.
348
354
  *
349
355
  * @param params - Signing parameters
350
- * @param params.operatorAccount - Operator account with private key for signing (EOA)
356
+ * @param params.operatorAccount - User's account for signing (from wagmi walletClient)
351
357
  * @param params.paymentRequirement - Payment requirements from 402 response
352
- * @param params.iatpWalletAddress - IATPWallet contract address (optional, uses operator address if not provided)
358
+ * @param params.iatpWalletAddress - IATPWallet contract address (optional)
353
359
  * @param params.requestPath - API request path (optional, uses payment_requirements.resource if not provided)
354
360
  * @returns Signed payment ready to encode and send
355
361
  *
356
362
  * @example
357
363
  * ```ts
364
+ * // Get payment requirement from 402 response
358
365
  * const requirement = await parsePaymentRequirement(response)
366
+ *
367
+ * // User signs payment (MetaMask popup appears)
359
368
  * const signedPayment = await signD402Payment({
360
- * operatorAccount: account,
369
+ * operatorAccount: walletClient.account, // User's wallet
361
370
  * paymentRequirement: requirement,
362
- * iatpWalletAddress: '0xUserWallet...'
371
+ * iatpWalletAddress: '0xUserIATPWallet...'
363
372
  * })
364
- * const encoded = encodePayment(signedPayment)
373
+ *
374
+ * // Encode for X-Payment header
375
+ * const paymentHeader = encodePayment(signedPayment)
365
376
  * ```
366
377
  */
367
378
  declare function signD402Payment(params: {
@@ -374,30 +385,27 @@ declare function signD402Payment(params: {
374
385
 
375
386
  /**
376
387
  * Parse 402 payment requirements from HTTP responses
377
- *
378
- * Matches Python implementation: IATP/src/traia_iatp/d402/clients/httpx.py lines 64-66
379
- * Response structure from: IATP/src/traia_iatp/d402/types.py d402PaymentRequiredResponse
380
388
  */
381
389
 
382
390
  /**
383
391
  * Parse payment requirements from HTTP 402 response.
384
392
  *
385
- * Matches Python:
386
- * data = response.json()
387
- * payment_response = d402PaymentRequiredResponse(**data)
388
- *
389
- * The 402 response body contains payment requirements in camelCase JSON format.
393
+ * When an API returns 402 "Payment Required", this function extracts
394
+ * the payment details (amount, token, network) from the response body.
390
395
  *
391
396
  * @param response - HTTP Response object with status 402
392
- * @returns First payment requirement from accepts array
397
+ * @returns First payment requirement from the response
393
398
  * @throws {Invalid402ResponseError} If response is not valid 402 or malformed
394
399
  *
395
400
  * @example
396
401
  * ```ts
397
- * const response = await fetch('http://api.example.com')
402
+ * const response = await fetch('https://sentiment-api.com/analyze')
403
+ *
398
404
  * if (response.status === 402) {
399
405
  * const requirement = await parsePaymentRequirement(response)
400
- * console.log(requirement.maxAmountRequired) // "10000"
406
+ * console.log('Payment required:', requirement.maxAmountRequired, 'wei')
407
+ * console.log('Token:', requirement.asset)
408
+ * console.log('Network:', requirement.network)
401
409
  * }
402
410
  * ```
403
411
  */
@@ -405,32 +413,32 @@ declare function parsePaymentRequirement(response: Response): Promise<PaymentReq
405
413
 
406
414
  /**
407
415
  * Base64 encoding/decoding for payment payloads
408
- *
409
- * Matches Python implementation: IATP/src/traia_iatp/d402/encoding.py
410
416
  */
411
417
 
412
418
  /**
413
- * Encode a payment object to base64 string.
419
+ * Encode a signed payment to base64 string for X-Payment header.
414
420
  *
415
- * This combines JSON serialization with base64 encoding.
416
- * Matches Python: encode_payment(payment_payload: Dict[str, Any]) -> str
421
+ * Takes a signed payment object and encodes it to base64 format
422
+ * that can be sent in the X-Payment HTTP header.
417
423
  *
418
- * @param payment - Payment object to encode
419
- * @returns Base64 encoded payment string suitable for X-Payment header
424
+ * @param payment - Signed payment object (from signD402Payment)
425
+ * @returns Base64 encoded string ready for X-Payment header
420
426
  *
421
427
  * @example
422
428
  * ```ts
423
- * const payment = { d402Version: 1, scheme: 'exact', payload: {...} }
424
- * const encoded = encodePayment(payment)
425
- * // Use in header: { 'X-Payment': encoded }
429
+ * const signedPayment = await signD402Payment({...})
430
+ * const encoded = encodePayment(signedPayment)
431
+ *
432
+ * // Send in HTTP request
433
+ * fetch(url, {
434
+ * headers: { 'X-Payment': encoded }
435
+ * })
426
436
  * ```
427
437
  */
428
438
  declare function encodePayment(payment: SignedPayment): string;
429
439
  /**
430
440
  * Decode a base64 encoded payment string back to payment object.
431
441
  *
432
- * Matches Python: decode_payment(encoded_payment: str) -> Dict[str, Any]
433
- *
434
442
  * @param encodedPayment - Base64 encoded payment string
435
443
  * @returns Decoded payment object
436
444
  *
@@ -481,9 +489,12 @@ declare function getUsdcAddress(network: SupportedNetwork): `0x${string}`;
481
489
  /**
482
490
  * Get chain ID for a given network.
483
491
  *
484
- * Matches Python: get_chain_id(network: str) -> str (chains.py lines 10-21)
492
+ * This function maps network names to chain IDs for parsing 402 payment requirements
493
+ * from external APIs. It supports many networks that may appear in 402 responses,
494
+ * even if IATP contracts are not deployed on those networks.
485
495
  *
486
- * Supports both network names and numeric chain IDs as strings.
496
+ * Note: IATP contracts are currently only deployed on Sepolia. This function exists
497
+ * to handle 402 responses from any API that might support other networks.
487
498
  *
488
499
  * @param network - Network name or chain ID as string
489
500
  * @returns Chain ID as number
@@ -494,7 +505,7 @@ declare function getUsdcAddress(network: SupportedNetwork): `0x${string}`;
494
505
  * ```ts
495
506
  * getChainId('sepolia') // Returns 11155111
496
507
  * getChainId('11155111') // Returns 11155111 (passthrough)
497
- * getChainId('base') // Returns 8453
508
+ * getChainId('base') // Returns 8453 (for parsing 402 responses)
498
509
  * ```
499
510
  */
500
511
  declare function getChainId(network: string): number;
@@ -675,16 +686,13 @@ declare const EIP712_TYPES: {
675
686
  };
676
687
 
677
688
  /**
678
- * Contract configuration and utilities for IATP.
679
- *
680
- * Matches Python implementation: IATP/src/traia_iatp/contracts/config.py
689
+ * Contract configuration and utilities.
681
690
  *
682
- * Bundles contract ABIs and addresses directly in the package for reliable access.
691
+ * Provides access to IATPWallet contract ABIs and deployed addresses.
692
+ * Contract data is bundled directly in the package for reliability.
683
693
  */
684
694
  /**
685
695
  * Supported contract names.
686
- *
687
- * Matches Python: ContractName enum (config.py lines 16-21)
688
696
  */
689
697
  declare enum ContractName {
690
698
  IATP_WALLET = "IATPWallet",
@@ -694,16 +702,11 @@ declare enum ContractName {
694
702
  }
695
703
  /**
696
704
  * Supported networks for contract deployments.
697
- *
698
- * Matches Python: SUPPORTED_NETWORKS (config.py line 25)
699
705
  */
700
- type SupportedContractNetwork = 'sepolia' | 'localhost';
706
+ type SupportedContractNetwork = 'sepolia';
701
707
  /**
702
708
  * Get contract address for a given network.
703
709
  *
704
- * Matches Python: get_contract_address(contract_name: str, network: str) -> Optional[str]
705
- * (config.py lines 77-118)
706
- *
707
710
  * @param contractName - Name of the contract (use ContractName enum)
708
711
  * @param network - Network name (default: "sepolia")
709
712
  * @param useProxy - Use proxy address if true, implementation if false (default: true)
@@ -719,9 +722,6 @@ declare function getContractAddress(contractName: string | ContractName, network
719
722
  /**
720
723
  * Get contract ABI for a given network.
721
724
  *
722
- * Matches Python: get_contract_abi(contract_name: str, network: str) -> Optional[List[dict]]
723
- * (config.py lines 121-156)
724
- *
725
725
  * @param contractName - Name of the contract (use ContractName enum)
726
726
  * @param network - Network name (default: "sepolia")
727
727
  * @returns Contract ABI as array of objects, or null if not found
@@ -736,8 +736,6 @@ declare function getContractAbi(contractName: string | ContractName, network?: S
736
736
  /**
737
737
  * Get contract configuration (address and ABI) for a network.
738
738
  *
739
- * Matches Python: get_contract_config(network: str) from wallet_creator.py
740
- *
741
739
  * @param contractName - Name of the contract
742
740
  * @param network - Network name (default: "sepolia")
743
741
  * @returns Object with address and abi, or null if not found
@@ -787,23 +785,16 @@ declare function isContractDeployed(contractName: string | ContractName, network
787
785
  /**
788
786
  * IATPWallet creation and management
789
787
  *
790
- * Matches Python implementation: IATP/src/traia_iatp/scripts/create_wallet.py
791
788
  */
792
789
 
793
790
  /**
794
791
  * Result of wallet creation.
795
- *
796
- * Matches Python: create_wallet() return type (lines 138-147)
797
792
  */
798
793
  interface WalletCreationResult {
799
794
  /** Address of the created IATPWallet contract */
800
795
  walletAddress: `0x${string}`;
801
- /** Owner address (who created it) */
796
+ /** Owner address (who created it, also the operator) */
802
797
  ownerAddress: `0x${string}`;
803
- /** Operator address (can sign payments) */
804
- operatorAddress: `0x${string}`;
805
- /** Operator private key (store securely!) */
806
- operatorPrivateKey: `0x${string}`;
807
798
  /** Transaction hash */
808
799
  transactionHash: Hash;
809
800
  /** Block number where wallet was created */
@@ -816,15 +807,15 @@ interface WalletCreationResult {
816
807
  /**
817
808
  * Create a new IATPWallet using IATPWalletFactory.
818
809
  *
819
- * Matches Python: create_wallet(owner_private_key, network, wait_confirmations)
820
- * (create_wallet.py lines 37-149)
810
+ * Creates an on-chain smart contract wallet where the user is both owner and operator.
811
+ * The user signs all payments themselves with their wallet (MetaMask/WalletConnect).
821
812
  *
822
813
  * This function:
823
- * 1. Generates a new operator keypair
824
- * 2. Calls IATPWalletFactory.createWallet(operatorAddress)
814
+ * 1. Calls IATPWalletFactory.createWallet(ownerAddress)
815
+ * 2. Sets owner as operator (user signs all payments)
825
816
  * 3. Waits for transaction confirmation
826
817
  * 4. Extracts wallet address from WalletCreated event
827
- * 5. Returns wallet info including operator keys
818
+ * 5. Returns wallet address and transaction info
828
819
  *
829
820
  * @param params - Creation parameters
830
821
  * @param params.ownerAccount - Owner's account (will own the wallet)
@@ -851,9 +842,8 @@ interface WalletCreationResult {
851
842
  */
852
843
  declare function createIATPWallet(params: {
853
844
  ownerAccount: Account;
854
- network?: 'sepolia' | 'localhost';
845
+ network?: 'sepolia';
855
846
  rpcUrl?: string;
856
- operatorPrivateKey?: `0x${string}`;
857
847
  }): Promise<WalletCreationResult>;
858
848
  /**
859
849
  * Get all IATPWallet addresses owned by a user.
@@ -861,29 +851,37 @@ declare function createIATPWallet(params: {
861
851
  * Queries the IATPWalletFactory contract to retrieve all wallets
862
852
  * where the specified address is the owner.
863
853
  *
854
+ * Use this to check if a user already has a wallet before calling createIATPWallet().
855
+ *
864
856
  * @param params - Query parameters
865
- * @param params.ownerAddress - Owner's address to query
857
+ * @param params.ownerAddress - User's wallet address (from MetaMask)
866
858
  * @param params.network - Network to query (default: "sepolia")
867
859
  * @param params.rpcUrl - Custom RPC URL (optional)
868
- * @returns Array of IATPWallet contract addresses
860
+ * @returns Array of IATPWallet contract addresses (empty if user has no wallets)
869
861
  *
870
862
  * @example
871
863
  * ```ts
872
864
  * import { getWalletsByOwner } from '@dcentralab/d402-client'
865
+ * import { useAccount } from 'wagmi'
866
+ *
867
+ * const { address } = useAccount()
873
868
  *
874
- * // Get user's wallets
869
+ * // Check if user has any wallets
875
870
  * const wallets = await getWalletsByOwner({
876
- * ownerAddress: '0xUserAddress...',
871
+ * ownerAddress: address,
877
872
  * network: 'sepolia'
878
873
  * })
879
874
  *
880
- * console.log(`User has ${wallets.length} wallets`)
881
- * wallets.forEach(addr => console.log('Wallet:', addr))
875
+ * if (wallets.length === 0) {
876
+ * // Show "Create Wallet" button
877
+ * } else {
878
+ * // Use existing wallet: wallets[0]
879
+ * }
882
880
  * ```
883
881
  */
884
882
  declare function getWalletsByOwner(params: {
885
883
  ownerAddress: Address;
886
- network?: 'sepolia' | 'localhost';
884
+ network?: 'sepolia';
887
885
  rpcUrl?: string;
888
886
  }): Promise<Address[]>;
889
887