atp-protocol 1.3.0__py3-none-any.whl → 1.4.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.
atp/config.py CHANGED
@@ -15,6 +15,18 @@ load_dotenv()
15
15
 
16
16
 
17
17
  def _bool_env(name: str, default: bool = False) -> bool:
18
+ """
19
+ Retrieve a boolean value from an environment variable.
20
+
21
+ Args:
22
+ name (str): The name of the environment variable.
23
+ default (bool, optional): The default value to return if the variable is not set.
24
+
25
+ Returns:
26
+ bool: True if the environment variable contains a truthy value
27
+ (one of "1", "true", "yes", "y", "on", case-insensitive),
28
+ otherwise False or the provided default.
29
+ """
18
30
  v = os.getenv(name)
19
31
  if v is None:
20
32
  return default
@@ -22,6 +34,15 @@ def _bool_env(name: str, default: bool = False) -> bool:
22
34
 
23
35
 
24
36
  def _float_env(name: str) -> Optional[float]:
37
+ """
38
+ Retrieve a float value from an environment variable.
39
+
40
+ Args:
41
+ name (str): The name of the environment variable.
42
+
43
+ Returns:
44
+ Optional[float]: The float value if set and valid, otherwise None.
45
+ """
25
46
  v = os.getenv(name)
26
47
  if v is None:
27
48
  return None
atp/middleware.py CHANGED
@@ -156,7 +156,8 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
156
156
  **Notes:**
157
157
 
158
158
  - The middleware only processes successful responses (status_code < 400).
159
- - If usage data cannot be parsed, the original response is returned without settlement.
159
+ - If usage data cannot be parsed (no input_tokens, output_tokens, or total_tokens
160
+ in the response), the middleware raises HTTP 422 with an error message.
160
161
  - Settlement operations may take time due to blockchain confirmation. Increase
161
162
  `settlement_timeout` if you experience timeout errors even when payments succeed.
162
163
  - The treasury pubkey is configured on the settlement service and cannot be
@@ -380,7 +381,8 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
380
381
 
381
382
  **Error Scenarios:**
382
383
  - Missing wallet (if required): Returns 402 Payment Required
383
- - No usage data: Returns original response without settlement
384
+ - No usage data: Raises 422 with message that endpoint must output
385
+ input_tokens, output_tokens, or total_tokens (or equivalent usage fields)
384
386
  - Encryption failure: Returns 500 with error (response not exposed)
385
387
  - Settlement failure: Returns encrypted response with error details
386
388
  (or raises exception if `fail_on_settlement_error=True`)
@@ -419,18 +421,14 @@ class ATPSettlementMiddleware(BaseHTTPMiddleware):
419
421
  f"No usage data found in response for {path}. "
420
422
  "Settlement service could not parse usage from response body."
421
423
  )
422
- # Return original response if no usage found
423
- # Remove Content-Length header since we consumed the body iterator
424
- new_headers = dict(response.headers)
425
- new_headers.pop("content-length", None)
426
- new_headers.pop("Content-Length", None)
427
- new_headers.pop("content-encoding", None)
428
- new_headers.pop("Content-Encoding", None)
429
- return Response(
430
- content=response_body,
431
- status_code=response.status_code,
432
- headers=new_headers,
433
- media_type=response.media_type,
424
+ raise HTTPException(
425
+ status_code=422,
426
+ detail=(
427
+ "Endpoint must include token usage in the response. "
428
+ "Response must contain at least one of: input_tokens, output_tokens, or total_tokens "
429
+ "(or equivalent fields such as prompt_tokens/completion_tokens in a usage object). "
430
+ f"No parseable usage data found for {path}."
431
+ ),
434
432
  )
435
433
 
436
434
  # Encrypt the agent response before payment verification
@@ -0,0 +1,427 @@
1
+ Metadata-Version: 2.3
2
+ Name: atp-protocol
3
+ Version: 1.4.0
4
+ Summary: ATP Protocol - Agentic Trade Protocol. The easiest way to enable agent-to-agent payments powered by Solana.
5
+ License: MIT
6
+ Keywords: atp,atp-protocol,solana,blockchain,cryptocurrency,payment-gated,agent-to-agent,agent payments,agent execution,payment settlement,solana payments,usdc,sol,fastapi,agent api,payment gateway,settlement service,agent marketplace,decentralized payments,web3,crypto payments,agent infrastructure,payment middleware,automated settlement
7
+ Author: The Swarm Corporation
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: cryptography
21
+ Requires-Dist: fastapi
22
+ Requires-Dist: httpx
23
+ Requires-Dist: loguru
24
+ Requires-Dist: pydantic
25
+ Requires-Dist: python-dotenv
26
+ Requires-Dist: setuptools
27
+ Requires-Dist: starlette
28
+ Requires-Dist: swarms
29
+ Project-URL: Documentation, https://github.com/The-Swarm-Corporation/ATP-Protocol
30
+ Project-URL: Homepage, https://github.com/The-Swarm-Corporation/ATP-Protocol
31
+ Project-URL: Repository, https://github.com/The-Swarm-Corporation/ATP-Protocol
32
+ Description-Content-Type: text/markdown
33
+
34
+ # ATP: Agent Trade Protocol
35
+
36
+ > The premier agent-to-agent payment protocol and foundational framework to empower the agent economy.
37
+
38
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+ [![Documentation](https://img.shields.io/badge/docs-swarms.ai-blue)](https://docs.swarms.ai/docs/atp/overview)
41
+
42
+ ## Overview
43
+
44
+ ATP (Agent Trade Protocol) is the premier agent-to-agent payment protocol that will be the foundational framework to empower the agent economy. Designed to overcome x402's issues and make agent-to-agent payments dynamic and simple, ATP enables automatic payment processing for agent services on the Solana blockchain. The protocol provides a middleware layer that automatically deducts payments from user wallets based on token usage, ensuring secure and transparent transactions.
45
+
46
+ ### Key Features
47
+
48
+ - **Security**: Response encryption ensures users cannot access output until payment is confirmed on-chain
49
+ - **Automation**: Zero-configuration payment processing through middleware integration
50
+ - **Decentralization**: All payments executed on Solana blockchain with full transaction visibility
51
+ - **Format Flexibility**: Supports multiple usage formats (OpenAI, Anthropic, Google, etc.) automatically
52
+ - **Transparency**: Automatic payment splitting between treasury and recipient wallets
53
+
54
+ ## Architecture
55
+
56
+ ATP Protocol operates through three main components:
57
+
58
+ 1. **Settlement Service (Facilitator)**: Centralized service handling all settlement logic, usage parsing, payment calculation, and blockchain transaction execution
59
+ 2. **Middleware**: FastAPI middleware that intercepts API responses, extracts usage data, encrypts responses, executes payments, and decrypts responses only after payment confirmation
60
+ 3. **Client**: User-facing client that simplifies making requests to ATP-protected endpoints and interacting with the settlement service
61
+
62
+ ### Request Flow
63
+
64
+ ```mermaid
65
+ sequenceDiagram
66
+ participant Client
67
+ participant Server
68
+ participant Middleware
69
+ participant SettlementService
70
+ participant Solana
71
+
72
+ Client->>Server: POST /v1/chat<br/>(with wallet key)
73
+ Server->>Server: Process request
74
+ Server->>Middleware: Response with usage data
75
+ Middleware->>Middleware: Encrypt response
76
+ Middleware->>SettlementService: Parse usage & calculate payment
77
+ SettlementService->>SettlementService: Calculate payment amount
78
+ SettlementService->>Solana: Create & sign transaction
79
+ Solana-->>SettlementService: Transaction confirmed
80
+ SettlementService-->>Middleware: Payment confirmed (tx signature)
81
+ Middleware->>Middleware: Decrypt response
82
+ Middleware->>Client: Return decrypted response<br/>(with settlement details)
83
+ ```
84
+
85
+ ## Quick Start
86
+
87
+ ### Installation
88
+
89
+ ```bash
90
+ pip install atp-protocol
91
+ ```
92
+
93
+ ### Server Setup (5 minutes)
94
+
95
+ Add ATP middleware to your FastAPI server:
96
+
97
+ ```python
98
+ from fastapi import FastAPI
99
+ from fastapi.responses import JSONResponse
100
+ from atp.middleware import ATPSettlementMiddleware
101
+ from atp.schemas import PaymentToken
102
+
103
+ app = FastAPI(title="My ATP-Protected API")
104
+
105
+ # Add ATP Settlement Middleware
106
+ app.add_middleware(
107
+ ATPSettlementMiddleware,
108
+ allowed_endpoints=["/v1/chat", "/v1/completions"],
109
+ input_cost_per_million_usd=10.0, # $10 per million input tokens
110
+ output_cost_per_million_usd=30.0, # $30 per million output tokens
111
+ recipient_pubkey="YourSolanaWalletPublicKeyHere", # Your wallet
112
+ payment_token=PaymentToken.SOL, # SOL or USDC
113
+ wallet_private_key_header="x-wallet-private-key",
114
+ require_wallet=True,
115
+ )
116
+
117
+ @app.post("/v1/chat")
118
+ async def chat(request: dict):
119
+ """Agent endpoint with automatic payment processing."""
120
+ message = request.get("message", "")
121
+
122
+ # Agent logic implementation
123
+ response_text = "Agent response here"
124
+
125
+ # Return response with usage data
126
+ # Middleware handles payment processing automatically
127
+ return JSONResponse(content={
128
+ "response": response_text,
129
+ "usage": {
130
+ "input_tokens": 100,
131
+ "output_tokens": 50,
132
+ "total_tokens": 150
133
+ }
134
+ })
135
+ ```
136
+
137
+ ### Client Usage
138
+
139
+ ```python
140
+ from atp.client import ATPClient
141
+
142
+ # Initialize client with wallet
143
+ client = ATPClient(
144
+ wallet_private_key="[1,2,3,...]", # Your wallet private key
145
+ settlement_service_url="https://facilitator.swarms.world"
146
+ )
147
+
148
+ # Make request with automatic payment processing
149
+ response = await client.post(
150
+ url="https://api.example.com/v1/chat",
151
+ json={"message": "Hello!"}
152
+ )
153
+
154
+ print(response["response"]) # Agent output
155
+ print(response["atp_settlement"]) # Payment details
156
+ ```
157
+
158
+ ## Examples
159
+
160
+ Below is a comprehensive table of example integrations and usage:
161
+
162
+ ### Framework Integrations
163
+
164
+ | Category | Example Link | Description |
165
+ |---------------------------|---------------------------------------------------------|----------------------------------------|
166
+ | **Framework Integration** | [Swarms Framework](./examples/tutorials/swarms/) | Enterprise multi-agent orchestration |
167
+ | **Framework Integration** | [LangChain](./examples/tutorials/langchain/) | Popular Python LLM framework |
168
+ | **Framework Integration** | [AutoGen](./examples/tutorials/autogen/) | Microsoft's multi-agent framework |
169
+ | **Framework Integration** | [CrewAI](./examples/tutorials/crewai/) | Multi-agent orchestration |
170
+ | **Framework Integration** | [Anthropic](./examples/tutorials/anthropic/) | Claude API integration |
171
+
172
+ ### Client & Server Example Scripts
173
+
174
+ | Category | Example Link | Description |
175
+ |----------------------|---------------------------------------------------------------------|--------------------------------------------|
176
+ | **Client Example** | [Health Check](./examples/client/example_health_check.py) | Check settlement service status |
177
+ | **Client Example** | [Parse Usage](./examples/client/example_parse_usage.py) | Parse usage from various formats |
178
+ | **Client Example** | [Calculate Payment](./examples/client/example_calculate_payment.py) | Calculate payment without executing |
179
+ | **Client Example** | [Execute Settlement](./examples/client/example_settle.py) | Direct settlement execution |
180
+ | **Client Example** | [Make Request](./examples/client/example_request.py) | Request ATP-protected endpoints |
181
+ | **Server Example** | [Basic Example](./examples/server/example.py) | Simple middleware setup |
182
+ | **Server Example** | [Full Flow](./examples/server/full_flow_example.py) | Complete payment flow |
183
+ | **Server Example** | [Settlement Service](./examples/server/settlement_service_example.py) | Direct service usage |
184
+
185
+ See [examples/README.md](./examples/README.md) for complete documentation.
186
+
187
+
188
+ ## Security Features
189
+
190
+ | Feature | Description |
191
+ |------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
192
+ | **Response Encryption** | Agent responses are **encrypted before payment verification**, ensuring users cannot see output until payment is confirmed on-chain. |
193
+ | **Payment Verification** | Responses are only decrypted after successful blockchain transaction confirmation (`status="paid"` with valid transaction signature). |
194
+ | **Error Handling** | Failed payments result in encrypted responses with error details, preventing unauthorized access to agent output. |
195
+
196
+
197
+ ## Payment Structure
198
+
199
+ Payments are automatically split between:
200
+
201
+ - **Treasury**: Receives processing fee (default 5%, configured on settlement service)
202
+ - **Recipient**: Receives remainder (95% by default) - your wallet specified via `recipient_pubkey`
203
+
204
+ ### Supported Payment Tokens
205
+
206
+ - **SOL** (Solana native token)
207
+ - **USDC** (USD Coin on Solana)
208
+
209
+ ## Usage Data Formats
210
+
211
+ The middleware automatically supports multiple usage formats:
212
+
213
+ ### OpenAI Format
214
+
215
+ ```json
216
+ {
217
+ "usage": {
218
+ "prompt_tokens": 100,
219
+ "completion_tokens": 50,
220
+ "total_tokens": 150
221
+ }
222
+ }
223
+ ```
224
+
225
+ ### Anthropic Format
226
+
227
+ ```json
228
+ {
229
+ "usage": {
230
+ "input_tokens": 100,
231
+ "output_tokens": 50
232
+ }
233
+ }
234
+ ```
235
+
236
+ ### Google/Gemini Format
237
+
238
+ ```json
239
+ {
240
+ "usageMetadata": {
241
+ "promptTokenCount": 100,
242
+ "candidatesTokenCount": 50,
243
+ "totalTokenCount": 150
244
+ }
245
+ }
246
+ ```
247
+
248
+ The settlement service automatically detects and parses these formats, so you can use any format your agent API returns.
249
+
250
+ ## Configuration
251
+
252
+ ### Environment Variables
253
+
254
+ ```bash
255
+ # Settlement Service
256
+ ATP_SETTLEMENT_URL="https://facilitator.swarms.world" # Default
257
+ ATP_SETTLEMENT_TIMEOUT=300.0 # 5 minutes (default)
258
+
259
+ # Encryption (optional - generates new key if not set)
260
+ ATP_ENCRYPTION_KEY="base64-encoded-fernet-key"
261
+ ```
262
+
263
+ ### Middleware Configuration
264
+
265
+ ```python
266
+ app.add_middleware(
267
+ ATPSettlementMiddleware,
268
+ allowed_endpoints=["/v1/chat"], # Endpoints to protect
269
+ input_cost_per_million_usd=10.0, # Pricing
270
+ output_cost_per_million_usd=30.0,
271
+ recipient_pubkey="YourWalletPublicKey", # Required
272
+ payment_token=PaymentToken.SOL, # SOL or USDC
273
+ wallet_private_key_header="x-wallet-private-key",
274
+ require_wallet=True, # Require wallet for payment
275
+ settlement_service_url="https://facilitator.swarms.world",
276
+ settlement_timeout=300.0,
277
+ fail_on_settlement_error=False, # Graceful error handling
278
+ )
279
+ ```
280
+
281
+ ## API Reference
282
+
283
+ ### Middleware
284
+
285
+ The `ATPSettlementMiddleware` class provides automatic payment processing for FastAPI endpoints.
286
+
287
+ **Key Features:**
288
+
289
+ - Automatic usage parsing from multiple formats
290
+ - Response encryption before payment
291
+ - Payment execution via settlement service
292
+ - Response decryption after payment confirmation
293
+
294
+ See [Middleware Documentation](./atp/middleware.py) for complete API reference.
295
+
296
+ ### Client
297
+
298
+ The `ATPClient` class provides a simple interface for:
299
+
300
+ - Making requests to ATP-protected endpoints
301
+ - Interacting with the settlement service directly
302
+ - Parsing usage data
303
+ - Calculating payments
304
+ - Executing settlements
305
+
306
+ See [Client Documentation](./atp/client.py) for complete API reference.
307
+
308
+ ### Settlement Service
309
+
310
+ The settlement service (facilitator) handles:
311
+
312
+ - Usage parsing from various formats
313
+ - Payment calculation
314
+ - Blockchain transaction creation and execution
315
+ - Transaction confirmation
316
+
317
+ See [Settlement Service Documentation](https://docs.swarms.ai/docs/atp/facilitator) for complete API reference.
318
+
319
+
320
+ ## Development
321
+
322
+ ### Requirements
323
+
324
+ - Python 3.10+
325
+ - FastAPI (for middleware)
326
+ - Solana wallet (for payments)
327
+
328
+ ### Installation from Source
329
+
330
+ ```bash
331
+ git clone https://github.com/The-Swarm-Corporation/ATP-Protocol.git
332
+ cd ATP-Protocol
333
+ pip install -e .
334
+ ```
335
+
336
+ ### Running Tests
337
+
338
+ ```bash
339
+ pytest tests/
340
+ ```
341
+
342
+ ### Code Quality
343
+
344
+ ```bash
345
+ # Format code
346
+ black .
347
+
348
+ # Lint code
349
+ ruff check .
350
+ ```
351
+
352
+
353
+ ## Error Handling
354
+
355
+ ### Missing Wallet Key
356
+
357
+ If wallet private key is missing and `require_wallet=True`:
358
+
359
+ ```json
360
+ {
361
+ "detail": "Missing wallet private key in header: x-wallet-private-key"
362
+ }
363
+ ```
364
+
365
+ Status: `401 Unauthorized`
366
+
367
+ ### Payment Failure
368
+
369
+ If payment fails and `fail_on_settlement_error=False` (default):
370
+
371
+ ```json
372
+ {
373
+ "response": "encrypted_data_here",
374
+ "response_encrypted": true,
375
+ "atp_settlement": {
376
+ "error": "Settlement failed",
377
+ "detail": "Insufficient funds",
378
+ "status_code": 400
379
+ },
380
+ "atp_settlement_status": "failed",
381
+ "atp_message": "Agent response is encrypted. Payment required to decrypt."
382
+ }
383
+ ```
384
+
385
+ The response remains encrypted until payment succeeds.
386
+
387
+ ## Best Practices
388
+
389
+ 1. **Wallet Security**: Never log or persist wallet private keys. Use them only in-memory for transaction signing.
390
+
391
+ 2. **Error Handling**: Use `fail_on_settlement_error=False` for graceful degradation. Check `atp_settlement_status` in responses to handle payment failures appropriately.
392
+
393
+ 3. **Timeout Configuration**: Increase `settlement_timeout` if you experience timeout errors. Blockchain confirmation can take time depending on network conditions.
394
+
395
+ 4. **Usage Data**: Always include accurate token counts in your responses. Middleware skips settlement if usage data cannot be parsed.
396
+
397
+ 5. **Testing**: Use testnet wallets and small amounts for testing. Verify transactions on Solana explorer before production deployment.
398
+
399
+ 6. **Monitoring**: Monitor `atp_settlement_status` in responses to track payment success rates and identify potential issues.
400
+
401
+ ## Resources
402
+
403
+ | Resource | Description |
404
+ |-----------------------------------|------------------------------------|
405
+ | [Full Documentation](https://docs.swarms.ai/docs/atp/overview) | Complete API documentation |
406
+ | [Settlement Service API](https://docs.swarms.ai/docs/atp/facilitator) | Facilitator API reference |
407
+ | [Middleware Reference](https://docs.swarms.ai/docs/atp/middleware) | Middleware configuration |
408
+ | [Client Reference](https://docs.swarms.ai/docs/atp/client) | Client API reference |
409
+ | [ATP Vision](https://docs.swarms.ai/docs/atp/vision) | Protocol vision and roadmap |
410
+
411
+
412
+ ## Contributing
413
+
414
+ Contributions are welcome. Please read our contributing guidelines and submit pull requests for review.
415
+
416
+ ## License
417
+
418
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
419
+
420
+ ## Acknowledgments
421
+
422
+ Built by [The Swarm Corporation](https://swarms.ai) to enable agent-to-agent commerce on the blockchain.
423
+
424
+ ---
425
+
426
+ For additional information, see the [examples directory](./examples/) or the [complete documentation](https://docs.swarms.ai/docs/atp/overview).
427
+
@@ -1,11 +1,11 @@
1
1
  atp/__init__.py,sha256=xCYA1cb5xw9IxqFsB1fC7jXBE48bHgKBq4ZhyW9AFyY,459
2
2
  atp/client.py,sha256=GUZZ81PaJMia7mK_SS3uzU3qCpg0ChoLVYmQIRrfxQ8,24510
3
- atp/config.py,sha256=EkswOYJ3Lj2WAw1Yy_2gbpk5FzJ3L--T6ARPixAOoW8,2336
3
+ atp/config.py,sha256=tY_S8aXrTbZJ4WIRQIXhIiXiRjeYT6_5Jh47QwZ1gnw,3013
4
4
  atp/encryption.py,sha256=kgyhjf8qGq3oZjDIxGHzOlc5KOLPTi7nv0RApPZGk7o,5341
5
- atp/middleware.py,sha256=br6wIfLQU_9ja62_k5R6htTe6SWqIT9b7FkBoeIYZOQ,29518
5
+ atp/middleware.py,sha256=d3Sxj66qMr2AX6hxZNFHaiqpdyXafEpf1McWOJVaklo,29546
6
6
  atp/schemas.py,sha256=29VtWKxtwlllAUOx2hoSEESpVWoKANdybOoTiTbFhnc,12344
7
7
  atp/settlement_client.py,sha256=7e_271Bx1ZT2YzZH0HjAOx1krDXgPhMWVakRKsMMS3k,31395
8
- atp_protocol-1.3.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
- atp_protocol-1.3.0.dist-info/METADATA,sha256=zPazL_nEFxMCv3hnfpFrfw2TBl7EJNtbNjUnwBT5PNU,21578
10
- atp_protocol-1.3.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
- atp_protocol-1.3.0.dist-info/RECORD,,
8
+ atp_protocol-1.4.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
9
+ atp_protocol-1.4.0.dist-info/METADATA,sha256=rLnBQhoFlqGx9lxHDJXJm6zDDdIGVlXx0Ds4mpMYX24,15887
10
+ atp_protocol-1.4.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
+ atp_protocol-1.4.0.dist-info/RECORD,,
@@ -1,590 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: atp-protocol
3
- Version: 1.3.0
4
- Summary: ATP Protocol - Agentic Trade Protocol. The easiest way to enable agent-to-agent payments powered by Solana.
5
- License: MIT
6
- Keywords: atp,atp-protocol,solana,blockchain,cryptocurrency,payment-gated,agent-to-agent,agent payments,agent execution,payment settlement,solana payments,usdc,sol,fastapi,agent api,payment gateway,settlement service,agent marketplace,decentralized payments,web3,crypto payments,agent infrastructure,payment middleware,automated settlement
7
- Author: The Swarm Corporation
8
- Requires-Python: >=3.10,<4.0
9
- Classifier: Development Status :: 4 - Beta
10
- Classifier: Intended Audience :: Developers
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
- Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
18
- Classifier: Topic :: Office/Business :: Financial
19
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
- Requires-Dist: cryptography
21
- Requires-Dist: fastapi
22
- Requires-Dist: httpx
23
- Requires-Dist: loguru
24
- Requires-Dist: pydantic
25
- Requires-Dist: python-dotenv
26
- Requires-Dist: setuptools
27
- Requires-Dist: starlette
28
- Requires-Dist: swarms
29
- Project-URL: Documentation, https://github.com/The-Swarm-Corporation/ATP-Protocol
30
- Project-URL: Homepage, https://github.com/The-Swarm-Corporation/ATP-Protocol
31
- Project-URL: Repository, https://github.com/The-Swarm-Corporation/ATP-Protocol
32
- Description-Content-Type: text/markdown
33
-
34
- # ATP Protocol
35
-
36
- **ATP (Agent Transaction Protocol)** enables automatic payment processing for AI agent APIs on Solana. Add billing to any FastAPI endpoint with a few lines of code.
37
-
38
- > **Part of the [Swarms.ai](https://swarms.ai) ecosystem** - ATP Protocol is built for the [Swarms](https://github.com/kyegomez/swarms) multi-agent orchestration framework, providing seamless payment infrastructure for agent-to-agent transactions.
39
-
40
- ## What It Does
41
-
42
- ATP Protocol makes it easy to charge for API usage:
43
-
44
- - **Automatic billing** - Payment is processed automatically after each request
45
- - **Solana payments** - Uses SOL or USDC for fast, cheap transactions
46
- - **Token-based pricing** - Charges based on input/output token usage
47
- - **Response encryption** - Agent responses are encrypted until payment is confirmed
48
- - **Payment verification** - Responses are only decrypted after successful payment
49
- - **Zero infrastructure** - No payment processors, no databases, just Solana
50
-
51
- ## Quick Start
52
-
53
- First, install the package:
54
-
55
- ```bash
56
- pip install atp-protocol
57
- ```
58
-
59
- ## Usage
60
-
61
- Then add automatic billing to your FastAPI app:
62
-
63
- ```python
64
- from fastapi import FastAPI
65
- from atp.middleware import ATPSettlementMiddleware
66
- from atp.schemas import PaymentToken
67
-
68
- app = FastAPI()
69
-
70
- # Add the middleware
71
- app.add_middleware(
72
- ATPSettlementMiddleware,
73
- allowed_endpoints=["/v1/chat", "/v1/completions"],
74
- input_cost_per_million_usd=10.0, # $10 per million input tokens
75
- output_cost_per_million_usd=30.0, # $30 per million output tokens
76
- recipient_pubkey="YourSolanaWalletHere", # Your wallet receives 95%
77
- payment_token=PaymentToken.SOL,
78
- )
79
-
80
- # Your endpoint just needs to return usage data
81
- @app.post("/v1/chat")
82
- async def chat(request: dict):
83
- return {
84
- "output": "Response here",
85
- "usage": {
86
- "input_tokens": 150,
87
- "output_tokens": 50,
88
- }
89
- }
90
- ```
91
-
92
- **Client makes request:**
93
-
94
- ```bash
95
- curl -X POST http://localhost:8000/v1/chat \
96
- -H "x-wallet-private-key: [1,2,3,...]" \
97
- -d '{"message": "Hello!"}'
98
- ```
99
-
100
- **Response includes payment details (decrypted after payment):**
101
-
102
- ```json
103
- {
104
- "output": "Response here",
105
- "usage": {"input_tokens": 150, "output_tokens": 50},
106
- "atp_settlement": {
107
- "status": "paid",
108
- "transaction_signature": "5j7s8K9...",
109
- "payment": {
110
- "total_amount_sol": 0.0003,
111
- "recipient": {"amount_sol": 0.000285},
112
- "treasury": {"amount_sol": 0.000015}
113
- }
114
- }
115
- }
116
- ```
117
-
118
- **If payment fails, response remains encrypted:**
119
-
120
- ```json
121
- {
122
- "output": "encrypted_data_here...",
123
- "usage": {"input_tokens": 150, "output_tokens": 50},
124
- "atp_settlement": {
125
- "error": "Settlement failed",
126
- "message": "Insufficient funds"
127
- },
128
- "atp_settlement_status": "failed",
129
- "atp_message": "Agent response is encrypted. Payment required to decrypt. Please provide a valid wallet private key and ensure payment succeeds."
130
- }
131
- ```
132
-
133
- That's it! Payment is automatically processed on Solana, and responses are protected until payment is confirmed.
134
-
135
- ---
136
-
137
- ## How It Works
138
-
139
- The ATP Protocol uses a **Settlement Service** to handle all payment logic. Here's the flow:
140
-
141
- ```mermaid
142
- sequenceDiagram
143
- autonumber
144
- participant C as Client
145
- participant M as Middleware
146
- participant E as Your Endpoint
147
- participant SS as Settlement Service
148
- participant S as Solana
149
-
150
- C->>M: POST /v1/chat<br/>(x-wallet-private-key header)
151
- M->>E: Forward request
152
- E-->>M: Response + usage data
153
- M->>M: Extract token counts<br/>(auto-detects format)
154
- M->>M: Encrypt agent response<br/>(protect output)
155
- M->>SS: Calculate payment<br/>(usage → USD → SOL/USDC)
156
- SS->>SS: Split payment<br/>(95% recipient, 5% treasury)
157
- SS->>S: Send payment transaction
158
- S-->>SS: Transaction signature
159
- SS-->>M: Settlement details
160
- M->>M: Verify payment status
161
- alt Payment succeeded
162
- M->>M: Decrypt response
163
- else Payment failed
164
- M->>M: Keep response encrypted
165
- end
166
- M->>M: Add settlement info<br/>to response
167
- M-->>C: Response + atp_settlement
168
- ```
169
-
170
- ### Step-by-Step
171
-
172
- 1. **Client sends request** with wallet private key in header
173
- 2. **Middleware intercepts** and forwards to your endpoint
174
- 3. **Your endpoint executes** and returns response with usage data
175
- 4. **Middleware extracts** token counts (supports OpenAI, Anthropic, Google formats)
176
- 5. **Middleware encrypts** agent response to protect output until payment is confirmed
177
- 6. **Settlement Service calculates** cost from token usage
178
- 7. **Settlement Service splits** payment: 95% to you, 5% to Swarms Treasury
179
- 8. **Settlement Service sends** Solana transaction
180
- 9. **Middleware verifies** payment status from settlement service
181
- 10. **If payment succeeded**: Middleware decrypts response and returns it
182
- 11. **If payment failed**: Response remains encrypted with error message
183
- 12. **Middleware adds** settlement info to response
184
-
185
- ### Architecture
186
-
187
- ```mermaid
188
- flowchart TB
189
- C[Client] -->|Request + Wallet Key| M[ATP Middleware]
190
- M -->|Forward| E[Your Endpoint]
191
- E -->|Response + Usage| M
192
- M -->|Calculate Payment| SS[Settlement Service]
193
- SS -->|Send Transaction| S[Solana]
194
- S -->|Transaction Signature| SS
195
- SS -->|Settlement Details| M
196
- M -->|Response + Payment Info| C
197
-
198
- SS -->|95%| R[Your Wallet]
199
- SS -->|5%| T[Swarms Treasury]
200
- ```
201
-
202
- The **Settlement Service** is a centralized service that handles:
203
-
204
- - Parsing usage data from various API formats
205
- - Calculating payment amounts
206
- - Executing Solana transactions
207
- - Verifying payments
208
-
209
- The official facilitator at **`https://facilitator.swarms.world`** is ultra-fast and powered by Rust, ensuring low-latency payment processing. This keeps your middleware simple and ensures all settlement logic is immutable and centralized.
210
-
211
- ---
212
-
213
- ## Configuration
214
-
215
- ### Required Parameters
216
-
217
- | Parameter | Description |
218
- | --------- | ----------- |
219
- | `allowed_endpoints` | List of endpoint paths to apply settlement (e.g., `["/v1/chat"]`) |
220
- | `input_cost_per_million_usd` | Cost per million input tokens in USD |
221
- | `output_cost_per_million_usd` | Cost per million output tokens in USD |
222
- | `recipient_pubkey` | Your Solana wallet address (receives 95% of payment) |
223
-
224
- ### Optional Parameters
225
-
226
- | Parameter | Default | Description |
227
- | --------- | ------- | ----------- |
228
- | `wallet_private_key_header` | `x-wallet-private-key` | HTTP header name for wallet key |
229
- | `payment_token` | `PaymentToken.SOL` | `PaymentToken.SOL` or `PaymentToken.USDC` |
230
- | `require_wallet` | `True` | Require wallet key or skip settlement when missing |
231
- | `settlement_service_url` | From `ATP_SETTLEMENT_URL` env | Settlement service URL |
232
- | `settlement_timeout` | From `ATP_SETTLEMENT_TIMEOUT` env or `300.0` | Timeout in seconds for settlement requests (default: 5 minutes) |
233
- | `fail_on_settlement_error` | `False` | If `True`, raises HTTPException on settlement failure; if `False`, returns encrypted response with error |
234
- | `skip_preflight` | `False` | Skip Solana transaction preflight simulation |
235
- | `commitment` | `"confirmed"` | Solana commitment level (`processed`\|`confirmed`\|`finalized`) |
236
-
237
- ### Environment Variables
238
-
239
- ```bash
240
- # Settlement Service URL (default: https://facilitator.swarms.world)
241
- # The official facilitator is ultra-fast and powered by Rust
242
- ATP_SETTLEMENT_URL="https://facilitator.swarms.world"
243
-
244
- # Settlement Service Timeout (default: 300.0 seconds / 5 minutes)
245
- # Settlement operations may take longer due to blockchain confirmation times
246
- # Increase this value if you experience timeout errors even when payments succeed
247
- ATP_SETTLEMENT_TIMEOUT="300.0"
248
-
249
- # Solana RPC URL (default: https://api.mainnet-beta.solana.com)
250
- SOLANA_RPC_URL="https://api.mainnet-beta.solana.com"
251
- ```
252
-
253
- ---
254
-
255
- ## Payment Calculation
256
-
257
- The middleware calculates cost from token usage:
258
-
259
- ```text
260
- usd_cost = (input_tokens / 1,000,000 × input_rate) + (output_tokens / 1,000,000 × output_rate)
261
- token_amount = usd_cost / token_price_usd
262
- ```
263
-
264
- **Payment Split:**
265
-
266
- - **95%** → Your wallet (`recipient_pubkey`)
267
- - **5%** → Swarms Treasury (processing fee)
268
-
269
- The fee is **deducted from the total** (not added on top).
270
-
271
- ### Example
272
-
273
- If a request uses 1,000 input tokens and 500 output tokens:
274
-
275
- - Input cost: `1,000 / 1,000,000 × $10 = $0.01`
276
- - Output cost: `500 / 1,000,000 × $30 = $0.015`
277
- - **Total: $0.025 USD**
278
-
279
- At SOL price of $100:
280
-
281
- - Payment: `$0.025 / $100 = 0.00025 SOL`
282
- - You receive: `0.00025 × 0.95 = 0.0002375 SOL`
283
- - Treasury receives: `0.00025 × 0.05 = 0.0000125 SOL`
284
-
285
- ---
286
-
287
- ## Supported Usage Formats
288
-
289
- The middleware automatically detects usage from common API formats:
290
-
291
- - **OpenAI**: `prompt_tokens`, `completion_tokens`, `total_tokens`
292
- - **Anthropic**: `input_tokens`, `output_tokens`, `total_tokens`
293
- - **Google/Gemini**: `promptTokenCount`, `candidatesTokenCount`, `totalTokenCount`
294
- - **Generic**: `input_tokens`, `output_tokens`, `total_tokens`
295
- - **Nested**: `usage.*`, `meta.usage`, `statistics.*`
296
-
297
- Your endpoint can return usage in any of these formats - the middleware will find it.
298
-
299
- ---
300
-
301
- ## Complete Example
302
-
303
- ```python
304
- from fastapi import FastAPI, JSONResponse
305
- from atp.middleware import ATPSettlementMiddleware
306
- from atp.schemas import PaymentToken
307
-
308
- app = FastAPI()
309
-
310
- # Configure middleware
311
- app.add_middleware(
312
- ATPSettlementMiddleware,
313
- allowed_endpoints=["/v1/chat"],
314
- input_cost_per_million_usd=10.0,
315
- output_cost_per_million_usd=30.0,
316
- recipient_pubkey="YourSolanaWalletHere",
317
- payment_token=PaymentToken.SOL,
318
- require_wallet=True,
319
- fail_on_settlement_error=False, # Return encrypted response on error
320
- settlement_timeout=300.0, # 5 minutes timeout
321
- )
322
-
323
- @app.post("/v1/chat")
324
- async def chat(request: dict):
325
- # Your business logic here
326
- message = request.get("message", "")
327
-
328
- # Simulate API call that returns usage
329
- response_data = {
330
- "output": f"You said: {message}",
331
- "usage": {
332
- "input_tokens": len(message.split()) * 2, # Rough estimate
333
- "output_tokens": 50,
334
- "total_tokens": len(message.split()) * 2 + 50,
335
- }
336
- }
337
-
338
- return JSONResponse(content=response_data)
339
-
340
- if __name__ == "__main__":
341
- import uvicorn
342
- uvicorn.run(app, host="0.0.0.0", port=8000)
343
- ```
344
-
345
- **Run it:**
346
-
347
- ```bash
348
- python app.py
349
- ```
350
-
351
- **Test it:**
352
-
353
- ```bash
354
- curl -X POST http://localhost:8000/v1/chat \
355
- -H "Content-Type: application/json" \
356
- -H "x-wallet-private-key: [1,2,3,...]" \
357
- -d '{"message": "Hello, world!"}'
358
- ```
359
-
360
- ### Swarms Framework Integration
361
-
362
- For a complete example showing how to integrate ATP Protocol with [Swarms](https://github.com/kyegomez/swarms) agents, see:
363
-
364
- **[examples/example.py](examples/example.py)** or **[example.py](example.py)** (root directory)
365
-
366
- This example demonstrates:
367
-
368
- - Setting up a Swarms agent
369
- - Creating FastAPI endpoints that use the agent
370
- - Automatic payment processing with ATP middleware
371
- - Usage tracking and billing for agent services
372
-
373
- **Quick start with Swarms:**
374
-
375
- ```bash
376
- # Install dependencies
377
- pip install swarms atp-protocol
378
-
379
- # Set your OpenAI API key
380
- export OPENAI_API_KEY="your-key-here"
381
-
382
- # Run the example
383
- python examples/example.py
384
- # or
385
- python example.py
386
- ```
387
-
388
- ---
389
-
390
- ## Examples
391
-
392
- ATP Protocol includes comprehensive examples showing how to integrate with various AI agent frameworks and APIs. All examples demonstrate automatic payment processing, token usage tracking, and Solana settlement.
393
-
394
- ### Framework Integration Examples
395
-
396
- | Framework | Directory | Description | Documentation |
397
- |-----------|-----------|-------------|--------------|
398
- | **Swarms** | [`examples/swarms/`](examples/swarms/) | Swarms framework integration - native ATP Protocol support | [README](examples/swarms/README.md) |
399
- | **LangChain** | [`examples/langchain/`](examples/langchain/) | LangChain agent integration with tools and conversational interface | [README](examples/langchain/README.md) |
400
- | **AutoGen** | [`examples/autogen/`](examples/autogen/) | AutoGen multi-agent conversation framework integration | [README](examples/autogen/README.md) |
401
- | **CrewAI** | [`examples/crewai/`](examples/crewai/) | CrewAI multi-agent crew workflows and task pipelines | [README](examples/crewai/README.md) |
402
- | **Anthropic API** | [`examples/anthropic/`](examples/anthropic/) | Direct integration with Anthropic's Claude API | [README](examples/anthropic/README.md) |
403
-
404
- ### Standalone Examples
405
-
406
- | Example | File | Description |
407
- |---------|------|-------------|
408
- | **Swarms Integration** | [`examples/example.py`](examples/example.py) | Complete Swarms framework integration example |
409
- | **Full Flow** | [`examples/full_flow_example.py`](examples/full_flow_example.py) | End-to-end payment flow demonstration |
410
- | **Settlement Service** | [`examples/settlement_service_example.py`](examples/settlement_service_example.py) | Direct settlement service usage |
411
- | **Client Smoke Test** | [`examples/client_smoke_test.py`](examples/client_smoke_test.py) | Client testing and validation |
412
-
413
- ### Quick Start with Examples
414
-
415
- Each example includes:
416
- - **Server** (`server.py`) - FastAPI server with ATP middleware configured
417
- - **Client** (`client.py`) - Example client with wallet authentication
418
- - **README** - Framework-specific setup and usage instructions
419
-
420
- **Getting started:**
421
-
422
- 1. Navigate to an example directory:
423
- ```bash
424
- cd examples/swarms # or langchain, autogen, crewai, anthropic
425
- ```
426
-
427
- 2. Install dependencies (see example's README for specific requirements)
428
-
429
- 3. Configure environment variables:
430
- ```bash
431
- # Create .env file
432
- OPENAI_API_KEY="your-key" # For Swarms, LangChain, AutoGen, CrewAI
433
- ANTHROPIC_API_KEY="your-key" # For Anthropic
434
- ATP_PRIVATE_KEY="[1,2,3,...]"
435
- ```
436
-
437
- 4. Update `recipient_pubkey` in `server.py` with your Solana wallet address
438
-
439
- 5. Run the server:
440
- ```bash
441
- python server.py
442
- ```
443
-
444
- 6. Test with the client:
445
- ```bash
446
- python client.py
447
- ```
448
-
449
- For detailed instructions, see the [Examples README](examples/README.md) or the framework-specific README in each example directory.
450
-
451
- ---
452
-
453
- ## Response Encryption & Payment Verification
454
-
455
- ATP Protocol includes built-in **response encryption** to ensure users cannot access agent output until payment is confirmed. This provides strong protection against payment fraud.
456
-
457
- ### How It Works
458
-
459
- 1. **After endpoint execution**: The middleware encrypts sensitive response fields (e.g., `output`, `response`, `result`, `message`) before processing payment
460
- 2. **Payment processing**: Settlement is attempted via the Settlement Service
461
- 3. **Payment verification**: The middleware checks if payment status is `"paid"` and a transaction signature exists
462
- 4. **Conditional decryption**:
463
- - ✅ **Payment succeeded**: Response is decrypted and returned to client
464
- - ❌ **Payment failed**: Response remains encrypted with error message
465
-
466
- ### Encrypted Response Format
467
-
468
- When payment fails, the response includes encrypted data and a clear message:
469
-
470
- ```json
471
- {
472
- "output": "encrypted_data_here...",
473
- "usage": {"input_tokens": 150, "output_tokens": 50},
474
- "atp_settlement": {
475
- "error": "Settlement service unavailable",
476
- "message": "Request timed out after 300.0s. The payment may have been sent successfully, but the settlement service did not respond in time.",
477
- "type": "ReadTimeout"
478
- },
479
- "atp_settlement_status": "failed",
480
- "atp_message": "Agent response is encrypted. Payment required to decrypt. Please provide a valid wallet private key and ensure payment succeeds."
481
- }
482
- ```
483
-
484
- ### Settlement Error Handling
485
-
486
- The middleware provides flexible error handling via the `fail_on_settlement_error` parameter:
487
-
488
- - **`fail_on_settlement_error=False`** (default):
489
- - Returns encrypted response with error details
490
- - Client receives usage data and error information
491
- - Useful for debugging and graceful degradation
492
-
493
- - **`fail_on_settlement_error=True`**:
494
- - Raises `HTTPException` (500) when settlement fails
495
- - Request fails immediately
496
- - Useful for strict payment requirements
497
-
498
- ### Timeout Handling
499
-
500
- Settlement operations may take time due to blockchain confirmation. The middleware provides informative timeout messages:
501
-
502
- - **ReadTimeout**: Payment may have succeeded, but settlement service didn't respond in time
503
- - **ConnectTimeout**: Settlement service is unreachable
504
- - **HTTP errors**: Network or service errors with status codes
505
-
506
- Increase `settlement_timeout` if you experience timeouts even when payments succeed.
507
-
508
- ---
509
-
510
- ## Error Handling
511
-
512
- - **Missing wallet key**: Returns `401 Unauthorized` if `require_wallet=True`
513
- - **Missing usage data**: Logs warning and returns original response (no settlement)
514
- - **Payment failure**:
515
- - If `fail_on_settlement_error=False`: Returns encrypted response with error details
516
- - If `fail_on_settlement_error=True`: Returns `500 Internal Server Error` and raises exception
517
- - **Invalid private key**: Returns `500 Internal Server Error` with parsing error
518
- - **Encryption failure**: Returns `500 Internal Server Error` without exposing agent output
519
- - **Settlement timeout**: Returns encrypted response with timeout message (payment may have succeeded)
520
-
521
- ---
522
-
523
- ## How the Settlement Service Works
524
-
525
- The Settlement Service is a centralized API that handles all payment logic. The official facilitator service at **`https://facilitator.swarms.world`** is ultra-fast and powered by Rust, ensuring low-latency payment processing.
526
-
527
- The service provides:
528
-
529
- - **`POST /v1/settlement/parse-usage`** - Parse usage from various formats
530
- - **`POST /v1/settlement/calculate-payment`** - Calculate payment amounts
531
- - **`POST /v1/settlement/settle`** - Execute payment transaction
532
-
533
- The middleware calls these endpoints automatically. You can also call them directly if needed.
534
-
535
- ### Settlement Service Flow
536
-
537
- 1. **Parse usage** - Normalize token counts from any format
538
- 2. **Calculate cost** - Convert tokens to USD using your rates
539
- 3. **Fetch token price** - Get current SOL/USDC price
540
- 4. **Calculate payment** - Convert USD to token amount
541
- 5. **Split payment** - Calculate 95%/5% split
542
- 6. **Send transaction** - Execute Solana payment
543
- 7. **Verify** - Confirm transaction succeeded
544
- 8. **Return details** - Transaction signature and payment breakdown
545
-
546
- All settlement logic is immutable and centralized in the service, ensuring consistency and reliability.
547
-
548
- ---
549
-
550
- ## Payment Tokens
551
-
552
- ATP Protocol supports two payment tokens:
553
-
554
- - **SOL** - Native Solana token (default)
555
- - **USDC** - Stablecoin (treated as $1 USD)
556
-
557
- Set `payment_token=PaymentToken.USDC` to use USDC instead of SOL.
558
-
559
- ---
560
-
561
- ## Security Considerations
562
-
563
- | Security Aspect | Details |
564
- |------------------------------|-------------------------------------------------------------------|
565
- | **Private keys** | Only used in-memory during each request |
566
- | **No key storage** | Keys are never persisted |
567
- | **Settlement Service** | Handles all sensitive operations |
568
- | **Response encryption** | Agent outputs are encrypted until payment is confirmed |
569
- | **Payment verification** | Responses are only decrypted after successful payment verification |
570
- | **Transaction verification** | Ensures payments are confirmed before a response is returned |
571
- | **Encrypted failure mode** | Failed payments keep responses encrypted, preventing output access |
572
-
573
- ---
574
-
575
- ## About Swarms
576
-
577
- ATP Protocol is part of the **[Swarms](https://swarms.ai)** ecosystem, the enterprise-grade production-ready multi-agent orchestration framework. Swarms provides the infrastructure for building and deploying autonomous agents at scale.
578
-
579
- - **Framework**: [Swarms on GitHub](https://github.com/kyegomez/swarms)
580
- - **Documentation**: [docs.swarms.world](https://docs.swarms.world)
581
- - **Website**: [swarms.ai](https://swarms.ai)
582
-
583
- ATP Protocol integrates seamlessly with Swarms agents, enabling agent-to-agent payments and automatic billing for agent services built on the Swarms framework.
584
-
585
- ---
586
-
587
- ## License
588
-
589
- See [LICENSE](LICENSE) file for details.
590
-