scan_contract
Analyze smart contracts on Base mainnet to detect security vulnerabilities including reentrancy patterns, access control issues, hidden mints, proxy patterns, and dangerous opcodes.
Instructions
Analyze a smart contract on Base mainnet for security issues including reentrancy patterns, access control, hidden mints, proxy patterns, and dangerous opcodes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Contract address on Base mainnet |
Implementation Reference
- src/index.ts:588-671 (handler)The handler implementation for the "scan_contract" tool. It fetches bytecode, extracts function selectors, analyzes opcodes, identifies contract types, checks ownership, and performs various security checks based on the extracted information.
server.tool( "scan_contract", "Analyze a smart contract on Base mainnet for security issues including reentrancy patterns, access control, hidden mints, proxy patterns, and dangerous opcodes.", { address: z.string().describe("Contract address on Base mainnet"), }, async ({ address }) => { try { const code = await getContractBytecode(address); if (code === "0x" || code.length <= 2) { return ok({ address, isContract: false, message: "Address is not a contract (EOA or empty)" }); } const selectors = extractSelectors(code); const { findings, riskCounts } = analyzeSelectorRisks(selectors); const opcodes = analyzeOpcodes(code); const contractTypes = identifyContractType(selectors); const ownership = await checkOwnership(address); const issues: Array<{ severity: string; issue: string; detail: string }> = []; // Reentrancy risk: delegatecall + external calls if (opcodes.hasDelegatecall) { issues.push({ severity: "high", issue: "DELEGATECALL present", detail: "Contract uses delegatecall which can execute arbitrary external code. Potential reentrancy or logic manipulation risk." }); } // Selfdestruct if (opcodes.hasSelfDestruct) { issues.push({ severity: "critical", issue: "SELFDESTRUCT present", detail: "Contract can be destroyed. All funds and state will be lost permanently." }); } // Access control issues if (ownership.hasOwner && !ownership.isRenounced) { const dangerousWithOwner = findings.filter(f => f.risk === "critical" || f.risk === "high"); if (dangerousWithOwner.length > 0) { issues.push({ severity: "high", issue: "Active owner with dangerous permissions", detail: `Owner (${ownership.owner}) can call: ${dangerousWithOwner.map(f => f.name).join(", ")}`, }); } } // Hidden mint const hasMint = findings.some(f => f.selector === "40c10f19"); if (hasMint) { issues.push({ severity: "critical", issue: "Mint function detected", detail: "Owner can mint unlimited tokens, diluting holders." }); } // Proxy patterns const isProxy = contractTypes.includes("Proxy Contract"); if (isProxy) { issues.push({ severity: "medium", issue: "Proxy contract", detail: "Contract logic can be upgraded. The code you see today may change tomorrow." }); } // Token approval traps: check if there's approve but unusual patterns const hasApprove = findings.some(f => f.selector === "095ea7b3"); const hasTransferFrom = findings.some(f => f.selector === "23b872dd"); if (hasApprove && !hasTransferFrom) { issues.push({ severity: "medium", issue: "Approve without transferFrom", detail: "Contract has approve() but no transferFrom(). Unusual pattern — may trap approvals." }); } // Trading control const hasTradingControl = findings.some(f => f.selector === "1a8145bb"); if (hasTradingControl) { issues.push({ severity: "critical", issue: "Trading can be disabled", detail: "Owner can call setTradingActive(false) to prevent all trading." }); } return ok({ address, contractTypes, bytecodeSize: (code.length - 2) / 2, ownership: serializeBigInts(ownership) as Record<string, unknown>, opcodeAnalysis: opcodes, riskCounts, issues, knownFunctions: findings, totalSelectorsFound: selectors.length, }); } catch (err) { return fail(`scan_contract failed: ${err instanceof Error ? err.message : String(err)}`); } } );