proofgate 0.1.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.
- proofgate/__init__.py +51 -0
- proofgate/client.py +524 -0
- proofgate/exceptions.py +36 -0
- proofgate/types.py +179 -0
- proofgate-0.1.0.dist-info/METADATA +248 -0
- proofgate-0.1.0.dist-info/RECORD +8 -0
- proofgate-0.1.0.dist-info/WHEEL +4 -0
- proofgate-0.1.0.dist-info/licenses/LICENSE +21 -0
proofgate/__init__.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ProofGate SDK
|
|
3
|
+
|
|
4
|
+
Blockchain guardrails for AI agents. Validate transactions
|
|
5
|
+
before execution to prevent wallet drains, infinite approvals,
|
|
6
|
+
and other security risks.
|
|
7
|
+
|
|
8
|
+
Example:
|
|
9
|
+
>>> from proofgate import ProofGate
|
|
10
|
+
>>>
|
|
11
|
+
>>> pg = ProofGate(api_key="pg_your_key")
|
|
12
|
+
>>>
|
|
13
|
+
>>> result = await pg.validate(
|
|
14
|
+
... from_address="0xAgent...",
|
|
15
|
+
... to="0xContract...",
|
|
16
|
+
... data="0xa9059cbb...",
|
|
17
|
+
... )
|
|
18
|
+
>>>
|
|
19
|
+
>>> if result.safe:
|
|
20
|
+
... # Execute transaction
|
|
21
|
+
... pass
|
|
22
|
+
... else:
|
|
23
|
+
... print(f"Blocked: {result.reason}")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from proofgate.client import ProofGate, AsyncProofGate
|
|
27
|
+
from proofgate.types import (
|
|
28
|
+
ProofGateConfig,
|
|
29
|
+
ValidateRequest,
|
|
30
|
+
ValidateResponse,
|
|
31
|
+
ValidationCheck,
|
|
32
|
+
AgentCheckResponse,
|
|
33
|
+
EvidenceResponse,
|
|
34
|
+
UsageResponse,
|
|
35
|
+
)
|
|
36
|
+
from proofgate.exceptions import ProofGateError
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"ProofGate",
|
|
40
|
+
"AsyncProofGate",
|
|
41
|
+
"ProofGateConfig",
|
|
42
|
+
"ValidateRequest",
|
|
43
|
+
"ValidateResponse",
|
|
44
|
+
"ValidationCheck",
|
|
45
|
+
"AgentCheckResponse",
|
|
46
|
+
"EvidenceResponse",
|
|
47
|
+
"UsageResponse",
|
|
48
|
+
"ProofGateError",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
__version__ = "0.1.0"
|
proofgate/client.py
ADDED
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
"""ProofGate SDK Client implementations."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, Dict, Any
|
|
4
|
+
import httpx
|
|
5
|
+
|
|
6
|
+
from proofgate.types import (
|
|
7
|
+
ProofGateConfig,
|
|
8
|
+
ValidateRequest,
|
|
9
|
+
ValidateResponse,
|
|
10
|
+
AgentCheckResponse,
|
|
11
|
+
EvidenceResponse,
|
|
12
|
+
UsageResponse,
|
|
13
|
+
)
|
|
14
|
+
from proofgate.exceptions import ProofGateError
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AsyncProofGate:
|
|
18
|
+
"""Async ProofGate SDK Client.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> from proofgate import AsyncProofGate
|
|
22
|
+
>>>
|
|
23
|
+
>>> pg = AsyncProofGate(api_key="pg_your_key")
|
|
24
|
+
>>>
|
|
25
|
+
>>> result = await pg.validate(
|
|
26
|
+
... from_address="0xAgent...",
|
|
27
|
+
... to="0xContract...",
|
|
28
|
+
... data="0xa9059cbb...",
|
|
29
|
+
... )
|
|
30
|
+
>>>
|
|
31
|
+
>>> if result.safe:
|
|
32
|
+
... # Execute transaction
|
|
33
|
+
... pass
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
api_key: str,
|
|
39
|
+
*,
|
|
40
|
+
base_url: str = "https://www.proofgate.xyz/api",
|
|
41
|
+
chain_id: int = 56,
|
|
42
|
+
guardrail_id: Optional[str] = None,
|
|
43
|
+
timeout: float = 30.0,
|
|
44
|
+
):
|
|
45
|
+
"""Initialize ProofGate client.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
api_key: API key from ProofGate dashboard (starts with pg_)
|
|
49
|
+
base_url: Base URL for API (default: https://www.proofgate.xyz/api)
|
|
50
|
+
chain_id: Default chain ID (default: 56 for BSC)
|
|
51
|
+
guardrail_id: Default guardrail ID to use for validations
|
|
52
|
+
timeout: Request timeout in seconds (default: 30.0)
|
|
53
|
+
"""
|
|
54
|
+
if not api_key:
|
|
55
|
+
raise ProofGateError(
|
|
56
|
+
"API key is required. Get one at https://www.proofgate.xyz/dashboard",
|
|
57
|
+
"MISSING_API_KEY",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if not api_key.startswith("pg_"):
|
|
61
|
+
raise ProofGateError(
|
|
62
|
+
'Invalid API key format. Keys start with "pg_"',
|
|
63
|
+
"INVALID_API_KEY",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
self.config = ProofGateConfig(
|
|
67
|
+
api_key=api_key,
|
|
68
|
+
base_url=base_url,
|
|
69
|
+
chain_id=chain_id,
|
|
70
|
+
guardrail_id=guardrail_id,
|
|
71
|
+
timeout=timeout,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
self._client = httpx.AsyncClient(
|
|
75
|
+
base_url=base_url,
|
|
76
|
+
timeout=timeout,
|
|
77
|
+
headers={
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
"X-API-Key": api_key,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
async def __aenter__(self) -> "AsyncProofGate":
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
async def __aexit__(self, *args: Any) -> None:
|
|
87
|
+
await self.close()
|
|
88
|
+
|
|
89
|
+
async def close(self) -> None:
|
|
90
|
+
"""Close the HTTP client."""
|
|
91
|
+
await self._client.aclose()
|
|
92
|
+
|
|
93
|
+
async def _request(
|
|
94
|
+
self,
|
|
95
|
+
method: str,
|
|
96
|
+
path: str,
|
|
97
|
+
json: Optional[Dict[str, Any]] = None,
|
|
98
|
+
) -> Dict[str, Any]:
|
|
99
|
+
"""Make an API request."""
|
|
100
|
+
try:
|
|
101
|
+
response = await self._client.request(method, path, json=json)
|
|
102
|
+
data = response.json()
|
|
103
|
+
|
|
104
|
+
if not response.is_success:
|
|
105
|
+
raise ProofGateError(
|
|
106
|
+
data.get("error") or data.get("message") or f"HTTP {response.status_code}",
|
|
107
|
+
"API_ERROR",
|
|
108
|
+
response.status_code,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return data
|
|
112
|
+
|
|
113
|
+
except httpx.TimeoutException:
|
|
114
|
+
raise ProofGateError("Request timeout", "TIMEOUT")
|
|
115
|
+
except httpx.RequestError as e:
|
|
116
|
+
raise ProofGateError(str(e), "NETWORK_ERROR")
|
|
117
|
+
|
|
118
|
+
async def validate(
|
|
119
|
+
self,
|
|
120
|
+
from_address: str,
|
|
121
|
+
to: str,
|
|
122
|
+
data: str,
|
|
123
|
+
value: str = "0",
|
|
124
|
+
guardrail_id: Optional[str] = None,
|
|
125
|
+
chain_id: Optional[int] = None,
|
|
126
|
+
) -> ValidateResponse:
|
|
127
|
+
"""Validate a transaction before execution.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
from_address: Sender address (your agent's wallet)
|
|
131
|
+
to: Target contract address
|
|
132
|
+
data: Transaction calldata
|
|
133
|
+
value: Value in wei (default: "0")
|
|
134
|
+
guardrail_id: Guardrail ID (overrides default)
|
|
135
|
+
chain_id: Chain ID (overrides default)
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Validation result
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
>>> result = await pg.validate(
|
|
142
|
+
... from_address="0xAgent...",
|
|
143
|
+
... to="0xUniswap...",
|
|
144
|
+
... data="0x38ed1739...", # swap calldata
|
|
145
|
+
... )
|
|
146
|
+
>>>
|
|
147
|
+
>>> if result.safe:
|
|
148
|
+
... # Execute the swap
|
|
149
|
+
... pass
|
|
150
|
+
>>> else:
|
|
151
|
+
... print(f"Blocked: {result.reason}")
|
|
152
|
+
"""
|
|
153
|
+
response = await self._request(
|
|
154
|
+
"POST",
|
|
155
|
+
"/validate",
|
|
156
|
+
json={
|
|
157
|
+
"from": from_address,
|
|
158
|
+
"to": to,
|
|
159
|
+
"data": data,
|
|
160
|
+
"value": value,
|
|
161
|
+
"guardrailId": guardrail_id or self.config.guardrail_id,
|
|
162
|
+
"chainId": chain_id or self.config.chain_id,
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
return ValidateResponse.model_validate(response)
|
|
166
|
+
|
|
167
|
+
async def validate_or_throw(
|
|
168
|
+
self,
|
|
169
|
+
from_address: str,
|
|
170
|
+
to: str,
|
|
171
|
+
data: str,
|
|
172
|
+
value: str = "0",
|
|
173
|
+
guardrail_id: Optional[str] = None,
|
|
174
|
+
chain_id: Optional[int] = None,
|
|
175
|
+
) -> ValidateResponse:
|
|
176
|
+
"""Validate and throw if unsafe (convenience method).
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
from_address: Sender address (your agent's wallet)
|
|
180
|
+
to: Target contract address
|
|
181
|
+
data: Transaction calldata
|
|
182
|
+
value: Value in wei (default: "0")
|
|
183
|
+
guardrail_id: Guardrail ID (overrides default)
|
|
184
|
+
chain_id: Chain ID (overrides default)
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Validation result (only if safe)
|
|
188
|
+
|
|
189
|
+
Raises:
|
|
190
|
+
ProofGateError: If validation fails
|
|
191
|
+
|
|
192
|
+
Example:
|
|
193
|
+
>>> try:
|
|
194
|
+
... await pg.validate_or_throw(from_address, to, data)
|
|
195
|
+
... # Safe to execute
|
|
196
|
+
... await wallet.send_transaction(to=to, data=data)
|
|
197
|
+
... except ProofGateError as e:
|
|
198
|
+
... print(f"Blocked: {e.message}")
|
|
199
|
+
"""
|
|
200
|
+
result = await self.validate(
|
|
201
|
+
from_address=from_address,
|
|
202
|
+
to=to,
|
|
203
|
+
data=data,
|
|
204
|
+
value=value,
|
|
205
|
+
guardrail_id=guardrail_id,
|
|
206
|
+
chain_id=chain_id,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
if not result.safe:
|
|
210
|
+
raise ProofGateError(
|
|
211
|
+
result.reason,
|
|
212
|
+
"VALIDATION_FAILED",
|
|
213
|
+
validation_result=result,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return result
|
|
217
|
+
|
|
218
|
+
async def check_agent(self, wallet: str) -> AgentCheckResponse:
|
|
219
|
+
"""Check an agent's trust score and verification status.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
wallet: Agent wallet address
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Agent verification info
|
|
226
|
+
|
|
227
|
+
Example:
|
|
228
|
+
>>> agent = await pg.check_agent("0x123...")
|
|
229
|
+
>>>
|
|
230
|
+
>>> if agent.verification_status == "verified":
|
|
231
|
+
... print(f"Trusted agent: {agent.tier_emoji} {agent.trust_score}/100")
|
|
232
|
+
>>> else:
|
|
233
|
+
... print("Warning: Unverified agent")
|
|
234
|
+
"""
|
|
235
|
+
response = await self._request("GET", f"/agents/check?wallet={wallet}")
|
|
236
|
+
return AgentCheckResponse.model_validate(response)
|
|
237
|
+
|
|
238
|
+
async def get_evidence(self, validation_id: str) -> EvidenceResponse:
|
|
239
|
+
"""Get evidence for a past validation.
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
validation_id: Validation ID
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Evidence details
|
|
246
|
+
|
|
247
|
+
Example:
|
|
248
|
+
>>> evidence = await pg.get_evidence("val_abc123")
|
|
249
|
+
>>> print(evidence.transaction)
|
|
250
|
+
>>> print(evidence.result)
|
|
251
|
+
"""
|
|
252
|
+
response = await self._request("GET", f"/evidence/{validation_id}")
|
|
253
|
+
return EvidenceResponse.model_validate(response)
|
|
254
|
+
|
|
255
|
+
async def get_usage(self, wallet: str) -> UsageResponse:
|
|
256
|
+
"""Get validation usage stats for a wallet.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
wallet: Wallet address
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
Usage statistics
|
|
263
|
+
"""
|
|
264
|
+
response = await self._request("GET", f"/validate?wallet={wallet}")
|
|
265
|
+
return UsageResponse.model_validate(response)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class ProofGate:
|
|
269
|
+
"""Synchronous ProofGate SDK Client.
|
|
270
|
+
|
|
271
|
+
Uses httpx sync client under the hood. For async applications,
|
|
272
|
+
use AsyncProofGate instead.
|
|
273
|
+
|
|
274
|
+
Example:
|
|
275
|
+
>>> from proofgate import ProofGate
|
|
276
|
+
>>>
|
|
277
|
+
>>> pg = ProofGate(api_key="pg_your_key")
|
|
278
|
+
>>>
|
|
279
|
+
>>> result = pg.validate(
|
|
280
|
+
... from_address="0xAgent...",
|
|
281
|
+
... to="0xContract...",
|
|
282
|
+
... data="0xa9059cbb...",
|
|
283
|
+
... )
|
|
284
|
+
>>>
|
|
285
|
+
>>> if result.safe:
|
|
286
|
+
... # Execute transaction
|
|
287
|
+
... pass
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
def __init__(
|
|
291
|
+
self,
|
|
292
|
+
api_key: str,
|
|
293
|
+
*,
|
|
294
|
+
base_url: str = "https://www.proofgate.xyz/api",
|
|
295
|
+
chain_id: int = 56,
|
|
296
|
+
guardrail_id: Optional[str] = None,
|
|
297
|
+
timeout: float = 30.0,
|
|
298
|
+
):
|
|
299
|
+
"""Initialize ProofGate client.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
api_key: API key from ProofGate dashboard (starts with pg_)
|
|
303
|
+
base_url: Base URL for API (default: https://www.proofgate.xyz/api)
|
|
304
|
+
chain_id: Default chain ID (default: 56 for BSC)
|
|
305
|
+
guardrail_id: Default guardrail ID to use for validations
|
|
306
|
+
timeout: Request timeout in seconds (default: 30.0)
|
|
307
|
+
"""
|
|
308
|
+
if not api_key:
|
|
309
|
+
raise ProofGateError(
|
|
310
|
+
"API key is required. Get one at https://www.proofgate.xyz/dashboard",
|
|
311
|
+
"MISSING_API_KEY",
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
if not api_key.startswith("pg_"):
|
|
315
|
+
raise ProofGateError(
|
|
316
|
+
'Invalid API key format. Keys start with "pg_"',
|
|
317
|
+
"INVALID_API_KEY",
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
self.config = ProofGateConfig(
|
|
321
|
+
api_key=api_key,
|
|
322
|
+
base_url=base_url,
|
|
323
|
+
chain_id=chain_id,
|
|
324
|
+
guardrail_id=guardrail_id,
|
|
325
|
+
timeout=timeout,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
self._client = httpx.Client(
|
|
329
|
+
base_url=base_url,
|
|
330
|
+
timeout=timeout,
|
|
331
|
+
headers={
|
|
332
|
+
"Content-Type": "application/json",
|
|
333
|
+
"X-API-Key": api_key,
|
|
334
|
+
},
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def __enter__(self) -> "ProofGate":
|
|
338
|
+
return self
|
|
339
|
+
|
|
340
|
+
def __exit__(self, *args: Any) -> None:
|
|
341
|
+
self.close()
|
|
342
|
+
|
|
343
|
+
def close(self) -> None:
|
|
344
|
+
"""Close the HTTP client."""
|
|
345
|
+
self._client.close()
|
|
346
|
+
|
|
347
|
+
def _request(
|
|
348
|
+
self,
|
|
349
|
+
method: str,
|
|
350
|
+
path: str,
|
|
351
|
+
json: Optional[Dict[str, Any]] = None,
|
|
352
|
+
) -> Dict[str, Any]:
|
|
353
|
+
"""Make an API request."""
|
|
354
|
+
try:
|
|
355
|
+
response = self._client.request(method, path, json=json)
|
|
356
|
+
data = response.json()
|
|
357
|
+
|
|
358
|
+
if not response.is_success:
|
|
359
|
+
raise ProofGateError(
|
|
360
|
+
data.get("error") or data.get("message") or f"HTTP {response.status_code}",
|
|
361
|
+
"API_ERROR",
|
|
362
|
+
response.status_code,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
return data
|
|
366
|
+
|
|
367
|
+
except httpx.TimeoutException:
|
|
368
|
+
raise ProofGateError("Request timeout", "TIMEOUT")
|
|
369
|
+
except httpx.RequestError as e:
|
|
370
|
+
raise ProofGateError(str(e), "NETWORK_ERROR")
|
|
371
|
+
|
|
372
|
+
def validate(
|
|
373
|
+
self,
|
|
374
|
+
from_address: str,
|
|
375
|
+
to: str,
|
|
376
|
+
data: str,
|
|
377
|
+
value: str = "0",
|
|
378
|
+
guardrail_id: Optional[str] = None,
|
|
379
|
+
chain_id: Optional[int] = None,
|
|
380
|
+
) -> ValidateResponse:
|
|
381
|
+
"""Validate a transaction before execution.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
from_address: Sender address (your agent's wallet)
|
|
385
|
+
to: Target contract address
|
|
386
|
+
data: Transaction calldata
|
|
387
|
+
value: Value in wei (default: "0")
|
|
388
|
+
guardrail_id: Guardrail ID (overrides default)
|
|
389
|
+
chain_id: Chain ID (overrides default)
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
Validation result
|
|
393
|
+
"""
|
|
394
|
+
response = self._request(
|
|
395
|
+
"POST",
|
|
396
|
+
"/validate",
|
|
397
|
+
json={
|
|
398
|
+
"from": from_address,
|
|
399
|
+
"to": to,
|
|
400
|
+
"data": data,
|
|
401
|
+
"value": value,
|
|
402
|
+
"guardrailId": guardrail_id or self.config.guardrail_id,
|
|
403
|
+
"chainId": chain_id or self.config.chain_id,
|
|
404
|
+
},
|
|
405
|
+
)
|
|
406
|
+
return ValidateResponse.model_validate(response)
|
|
407
|
+
|
|
408
|
+
def validate_or_throw(
|
|
409
|
+
self,
|
|
410
|
+
from_address: str,
|
|
411
|
+
to: str,
|
|
412
|
+
data: str,
|
|
413
|
+
value: str = "0",
|
|
414
|
+
guardrail_id: Optional[str] = None,
|
|
415
|
+
chain_id: Optional[int] = None,
|
|
416
|
+
) -> ValidateResponse:
|
|
417
|
+
"""Validate and throw if unsafe (convenience method).
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
from_address: Sender address (your agent's wallet)
|
|
421
|
+
to: Target contract address
|
|
422
|
+
data: Transaction calldata
|
|
423
|
+
value: Value in wei (default: "0")
|
|
424
|
+
guardrail_id: Guardrail ID (overrides default)
|
|
425
|
+
chain_id: Chain ID (overrides default)
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
Validation result (only if safe)
|
|
429
|
+
|
|
430
|
+
Raises:
|
|
431
|
+
ProofGateError: If validation fails
|
|
432
|
+
"""
|
|
433
|
+
result = self.validate(
|
|
434
|
+
from_address=from_address,
|
|
435
|
+
to=to,
|
|
436
|
+
data=data,
|
|
437
|
+
value=value,
|
|
438
|
+
guardrail_id=guardrail_id,
|
|
439
|
+
chain_id=chain_id,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
if not result.safe:
|
|
443
|
+
raise ProofGateError(
|
|
444
|
+
result.reason,
|
|
445
|
+
"VALIDATION_FAILED",
|
|
446
|
+
validation_result=result,
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
return result
|
|
450
|
+
|
|
451
|
+
def check_agent(self, wallet: str) -> AgentCheckResponse:
|
|
452
|
+
"""Check an agent's trust score and verification status.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
wallet: Agent wallet address
|
|
456
|
+
|
|
457
|
+
Returns:
|
|
458
|
+
Agent verification info
|
|
459
|
+
"""
|
|
460
|
+
response = self._request("GET", f"/agents/check?wallet={wallet}")
|
|
461
|
+
return AgentCheckResponse.model_validate(response)
|
|
462
|
+
|
|
463
|
+
def get_evidence(self, validation_id: str) -> EvidenceResponse:
|
|
464
|
+
"""Get evidence for a past validation.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
validation_id: Validation ID
|
|
468
|
+
|
|
469
|
+
Returns:
|
|
470
|
+
Evidence details
|
|
471
|
+
"""
|
|
472
|
+
response = self._request("GET", f"/evidence/{validation_id}")
|
|
473
|
+
return EvidenceResponse.model_validate(response)
|
|
474
|
+
|
|
475
|
+
def get_usage(self, wallet: str) -> UsageResponse:
|
|
476
|
+
"""Get validation usage stats for a wallet.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
wallet: Wallet address
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
Usage statistics
|
|
483
|
+
"""
|
|
484
|
+
response = self._request("GET", f"/validate?wallet={wallet}")
|
|
485
|
+
return UsageResponse.model_validate(response)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def is_transaction_safe(
|
|
489
|
+
api_key: str,
|
|
490
|
+
from_address: str,
|
|
491
|
+
to: str,
|
|
492
|
+
data: str,
|
|
493
|
+
value: str = "0",
|
|
494
|
+
) -> bool:
|
|
495
|
+
"""Quick validation helper.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
api_key: ProofGate API key
|
|
499
|
+
from_address: Sender address
|
|
500
|
+
to: Target contract address
|
|
501
|
+
data: Transaction calldata
|
|
502
|
+
value: Value in wei (default: "0")
|
|
503
|
+
|
|
504
|
+
Returns:
|
|
505
|
+
Whether the transaction is safe
|
|
506
|
+
|
|
507
|
+
Example:
|
|
508
|
+
>>> from proofgate import is_transaction_safe
|
|
509
|
+
>>>
|
|
510
|
+
>>> safe = is_transaction_safe(
|
|
511
|
+
... "pg_xxx",
|
|
512
|
+
... from_address=agent,
|
|
513
|
+
... to=contract,
|
|
514
|
+
... data=calldata,
|
|
515
|
+
... )
|
|
516
|
+
"""
|
|
517
|
+
with ProofGate(api_key=api_key) as pg:
|
|
518
|
+
result = pg.validate(
|
|
519
|
+
from_address=from_address,
|
|
520
|
+
to=to,
|
|
521
|
+
data=data,
|
|
522
|
+
value=value,
|
|
523
|
+
)
|
|
524
|
+
return result.safe
|
proofgate/exceptions.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Exceptions for ProofGate SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from proofgate.types import ValidateResponse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ProofGateError(Exception):
|
|
10
|
+
"""Base exception for ProofGate errors.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
message: Human-readable error message
|
|
14
|
+
code: Error code (e.g., 'VALIDATION_FAILED', 'API_ERROR')
|
|
15
|
+
status_code: HTTP status code (if applicable)
|
|
16
|
+
validation_result: Validation result (if validation failed)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
message: str,
|
|
22
|
+
code: str,
|
|
23
|
+
status_code: Optional[int] = None,
|
|
24
|
+
validation_result: Optional["ValidateResponse"] = None,
|
|
25
|
+
):
|
|
26
|
+
super().__init__(message)
|
|
27
|
+
self.message = message
|
|
28
|
+
self.code = code
|
|
29
|
+
self.status_code = status_code
|
|
30
|
+
self.validation_result = validation_result
|
|
31
|
+
|
|
32
|
+
def __str__(self) -> str:
|
|
33
|
+
return f"[{self.code}] {self.message}"
|
|
34
|
+
|
|
35
|
+
def __repr__(self) -> str:
|
|
36
|
+
return f"ProofGateError(code={self.code!r}, message={self.message!r})"
|
proofgate/types.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Type definitions for ProofGate SDK."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional, List, Literal
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProofGateConfig(BaseModel):
|
|
8
|
+
"""Configuration for ProofGate client."""
|
|
9
|
+
|
|
10
|
+
api_key: str = Field(..., description="API key from ProofGate dashboard (starts with pg_)")
|
|
11
|
+
base_url: str = Field(
|
|
12
|
+
default="https://www.proofgate.xyz/api",
|
|
13
|
+
description="Base URL for API"
|
|
14
|
+
)
|
|
15
|
+
chain_id: int = Field(default=56, description="Default chain ID (56 = BSC)")
|
|
16
|
+
guardrail_id: Optional[str] = Field(
|
|
17
|
+
default=None,
|
|
18
|
+
description="Default guardrail ID to use for validations"
|
|
19
|
+
)
|
|
20
|
+
timeout: float = Field(default=30.0, description="Request timeout in seconds")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ValidateRequest(BaseModel):
|
|
24
|
+
"""Request for transaction validation."""
|
|
25
|
+
|
|
26
|
+
from_address: str = Field(..., alias="from", description="Sender address (your agent's wallet)")
|
|
27
|
+
to: str = Field(..., description="Target contract address")
|
|
28
|
+
data: str = Field(..., description="Transaction calldata")
|
|
29
|
+
value: str = Field(default="0", description="Value in wei")
|
|
30
|
+
guardrail_id: Optional[str] = Field(default=None, description="Guardrail ID (overrides default)")
|
|
31
|
+
chain_id: Optional[int] = Field(default=None, description="Chain ID (overrides default)")
|
|
32
|
+
|
|
33
|
+
class Config:
|
|
34
|
+
populate_by_name = True
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ValidationCheck(BaseModel):
|
|
38
|
+
"""Individual check result from validation."""
|
|
39
|
+
|
|
40
|
+
name: str = Field(..., description="Check name (e.g., 'allowed_contracts', 'daily_limit')")
|
|
41
|
+
passed: bool = Field(..., description="Did this check pass?")
|
|
42
|
+
details: str = Field(..., description="Human-readable details")
|
|
43
|
+
severity: Literal["info", "warning", "critical"] = Field(
|
|
44
|
+
..., description="Severity level"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ValidateResponse(BaseModel):
|
|
49
|
+
"""Response from transaction validation."""
|
|
50
|
+
|
|
51
|
+
validation_id: str = Field(..., alias="validationId", description="Unique validation ID")
|
|
52
|
+
result: Literal["PASS", "FAIL", "PENDING"] = Field(..., description="Validation result")
|
|
53
|
+
reason: str = Field(..., description="Human-readable reason")
|
|
54
|
+
evidence_uri: str = Field(..., alias="evidenceUri", description="Evidence URI")
|
|
55
|
+
safe: bool = Field(..., description="Is the transaction safe to execute?")
|
|
56
|
+
checks: List[ValidationCheck] = Field(default_factory=list, description="Detailed check results")
|
|
57
|
+
chain_id: int = Field(..., alias="chainId", description="Chain ID validated on")
|
|
58
|
+
authenticated: bool = Field(default=False, description="Was API key authenticated?")
|
|
59
|
+
tier: str = Field(default="free", description="User tier (free/pro)")
|
|
60
|
+
backend: str = Field(default="local", description="Backend used (local/evidence-service)")
|
|
61
|
+
on_chain_recorded: bool = Field(
|
|
62
|
+
default=False, alias="onChainRecorded", description="Was proof recorded on-chain?"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
class Config:
|
|
66
|
+
populate_by_name = True
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class AgentStats(BaseModel):
|
|
70
|
+
"""Validation statistics for an agent."""
|
|
71
|
+
|
|
72
|
+
total_validations: int = Field(..., alias="totalValidations")
|
|
73
|
+
passed_validations: int = Field(..., alias="passedValidations")
|
|
74
|
+
failed_validations: int = Field(..., alias="failedValidations")
|
|
75
|
+
pass_rate: float = Field(..., alias="passRate")
|
|
76
|
+
|
|
77
|
+
class Config:
|
|
78
|
+
populate_by_name = True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class AgentRegistration(BaseModel):
|
|
82
|
+
"""Registration info for an agent."""
|
|
83
|
+
|
|
84
|
+
name: Optional[str] = None
|
|
85
|
+
registered_at: str = Field(..., alias="registeredAt")
|
|
86
|
+
|
|
87
|
+
class Config:
|
|
88
|
+
populate_by_name = True
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class AgentCheckResponse(BaseModel):
|
|
92
|
+
"""Response from agent check."""
|
|
93
|
+
|
|
94
|
+
wallet: str = Field(..., description="Wallet address (lowercase)")
|
|
95
|
+
is_registered: bool = Field(..., alias="isRegistered", description="Is this agent registered?")
|
|
96
|
+
verification_status: Literal["verified", "registered", "unverified", "unknown"] = Field(
|
|
97
|
+
..., alias="verificationStatus", description="Verification status"
|
|
98
|
+
)
|
|
99
|
+
verification_message: str = Field(..., alias="verificationMessage", description="Human-readable message")
|
|
100
|
+
trust_score: int = Field(..., alias="trustScore", description="Trust score (0-100)")
|
|
101
|
+
tier: Literal["diamond", "gold", "silver", "bronze", "unverified"] = Field(
|
|
102
|
+
..., description="Trust tier"
|
|
103
|
+
)
|
|
104
|
+
tier_emoji: str = Field(..., alias="tierEmoji", description="Tier emoji")
|
|
105
|
+
tier_name: str = Field(..., alias="tierName", description="Tier display name")
|
|
106
|
+
stats: AgentStats = Field(..., description="Validation statistics")
|
|
107
|
+
registration: Optional[AgentRegistration] = Field(
|
|
108
|
+
default=None, description="Registration info (if registered)"
|
|
109
|
+
)
|
|
110
|
+
recommendation: str = Field(..., description="Safety recommendation")
|
|
111
|
+
|
|
112
|
+
class Config:
|
|
113
|
+
populate_by_name = True
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class EvidenceTransaction(BaseModel):
|
|
117
|
+
"""Transaction details in evidence."""
|
|
118
|
+
|
|
119
|
+
from_address: str = Field(..., alias="from")
|
|
120
|
+
to: str
|
|
121
|
+
data: str
|
|
122
|
+
value: str
|
|
123
|
+
|
|
124
|
+
class Config:
|
|
125
|
+
populate_by_name = True
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class EvidenceResult(BaseModel):
|
|
129
|
+
"""Validation result in evidence."""
|
|
130
|
+
|
|
131
|
+
status: Literal["PASS", "FAIL", "PENDING"]
|
|
132
|
+
reason: str
|
|
133
|
+
safe: bool
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class EvidenceAgent(BaseModel):
|
|
137
|
+
"""Agent info in evidence."""
|
|
138
|
+
|
|
139
|
+
wallet: str
|
|
140
|
+
name: Optional[str] = None
|
|
141
|
+
verified: bool
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class EvidenceProof(BaseModel):
|
|
145
|
+
"""Proof metadata in evidence."""
|
|
146
|
+
|
|
147
|
+
authenticated: bool
|
|
148
|
+
on_chain_recorded: bool = Field(..., alias="onChainRecorded")
|
|
149
|
+
batch_id: Optional[str] = Field(default=None, alias="batchId")
|
|
150
|
+
recorded_at: Optional[str] = Field(default=None, alias="recordedAt")
|
|
151
|
+
|
|
152
|
+
class Config:
|
|
153
|
+
populate_by_name = True
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class EvidenceResponse(BaseModel):
|
|
157
|
+
"""Response from evidence retrieval."""
|
|
158
|
+
|
|
159
|
+
validation_id: str = Field(..., alias="validationId", description="Validation ID")
|
|
160
|
+
timestamp: str = Field(..., description="Timestamp")
|
|
161
|
+
chain_id: int = Field(..., alias="chainId", description="Chain ID")
|
|
162
|
+
transaction: EvidenceTransaction = Field(..., description="Transaction details")
|
|
163
|
+
result: EvidenceResult = Field(..., description="Validation result")
|
|
164
|
+
guardrail_id: Optional[str] = Field(default=None, alias="guardrailId", description="Guardrail used")
|
|
165
|
+
agent: EvidenceAgent = Field(..., description="Agent info")
|
|
166
|
+
proof: EvidenceProof = Field(..., description="Proof metadata")
|
|
167
|
+
|
|
168
|
+
class Config:
|
|
169
|
+
populate_by_name = True
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class UsageResponse(BaseModel):
|
|
173
|
+
"""Response from usage check."""
|
|
174
|
+
|
|
175
|
+
wallet: str
|
|
176
|
+
tier: str
|
|
177
|
+
validations_used: int
|
|
178
|
+
validations_limit: int
|
|
179
|
+
daily_spent_wei: str
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: proofgate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official ProofGate SDK — blockchain transaction validation and guardrails for AI agents
|
|
5
|
+
Project-URL: Homepage, https://www.proofgate.xyz
|
|
6
|
+
Project-URL: Documentation, https://www.proofgate.xyz/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/ProofGate/proofgate-python
|
|
8
|
+
Project-URL: Issues, https://github.com/ProofGate/proofgate-python/issues
|
|
9
|
+
Author-email: 0xCR6 <cristian@proofgate.xyz>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai-agent,blockchain,bsc,defi,ethereum,guardrails,proofgate,security,validation,web3
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Requires-Dist: httpx>=0.24.0
|
|
27
|
+
Requires-Dist: pydantic>=2.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-httpx>=0.21.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# proofgate
|
|
38
|
+
|
|
39
|
+
> Blockchain guardrails for AI agents. Validate transactions before execution.
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/proofgate/)
|
|
42
|
+
[](https://www.python.org/downloads/)
|
|
43
|
+
[](https://opensource.org/licenses/MIT)
|
|
44
|
+
|
|
45
|
+
## What is ProofGate?
|
|
46
|
+
|
|
47
|
+
ProofGate validates blockchain transactions before your AI agent executes them. It prevents:
|
|
48
|
+
|
|
49
|
+
- 🚫 **Wallet drains** from prompt injection attacks
|
|
50
|
+
- 🚫 **Infinite approvals** to malicious contracts
|
|
51
|
+
- 🚫 **Excessive spending** beyond daily limits
|
|
52
|
+
- 🚫 **High slippage** swaps that lose money
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install proofgate
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### Synchronous Usage
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from proofgate import ProofGate
|
|
66
|
+
|
|
67
|
+
# Initialize client
|
|
68
|
+
pg = ProofGate(api_key="pg_your_api_key") # Get from proofgate.xyz/dashboard
|
|
69
|
+
|
|
70
|
+
# Validate before sending
|
|
71
|
+
result = pg.validate(
|
|
72
|
+
from_address="0xYourAgentWallet",
|
|
73
|
+
to="0xContractAddress",
|
|
74
|
+
data="0xa9059cbb...", # Transaction calldata
|
|
75
|
+
value="0",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if result.safe:
|
|
79
|
+
# ✅ Execute the transaction
|
|
80
|
+
wallet.send_transaction(to=to, data=data, value=value)
|
|
81
|
+
else:
|
|
82
|
+
# 🚫 Transaction blocked
|
|
83
|
+
print(f"Blocked: {result.reason}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Async Usage
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from proofgate import AsyncProofGate
|
|
90
|
+
|
|
91
|
+
async def main():
|
|
92
|
+
async with AsyncProofGate(api_key="pg_your_api_key") as pg:
|
|
93
|
+
result = await pg.validate(
|
|
94
|
+
from_address="0xYourAgentWallet",
|
|
95
|
+
to="0xContractAddress",
|
|
96
|
+
data="0xa9059cbb...",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if result.safe:
|
|
100
|
+
# Execute transaction
|
|
101
|
+
pass
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### `ProofGate(config)` / `AsyncProofGate(config)`
|
|
107
|
+
|
|
108
|
+
Create a new ProofGate client.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
pg = ProofGate(
|
|
112
|
+
api_key="pg_xxx", # Required: Your API key
|
|
113
|
+
chain_id=56, # Optional: Default chain (56 = BSC)
|
|
114
|
+
guardrail_id="xxx", # Optional: Default guardrail
|
|
115
|
+
base_url="https://...", # Optional: Custom API URL
|
|
116
|
+
timeout=30.0, # Optional: Request timeout (seconds)
|
|
117
|
+
)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `pg.validate(request)`
|
|
121
|
+
|
|
122
|
+
Validate a transaction.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
result = pg.validate(
|
|
126
|
+
from_address="0xAgent...",
|
|
127
|
+
to="0xContract...",
|
|
128
|
+
data="0x...",
|
|
129
|
+
value="0", # Optional
|
|
130
|
+
guardrail_id="xxx", # Optional: Override default
|
|
131
|
+
chain_id=56, # Optional: Override default
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Returns ValidateResponse with:
|
|
135
|
+
# - validation_id: str
|
|
136
|
+
# - result: "PASS" | "FAIL" | "PENDING"
|
|
137
|
+
# - reason: str
|
|
138
|
+
# - safe: bool
|
|
139
|
+
# - checks: List[ValidationCheck]
|
|
140
|
+
# - authenticated: bool
|
|
141
|
+
# - evidence_uri: str
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `pg.validate_or_throw(request)`
|
|
145
|
+
|
|
146
|
+
Validate and raise exception if unsafe.
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from proofgate import ProofGateError
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
pg.validate_or_throw(
|
|
153
|
+
from_address=from_addr,
|
|
154
|
+
to=to_addr,
|
|
155
|
+
data=calldata,
|
|
156
|
+
)
|
|
157
|
+
# Safe to execute
|
|
158
|
+
except ProofGateError as e:
|
|
159
|
+
print(f"Blocked: {e.message}")
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `pg.check_agent(wallet)`
|
|
163
|
+
|
|
164
|
+
Check an agent's trust score.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
agent = pg.check_agent("0x123...")
|
|
168
|
+
|
|
169
|
+
print(agent.trust_score) # 85
|
|
170
|
+
print(agent.tier) # "gold"
|
|
171
|
+
print(agent.verification_status) # "verified"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `pg.get_evidence(validation_id)`
|
|
175
|
+
|
|
176
|
+
Get evidence for a past validation.
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
evidence = pg.get_evidence("val_abc123")
|
|
180
|
+
print(evidence.transaction)
|
|
181
|
+
print(evidence.result)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Guardrails
|
|
185
|
+
|
|
186
|
+
Guardrails define what your agent can do. Create them at [proofgate.xyz/guardrails](https://www.proofgate.xyz/guardrails).
|
|
187
|
+
|
|
188
|
+
Example guardrail rules:
|
|
189
|
+
- **Whitelist contracts**: Only Uniswap, Aave, Compound
|
|
190
|
+
- **Max approval**: 1,000 USDC per approval
|
|
191
|
+
- **Max slippage**: 1% on swaps
|
|
192
|
+
- **Daily limit**: $10,000 total spending
|
|
193
|
+
|
|
194
|
+
## Error Handling
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from proofgate import ProofGate, ProofGateError
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
pg.validate(from_address=from_addr, to=to_addr, data=calldata)
|
|
201
|
+
except ProofGateError as e:
|
|
202
|
+
print(f"Code: {e.code}") # "VALIDATION_FAILED"
|
|
203
|
+
print(f"Message: {e.message}") # "Infinite approval detected"
|
|
204
|
+
print(f"Result: {e.validation_result}")
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Error codes:
|
|
208
|
+
- `MISSING_API_KEY` - No API key provided
|
|
209
|
+
- `INVALID_API_KEY` - Key doesn't start with `pg_`
|
|
210
|
+
- `VALIDATION_FAILED` - Transaction failed validation
|
|
211
|
+
- `API_ERROR` - API returned an error
|
|
212
|
+
- `NETWORK_ERROR` - Network request failed
|
|
213
|
+
- `TIMEOUT` - Request timed out
|
|
214
|
+
|
|
215
|
+
## Type Hints
|
|
216
|
+
|
|
217
|
+
Full type hints included:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from proofgate import (
|
|
221
|
+
ProofGateConfig,
|
|
222
|
+
ValidateRequest,
|
|
223
|
+
ValidateResponse,
|
|
224
|
+
ValidationCheck,
|
|
225
|
+
AgentCheckResponse,
|
|
226
|
+
EvidenceResponse,
|
|
227
|
+
)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Get Your API Key
|
|
231
|
+
|
|
232
|
+
1. Go to [proofgate.xyz](https://www.proofgate.xyz)
|
|
233
|
+
2. Connect your wallet
|
|
234
|
+
3. Register your AI agent
|
|
235
|
+
4. Copy your API key (starts with `pg_`)
|
|
236
|
+
|
|
237
|
+
**Free tier:** 100 validations/month
|
|
238
|
+
|
|
239
|
+
## Links
|
|
240
|
+
|
|
241
|
+
- **Website:** [proofgate.xyz](https://www.proofgate.xyz)
|
|
242
|
+
- **Documentation:** [proofgate.xyz/docs](https://www.proofgate.xyz/docs)
|
|
243
|
+
- **Dashboard:** [proofgate.xyz/dashboard](https://www.proofgate.xyz/dashboard)
|
|
244
|
+
- **GitHub:** [github.com/ProofGate/proofgate-python](https://github.com/ProofGate/proofgate-python)
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT © [0xCR6](https://twitter.com/0xCR6)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
proofgate/__init__.py,sha256=RYOe5gCXPhsPG6-HzsnmVkdWpzE6GoIHimcZ4J9sdTE,1130
|
|
2
|
+
proofgate/client.py,sha256=nnCqjtD12WXU5u1dzkx6VEMxnAYiZgJ-9HSFrPdl0Fs,15765
|
|
3
|
+
proofgate/exceptions.py,sha256=PCbAa3hHlNvG0seXRl0j1ubbi6PGLJHyIdEE8tb0bpo,1059
|
|
4
|
+
proofgate/types.py,sha256=RPJPHlyi1NZ31MoLntoXlUb8S_EpdVCKbg9MQQj6XnY,6588
|
|
5
|
+
proofgate-0.1.0.dist-info/METADATA,sha256=oe1bbnV56br6ryNBiWfqYasIi7CcYVN9oxTorQ6qi2E,6817
|
|
6
|
+
proofgate-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
7
|
+
proofgate-0.1.0.dist-info/licenses/LICENSE,sha256=Z3Jp3T7pcPkUZiJK7_WuigXNQZYY_bpasmJg1mS9NA8,1062
|
|
8
|
+
proofgate-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 0xCR6
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|