A CLI to investigate Ethereum wallets: transfer history, top tokens, and activity patterns in one command.
I started this project while learning on-chain forensics. Etherscan is great for inspecting one transaction at a time, but it doesn't answer the questions I actually care about: across a window of time, what did this wallet do? How much volume in each token? What patterns are visible? I wanted a tool that runs in seconds, in a terminal, and gives me a summary I can actually read.
wallet-activity-reporter takes an Ethereum address and a block range, fetches every ERC-20 Transfer event where that address is either the sender or the receiver, decodes amounts with the correct decimals, and presents the activity chronologically alongside a top-tokens summary. Internally it paginates eth_getLogs calls to fit within free-tier RPC limits, and caches token metadata so repeat tokens don't trigger redundant RPC reads.
It also shows what most wallet trackers don't. Tools like Zerion or DeBank give you a snapshot of a wallet's current holdings. This one shows you the process - every transfer in a defined window, including exotic tokens you've never heard of, with exact amounts and direction. The built-in summary surfaces the top sent and received tokens by transfer count, total volumes per token, and a count of unique tokens involved. You pick the time window. The tool does the rest.
- Bidirectional scanning - fetches both incoming and outgoing transfers in parallel, merged into a single chronological view.
- Pagination built-in - automatically splits large block ranges into chunks that fit free-tier RPC limits (10 blocks per
eth_getLogscall on Alchemy free). - Token-aware output - resolves symbols and decimals on the fly via
readContract, converts rawbigintamounts to human-readable values. - Smart caching - token metadata is cached per address, so repeat tokens (like USDT appearing 50 times) trigger only one RPC roundtrip.
- Built-in summary - top sent and received tokens, total event counts, unique token count, and approximate time range.
- Etherscan links - every transaction includes a direct Etherscan URL for quick verification.
- Modular architecture - logic split across fetcher, tokens, formatters, and aggregator modules for clarity and reusability.
git clone https://github.com/Frodrinos/wallet-activity-reporter.git
cd wallet-activity-reporter
npm installCopy the example environment file and add your RPC URL:
cp .env.example .envEdit .env:
RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY
Scan an address with default range (100 blocks):
node main.js 0x28C6c06298d514Db089934071355E5743bf21d60Or specify a custom block range:
node main.js 0x28C6c06298d514Db089934071355E5743bf21d60 500node main.js 0x[VICTIM_ADDRESS] 500Address poisoning attacks send many tiny transfers (often $0.00 or fractional cents) from spoofed addresses that look visually similar to the victim's real counterparties. The goal: trick the victim into copy-pasting a wrong address from their transaction history.
The summary section makes this pattern obvious - look for dozens of incoming transfers with negligible amounts in the top received tokens. A clean wallet shows a handful of meaningful transfers. A poisoned wallet shows a flood of spam.
node main.js 0x28C6c06298d514Db089934071355E5743bf21d60 50This is Binance's hot wallet, scanned across 50 blocks (~10 minutes). A typical centralized exchange shows:
- Heavy USDT inflows from user deposits.
- Smaller, batched outflows to withdrawal addresses.
- 49+ unique tokens active simultaneously.
- Incoming count significantly higher than outgoing - confirming the deposit-heavy direction.
Useful for monitoring exchange health, spotting unusual volume changes, or comparing flows across different exchanges.
Run the tool on multiple suspected wallets and compare their outputs:
node main.js 0xWALLET_A 100
node main.js 0xWALLET_B 100
node main.js 0xWALLET_C 100Sybil farms - multiple wallets controlled by one operator - leave distinctive fingerprints. Look for matching activity across wallets:
- Same tokens transferred in same amounts during overlapping block ranges.
- Identical transfer counts within a short window.
- Same counterparty addresses receiving funds.
If three "different" wallets show 12 USDC transfers of identical amounts to the same address within the same 100 blocks - you've likely found a coordinated cluster. This is the foundation of sybil detection work for airdrops and grants programs.
wallet-activity-reporter/
├── main.js # CLI entry point - argv parsing, orchestration, output
├── src/
│ ├── fetcher.js # fetchAllLogs - paginated getLogs with progress
│ ├── tokens.js # getTokenInfo with in-memory cache
│ ├── formatters.js # formatAmount, formatLargeNumber, shortHash
│ └── aggregator.js # aggregateByToken, printTopTokens
├── .env.example # Template for environment variables
├── package.json
└── README.md
The architecture follows a clear separation of concerns: fetcher handles RPC pagination, tokens handles ERC-20 metadata with caching, formatters are pure utility functions, and aggregator builds the summary. The main file is intentionally thin - it parses CLI arguments, orchestrates module calls, and renders output. Each module takes the client instance as a parameter (dependency injection) rather than reaching for a global, making the code easier to test and reuse.
The current version handles single-address analysis well, but there's room to grow:
- Multi-address comparison mode - pass multiple addresses in one command, automatically detect overlapping transfer patterns (foundation for built-in sybil detection).
- Native ETH transfers - currently only ERC-20 events are decoded; native transfers via
eth_getBlockByNumberwould complete the picture. - ERC-721 / NFT support - Transfer event signature is identical to ERC-20, but indexed parameters differ; needs separate handling.
- CSV / JSON export - for piping output into spreadsheets or further analysis pipelines.
- Block-to-timestamp resolution - show real dates instead of approximate "~10 minutes" estimates.
- Pattern detection helpers - automated flags for common forensics signals (mass outflows, address poisoning floods, matching cluster activity).
- Dune / Flipside integration - for larger datasets that exceed RPC practical limits.
If any of these would be useful for your work, open an issue or contribute a PR.
- viem - Ethereum library for RPC calls, ABI parsing, and unit conversions.
- Node.js - runtime, using native ES modules and top-level await.
- dotenv - environment variable management.
MIT
