Postern
The measurement measured

What is standing open on Robinhood Chain

2,702 ERC-20 approvals, read from 26 windows of 27 blocks spread across the chain's whole life, then followed to block 56,794,300. 1,916 calls, 380 seconds, no vendor, no key and no proxy anywhere in it.

19.7%
of new approvals ask for no limit at all
533 of 2,702; 67.8% name an exact amount, 12.5% are revocations
37.1%
are still standing at the present block
334 of 900 followed, out of a population of 1,596
79
have a balance behind them
23.7% of what is standing — the rest is a right over an empty wallet
79
proved spendable, by moving the money in simulation
100% of those with a balance; 0 refused
Two counts and one sample

These are different kinds of claim

A count

How many approvals a window contains, how many are unlimited, how many are revocations. Complete for that window: reading logs is cheap, and nothing is left out.

A sample

Whether a given approval is still standing costs two calls and proving it costs three more, so 900 of 1,596 distinct triples were followed. The sample is deterministic, so a second scan covers the same ones and the two can be compared.

An execution

The proof is not a count or a sample of anything. It is 79 separate transactions, each run on the real EVM at the present block, each returning success. There is no inference in it.

The proof

Not a flag. The money moves.

For every allowance with a balance behind it, the spender's own transferFrom is executed from the spender's own address, for the exposed amount, through eth_call. An eth_call is a real EVM with no persistence: the transfer happens, the state is discarded, and nothing was signed, written or moved.

And it is controlled, because a simulator that says yes to everything looks exactly like one telling the truth. Two negative controls run beside every proof: the same call for one unit more than the allowance permits, and the same call against a stranger's balance. Both must fail. In this run 158 controls were executed and 158 held; the scanner exits non-zero and writes nothing if a single one passes, because one control passing wrongly voids every proof beside it.
StageCountOf whatWhat it means
Approvals sampled900distinct token + owner + spender
Still standing33437.1%allowance is non-zero right now
…of those, unlimited26679.6%capped at type(uint256).max
With a balance behind7923.7%the owner still holds some of that token
Proved spendable79100%the transfer succeeded in simulation
Refused by the token00.0%none in this run
Controls run / held158158over-amount and stranger-balance, both must fail

35 distinct spenders hold those 79 exposures, across 56 tokens. Every one of them is a contract; not one is an ordinary account.

The one trend

The unlimited approval is going out of fashion

Windows grouped by how old they are. The unit is the window rather than the approval, because one busy window would otherwise decide the answer for a whole era.

30 d+31.8%
7–30 d35.4%
1–7 d11.4%
0–1 d15.2%
Age of windowWindowsERC-20UnlimitedShare
30 d+953417031.8%
7–30 d839614035.4%
1–7 d51,22514011.4%
0–1 d45478315.2%

What this is not. It is a fact about the flow of new approvals, not about the stock of standing ones. The old unlimited approvals did not go anywhere: 266 of the 334 still standing in this sample are unlimited, which is 79.6% of everything open. Habits improving does not close a door that is already open.

What went wrong while building this

Two traps, both of which looked like data

ERC-20 and ERC-721 share a topic

Approval(address,address,uint256) is the signature of both, and the hash does not care that one indexes its third argument and the other does not. An ERC-20 approval arrives with three topics and 32 bytes of data holding the amount. An NFT approval arrives with four topics and empty data, because the tokenId is indexed.

Read them together and BigInt(log.data) throws — if you are lucky. Catch that and default to zero, and every NFT approval is filed as a revocation: the same mistake, pointing the other way, and silent. 20 of the 2,722 logs in this scan were the NFT variant, 0.73%.

A truthiness test deleted the evidence

This chain's genesis block has timestamp 0, which puts its start in 1970 and quietly shifts every age on this page. The scanner probes block timestamps to measure the chain's own clock, and it reported the trap as absent.

It was checking if (ts). Zero is falsy, so block 0 was dropped before the check that exists to report it ever ran — an instrument deleting the evidence for the thing it was built to find. It compares against null now, and reports the zero. The chain's measured rates: 42.936s then 1.218s then 0.155s, settling at 0.101s per block.

Neither was caught by a test. One threw and the other did not. The rule this site runs on is that a number which flatters the argument gets audited first — but the zero-timestamp bug argued against the site, by hiding a trap worth reporting, and it deserved the same look.

Run this on an address →