Last quarter, in a diligence review, the input manifest came back with ten fields and zero of them populated. No title. No source. No summary. The information-point list contained zero entries. The downstream engine, briefed to run a nine-dimension framework, ran it: fifty-four cells, every one stamped N/A, complete with tables, footnotes, a risk matrix and a disclaimer. It shipped. It looked like research.
It was a null object in a suit.
I have watched that same failure clear real capital. The expensive failure in DeFi is never the one that throws an error. It is the one that returns 200 OK with nothing inside. Blizz Finance lost roughly $8.3 million in May 2022 โ not because an oracle went dark, but because it kept answering. Chainlink's LUNA aggregator was floored at a minimum answer of $0.107 while the asset traded below a cent. The protocol asked a question. It received a number. The number was correctly formatted, correctly signed, correctly delivered. The number was dead.
Same defect class. Different invoice.

The structure underneath the question
Every yield figure you read in this market has travelled through four trust boundaries: an RPC node, an indexer, an oracle, and something that does arithmetic. Each hop can fail in three ways โ loudly, quietly, or silently. Only one of those three costs money, and it is not the loud one.
In a bear market this stops being academic. The question readers actually ask me is not "what is the APY." It is "are my assets safe." That question cannot be answered by a dashboard. It can only be answered by knowing whether the number on the dashboard is alive at the moment you read it. A protocol bleeding LPs over seven days is not hiding that information โ it is publishing it in a feed that most readers have no ritual for interrogating.
The document that crossed my desk made this point accidentally and better than any risk framework I have seen. Its integrity table โ ten checks, zero valid โ was the only genuinely valuable artifact in it. Title missing. Source missing. Summary empty. Information points: zero. Verdict: analysis feasibility = 0. Everything below that table was decoration. Everything above it was the actual work.

I built my career on that ordering. In 2017 I manually audited 50+ ERC-20 contracts for a Singapore fund while everyone else was reading whitepapers, and I rejected three high-profile ICOs on reentrancy findings that nobody had bothered to look for. The lesson was not "contracts are dangerous." The lesson was that a claim with no verifiable source is not a weak claim โ it is not a claim at all. Stated confidence is not evidence. Rendered formatting is not evidence.
The bear market enforces this with unusual violence, because there is no new inflow to mask the error. When the tide is rising, a stale read costs you upside. When the tide is falling, a stale read costs you the position.
Failure taxonomy: hard, soft, silent
Hard failure reverts. latestRoundData() throws, the transaction reverts, gas is spent, nothing is stolen. This is the market's favourite failure, because it is free.
Soft failure returns an answer that is technically true and operationally useless โ a price from 40 hours ago, a TVL snapshot from before the pool was drained, an APY computed off an emissions schedule that governance altered last week. It is survivable if the consumer checks metadata. Most do not.
Silent failure returns a plausible number with no signal that anything is wrong. The response is 200. The payload is empty or stale. Nothing in the entire stack โ the node, the indexer, the UI, the LLM summary at the end โ produces a single moment of friction. This is the one that kills.
Here is where it actually lives.
Oracle staleness vs oracle floors
latestRoundData() returns five values. Almost every consumer on-chain checks two: answer > 0 and roundId > 0. That is it. Two of five.
The two that matter are updatedAt and answeredInRound. updatedAt tells you when the aggregate was last refreshed; compare it against the feed's published heartbeat plus deviation threshold, not against block.timestamp minus some number you guessed. answeredInRound < roundId means the answer you are reading was carried over from a previous round โ a stale carry-forward rendered as a fresh value.
Then there is the floor. Chainlink aggregators historically exposed minAnswer and maxAnswer as circuit breakers against manipulation. In practice, on LUNA, that breaker held the reported price at $0.107 while the market cleared at fractions of a cent. Blizz Finance's liquidation engine consumed the floor as truth and let borrowers withdraw against collateral that had already evaporated. Venus took a comparable hit on the same feed, same week, same root cause.
A circuit breaker that cannot be distinguished from a price is not a safety feature. It is a lie with an SLA.
For L2 deployments there is a second dependency: the sequencer uptime feed. Downstream liquidation logic must not execute for a grace window after the sequencer restarts, because price movement during the outage was real and the liquidations were not. Arbitrum's early outage ran for hours. On L1 the feed updated. On L2 nothing could be enforced. Anyone whose risk engine ignored that feed was operating on a price that had already moved and a market that could not respond.
Indexer drift
Subgraphs expose _meta { block { number hash } }. Almost nobody reads it. Pull the indexed block number and compare it to the chain head before you act on any figure the indexer produced. On a 12-second chain, a 2,000-block gap is roughly six hours forty minutes of invisible staleness. Your "7-day LP outflow" panel might be a snapshot from before the outflow started. Smart money doesn't read the dashboard; it reads the metadata behind the dashboard.
The arithmetic layer
Yield math fails in a specific, repeatable way: it measures its own numerator and denominator in the same falling asset.
APR = emissions_per_block ร blocks_per_year ร token_price / TVL. If the emission token and the TVL asset are correlated โ and in a bear market they always are โ a price decline shrinks the denominator, which inflates the APR, which attracts deposits into a protocol whose economics are deteriorating. Reflexive APR is a death spiral with a good user interface.
The honest screen is APY_real = APY_gross โ impermanent loss โ funding cost โ gas โ slippage, and almost nobody computes the fourth and fifth terms because they are not on the protocol's homepage.
I learned that the expensive way in 2020. My CompoundโUniswap rebalancing script ran at 45% APY for six months on a $500,000 book. Version zero read DAI spot from a single Uniswap pool. In March 2020, DAI traded between $1.02 and $1.10 on Uniswap while Curve held peg โ a naive reader would have rotated into DAI at $1.08 and paid an 8% toll. At 45% annualised, that single click burns sixty-five days of yield. Version one added a 50bps deviation guard against a 30-minute TWAP. That guard, not the strategy, is what I actually got paid for.
The same defect shows up in ERC-4626 vaults. convertToAssets(1e18) divides by totalSupply. Empty vault: division by zero. Solidity reverts โ you are fine. A JavaScript front end returns NaN or 0, renders it as a share price, and now you have published a fabrication with a clean UI. The chain was safe. The reading layer was not.
Which is exactly what happened in that diligence review. An empty payload entered a rendering pipeline and exited as a professional document. Strip the formatting and it is indistinguishable from a floored oracle feeding a liquidation engine: an absence of data, formatted as data, consumed as data.
The assertion layer
The document's own remedy is the correct one, and it generalises directly to protocols: add non-null assertions and fail loudly. It proposed the equivalent of informationPoints.length >= 3 && summary !== "" โ a hard gate that halts the pipeline instead of passing an empty object downstream. In production systems we call that a circuit breaker. In DeFi we call it a sequencer feed, a heartbeat check, a Pyth confidence interval rejection when confidence / price exceeds tolerance. Same primitive. Same purpose: make the system loud before it makes it expensive.
The other three checks in that document deserve to be lift-and-shifted into every yield decision: require at least two verifiable quantitative datapoints (a number, a date, an amount, a ratio); require source-type labelling (official disclosure vs on-chain data vs press paraphrase vs anonymous leak), because that single field caps the confidence ceiling of everything downstream; and require interest-alignment labelling โ does the source hold the token, raise the round, or stand to profit from the direction of the claim.
When I ran the MiCA-compliant pilot for a European family office in 2025 โ permissioned pools on Polygon CDK, $10 million, twelve percent, zero incidents โ roughly half the engineering was not yield. It was lineage. Every reported figure traced to a named data provider, a timestamp, and a retrievable source. The regulator did not ask what the yield was. They asked how we knew.
Where the industry gets it backwards
We have responded to data risk by adding dashboards. More charts, more panels, more real-time widgets. That is a liability dressed as transparency, because every additional surface is another place where a null can be rendered as a number and every one of them removes a moment of friction that was doing useful work.
Retail optimises for legibility. Institutions optimise for falsifiability. Those are opposed goals. A legible number is one you can read without asking where it came from. A falsifiable number is one you can disprove โ and disproof requires metadata that makes the reading slower and less pleasant.
The reviewer who refused to produce the analysis when the input was empty delivered more value than the one who produced fifty-four cells of N/A with correct formatting. That is the correct instinct and it is genuinely rare, because every incentive in this industry rewards output volume over output integrity. Sentiment buys the dip; data fills the position. The two are not the same act.
Here is the contrarian angle nobody wants to price: in a bear market, the number that scares you is the honest one, and the number that looks stable is the one that stopped updating. A protocol whose APY holds at 19% while its TVL bleeds has not found a stable business model. It has found a cached value.
What to verify before your next LP decision
Three checks, in order, none of which require a subscription.
Read updatedAt on every feed your position depends on and compare it against the published heartbeat plus deviation threshold. If the gap exceeds one daily cycle on a liquid asset, treat the position as unmarked. Pull _meta.block.number from every indexer you rely on and diff it against the chain head. And stress-test the yield: if the emission token's price halves tomorrow, does the number survive, or does it double and keep attracting deposits into a deteriorating structure?

The next cycle will not be won by the protocols with the best dashboards. It will be won by the ones whose numbers revert when they should. The question worth asking your counterparty this week is not what their yield is โ it is what their system does when the feed returns nothing. If the answer is "it shows zero," you already know how this ends.