Build1 distinct publisher3 min readPublished
Queue deduplication can only match ids the producer already computed, and a chain re-presents the same transfer on every overlapping poll, so the fix is an identity on the payment plus state that proves it.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
A broker removes duplicate deliveries of a message you already decided to send, and on a chain the decision to send is the part that repeats [2]. Everything else is bookkeeping about which identity you hand it.
Three identities are on the table. A broker message id is attempt-scoped, so two polls that see the same transfer mint two ids, and dedup then covers retries of a single publish and nothing else [9]. A block-scoped identity, block hash plus index or a poll cursor, is location-scoped: it survives ordinary repetition and changes at the exact moment the transfer is mined into a different block, which the post sums up as location-based keys failing exactly when the chain gets interesting [10]. The third names the payment, and the post's uncomfortable observation is that if you can compute it you have already solved deduplication, at which point the broker feature is doing nothing for you [5].
Then the units. Broker deduplication happens inside a window expressed in minutes, while finality is expressed in depth, and depth per asset [12]. chain-watch's ConfirmationPolicy takes `default=6` with `per_asset` overrides of 12 for ETH and USDT, so `depth_for("BTC")` returns 6 and `depth_for("USDT")` returns 12 [13]. Six blocks is an hour on one chain and a couple of minutes on another, and a resync replays a year of history in the time it takes to read it [14]. Take the slow chain: an hour across six confirmations averages ten minutes a block, so the same depth-12 setting there would be roughly two hours of window [1]. A minute-based setting has to cover the worst case, and the worst case is a replay from height zero.
Adoption has ceremony. The watcher's state is the guarantee, so it has to be persisted and rehydrated, which the post does by loading a JSON snapshot through `WatcherState.from_dict` and passing it into the constructor [18]. A watcher that boots with empty state re-reports everything it can still see. Unbounded growth is an odd thing to write into your own README, and writing it there is the right call.
The argument arrives from the maintainer of the library it recommends [7], so check the mechanism rather than the recommendation: read your poll loop and see whether the range it reads can include a block it has read before. The part that may not transfer is the key shape, because a `(tx_id, output_index)` pair presumes your source hands you a stable output index for the payment you care about. The policy example configures ETH and USDT next to BTC [13], so the intent reaches account-based assets, and whether that index holds there is a question for your node's API, not for your queue.
Ranked by verification strength, evidence, and original report placement.
A service that credits user balances from on-chain deposits has to tell its consumer about each deposit exactly once.
A broker deduplicates the delivery of a message you already decided to send; nothing in it deduplicates the decision to send, and on a chain the decision is the part that repeats.
A deposit watcher polls, and every poll re-reads a range of blocks that overlaps the previous one, because that overlap is the only way to notice that a block already read is gone; the same transfer therefore comes back poll after poll by design.
With a process restart, a node resync, or an operator replaying from height zero after a bad deploy, the same payment is presented to the code an unbounded number of times over an unbounded stretch of wall-clock time.
Broker deduplication only helps if you hand it the same dedup id each time: if you can compute a stable id you have already solved deduplication and the broker is doing nothing for you, and if you cannot, the broker has nothing to work with.
In chain-watch, a small library the post's author maintains, deposit identity is DepositKey: the (tx_id, output_index) pair naming the transaction output the money landed on, carried on every deposit as deposit.key.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · September 3, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
The bot returned 4.33%. Doing nothing returned 127.77%. The useful part is why.1 distinct publisher
invest
Moscow Exchange to list BTC and ETH perpetuals in September as Russia's digital currency law lands1 distinct publisher
invest
Sberbank quotes 0.3% to move Russian trade payments onto crypto rails1 distinct publisher
build
Force the tool call, then hand Lightsail a long-lived key1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Authoritative on its own code, unchecked on everything else
Two very different kinds of claim sit side by side here. The library specifics — the (tx_id, output_index) key, depth_for("BTC") returning 6 against a depth-12 override, WatcherState.from_dict rehydrating a snapshot — come from the person who wrote them and can be verified in an afternoon against the repository the post links. The load the argument actually rests on is the assertion that broker deduplication happens inside minute-scale windows, and for that dev.to's post names no broker, no setting and no documentation. The reasoning is coherent; the premise is uncorroborated.
No usage visible at all
Not one install count, dependent project, star figure, release note or named production deployment appears. The closest thing to a usage signal is the author's own description of years spent building custodial wallets and onramps, which is a biography rather than evidence that chain-watch itself credits anyone's deposits today.
The piece undersells itself
The most quotable line in the post is a confession: settled only grows, the snapshot grows with the number of deposits ever seen, and that is the price of the guarantee. No throughput figures, no adopter names, no claim to have invented anything — the library link is almost an afterthought to the modelling argument. A promotional post about your own project does not usually volunteer its unbounded-state problem in the middle.
Maintainer arguing for his own library
The conclusion of the argument is 'use the type I wrote', the venue is self-published with nobody between draft and reader, and the credential offered up front is the author's own account of his career. That is not the same as puffery — the post is specific and admits its costs — but the framing and the interest behind the framing cannot be pulled apart, and no second voice in this reporting does the pulling.
Believable, single-voiced, easy to falsify if wrong
We would stand behind the identity argument and the described API; we would not yet stand behind the sweeping claim about brokers, or any implication that this code has been proved against a live reorg. One author, one venue, zero usage signals — but also unusually falsifiable material, since the repository is public and the numbers in the snippets are checkable line by line.