Ly Gravity

Zero Passes Every Check: The Null-Value Failure Mode Inside DeFi's Risk Engines

CryptoNode • • Podcast

Last week a nine-field analysis template came back to me with every field empty. The parser did not throw. The schema validator did not object. The scoring routine downstream read nine zeros, summed them against additive weights, and returned a verdict of zero risk.

That is the entire bug, compressed into one paragraph.

In a typed system, absence has a value. The value is zero. And zero is a legal input to almost every function ever written. Nothing in the type system distinguishes "the price is zero" from "we never got a price." Nothing in the schema distinguishes "this dimension was assessed and found clean" from "this dimension was never assessed at all." Both encode to the same bit pattern, and both pass the same bounds check, because the check was written as require(x <= MAX) and never as require(x != 0).

I have spent the last several years auditing exactly this seam — the boundary between a protocol's arithmetic, which is usually sound, and its input domain, which is usually unexamined. The conclusion I keep arriving at is uncomfortable for an industry that has poured enormous resources into formal verification: the arithmetic is rarely the thing that kills you. The assumption that the input was ever real is.

What follows is a technical anatomy of that assumption. Not a market call. A failure-mode map.

In a market that has gone nowhere for a quarter, this bug is invisible. Every feed sits within a percent or two of its thirty-day mean, so a substituted last-known-good value and a live value are numerically indistinguishable, and the guard that was never written costs nothing. Chop is not the absence of risk; it is the period in which the risk accrues interest without being billed. The fire only starts when the tape moves.

Context

Solidity has no null. This is not an oversight; it is a consequence of the EVM's storage model. Every slot is initialized to zero, every mapping lookup for an unset key returns zero, every struct field in a freshly allocated memory region is zero. The language gives you no way to express "this variable has not been assigned" because the machine underneath has no such state.

The consequence is that protocols must manufacture the concept of absence. They do it with sentinels: type(uint256).max, a paired boolean (exists, initialized, isValid), a separate updatedAt timestamp, or a dedicated event log that the contract itself cannot read. Every protocol that forgets to manufacture it inherits a class of bug that no amount of arithmetic review will catch, because the code is arithmetically correct — it is correct for all inputs in the domain the author had in mind, and the author's domain excluded the case that mattered.

The most consequential instance lives in price feeds. Chainlink's aggregator interface, latestRoundData(), returns five values: (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound). Five values, and the overwhelming majority of integrations in the wild read exactly one of them.

That single read is the industry's most-copied line of code and its least-examined one.

The second instance lives in lending markets. Aave and Compound do not discover an interest rate; they compute one from a governance-set function, and that function has a shape — a kink, a slope, a base — that was chosen by a risk committee and ratified by token holders. The rate is an administrative price. Once you internalize that, the relationship between the oracle and the rate model stops looking like "market data feeding a market mechanism" and starts looking like "one administrative input feeding another administrative input." That reframing matters, because it changes what a corrupted input actually corrupts.

The third instance lives in the share accounting of every vault. totalSupply == 0 is a null. totalAssets == 0 is a null. And the ERC-4626 standard, which is otherwise the most carefully specified interface in DeFi, leaves the zero state to the implementer.

Let me take these in order, because they share a single root and the root is worth stating plainly before the details: a protocol is only as correct as the domain of its inputs, and the domain is almost never written down.

Core

The canonical correct integration of a price feed looks like this:

Market Prices

BTC Bitcoin
$83,063.3 +1.83%
ETH Ethereum
$2,450.86 +2.48%
SOL Solana
$106.62 +2.12%
BNB BNB Chain
$746.4 +2.47%
XRP XRP Ledger
$1.34 +3.45%
DOGE Dogecoin
$0.0820 +3.55%
ADA Cardano
$0.2248 +3.83%
AVAX Avalanche
$9.73 +2.62%
DOT Polkadot
$1.16 +2.81%
LINK Chainlink
$12.41 +3.66%

Fear & Greed

63

Greed

Market Sentiment

Event Calendar

{{年份}}
18
03
unlock Sui Token Unlock

Team and early investor shares released

08
04
upgrade Solana Firedancer

Independent validator client goes live on mainnet

15
04
halving Bitcoin Halving

Block reward reduced to 3.125 BTC

22
03
unlock Optimism Unlock

Circulating supply increases by about 2%

12
05
halving BCH Halving

Block reward halving event

30
04
upgrade Celestia Mainnet Upgrade

Improves data availability sampling efficiency

28
03
unlock Arbitrum Token Unlock

92 million ARB released

10
05
upgrade Ethereum Pectra Upgrade

Raises validator limit and account abstraction

Altseason Index

40

Bitcoin Season

BTC Dominance Altseason

Gas Tracker

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

Market Cap

All →
# Coin Price
1
Bitcoin BTC
$83,063.3
1
Ethereum ETH
$2,450.86
1
Solana SOL
$106.62
1
BNB Chain BNB
$746.4
1
XRP Ledger XRP
$1.34
1
Dogecoin DOGE
$0.0820
1
Cardano ADA
$0.2248
1
Avalanche AVAX
$9.73
1
Polkadot DOT
$1.16
1
Chainlink LINK
$12.41

🐋 Whale Tracker

🔵
0x2ffa...2cb7
5m ago
Stake
16,668 SOL
🟢
0xb521...3fda
6h ago
In
805.68 BTC
🔴
0x3afa...5b4e
12m ago
Out
2,468,646 USDT

💡 Smart Money

0x51e3...142d
Top DeFi Miner
-$3.3M
85%
0x4265...3d30
Early Investor
-$0.6M
77%
0x11f5...5106
Experienced On-chain Trader
+$4.4M
67%

Tools

All →