Koinly Found $410 That My Staking Spreadsheet Missed
I staked ETH through 2025 and logged rewards by hand, seven rows. Koinly's API sync pulled 41 reward events. Gap: $410 of income I would have omitted. Rewards count as ordinary income on receipt date. My February 3 sale added short-term gains. Extra tax: about $98.
Seven rows. That is what my hand-kept spreadsheet claimed for a full year of staking rewards on 3.1 ETH, built at my kitchen table in January 2025, and seven rows was also the number that almost went on a federal tax return, cuz I trusted my own logging more than I trusted the blockchain's.
The money involved: modest, then not slight. Thirty-four missed events at $6 to $40 each, $410 of income at stake, taxed at my marginal 24%, about $98 of exposure. The filing deadline was April 15 and my return was already drafted in TurboTax, and the draft was quietly wrong in a way no human would ever catch, because who audits a spreadsheet against itself?
The fix was boring. Koinly, a crypto tax app, synced my wallet address and my exchange accounts on March 8 and returned 41 reward events for 2025, dated, priced, dollar-ized, exported to a CSV I still have open. The spreadsheet did not survive the comparison. What I absorbed is not "use the app," though use the app. It is what receipt-date pricing does to lazy logging, and why the bug stays invisible til the one year the IRS receives a matching copy of somebody else's numbers.
thirty-four tiny restakes
Setup: 3.1 ETH staked through a pool, rewards paid weekly, auto-restaked by default. Auto-restake is compound interest with a paper trail: every restake is a receipt of income at that day's price, and every restake creates a new tax lot at a new cost basis. Weekly over a season is dozens of rows. My method was to open the rewards tab monthly and jot down whatev number looked representative. Seven rows for the year. Representative is not a tax concept. It is not even an accounting one.
the sync, march 8, 9 p.m.
Koinly's setup took eleven minutes: paste the wallet's public address, connect read-only API keys for the exchange, let it walk the chain. The import screen filled row by row while I watched, and row 12 was the first one my spreadsheet never had. By row 41 the app claimed $1,086 of total reward income for 2025 against my sheet's $676. Difference: $410. I sat with both numbers on screen for a while, the way you sit with a scale that just told you something true.
what receipt-date pricing means
The rule that broke me: staking rewards are ordinary income at fair market value on the day received, not when sold, not when withdrawn, not when convenient. Example out of my own 41 rows: a 0.004 ETH restake on January 21 was $12.60 of income, and the identical 0.004 ETH restake on August 11 was $17.20 of income. Same coins, different prices, thirty-four times across the year. My seven rows had averaged winter prices across the whole calendar, which is exactly how a careful, organized person misses $410. The system worked. That was the problem.
february 3, the sale
On February 3, 2026 I sold 1.0 ETH at $4,062 to cover a roof deductible, which turned every lot into a sale with a gain or loss attached. Held under a year, so short-term, taxed like income on top of the income already recognized at receipt. Double entry, every reward: once when it arrived, again when it left. My spreadsheet had columns for neither, and TurboTax's interview questions about cost basis had answers I did not have until Koinly produced 'em, lot by lot, from the chain itself.
the double entry, explained by damage
One reward, two taxes, that is the structure people miss. Arrival: ordinary income, valued on that day's price. Departure: a gain or loss, measured against the value you were already taxed on at arrival. The gap between those two numbers is typically pennies on a weekly restake, which is why nobody notices, and why thirty-four unnoticed gaps become a four-hundred-dollar hole. My spreadsheet knew how to count the second event for one row outta seven. The first event, the income, is the one the IRS sees first, and the only one it needed my app to confess.
the first 1099-da
This is also the first filing season with Form 1099-DA, broker-reported crypto sales, and my exchange issued one covering the February 3 sale. A matching copy goes to the IRS, which changes behavior more than any blog post ever has, cuz a mismatch between my return and a broker's form is now a matching notice waiting to be generated. Koinly drafted Form 8949 with 42 rows, the 41 rewards plus the sale, and the totals reconciled to the 1099 to the dollar. To the dollar. I checked twice, cuz a reconciliation that clean felt like a trick.
$98, not $410
Perspective, since $410 reads scary. The extra tax was about $98 at my 24% marginal rate, the failure-to-report consequences would have been slight still, and none of this was an audit, just a private correction in my own kitchen. The $98 was never the point. The point is that my system produced a number with total confidence and no accuracy, and TurboTax would have accepted it without a blink, and the confidence is the dangerous part, not the error.
the manual-entry retirement
The spreadsheet still exists, column F still says "notes," but it demoted itself to a cross-check the night the CSV imported clean. Koinly holds the watch addresses now, the 42 rows reconcile, the 8949 is filed, and the return went out March 12, five days before this writing, with a refund I had not planned on. Seven rows versus 41. That is the whole audit trail of my laziness, and it cost $98 to find out, which is the cheapest accounting degree ever issued.