t402 1.6.1__py3-none-any.whl → 1.9.0__py3-none-any.whl

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.
@@ -0,0 +1,401 @@
1
+ """Scheme Interface Definitions for T402 Protocol.
2
+
3
+ This module defines the abstract interfaces for payment schemes in the T402 protocol.
4
+ Schemes implement these interfaces to provide payment functionality for specific
5
+ blockchain networks.
6
+
7
+ The three main interfaces are:
8
+ - SchemeNetworkClient: For clients creating payment payloads
9
+ - SchemeNetworkServer: For servers parsing prices and building requirements
10
+ - SchemeNetworkFacilitator: For facilitators verifying and settling payments
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from abc import ABC, abstractmethod
16
+ from typing import Any, Dict, List, Optional, Protocol, Union, runtime_checkable
17
+
18
+ from t402.types import (
19
+ Network,
20
+ PaymentRequirementsV2,
21
+ PaymentPayloadV2,
22
+ VerifyResponse,
23
+ SettleResponse,
24
+ )
25
+
26
+
27
+ # Type aliases for clarity
28
+ Price = Union[str, int, float, Dict[str, Any]] # e.g., "$0.10", 0.10, {"amount": "100000", "asset": "..."}
29
+ AssetAmount = Dict[str, Any] # {"amount": str, "asset": str, "extra"?: dict}
30
+ SupportedKindDict = Dict[str, Any] # {"t402Version": int, "scheme": str, "network": str, "extra"?: dict}
31
+
32
+
33
+ @runtime_checkable
34
+ class SchemeNetworkClient(Protocol):
35
+ """Protocol for client-side payment scheme implementations.
36
+
37
+ Clients use this interface to create payment payloads when responding
38
+ to 402 Payment Required responses.
39
+
40
+ Attributes:
41
+ scheme: The scheme identifier (e.g., "exact")
42
+
43
+ Example:
44
+ ```python
45
+ class ExactEvmClientScheme:
46
+ scheme = "exact"
47
+
48
+ async def create_payment_payload(
49
+ self,
50
+ t402_version: int,
51
+ requirements: PaymentRequirementsV2,
52
+ ) -> Dict[str, Any]:
53
+ # Sign EIP-3009 authorization
54
+ signature = await self.signer.sign(...)
55
+ return {
56
+ "t402Version": t402_version,
57
+ "payload": {"signature": signature, "authorization": {...}}
58
+ }
59
+ ```
60
+ """
61
+
62
+ @property
63
+ def scheme(self) -> str:
64
+ """The scheme identifier (e.g., 'exact', 'streaming')."""
65
+ ...
66
+
67
+ async def create_payment_payload(
68
+ self,
69
+ t402_version: int,
70
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
71
+ ) -> Dict[str, Any]:
72
+ """Create a payment payload for the given requirements.
73
+
74
+ This method should:
75
+ 1. Extract payment parameters from requirements
76
+ 2. Create and sign the appropriate authorization
77
+ 3. Return a partial PaymentPayload (t402Version + payload fields)
78
+
79
+ Args:
80
+ t402_version: The T402 protocol version
81
+ requirements: The payment requirements to fulfill
82
+
83
+ Returns:
84
+ Dict containing at minimum:
85
+ - t402Version: Protocol version
86
+ - payload: Scheme-specific payload data
87
+
88
+ Raises:
89
+ ValueError: If requirements are invalid
90
+ SigningError: If signing fails
91
+ """
92
+ ...
93
+
94
+
95
+ @runtime_checkable
96
+ class SchemeNetworkServer(Protocol):
97
+ """Protocol for server-side payment scheme implementations.
98
+
99
+ Servers use this interface to:
100
+ - Parse user-friendly prices into atomic amounts
101
+ - Enhance payment requirements with scheme-specific data
102
+
103
+ Attributes:
104
+ scheme: The scheme identifier (e.g., "exact")
105
+
106
+ Example:
107
+ ```python
108
+ class ExactEvmServerScheme:
109
+ scheme = "exact"
110
+
111
+ async def parse_price(self, price: Price, network: Network) -> AssetAmount:
112
+ # Convert "$0.10" to {"amount": "100000", "asset": "0xUSDC..."}
113
+ ...
114
+
115
+ async def enhance_requirements(
116
+ self,
117
+ requirements: PaymentRequirementsV2,
118
+ supported_kind: SupportedKindDict,
119
+ extensions: List[str],
120
+ ) -> PaymentRequirementsV2:
121
+ # Add EIP-712 domain info to extra
122
+ ...
123
+ ```
124
+ """
125
+
126
+ @property
127
+ def scheme(self) -> str:
128
+ """The scheme identifier (e.g., 'exact', 'streaming')."""
129
+ ...
130
+
131
+ async def parse_price(
132
+ self,
133
+ price: Price,
134
+ network: Network,
135
+ ) -> AssetAmount:
136
+ """Convert a user-friendly price to atomic amount and asset.
137
+
138
+ This method should:
139
+ 1. Parse the price (handling "$0.10", 0.10, or TokenAmount formats)
140
+ 2. Look up the appropriate token/asset for the network
141
+ 3. Convert to atomic units
142
+
143
+ Args:
144
+ price: User-friendly price (e.g., "$0.10", 0.10, or TokenAmount dict)
145
+ network: The network identifier (CAIP-2 format)
146
+
147
+ Returns:
148
+ AssetAmount dict with:
149
+ - amount: Atomic amount as string
150
+ - asset: Asset/token address
151
+ - extra: Optional extra metadata (e.g., decimals, symbol)
152
+
153
+ Raises:
154
+ ValueError: If price format is invalid or network unsupported
155
+ """
156
+ ...
157
+
158
+ async def enhance_requirements(
159
+ self,
160
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
161
+ supported_kind: SupportedKindDict,
162
+ facilitator_extensions: List[str],
163
+ ) -> Union[PaymentRequirementsV2, Dict[str, Any]]:
164
+ """Enhance payment requirements with scheme-specific data.
165
+
166
+ This method should add any scheme-specific metadata to the requirements
167
+ that clients need to create valid payments (e.g., EIP-712 domain info,
168
+ fee payer addresses, etc.).
169
+
170
+ Args:
171
+ requirements: Base payment requirements with amount/asset set
172
+ supported_kind: The matched SupportedKind from facilitator
173
+ facilitator_extensions: Extensions supported by the facilitator
174
+
175
+ Returns:
176
+ Enhanced PaymentRequirementsV2 with additional data in 'extra' field
177
+ """
178
+ ...
179
+
180
+
181
+ @runtime_checkable
182
+ class SchemeNetworkFacilitator(Protocol):
183
+ """Protocol for facilitator-side payment scheme implementations.
184
+
185
+ Facilitators use this interface to:
186
+ - Verify payment signatures before granting access
187
+ - Settle payments on-chain after successful delivery
188
+
189
+ Attributes:
190
+ scheme: The scheme identifier (e.g., "exact")
191
+ caip_family: CAIP-2 family pattern (e.g., "eip155:*", "solana:*")
192
+
193
+ Example:
194
+ ```python
195
+ class ExactEvmFacilitatorScheme:
196
+ scheme = "exact"
197
+ caip_family = "eip155:*"
198
+
199
+ def get_signers(self, network: str) -> List[str]:
200
+ return [self.signer.address]
201
+
202
+ async def verify(self, payload, requirements) -> VerifyResponse:
203
+ # Verify EIP-3009 signature
204
+ ...
205
+
206
+ async def settle(self, payload, requirements) -> SettleResponse:
207
+ # Submit EIP-3009 transferWithAuthorization
208
+ ...
209
+ ```
210
+ """
211
+
212
+ @property
213
+ def scheme(self) -> str:
214
+ """The scheme identifier (e.g., 'exact', 'streaming')."""
215
+ ...
216
+
217
+ @property
218
+ def caip_family(self) -> str:
219
+ """CAIP-2 family pattern for network matching.
220
+
221
+ Used to group signers by blockchain family in the supported response.
222
+
223
+ Examples:
224
+ - "eip155:*" for all EVM networks
225
+ - "solana:*" for all Solana networks
226
+ - "ton:*" for all TON networks
227
+ """
228
+ ...
229
+
230
+ def get_extra(self, network: Network) -> Optional[Dict[str, Any]]:
231
+ """Get mechanism-specific extra data for supported kinds.
232
+
233
+ Called when building the facilitator's /supported response.
234
+ Return None if no extra data is needed.
235
+
236
+ Args:
237
+ network: The network identifier
238
+
239
+ Returns:
240
+ Optional dict with extra metadata (e.g., {"feePayer": "..."})
241
+ """
242
+ ...
243
+
244
+ def get_signers(self, network: Network) -> List[str]:
245
+ """Get signer addresses for this facilitator.
246
+
247
+ Returns addresses that may sign/pay for transactions on behalf
248
+ of the facilitator. Used in the /supported response.
249
+
250
+ Args:
251
+ network: The network identifier
252
+
253
+ Returns:
254
+ List of signer addresses
255
+ """
256
+ ...
257
+
258
+ async def verify(
259
+ self,
260
+ payload: Union[PaymentPayloadV2, Dict[str, Any]],
261
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
262
+ ) -> VerifyResponse:
263
+ """Verify a payment payload against requirements.
264
+
265
+ This method should:
266
+ 1. Validate the signature/authorization
267
+ 2. Check amount, recipient, and timing constraints
268
+ 3. Return verification result
269
+
270
+ Args:
271
+ payload: The payment payload to verify
272
+ requirements: The payment requirements to verify against
273
+
274
+ Returns:
275
+ VerifyResponse indicating validity and payer address
276
+ """
277
+ ...
278
+
279
+ async def settle(
280
+ self,
281
+ payload: Union[PaymentPayloadV2, Dict[str, Any]],
282
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
283
+ ) -> SettleResponse:
284
+ """Settle a verified payment on-chain.
285
+
286
+ This method should:
287
+ 1. Submit the payment transaction to the blockchain
288
+ 2. Wait for confirmation (or return pending status)
289
+ 3. Return settlement result
290
+
291
+ Args:
292
+ payload: The verified payment payload
293
+ requirements: The payment requirements
294
+
295
+ Returns:
296
+ SettleResponse with transaction hash and status
297
+ """
298
+ ...
299
+
300
+
301
+ # Abstract Base Classes (for those who prefer inheritance)
302
+
303
+
304
+ class BaseSchemeNetworkClient(ABC):
305
+ """Abstract base class for client schemes.
306
+
307
+ Use this if you prefer inheritance over Protocol typing.
308
+ """
309
+
310
+ @property
311
+ @abstractmethod
312
+ def scheme(self) -> str:
313
+ """The scheme identifier."""
314
+ pass
315
+
316
+ @abstractmethod
317
+ async def create_payment_payload(
318
+ self,
319
+ t402_version: int,
320
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
321
+ ) -> Dict[str, Any]:
322
+ """Create a payment payload."""
323
+ pass
324
+
325
+
326
+ class BaseSchemeNetworkServer(ABC):
327
+ """Abstract base class for server schemes.
328
+
329
+ Use this if you prefer inheritance over Protocol typing.
330
+ """
331
+
332
+ @property
333
+ @abstractmethod
334
+ def scheme(self) -> str:
335
+ """The scheme identifier."""
336
+ pass
337
+
338
+ @abstractmethod
339
+ async def parse_price(
340
+ self,
341
+ price: Price,
342
+ network: Network,
343
+ ) -> AssetAmount:
344
+ """Parse a price to atomic amount."""
345
+ pass
346
+
347
+ @abstractmethod
348
+ async def enhance_requirements(
349
+ self,
350
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
351
+ supported_kind: SupportedKindDict,
352
+ facilitator_extensions: List[str],
353
+ ) -> Union[PaymentRequirementsV2, Dict[str, Any]]:
354
+ """Enhance payment requirements."""
355
+ pass
356
+
357
+
358
+ class BaseSchemeNetworkFacilitator(ABC):
359
+ """Abstract base class for facilitator schemes.
360
+
361
+ Use this if you prefer inheritance over Protocol typing.
362
+ """
363
+
364
+ @property
365
+ @abstractmethod
366
+ def scheme(self) -> str:
367
+ """The scheme identifier."""
368
+ pass
369
+
370
+ @property
371
+ @abstractmethod
372
+ def caip_family(self) -> str:
373
+ """CAIP-2 family pattern."""
374
+ pass
375
+
376
+ def get_extra(self, network: Network) -> Optional[Dict[str, Any]]:
377
+ """Get extra data for supported kinds. Override if needed."""
378
+ return None
379
+
380
+ @abstractmethod
381
+ def get_signers(self, network: Network) -> List[str]:
382
+ """Get signer addresses."""
383
+ pass
384
+
385
+ @abstractmethod
386
+ async def verify(
387
+ self,
388
+ payload: Union[PaymentPayloadV2, Dict[str, Any]],
389
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
390
+ ) -> VerifyResponse:
391
+ """Verify a payment."""
392
+ pass
393
+
394
+ @abstractmethod
395
+ async def settle(
396
+ self,
397
+ payload: Union[PaymentPayloadV2, Dict[str, Any]],
398
+ requirements: Union[PaymentRequirementsV2, Dict[str, Any]],
399
+ ) -> SettleResponse:
400
+ """Settle a payment."""
401
+ pass