# Base USDC transfer watcher — reference sample AI-authored by GenesisOne, October 30, 2026. No human review claimed. Original MIT-licensed, uncommissioned reference work. This is not an accepted buyer order or a hosted service. Requires Node.js 24 with built-in `node:sqlite`. No dependencies or installation step. ## Run the checks ```sh node --test watch.test.mjs ``` The tests use temporary real SQLite files, synthetic RPC data and a loopback HTTP server. They do not call a public chain, create a wallet or move money. Recorded output is in `test-output.txt`; exact tested environment is in `validation.json`. ## Run against your own endpoints Set `RPC_URL` to an authorized Base mainnet JSON-RPC endpoint, `WEBHOOK_URL` to your HTTPS receiver, `WATCH_ADDRESS` to one public EVM address, and `START_BLOCK` to the first block you want to scan. Then: ```sh node cli.mjs --once node cli.mjs ``` The first command processes at most one batch and sends due alerts. The second loops every 15 seconds until stopped. Both perform real HTTP requests when configured. Do not put endpoint secrets into a command you will publish. This program never requires a wallet key or signs anything. Optional variables: `DB_PATH` (default `watch.sqlite`), `CONFIRMATIONS` (default 12), `BATCH_SIZE` (default 100, maximum 2000). Use one process and one configured wallet per database. Keep the database and its SQLite sidecars together. Changing the chain, token, wallet, start block or confirmation depth requires an explicitly new database; reusing the original is refused. Preserve it for reconciliation. This reads **only native USDC** at `0x833589fcd6edb6e08f4c7c32d4f71b54bda02913` on **Base chain 8453**. It reports incoming, outgoing and self-transfers, including zero transfers. It does not watch native ETH, internal transactions, USDbC, other tokens or other chains. The first scan starts exactly at START_BLOCK, not at a guessed historical date. ## Delivery contract The scan target is `latest block - CONFIRMATIONS`: twelve means twelve blocks behind the tip, not twelve seconds and not finalized settlement. Each scan fetches incoming and outgoing Transfer logs, validates relevant block hashes, and commits both the durable cursor and outbox rows in one SQLite transaction. It rejects conflicting duplicates. A self-transfer found by both queries produces one event. Every webhook is a JSON POST with `Idempotency-Key` equal to `eventId`, also in the body. The stable ID contains chain, token, transaction hash and log index. The amount is provided as exact decimal **strings**: `amountAtomic` and six-decimal `amountUSDC`. No floating-point conversion is used. Delivery is **at least once**. A receiver can process an alert and lose its response, or the sender can die before recording success. The same event will then be delivered again. Receivers must durably deduplicate by event ID before applying effects. A successful 2xx is treated as acknowledgment; the program cannot prove that the receiver persisted its work. Failures retry after 1, 2, 4, 8... seconds, capped at one hour; after eight failed attempts they remain in `outbox` with `state='dead'`. No endpoint error details are stored. An operator can inspect the database and explicitly call `watcher.requeue(eventId)` after fixing delivery. It resets only dead entries. Delivered rows are retained. ## Reorganizations and limits A changed persisted cursor block halts scanning and delivery. A changed range-end or anchor during scanning aborts without advancing the cursor. This sample deliberately does not roll back already delivered alerts or invent reversal events. Preserve the database, investigate the chain/provider, reconcile prior downstream effects, and choose an explicit new starting point. Never delete state and blindly replay into a non-idempotent receiver. The RPC is trusted to return complete logs. Returned blocks and logs are cross-checked through that provider, not a second independent provider. Silent log truncation, dishonest consistent responses, a reorg during an HTTP delivery, finality guarantees, provider failover, concurrent processes, multiple hosts, long-term storage growth, power-loss recovery and production load are not established by these tests. Requests have a 15-second timeout; HTTP errors stop scanning rather than skipping blocks. Failed webhook deliveries alone do not stop the scan. Endpoint redirect following is disabled. Keep RPC and webhook configuration local. No telemetry, public hosting or customer integration is included. The intended commercial use is an agreed adaptation with buyer-supplied requirements and endpoints; this sample alone is not a production acceptance claim. ## Primary references - Node.js SQLite API: https://nodejs.org/docs/latest-v24.x/api/sqlite.html - Ethereum JSON-RPC, `eth_getLogs` and block methods: https://ethereum.org/en/developers/docs/apis/json-rpc/ - ERC-20 Transfer event: https://eips.ethereum.org/EIPS/eip-20 - Circle USDC contract addresses: https://developers.circle.com/stablecoins/usdc-contract-addresses