Skip to content

Fix Ethereum FDV and stop the Beacon fetch from failing - #679

Merged
alibabaedge merged 3 commits into
devfrom
fix/486-fdv-decouple-supply-from-nodes
Aug 1, 2026
Merged

Fix Ethereum FDV and stop the Beacon fetch from failing#679
alibabaedge merged 3 commits into
devfrom
fix/486-fdv-decouple-supply-from-nodes

Conversation

@m1amgn

@m1amgn m1amgn commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

task #486

Ethereum FDV was stuck at $0. getTvs aborted the whole snapshot whenever the
Beacon request returned nothing — discarding the supply it had already fetched
successfully from Etherscan/CoinGecko — so total_supply was never written and
update-fdv kept skipping on its supply <= 0 guard.

The Beacon request itself always failed: the mainnet validator endpoint returns
~1 GB in one response and res.json() cannot exceed the V8 512 MB string limit.
Three retries burned 313s every hour and always ended empty. Server-side
filtering does not help — ?status=active and ?status=active_ongoing return the
full set byte for byte. Now folded incrementally with stream-json: 15 MB heap
over the full gigabyte, 107s to a real result.

Mainnet no longer indexes validators one by one — jobs/get-nodes.ts queries the
database per node, so ~890k active validators would mean ~890k round trips.
Aggregate stake is streamed instead. Testnets keep the per-node path.

Also renames the account Tokens tab to Movements (en/ru/pt) — it lists wallet
transfers, not holdings. Route and message namespace unchanged.

m1amgn added 3 commits July 29, 2026 18:15
FDV is supply times price and has no dependency on the validator set, but
getTvs aborted the whole snapshot whenever the Beacon request came back
empty. The supply had already been fetched successfully from Etherscan and
CoinGecko at that point and was discarded along with the empty node list,
so update-chain-tvs never wrote total_supply and update-fdv kept skipping on
its supply <= 0 guard. Ethereum FDV stayed at 0 in the networks table.

The Beacon endpoint fails for mainnet because its active-validator response
exceeds the V8 string limit (Cannot create a string longer than 0x1fffffe8
characters), so this is the steady state rather than a transient blip.

Staking figures now degrade to zero when the validator set is unavailable
while supply is still published. Bonded stake exceeding total supply is
treated the same way, so a ratio above 1 can never reach the database. The
only remaining abort is a missing supply, where returning null correctly
preserves the previous snapshot.

Verified end to end against a local database: chain-tvls wrote
120682557074402769230357351 wei and update-fdv computed 231410010015.74 USD
at a price of 1917.51.
The mainnet validator endpoint returns ~1 GB in a single response, so
res.json() could never materialise it and threw "Cannot create a string
longer than 0x1fffffe8 characters" — the V8 string limit is 512 MB. Three
retries burned 313 seconds every hour and always ended with an empty list,
which is why Ethereum had no validators, no TVS and no APR.

Server-side filtering does not help: ?status=active and ?status=active_ongoing
both return the full set byte for byte (1059431887 vs 1059448434), so the node
ignores the parameter. Of the 2.32M entries returned, 1.43M are withdrawal_done
and only ~890k are active.

Fold the response incrementally with stream-json instead. Memory stays flat —
15 MB heap and 156 MB RSS over the full gigabyte — and a live run now completes
in 107 seconds where it previously spent 313 seconds failing.

Mainnet no longer indexes validators one by one. jobs/get-nodes.ts issues
database queries per node, so a successful parse would mean ~890k round trips
and rows for a single chain; aggregate stake is streamed instead. Testnets keep
the per-node path, their sets being small enough to index.

Live verification: 2322293 validators streamed, 892032 bonded, bonded stake
41452485.77 ETH against a supply of 120682557.07 ETH, TVS 34.35%.

Note for review: the bonded figure follows the pre-existing definition in this
code (active* plus withdrawal_possible, using current rather than effective
balances). It could not be cross-checked against a public source — beaconcha.in
and ultrasound.money both require an API key now — and 34.35% sits above the
commonly quoted staked share, so the definition is worth a second look.
The tab lists transfers in and out of the wallet, so "Tokens" read as a
holdings view and set the wrong expectation. Its page title said "Token
Portfolio and Assets Holdings", which described a portfolio the tab never
showed.

Renames the tab label and the page title across all three locales. The route
stays /address/<addr>/tokens and the AccountPage.Tokens message namespace is
unchanged, so existing links keep working and the diff stays confined to the
strings a user actually sees.

Verified in a local render for en, ru and pt: tab reads Movements / Движения /
Movimentos and the title reads Token Movements / Движения токенов /
Movimentos de Tokens, with no missing-message fallbacks.
@m1amgn m1amgn mentioned this pull request Aug 1, 2026
@alibabaedge
alibabaedge merged commit 8422ddc into dev Aug 1, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants