Why this is the error that matters most
Every other number depends on it. If a transfer is misread as a sale, you get a phantom realised gain, a cost basis reset to the transfer date, and a balance that looks right while the history behind it is wrong. It is also the error that is hardest to notice, because nothing looks broken.
To be fair about the field: several established tools do detect transfers automatically. Koinly matches them on its free tier and publishes its rules, and CoinTracker matches them too. Where it gets hard is volume. In a public thread about a portfolio with more than 100,000 transactions, a crypto-tax firm described what is left to the user:
due to high volume of transactions, it wont reconcile on their own. You have to review each transaction and fix cost basis/missing transaction/wrong gains/wrong acquired date/transfers/wrong tokens/bridge tokens/defi transaction (If any) by yourself.
Another commenter in the same thread listed what to check before trusting a report at all:
check missing cost basis, duplicate transfers, spam/dust tokens, failed/expired trades, bridges, and unsupported tokens before trusting the report. Also be careful deleting transactions unless you're sure what they represent.
Missing cost basis, duplicate transfers and spam tokens are three of the four things our reconciliation engine looks for on its own. The warning about deleting transactions is also why marking something as spam here puts it in a recoverable trash rather than destroying it.
How a match is decided
Three levels, in order of confidence. Only the first is applied silently.
| Signal | What has to agree | What we do |
|---|---|---|
| Transaction hash | The withdrawal and the deposit carry the same on-chain transaction hash. | Linked automatically. This is identity, not inference. |
| Asset, amount, time | Same asset, amounts within 1%, and the deposit lands within 4 hours of the withdrawal. | Proposed as a match for you to confirm. The 1% absorbs the network fee taken in flight. |
| Bridge inference | Value within 3% in USD, within 6 hours, across two different chains, with wrapped tokens normalised to their underlying. | Proposed, and labelled as a bridge. Wider tolerances because bridges charge more and settle slower. |
Anything that clears none of these stays unmatched and visible, rather than being quietly attached to the nearest plausible candidate.
What happens when we are not sure
Uncertain candidates go to a reconciliation queue where you confirm or reject them. A decision is not a one-way door: every resolution is recorded in a ledger that can be reverted, so a wrong confirmation can be undone without rebuilding your history.
When the transfer graph changes, cost basis is propagated across it again. Linking a transfer is not just a cosmetic tidy-up: it moves the basis from the account where you bought the coin to the account where you now hold it.
We do not auto-apply a match we are unsure about, even when it would make the numbers look tidier. A guessed link that is wrong either double-counts a position or hides capital, and both are harder to find later than an unmatched row you can see.
Where this still falls short
Two known limits, stated plainly.
- If the same address is used on both sides of a swap, we can still misread the direction of the flip. This is an open limitation.
- A decentralised-exchange swap routed through more than two legs is harder to reconstruct, and some of these are synthesised rather than read directly.