Every data source, every cache, every limitation — listed in plain text on this page. If a number on this site is wrong, this is where you find out why.
Verifiable is a commitment, not a claim of truth. Every number on this site is verifiable — we publish the method, expose the artifacts, and preserve the evidence. That is not the same as saying every number is right. "Verifiable" means we committed publicly to a specific value, using a stated method, with the raw material preserved, so if we are wrong you can catch us. Everything below is that audit trail — the check, not the claim.
When our own checks detect a value we now believe is wrong, we degrade the affected surface honestly — yellow badge, "data delayed" placeholder, scope note — rather than silently patch it. An auto-fixer that hides its own evidence would be the quietest liar of all.
Why this page exists. Most XRPL dashboards say "live" without telling you what that means. We commit to the opposite: every claim of "live" is backed by a measurable cadence below, and every cache is named with its TTL. If you disagree with our numbers, this page is the audit trail.
Scope note: the four-layer truth-audit (CLAIMS.yaml manifest + continuous L2/L3 alarms) covers metric-bearing pages. Form, policy, and help routes (/verify, /terms, /privacy, /security, /help/*) are self-attested — no data claims to audit.
Page last revised 2026-08-09. Versioned in git alongside the code that ships these features.
Three states: Live means a WebSocket pushes new data without a page refresh. Cached means we re-query the XRP Ledger on a fixed cadence and serve the most recent answer to all visitors during the cache window.
| Page / surface | State | Cadence / TTL | Underlying source |
|---|---|---|---|
| /api/ledger-tip | Cached | 60 sec | server_info on public XRPL node |
| Ledger heartbeat chip (every page header) |
Cached | polls every 30 sec → 20 sec server cache | /api/ledger-tip |
| /wallet/<addr> tx counter, last seen, sparkline today bin |
Live | WebSocket push (~3–5 sec per validated ledger) | Browser subscribes directly to wss://xrplcluster.com |
| /wallet/<addr> balances, holdings, network graph, AMM positions |
Cached | 5 min | account_info, account_lines, account_tx, amm_info |
| /whales large-XRP / tagged / trustset feed |
Live | WebSocket push (~3–5 sec per validated ledger) | Browser subscribes directly to wss://xrplcluster.com; initial page load is from worker → Neon |
| /tokens, /token/<currency>/<issuer> per-token swap activity |
Live | WebSocket push for new swaps; aggregates rebuild on next reload | Browser WS to wss://xrplcluster.com; rollups from worker → Neon |
| /pools constellation swap pulses + per-pool TVL |
Live | WebSocket push; TVL adjusts on each AMM LP-token delta | Browser WS to wss://xrplcluster.com; static pool index seeded from amm_info |
| /api/pools/recent_events | Live | worker writes pool swaps as they happen; API reads on each call | Worker → Neon Postgres |
| /cold-storage | Cached | 5 min | account_info on labeled cold wallets |
| /rlusd cross-chain supply, mint/burn events |
Cached | 5 min | Ethereum public JSON-RPC (1rpc.io/eth) + XRPL public node (s1.ripple.com) |
| /api/rlusd/state | Cached | 5 min | eth_call, eth_getLogs, gateway_balances, account_tx |
| /mpts MPT registry + holder counts |
Cached | hourly snapshot worker | daily ledger_data walk seeds the registry; hourly mpt_holders + ledger_entry refresh holder counts and outstanding supply |
| /mpt/<id> detail page + supply history chart |
Cached | hourly snapshot; history chart from 90-day time-series | same hourly worker; time-series written to mpt_supply_history on each successful walk |
| /mpt/issuer/<wallet> issuer roll-up + attestation badge |
Cached | hourly snapshot | aggregated from same hourly worker snapshot; domain attestation verified at index time against .well-known/xrp-ledger.toml |
| /lending amendment status + protocol explainer |
Cached | 5 min | feature RPC (amendment voting status); switches to live broker/vault data once LendingProtocol amendment activates |
Five surfaces use browser-side WebSocket push (Live) from wss://xrplcluster.com. The remaining cached surfaces are derived from RPC calls or background snapshot workers — either there's no streaming equivalent, or the data changes on a cadence where a short TTL is the honest framing.
All on-chain data is read from public XRPL nodes — peers in the consensus network. A node can't lie about ledger contents without the rest of the network rejecting it.
wss://xrplcluster.com — Community-operated full-history cluster run by the XRP Ledger Foundation. Used by the browser for all per-page real-time subscriptions (whales, tokens, pools, wallet, liveness chip).wss://s2.ripple.com — Ripple-operated full-history node. Used by the server-side worker for streaming validated transactions into Postgres. Also kept as the first browser fallback if xrplcluster.com is unreachable.s1.ripple.com:51234 — Ripple-operated general-purpose JSON-RPC node. Used by the network pulse, ledger-tip, and RLUSD-issuer endpoints.RLUSD is a stablecoin that lives on Ethereum as well as the XRP Ledger. To surface the Ethereum-side supply and treasury activity we query a public Ethereum JSON-RPC endpoint directly — no API key, no third-party gateway. The node only sees standard public reads (totalSupply, recent Transfer logs) and cannot lie about contract state without producing an inconsistent block that the rest of the Ethereum network would reject.
1rpc.io/eth — Public, key-free Ethereum JSON-RPC endpoint. Used by /api/rlusd/state to read the RLUSD ERC-20 totalSupply and recent Transfer logs at contract 0x8292…17eD.
Disclosure. Ripple's documentation explicitly states their public servers are not intended for sustained business use. Browser-side traffic has now been migrated to the community-operated cluster
wss://xrplcluster.com (run by the XRP Ledger Foundation), with wss://s2.ripple.com and wss://s1.ripple.com retained as automatic fallbacks. Our own rippled node is already in service for the forward-walker and MCP tool envelope reads (classified own-node in the source-tier table below); migrating the continuous XRPL streaming worker from wss://s2.ripple.com to the same own-node is the next step.
Worker writes to Neon Postgres (managed Postgres, US-hosted) and a redundant local SQLite snapshot. The web app prefers Postgres for fresh reads and falls back to the SQLite snapshot if the Postgres connection is unavailable. No third-party analytics API (Bithomp, XRPSCAN, xrpl.to, XPMarket, DefiLlama, CoinGecko) feeds any of our metrics — price, volume, TVL, balances are all computed directly from the ledger.
Token display names are hand-curated in
token_names.json
in the public GitHub repo, each with a verifiable source URL (exchange page, project .toml, or audit), accepted via public PR review. Account labels are layered by priority:
named_accounts.json in the repo; highest trust, manually reviewed.Domain field and the domain's .well-known/xrp-ledger.toml form a verified two-way chain (see Domain attestation below). Stored with source=\'toml\'.Every label is stored with its source so users can tell first-party from TOML-attested from reference.
Every UTC day we capture a small canonical set of headline metrics (validated ledger index, AMM pool count and total TVL, MPT count, named-accounts count), hash that capture into a Merkle leaf, extend a global append-only Merkle chain, and sign the resulting envelope with our Ed25519 private key. The signed JSON is published at /.well-known/snapshots/YYYY-MM-DD.json and the cumulative chain root at /.well-known/snapshots/chain.json. Both are static, cacheable, and independently verifiable forever.
Why this exists. Web dashboards can silently re-render history. A number that was true yesterday can quietly become a different number today, and visitors have no way to tell. Daily signed snapshots make that class of drift detectable: if the JSON you fetch today doesn't pass cryptographic verification against our published public key, something is wrong — either with the file, the chain, or the signing key. No other XRPL dashboard publishes a verifiable history of its own numbers.
Anatomy of one snapshot.
Each daily file contains: the metrics block (name → value+unit pairs), a canonical-JSON SHA-256 leaf hash, the leaf's index in the global chain, the audit path proving inclusion under that day's chain root, the previous chain root, the new chain root, and an Ed25519 signature over the canonical envelope summary. All hashing follows RFC 6962-style domain separation — 0x00 byte prefix for leaves, 0x01 for internal nodes — so leaves and intermediate hashes can never collide.
How to verify yourself. Three independent checks, all server-side-free:
_xrpld-snapshot-key.xrpldashboard.com. All four sources must agree.0x00 || canonical-JSON of the {signing_domain, schema_version, snapshot_date_utc, metrics} subset).audit_path from the leaf, hashing each pair with the 0x01 domain separator. The result must equal the published chain_root.signature_ed25519 (hex-encoded) against the canonical-JSON of the envelope summary {signing_domain, schema_version, snapshot_date_utc, leaf_hash, leaf_index, leaves_total, chain_root, previous_root}, using the public key from step 1.Our one-click verification form runs all three checks server-side and shows each pass/fail independently — the same verification you can run locally with any Ed25519 library plus a SHA-256.
Trust model. A signed snapshot proves only that the published number existed on the recorded date and was signed by the key whose public half we pin in four places. It does not prove the number was correct — that depends on the source data and our collection logic, both documented in the rest of this page. Signed snapshots make it impossible for us to quietly rewrite history without being caught, but they are not a substitute for the rest of the methodology audit; they are the audit's lower bound.
Signing key fingerprint.
7F:D4:F2:F4:D2:57:7C:BE
Schema version: 3.
Signing domain: xrpldashboard.com/signed_snapshot/v1.
Curve: Ed25519.
Browse the public snapshot index at /snapshots/.
Since 2026-08-07, each daily chain_root is additionally committed inside an XRP Ledger Payment transaction memo. The anchor account rL2yMECEyUT94pLDrAcetMNMG1H4xqpNWQ sends the payment to the ops account rwrcJL3Exd1ZUYz11Wug6wvWC448CiTXfd. The transaction is 1 drop, plus the standard XRPL fee; the memo is the payload. This puts the chain root on a canonical, third-party-replicated timeline that we cannot rewrite without minting a public contradiction.
Cadence. Weekly, manual today. The language upgrades when automation lands. Missed weeks are visible on-ledger and will be reconciled explicitly rather than backdated.
First anchor.
Transaction 01D0BB9D230955F43DB35703E2EB7F5DFA43CEB69CCBBF57FBC8F17407E50DF8,
validated in ledger 106140698 at 2026-08-07 21:49:32 UTC (result tesSUCCESS).
Memo format (v1, normative).
All payload lives inside the single MemoData field. Wallet UIs may auto-populate MemoType="Description" and MemoFormat="text/plain"; verifiers must ignore those and read only MemoData.
xrpldashboard/anchor/v1|<ISO date>|<chain_root_hex>xrpldashboard/anchor-correction/v1|<ISO date>|<prior_tx_hash>|<chain_root_hex>Verifier rules (v1, normative).
MemoData before splitting or comparing. Xaman and some other wallets append trailing newlines (observed: six \n bytes) that are not part of the payload.MemoData (the string before the first |), not by MemoType.E94ADB8CF438EB94DCC00725572CBCC03ACC3084F12DE706AEB4D418B6A7438B) that funded the ops account before anchoring began.prior_tx_hash they are replacing; there are no silent gaps.chain_root_hex from the memo to the published chain_root for the same ISO date in /.well-known/snapshots/chain.json. Any mismatch is a live-alarm event.
Trust model — what the anchor proves and what it does not.
The on-ledger anchor proves timestamped commitment to a published digest — that this exact chain_root existed and was published by this date. It does not prove the underlying analytics are correct; that is the job of the four-layer audit, cross-checks, and published methodology. The anchor makes silent rewriting detectable, not errors impossible. The signed-snapshot chain is tamper-evident against the site alone; the on-ledger anchor makes tampering additionally require a contradicting public XRPL history — a much larger and third-party-observed act.
Full spec (accounts, memo layout, deviation history, pre-lock amendments) lives at docs/ONLEDGER_ANCHOR_SPEC.md in the source repository.
A "domain-attested" issuer is one we can cryptographically link to a public web domain by following a two-way chain. First, the issuer's on-ledger Domain field (set via AccountSet) points to a hostname (e.g. sivax.io). Second, that hostname publishes an xrp-ledger.toml file at /.well-known/xrp-ledger.toml whose [[ISSUERS]] block explicitly names the same on-ledger wallet. Both directions have to agree — if either side is missing or contradicts, no badge.
This matters because anyone can mint an MPT and claim to be an institutional issuer. Attestation lets a visitor verify the claim without trusting xrpldashboard: the domain is the badge, the .well-known/xrp-ledger.toml file is publicly readable, and the entire chain is independently checkable.
What the green ✓ does NOT mean: it is not an endorsement, not KYC, not legal or regulatory verification, not a signal of financial soundness. It only certifies that the on-ledger account and the named domain are operated by the same party. Whether that party is trustworthy in any other sense is for the visitor to research.
Where the badge renders:
Currently on /mpt/issuer/<wallet> pages for verified MPT issuers. Will extend to /tokens, /whales, and homepage label surfaces as more issuers publish xrp-ledger.toml attestations.
How institutional Real-World Asset families surface on /rwa — and what we deliberately exclude.
Domain field → matching xrp-ledger.toml listing the same wallet. No name-pattern matching alone — a pool called "Foo/BlackRock" is not evidence BlackRock issues anything.token_names.json form a brand-protection allowlist. When a pool surfaces a currency code on the allowlist but the issuer wallet is not on the allowlist for that brand, the pool is annotated as an unverified-brand spoof and renders with a ⚠ marker on /pools. The same substrate gates inclusion on /rwa — the spoofs never appear as part of a verified family.excluded for cases we believe are spoofs / mislabels; pending for cases that may clear once domain attestation lands). The list is editorial, public, and updated as evidence changes — readers can see what we considered and chose not to surface.A wallet with vanity prefix rondo4tPzRyU72uNpY97iCqXGYd35AmYv
set its on-ledger Domain field to ondo.finance/ousg.
A one-way Domain check would have validated this as Ondo. The two-way TOML chain caught it:
ondo.finance/ousghttps://ondo.finance/.well-known/xrp-ledger.toml[[ISSUERS]] block lists rHuiXXjHLpMP8ZE9sSQU5aADQVWDwv6h5p as canonical OUSG issuer — NOT the rondo vanity walletThis same wallet also issues a fabricated ONDO token (Ondo's governance token is Ethereum-only — no XRPL presence) and pairs with the BlackRock and Franklin Templeton vanity wallets in self-referential spoof pools. After adding OUSG and ONDO to the verified-brand allowlist, all 12 spoof pool sides auto-flag with ⚠ on /pools.
The constellation on /pools fires a comet at the matching star
whenever a top-10 AMM pool sees an on-chain event: cyan inbound for
AMMDeposit, amber outbound for AMMWithdraw, white impact ring
for a Payment swap routed through the pool. The comet's size carries
one extra dimension — the magnitude of XRP that moved on the XRP side of the pool
in that transaction.
The XRP-side delta is extracted from the transaction's meta.AffectedNodes
block by the XRPL streaming worker (xrpl_stream.py) at write time — never
re-derived client-side. For IOU↔IOU swaps and pre-walker rows where no XRP delta
is available, magnitude is recorded as NULL and the comet renders at neutral scale
(1.0×) — honest "unknown", not a guessed value. Walker began writing magnitudes
on 2026-06-10 at 12:21 UTC; events before that bootstrap timestamp will always
render neutral.
Scaling math. Sublinear log scale on the XRP side, calibrated against live percentile data so dust transfers stay perceptible without flooring everything to a single value:
scale = clamp(0.7, 0.7 + 0.25 · log₁₀(xrp · 100 + 1), 2.0)
Anchor points against the live distribution: dust (1 drop) → 0.70× floor; p50 (0.10 XRP) → 0.96×; p95 (46 XRP) → 1.62×; p99 (259 XRP) → 1.80×; max observed (3,641 XRP) → 2.0× cap.
Under prefers-reduced-motion the comets are suppressed entirely;
the constellation status pill flashes the event label (DEPOSIT / WITHDRAW / SWAP)
in the matching colour for 250 ms instead. Information is delivered, motion is
not — same accessibility contract as the homepage globe.
/sidechain renders one row from
bridge_signer_history — the most recent observed state of the
SignerList on the Axelar XRPL Gateway account
rfmS3zqrQrka8wVyhXifEeyTwe8AMz2Yhw. The hero stat is computed from
that row at request time: when every signer carries the same weight the page
shows M-of-N (quorum ÷ uniform weight = the count that must agree);
when weights diverge it shows the raw quorum and signer count instead, because
a flat M-of-N would mislead.
The walker (bridge_signer_walker.py) runs hourly via launchd. On its
first run it took an account_objects snapshot of the live SignerList
and wrote one row with tx_hash = 'BOOTSTRAP' — that row anchors the
rotation timeline but does not itself count as a rotation. From there each pass
scans account_tx on the gateway in the validated-ledger range,
filters for SignerListSet transactions with tesSUCCESS,
and inserts one row per observed rotation. The PK on
(ledger_index, tx_hash) makes overlapping re-runs idempotent.
Bootstrap horizon: 2026-06-08 11:07 UTC. Any verifier rotation
that happened before that ledger is not in our timeline — same shape as the
pools-constellation magnitude horizon above. The freshness pill on the page is
driven by the walker's last successful run, not by the row's
close_time: rotations are rare, so a "data fresh 1 hour ago" badge
means the walker checked the chain an hour ago and found no new rotation —
not that the multisig itself changed. Cross-references to
axelarscan.io
and bithomp's gateway view
are linked on the page for anyone who wants to verify against the canonical XRPL ledger directly.
Payment
transaction of 100,000 XRP or more. Smaller transfers don't appear on /whales. We do
not aggregate multiple smaller transfers — each row is one on-chain payment.Payment +
OfferCreate fills + AMM swap legs touching that currency/issuer pair, over a 30-day window.account_info + account_lines),
same constant-product formula the protocol uses internally. This is the spot price at the moment of fetch — it changes with every swap.account_tx entries. Sparse wallets (under 3 counterparties in 30 days) display a note explaining the gap, usually because most activity is order-book trading without a single counterparty.ledger_data walk, 1-5 hours), and an hourly worker re-walks the mpt_holders RPC + refreshes current OutstandingAmount via ledger_entry for each known issuance. Results are stored with a non-null reason enum so the source state is machine-readable, not just visible in a tooltip. The enum values are: complete (walked cleanly, at least one non-issuer holder), no_holders (walked cleanly, zero non-issuer holders), incomplete (walk hit the page cap before exhausting markers; partial counts are suppressed), skipped_test (TEST/TMPT tickers or "Test ..." names — not walked, labelled distinctly from "we haven't walked yet"), pending (never walked, or the RPC errored on this cycle). The headline number is the count of holders with a positive balance; "authorized" is stored alongside. Holders count excludes the issuer's own treasury balance, matching CMC circulating-supply convention.OutstandingAmount — so the ratio is faithful even though our stored top-N list is capped at 20 entries.mpt_supply_history. Both the holders walk and the current OutstandingAmount are re-fetched per cycle, so each row is internally consistent — top-1/top-3 share are never computed against a stale denominator. Pending, incomplete, ledger_entry-failed, and skipped-test runs are excluded — the time-series is gap-free where it has data, not gap-filled across uncertainty. Raw rows retained 90 days; daily rollup beyond. Initial seed (2026-05-12 23:29 UTC): 203 issuances entered the time-series — 143 with zero positive-balance holders, 60 with active distribution. Current count grows as new MPTs are minted; see /mpts for the live figure. Anyone curious can verify against the live table./mpts table defaults to two presentational filters that hide the long tail: "Has name" (excludes MPTs missing XLS-89 metadata) and "Has supply" (excludes never-minted issuances where OutstandingAmount = 0). Both default-on, both togglable from the chip row, both persist in localStorage. The full data is always present in the page — filters only affect display — and /api/mpts returns every row unfiltered. Power users can override the supply threshold via ?outstanding_min=N (e.g. ?outstanding_min=100 for a tighter view); the chip label updates to reflect the override./api/whales/recent every 10 seconds, dedupes by transaction hash, and renders one halo-pulse roughly every 5 seconds for each new event seen. Each halo-pulse corresponds to an actual transaction recorded on /whales. On fetch failure the whale layer falls silent rather than faking traffic; under prefers-reduced-motion both layers pause and the static sphere remains./whales,
/tokens) show data up to the last successful write. Per-page WebSockets continue working independently.server_info (validated_ledger), cached 10 minutes. Reserves only change via on-chain amendment, so the cache is safe; the literal numbers in the calculation will reflect the network's current parameters automatically.
The /analytics page renders the same visitor counts twice: filtered ("humans") and unfiltered ("bots"). Both series come from page_views rows; the filter is a query-time predicate, not a stored label, so the rule is transparent and reversible.
Rule. A row is classified as bot if its (path, user-agent) pair has appeared ≥ 30 times in the trailing 7 days AND the total hit count is ≤ 1.10 × distinct visitor identifiers for that pair. The volume threshold isolates aggregate scanner activity from ambient traffic; the ratio clause distinguishes rotating-IP proxies (many one-shot visitors) from viral human bursts arriving from a shared link (also many one-shot visitors, but usually staying below the volume floor).
Retrospective flip. Because the rule reads the current 7-day aggregate on every query, rows can reclassify as evidence accrues. A burst in progress is counted as human for its first ~29 hits, then flips to bot the moment the 30th hit lands. Recent counts converge on the honest answer rather than committing to an early classification.
Declared boundary. The rule keys on repeated (path, user-agent) volume. A scanner rotating user-agent strings as well as IPs — one hit per (ip, ua) cell — keeps every cell below the volume floor and is not caught by this rule. We accept the boundary at current traffic (the arms-race cost isn't worth the accuracy gain); if scanner behaviour shifts, the rule will be extended and this section updated.
A third rule catches rotating-IP fleet attacks where each IP hits a real page exactly once with a stock browser user-agent — invisible to both prior rules.
Signal. A spike in unique IPs for a (country, path) pair far above that combination's 30-day baseline. Example: Israel + /whales averaging ~2 unique IPs/day spiked to 774 unique IPs in one day — a 387× multiplier. The rule fires when unique IPs exceed 10× the trailing-30-day median AND exceed an absolute floor of 50 unique IPs (prevents small-baseline countries from triggering on noise).
Scope. Classification is by cohort (country + path + day), not by individual history. All visits matching the cohort fingerprint on a burst day are reclassified as bot — including any genuine visitor from that country who happened to visit that path on that day. The rule is retroactive: once a burst day is confirmed, historical rows reclassify automatically the next time /analytics is queried.
Declared boundary. A genuine visitor from Israel who visited /whales on a burst day is retrospectively classified as bot. We accept this false-positive at current traffic scale — on a day with 774 IL/whales hits, the probability that any of them were genuine non-fleet visitors is low, and growing with evidence. The rule distinguishes on the COHORT shape (deceptive UAs, real pages, one hit per IP, country-concentrated) rather than on being a bot — declared AI crawlers identify themselves in their user-agent and are classified by the existing UA pattern rule before this predicate is checked.
Review trigger. Re-audit thresholds when daily human traffic exceeds 1,000 unique visitors. At that scale, genuine single-visit /whales traffic from any country becomes frequent enough that the absolute-floor and multiplier math needs rechecking against the false-positive rate.
Every tool served by the MCP server (see Agent Tier design doc) carries a methodology_url field in its proof envelope. The anchors below are the deep-link targets those envelopes cite — each names the data source, freshness contract, and any known limitations for one class of tool. If a tool's envelope points here, this is the section a caller lands on.
Source: local_rippled (self-hosted node) or s1.ripple.com:51234 when the local node is unavailable. Returns the current validated ledger index, close time, and hash — the same values the browser liveness chip reads.
Freshness contract: ≤ 5s (ledger close cadence). No cache — every call is a live ledger RPC. Envelopes emit as_of as the ledger close time, not the fetch time.
Source: s1.ripple.com:51234 via the feature RPC + the canonical Amendments ledger object. Amendment definitions the responding node doesn't recognize are named via off-ledger sources in amendments_state.KNOWN_UNRECOGNIZED_HASHES (each entry cites a verifiable rippled PR or spec URL — see the /amendments page for the human surface, including a truth-first note whenever the node lags a network-enabled amendment). Freshness contract: ≤ 5min (per amendments_state.CACHE_TTL). cross_check_status = agree when the enabled-count from the feature RPC and the Amendments ledger object are within tolerance; disagree otherwise.
Amendment vote tallies — honest limit.
The feature RPC's count and threshold fields report the responding node's own validator vote — they return None for any non-validator, which includes our self-hosted node and every public gateway (s1/s2). Aggregated trusted-validator support percentages therefore cannot be sourced from a single rippled RPC. During active-news windows for specific amendments we attach an interim honest label sourced from xrpscan.com's amendments API (curated in amendments_state.INTERIM_VOTE_NOTES, refreshed manually against the primary source). A live-fetch integration with the honest_partial envelope pattern is in design (owed 2026-08-22).
Source: vl.ripple.com (Ripple's canonical published Unique Node List) cross-checked against vl.xrplf.org (XRPLF-published UNL). Returns the list version, ephemeral key expiration, and validator entries.
Freshness contract: ≤ 30min. When one of the two published lists fails to fetch, the tool routes honest_partial=true with a scope_note naming which list failed — never fabricates a synthetic UNL from a single source.
Source: local_rippled_stream_capture — the same live capture feed the /whales page reads. Two-tier threshold, both named in the response payload: xrpl_stream.py captures at ≥ 50_000 XRP (walker floor, env-tunable via WHALE_XRP_THRESHOLD_XRP); the MCP tool + /whales default display floor is ≥ 100_000 XRP (mirrors the human surface). Tagged rows use TAGGED_XRP_FLOOR_DROPS = 100 XRP. TrustSet entries are excluded — they signal intent, not movement.
Freshness contract: ≤ 5min (stream cadence + PG-write lag). Token-denominated tagged rows bypass the XRP floor; agents needing USD-priced sizing must join against the token-price oracle themselves. The tool response includes this caveat verbatim in a note field.
Supply.
Source: ethereum_public_rpc + xrpl_public_rpc — the same rlusd_live cache the /rlusd page reads.
Freshness contract: ≤ 30min. When either chain fetch errored, the envelope emits honest_partial=true with a scope_note naming which side failed — never a fabricated cross-chain total.
cross_check_status='not_applicable' here: the two chains measure independent issuance pools, not the same fact from two sources, so they cannot agree/disagree.
24h flow.
Source: rlusd_supply_history + xrpl_gateway_balances. Freshness contract: finalized_only — the machine-readable form of the R1/R2 finalized-window rule (snapshot_date < today_utc). Today's partial-day row is invisible to this tool; only rows the answer_plausibility_walker would have evaluated as finalized are eligible. This is the fix for the RLUSD 53-day false-flat class of bug that led to the R2 patch (see docs/TRUTH_AUDIT_DESIGN.md).
cross_check_status here is derived from a real paired computation: stored xrpl_net_change_24h (Option-A gateway_balances diff) vs derived xrpl_supply[t] − xrpl_supply[t-1]. Agreement within CROSS_CHECK_EPSILON_RLUSD (1) emits agree; any larger divergence is disagree — an agent reading disagree should downweight the number, not just relay it. The same three-state verdict is surfaced as a chip on the /rlusd page next to the freshness pill — one derivation, two surfaces.
Source: rank_amms_walker + amm_tvl_recorder — the same amm_ranked_pools snapshot the /pools page reads. rank_amms curates the ranked set (thresholds on liquidity and non-zero pair sides); amm_tvl_recorder fills the tvl_usd + tvl_status columns from live pricing. Rows with NULL tvl_usd sort last in the top-N view — the absence is preserved, not silently dropped.
Freshness contract: ≤ 30min — matches the recorder cadence. Unranked AMM accounts (below thresholds, or newer than the last snapshot cycle) return a RuntimeError from get_amm_pool rather than a stub — absence IS the signal, same rule the Day 3 finalized-window tool applies.
Source: verify_toml_accounts + enrich_token_names — the same account_labels table the /tokens per-row attestation badge reads. Three-state ladder mirrors app.py:2589-2598 (v3 §7):
verified — the issuer address has a label with source='toml' (verify_toml_accounts successfully fetched and parsed the issuer's .toml declaration);
self-described — labeled with a non-toml source (derived:xls-15, enrich_token_names): named by an evidence trail but not TOML-verified;
null — no account_labels row for the issuer. Absence IS the signal — the field is explicitly null, never fabricated.
Freshness contract: daily. Every response includes dispute_contact_url in the data payload — first-party channel for any issuer who disagrees with the label. Same target the /tokens per-row footer link uses (purpose=attestation-dispute in app.py CONTACT_PURPOSES).
Source: rwa_family + rwa_pool_attribution — the same curated allowlist tables the /rwa page reads. get_rwa_families returns every family with its attributed pool count; get_rwa_pools returns every pool-attribution row with provenance + tvl_usd joined against amm_ranked_pools (same join as app.py:3086).
attestation_level ∈ {verified, inferred, preliminary} is a per-family curation grade (schema constraint in db.py:365); confidence ∈ {high, medium, low} is a per-pool attribution grade. Both are curated, not derived — the manifest of what we chose to surface, and with what strength of claim.
Freshness contract: daily (families) / ≤ 30min (pools, since the TVL join reads the amm_ranked_pools snapshot). Both responses include dispute_contact_url — a family or pool owner disagreeing with an attribution has the same first-party correction channel.
Source: mpt_snapshot + mpt_holders_refresh — the same mpt_snapshot JSON payload the /mpts page reads. Reports total active MPTs and a by-class breakdown as the walker recorded them; not third-party-naming (no per-issuer labels here, so no dispute_contact_url). A mislabel of a specific MPT issuer lands on get_token_attestation, not here.
Freshness contract: daily (mpt_snapshot walker cadence). The snapshot dict includes snapshot_age_seconds — an agent that wants a fresher read can compare that value against the daily contract and back off accordingly.
Source: signed_snapshot_walker — the daily launchd job that writes signed_snapshots/YYYY-MM-DD.json with an Ed25519 signature, RFC 6962-style Merkle audit path, and pinned pubkey fingerprint. These two tools are the moat expression as an MCP surface: get_signed_snapshot(date_str) retrieves the full signed envelope for one ISO date (raises when absent — the walker has not produced this date yet, or the date predates the chain start). verify_snapshot_signature(envelope) is stateless: an agent hands back the exact envelope it received (either the full {data, proof, server} wrapper or the bare signed payload) and this tool re-derives the leaf hash, checks the Ed25519 signature against the pinned pubkey, and checks the audit path against the claimed chain root — the same verification path a third-party verifier would run with no shared state.
Freshness contract: daily (get) / ≤ 5min (verify — stateless in-process check).
The round-trip receipt: a caller who screenshots a metric today can hand the snapshot back into verify_snapshot_signature six months later — from a completely different site, or from a local Python REPL using the same signed_snapshot.verify_envelope function — and prove the number wasn't silently changed. See Signed integrity snapshots above for the human-facing deep-dive on the chain design.
This site is a public read-only source of XRP Ledger and cross-chain data. Automated retrieval, citation, and machine reading are welcome — anticipated, even. This section is the transparent contract for anything reading this page programmatically.
/llms.txt — markdown site directory (llmstxt.org convention). Every URL listed resolves to a live public page./.well-known/agents.json — agent-discovery manifest (Wildcard-AI flavor). Contains site identity, rate limits, trust surfaces, and the proof-annotation envelope agents should expect./openapi.json — OpenAPI 3.0 spec for the LIVE read-only surface. Includes the ProofAnnotationEnvelope schema (the standard response wrapper) and the machine-readable MCP tool inventory at info.x-mcp-tools./docs — Swagger UI rendering of the above. Human-readable; agents typically fetch /openapi.json directly./claims — queryable public claims manifest. Every claim on the site has a permanent URI at /claims/xrpl.<domain>.<series> with a traffic-light sovereignty tier (green = own infrastructure, yellow = public XRPL RPC or unverified, red = third-party derived). Content-negotiated JSON via Accept: application/json or .json suffix. Machine-readable index at /claims/index.json./.well-known/security.txt — security disclosure contact.
Four self-contained snippets — curl, Python, JavaScript for fetching a claim envelope + a Python end-to-end verifier for the daily signed snapshots — live on the claims manifest:
/claims#use-this-data.
Every snippet on that page was executed against live prod before shipping. Copy any one, run it, get a proof-annotated response back in under a second.
Every JSON payload from the MCP server carries a receipts block. The MCP server is public at https://mcp.xrpldashboard.com/mcp (public beta through 2026-09), streamable-http transport, protocol version 2025-06-18, no auth. Backed by our own rippled node on the Lenovo box. The read-only HTTP API will carry the same block when it ships. Agents verify our numbers locally — against ledger truth, against the signed-snapshot chain, against
CLAIMS.yaml — without a support ticket. Envelope shape:
{
"source": "local_rippled | neon_postgres | ethereum_1rpc | ...",
"as_of": "2026-07-29T15:42:00Z",
"methodology_url": "https://xrpldashboard.com/methodology#...",
"claims_ref": "rlusd_xrpl_supply", // where a CLAIMS.yaml entry exists
"snapshot_signature": "ed25519:...@chain#N" // where the datum is snapshot-derived
}
The read-only OpenAPI spec is live at /openapi.json (Swagger UI at /docs) — the ProofAnnotationEnvelope schema above is machine-readable at #/components/schemas/ProofAnnotationEnvelope, and the 15-tool MCP inventory is at info.x-mcp-tools. The MCP server is public and live at https://mcp.xrpldashboard.com/mcp (public beta through 2026-09; the server runs as a systemd daemon on the Lenovo box, same host as our rippled node, exposed via Cloudflare Tunnel). Per-tool freshness contracts are declared inside each tool response envelope (freshness_contract field: ≤ 5min / ≤ 30min / daily / finalized_only) and mirror the on-page freshness chips agents see for the same data. See the
design doc on GitHub for the full build sequence.
The /nfts page surfaces XLS-20 NFT activity (mints, burns, offers, sales) with two source classes, each labeled at point of display:
Ledger RPC (transactions=True, expand=True), 5-minute cadence, 200-ledger batches, head-safety margin of 3. Only tesSUCCESS transactions are counted. This tier is classified own-node.
s2-clio.ripple.com because full history was required and our own rippled node does not carry it. This tier is classified third-party.
The 2026-08-10 gap audit of the historical range produced ~95.6% coverage of a 2,958,523-ledger range (2026-04-01 → head): 2,194,433 ledgers were observed with NFT activity (4,955,611 events), ~635,090 contained no NFT transactions (legitimately empty of NFT tx), and ~129,000 are residual holes — public-Clio 503 responses the walker persisted past during backfill. The 95.6% denominator is the full range; empty-by-consensus ledgers count as covered, residual holes count as missed. This is disclosed on /nfts rather than surfaced as false-complete.
Under our sovereign-source doctrine — SELLABLE_REQUIRES_SOVEREIGN_SOURCE — any endpoint whose underlying data was read through a third-party pipe stays free forever, honestly labeled, until it can be re-derived from our own infrastructure. NFT historical backfill therefore sits permanently in the free tier until (and unless) we buy a full-history rippled node and re-derive the range from it. The doctrine is fully documented in docs/X402_RAILS_DARK_SCOPING.md § 2 Paid-candidate filter.
A tamper-evident chain of daily Ed25519-signed database snapshots is served under
/.well-known/snapshots/chain.json. The public key is pinned at
/.well-known/snapshots/pubkey.pem. Agents that need audit-grade evidence can verify any snapshot payload cryptographically against this key without trusting the server or the network path in between. See Signed integrity snapshots above for details.
Since 2026-08-07, each daily chain_root is additionally anchored on the XRP Ledger from account rL2yMECEyUT94pLDrAcetMNMG1H4xqpNWQ (first anchor tx 01D0BB9D230955F43DB35703E2EB7F5DFA43CEB69CCBBF57FBC8F17407E50DF8, ledger 106140698). Cadence is weekly, manual today. Memo format v1 (namespace-in-MemoData) and verifier rules — including the mandatory .strip() on MemoData before splitting — are documented at On-ledger anchor of the snapshot chain above.
Free for humans and identified agents at reasonable volume. Transparent, no silent throttling. Declared shape:
Retry-After header.
Enforcement is live as of 2026-08-02. The numbers here, in /.well-known/agents.json, and what the server actually enforces are held in sync by a regression test that reads the module's default-rate strings on every run.
We do not retain agent queries. Aggregate demand telemetry (tool-call counts per tool per day, unique anonymous client fingerprints, MCP-server session durations) is kept to inform which surfaces to prioritise. No query bodies, no client identifiers beyond what an anonymous fingerprint provides.
The Agent Tier ships free at v1 by construction — no accounts, no API keys, no payment rails. A paid tier is only a decision on the table after (1) US legal guidance on receiving crypto micropayments as a solo LLC clears, and (2) 60-90 days of observed demand justify the metering. Until then, everything here stays free, and the four-zeros posture (nothing here receives crypto, holds fiat, or touches user funds) is preserved by architecture, not by promise. See the Agent Tier design doc for the full scope contract.
Freshness contract for this section and the agent-tier surfaces (llms.txt, agents.json, openapi.json): last verified 2026-08-29. Bumped whenever the agent-tier surface changes.
This methodology page is part of the same git repository as the code. Any time the site's caching behavior, data sources, or methodology changes, the corresponding edit lands in this file in the same commit. The commit history of templates/methodology.html
is the canonical change log.
Found a discrepancy? Open an issue on GitHub or send us a note. We'll either fix the data, fix the explanation, or — if it's a genuine ambiguity — add it to the limitations list above.