2026-08-03
Curve liquidity lockers and their auto-compounding wrappers are a good example of why "just parse the events" doesn't scale past the handful of protocols every tax tool already supports. We added two of them - Stake DAO's sdCRV gauge and Concentrator's (AladdinDAO) aCRV vault - and they turned out to need opposite fixes.
Staking and unstaking sdCRV in Stake DAO's gauge is unremarkable: Deposit
and Withdraw events, decoded the same way as any other Curve-style gauge.
Claiming rewards is where it gets interesting. We pulled a real
claim_rewards() transaction from mainnet and checked its full receipt: the
gauge contract itself emits zero logs. Not a missing field, not an
event we hadn't mapped yet - the contract doesn't fire anything at all when
a reward claim happens. The only on-chain signal is four plain ERC20
transfers (CRV, SDT, 3Crv, crvUSD) sent directly from the gauge to the
claimer.
That meant the normal decode path - match a log's address to a known protocol contract, then read its event args - had nothing to anchor on. We added a second mechanism: match on the transaction's target contract instead of a log's address, then reconstruct the claim from the plain transfers that land in the same receipt. It only attributes a claim correctly when the wallet that paid gas is also the one receiving the tokens - a direct claim from your own wallet. A claim routed through a keeper bot or an auto-compounding strategy (which we also found in the wild while verifying this) won't show up, by design: we'd rather return nothing than guess wrong and hand back a mislabeled line.
Concentrator's aCRV vault is a standard ERC-4626 auto-compounder over
cvxCRV, so Deposit and Withdraw decode cleanly with no special handling.
The vault also emits a Harvest event every time anyone calls the
auto-compound function - which can happen inside your own deposit or
withdraw transaction as a side effect, or in a transaction you have nothing
to do with, triggered by a keeper bot compounding on behalf of everyone in
the vault. It's not a claim by whoever sent the transaction, and it's not
something that belongs in your transaction history at all.
We could have let it fall through to an "unclassified" line, but that would tell you to go look something up that isn't actually yours to look up. So that event is explicitly suppressed at the config level: recognized, and deliberately produces no output line, rather than a misleading one.
Both cases boil down to the same principle: a missing label is an inconvenience, a wrong label is a bug in your tax return. Where the on-chain data doesn't cleanly support attributing an event to a specific user, we leave it out rather than guess. As always, what comes back is a classification - "this is a Stake DAO reward claim" - never a cost basis or a tax position.