Most articles about phantom gains, including ours, explain the mechanism and stop there. This one runs it on a real wallet cluster and publishes the number.
We took the most public address cluster on Ethereum — vitalik.eth plus the Etherscan-tagged VB, Vb 2 and Vb 3 addresses and one media-documented cold wallet — and computed realized gains on its native-ETH history twice. Same engine, same data, same classifications. The only difference between the two runs: whether transfers between the entity's own wallets carry their cost basis, or lose it.
Losing it is what per-wallet tools do when they don't link the wallets together. On this cluster it overstates lifetime realized gains by $44,975,739.
| realized gain (genesis → 2023-03-31) | |
|---|---|
| naive per-wallet tool (transfers lose basis) | $164,130,459 |
| transfer-aware | $119,154,719 |
| overstated "phantom" gain | $44,975,739 |
To be explicit about what this is and isn't: this is a measurement of how two ways of handling self-transfers diverge on one public dataset. It is not a claim about anyone's actual tax position, filings, or liability. We have no visibility into either. Every address here is identified by an on-chain ENS name, an Etherscan public name tag, or mainstream press coverage — there is nothing here that wasn't already public. This is not tax advice.
Why this cluster
We needed a subject that does the specific things that break naive tools, and that we could name without exposing anyone.
This cluster does all of them: multi-hop self-transfers (VB → vitalik.eth, VB → Safe → cold wallet), self-staking, WETH wraps, and large disposals years after the transferred coins were acquired. The five addresses:
| address | label | how it's attributed |
|---|---|---|
0xd8da6bf2…96045 |
vitalik.eth | ENS name, on-chain |
0xab5801a7…aec9b |
VB (legacy) | Etherscan public name tag |
0x1db3439a…a6ee6 |
Vb 2 | Etherscan public name tag |
0x220866b1…a3a9d |
Vb 3 (Safe) | Etherscan public name tag |
0xd04daa65…28fd7 |
cold wallet | received 70,000 ETH from Vb 3 after a 1-ETH test send; widely reported |
The moves that a per-wallet tool books at $0 basis on arrival are large and old:
| date | from | to | amount |
|---|---|---|---|
| 2021-05-12 | VB (legacy) | Vb 3 (Safe) | 320,000 ETH |
| 2016-08-05 | VB (legacy) | Vb 2 | 100,000 ETH |
| 2016-08-10 | Vb 2 | VB (legacy) | 79,462.66 ETH |
| 2022-11-24 | Vb 3 (Safe) | cold wallet | 40,000 ETH |
| 2022-05-16 | Vb 3 (Safe) | cold wallet | 30,000 ETH |
Coins acquired in 2015 and moved in 2016 get sold in 2021. A tool that lost the basis at the 2016 transfer prices that 2021 sale against zero.
The damage concentrates in two years
| year | naive | transfer-aware | overstatement |
|---|---|---|---|
| 2016 | $5,216,955 | $5,065,243 | $151,711 |
| 2017 | $38,034,500 | $37,728,650 | $305,849 |
| 2018 | $3,932,439 | $3,793,849 | $138,590 |
| 2019 | $1,636,279 | $1,533,193 | $103,085 |
| 2020 | $2,734,481 | $2,627,965 | $106,516 |
| 2021 | $55,404,397 | $32,238,166 | $23,166,232 |
| 2022 | $31,336,181 | $10,476,703 | $20,859,478 |
| 2023 | $25,835,884 | $25,691,607 | $144,277 |
2022 is the clearest case. The naive run reports $31.3M of realized gains. Carry the basis correctly across the entity's own transfers and the same disposals come out at $10.5M.
Look at what happens at the level of individual disposals, and the sign flips:
| date | naive gain | actual gain | phantom |
|---|---|---|---|
| 2021-12-14 | $7,565,791 | −$799,790 | $8,365,581 |
| 2021-09-26 | $4,413,005 | −$1,860,762 | $6,273,767 |
| 2021-07-01 | $2,279,354 | −$1,903,436 | $4,182,790 |
| 2022-01-09 | $2,318,839 | −$818,254 | $3,137,093 |
These are losses being reported as multi-million-dollar gains. That is the part worth sitting with: the error isn't a percentage off a large number, it's the wrong direction.
Why you can trust the arithmetic
A number this size is only worth anything if the ledger reconciles to the chain. Here is the balance tie-out at the cutoff block (16,950,600), with gas priced from each transaction's own receipt:
| wallet | ledger (ETH) | on-chain (ETH) | diff | tie-out |
|---|---|---|---|---|
| vitalik.eth | 5149.62524 | 5149.62524 | 0 | PASS |
| VB (legacy) | 59.41928 | 59.41928 | 0 | PASS |
| Vb 2 | 7.904313 | 7.904313 | 0 | PASS |
| Vb 3 (Safe) | 244001.011354 | 244001.011354 | 0 | PASS |
| cold wallet | 50001.094312 | 50001.094312 | 0 | PASS |
Five of five wallets reconcile within 0.0001 ETH. The cutoff is deliberately before Shapella withdrawals began, so the native-ETH ledger is closed under transaction lists plus proposer fees — any residual would be a data defect, not an excuse.
The method, in short: 5,334 raw rows from the key-less Blockscout public API became 6,175 canonical events. Every one of the 2,671 transaction receipts was read for exact gas (gasUsed × effectiveGasPrice). Prices are DefiLlama daily closes. Validator deposits and WETH wraps are not sales. Safe delegatecall traces are dropped, because Blockscout reports them with the parent call's value and any pipeline that keeps them double-counts every Safe execution.
Two defects we found in our own pipeline
Both were producing an "ETH from nowhere" signature, and both invalidated every figure this analysis carried before 2026-07-29. We are publishing them because a tie-out that only ever passes is a tie-out nobody is testing.
Gas came from the explorer's indexed fields. Neither gasUsed nor gasPrice as indexed is the receipt value — gasPrice is maxFeePerGas under EIP-1559. Fees are modeled as mini-disposals, so a wrong fee is a wrong realized gain as well as a broken tie-out. Fixing it moved vitalik.eth from −0.685055 ETH to exactly zero.
Proposer income was cached as zero when the fetch failed. 270 of Vb 2's 627 proposed blocks were stored with a zero priority fee and a null timestamp, because rate-limited responses were read optimistically. They are real income: 4.29 ETH recorded against 7.16 ETH on chain. Repaired, Vb 2's difference fell from −3.04 ETH to −0.18 ETH.
What remains is contract-internal ETH that block explorers don't index per address. We bisected it to the block: VB (legacy) first diverges at block 13,787,699, where the on-chain balance rises by 0.0085 ETH with no transaction and no internal transaction returned for that address. Closing it needs trace-level ingestion — and one caveat we measured while testing that: trace_filter returns frames from reverted sub-calls, and counting them naively over-credited VB by 0.067 ETH. Trace ingestion has to prune every subtree under a reverted ancestor before it's an improvement.
What this means for a normal wallet
You almost certainly don't move 320,000 ETH between your own addresses. But the mechanism doesn't care about size, and two things make it more likely to hit you now than it used to:
Since 2025, Rev. Proc. 2024-28 requires per-wallet basis tracking rather than a universal pool. Per-wallet is exactly the mode in which an unlinked self-transfer looks like an acquisition at zero.
And Form 1099-DA reporting means brokers now send the IRS their own view of your disposals. Where a broker never saw your acquisition — because it happened in a wallet, on another exchange, or years earlier — the basis field is where the gap shows up.
The check is the same at any size: for each sale in your report, find the acquisition it was matched against. If the tool can't show you one, that line is priced against zero.
This is not tax advice, and none of the above is a substitute for a qualified tax professional looking at your actual records.
If you'd rather have the breaks in your basis chain found for you, Verilot Check reads your Ethereum wallets directly on-chain and flags every transfer between your own addresses that would otherwise be booked as a sale, with a tx-hash on every line. Free and read-only — no wallet connection, no sign-up, up to 5 wallets and 500 events per scan, Ethereum mainnet today. Run my free scan.