Skip to content

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Blockchain Flow Map

The live page on the globe: evidenced cross-border routes between the United States, the Caribbean and Europe, with the three headline figures, the leading corridors and the 1H window The same hour unfolded into the Equal Earth atlas: routes linking the United States and the Caribbean with Europe, the Seychelles, South Africa and Australia

The live page on 19 October 2026 at 21:13 UTC, 1H window, on the globe and unfolded into the Equal Earth atlas. The routes are what that hour's evidenced wallets showed, not a standing claim; the page read PARTIAL because Avalanche's public endpoint was rate-limiting.

verify licence: MIT

Live: flows.jakepercy.com · Landmarks · llms.txt · methodology

Published by GitHub Pages from main on every push, through the same gated build.

A live, evidence-only map of cross-border stablecoin settlement. The visitor's browser reads USDC and USDT Transfer logs straight from free public RPC endpoints on seven chains (Ethereum, Base, Arbitrum, Avalanche, Polygon, Optimism, Tron), attributes each transfer against a registry of exchange and custodian wallets whose evidence is a public name tag on the address's own explorer page plus a regulator or company document for the operator's jurisdiction, and draws a route only when both ends of a transfer are evidenced wallets in different jurisdictions. The page needs no server and no API key: your browser reads the chains itself. A small recorder on Cloudflare reads the same public endpoints around the clock and publishes sealed quarter-hour summaries as public, read-only files, so the 24H and 7D windows are ready when the page opens. The page is a static folder that CI builds through the gate and GitHub Pages publishes. The map deliberately shows only a small fraction of on-chain volume and says exactly how small.

What you are looking at

  • Three headline figures. Observed on evidenced wallets (every priced transfer touching a registry wallet), Adjusted activity (after mint/burn, bridge, same-entity, treasury and bot transfers are removed) and Geographically attributed (the share of adjusted value that could be placed at both ends, in different jurisdictions). The coverage percentage beside the third figure is the honest number: usually single digits.
  • The drawing rule. "A route is drawn only when both ends of a transfer are publicly evidenced wallets in different jurisdictions. Most transfers are not, by design." A glow at a jurisdiction is one-sided evidenced activity, never a route.
  • Windows. 5M and 1H come from transfers held in memory. 24H and 7D are assembled from completed quarter-hours, each sealed into exact accounting: those the visitor's own browser watched, kept in that browser, and those the shared history recorder published; for each chain and quarter hour the better-observed one is used, never both. They unlock once 80% of the window has been observed. The browser uploads nothing, and nothing is scaled up. The bars under the map can be read and clicked to replay from that moment; a corridor's panel shows its own bars, so a total made of one burst and one made of steady flow no longer look alike.
  • Why is this mapped here? Every corridor opens into evidence cards: the entity, the explorer tag, the jurisdiction document, the date each was last verified, and whether the endpoint is a first-party label, a DERIVED cross-chain reuse of an Ethereum label, or an INFERRED deposit address seen sweeping into a labelled wallet.
  • Unmapped. The transfers the map cannot place, who they touched, and the largest unplaced counterparties as a research lead list, never as evidence.
  • Landmarks. A second, static page: sixteen landmark transactions read from their own chains by two or three independent endpoints that must agree, named only under a written rule, with every figure stamped from chain data.

The rules it refuses to break

  1. An address enters the registry only when its own explorer page shows a public name tag, stored verbatim with the date it was read. Researcher compilations, analytics firms, exchange-published lists and memory are not evidence.
  2. A jurisdiction comes from a regulator register, a court filing or the company's own legal document, and must name one legal entity that holds customer crypto whatever the client's residence (the operator test). Ten brands with clean tags were removed when their own documents failed it.
  3. Deposit addresses, funders, routers, bridges, DEX and token contracts and issuer treasuries never enter the registry.
  4. No CAPTCHA is bypassed and no rate limit worked around; an explorer that blocks a page is read another lawful way or the address is skipped.
  5. Evidence expires. The model refuses evidence older than 180 days at the transfer's own time, and the build fails 60 days before the earliest expiry so a published page cannot go stale in public.
  6. Derived evidence is second class: never VERIFIED, never for a contract, never the anchor of an inference.
  7. The observed total is a declared sample, never an estimate. A small unfiltered slice of chain time is read periodically to state how small the evidenced share is, and is never scaled up.
  8. No synthetic data, ever. When a feed fails the page shows LOADING, PARTIAL, DELAYED or RECONNECTING; it never falls back to a placeholder.

Decisions

Each one is written up with the measured evidence and the condition under which it would be reopened, in docs/DECISIONS-2026-09.md.

Decided Decision Consequence
D1 2026-09-21 An exchange's own published address list is not evidence. Explorer tags stay the only way in.
D2 2026-09-21 Wallets with no stablecoin transfer in 90 days leave the live filter but stay as evidence. Visitor upload for the first hour fell about 89%; replayed hours identical.
D3 2026-09-21 The operator test: one legal entity, one jurisdiction, whatever the client's residence. FalconX, Copper, BitGo, Cumberland, Galaxy, Jump, B2C2, GSR, Zero Hash and Amber Group removed.
D4 2026-09-25 A token is read only where its issuer publishes the contract. BNB Chain absent (bridge-issued pegs); Polygon and Optimism USDC only; Tron USDT only.
D5 2026-09-25 A 24H or 7D figure is what this browser recorded, in sealed quarter-hours, offered at 80% coverage. Recorded history, measured coverage, real baselines; no per-transfer detail stored.
D6 2026-09-29 Tronscan's own public name tags are admissible for Tron, like Etherscan's. Tron live with 27 tagged wallets; nothing derives onto Tron.
D7 2026-10-02 Who the Landmarks page may name: an explorer tag crediting no outside source, or a primary document identifying the transaction. News and analytics firms never name anyone there; a person only on their own statement or a court record.
D8 2026-10-21 A shared recorder may seal the same quarter-hours as each browser, with the same code; one span per chain and quarter hour, the better-observed one, never summed. Built in worker/, live on Cloudflare since 2026-10-26 and read by the page since 2026-10-27, after its spans were compared with a browser's. It backfills a week; transfers older than the page's price sources reach are priced from Bitstamp (amended 2026-10-26).

How it works

flowchart LR
  REC["worker/ history recorder<br/>sealed quarter hours, public files"] --> LC
  subgraph browser ["Visitor's browser"]
    RPC["Keyless public RPC<br/>eth_getLogs, two topic positions"] --> LC["live-client.ts<br/>feeds, backfill, poll, sample, health"]
    LC --> CORE["live-core.ts<br/>decode, price, classify, inferDeposits"]
    CORE --> ENG["engine.ts<br/>aggregateSpan: corridors, countries, totals"]
    ENG --> UI["atlas.tsx and components/map<br/>globe that unfolds into Equal Earth"]
    ENG --> ROLL["rollup.ts<br/>15-minute sealed spans"]
    ROLL <--> IDB[("IndexedDB<br/>this browser only")]
  end
  subgraph registry ["Evidence pipeline, offline"]
    TAG["read-tag.mjs<br/>own explorer page"] --> ADDR["addresses.txt<br/>chain, entity, address, tag, date"]
    ADDR --> PROBE["probe-code.mjs"] --> GEN["gen-addresses.mjs"]
    DORM["measure-dormancy.mjs<br/>90 days, monthly"] --> GEN
    GEN --> KA["known-addresses.ts<br/>generated"]
    KA --> ENT["known-entities.ts<br/>entities, jurisdiction evidence, lookups"]
  end
  subgraph gate ["Build gate: pnpm build:live"]
    V["verify-all.mjs<br/>8 verifiers and tsc"] --> VITE["vite build"] --> OUT["dist-live/<br/>index, landmarks, llms.txt, methodology.md"]
  end
  ENT --> CORE
  ENT --> V
Loading

The pure parts (lib/atlas/live-core.ts, engine.ts, rollup.ts, model.ts) have no fetch, DOM or timers and are exercised by the verifiers in plain Node. The transport and state machine (live-client.ts) rotates endpoints, counts failed chunks as partial coverage rather than swallowing them, and re-reads the latest hour after a sleep.

Quickstart

Node 22.18 or newer (the build-time renderers import TypeScript from plain modules).

corepack enable && pnpm install
pnpm dev:live
pnpm verify && pnpm typecheck && pnpm build:live

pnpm build:live refuses to build if any verifier fails, including when the evidence registry would expire within 60 days or the dormancy measurement is older than 45 days. node scripts/serve-dist.cjs dist-live serves the build under a nested path the way the FTP folder does.

The evidence pipeline, in five steps

  1. Lead. A candidate wallet comes from an activity measurement (the largest unlabelled counterparties of evidenced wallets), a holder export, or a lead feed. A lead is never evidence.
  2. Tag. scripts/registry/read-tag.mjs reads the address's own explorer page and prints the tag verbatim, with any "tagged based on a compilation" disclosure, which goes into the row's note.
  3. Operator. The brand's own documents must name one legal entity, in one jurisdiction, that holds customer crypto for every client. If custody depends on the client's residence, the brand stays out, however active.
  4. Activity. A tagged wallet is admitted only if it moved at least $100k in the screening window; a documented operator whose wallets moved nothing in 90 days is recorded as such and left out.
  5. Gate. gen-addresses.mjs refuses orphans (a contract on Ethereum with no code on another chain), the verifiers check every row resolves and every date is real, and the build stamps the registry's size and freshness into llms.txt and the page.

What it costs a visitor

Measured, with the report each figure comes from:

Figure Measured Source
One hour on Ethereum, Base and Arbitrum, filtered feed 4.1 MB down, 2.1 MB up 2026-09-20 docs/LIVE-FEED.md
The same, unfiltered about 140 MB 2026-09-20 docs/LIVE-FEED.md
Upload for the backfilled hour after the dormant tier 2.2 MB to 0.23 MB 2026-09-21 docs/measurements/2026-09-21/dormancy.md
One hour of the Tron feed, 21 wallets 1.24 MB on the wire 2026-10-07 docs/measurements/2026-10-06/tron-tronscan-tags.md
Endpoint caps that bind the filter 1,000 addresses per topic (Ethereum), 997 (Arbitrum) 2026-09-21 docs/LIVE-FEED.md, lib/atlas/feeds.ts

Who did what

The rules, the seven decisions, every admission and removal, the holder exports, the bandwidth and budget calls and the phone-layout calls were Jake Percy's. The code was written with AI coding agents working under AGENTS.md and CLAUDE.md: a standard they could not relax, enforced by the build gate rather than by trust. Each change was also recorded in an engineering log kept with the project but not published; the facts the public documents rely on are in docs/: the method, the decisions, the live feed's measured limits and the dated measurement reports.

Maintenance

  • The dormancy measurement is redone monthly (scripts/registry/measure-dormancy.mjs, about 100 minutes on free endpoints); the build fails once it is older than 45 days. Last measured 2026-10-07.
  • The Landmarks "recent" window moves monthly (scripts/landmarks/README.md).
  • Evidence is re-verified before it ages out: the earliest current expiry is 2027-03-17 and the gate starts failing 60 days before it.

Status

Updated 2026-10-21. Seven chains live; 1,221 first-party wallets (plus 3,577 derived) across 68 entities and 30 jurisdictions; Solana not connected (it needs a keyed indexer). The repository was prepared for publication on 2026-10-18 and went public on 2026-10-19: the deferred backend scaffold and the unused template code left the tree, the gate type-checks the whole project, the page's first minute reads honestly, both pages name and link their author and the source, the 1H window has corridor baselines, and the bulk explorer-scan outputs are kept offline. On 2026-10-19 a pinch on the flat map could fling it off a phone's screen; that is fixed, and the flat map opens on the whole world. Since 2026-10-19 every push to main also publishes the map to GitHub Pages through the same gated build. The screenshots above are dated captures of the live page, and the projection caption no longer sits under the map legend on desktop. On 2026-10-20 the health badge, which a 375 px phone clipped at the right edge of the top bar, leaves the top bar on phones (the time strip and status strip still show it), and the headline figures were re-measured at 375 px: three columns, nothing overlapping. On 2026-10-21 sealing moved into lib/atlas/recorder-core.ts, checked on recorded real Ethereum and Tron logs; what the page shows is unchanged, except that a quarter hour sealed in the moment between a poll and the page's re-classification of it is no longer stored with that poll's transfers unattributed. Later that day Avalanche, which had read PARTIAL since api.avax.network cut its filtered reads from 5,000 blocks to 100, reads LIVE again: Tenderly's Avalanche gateway joined publicnode on the filtered feed (re-measured in docs/LIVE-FEED.md), and the page now moves to the next endpoint when one refuses a request with a JSON-RPC error, so the next such cut costs one endpoint rather than a chain. Base was re-measured the same day: mainnet.base.org had cut its filtered reads from 2,000 blocks to 200 and then refused them, which had left publicnode as the only endpoint serving Base's filter. Tenderly's and Sentio's Base endpoints now serve it too, with Base's chunk lowered from 1,500 blocks to the 1,000 they take. Since 2026-10-21 the map lives at flows.jakepercy.com, published by GitHub Pages from main; it is no longer uploaded by hand to a folder on jakepercy.com. On 2026-10-26 the history recorder of decision D8 was built in worker/, after a test run on Cloudflare, and deployed. It backfilled a week on its first start and publishes each day's spans in a compact, lossless format, about 2.6 MB a week gzipped. On 2026-10-27 the page began reading it, after a comparison with a browser's own spans (docs/measurements/2026-10-27/) found the two read the same transfers and that the browser had sealed each quarter hour before reading a sweep made just after its close; both now seal once reading has passed two minutes beyond the end. Later on 2026-10-27 playback began to scrub the recorded week on 24H and 7D (it had been held to the last hour), the timeline's bars became readable and clickable, and the corridor panel gained the corridor's own bars. The project was formerly Ledger Atlas; some file names and the browser's history store still carry that name.

Repository map

Path What it is
live-lite/ The two pages' entries, styles and the llms.txt prose template
components/atlas.tsx, components/map/ The UI and the globe renderer
lib/atlas/ Model, accounting, live client, sealed history, registry, geography
worker/ The history recorder (decision D8): a Cloudflare Worker that seals and publishes 24H and 7D history
scripts/registry/ The evidence pipeline: source list, tag reader, code probe, dormancy scan, generator
scripts/verify-*.{cjs,mjs}, scripts/verify-all.mjs The build gate
scripts/fixtures/ Real chain logs, headers and prices recorded for the verifiers to replay (scripts/record-recorder-fixture.mjs)
scripts/landmarks/, lib/landmarks/ The Landmarks page pipeline and its generated data
scripts/llms/ llms.txt, methodology.md and the page's plain-text surfaces
scripts/measure-*.mjs, scripts/screen-candidate-chain.mjs Offline diagnostics that rank work by measured activity
docs/ Methodology, decisions, the live feed and its measured limits, API plan, measurement reports
AGENTS.md, CLAUDE.md The standing instructions the AI coding agents work under

See NOTICE for the terms on the evidence registry and the measurement reports.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages