auditContract
Analyze Ethereum smart contracts for security vulnerabilities and code quality issues. Enter a contract address to receive detailed audit results including potential risks and recommendations.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | ||
| chain | No | eth |
Implementation Reference
- tools/audit.js:26-52 (handler)The core asynchronous handler function for the 'auditContract' tool. It initializes Web3, analyzes the contract address using helper functions, formats the results into MCP content format, and handles errors.async ({ address, chain }) => { try { // Use the web3 instance from the environment variable or default public node console.error('Creating Web3 instance with URL:', process.env.ETH_RPC_URL); const web3 = new Web3(process.env.ETH_RPC_URL || 'https://eth.llamarpc.com'); // Perform the contract analysis console.error('Analyzing address:', address); const result = await analyzeAddress(web3, address); // Format the output for MCP response return { content: [{ type: "text", text: formatAnalysisResults(result) }] }; } catch (error) { console.error('Error in auditContract:', error); return { content: [{ type: "text", text: `Error analyzing contract: ${error.message}` }] }; } }
- tools/audit.js:22-25 (schema)Zod-based input schema validating the 'address' parameter as a 42-character Ethereum address starting with 0x, and optional 'chain' parameter defaulting to 'eth'.{ address: z.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"), chain: z.string().optional().default("eth") },
- tools/audit.js:19-55 (registration)The registerAuditTool exported function that registers the 'auditContract' tool on the MCP server instance using server.tool, providing the schema and handler.export function registerAuditTool(server) { console.error('Registering audit tool...'); server.tool("auditContract", { address: z.string().regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"), chain: z.string().optional().default("eth") }, async ({ address, chain }) => { try { // Use the web3 instance from the environment variable or default public node console.error('Creating Web3 instance with URL:', process.env.ETH_RPC_URL); const web3 = new Web3(process.env.ETH_RPC_URL || 'https://eth.llamarpc.com'); // Perform the contract analysis console.error('Analyzing address:', address); const result = await analyzeAddress(web3, address); // Format the output for MCP response return { content: [{ type: "text", text: formatAnalysisResults(result) }] }; } catch (error) { console.error('Error in auditContract:', error); return { content: [{ type: "text", text: `Error analyzing contract: ${error.message}` }] }; } } ); console.error('Audit tool registered successfully'); }
- main.js:63-63 (registration)Invocation of registerAuditTool during MCP server initialization, which executes the tool registration.registerAuditTool(server);
- tools/audit.js:63-154 (helper)Primary helper function orchestrating the contract audit: address validation, contract detection, creation info, Etherscan verification, standard detection (ERC20/721/1155), bytecode analysis, basic security heuristics, and result compilation.async function analyzeAddress(web3, address) { try { // Validate address if (!web3.utils.isAddress(address)) { throw new Error('Invalid Ethereum address format'); } // Clean and format the address const formattedAddress = web3.utils.toChecksumAddress(address); // Step 1: Check if address is a contract const isContract = await checkIfContract(web3, formattedAddress); let result = { address: formattedAddress, isContract: isContract, isVerified: false, contractName: null, contractCreator: null, creationTx: null, creationTimestamp: null, contractCode: null, sourceCode: null, abi: null, error: null }; // If not a contract, return early if (!isContract) { result.error = 'Address is not a contract'; // Check ETH balance const balance = await web3.eth.getBalance(formattedAddress); result.ethBalance = web3.utils.fromWei(balance, 'ether'); // Check transaction count const txCount = await web3.eth.getTransactionCount(formattedAddress); result.transactionCount = txCount; return result; } // Get creation info const creationInfo = await getContractCreationInfo(formattedAddress); if (creationInfo) { result.contractCreator = creationInfo.contractCreator; result.creationTx = creationInfo.txHash; result.creationTimestamp = creationInfo.timestamp; } // Step 2: Check if contract is verified on Etherscan const verificationInfo = await checkIfVerified(formattedAddress); result.isVerified = verificationInfo.isVerified; // Get bytecode regardless of verification status const bytecode = await web3.eth.getCode(formattedAddress); result.contractCode = bytecode; // Step 3: If verified, get contract code and ABI if (verificationInfo.isVerified) { result.sourceCode = verificationInfo.sourceCode; result.contractName = verificationInfo.contractName; result.abi = verificationInfo.abi; // Check contract interfaces/standards (ERC20, ERC721, etc.) result.standards = await detectContractStandards(formattedAddress, verificationInfo.abi); } else { result.error = 'Contract is not verified on Etherscan'; // Attempt to detect contract type from bytecode result.probableType = await detectContractTypeFromBytecode(bytecode); } // Add security analysis if verified (basic heuristics) if (verificationInfo.isVerified && verificationInfo.sourceCode) { result.securityAnalysis = analyzeContractSecurity(verificationInfo.sourceCode); } return result; } catch (error) { console.error('Error analyzing address:', error); return { address: address, isContract: false, isVerified: false, contractCode: null, sourceCode: null, error: error.message }; } }