Repository navigation
v5.4.0
Nuthatch 5.4.0 adds the deposit sweep (RFC-0064): an address-history nest that reads each block once
for its whole watched set, so its cost is per block rather than per address, and delivers incoming
transfers as one numbered feed with retractions when a reorg takes one back. Nothing about an
existing nest changes. There is no storage migration.
This minor is early. 5.x cuts features monthly, and this one was brought forward for a payment
processor that asked on 2026-10-14 for a deposit indexer over hundreds of thousands of custody
addresses (#2044). It adds and breaks nothing, which is all the policy asks of a minor.
The deposit sweep (RFC-0064)
An [address_history] nest with an [address_history.sweep] table reads every block from where it
starts, once, and matches it against the whole watched set in memory, instead of discovering each
address on its own (#2048).
- Transactions and transfers: normal transactions both ways, and ERC-20, ERC-721 (with token id)
and ERC-1155 single and batch transfers, served by the sametxlist,tokentx,tokennfttxand
token1155txas before. - Internal transfers: with
internal = true, onetrace_blockper block, so value a smart wallet
or contract sends from inside a call is caught. Internal coverage is held apart, so blocks swept
before tracing was turned on claim none. - A growing set:
POST /api/watchtakes{"addresses": [...]}, up to about 350,000 a call, all
or none, on a loopback bind. Each address is covered from the block it joined; nothing before it is
claimed. - Near the tip:
confirmations = Nsweeps to N blocks under the head instead of the finalized
head. A reorg above finality takes back what it replaced. - The deposits feed:
account/nuthatchDeposits&after=<seq>lists every incoming row as a numbered
deposit, and a reorg adds a retraction naming each one it took back, once.sweptThroughsays how
far the feed is complete. - Webhook: with
webhook = "https://..."the feed is POSTed oldest first, at least once. A batch is
marked delivered only after a 2xx, so a failed delivery is sent again and a consumer drops repeats
byseq. The feed is the record; nothing is lost while a consumer is away.
A window counts as swept only when every call for it succeeded: a failed block, log, receipt or trace
call leaves it unswept and retried, never skipped.
Checked against Etherscan on mainnet: about 8,100 rows across six addresses and three ranges
(transactions, 3,768 ERC-20, 229 ERC-721 and 15 ERC-1155 transfers) and 767 internal transactions,
every field compared, identical. Live at the tip with confirmations = 2 and 12 s polls, the webhook
delivered exactly the four deposits Etherscan lists for the blocks swept. At a million watched
addresses a window took a median 2.0 s against 1.8 s for one address, in 467 MB.
Gated on Lodestar's data
Every change is in the address-history path, which no production nest declares, so this release
changes no query path the release gate measures.
Compatibility and upgrade
Replace the binary and restart. A 5.3 store is used as it is; the sweep's tables are created on open.