Dev to main - #681
Merged
Merged
Conversation
Normalize the persisted average interval into seconds for signing-window duration estimates and classify block- versus slot-based networks in one place. Reuse one typed Prisma chain selection across validator queries, including synthetic Aztec rows, so avgTxInterval is always present without growing the legacy service. Register focused tests for Cosmos values, millisecond chains, slot precedence, missing intervals, and invalid windows.
Replace the misleading lifetime header copy in every table namespace and add the previously missing network-nodes hint in English, Russian, and Portuguese. Render the canonical block or slot window and approximate hours in all uptime and missed-block cell tooltips. Preserve localized Aztec attestation and proposal details, use no-time variants when intervals are unavailable, and omit tooltips when the window itself is invalid.
Return a typed translation descriptor from the pure missed-window utility so block/slot and time/no-time key selection has one canonical implementation. The three server row components now translate that descriptor directly instead of repeating the same branching. Focused tests pin key selection, value formatting, and the no-window result.
Both sides appended new entries to the single-line "test" script in package.json, so git could not reconcile them automatically. dev added the Ethereum total-supply and TVS suites, this branch added the missed-window suite; the resolution keeps all three and preserves the alphabetical order of the file list. No other file conflicted: the Ethereum FDV work touched only the ethereum chain tools, .env.example and CLAUDE.md, while this branch touches the validator/node tables, locale files, chain-service and src/utils.
…p-window Fix/506 missed blocks tooltip window
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.
…from-nodes Fix Ethereum FDV and stop the Beacon fetch from failing
Introduce a locale-aware formatter that caps regular token values at two fraction digits while preserving two significant digits for small non-zero amounts. Apply it to rich-list delegations, staking results, Monero fee and pool values, and the mining calculator; keep USD output in the localized currency formatter with a two-digit maximum. Register focused boundary and locale tests without changing prices, rates, technical metrics, or exact ledger-string displays.
Honor the existing link prop for boolean node-detail statuses and give icon-only anchors the localized row label as their accessible name. Point known Voting states to the validator voting summary, and build supported Send TX destinations from the curated message-type resolver with encoded repeatable query parameters. Keep unknown or unsupported states inert and add a round-trip filter test proving the Send query remains active after parsing.
Capping USD output at two fraction digits made small amounts render as $0.00. The mining calculator shows a pool fee of one to two percent of a daily payout, so any miner earning less than roughly half a dollar a day saw the fee line collapse to zero; the same happened to dust delegations in the validator rich list. Losing the value entirely is worse than the long decimal tail the rounding was meant to remove. formatCurrencyDecimal keeps the two-digit currency format but renders anything below a cent as a bound - <$0.01, or >-$0.01 when negative, since the calculator's net profit goes negative on unprofitable rigs. This mirrors what formatDecimal already does for token amounts: never round a non-zero value down to nothing. The helper caches one Intl.NumberFormat per locale and currency. The rich list builds a formatter per table row, so it was allocating one instance per delegation on every render.
formatXmrReward cut the fractional part with slice(0, 4), so anything below 0.0001 XMR rendered as "0.0000 XMR". A typical Monero transaction fee is around 0.00003 XMR, which meant the fee column on the network transaction list, the fee on a transaction page, and the per-transaction fees inside an expanded block were all showing zero. The cut also truncated rather than rounded, reporting 0.00029 as 0.0002. Reusing formatDecimal fixes both: values at or above 0.01 keep two fraction digits, smaller ones fall back to significant digits, so fees stay readable and block rewards stay short. Block rewards now read 0.61 XMR instead of 0.6086. The average reward card on the blocks page formatted the same quantity with four digits of its own, so it moves to the shared helper too - otherwise the list and the block page disagreed about the same number.
…ckable-node-details Fix/673 674 decimals and clickable node details
Node 20's undici/webstreams implementation has a race where an AbortSignal.timeout() firing mid-response-body-read corrupts the internal TransformStream (TypeError: controller[kState].transformAlgorithm is not a function). Under load from failing LCD endpoints this piled up into an event-loop livelock that took down validatorinfo-main-frontend. Fixed upstream in Node after 24.18; moving both build stages there to see whether the crash pattern recurs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.