Skip to content

rnts08/eth-watchtower

Repository files navigation

ETH Watchtower

CI Status Docker Build Go Report Card

Website on GitHub Direct link

ETH Watchtower is a real-time Ethereum event monitoring tool written in Go. It connects to an Ethereum RPC node via WebSocket to detect and analyze various on-chain activities, including contract deployments, token mints, liquidity creation, and DEX trades.

What is Checked?

When running against an RPC, ETH Watchtower performs deep inspection in two distinct phases:

1. Real-Time Event Monitoring

As blocks arrive, the engine analyzes transaction logs to detect:

  • Contract Deployments: Instantly captures new bytecode for analysis.
  • Token Mints: Detects Transfer events from the zero address, flagging potential infinite mint exploits or hidden premints.
  • Whale Movements: Alerts on value transfers exceeding configured thresholds.
  • Suspicious Approvals: Identifies infinite approvals or approvals to known malicious entities.
  • DEX Activity: Monitors liquidity events and swaps on Uniswap-compatible protocols.
  • Flash Loans: Detects large capital movements via flash loan callbacks.
  • Ownership Changes: Tracks ownership renouncements (often fake) or transfers.

2. Static Bytecode Analysis

Every new contract bytecode is disassembled and scanned against a library of heuristic patterns (detailed in the sections below) to identify vulnerabilities, honeypots, and malicious logic.

Features

  • Contract Discovery: Detects new smart contract deployments and identifies token standards (ERC20, ERC721, ERC1155).
  • Mint Detection: Monitors Transfer events to detect token minting activities (transfers from the zero address).
  • DEX Monitoring: Watches for liquidity pool creation and token swaps on configured DEXes (e.g., Uniswap V2).
  • Whale Watch: Flags ERC20 transfers that exceed a configured value threshold.
  • Large Approval: Flags ERC20 approvals that exceed a configured value threshold or are infinite.
  • Static Analysis: Scans bytecode for risk factors like SelfDestruct, HiddenMint, WriteToSlotZero, ReturnBomb, ERC777Reentrancy, DelegateCallToZero, CostlyLoop, ProxyDestruction, MetamorphicExploit, HardcodedSelfDestruct, UnsafeDelegateCall, UncheckedMath, UncheckedCall, UncheckedSend, and UncheckedLowLevelCall.
  • Metrics: Exposes Prometheus metrics for monitoring the watcher's health and detected events.
  • Resilience: Includes a watchdog to detect stalled RPC connections, failover support for multiple RPC endpoints, and a circuit breaker to temporarily avoid failing nodes.
  • Graceful Shutdown: Handles OS signals (SIGINT, SIGTERM) for clean termination.

Build from Source

Clone the repository and build the executable:

git clone https://github.com/rnts08/eth-watchtower.git
cd eth-watchtower
make build

Running

Start the watcher by providing the path to your configuration file:

./eth-watchtower -config config.json

Command Line Flags

  • -config: Path to the configuration JSON file (default: config.json).
  • -metrics: Address to serve Prometheus metrics (default: :2112).

Configuration Reference

The config.json file supports the following sections:

Section Field Type Default Description
rpc url string RPC endpoint URL (WebSocket or HTTPS); rpc is an array of endpoints for failover
rpc apiKey string "" Optional API key appended as query parameter
output string "eth-watchtower.jsonl" Path to the JSON Lines output file
log string "eth-watchtower.log" Path to the log file
db_path string "eth-watch.db" Path to the BoltDB persistence database
whale_threshold string Minimum transfer value to flag as whale (in wei)
concurrency int 20 Max concurrent RPC calls and analysis jobs
analyzer_pool_size int 20 Analyzer goroutine pool size (defaults to concurrency)
events transfers bool true Monitor ERC20 Transfer events (mint + whale detection)
events liquidity bool true Monitor DEX PairCreated events
events trades bool true Monitor DEX Swap events
events flashloans bool true Monitor flash loan events
events approvals bool true Monitor ERC20 Approval events
events ownership_transfers bool true Monitor OwnershipTransferred events
heuristics.max_rpc_failures int 3 Consecutive failures before circuit-breaker trips
heuristics.rpc_trip_duration duration "5m" Circuit-breaker cooldown period
heuristics.rpc_watchdog_interval duration "10s" Interval between RPC health checks
heuristics.rpc_stalled_threshold duration "60s" Time without new blocks before triggering stall alert
heuristics.max_code_cache_size int 1000 Max cached bytecode entries to avoid re-analysis
heuristics.high_frequency_threshold int 3 Deployments within window to trigger HighFrequencyDeployer
heuristics.high_frequency_score int 50 Risk score contribution for high-frequency deployment
heuristics.high_frequency_window duration "5m" Time window for high-frequency deployer tracking
heuristics.new_contract_base_score int 10 Baseline risk score for any new contract
heuristics.max_risk_score int 999 Capped maximum risk score
heuristics.flash_mint_score int 60 Risk score for flash-mint detection (mint + flash loan in same tx)
heuristics.rug_pull_window duration "24h" Time window for LP token burn tracking (rug pull)
heuristics.snipe_window_blocks int 2 Block window after liquidity creation for snipe detection
heuristics.dust_threshold int 100 Max token value (in wei) to consider a transfer as dust
heuristics.dust_recipient_soft int 100 Number of unique dust recipients before flagging DustDistribution
heuristics.heuristic_scores map Per-heuristic score overrides (keys are static analysis heuristic names)
heuristics.event_scores map Per-event score overrides (keys: MintDetected, WhaleTransfer, ApprovalDetected, FlashLoanDetected, MintToDeployer, EarlyBuyDetected, DustDistribution, MultipleMints, RugPullDetected, LiquidityCreated, TradingDetected, FlashMintDetected, InfiniteApproval, LargeApproval, OwnershipTransferred, OwnershipRenounced)
heuristics.enable []string Explicitly enable only these heuristics
heuristics.disable []string Disable specific heuristics
dexes name string DEX name (e.g., UniswapV2); section is an array of DEX configs
dexes pairCreatedTopic string Topic hash for PairCreated event
dexes swapTopic string Topic hash for Swap event
contracts address string Contract address to watch; section is an array of contract configs
contracts name string "" Human-readable label for the contract
contracts type string "" Contract type hint (e.g., ERC20, ERC721)
contracts risk_weight float 0 (deprecated — use score_multiplier)
contracts whale_threshold string "" Per-contract whale threshold override (in wei)
contracts enabled bool true Enable/disable monitoring for this contract
contracts score_multiplier float 1.0 Multiplier applied to all risk scores for this contract
contracts event_overrides map Per-event enable/disable overrides (keys are event flag names)
contracts max_risk_score int 999 Per-contract cap on maximum risk score

Docker

You can also run ETH Watchtower using Docker.

Building the Image

docker build -t eth-watchtower .

Running the Container

Mount your config.json into the container:

docker run -d \
  -v $(pwd)/config.json:/app/config.json \
  -p 2112:2112 \
  --name eth-watchtower \
  eth-watchtower

Testing

The project includes unit tests for event handling logic, token type detection, and concurrency safety.

To run the tests:

go test -v .

To run tests with the Go race detector enabled (recommended to verify thread safety):

go test -race -v .

Output

Events

Detected events are written to the configured output file (e.g., eth-watch-events.jsonl) in JSON Lines format.

Example:

{"contract":"0x...","deployer":"0x...","block":123456,"tokenType":"ERC20","mintDetected":true,"riskScore":55,"flags":["MintDetected"],"txHash":"0x..."}

Metrics

Prometheus metrics are exposed at http://localhost:2112/metrics (or the configured address).

Key metrics include:

  • eth_watcher_contracts_discovered_total: Total number of new contracts discovered.
  • eth_watcher_mints_detected_total: Total number of mints detected.
  • eth_watcher_trades_detected_total: Total number of trades detected.
  • eth_watcher_flashloans_detected_total: Total number of flashloans detected.
  • eth_watcher_rpc_latency_seconds: RPC connection latency.
  • eth_watcher_active_subscriptions: Current number of active WebSocket subscriptions.
  • eth_watcher_code_analysis_flags_total: Total number of times a specific code analysis flag has been detected.

Visualization

A Grafana dashboard configuration is provided in grafana_dashboard.json. You can import this JSON file into your Grafana instance to visualize the metrics exported by ETH Watchtower.

Tips and appreciations

ETH/ERC20: 0x968cC7D93c388614f620Ef812C5fdfe64029B92d

SOL: HB2o6q6vsW5796U5y7NxNqA7vYZW1vuQjpAHDo7FAMG8

BTC: bc1qkmzc6d49fl0edyeynezwlrfqv486nmk6p5pmta

Vulnerability Detection

  • ReadOnlyReentrancy: Detects external calls followed by state reads (read-only reentrancy risk).
  • ArbitraryStorageWrite: Detects storage writes where the slot is derived from calldata.
  • UninitializedPointer: Detects writes to storage slot 0 via uninitialized pointers.
  • UncheckedEcrecover: Detects ecrecover return value not checked against zero.
  • MissingZeroCheck: Detects missing zero-address validation in transfers.
  • SignatureReplay: Detects signature usage without nonces.
  • WriteToSlotZero: Detects writing to storage slot 0, often a proxy implementation bug or uninitialized pointer.
  • TokenDraining: Detects calls where the token address is user-controlled.
  • TxOriginPhishing: Detects tx.origin usage immediately followed by a call, a common phishing pattern.
  • BurstMint: Detects token minting or transfer logic occurring within a loop structure.
  • SelfAllocation: Detects contracts assigning state or ownership to the caller during initialization without checking existing state.
  • ArbitraryJump: Detects jumps to destinations derived from calldata.
  • FrontRunning: Detects transaction order dependency patterns (e.g., hash solution verification).
  • TransferTopicWithoutLogs: Detects the Transfer event topic in bytecode without corresponding LOG opcodes.
  • SignatureMalleability: Detects ecrecover usage without strict s-value checks (EIP-2).
  • UninitializedConstructor: Detects owner-setting logic that can be re-called.
  • GasTokenMinting: Detects patterns associated with minting gas tokens via SELFDESTRUCT refunds.
  • IntegerTruncation: Detects masking of calldata inputs that could lead to truncation.
  • UninitializedLocalVariables: Detects usage of memory variables before they are written to, a common bug with storage pointers in memory.
  • UninitializedState: Detects storage reads from slots that haven't been written to, implying uninitialized state usage.
  • PublicBurn: Detects unprotected burn functions that can be called by anyone.
  • UnprotectedUpgrade: Detects unprotected proxy upgradeTo functions.
  • AssemblyErrorProne: Detects patterns prone to errors in inline assembly, like misusing storage pointers for memory operations.
  • ReinitializableProxy: Detects proxies with an initialize function that can be called multiple times.
  • MisleadingFunctionName: Detects emission of Transfer events from functions that lack standard ERC20 selectors.
  • UnrestrictedDelegateCall: Detects delegatecall where the target address is not validated.
  • StrictBalanceEquality: Detects strict equality checks on address(this).balance.
  • DivideBeforeMultiply: Detects division before multiplication causing precision loss.
  • UncheckedReturnData: Detects low-level calls where return data is ignored.
  • HardcodedGasLimit: Detects calls with hardcoded gas amounts.
  • LockedEther: Detects contracts that can receive ETH but have no way to withdraw it.
  • ShadowingState: Detects state reads that are immediately popped (useless reads).
  • UncheckedMath: Detects arithmetic operations without overflow checks (pre-0.8.0).
  • ReentrancyNoGasLimit: Detects calls that forward all gas, increasing reentrancy risk.
  • UnprotectedEtherWithdrawal: Detects withdrawal functions that do not check state (e.g. ownership or balance).
  • UncheckedTransfer: Detects ERC20 transfer calls where the return value is ignored.
  • UncheckedTransferFrom: Detects ERC20 transferFrom calls where the return value is ignored.
  • UncheckedCall: Detects low-level calls where the return value is ignored.
  • UncheckedSend: Detects send calls (gas=2300) where the return value is ignored.
  • UncheckedLowLevelCall: Detects call with custom gas where the return value is ignored.
  • UncheckedCreate: Detects contract creation where the result address is ignored.
  • MissingReturn: Detects contracts that appear to be tokens but lack a RETURN opcode.
  • UncheckedDelegateCall: Detects delegatecall where the return value is ignored.
  • ReinitializableProxy: Detects proxies with an initialize function that can be called multiple times.
  • SelfDestruct: Detects usage of the SELFDESTRUCT opcode.
  • ReentrancyGuard: Detects usage of reentrancy guards (e.g., OpenZeppelin).
  • ERC777Reentrancy: Detects usage of the ERC1820 registry, often associated with ERC777 reentrancy vectors.

Honeypot & Scam Patterns

  • FakeToken: Detects contracts mimicking ERC20 signatures but lacking storage logic.
  • StrawManContract: Detects "cash out" patterns that are actually traps (e.g., hidden reverts, delegatecalls).
  • GasGriefingLoop: Detects loops designed to consume gas.
  • HardcodedSelfDestruct: Detects SELFDESTRUCT with a hardcoded beneficiary address.
  • HiddenFee: Detects transfers where the amount is reduced by a constant value.
  • FakeHighBalance: Detects balanceOf returning hardcoded large values.
  • FakeTransferEvent: Detects Transfer events without storage updates.
  • PhantomFunction: Detects do-nothing functions that trap funds.
  • OwnerTransferCheck: Detects transfer functions restricted to the owner.
  • TradingCooldown: Detects time-lock or cooldown mechanisms on transfers.
  • TaxToken: Detects transfer logic involving division, indicative of transfer taxes.
  • HiddenApproval: Detects contracts with an approve selector but no transfer logic.
  • PotentialHoneypot: Detects transfer functions that write to state but don't emit Transfer events.
  • SuspiciousStateChange: Detects state writes without prior reads (blind overwrites).
  • ZeroAddressTransfer: Detects Transfer events to the zero address (burns) that are not from standard burn functions.
  • FakeReturn: Detects a specific fake return pattern used to deceive callers.
  • NoTransferEvent: Detects transfer functions that do not emit events.
  • HardcodedBlacklistedAddress: Detects references to known malicious addresses (e.g., Tornado Cash router).
  • HiddenMint: Detects minting logic hidden within transfer functions.
  • ReturnBomb: Detects contracts that revert with large data or in a way to grief callers.
  • GasGriefing: Detects usage of INVALID opcode or other gas-wasting patterns.

Proxy & Metamorphic

  • NonStandardProxy: Detects proxies that do not follow EIP-1967.
  • MinimalProxy: Detects EIP-1167 minimal proxy clones.
  • ProxySelectorClash: Detects proxies with potential selector clashes between proxy and implementation.
  • SuspiciousDelegate: Detects delegatecalls to hardcoded addresses.
  • DelegateCallToSelf: Detects delegatecall to address(this), a pattern often used in metamorphic contracts.
  • Metamorphic: Detects usage of CREATE2 (base detection).
  • ProxyDestruction: Detects delegatecall combined with selfdestruct (proxy destruction risk).
  • MetamorphicExploit: Detects CREATE2 combined with selfdestruct (metamorphic exploit risk).
  • UnsafeDelegateCall: Detects delegatecall using calldata, allowing arbitrary code execution.
  • DelegateCallToZero: Detects delegatecall to the zero address.
  • DelegateCall: Detects usage of delegatecall (base detection).

Control Flow & Loops

  • DoSGasLimit: Detects loops bounded by dynamic data (DoS vector).
  • DeadCode: Detects unreachable code.
  • InfiniteLoop: Detects unconditional backward jumps.
  • CallInLoop: Detects calls executed inside loops.
  • LoopDetected: Detects any backward jump (base loop detection).
  • DelegateCallInLoop: Detects delegatecalls executed inside loops.
  • FactoryInLoop: Detects contract creation inside loops.
  • SelfDestructInLoop: Detects self-destructs inside loops.
  • GasDependentLoop: Detects loops with gas operations.
  • CostlyLoop: Detects storage writes (SSTORE) inside loops.

Context & Environment

  • TimestampDependence: Detects logic conditional on block.timestamp.
  • BadRandomness: Detects usage of blockhash for randomness.
  • WeakRandomness: Detects usage of difficulty or prevrandao.
  • BlockStuffing: Detects usage of gaslimit.
  • AntiContractCheck: Detects checks on extcodesize (often used to block smart contract interactions).
  • CodeHashCheck: Detects checks on extcodehash.
  • TxOrigin: Detects usage of tx.origin for authorization.
  • BlockTimestampManipulation: Detects usage of block.timestamp in comparison operations.
  • GasPriceCheck: Detects logic dependent on tx.gasprice.
  • CoinbaseCheck: Detects logic dependent on block.coinbase.
  • BlockNumberCheck: Detects logic dependent on block.number.
  • ChainIDCheck: Detects logic dependent on chainid.
  • CheckOwnBalance: Detects logic checking address(this).balance.
  • GasUsage: Detects usage of the GAS opcode.

Access Control

  • PrivilegedSelfDestruct: Detects self-destructs protected by access control.
  • UnprotectedSelfDestruct: Detects self-destructs reachable without authorization checks.

Functionality & Standards

  • Mintable: Detects minting function selectors.
  • Burnable: Detects burning function selectors.
  • Ownable: Detects ownership management selectors.
  • Blacklist: Detects blacklist function selectors.
  • FlashLoanReceiver: Detects implementation of flash loan callback interfaces (e.g., onFlashLoan).
  • Upgradable: Detects upgradeable proxy selectors.
  • InterfaceCheck: Detects ERC165 interface checks.
  • FlashLoan: Detects flash loan function selectors.
  • Withdrawal: Detects withdrawal function selectors.
  • RenounceOwnership: Detects ownership renouncement.

Code Structure & Quality

  • Stateless: Detects contracts with no storage operations (often logic contracts or scams).
  • SuspiciousCodeSize: Detects code size checks on itself.
  • IncorrectConstructor: Detects potential constructor naming errors (Solidity <0.4.22).
  • LowLevelCall: Detects usage of low-level call.
  • ContractFactory: Detects contract creation (create).
  • CalldataSizeCheck: Detects checks on calldatasize.

Support the project

  • ETH/ERC20: 0x968cC7D93c388614f620Ef812C5fdfe64029B92d

  • SOL: HB2o6q6vsW5796U5y7NxNqA7vYZW1vuQjpAHDo7FAMG8

  • BTC: bc1qkmzc6d49fl0edyeynezwlrfqv486nmk6p5pmta

  • LTC: ltc1q0ahxru7nwgey64agffr7x89swekj7sz8stqc6x

  • XRP: rUW7Q64vR4PwDM3F27etd6ipxK8MtuxsFs

    Buy me a coffee at https://buymeacoffee.com/timhbergsta, support me via Ko-Fi at https://ko-fi.com/rnts08, or send donations to timh@tbtechvn.com via PayPal directly.

About

An Ethereum chain watchtower application

Resources

Stars

Watchers

Forks

Sponsor this project

Packages

 
 
 

Contributors