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.
- t402/__init__.py +169 -2
- t402/common.py +37 -8
- t402/encoding.py +298 -1
- t402/facilitator.py +1 -1
- t402/fastapi/__init__.py +79 -0
- t402/fastapi/dependencies.py +398 -0
- t402/fastapi/middleware.py +665 -130
- t402/schemes/__init__.py +164 -0
- t402/schemes/evm/__init__.py +46 -0
- t402/schemes/evm/exact/__init__.py +29 -0
- t402/schemes/evm/exact/client.py +265 -0
- t402/schemes/evm/exact/server.py +181 -0
- t402/schemes/evm/upto/__init__.py +58 -0
- t402/schemes/evm/upto/client.py +240 -0
- t402/schemes/evm/upto/types.py +305 -0
- t402/schemes/interfaces.py +401 -0
- t402/schemes/registry.py +477 -0
- t402/schemes/ton/__init__.py +22 -0
- t402/schemes/ton/exact/__init__.py +27 -0
- t402/schemes/ton/exact/client.py +343 -0
- t402/schemes/ton/exact/server.py +201 -0
- t402/schemes/tron/__init__.py +22 -0
- t402/schemes/tron/exact/__init__.py +27 -0
- t402/schemes/tron/exact/client.py +260 -0
- t402/schemes/tron/exact/server.py +192 -0
- t402/schemes/upto/__init__.py +80 -0
- t402/schemes/upto/types.py +376 -0
- t402/types.py +178 -8
- {t402-1.6.1.dist-info → t402-1.9.0.dist-info}/METADATA +1 -1
- {t402-1.6.1.dist-info → t402-1.9.0.dist-info}/RECORD +32 -11
- {t402-1.6.1.dist-info → t402-1.9.0.dist-info}/WHEEL +0 -0
- {t402-1.6.1.dist-info → t402-1.9.0.dist-info}/entry_points.txt +0 -0
|
@@ -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
|