t402 1.6.1__tar.gz

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.
Files changed (72) hide show
  1. t402-1.6.1/.gitignore +14 -0
  2. t402-1.6.1/.python-version +1 -0
  3. t402-1.6.1/PKG-INFO +470 -0
  4. t402-1.6.1/README.md +445 -0
  5. t402-1.6.1/pyproject.toml +58 -0
  6. t402-1.6.1/src/t402/__init__.py +390 -0
  7. t402-1.6.1/src/t402/bridge/__init__.py +140 -0
  8. t402-1.6.1/src/t402/bridge/client.py +327 -0
  9. t402-1.6.1/src/t402/bridge/constants.py +275 -0
  10. t402-1.6.1/src/t402/bridge/router.py +221 -0
  11. t402-1.6.1/src/t402/bridge/scan.py +226 -0
  12. t402-1.6.1/src/t402/bridge/types.py +306 -0
  13. t402-1.6.1/src/t402/chains.py +92 -0
  14. t402-1.6.1/src/t402/cli.py +324 -0
  15. t402-1.6.1/src/t402/clients/__init__.py +20 -0
  16. t402-1.6.1/src/t402/clients/base.py +199 -0
  17. t402-1.6.1/src/t402/clients/httpx.py +136 -0
  18. t402-1.6.1/src/t402/clients/requests.py +145 -0
  19. t402-1.6.1/src/t402/common.py +169 -0
  20. t402-1.6.1/src/t402/encoding.py +28 -0
  21. t402-1.6.1/src/t402/erc4337/__init__.py +188 -0
  22. t402-1.6.1/src/t402/erc4337/accounts.py +432 -0
  23. t402-1.6.1/src/t402/erc4337/bundlers.py +458 -0
  24. t402-1.6.1/src/t402/erc4337/paymasters.py +530 -0
  25. t402-1.6.1/src/t402/erc4337/types.py +314 -0
  26. t402-1.6.1/src/t402/evm_paywall_template.py +2 -0
  27. t402-1.6.1/src/t402/exact.py +130 -0
  28. t402-1.6.1/src/t402/facilitator.py +135 -0
  29. t402-1.6.1/src/t402/fastapi/__init__.py +0 -0
  30. t402-1.6.1/src/t402/fastapi/middleware.py +219 -0
  31. t402-1.6.1/src/t402/flask/__init__.py +0 -0
  32. t402-1.6.1/src/t402/flask/middleware.py +334 -0
  33. t402-1.6.1/src/t402/mcp/__init__.py +109 -0
  34. t402-1.6.1/src/t402/mcp/constants.py +213 -0
  35. t402-1.6.1/src/t402/mcp/server.py +527 -0
  36. t402-1.6.1/src/t402/mcp/tools.py +169 -0
  37. t402-1.6.1/src/t402/mcp/types.py +241 -0
  38. t402-1.6.1/src/t402/networks.py +132 -0
  39. t402-1.6.1/src/t402/path.py +43 -0
  40. t402-1.6.1/src/t402/paywall.py +132 -0
  41. t402-1.6.1/src/t402/py.typed +0 -0
  42. t402-1.6.1/src/t402/svm.py +1562 -0
  43. t402-1.6.1/src/t402/svm_paywall_template.py +2 -0
  44. t402-1.6.1/src/t402/ton.py +474 -0
  45. t402-1.6.1/src/t402/ton_paywall_template.py +193 -0
  46. t402-1.6.1/src/t402/tron.py +578 -0
  47. t402-1.6.1/src/t402/types.py +365 -0
  48. t402-1.6.1/src/t402/wdk/__init__.py +140 -0
  49. t402-1.6.1/src/t402/wdk/chains.py +245 -0
  50. t402-1.6.1/src/t402/wdk/errors.py +211 -0
  51. t402-1.6.1/src/t402/wdk/signer.py +657 -0
  52. t402-1.6.1/src/t402/wdk/types.py +134 -0
  53. t402-1.6.1/tests/clients/__init__.py +0 -0
  54. t402-1.6.1/tests/clients/test_base.py +194 -0
  55. t402-1.6.1/tests/clients/test_httpx.py +239 -0
  56. t402-1.6.1/tests/clients/test_requests.py +310 -0
  57. t402-1.6.1/tests/fastapi_tests/__init__.py +0 -0
  58. t402-1.6.1/tests/fastapi_tests/test_middleware.py +528 -0
  59. t402-1.6.1/tests/flask_tests/__init__.py +0 -0
  60. t402-1.6.1/tests/flask_tests/test_middleware.py +357 -0
  61. t402-1.6.1/tests/test_bridge.py +706 -0
  62. t402-1.6.1/tests/test_common.py +175 -0
  63. t402-1.6.1/tests/test_encoding.py +81 -0
  64. t402-1.6.1/tests/test_exact.py +198 -0
  65. t402-1.6.1/tests/test_mcp.py +505 -0
  66. t402-1.6.1/tests/test_paywall.py +258 -0
  67. t402-1.6.1/tests/test_svm.py +931 -0
  68. t402-1.6.1/tests/test_ton.py +420 -0
  69. t402-1.6.1/tests/test_tron.py +440 -0
  70. t402-1.6.1/tests/test_types.py +162 -0
  71. t402-1.6.1/tests/test_wdk.py +444 -0
  72. t402-1.6.1/uv.lock +2290 -0
t402-1.6.1/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ .env
2
+ node_modules/
3
+ dist/
4
+ coverage/
5
+ .turbo/
6
+ .next/
7
+ proxy
8
+ .env
9
+ __pycache__/
10
+ **/.DS_Store
11
+ e2e/facilitators/external-proxies/*
12
+ !e2e/facilitators/external-proxies/README.md
13
+ .vercel
14
+ .env*.local
@@ -0,0 +1 @@
1
+ 3.10
t402-1.6.1/PKG-INFO ADDED
@@ -0,0 +1,470 @@
1
+ Metadata-Version: 2.4
2
+ Name: t402
3
+ Version: 1.6.1
4
+ Summary: t402: An internet native payments protocol
5
+ Author-email: T402 Team <dev@t402.io>
6
+ License: Apache-2.0
7
+ Keywords: crypto,payments,sdk,t402,tether,usdt,web3
8
+ Requires-Python: >=3.10
9
+ Requires-Dist: eth-account>=0.13.7
10
+ Requires-Dist: eth-typing>=4.0.0
11
+ Requires-Dist: eth-utils>=3.0.0
12
+ Requires-Dist: fastapi[standard]>=0.115.12
13
+ Requires-Dist: flask>=3.0.0
14
+ Requires-Dist: pydantic-settings>=2.2.1
15
+ Requires-Dist: pydantic>=2.10.3
16
+ Requires-Dist: python-dotenv>=1.0.1
17
+ Requires-Dist: web3>=6.0.0
18
+ Provides-Extra: all
19
+ Requires-Dist: solana>=0.35.0; extra == 'all'
20
+ Requires-Dist: solders>=0.21.0; extra == 'all'
21
+ Provides-Extra: svm
22
+ Requires-Dist: solana>=0.35.0; extra == 'svm'
23
+ Requires-Dist: solders>=0.21.0; extra == 'svm'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # t402 Python
27
+
28
+ Python SDK for the T402 HTTP-native stablecoin payments protocol.
29
+
30
+ [![PyPI version](https://badge.fury.io/py/t402.svg)](https://pypi.org/project/t402/)
31
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ pip install t402
37
+
38
+ # or with uv
39
+ uv add t402
40
+ ```
41
+
42
+ ## Features
43
+
44
+ - **Multi-Chain Support**: EVM (Ethereum, Base, Polygon, etc.), TON, TRON, Solana
45
+ - **Server Middleware**: FastAPI and Flask integrations
46
+ - **Client Libraries**: httpx and requests adapters
47
+ - **ERC-4337 Account Abstraction**: Gasless payments with smart accounts
48
+ - **USDT0 Cross-Chain Bridge**: LayerZero-powered bridging
49
+ - **WDK Integration**: Tether Wallet Development Kit support
50
+
51
+ ## FastAPI Integration
52
+
53
+ The simplest way to add t402 payment protection to your FastAPI application:
54
+
55
+ ```py
56
+ from fastapi import FastAPI
57
+ from t402.fastapi.middleware import require_payment
58
+
59
+ app = FastAPI()
60
+ app.middleware("http")(
61
+ require_payment(price="0.01", pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C")
62
+ )
63
+
64
+ @app.get("/")
65
+ async def root():
66
+ return {"message": "Hello World"}
67
+ ```
68
+
69
+ To protect specific routes:
70
+
71
+ ```py
72
+ app.middleware("http")(
73
+ require_payment(price="0.01",
74
+ pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C"),
75
+ path="/foo" # <-- this can also be a list ex: ["/foo", "/bar"]
76
+ )
77
+ ```
78
+
79
+ ## Flask Integration
80
+
81
+ The simplest way to add t402 payment protection to your Flask application:
82
+
83
+ ```py
84
+ from flask import Flask
85
+ from t402.flask.middleware import PaymentMiddleware
86
+
87
+ app = Flask(__name__)
88
+
89
+ # Initialize payment middleware
90
+ payment_middleware = PaymentMiddleware(app)
91
+
92
+ # Add payment protection for all routes
93
+ payment_middleware.add(
94
+ price="$0.01",
95
+ pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
96
+ )
97
+
98
+ @app.route("/")
99
+ def root():
100
+ return {"message": "Hello World"}
101
+ ```
102
+
103
+ To protect specific routes:
104
+
105
+ ```py
106
+ # Protect specific endpoint
107
+ payment_middleware.add(
108
+ path="/foo",
109
+ price="$0.001",
110
+ pay_to_address="0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
111
+ )
112
+ ```
113
+
114
+ ## Client Integration
115
+
116
+ ### Simple Usage
117
+
118
+ #### Httpx Client
119
+ ```py
120
+ from eth_account import Account
121
+ from t402.clients.httpx import t402HttpxClient
122
+
123
+ # Initialize account
124
+ account = Account.from_key("your_private_key")
125
+
126
+ # Create client and make request
127
+ async with t402HttpxClient(account=account, base_url="https://api.example.com") as client:
128
+ response = await client.get("/protected-endpoint")
129
+ print(await response.aread())
130
+ ```
131
+
132
+ #### Requests Session Client
133
+ ```py
134
+ from eth_account import Account
135
+ from t402.clients.requests import t402_requests
136
+
137
+ # Initialize account
138
+ account = Account.from_key("your_private_key")
139
+
140
+ # Create session and make request
141
+ session = t402_requests(account)
142
+ response = session.get("https://api.example.com/protected-endpoint")
143
+ print(response.content)
144
+ ```
145
+
146
+ ### Advanced Usage
147
+
148
+ #### Httpx Extensible Example
149
+ ```py
150
+ import httpx
151
+ from eth_account import Account
152
+ from t402.clients.httpx import t402_payment_hooks
153
+
154
+ # Initialize account
155
+ account = Account.from_key("your_private_key")
156
+
157
+ # Create httpx client with t402 payment hooks
158
+ async with httpx.AsyncClient(base_url="https://api.example.com") as client:
159
+ # Add payment hooks directly to client
160
+ client.event_hooks = t402_payment_hooks(account)
161
+
162
+ # Make request - payment handling is automatic
163
+ response = await client.get("/protected-endpoint")
164
+ print(await response.aread())
165
+ ```
166
+
167
+ #### Requests Session Extensible Example
168
+ ```py
169
+ import requests
170
+ from eth_account import Account
171
+ from t402.clients.requests import t402_http_adapter
172
+
173
+ # Initialize account
174
+ account = Account.from_key("your_private_key")
175
+
176
+ # Create session and mount the t402 adapter
177
+ session = requests.Session()
178
+ adapter = t402_http_adapter(account)
179
+
180
+ # Mount the adapter for both HTTP and HTTPS
181
+ session.mount("http://", adapter)
182
+ session.mount("https://", adapter)
183
+
184
+ # Make request - payment handling is automatic
185
+ response = session.get("https://api.example.com/protected-endpoint")
186
+ print(response.content)
187
+ ```
188
+
189
+ ## Manual Server Integration
190
+
191
+ If you're not using the FastAPI middleware, you can implement the t402 protocol manually. Here's what you'll need to handle:
192
+
193
+ 1. Return 402 error responses with the appropriate response body
194
+ 2. Use the facilitator to validate payments
195
+ 3. Use the facilitator to settle payments
196
+ 4. Return the appropriate response header to the caller
197
+
198
+ Here's an example of manual integration:
199
+
200
+ ```py
201
+ from typing import Annotated
202
+ from fastapi import FastAPI, Request
203
+ from t402.types import PaymentRequiredResponse, PaymentRequirements
204
+ from t402.encoding import safe_base64_decode
205
+
206
+ payment_requirements = PaymentRequirements(...)
207
+ facilitator = FacilitatorClient(facilitator_url)
208
+
209
+ @app.get("/foo")
210
+ async def foo(req: request: Request):
211
+ payment_required = PaymentRequiredResponse(
212
+ t402_version: 1,
213
+ accepts=[payment_requirements],
214
+ error="",
215
+ )
216
+ payment_header = req.headers.get("X-PAYMENT", "")
217
+
218
+ if payment_header == "":
219
+ payment_required.error = "X-PAYMENT header not set"
220
+ return JSONResponse(
221
+ content=payment_required.model_dump(by_alias=True),
222
+ status_code=402,
223
+ )
224
+
225
+ payment = PaymentPayload(**json.loads(safe_base64_decode(payment_header)))
226
+
227
+ verify_response = await facilitator.verify(payment, payment_requirements)
228
+ if not verify_response.is_valid:
229
+ payment_required.error = "Invalid payment"
230
+ return JSONResponse(
231
+ content=payment_required.model_dump(by_alias=True),
232
+ status_code=402,
233
+ )
234
+
235
+ settle_response = await facilitator.settle(payment, payment_requirements)
236
+ if settle_response.success:
237
+ response.headers["X-PAYMENT-RESPONSE"] = base64.b64encode(
238
+ settle_response.model_dump_json().encode("utf-8")
239
+ ).decode("utf-8")
240
+ else:
241
+ payment_required.error = "Settle failed: " + settle_response.error
242
+ return JSONResponse(
243
+ content=payment_required.model_dump(by_alias=True),
244
+ status_code=402,
245
+ )
246
+ ```
247
+
248
+ For more examples and advanced usage patterns, check out our [examples directory](https://github.com/t402-io/t402/tree/main/examples/python).
249
+
250
+ ## Multi-Chain Support
251
+
252
+ ### TON Network
253
+
254
+ ```python
255
+ from t402 import (
256
+ TON_MAINNET,
257
+ TON_TESTNET,
258
+ validate_ton_address,
259
+ prepare_ton_payment_header,
260
+ get_ton_network_config,
261
+ )
262
+
263
+ # Validate address
264
+ is_valid = validate_ton_address("EQD...")
265
+
266
+ # Get network config
267
+ config = get_ton_network_config(TON_MAINNET)
268
+ ```
269
+
270
+ ### TRON Network
271
+
272
+ ```python
273
+ from t402 import (
274
+ TRON_MAINNET,
275
+ TRON_NILE,
276
+ validate_tron_address,
277
+ prepare_tron_payment_header,
278
+ get_tron_network_config,
279
+ )
280
+
281
+ # Validate address
282
+ is_valid = validate_tron_address("T...")
283
+
284
+ # Get network config
285
+ config = get_tron_network_config(TRON_MAINNET)
286
+ ```
287
+
288
+ ### Solana (SVM) Network
289
+
290
+ ```python
291
+ from t402 import (
292
+ SOLANA_MAINNET,
293
+ SOLANA_DEVNET,
294
+ SOLANA_TESTNET,
295
+ validate_svm_address,
296
+ prepare_svm_payment_header,
297
+ get_svm_network_config,
298
+ get_svm_usdc_address,
299
+ is_svm_network,
300
+ )
301
+
302
+ # Validate address
303
+ is_valid = validate_svm_address("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v")
304
+
305
+ # Get network config
306
+ config = get_svm_network_config(SOLANA_MAINNET)
307
+
308
+ # Get USDC mint address
309
+ usdc_mint = get_svm_usdc_address(SOLANA_MAINNET)
310
+
311
+ # Check if network is Solana
312
+ is_solana = is_svm_network("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")
313
+ ```
314
+
315
+ Install with optional Solana dependencies:
316
+
317
+ ```bash
318
+ pip install t402[svm]
319
+ ```
320
+
321
+ ## ERC-4337 Account Abstraction
322
+
323
+ Gasless payments using smart accounts and paymasters:
324
+
325
+ ```python
326
+ from t402 import (
327
+ create_bundler_client,
328
+ create_paymaster,
329
+ create_smart_account,
330
+ SafeAccountConfig,
331
+ )
332
+
333
+ # Create bundler client
334
+ bundler = create_bundler_client(
335
+ bundler_type="pimlico",
336
+ api_key="your_api_key",
337
+ chain_id=8453 # Base
338
+ )
339
+
340
+ # Create paymaster for sponsored transactions
341
+ paymaster = create_paymaster(
342
+ paymaster_type="pimlico",
343
+ api_key="your_api_key",
344
+ chain_id=8453
345
+ )
346
+
347
+ # Create Safe smart account
348
+ account = create_smart_account(
349
+ config=SafeAccountConfig(
350
+ owner_private_key="0x...",
351
+ chain_id=8453,
352
+ ),
353
+ bundler=bundler,
354
+ paymaster=paymaster,
355
+ )
356
+ ```
357
+
358
+ ## USDT0 Cross-Chain Bridge
359
+
360
+ Bridge USDT0 across chains using LayerZero:
361
+
362
+ ```python
363
+ from t402 import (
364
+ create_usdt0_bridge,
365
+ create_cross_chain_payment_router,
366
+ get_bridgeable_chains,
367
+ )
368
+
369
+ # Check supported chains
370
+ chains = get_bridgeable_chains()
371
+
372
+ # Create bridge client
373
+ bridge = create_usdt0_bridge(
374
+ private_key="0x...",
375
+ source_chain_id=1, # Ethereum
376
+ )
377
+
378
+ # Get quote
379
+ quote = await bridge.get_quote(
380
+ destination_chain_id=8453, # Base
381
+ amount="1000000", # 1 USDT0
382
+ )
383
+
384
+ # Execute bridge
385
+ result = await bridge.bridge(
386
+ destination_chain_id=8453,
387
+ amount="1000000",
388
+ recipient="0x...",
389
+ )
390
+ ```
391
+
392
+ ## WDK Integration
393
+
394
+ Tether Wallet Development Kit support:
395
+
396
+ ```python
397
+ from t402 import (
398
+ WDKSigner,
399
+ generate_seed_phrase,
400
+ WDKConfig,
401
+ get_wdk_usdt0_chains,
402
+ )
403
+
404
+ # Generate new wallet
405
+ seed = generate_seed_phrase()
406
+
407
+ # Create WDK signer
408
+ signer = WDKSigner(
409
+ config=WDKConfig(
410
+ seed_phrase=seed,
411
+ chains=get_wdk_usdt0_chains(),
412
+ )
413
+ )
414
+
415
+ # Get address
416
+ address = await signer.get_address(chain_id=8453)
417
+
418
+ # Sign payment
419
+ signature = await signer.sign_payment(
420
+ chain_id=8453,
421
+ amount="1000000",
422
+ recipient="0x...",
423
+ )
424
+ ```
425
+
426
+ ## API Reference
427
+
428
+ ### Core Types
429
+
430
+ | Type | Description |
431
+ |------|-------------|
432
+ | `PaymentRequirements` | Payment configuration |
433
+ | `PaymentPayload` | Signed payment data |
434
+ | `VerifyResponse` | Verification result |
435
+ | `SettleResponse` | Settlement result |
436
+
437
+ ### Network Utilities
438
+
439
+ | Function | Description |
440
+ |----------|-------------|
441
+ | `is_evm_network(network)` | Check if EVM network |
442
+ | `is_ton_network(network)` | Check if TON network |
443
+ | `is_tron_network(network)` | Check if TRON network |
444
+ | `is_svm_network(network)` | Check if Solana SVM network |
445
+ | `get_network_type(network)` | Get network type string |
446
+
447
+ ### Facilitator Client
448
+
449
+ ```python
450
+ from t402 import FacilitatorClient, FacilitatorConfig
451
+
452
+ client = FacilitatorClient(FacilitatorConfig(
453
+ url="https://facilitator.t402.io"
454
+ ))
455
+
456
+ # Verify payment
457
+ result = await client.verify(payload, requirements)
458
+
459
+ # Settle payment
460
+ result = await client.settle(payload, requirements)
461
+ ```
462
+
463
+ ## Requirements
464
+
465
+ - Python 3.10+
466
+ - pip or uv package manager
467
+
468
+ ## Documentation
469
+
470
+ Full documentation available at [docs.t402.io](https://docs.t402.io/sdks/python)