arczk-agent 0.1.0__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.
- arczk_agent-0.1.0/PKG-INFO +251 -0
- arczk_agent-0.1.0/README.md +217 -0
- arczk_agent-0.1.0/arczk/__init__.py +26 -0
- arczk_agent-0.1.0/arczk/client.py +162 -0
- arczk_agent-0.1.0/arczk/crypto.py +96 -0
- arczk_agent-0.1.0/arczk/integrations.py +58 -0
- arczk_agent-0.1.0/arczk/prover.py +74 -0
- arczk_agent-0.1.0/arczk/types.py +58 -0
- arczk_agent-0.1.0/arczk/vault.py +100 -0
- arczk_agent-0.1.0/arczk_agent.egg-info/PKG-INFO +251 -0
- arczk_agent-0.1.0/arczk_agent.egg-info/SOURCES.txt +17 -0
- arczk_agent-0.1.0/arczk_agent.egg-info/dependency_links.txt +1 -0
- arczk_agent-0.1.0/arczk_agent.egg-info/requires.txt +13 -0
- arczk_agent-0.1.0/arczk_agent.egg-info/top_level.txt +1 -0
- arczk_agent-0.1.0/pyproject.toml +66 -0
- arczk_agent-0.1.0/setup.cfg +4 -0
- arczk_agent-0.1.0/tests/test_client.py +49 -0
- arczk_agent-0.1.0/tests/test_crypto.py +34 -0
- arczk_agent-0.1.0/tests/test_vault.py +42 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arczk-agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Autonomous AI Agent SDK for ArcNano Shielded Zero-Knowledge Nanopayments on Arc
|
|
5
|
+
Author-email: Trymbak Mahant <trymbakmahant@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Trymbakmahant/arcnano
|
|
8
|
+
Project-URL: Documentation, https://github.com/Trymbakmahant/arcnano
|
|
9
|
+
Project-URL: Repository, https://github.com/Trymbakmahant/arcnano
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/Trymbakmahant/arcnano/issues
|
|
11
|
+
Keywords: arcnano,zk-proofs,x402,ai-agents,langchain,crewai,micropayments,arc-network,groth16,zero-knowledge,autonomous-agents
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Security :: Cryptography
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: requests>=2.28.0
|
|
25
|
+
Requires-Dist: httpx>=0.24.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
30
|
+
Provides-Extra: langchain
|
|
31
|
+
Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
|
|
32
|
+
Provides-Extra: crewai
|
|
33
|
+
Requires-Dist: crewai>=0.1.0; extra == "crewai"
|
|
34
|
+
|
|
35
|
+
# arczk-agent
|
|
36
|
+
|
|
37
|
+
> **Autonomous AI Agent SDK for ArcNano Shielded Zero-Knowledge Nanopayments on Arc.**
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/arczk-agent/)
|
|
40
|
+
[](https://pypi.org/project/arczk-agent/)
|
|
41
|
+
[](https://opensource.org/licenses/MIT)
|
|
42
|
+
[](https://testnet.arcscan.io)
|
|
43
|
+
[](https://github.com/Trymbakmahant/arcnano)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## ⚡ Overview
|
|
48
|
+
|
|
49
|
+
`arczk-agent` empowers autonomous AI agents (**LangChain**, **CrewAI**, **AutoGPT**, **LlamaIndex**) to execute instant, privacy-preserving micro-payments over standard **HTTP 402 Payment Required** protocols with complete identity unlinkability on the **Arc Network**.
|
|
50
|
+
|
|
51
|
+
### Why use `arczk-agent`?
|
|
52
|
+
|
|
53
|
+
- 🛡️ **Zero Signer Exposure**: The calling AI agent never broadcasts on-chain transactions or exposes private keys. API providers cannot link prompt requests to any on-chain wallet balance.
|
|
54
|
+
- ⚡ **Autonomous X402 Negotiation**: Automatically intercepts `402 Payment Required` responses, extracts cryptographic invoice parameters, generates Groth16 spend proofs in RAM, and retries in single-digit milliseconds.
|
|
55
|
+
- 🔐 **Shielded Note Vault**: Client-side note generation (`secret`, `nullifier_seed`, Poseidon commitments) with local encrypted JSON persistence.
|
|
56
|
+
- 🤖 **Agent Framework Ready**: Drop-in tool adapters for **LangChain** and **CrewAI** multi-agent pipelines.
|
|
57
|
+
- ⛽ **Zero Gas Overhead**: Note settlement is batched and sponsored by API providers via Circle Gas Station (ERC-4337) on Arc L1.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🔄 How Autonomous X402 Negotiation Works
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Autonomous Agent (Python) Protected API Gateway (X402) Arc L1
|
|
65
|
+
| | |
|
|
66
|
+
| 1. POST /v1/inference (no credentials) | |
|
|
67
|
+
|--------------------------------------------->| |
|
|
68
|
+
| | |
|
|
69
|
+
| 2. 402 Payment Required | |
|
|
70
|
+
| WWW-Authenticate: X402 pool=... | |
|
|
71
|
+
|<---------------------------------------------| |
|
|
72
|
+
| | |
|
|
73
|
+
| -- Parse X402 Invoice | |
|
|
74
|
+
| -- Retrieve Note from Vault | |
|
|
75
|
+
| -- Generate Groth16 Proof in RAM | |
|
|
76
|
+
| | |
|
|
77
|
+
| 3. POST /v1/inference | |
|
|
78
|
+
| Authorization: X402 {"proof": ...} | |
|
|
79
|
+
|--------------------------------------------->| |
|
|
80
|
+
| |-- Verify Proof (<8ms) |
|
|
81
|
+
| |-- Check Nullifier Cache |
|
|
82
|
+
| 4. 200 OK (Stream LLM Response) | |
|
|
83
|
+
|<---------------------------------------------| |
|
|
84
|
+
| | 5. batchSpend (Sponsored) |
|
|
85
|
+
| -- Mark Note Spent in Vault |---------------------------->|
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 📦 Installation
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Standard installation
|
|
94
|
+
pip install arczk-agent
|
|
95
|
+
|
|
96
|
+
# Using uv (recommended for ultra-fast installs)
|
|
97
|
+
uv pip install arczk-agent
|
|
98
|
+
|
|
99
|
+
# With LangChain support
|
|
100
|
+
pip install "arczk-agent[langchain]"
|
|
101
|
+
|
|
102
|
+
# With CrewAI support
|
|
103
|
+
pip install "arczk-agent[crewai]"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 🚀 Quickstart
|
|
109
|
+
|
|
110
|
+
### 1. Direct Python Client with Transparent X402 Handling
|
|
111
|
+
|
|
112
|
+
The `ArcAgentClient` behaves like standard `requests`, but transparently intercepts HTTP 402 challenges and fulfills them:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from arczk import ArcAgentClient, NoteVault
|
|
116
|
+
|
|
117
|
+
# 1. Initialize local shielded note vault
|
|
118
|
+
vault = NoteVault("~/.arcnano/agent_vault.json")
|
|
119
|
+
|
|
120
|
+
# 2. Fund/initialize an unspent note (0.01 USDC = 10,000 micro-units)
|
|
121
|
+
vault.create_note(denomination=10000)
|
|
122
|
+
|
|
123
|
+
print(f"Active unspent balance: {vault.unspent_balance()} micro-units")
|
|
124
|
+
|
|
125
|
+
# 3. Create autonomous agent HTTP client
|
|
126
|
+
client = ArcAgentClient(vault=vault)
|
|
127
|
+
|
|
128
|
+
# 4. Request any X402-enabled API endpoint:
|
|
129
|
+
# The client automatically handles HTTP 402, generates a ZK proof, and fulfills payment!
|
|
130
|
+
response = client.post(
|
|
131
|
+
"https://api.inference.ai/v1/generate",
|
|
132
|
+
json={"prompt": "Analyze autonomous financial markets on Arc"}
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
print("Status:", response.status_code)
|
|
136
|
+
print("Response:", response.json())
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### 2. LangChain Autonomous Agent Integration
|
|
142
|
+
|
|
143
|
+
Plug `ArcNanoLangChainTool` into any LangChain agent executor:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
147
|
+
from langchain_openai import ChatOpenAI
|
|
148
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
149
|
+
from arczk.integrations import ArcNanoLangChainTool
|
|
150
|
+
|
|
151
|
+
# Initialize tool
|
|
152
|
+
payment_tool = ArcNanoLangChainTool()
|
|
153
|
+
|
|
154
|
+
tools = [payment_tool]
|
|
155
|
+
llm = ChatOpenAI(model="gpt-4o", temperature=0)
|
|
156
|
+
|
|
157
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
158
|
+
("system", "You are an autonomous research agent. Use the arcnano tool to pay for external compute APIs."),
|
|
159
|
+
("human", "{input}"),
|
|
160
|
+
("placeholder", "{agent_scratchpad}"),
|
|
161
|
+
])
|
|
162
|
+
|
|
163
|
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
164
|
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
165
|
+
|
|
166
|
+
agent_executor.invoke({
|
|
167
|
+
"input": "Call https://api.inference.ai/v1/generate to retrieve specialized market intelligence."
|
|
168
|
+
})
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
### 3. CrewAI Autonomous Agent Tool
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from crewai import Agent, Task, Crew
|
|
177
|
+
from arczk.integrations import ArcNanoPaymentTool
|
|
178
|
+
|
|
179
|
+
payment_tool = ArcNanoPaymentTool()
|
|
180
|
+
|
|
181
|
+
researcher = Agent(
|
|
182
|
+
role="Autonomous Intelligence Scout",
|
|
183
|
+
goal="Gather paid API data on Arc without leaking signer identity",
|
|
184
|
+
backstory="Specialized in zero-knowledge agent transactions",
|
|
185
|
+
tools=[payment_tool.run],
|
|
186
|
+
verbose=True,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
task = Task(
|
|
190
|
+
description="Fetch data from https://api.inference.ai/v1/generate using shielded payment.",
|
|
191
|
+
expected_output="JSON data returned from the paid inference endpoint.",
|
|
192
|
+
agent=researcher,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
crew = Crew(agents=[researcher], tasks=[task])
|
|
196
|
+
result = crew.kickoff()
|
|
197
|
+
print(result)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 📚 Core Modules Reference
|
|
203
|
+
|
|
204
|
+
### `ArcAgentClient`
|
|
205
|
+
Autonomous HTTP client with session pooling and automated payment retry:
|
|
206
|
+
- `client.request(method, url, headers=None, auto_pay=True, **kwargs)`
|
|
207
|
+
- `client.get(url, **kwargs)`
|
|
208
|
+
- `client.post(url, **kwargs)`
|
|
209
|
+
- `client.parse_invoice(response)`: Extracts `recipient`, `pool`, `root`, and `denomination` from RFC `WWW-Authenticate` headers or JSON body.
|
|
210
|
+
|
|
211
|
+
### `NoteVault`
|
|
212
|
+
Encrypted local note manager storing client-side shielded notes:
|
|
213
|
+
- `vault.create_note(denomination=10000)`: Generates cryptographically secure random `secret` and `nullifier_seed` scalars in the BN254 field and computes Poseidon commitments.
|
|
214
|
+
- `vault.get_unspent_note(denomination=None)`: Retrieves the first unspent note with sufficient value.
|
|
215
|
+
- `vault.mark_spent(nullifier_hash)`: Marks note as consumed to prevent client-side replays.
|
|
216
|
+
- `vault.unspent_balance()`: Total available unspent units.
|
|
217
|
+
- `vault.save(filepath)` / `vault.load(filepath)`: JSON file persistence.
|
|
218
|
+
|
|
219
|
+
### `Groth16Prover`
|
|
220
|
+
RAM-based Groth16 spend proof generator:
|
|
221
|
+
- Binds public signals `[root, nullifierHash, recipient, aspRoot]` to the provider's wallet.
|
|
222
|
+
- Prevents frontrunning: proof is cryptographically tied to the exact recipient address specified in the invoice.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 🌐 Network & Contract Reference
|
|
227
|
+
|
|
228
|
+
| Parameter | Value |
|
|
229
|
+
| :--- | :--- |
|
|
230
|
+
| **Network** | Arc Testnet (Circle L1) |
|
|
231
|
+
| **Chain ID** | `5042002` |
|
|
232
|
+
| **Gas & Settlement Asset** | USDC (Native Gas & Denomination) |
|
|
233
|
+
| **RPC Endpoint** | `https://rpc.testnet.arc.network` |
|
|
234
|
+
| **Explorer** | [https://testnet.arcscan.io](https://testnet.arcscan.io) |
|
|
235
|
+
| **ArcNanoPool Contract** | [`0xa40d68FDEa3B6fb01c966A9d29A6fc341AE476Ca`](https://testnet.arcscan.io/address/0xa40d68FDEa3B6fb01c966A9d29A6fc341AE476Ca) |
|
|
236
|
+
| **Standard Denominations** | `1000` (0.001 USDC), `10000` (0.01 USDC), `100000` (0.1 USDC) |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 🧪 Testing
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Run test suite
|
|
244
|
+
pytest tests/ -v
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 📄 License
|
|
250
|
+
|
|
251
|
+
MIT © [Trymbak Mahant](https://github.com/Trymbakmahant)
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# arczk-agent
|
|
2
|
+
|
|
3
|
+
> **Autonomous AI Agent SDK for ArcNano Shielded Zero-Knowledge Nanopayments on Arc.**
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/arczk-agent/)
|
|
6
|
+
[](https://pypi.org/project/arczk-agent/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://testnet.arcscan.io)
|
|
9
|
+
[](https://github.com/Trymbakmahant/arcnano)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Overview
|
|
14
|
+
|
|
15
|
+
`arczk-agent` empowers autonomous AI agents (**LangChain**, **CrewAI**, **AutoGPT**, **LlamaIndex**) to execute instant, privacy-preserving micro-payments over standard **HTTP 402 Payment Required** protocols with complete identity unlinkability on the **Arc Network**.
|
|
16
|
+
|
|
17
|
+
### Why use `arczk-agent`?
|
|
18
|
+
|
|
19
|
+
- 🛡️ **Zero Signer Exposure**: The calling AI agent never broadcasts on-chain transactions or exposes private keys. API providers cannot link prompt requests to any on-chain wallet balance.
|
|
20
|
+
- ⚡ **Autonomous X402 Negotiation**: Automatically intercepts `402 Payment Required` responses, extracts cryptographic invoice parameters, generates Groth16 spend proofs in RAM, and retries in single-digit milliseconds.
|
|
21
|
+
- 🔐 **Shielded Note Vault**: Client-side note generation (`secret`, `nullifier_seed`, Poseidon commitments) with local encrypted JSON persistence.
|
|
22
|
+
- 🤖 **Agent Framework Ready**: Drop-in tool adapters for **LangChain** and **CrewAI** multi-agent pipelines.
|
|
23
|
+
- ⛽ **Zero Gas Overhead**: Note settlement is batched and sponsored by API providers via Circle Gas Station (ERC-4337) on Arc L1.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 🔄 How Autonomous X402 Negotiation Works
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Autonomous Agent (Python) Protected API Gateway (X402) Arc L1
|
|
31
|
+
| | |
|
|
32
|
+
| 1. POST /v1/inference (no credentials) | |
|
|
33
|
+
|--------------------------------------------->| |
|
|
34
|
+
| | |
|
|
35
|
+
| 2. 402 Payment Required | |
|
|
36
|
+
| WWW-Authenticate: X402 pool=... | |
|
|
37
|
+
|<---------------------------------------------| |
|
|
38
|
+
| | |
|
|
39
|
+
| -- Parse X402 Invoice | |
|
|
40
|
+
| -- Retrieve Note from Vault | |
|
|
41
|
+
| -- Generate Groth16 Proof in RAM | |
|
|
42
|
+
| | |
|
|
43
|
+
| 3. POST /v1/inference | |
|
|
44
|
+
| Authorization: X402 {"proof": ...} | |
|
|
45
|
+
|--------------------------------------------->| |
|
|
46
|
+
| |-- Verify Proof (<8ms) |
|
|
47
|
+
| |-- Check Nullifier Cache |
|
|
48
|
+
| 4. 200 OK (Stream LLM Response) | |
|
|
49
|
+
|<---------------------------------------------| |
|
|
50
|
+
| | 5. batchSpend (Sponsored) |
|
|
51
|
+
| -- Mark Note Spent in Vault |---------------------------->|
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 📦 Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Standard installation
|
|
60
|
+
pip install arczk-agent
|
|
61
|
+
|
|
62
|
+
# Using uv (recommended for ultra-fast installs)
|
|
63
|
+
uv pip install arczk-agent
|
|
64
|
+
|
|
65
|
+
# With LangChain support
|
|
66
|
+
pip install "arczk-agent[langchain]"
|
|
67
|
+
|
|
68
|
+
# With CrewAI support
|
|
69
|
+
pip install "arczk-agent[crewai]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🚀 Quickstart
|
|
75
|
+
|
|
76
|
+
### 1. Direct Python Client with Transparent X402 Handling
|
|
77
|
+
|
|
78
|
+
The `ArcAgentClient` behaves like standard `requests`, but transparently intercepts HTTP 402 challenges and fulfills them:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from arczk import ArcAgentClient, NoteVault
|
|
82
|
+
|
|
83
|
+
# 1. Initialize local shielded note vault
|
|
84
|
+
vault = NoteVault("~/.arcnano/agent_vault.json")
|
|
85
|
+
|
|
86
|
+
# 2. Fund/initialize an unspent note (0.01 USDC = 10,000 micro-units)
|
|
87
|
+
vault.create_note(denomination=10000)
|
|
88
|
+
|
|
89
|
+
print(f"Active unspent balance: {vault.unspent_balance()} micro-units")
|
|
90
|
+
|
|
91
|
+
# 3. Create autonomous agent HTTP client
|
|
92
|
+
client = ArcAgentClient(vault=vault)
|
|
93
|
+
|
|
94
|
+
# 4. Request any X402-enabled API endpoint:
|
|
95
|
+
# The client automatically handles HTTP 402, generates a ZK proof, and fulfills payment!
|
|
96
|
+
response = client.post(
|
|
97
|
+
"https://api.inference.ai/v1/generate",
|
|
98
|
+
json={"prompt": "Analyze autonomous financial markets on Arc"}
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
print("Status:", response.status_code)
|
|
102
|
+
print("Response:", response.json())
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### 2. LangChain Autonomous Agent Integration
|
|
108
|
+
|
|
109
|
+
Plug `ArcNanoLangChainTool` into any LangChain agent executor:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
|
113
|
+
from langchain_openai import ChatOpenAI
|
|
114
|
+
from langchain_core.prompts import ChatPromptTemplate
|
|
115
|
+
from arczk.integrations import ArcNanoLangChainTool
|
|
116
|
+
|
|
117
|
+
# Initialize tool
|
|
118
|
+
payment_tool = ArcNanoLangChainTool()
|
|
119
|
+
|
|
120
|
+
tools = [payment_tool]
|
|
121
|
+
llm = ChatOpenAI(model="gpt-4o", temperature=0)
|
|
122
|
+
|
|
123
|
+
prompt = ChatPromptTemplate.from_messages([
|
|
124
|
+
("system", "You are an autonomous research agent. Use the arcnano tool to pay for external compute APIs."),
|
|
125
|
+
("human", "{input}"),
|
|
126
|
+
("placeholder", "{agent_scratchpad}"),
|
|
127
|
+
])
|
|
128
|
+
|
|
129
|
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
|
130
|
+
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
|
|
131
|
+
|
|
132
|
+
agent_executor.invoke({
|
|
133
|
+
"input": "Call https://api.inference.ai/v1/generate to retrieve specialized market intelligence."
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 3. CrewAI Autonomous Agent Tool
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from crewai import Agent, Task, Crew
|
|
143
|
+
from arczk.integrations import ArcNanoPaymentTool
|
|
144
|
+
|
|
145
|
+
payment_tool = ArcNanoPaymentTool()
|
|
146
|
+
|
|
147
|
+
researcher = Agent(
|
|
148
|
+
role="Autonomous Intelligence Scout",
|
|
149
|
+
goal="Gather paid API data on Arc without leaking signer identity",
|
|
150
|
+
backstory="Specialized in zero-knowledge agent transactions",
|
|
151
|
+
tools=[payment_tool.run],
|
|
152
|
+
verbose=True,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
task = Task(
|
|
156
|
+
description="Fetch data from https://api.inference.ai/v1/generate using shielded payment.",
|
|
157
|
+
expected_output="JSON data returned from the paid inference endpoint.",
|
|
158
|
+
agent=researcher,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
crew = Crew(agents=[researcher], tasks=[task])
|
|
162
|
+
result = crew.kickoff()
|
|
163
|
+
print(result)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 📚 Core Modules Reference
|
|
169
|
+
|
|
170
|
+
### `ArcAgentClient`
|
|
171
|
+
Autonomous HTTP client with session pooling and automated payment retry:
|
|
172
|
+
- `client.request(method, url, headers=None, auto_pay=True, **kwargs)`
|
|
173
|
+
- `client.get(url, **kwargs)`
|
|
174
|
+
- `client.post(url, **kwargs)`
|
|
175
|
+
- `client.parse_invoice(response)`: Extracts `recipient`, `pool`, `root`, and `denomination` from RFC `WWW-Authenticate` headers or JSON body.
|
|
176
|
+
|
|
177
|
+
### `NoteVault`
|
|
178
|
+
Encrypted local note manager storing client-side shielded notes:
|
|
179
|
+
- `vault.create_note(denomination=10000)`: Generates cryptographically secure random `secret` and `nullifier_seed` scalars in the BN254 field and computes Poseidon commitments.
|
|
180
|
+
- `vault.get_unspent_note(denomination=None)`: Retrieves the first unspent note with sufficient value.
|
|
181
|
+
- `vault.mark_spent(nullifier_hash)`: Marks note as consumed to prevent client-side replays.
|
|
182
|
+
- `vault.unspent_balance()`: Total available unspent units.
|
|
183
|
+
- `vault.save(filepath)` / `vault.load(filepath)`: JSON file persistence.
|
|
184
|
+
|
|
185
|
+
### `Groth16Prover`
|
|
186
|
+
RAM-based Groth16 spend proof generator:
|
|
187
|
+
- Binds public signals `[root, nullifierHash, recipient, aspRoot]` to the provider's wallet.
|
|
188
|
+
- Prevents frontrunning: proof is cryptographically tied to the exact recipient address specified in the invoice.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## 🌐 Network & Contract Reference
|
|
193
|
+
|
|
194
|
+
| Parameter | Value |
|
|
195
|
+
| :--- | :--- |
|
|
196
|
+
| **Network** | Arc Testnet (Circle L1) |
|
|
197
|
+
| **Chain ID** | `5042002` |
|
|
198
|
+
| **Gas & Settlement Asset** | USDC (Native Gas & Denomination) |
|
|
199
|
+
| **RPC Endpoint** | `https://rpc.testnet.arc.network` |
|
|
200
|
+
| **Explorer** | [https://testnet.arcscan.io](https://testnet.arcscan.io) |
|
|
201
|
+
| **ArcNanoPool Contract** | [`0xa40d68FDEa3B6fb01c966A9d29A6fc341AE476Ca`](https://testnet.arcscan.io/address/0xa40d68FDEa3B6fb01c966A9d29A6fc341AE476Ca) |
|
|
202
|
+
| **Standard Denominations** | `1000` (0.001 USDC), `10000` (0.01 USDC), `100000` (0.1 USDC) |
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 🧪 Testing
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Run test suite
|
|
210
|
+
pytest tests/ -v
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 📄 License
|
|
216
|
+
|
|
217
|
+
MIT © [Trymbak Mahant](https://github.com/Trymbakmahant)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ArcNano: Shielded Zero-Knowledge Nanopayments on Arc
|
|
3
|
+
Autonomous AI Agent SDK (LangChain, AutoGPT, CrewAI)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .types import ShieldedNote, X402Invoice, SpendProofPayload
|
|
7
|
+
from .crypto import poseidon, derive_commitment, derive_nullifier_hash, BN254_FIELD_PRIME
|
|
8
|
+
from .vault import NoteVault
|
|
9
|
+
from .prover import Groth16Prover
|
|
10
|
+
from .client import ArcAgentClient
|
|
11
|
+
from .integrations import ArcNanoPaymentTool
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ShieldedNote",
|
|
16
|
+
"X402Invoice",
|
|
17
|
+
"SpendProofPayload",
|
|
18
|
+
"poseidon",
|
|
19
|
+
"derive_commitment",
|
|
20
|
+
"derive_nullifier_hash",
|
|
21
|
+
"BN254_FIELD_PRIME",
|
|
22
|
+
"NoteVault",
|
|
23
|
+
"Groth16Prover",
|
|
24
|
+
"ArcAgentClient",
|
|
25
|
+
"ArcNanoPaymentTool",
|
|
26
|
+
]
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
from typing import Optional, Dict, Any, Union
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from .types import ShieldedNote, X402Invoice, SpendProofPayload
|
|
8
|
+
from .vault import NoteVault
|
|
9
|
+
from .prover import Groth16Prover
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("arczk.client")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ArcAgentClient:
|
|
15
|
+
"""
|
|
16
|
+
Autonomous AI Agent HTTP client with automatic X402 payment handling.
|
|
17
|
+
Intercepts HTTP 402 Payment Required, generates zero-knowledge spend proofs in memory,
|
|
18
|
+
and retries transparently with standardized X-Payment and Authorization headers.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
vault: Optional[NoteVault] = None,
|
|
24
|
+
prover: Optional[Groth16Prover] = None,
|
|
25
|
+
max_payment_per_call: int = 50000, # 0.05 USDC max limit per call
|
|
26
|
+
session: Optional[requests.Session] = None,
|
|
27
|
+
):
|
|
28
|
+
self.vault = vault or NoteVault()
|
|
29
|
+
self.prover = prover or Groth16Prover()
|
|
30
|
+
self.max_payment_per_call = max_payment_per_call
|
|
31
|
+
self.session = session or requests.Session()
|
|
32
|
+
|
|
33
|
+
def parse_invoice(self, response: requests.Response) -> X402Invoice:
|
|
34
|
+
"""Parses X402 challenge from response headers, WWW-Authenticate, or JSON body."""
|
|
35
|
+
headers = response.headers
|
|
36
|
+
recipient = headers.get("x402-recipient")
|
|
37
|
+
pool = headers.get("x402-pool", "0xa40d68FDEa3B6fb01c966A9d29A6fc341AE476Ca")
|
|
38
|
+
root = headers.get("x402-root")
|
|
39
|
+
asp_root = headers.get("x402-asp-root")
|
|
40
|
+
denomination = int(headers.get("x402-denomination", "10000"))
|
|
41
|
+
chain_id = int(headers.get("x402-chain-id", "5042002"))
|
|
42
|
+
|
|
43
|
+
# Parse standard RFC-style WWW-Authenticate: X402 ... header
|
|
44
|
+
auth_header = headers.get("www-authenticate", "")
|
|
45
|
+
if "X402" in auth_header:
|
|
46
|
+
pool_match = re.search(r'pool=["\']([^"\']+)["\']', auth_header)
|
|
47
|
+
if pool_match and not recipient:
|
|
48
|
+
pool = pool_match.group(1)
|
|
49
|
+
denom_match = re.search(r'denomination=["\']?(\d+)["\']?', auth_header)
|
|
50
|
+
if denom_match:
|
|
51
|
+
try:
|
|
52
|
+
denomination = int(denom_match.group(1))
|
|
53
|
+
except ValueError:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
# Parse response JSON body if present
|
|
57
|
+
raw_challenge = {}
|
|
58
|
+
try:
|
|
59
|
+
body = response.json()
|
|
60
|
+
raw_challenge = body
|
|
61
|
+
invoice_data = body.get("invoice") or body
|
|
62
|
+
if isinstance(invoice_data, dict):
|
|
63
|
+
recipient = recipient or invoice_data.get("recipient")
|
|
64
|
+
pool = pool or invoice_data.get("pool")
|
|
65
|
+
root = root or invoice_data.get("root")
|
|
66
|
+
asp_root = (
|
|
67
|
+
asp_root
|
|
68
|
+
or invoice_data.get("aspRoot")
|
|
69
|
+
or invoice_data.get("asp_root")
|
|
70
|
+
)
|
|
71
|
+
if "denomination" in invoice_data:
|
|
72
|
+
try:
|
|
73
|
+
denomination = int(invoice_data["denomination"])
|
|
74
|
+
except (ValueError, TypeError):
|
|
75
|
+
pass
|
|
76
|
+
if "chainId" in invoice_data or "chain_id" in invoice_data:
|
|
77
|
+
try:
|
|
78
|
+
chain_id = int(invoice_data.get("chainId") or invoice_data.get("chain_id"))
|
|
79
|
+
except (ValueError, TypeError):
|
|
80
|
+
pass
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
if not recipient or not root:
|
|
85
|
+
raise ValueError(f"Incomplete X402 payment invoice from server: {headers}")
|
|
86
|
+
|
|
87
|
+
return X402Invoice(
|
|
88
|
+
pool=pool,
|
|
89
|
+
denomination=denomination,
|
|
90
|
+
recipient=recipient,
|
|
91
|
+
root=root,
|
|
92
|
+
asp_root=asp_root or "0",
|
|
93
|
+
chain_id=chain_id,
|
|
94
|
+
raw_challenge=raw_challenge,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def request(
|
|
98
|
+
self,
|
|
99
|
+
method: str,
|
|
100
|
+
url: str,
|
|
101
|
+
headers: Optional[Dict[str, str]] = None,
|
|
102
|
+
auto_pay: bool = True,
|
|
103
|
+
**kwargs,
|
|
104
|
+
) -> requests.Response:
|
|
105
|
+
"""
|
|
106
|
+
Executes HTTP request with autonomous X402 negotiation.
|
|
107
|
+
"""
|
|
108
|
+
req_headers = dict(headers or {})
|
|
109
|
+
|
|
110
|
+
# 1. Dispatch initial request
|
|
111
|
+
resp = self.session.request(method, url, headers=req_headers, **kwargs)
|
|
112
|
+
|
|
113
|
+
# 2. If 402 Payment Required and auto_pay enabled, negotiate ZK proof
|
|
114
|
+
if resp.status_code == 402 and auto_pay:
|
|
115
|
+
logger.info("Received HTTP 402 Payment Required from %s. Negotiating proof...", url)
|
|
116
|
+
invoice = self.parse_invoice(resp)
|
|
117
|
+
|
|
118
|
+
if invoice.denomination > self.max_payment_per_call:
|
|
119
|
+
raise PermissionError(
|
|
120
|
+
f"Invoice denomination ({invoice.denomination}) exceeds agent spending limit ({self.max_payment_per_call})"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Retrieve unspent note from vault
|
|
124
|
+
note = self.vault.get_unspent_note(invoice.denomination)
|
|
125
|
+
if not note:
|
|
126
|
+
# If no note exists, create one for demonstration/testnet flow
|
|
127
|
+
note = self.vault.create_note(denomination=invoice.denomination)
|
|
128
|
+
logger.info("Generated note %s for invoice", note.nullifier_hash[:16])
|
|
129
|
+
|
|
130
|
+
# Generate Groth16 spend proof in RAM
|
|
131
|
+
proof_payload = self.prover.generate_proof(note, invoice)
|
|
132
|
+
|
|
133
|
+
# Attach standard X402 payment headers and retry
|
|
134
|
+
payload_json = json.dumps(proof_payload.to_dict())
|
|
135
|
+
req_headers["X-Payment"] = payload_json
|
|
136
|
+
req_headers["X-PAYMENT"] = payload_json
|
|
137
|
+
req_headers["Authorization"] = f"X402 {payload_json}"
|
|
138
|
+
|
|
139
|
+
retry_resp = self.session.request(method, url, headers=req_headers, **kwargs)
|
|
140
|
+
|
|
141
|
+
if retry_resp.status_code in (200, 201, 204):
|
|
142
|
+
# Mark note as spent upon successful fulfillment
|
|
143
|
+
self.vault.mark_spent(note.nullifier_hash)
|
|
144
|
+
logger.info("Payment verified and fulfilled. Note %s marked spent.", note.nullifier_hash[:16])
|
|
145
|
+
return retry_resp
|
|
146
|
+
else:
|
|
147
|
+
logger.warning("Payment retry failed with status %d: %s", retry_resp.status_code, retry_resp.text)
|
|
148
|
+
return retry_resp
|
|
149
|
+
|
|
150
|
+
return resp
|
|
151
|
+
|
|
152
|
+
def get(self, url: str, **kwargs) -> requests.Response:
|
|
153
|
+
return self.request("GET", url, **kwargs)
|
|
154
|
+
|
|
155
|
+
def post(self, url: str, **kwargs) -> requests.Response:
|
|
156
|
+
return self.request("POST", url, **kwargs)
|
|
157
|
+
|
|
158
|
+
def put(self, url: str, **kwargs) -> requests.Response:
|
|
159
|
+
return self.request("PUT", url, **kwargs)
|
|
160
|
+
|
|
161
|
+
def delete(self, url: str, **kwargs) -> requests.Response:
|
|
162
|
+
return self.request("DELETE", url, **kwargs)
|