Skip to content

About

A self-hosted, watch-only Bitcoin workbench for people who want to understand their wallets and follow activity on chain.

Resources

Contributing

Security policy

Stars

4 stars

Watchers

1 watching

Forks

Latest commit

 

History

490 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Chaingraph

Chaingraph is a self-hosted, watch-only Bitcoin workbench for people who want to understand their wallets and follow activity on chain.

It runs against your Bitcoin Core node and Electrum server. Workspace contents are saved encrypted in your browser; workspace names remain public. Saved records also work without a chain connection. A separate static demo build provides three prepared public-data examples without a backend.

Chaingraph is not a custodial wallet or a public service. It never touches private keys, cannot sign or spend, and does not identify people.

What you can do

  • Explore transactions. Look up a transaction, address or output in a chronologically ordered 3D or flat graph. Filter the view, follow funding and spending links, and inspect bounded address history.

  • Review wallets. Import one or more watch-only wallets from an account-level extended public key. Review transactions, coins, addresses and counterparties with wallet net changes and linked findings. Chaingraph derives addresses in your browser and refreshes wallet history from your own nodes. Coverage distinguishes incomplete observations from completed checks.

  • Annotate activity. Add labels, notes, bookmarks and tags to transactions, outputs and addresses. Undo and redo edits without rolling back accepted chain refreshes in the current session. Compare conflicting BIP329 entries before applying imports and inspect exports as a table or exact JSONL, with profiles for Sparrow, BTCPay Server, BlueWallet, Bitcoin Keeper and generic files. Labels support 255 characters; profiles preserve tags or transaction notes where the destination supports them. Try the example exchange files with the public demo wallet.

  • Run analysis. Use seven local tools to find patterns in outputs, inputs, address reuse, value flow, scripts and wallet overlap. Findings link to evidence and remain hypotheses, not proof of ownership.

  • Scan connections. Search loaded graph data for funding and spending paths, shared ancestors and descendants, and loops. Results are bounded observations you can add to the graph.

  • Start from examples. Open nine bundled mainnet and testnet4 workspaces with public transaction snapshots and starter annotations. They require no downloads and appear only for configured networks.

Requirements

  • A Bitcoin Core node and an Electrum server (Fulcrum is what Chaingraph is tested with) for mainnet, testnet4, or both. Each network uses its own pair.
  • Node.js 24 or newer for a native install, or Docker with Compose v2.
  • A modern browser with WebGL. Encrypted workspaces need a secure context, so use localhost or HTTPS.

Install

Run from source

npm ci
cp -n .env.example .env.testnet4  # or .env.mainnet, or both
chmod 600 .env.testnet4
# Edit the file with your Bitcoin Core RPC and Electrum connection details.
npm run dev

Open http://127.0.0.1:3001. The backend reads .env.mainnet and .env.testnet4 from its working directory (or CHAINGRAPH_NETWORK_CONFIG_DIR) and needs at least one of them. The file name selects the network. RPC accepts a user/password pair or a cookie file; see .env.example.

For a production build served from one origin:

npm run build
npm start      # http://127.0.0.1:3000, or SERVER_PORT

Run with Docker

mkdir -p config
cp -n .env.example config/.env.testnet4
chmod 750 config && chmod 640 config/.env.testnet4
sudo chgrp 1000 config config/.env.testnet4
# Edit config/.env.testnet4; container loopback is the container itself.
docker compose --env-file /dev/null up --build -d

Open http://127.0.0.1:3000. The container runs as an unprivileged user with a read-only filesystem, and Compose publishes the port on loopback only. HTTPS, private certificate authorities, cookie authentication and upgrades are covered in the deployment guide.

Validating a release

Each public container release has a signed source tag and a signed mapping that names its exact immutable image digest. Do not install from a mutable image tag.

1. Import the release key once

If you have already imported and checked this key, skip to step 2. Otherwise, download the Chaingraph public key and inspect it:

curl -fsSLo chaingraph-release-key.asc https://github.com/remcoros.gpg
gpg --show-keys --keyid-format long --with-fingerprint chaingraph-release-key.asc

It must show this primary fingerprint:

pub   ed25519/2F5B10B929CAC959 2024-10-28 [SC]
      Key fingerprint = 9D1B D304 339B 2D31 CFA5  637A 2F5B 10B9 29CA C959
uid                     Remco Ros (github.com/remcoros) <remcoros@live.nl>

Compare that fingerprint with a copy you trust. Only if it matches, import the key:

gpg --import chaingraph-release-key.asc

2. Verify a release

Verify both the source tag and the release mapping:

TAG=v0.1.0
git fetch --force origin "refs/tags/$TAG:refs/tags/$TAG"
git verify-tag "$TAG"
ASSET="chaingraph-$TAG.release.json"
BASE_URL="https://github.com/remcoros/chaingraph/releases/download/$TAG"
curl -fsSLO "$BASE_URL/$ASSET" "$BASE_URL/$ASSET.asc"
gpg --verify "$ASSET.asc" "$ASSET"

Both checks should include output like this. The date and timezone will differ:

gpg: Signature made ...
gpg:                using EDDSA key 9D1BD304339B2D31CFA5637A2F5B10B929CAC959
gpg: Good signature from "Remco Ros (github.com/remcoros) <remcoros@live.nl>" [unknown]
Primary key fingerprint: 9D1B D304 339B 2D31 CFA5  637A 2F5B 10B9 29CA C959

GnuPG may warn that the key is not certified with a trusted signature. That means you have not marked it trusted locally; still require the fingerprint above. Confirm that the mapping's source commit equals git rev-parse "$TAG^{commit}", then deploy image.name@image.indexDigest from the mapping as CHAINGRAPH_IMAGE. The deployment guide covers that path. Advanced users can rebuild and compare a native OCI descriptor.

Using Chaingraph

The user guide walks through workspaces, wallets, the graph, annotations, analysis, connection scans and backups. A short guided tour is built into the app and can be restarted from Help.

Create a workspace with a public name and a password. Everything else in it (description, wallets, loaded transactions, annotations, analysis results and your view) is encrypted before it reaches browser storage. Workspaces save automatically and can be exported as encrypted files for backup or transfer.

Data and trust

  • The backend is a read-only proxy to your Bitcoin Core RPC and Electrum server. It keeps no database, wallet, index, or cache of anything you look up. The proxy and your upstream services do see the script hashes and transaction IDs you look up.
  • Address derivation, scanning, analysis and encryption happen in the browser. Extended public keys are never sent to the backend as a wallet import.
  • Saved workspaces use AES-256-GCM with a PBKDF2-SHA256 derived key. Passwords live only in the unlocked browser tab. There is no recovery: keep encrypted exports and remember your password.
  • BIP329 metadata exports are plaintext. Key labels and extended public keys are included only when explicitly selected. Use encrypted workspace exports to preserve the complete workspace.
  • The backend has no login and binds to loopback by default. It is meant for one trusted user on a trusted machine or behind your own authenticated HTTPS proxy. Public or shared backend hosting is not supported. The static demo serves captured public data and has no chain backend.

Limits

  • Wallet import supports single-key account keys at depth 3 with legacy, nested SegWit, native SegWit and Taproot scripts. Descriptors, multisig, private keys, signing and spending are out of scope.
  • Loaded data is a snapshot. Scans, history and expansion are bounded, and a partial result never proves that nothing else exists. A missing spend means unknown, not unspent.
  • Heuristics are hypotheses. Common-input ownership can be wrong, CoinJoin detection is incomplete, and no tool identifies a person or proves a wallet owns anything.
  • Workspaces are stored per browser origin and subject to browser quotas. Export backups before large investigations.

Documentation

License

MIT license. Third-party dependency notices are in THIRD_PARTY_NOTICES.md.

About

A self-hosted, watch-only Bitcoin workbench for people who want to understand their wallets and follow activity on chain.

Resources

Contributing

Security policy

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages