# Solidity Entry Point Detection ## Entry Point Identification (State-Changing Only) ### Include: State-Changing Functions ```solidity function name() external { } // State-changing entry point function name() external payable { } // State-changing, receives ETH function name() public { } // State-changing entry point ``` ### Exclude: Read-Only Functions ```solidity function name() external view { } // EXCLUDE - cannot modify state function name() external pure { } // EXCLUDE - no state access function name() public view { } // EXCLUDE - cannot modify state ``` ### Visibility and Mutability Matrix | Visibility | Mutability | Include? | Notes | |------------|------------|----------|-------| | `external` | (none) | **Yes** | State-changing entry point | | `external` | `payable` | **Yes** | State-changing, receives ETH | | `external` | `view` | No | Read-only, exclude | | `external` | `pure` | No | No state access, exclude | | `public` | (none) | **Yes** | State-changing entry point | | `public` | `payable` | **Yes** | State-changing, receives ETH | | `public` | `view` | No | Read-only, exclude | | `public` | `pure` | No | No state access, exclude | | `internal` | any | No | Not externally callable | | `private` | any | No | Not externally callable | ### Special Entry Points - `receive() external payable` — Receives plain ETH transfers - `fallback() external` — Catches unmatched function calls - `constructor()` — One-time initialization (not recurring entry point) ## Access Control Patterns ### OpenZeppelin Patterns ```solidity // Ownable modifier onlyOwner() { require(msg.sender == owner); } // AccessControl modifier onlyRole(bytes32 role) { require(hasRole(role, msg.sender)); } // Common role constants bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); ``` ### Common Modifier Names → Role Classification | Modifier Pattern | Classification | |------------------|----------------| | `onlyOwner` | Admin/Owner | | `onlyAdmin` | Admin | | `onlyRole(ADMIN_ROLE)` | Admin | | `onlyRole(GOVERNANCE_ROLE)` | Governance | | `onlyGovernance` | Governance | | `onlyGuardian` | Guardian | | `onlyPauser`, `whenNotPaused` | Guardian/Pauser | | `onlyMinter` | Minter | | `onlyOperator` | Operator | | `onlyKeeper` | Keeper | | `onlyRelayer` | Relayer | | `onlyStrategy`, `onlyStrategist` | Strategist | | `onlyVault` | Contract-Only | ### Inline Access Control (Flag for Review) ```solidity require(msg.sender == someAddress, "..."); // Check who someAddress is require(authorized[msg.sender], "..."); // Dynamic authorization require(whitelist[msg.sender], "..."); // Whitelist pattern if (msg.sender != admin) revert(); // Inline admin check ``` ## Contract-Only Detection ### Callback Functions ```solidity // ERC token callbacks function onERC721Received(...) external returns (bytes4) function onERC1155Received(...) external returns (bytes4) function onERC1155BatchReceived(...) external returns (bytes4) // DeFi callbacks function uniswapV3SwapCallback(...) external function uniswapV3MintCallback(...) external function pancakeV3SwapCallback(...) external function algebraSwapCallback(...) external // Flash loan callbacks function onFlashLoan(...) external returns (bytes32) function executeOperation(...) external returns (bool) // Aave function receiveFlashLoan(...) external // Balancer ``` ### Contract-Caller Checks ```solidity require(msg.sender == address(pool), "..."); // Specific contract require(msg.sender != tx.origin, "..."); // Must be contract require(tx.origin != msg.sender); // No EOA calls ``` ## Extraction Strategy 1. Parse all `.sol` files 2. For each contract/interface/abstract: - Extract `external` and `public` functions - **Skip** functions with `view` or `pure` modifiers - Record function signature: `name(paramTypes)` - Record line number - Extract all modifiers applied 3. Classify by modifiers: - No access modifiers → Public (Unrestricted) - Known role modifier → Appropriate role category - Inline `require(msg.sender...)` → Review Required - Callback pattern → Contract-Only ## Inheritance Considerations - Check parent contracts for modifier definitions - A function may inherit access control from overridden function - Abstract contracts may define modifiers used by children - Interfaces define signatures but not access control ## Common Gotchas 1. **Initializers**: `initialize()` often has `initializer` modifier but may be unrestricted on first call 2. **Proxies**: Implementation contracts may have different access patterns than proxies 3. **Upgrades**: `upgradeTo()`, `upgradeToAndCall()` are high-privilege 4. **Multicall**: `multicall(bytes[])` allows batching—check what it can call 5. **Permit**: `permit()` functions enable gasless approvals—check EIP-2612 compliance