Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
583dba1
docs: 2026 market research and the product position it produced
bitcoinuniverseadmin Aug 26, 2026
8abaf07
feat(universe): universal search, live protocol pulse, and asset pages
bitcoinuniverseadmin Aug 26, 2026
88412c0
ci: gates for upstream marks, third-party origins, and em dashes
bitcoinuniverseadmin Aug 26, 2026
990c09d
brand: remove the upstream product identity, analytics, and third-par…
bitcoinuniverseadmin Aug 26, 2026
f2f03d9
ops: document the real deployment topology and drop upstream fleet sc…
bitcoinuniverseadmin Aug 26, 2026
644635e
brand: remove upstream imagery and social cards from the shipped assets
bitcoinuniverseadmin Aug 26, 2026
769a90e
build(frontend): copy resources in the Universe production build
bitcoinuniverseadmin Aug 26, 2026
08bf101
fix(backend): bind to loopback, and say when the node is still catchi…
bitcoinuniverseadmin Aug 26, 2026
ae09ab0
fix(gateway): rewrite the unprefixed API path onto the backend prefix
bitcoinuniverseadmin Aug 26, 2026
ba5c542
fix(gateway): make listening the default rather than a path comparison
bitcoinuniverseadmin Aug 26, 2026
577c06a
fix(a11y): name the icon-only controls, and stop the protocol rows ov…
bitcoinuniverseadmin Aug 26, 2026
2df3d4b
feat(gateway): security headers, and say why an empty panel is empty
bitcoinuniverseadmin Aug 26, 2026
9ecf047
docs: record every upstream subsystem this fork now modifies
bitcoinuniverseadmin Aug 26, 2026
3b7c215
perf: stop the footer jumping when page data arrives
bitcoinuniverseadmin Aug 26, 2026
85d6283
perf: start the footer below the fold so page growth costs nothing
bitcoinuniverseadmin Aug 26, 2026
67e968b
deps: clear every critical and high advisory that reaches shipped code
bitcoinuniverseadmin Aug 26, 2026
9173595
Universe Explorer: protocol product surfaces, branding cleanup, and C…
bitcoinuniverseadmin Aug 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 19 additions & 1 deletion .github/workflows/universe-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ jobs:
- name: Protocol coverage table matches the recorded manifest
run: node scripts/universe/generate-protocol-coverage.mjs --check

- name: No em dash anywhere
run: node scripts/universe/check-text.mjs

- name: No obsolete upstream product marks
run: node scripts/universe/check-branding.mjs

- name: No third-party data origins
run: node scripts/universe/check-origins.mjs

- name: Gateway routing
run: node --test scripts/universe/gateway.test.mjs

backend:
name: Backend build and test
runs-on: [self-hosted, linux-ultra]
Expand Down Expand Up @@ -91,4 +103,10 @@ jobs:

- name: Production build
working-directory: frontend
run: npm run build
run: npm run build:universe

- name: Built bundle carries no upstream marks
run: node scripts/universe/check-branding.mjs frontend/dist

- name: Built bundle calls no third-party origin
run: node scripts/universe/check-origins.mjs frontend/dist
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ target
docker/backend/start_ci.sh
# Universe: docs/data holds evidence-model documentation, not runtime data
!docs/data/

# Dependencies are never committed, at any depth.
node_modules/

# Visual QA working output. Curated review sets are committed under docs/design.
scripts/universe/visual-qa/artifacts/
scripts/universe/visual-qa/node_modules/
172 changes: 148 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,162 @@
# The Mempool Open Source Project® [![mempool](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ry4br7/master&style=flat-square)](https://dashboard.cypress.io/projects/ry4br7/runs)
# Universe Explorer

https://user-images.githubusercontent.com/93150691/226236121-375ea64f-b4a1-4cc0-8fad-a6fb33226840.mp4
The Bitcoin Universe mempool and block explorer. It shows what is happening on
Bitcoin right now, and what transactions actually do across Bitcoin Universe
protocols, with the evidence behind every claim.

<br>
Live at [explorer.bitcoinuniverse.io](https://explorer.bitcoinuniverse.io).

Mempool is the fully-featured mempool visualizer, explorer, and API service running at [mempool.space](https://mempool.space/).
## What makes it different

It is an open-source project developed and operated for the benefit of the Bitcoin community, with a focus on the emerging transaction fee market that is evolving Bitcoin into a multi-layer ecosystem.
Most explorers answer one of two questions. A mempool explorer tells you what
is pending and what it will cost to confirm. A protocol explorer tells you what
assets exist. Universe Explorer answers both in one place, and it never guesses.

# Installation Methods
- **Exact asset flows.** A transaction page names the inputs and outputs that
carry protocol assets, the action the authority reported, and the block that
proves it. Nothing is inferred from transaction shape.
- **Outputs are first class.** `/outpoint/:txid/:vout` is a real page. An output
is the unit that carries assets on Bitcoin, so it gets its own address.
- **States that mean something.** Proven, partly proven, outside coverage,
pending, and unavailable are five different answers. A missing indexer never
becomes a false zero.
- **Live protocol activity, measured.** The pulse page publishes its own
denominator: how many arriving transactions were checked, and how many carried
each protocol. Every number on it can be reproduced.
- **No trackers, no accounts.** Search is matched in your browser. Saved pages
and history live in local storage and never leave the device.
- **First-party data only.** Every figure comes from Bitcoin Universe's own
node, Electrum index, and protocol authorities.

Mempool can be self-hosted on a wide variety of your own hardware, ranging from a simple one-click installation on a Raspberry Pi full-node distro all the way to a robust production instance on a powerful FreeBSD server.
## Protocol coverage

Most people should use a <a href="#one-click-installation">one-click install method</a>.
The registry carries every protocol in the Bitcoin Universe ecosystem, and the
explorer states plainly which ones it can actually read.

Other install methods are meant for developers and others with experience managing servers. If you want support for your own production instance of Mempool, or if you'd like to have your own instance of Mempool run by the mempool.space team on their own global ISP infrastructure—check out <a href="https://mempool.space/enterprise" target="_blank">Mempool Enterprise®</a>.
| State | Meaning |
| --- | --- |
| Live, read only | A first-party authority is running and its evidence is shown. |
| Not yet available | No first-party authority for it is configured or answering here. The explorer makes no claim about it. |
| Different chain | The protocol lives on a chain this explorer does not serve. |

<a id="one-click-installation"></a>
## One-Click Installation
Live today, backed by the first-party Ord 0.29 authority: **Ordinals**,
**Rare Sats**, **Runes**.

Mempool can be conveniently installed on the following full-node distros:
- [Umbrel](https://github.com/getumbrel/umbrel)
- [RaspiBlitz](https://github.com/rootzoll/raspiblitz)
- [RoninDojo](https://code.samourai.io/ronindojo/RoninDojo)
- [myNode](https://github.com/mynodebtc/mynode)
- [StartOS](https://github.com/Start9Labs/start-os)
- [nix-bitcoin](https://github.com/fort-nix/nix-bitcoin/blob/a1eacce6768ca4894f365af8f79be5bbd594e1c3/examples/configuration.nix#L129)
`docs/protocols/PROTOCOL-COVERAGE.md` is generated from the registry and lists
every entry with its authority. Run `node scripts/universe/generate-protocol-coverage.mjs --check`
to verify the table still matches.

**We highly recommend you deploy your own Mempool instance this way.** No matter which option you pick, you'll be able to get your own fully-sovereign instance of Mempool up quickly without needing to fiddle with any settings.
## Architecture

## Advanced Installation Methods
Three processes behind one HTTPS origin:

Mempool can be installed in other ways too, but we only recommend doing so if you're a developer, have experience managing servers, or otherwise know what you're doing.
| Component | What it is |
| --- | --- |
| Explorer backend | `backend/` in this repository. Reads Bitcoin Core, Fulcrum, and MariaDB. |
| Protocol overlay | `backend-apis` standalone service. Serves `/api/v1/universe/*` and holds every indexer credential server side. |
| Frontend | `frontend/`, an Angular application served as static files with SPA fallback. |

- See the [`docker/`](./docker/) directory for instructions on deploying Mempool with Docker.
- See the [`backend/`](./backend/) and [`frontend/`](./frontend/) directories for manual install instructions oriented for developers.
- See the [`production/`](./production/) directory for guidance on setting up a more serious Mempool instance designed for high performance at scale.
The browser never talks to an indexer, and no indexer origin or credential is
ever exposed to it. See `docs/architecture/` for the overlay design and
`docs/data/ASSET-EVIDENCE.md` for the evidence contract.

## First-party data policy

No third-party blockchain API, public explorer, hosted indexer, analytics
service, or remote font is called at any point, from the server or the browser.
Collection-level artwork and metadata are the only permitted external sources,
and they are fetched server side and cached.

`node scripts/universe/check-origins.mjs` fails the build if a forbidden origin
appears in the source or in a production bundle. The production build also skips
asset synchronization, so nothing is downloaded from a third party at build time
either; mining pool logos fall back to the bundled default.

## Local development

Requires Node 24.19.0 and npm 11.17.0, both pinned in `.nvmrc` and
`package.json`.

```bash
cd backend && npm ci && npm run build && npm run start
```

```bash
cd frontend && npm ci && npm run serve
```

The frontend proxies `/api` to the backend. To point it at a running deployment
instead, set `MEMPOOL_BACKEND` in `frontend/proxy.conf.json`.

## Testing

```bash
cd frontend && npm run build:universe # production build, no third-party fetches
cd frontend && npm run test # Universe unit suite
cd frontend && npm run lint
cd backend && npm run test:ci && npm run lint
node scripts/universe/generate-protocol-coverage.mjs --check
node scripts/universe/check-text.mjs # no em dash anywhere
node scripts/universe/check-branding.mjs # no obsolete upstream marks
node scripts/universe/check-origins.mjs # no third-party data origins
```

The same checks run in `.github/workflows/universe-ci.yml` on the self-hosted
runner fleet. The branding and origin gates also accept a built bundle path, and
the release workflow runs them against `frontend/dist` before anything ships.

## Configuration

The backend reads `backend/mempool-config.json`. The overlay reads
`UNIVERSE_EXPLORER_SOURCES_JSON`, a JSON array of authority descriptors whose
bearer tokens are named, never embedded:

```json
[{ "authorityId": "ord",
"origin": "http://127.0.0.1:8382",
"bearerTokenEnv": "UNIVERSE_ORD_TOKEN",
"protocols": ["ordinals", "rare_sats", "runes"],
"network": "bitcoin:mainnet" }]
```

Parsing is strict and all or nothing: one invalid descriptor disables the whole
registry rather than serving partially trusted data.

## Deployment

`docs/operations/DEPLOYMENT.md` documents the release procedure. Releases are
deployed beside the running one and the gateway upstream is flipped, so a
rollback is a single flip back. Every deployment publishes its own commit on
`/api/v1/backend-info` and on the public `/source` page.

## Source and licence

Universe Explorer is free software under the
[GNU Affero General Public License, version 3](LICENSE) or later. Section 13
requires that anyone interacting with it over a network can get the
corresponding source, which is what `/source` provides.

This repository is a fork of the upstream Mempool Open Source Project. Upstream
copyright notices and the full licence text in [COPYING.md](COPYING.md) are
preserved. Upstream trademarks are not used: see
`docs/legal/TRADEMARK-AUDIT.md` and `docs/legal/AGPL-COMPLIANCE.md`.

## Upstream relationship

[UPSTREAM.md](UPSTREAM.md) records the exact upstream base, every subsystem this
fork modifies, and the known conflict points. `docs/operations/UPSTREAM-SYNC.md`
is the synchronization procedure. Universe changes are deliberately isolated so
upstream security fixes stay easy to take.

## Security

Report a suspected vulnerability privately to the Bitcoin Universe security
contact rather than opening a public issue. `docs/security/THREAT-MODEL.md`
records the trust boundaries this deployment assumes.

## Contributing

Work happens on `develop`. Open a pull request against it, keep Universe changes
inside `frontend/src/app/universe/` and the documented integration points where
possible, and make sure the checks above pass. [CONTRIBUTING.md](CONTRIBUTING.md)
covers the details inherited from upstream.
12 changes: 12 additions & 0 deletions UPSTREAM.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ synchronization procedure.
| `.github/workflows/universe-ci.yml`, `upstream-sync.yml` | Added. Upstream workflows are unchanged. |
| `scripts/universe/` | Added. Protocol coverage documentation generator and its CI check. |
| `.nvmrc` | Pinned to the Universe toolchain version (24.19.0). |
| `backend/src/index.ts`, `backend/src/config.ts` | `MEMPOOL.HTTP_HOST` added, defaulting to loopback. Upstream binds every interface. |
| `backend/src/api/backend-info.ts` | Publishes the node's own sync state so the explorer can say when its data is behind the chain. |
| `frontend/src/app/services/enterprise.service.ts` | Hosted analytics reduced to a no-op; the upstream redirect on an unknown subdomain removed; no hostname treated as an enterprise subdomain. |
| `frontend/src/app/services/state.service.ts`, `seo.service.ts` | Cross-network links, the services API, and the canonical domain point at this deployment or are unset. |
| `frontend/sync-assets.js`, `frontend/package.json` | `build:universe` omits localization and asset synchronization; the hosted CDN rewrite is removed. |
| Deleted upstream surfaces | `components/about/`, `components/trademark-policy/`, `components/accelerate-checkout/`, `lightning/group/`, the sponsor index variants, and the upstream node fleet scripts. |
| Rewritten upstream surfaces | `components/privacy-policy/`, `components/terms-of-service/`, `docs/api-docs/`. |
| Renamed identifiers | `activeGoggles$`, `goggleCycle`, `goggleIndex` are now `activeLens$`, `lensCycle`, `lensIndex`, so the trademark does not survive minification. |
| Accessibility | Accessible names added to the icon-only navigation, the search submit button, and the blockchain toggles. |
| `scripts/universe/` | Gateway, protocol coverage generator, and the branding, origin, and text gates. |

## Known upstream conflicts

Expand All @@ -53,6 +63,8 @@ synchronization procedure.
| `frontend/src/app/master-page.module.ts` | Upstream edits its route table regularly. The two Universe routes sit at the end of the child route array to keep the conflict small and mechanical. |
| Branding templates | Any upstream change to a rebranded template conflicts by construction. `docs/legal/TRADEMARK-AUDIT.md` lists every touched file so a merge can be resolved deliberately. |
| `frontend/package.json` | The `test` script diverges from upstream. Upstream's value is inert, so upstream's version can be discarded on conflict. |
| Punctuation | Every em dash was removed repository wide, including from inherited READMEs, and `scripts/universe/check-text.mjs` keeps them out. Expect one-character conflicts in those files on sync. |
| Branding edits across upstream components | The trademark work touches many upstream templates. `docs/legal/TRADEMARK-AUDIT.md` lists every one, and the branding gate fails the build if a sync reintroduces a mark. |

The two upstream spec files under `frontend/src/app/lightning/` import from a
path that does not exist in this tree and reference a missing `src/test.ts`.
Expand Down
4 changes: 2 additions & 2 deletions backend/eslint-local-rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ module.exports = {
if (!sym || !Array.isArray(sym.declarations)) return false;

for (const decl of sym.declarations) {
// method, function, property with function type — accept any with @asyncSafe
// method, function, property with function type, accept any with @asyncSafe
if (tsNodeHasJsDocTag(decl, opt.safeTag)) return true;
// for class methods, also check the parent (sometimes the tag is on the signature)
if (decl.parent && tsNodeHasJsDocTag(decl.parent, opt.safeTag)) return true;
Expand Down Expand Up @@ -379,7 +379,7 @@ module.exports = {
context.report({ node, messageId: 'unhandled' });
},

// void someAsyncCall() — only allowed if callee is @asyncSafe
// void someAsyncCall(), only allowed if callee is @asyncSafe
UnaryExpression(node) {
if (node.operator !== 'void') return;

Expand Down
5 changes: 3 additions & 2 deletions backend/mempool-config.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"BACKEND": "electrum",
"ENABLED": true,
"HTTP_PORT": 8999,
"HTTP_HOST": "127.0.0.1",
"SPAWN_CLUSTER_PROCS": 0,
"API_URL_PREFIX": "/api/v1/",
"POLL_RATE_MS": 2000,
Expand Down Expand Up @@ -128,7 +129,7 @@
"PASSWORD": ""
},
"EXTERNAL_DATA_SERVER": {
"MEMPOOL_API": "https://mempool.space/api/v1",
"MEMPOOL_API": "",
"MEMPOOL_ONION": "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1",
"LIQUID_API": "https://liquid.network/api/v1",
"LIQUID_ONION": "http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1"
Expand All @@ -152,7 +153,7 @@
]
},
"MEMPOOL_SERVICES": {
"API": "https://mempool.space/api/v1/services",
"API": "/services",
"ACCELERATIONS": false
},
"STRATUM": {
Expand Down
6 changes: 3 additions & 3 deletions backend/mempool-config.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"BACKEND": "none",
"ENABLED": true,
"HTTP_PORT": 8998,
"HTTP_HOST": "127.0.0.1",
"SPAWN_CLUSTER_PROCS": 0,
"API_URL_PREFIX": "/api/v1/",
"POLL_RATE_MS": 2000,
Expand Down Expand Up @@ -128,7 +129,7 @@
"PASSWORD": ""
},
"EXTERNAL_DATA_SERVER": {
"MEMPOOL_API": "https://mempool.space/api/v1",
"MEMPOOL_API": "",
"MEMPOOL_ONION": "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1",
"LIQUID_API": "https://liquid.network/api/v1",
"LIQUID_ONION": "http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1"
Expand All @@ -147,7 +148,7 @@
"SERVERS": []
},
"MEMPOOL_SERVICES": {
"API": "https://mempool.space/api/v1/services",
"API": "/services",
"ACCELERATIONS": false
},
"STRATUM": {
Expand All @@ -160,4 +161,3 @@
"API_KEY": ""
}
}

Loading
Loading