The ChainGPT Smart Contract Auditor provides automated security vulnerability analysis for smart contracts. It offers comprehensive audit reports with support for both immediate and streaming responses, plus session-based history tracking.
Table of Contents
Installation
Quick Start
Authentication & Client Setup
AuditorService Methods
Request Models & Parameters
Response Models
Error Handling
Best Practices
Complete Examples
Installation
pipinstallchaingpt
Requirements:
Python 3.8+
Valid ChainGPT API key
Quick Start
Authentication & Client Setup
Environment Setup:
AuditorService Methods
1. audit_contract() - Complete Audit Response
Returns the full audit report in a single response.
When to use:
You want the complete audit report at once
Working with shorter contracts
Building batch processing systems
Example:
2. stream_audit() - Streaming Audit Response
Streams the audit report progressively as it's generated.
When to use:
Large contracts with lengthy audit reports
Real-time UI updates
Progressive result display
Example:
3. get_audit_history() - Session History
Retrieves past audit conversations for a session.
Parameters:
limit: Max entries to return (default: 10)
offset: Pagination offset (default: 0)
sort_by: Sort field (default: "createdAt")
sort_order: "asc" or "desc" (default: "desc")
sdk_unique_id: Required for session-specific history
Example:
Request Models & Parameters
SmartContractAuditRequestModel
Field Details:
Field
Type
Required
Description
model
Literal
No
Always "smart_contract_auditor" (auto-set)
question
str
Yes
Contract code + audit instructions
chatHistory
enum
No
ON or OFF (default: OFF)
sdkUniqueId
str
Conditional
Required if chatHistory=ON, 1-100 chars
Crafting Effective Questions:
Focus on:
Reentrancy vulnerabilities
Integer overflow/underflow
Access control issues
Gas optimization opportunities
Best practice compliance """
Chat History & Sessions
Without History (Stateless):
With History (Session-based):
Response Models
LLMResponseModel (for audit results)
GetChatHistoryResponseModel (for history)
Error Handling
Exception Hierarchy
Comprehensive Error Handling
Best Practices
1. Resource Management
2. Session Management
3. Contract Preparation
4. Streaming Best Practices
Complete Examples
Example 1: Basic Contract Audit
Example 2: Session-Based Multi-Contract Audit
Example 3: Production-Ready Audit Service
This documentation provides a comprehensive guide for developers to effectively use the ChainGPT Smart Contract Auditor SDK with practical examples, best practices, and robust error handling patterns.
# ❌ Too vague
question = "Check this contract"
# ✅ Specific and detailed
question = """
Please perform a comprehensive security audit on this Solidity contract:
```solidity
pragma solidity ^0.8.0;
contract MyToken {
// contract code here
}
request = SmartContractAuditRequestModel(
question="Audit this contract...",
chatHistory=ChatHistoryMode.OFF
)
session_id = "audit-session-" + str(uuid.uuid4())
# First audit
request1 = SmartContractAuditRequestModel(
question="Audit this ERC20 contract...",
chatHistory=ChatHistoryMode.ON,
sdkUniqueId=session_id
)
# Follow-up question in same session
request2 = SmartContractAuditRequestModel(
question="Can you explain the reentrancy issue in more detail?",
chatHistory=ChatHistoryMode.ON,
sdkUniqueId=session_id
)
class LLMResponseModel:
status: bool # Success indicator
statusCode: Optional[int] # HTTP status
message: str # Response message
data: LLMResponseDataModel
class LLMResponseDataModel:
bot: str # The actual audit report
class GetChatHistoryResponseModel:
status: Optional[bool]
statusCode: Optional[int]
message: str
data: ChatHistoryDataModel
class ChatHistoryDataModel:
count: int # Total entries found
rows: List[ChatHistoryEntryModel] # History entries
class ChatHistoryEntryModel:
id: str
question: str # Your original audit request
answer: str # The AI's audit report
createdAt: str # Timestamp
sdkUniqueId: str # Session ID
# ... other fields
from chaingpt.exceptions import (
ChainGPTError, # Base exception
APIError, # API-related errors
AuthenticationError, # Invalid API key
ValidationError, # Invalid request data
RateLimitError, # Rate limit exceeded
TimeoutError, # Request timeout
)
import logging
from chaingpt.exceptions import *
async def robust_audit(contract_code: str):
try:
request = SmartContractAuditRequestModel(
question=f"Audit: ```solidity\n{contract_code}\n```"
)
response = await client.auditor.audit_contract(request)
if not response.status:
logging.warning(f"Audit warning: {response.message}")
return response.data.bot
except AuthenticationError:
logging.error("Invalid API key - check your credentials")
raise
except ValidationError as e:
logging.error(f"Invalid request: {e.message}")
if e.field:
logging.error(f"Problem with field: {e.field}")
raise
except RateLimitError as e:
logging.error(f"Rate limited. Retry after: {e.retry_after} seconds")
raise
except TimeoutError:
logging.error("Request timed out - try with smaller contract or increase timeout")
raise
except APIError as e:
logging.error(f"API error {e.status_code}: {e.message}")
raise
except ChainGPTError as e:
logging.error(f"SDK error: {e.message}")
if e.details:
logging.error(f"Details: {e.details}")
raise
except Exception as e:
logging.error(f"Unexpected error: {e}")
raise
# ✅ Always use context manager or explicit cleanup
async with ChainGPTClient(api_key=API_KEY) as client:
# Your audit code here
pass
# Client automatically closed
# Or explicit cleanup:
client = ChainGPTClient(api_key=API_KEY)
try:
# Your audit code here
pass
finally:
await client.close()
import uuid
def generate_session_id() -> str:
"""Generate unique session ID for audit history"""
return f"audit-{uuid.uuid4()}"
# Use consistent session IDs for related audits
session_id = generate_session_id()
def prepare_audit_request(contract_code: str, focus_areas: List[str] = None) -> str:
"""Prepare a well-structured audit request"""
base_prompt = f"""
Please perform a comprehensive security audit on this Solidity contract:
```solidity
{contract_code}
"""
if focus_areas:
base_prompt += f"\nPlease focus on: {', '.join(focus_areas)}"
return base_prompt
async def stream_with_timeout(request: SmartContractAuditRequestModel, timeout: int = 300):
"""Stream with custom timeout handling"""
import asyncio
async def stream_audit():
result = ""
async for chunk in client.auditor.stream_audit(request):
result += chunk.decode('utf-8')
yield result
try:
async for partial_result in asyncio.wait_for(stream_audit(), timeout=timeout):
# Process partial results
pass
except asyncio.TimeoutError:
print(f"Streaming timed out after {timeout} seconds")
import asyncio
import os
from chaingpt.client import ChainGPTClient
from chaingpt.models.auditor import SmartContractAuditRequestModel
from chaingpt.exceptions import ChainGPTError
async def basic_audit_example():
API_KEY = os.getenv("CHAINGPT_API_KEY")
contract_code = """
pragma solidity ^0.8.0;
contract SimpleBank {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
}
"""
async with ChainGPTClient(api_key=API_KEY) as client:
try:
request = SmartContractAuditRequestModel(
question=f"Please audit this contract for security vulnerabilities:\n\n```solidity\n{contract_code}\n```"
)
response = await client.auditor.audit_contract(request)
print("=== AUDIT REPORT ===")
print(response.data.bot)
except ChainGPTError as e:
print(f"Audit failed: {e}")
if __name__ == "__main__":
asyncio.run(basic_audit_example())
import asyncio
import uuid
from chaingpt.client import ChainGPTClient
from chaingpt.models.auditor import SmartContractAuditRequestModel
from chaingpt.types import ChatHistoryMode
async def session_audit_example():
API_KEY = os.getenv("CHAINGPT_API_KEY")
session_id = f"audit-{uuid.uuid4()}"
contracts = {
"Token": "contract Token { ... }",
"Vault": "contract Vault { ... }",
"Factory": "contract Factory { ... }"
}
async with ChainGPTClient(api_key=API_KEY) as client:
# Audit each contract in the same session
for name, code in contracts.items():
print(f"\n=== Auditing {name} ===")
request = SmartContractAuditRequestModel(
question=f"Audit the {name} contract:\n```solidity\n{code}\n```",
chatHistory=ChatHistoryMode.ON,
sdkUniqueId=session_id
)
# Stream the response
async for chunk in client.auditor.stream_audit(request):
print(chunk.decode('utf-8'), end='', flush=True)
print("\n")
# Ask follow-up question about all contracts
followup = SmartContractAuditRequestModel(
question="Are there any security issues when these contracts interact with each other?",
chatHistory=ChatHistoryMode.ON,
sdkUniqueId=session_id
)
response = await client.auditor.audit_contract(followup)
print("\n=== INTERACTION ANALYSIS ===")
print(response.data.bot)
# Get session history
history = await client.auditor.get_audit_history(
sdk_unique_id=session_id,
limit=10
)
print(f"\n=== SESSION SUMMARY ===")
print(f"Total interactions: {history.data.count}")
for entry in history.data.rows:
print(f"- {entry.createdAt}: {entry.question[:50]}...")
if __name__ == "__main__":
asyncio.run(session_audit_example())
import asyncio
import logging
from typing import Optional, Dict, Any
from dataclasses import dataclass
from chaingpt.client import ChainGPTClient
from chaingpt.models.auditor import SmartContractAuditRequestModel
from chaingpt.types import ChatHistoryMode
from chaingpt.exceptions import *
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@dataclass
class AuditResult:
success: bool
report: Optional[str] = None
error: Optional[str] = None
session_id: Optional[str] = None
class SmartContractAuditor:
def __init__(self, api_key: str):
self.api_key = api_key
self.client: Optional[ChainGPTClient] = None
async def __aenter__(self):
self.client = ChainGPTClient(api_key=self.api_key)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
if self.client:
await self.client.close()
async def audit_contract(
self,
contract_code: str,
focus_areas: Optional[list] = None,
use_session: bool = False,
session_id: Optional[str] = None
) -> AuditResult:
"""
Audit a smart contract with comprehensive error handling
"""
if not self.client:
return AuditResult(False, error="Client not initialized")
try:
# Prepare audit question
question = self._prepare_question(contract_code, focus_areas)
# Configure request
chat_mode = ChatHistoryMode.ON if use_session else ChatHistoryMode.OFF
request = SmartContractAuditRequestModel(
question=question,
chatHistory=chat_mode,
sdkUniqueId=session_id if use_session else None
)
# Execute audit
response = await self.client.auditor.audit_contract(request)
if response.status:
logger.info("Audit completed successfully")
return AuditResult(
success=True,
report=response.data.bot,
session_id=session_id
)
else:
logger.warning(f"Audit completed with warnings: {response.message}")
return AuditResult(
success=False,
error=response.message
)
except AuthenticationError:
error_msg = "Authentication failed - check API key"
logger.error(error_msg)
return AuditResult(False, error=error_msg)
except ValidationError as e:
error_msg = f"Invalid request: {e.message}"
logger.error(error_msg)
return AuditResult(False, error=error_msg)
except RateLimitError as e:
error_msg = f"Rate limit exceeded. Retry after {e.retry_after}s"
logger.error(error_msg)
return AuditResult(False, error=error_msg)
except Exception as e:
error_msg = f"Unexpected error: {str(e)}"
logger.error(error_msg)
return AuditResult(False, error=error_msg)
def _prepare_question(self, contract_code: str, focus_areas: Optional[list]) -> str:
"""Prepare a comprehensive audit question"""
question = f"""
Please perform a comprehensive security audit on this Solidity contract:
```solidity
{contract_code}
Please analyze for:
- Security vulnerabilities (reentrancy, overflow, access control)
- Gas optimization opportunities
- Code quality and best practices
- Compliance with latest Solidity standards
"""
if focus_areas:
question += f"\nPay special attention to: {', '.join(focus_areas)}"
return question
async def get_session_summary(self, session_id: str) -> Dict[str, Any]:
"""Get summary of audit session"""
if not self.client:
return {"error": "Client not initialized"}
try:
history = await self.client.auditor.get_audit_history(
sdk_unique_id=session_id,
limit=50
)
return {
"session_id": session_id,
"total_audits": history.data.count,
"entries": [
{
"timestamp": entry.createdAt,
"question_preview": entry.question[:100] + "...",
"report_preview": entry.answer[:200] + "..."
}
for entry in history.data.rows
]
}
except Exception as e:
return {"error": str(e)}
# Usage example
async def main():
API_KEY = os.getenv("CHAINGPT_API_KEY")
contract = """
pragma solidity ^0.8.0;
contract MyContract {
// Your contract code here
}
"""
async with SmartContractAuditor(API_KEY) as auditor:
result = await auditor.audit_contract(
contract_code=contract,
focus_areas=["reentrancy", "access control"],
use_session=True,
session_id="production-audit-001"
)
if result.success:
print("Audit Report:")
print(result.report)
else:
print(f"Audit failed: {result.error}")
if __name__ == "__main__":
asyncio.run(main())