|
| 1 | +--- |
| 2 | +name: rustplorer |
| 3 | +description: Use when the user needs to set up, configure, run, or troubleshoot rustplorer — a high-performance multi-chain deposit detector for EVM, Solana, and Bitcoin. Trigger on mentions of rustplorer, monitoring blockchain deposits, tracking crypto addresses for incoming payments, multi-chain deposit detection, watching addresses across chains, or setting up a self-hosted deposit tracker. Also trigger when users ask about configuring TOML chain configs, RPC failover for blockchains, daemon/watch mode for blockchain monitoring, or the HTTP API for dynamic address management. |
| 4 | +--- |
| 5 | + |
| 6 | +# rustplorer |
| 7 | + |
| 8 | +Help users set up, configure, run, and troubleshoot [rustplorer](https://github.com/maxylev/rustplorer) — a high-performance multi-chain deposit detector that monitors EVM, Solana, and Bitcoin addresses using only public RPC endpoints. |
| 9 | + |
| 10 | +## Core concepts |
| 11 | + |
| 12 | +rustplorer works on a **push** model: instead of asking "did address X receive a deposit?" for each address, it downloads blocks and asks "does this block contain any of my tracked addresses?" All filtering happens locally in memory using a `HashSet` with O(1) lookup — this is how it scales to 1M+ addresses. |
| 13 | + |
| 14 | +It scans three chain families: |
| 15 | +- **EVM** (Ethereum, Base, Polygon, BSC, Arbitrum, etc.) — ERC-20/ERC-721 via `eth_getLogs`, native tokens via `eth_getBlockByNumber` |
| 16 | +- **Solana** — Native SOL and SPL tokens via `getBlock` |
| 17 | +- **Bitcoin** — Native BTC via `getblockhash` + `getblock` (verbosity 3, requires Bitcoin Core v24.0.0+) |
| 18 | + |
| 19 | +Chains are identified by [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md) IDs: |
| 20 | +- EVM: `eip155:<chain_id>` (e.g., `eip155:1` for Ethereum, `eip155:8453` for Base) |
| 21 | +- Solana: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (mainnet genesis hash) |
| 22 | +- Bitcoin: `bip122:000000000019d6689c085ae165831e93` (mainnet genesis hash) |
| 23 | + |
| 24 | +## Installation |
| 25 | + |
| 26 | +rustplorer can be installed three ways. Recommend based on the user's setup: |
| 27 | + |
| 28 | +**Docker (simplest)** — pre-built image at `ghcr.io/maxylev/rustplorer:latest`: |
| 29 | +```bash |
| 30 | +docker pull ghcr.io/maxylev/rustplorer:latest |
| 31 | +``` |
| 32 | + |
| 33 | +**Cargo (if Rust is installed)**: |
| 34 | +```bash |
| 35 | +cargo install rustplorer |
| 36 | +``` |
| 37 | + |
| 38 | +**From source**: |
| 39 | +```bash |
| 40 | +git clone https://github.com/maxylev/rustplorer.git |
| 41 | +cd rustplorer |
| 42 | +cargo install --path . |
| 43 | +``` |
| 44 | + |
| 45 | +## Configuration |
| 46 | + |
| 47 | +rustplorer uses a TOML config file (`Config.toml` by default, override with `-c`). |
| 48 | + |
| 49 | +### Chain configuration (`[[chains]]`) |
| 50 | + |
| 51 | +Each chain entry has: |
| 52 | +- `caip2` (required) — CAIP-2 chain ID |
| 53 | +- `rpc` (required) — Array of RPC URLs; order matters for failover |
| 54 | +- `start_block` (optional) — First block to scan; auto-detected from node if omitted |
| 55 | +- `end_block` (optional) — Last block to scan; auto-detected from node if omitted |
| 56 | + |
| 57 | +**Block range auto-detection behavior:** |
| 58 | + |
| 59 | +| `start_block` | `end_block` | Behavior | |
| 60 | +|---|---|---| |
| 61 | +| set | set | Scan `start_block` → `end_block` | |
| 62 | +| set | omitted | Scan `start_block` → node tip | |
| 63 | +| omitted | set | Scan `(end_block - lookback)` → `end_block` | |
| 64 | +| omitted | omitted | Scan `(node tip - lookback)` → `node tip` | |
| 65 | + |
| 66 | +Default lookback values: |
| 67 | +- EVM: 1,000 blocks (~20 min on Ethereum, ~3 min on Polygon) |
| 68 | +- Solana: 500 slots (~3-4 min) |
| 69 | +- Bitcoin: 6 blocks (~1 hour) |
| 70 | + |
| 71 | +**Important**: Always include at least 2 RPC endpoints per chain for failover. If an endpoint returns a 429 (rate limit), 5xx, or JSON-RPC error, rustplorer automatically tries the next one. |
| 72 | + |
| 73 | +### Asset configuration (`[assets.NAME]`) |
| 74 | + |
| 75 | +Each asset entry has: |
| 76 | +- `network` (required) — Must match a chain's `caip2` |
| 77 | +- `contract` (required) — Token contract address, or `"native"` for the gas token |
| 78 | +- `decimals` (required) — Token decimal places (ETH=18, MATIC=18, SOL=9, BTC=8, USDC=6) |
| 79 | + |
| 80 | +The asset name (e.g., `USDC_ETH`) is used in the `token` field of deposit output. |
| 81 | + |
| 82 | +### Address file |
| 83 | + |
| 84 | +One address per line. Supports mixed EVM, Solana, and Bitcoin in the same file: |
| 85 | +``` |
| 86 | +0x71C7656EC7ab88b098defB751B7401B5f6d8976F |
| 87 | +0x8Ba1f109551bD432803012645Ac136ddd64DBA72 |
| 88 | +AMYmXa54xZuS7rjeSX7E4YwNVKpNbhFHK9gP7jLCN3A |
| 89 | +bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq |
| 90 | +``` |
| 91 | + |
| 92 | +EVM addresses are case-insensitive (stored lowercase). Solana and Bitcoin addresses are stored as-is. |
| 93 | + |
| 94 | +## Running |
| 95 | + |
| 96 | +### Single scan |
| 97 | + |
| 98 | +```bash |
| 99 | +rustplorer --addresses addresses.txt # JSON to stdout |
| 100 | +rustplorer -a addresses.txt -o deposits.json # Save to file |
| 101 | +rustplorer -a addresses.txt --format csv -o out.csv # CSV output |
| 102 | +rustplorer -a addresses.txt --verbose -o results.json # With progress output |
| 103 | +``` |
| 104 | + |
| 105 | +### CLI overrides |
| 106 | + |
| 107 | +Override config behavior from the command line: |
| 108 | +```bash |
| 109 | +# Scan only one network |
| 110 | +rustplorer -a addresses.txt --network eip155:1 |
| 111 | + |
| 112 | +# Override block range for that network |
| 113 | +rustplorer -a addresses.txt --network eip155:137 --start-block 55000000 --end-block 55001000 |
| 114 | + |
| 115 | +# Override RPC endpoints (comma-separated) |
| 116 | +rustplorer -a addresses.txt --network eip155:1 --rpc "https://rpc.ankr.com/eth,https://eth.llamarpc.com" |
| 117 | +``` |
| 118 | + |
| 119 | +### Daemon mode (`--watch`) |
| 120 | + |
| 121 | +Continuous polling that picks up where the last scan left off: |
| 122 | +```bash |
| 123 | +rustplorer -a addresses.txt --watch --interval 30 |
| 124 | +rustplorer -a addresses.txt --watch --interval 60 -o deposits.jsonl |
| 125 | +``` |
| 126 | + |
| 127 | +Daemon behavior: |
| 128 | +1. Runs a full scan cycle |
| 129 | +2. Records the highest block scanned per chain |
| 130 | +3. Sleeps for `--interval` seconds (default 60) |
| 131 | +4. **Hot-reloads** the address file from disk — add/remove/edit addresses and changes take effect without restart |
| 132 | +5. Starts next scan at `last_block + 1` (no missed blocks, no overlaps) |
| 133 | + |
| 134 | +In watch mode, JSON output uses JSON Lines format (`.jsonl`) — one object per line, appended on each cycle. CSV uses standard CSV with headers on first write. |
| 135 | + |
| 136 | +### HTTP API (`--api-port`) |
| 137 | + |
| 138 | +Start a REST API for dynamic address management: |
| 139 | +```bash |
| 140 | +rustplorer -a addresses.txt --watch --interval 30 --api-port 3000 |
| 141 | +``` |
| 142 | + |
| 143 | +Endpoints: |
| 144 | + |
| 145 | +| Method | Path | Description | |
| 146 | +|--------|------|-------------| |
| 147 | +| `GET` | `/addresses` | List all tracked addresses | |
| 148 | +| `POST` | `/addresses` | Add address(es) | |
| 149 | +| `DELETE` | `/addresses` | Remove address(es) | |
| 150 | + |
| 151 | +POST/DELETE body accepts either `{"address": "0x..."}` for a single address or `{"addresses": ["0x...", "..."]}` for batches: |
| 152 | +```bash |
| 153 | +# Add one address |
| 154 | +curl -X POST http://localhost:3000/addresses \ |
| 155 | + -H "Content-Type: application/json" \ |
| 156 | + -d '{"address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F"}' |
| 157 | + |
| 158 | +# Add multiple |
| 159 | +curl -X POST http://localhost:3000/addresses \ |
| 160 | + -H "Content-Type: application/json" \ |
| 161 | + -d '{"addresses": ["0xAAA...", "0xBBB..."]}' |
| 162 | +``` |
| 163 | + |
| 164 | +### CLI address management |
| 165 | + |
| 166 | +Edit the address file directly from the CLI (operates on the file and exits immediately): |
| 167 | +```bash |
| 168 | +rustplorer -a addresses.txt --add-address "0xNewAddress..." |
| 169 | +rustplorer -a addresses.txt --add-address "0xAAA..." --add-address "0xBBB..." |
| 170 | +rustplorer -a addresses.txt --remove-address "0xAAA..." |
| 171 | +``` |
| 172 | + |
| 173 | +## Output format |
| 174 | + |
| 175 | +### JSON output fields |
| 176 | + |
| 177 | +Each deposit result has: |
| 178 | +- `chain` — CAIP-2 chain ID where the deposit was detected |
| 179 | +- `token` — Asset name from config (e.g., `USDC_ETH`, `ETH_NATIVE`, or `Native` for unnamed) |
| 180 | +- `from_address` — Sender address |
| 181 | +- `to_address` — Receiver address (matched from the address file) |
| 182 | +- `amount_raw` — Raw hex (EVM), lamports (Solana), or satoshis (BTC) |
| 183 | +- `amount_clean` — Human-readable decimal string using the configured decimals |
| 184 | +- `block_number` — Block number (or slot for Solana) where the deposit occurred |
| 185 | + |
| 186 | +### CSV output |
| 187 | + |
| 188 | +Same fields as columns: `chain,token,from_address,to_address,amount_raw,amount_clean,block_number` |
| 189 | + |
| 190 | +## Troubleshooting |
| 191 | + |
| 192 | +### Common RPC issues |
| 193 | + |
| 194 | +**"429 Too Many Requests" / rate limiting**: Add more RPC endpoints to the `rpc` array. Free public endpoints typically allow 5-10 req/sec. rustplorer's chunking strategy helps (200-block chunks for EVM `eth_getLogs`), but native ETH scanning requires 1 RPC call per block. For production, consider dedicated nodes. |
| 195 | + |
| 196 | +**Solana "getBlock" failures**: Free Solana RPC endpoints often limit to ~100 requests per 10 seconds. If scanning more than ~100 slots, expect delays or failures. Use a paid RPC provider for production Solana scanning. |
| 197 | + |
| 198 | +**Bitcoin requires verbosity 3**: The `getblock` verbosity 3 format (which includes `prevout` data) is supported by Bitcoin Core v24.0.0+. Not all public endpoints support this. If `publicnode.com` fails, try alternative Bitcoin RPC providers. |
| 199 | + |
| 200 | +**EVM "execution reverted" or "max range exceeded"**: The `eth_getLogs` range is typically limited to 500-2,000 blocks. rustplorer chunks at 200 blocks — if you still see range errors, the RPC provider may have stricter limits. Try a different endpoint or reduce the block range. |
| 201 | + |
| 202 | +### Block range issues |
| 203 | + |
| 204 | +**"start_block > end_block, skipping"**: This message means the configured range is inverted. When using `--watch`, this can happen if the last scanned block is higher than the node's current tip (e.g., after a chain reorganization). It's harmless — the next cycle will resolve it. |
| 205 | + |
| 206 | +**No deposits found when expected**: Verify: |
| 207 | +1. The address is in the file and spelled correctly (EVM addresses are case-insensitive) |
| 208 | +2. The chain config covers the block range where the deposit occurred |
| 209 | +3. The asset config matches the token's network and contract address |
| 210 | +4. RPC endpoints are responding (run with `--verbose` to see progress) |
| 211 | + |
| 212 | +### Daemon-specific issues |
| 213 | + |
| 214 | +**Address file changes not being picked up**: The hot-reload only happens at the start of each polling cycle. If you need changes reflected immediately, use the HTTP API instead (`--api-port`). |
| 215 | + |
| 216 | +**Output file growing unboundedly**: In watch mode, results are appended. Consider log rotation or periodic cleanup for long-running daemons. |
| 217 | + |
| 218 | +### Docker-specific |
| 219 | + |
| 220 | +**File mounting**: When using Docker, config and address files must be mounted into the container. The internal default is `Config.toml` in the working directory (`/app/`), so mount and reference consistently: |
| 221 | +```bash |
| 222 | +docker run --rm \ |
| 223 | + -v $(pwd)/Config.toml:/app/Config.toml \ |
| 224 | + -v $(pwd)/addresses.txt:/app/addresses.txt \ |
| 225 | + ghcr.io/maxylev/rustplorer:latest \ |
| 226 | + -c /app/Config.toml -a /app/addresses.txt |
| 227 | +``` |
| 228 | + |
| 229 | +## Example configurations |
| 230 | + |
| 231 | +### Minimal: Ethereum only, native + USDC |
| 232 | + |
| 233 | +```toml |
| 234 | +[[chains]] |
| 235 | +caip2 = "eip155:1" |
| 236 | +rpc = ["https://eth.llamarpc.com", "https://rpc.ankr.com/eth"] |
| 237 | + |
| 238 | +[assets.ETH] |
| 239 | +network = "eip155:1" |
| 240 | +contract = "native" |
| 241 | +decimals = 18 |
| 242 | + |
| 243 | +[assets.USDC] |
| 244 | +network = "eip155:1" |
| 245 | +contract = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" |
| 246 | +decimals = 6 |
| 247 | +``` |
| 248 | + |
| 249 | +### Multi-chain with Solana and Bitcoin |
| 250 | + |
| 251 | +```toml |
| 252 | +[[chains]] |
| 253 | +caip2 = "eip155:1" |
| 254 | +rpc = ["https://eth.llamarpc.com", "https://cloudflare-eth.com"] |
| 255 | + |
| 256 | +[[chains]] |
| 257 | +caip2 = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" |
| 258 | +rpc = ["https://api.mainnet-beta.solana.com"] |
| 259 | + |
| 260 | +[[chains]] |
| 261 | +caip2 = "bip122:000000000019d6689c085ae165831e93" |
| 262 | +rpc = ["https://bitcoin-rpc.publicnode.com"] |
| 263 | + |
| 264 | +[assets.ETH] |
| 265 | +network = "eip155:1" |
| 266 | +contract = "native" |
| 267 | +decimals = 18 |
| 268 | + |
| 269 | +[assets.SOL] |
| 270 | +network = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" |
| 271 | +contract = "native" |
| 272 | +decimals = 9 |
| 273 | + |
| 274 | +[assets.BTC] |
| 275 | +network = "bip122:000000000019d6689c085ae165831e93" |
| 276 | +contract = "native" |
| 277 | +decimals = 8 |
| 278 | +``` |
| 279 | + |
| 280 | +### Production daemon with API |
| 281 | + |
| 282 | +```bash |
| 283 | +rustplorer -a addresses.txt --watch --interval 60 --api-port 3000 -o deposits.jsonl --verbose |
| 284 | +``` |
| 285 | + |
| 286 | +## Reference |
| 287 | + |
| 288 | +The full README is at `https://github.com/maxylev/rustplorer`. Key details are captured above — if the user needs something not covered here (e.g., programmatic Rust library usage, E2E testing with local chains), read the README directly. |
0 commit comments