- Rust 63.6%
- TypeScript 30.2%
- Shell 4.6%
- JavaScript 1.1%
- PLpgSQL 0.2%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .agent-loop | ||
| .agents/skills/canary-issue-loop | ||
| .claude/agents | ||
| .github | ||
| backend | ||
| docs | ||
| frontend | ||
| screenshots | ||
| scripts | ||
| .gitignore | ||
| .gitleaks.toml | ||
| .node-version | ||
| agent-reference.md | ||
| AGENTS.md | ||
| ELASTIC-LICENSE-2.0.txt | ||
| LICENSE.md | ||
| README.md | ||
| rust-toolchain.toml | ||
Canary with BLAKE2b proof of work
This is an unofficial fork of Canary that follows the BLAKE2b proof-of-work hardfork of Bitcoin. It is not affiliated with the Canary project. Upstream has not adopted the fork, so use upstream instead if that is what you want.
Not reviewed by upstream. Everything below the divider is upstream's documentation and describes Canary rather than this fork.
What differs from upstream
Nothing in Canary's own code. Past the hardfork's activation height a block header is 164 bytes and its id is a BLAKE2b hash rather than 80 bytes and SHA256d; stock rust-bitcoin parses 80 and rejects the rest, so every header lookup fails with parse failed: data not consumed entirely when explicitly deserializing, no wallet syncs, and the queue backs up indefinitely.
The fix is entirely in the dependencies, pinned by immutable git rev in backend/Cargo.toml:
| Crate | Fork | What it adds |
|---|---|---|
bitcoin |
privkeyio/rust-bitcoin | The extended 164 byte header and its BLAKE2b block id |
electrum-client |
privkeyio/rust-electrum-client | Splits a batch of concatenated headers by length rather than a fixed 80 byte stride |
bdk_wallet and bdk_electrum need no fork; they inherit the fix through bitcoin. A build guard in backend/src/lib.rs fails the build outright if the patched crates are ever missing, rather than letting the mis-parse surface at runtime past the activation height.
Requires a Knots-backed Electrum server
Only Bitcoin Knots schedules the hardfork, and only a BLAKE2b-aware Electrum server serves the extended headers. A standard Fulcrum stops at the activation block rather than serving wrong data, and Electrs has no build that understands the new form at all.
Branches
| Branch | Base | Use |
|---|---|---|
master |
upstream master |
The fork's line. Carries the dependency patches. |
Verification
The whole chain is verified against a live Knots-backed Electrum server, and backend/system_tests/blake2b_hardfork_headers.rs drives the real client over a socket against a fake one, asserting both the recombined timestamp and the BLAKE2b block id. Removing the bitcoin patch reproduces the production error exactly. The electrum-client patch is not covered by that test: it rewrites the pre-1.6 concatenated-header path, and a server advertising protocol 1.6, which Fulcrum does, takes the array path instead.
Canary Wallet
Canary Wallet is a Bitcoin monitoring and early warning system built in Rust using BDK (Bitcoin Development Kit) with a Next.js frontend. It provides real-time transaction intelligence, advanced pattern recognition (RBF, CPFP, consolidation), and instant multilingual notifications for Bitcoin wallet activity - designed specifically for monitoring cold storage and Bitcoin holdings you don't actively use.
Why Use Canary Wallet?
A canary in the cold mine - When your bitcoins are in cold storage, you seldom check on them. Canary Wallet acts as an early warning system that alerts you the moment your coins move, giving you immediate notification of any activity on your wallets.
Screenshots
Empty Wallets
Start with a clean watch-only wallet list and add your first wallet when you are ready.
Start from an empty wallet list and add the first watch-only wallet.
Add a Wallet
Select your wallet type from popular software wallets (Sparrow, BlueWallet, Electrum) or hardware wallets (ColdCard, Ledger, Trezor). Single-sig and multisig watch-only wallets are both supported. Canary Wallet only needs read-only access to monitor transactions - your private keys stay safe in your wallet.
Add a read-only descriptor for a wallet named Test.
Step-by-Step Setup
Follow wallet-specific instructions to export your output descriptor or XPUB. Each supported wallet has tailored guidance to make setup easy.
Follow the Sparrow-specific guide to export a descriptor safely.
Wallet Dashboard
View your balance in BTC and fiat and see your complete transaction history with send/receive indicators.
Monitor balances, pending activity, and transaction details from one dashboard.
Notifications
Give each contact its own delivery methods, transaction rules, balance alerts, and message-content privacy level.
Review notification behavior at a glance and open the editor only when changes are needed.
Settings
Customize your language preference (9 languages supported) and fiat currency display. Exchange rates update automatically via CoinGecko.
Configure appearance, regional preferences, transaction explorer, and ntfy notifications.
Key Features
Watch-only wallets
- Single-sig and multisig wallets
- Output descriptors, XPUBs, and individual addresses
- No seed phrases or private keys
Transaction Monitoring
- Sending and receiving bitcoin notifications
- Transaction confirmation alerts
- RBF (Replace-By-Fee) detection - fee bumping notifications
- CPFP (Child-Pays-For-Parent) detection - transaction acceleration notifications
Balance Alerts
- Configurable threshold alerts (above/below/equals)
- Support for both BTC and fiat currency thresholds
- Smart crossing detection to prevent notification spam
- Auto-disable after firing with manual reactivation
Notifications
Real-time notifications in 9 languages via ntfy push (default public server ntfy.sh, or a local server such as the Umbrel ntfy app), encrypted Nostr DMs, self-hosted JSON webhooks, and optional Telegram bot messages.
canarybitcoin.com additionally supports SMS (via Twilio) and Email (via Resend) notifications.
Supported Languages: English, Norwegian, Spanish, Portuguese, German, French, Japanese, Danish, Swedish
Umbrel / Docker note: On Umbrel, Canary Wallet auto-detects the local ntfy app through the Docker-internal URL provided by the Umbrel package. You should not need to enter
http://ntfy_app_1manually. Use "Send Test Notification" in Settings to verify your configuration.
With CANARY_MODE=self-hosted, custom ntfy URLs can use Docker-internal names (such as http://ntfy on a shared Docker network), LAN addresses (such as http://192.168.1.20:8080), and Tailscale addresses or MagicDNS names (such as http://100.64.0.10:8080). This works on Umbrel, StartOS, myNode, and standalone Docker without an extra flag. Existing saved private URLs work after upgrading. The Canary backend must be able to resolve the hostname and reach the server; browser access alone is insufficient. Loopback addresses refer to the backend's own network namespace. Link-local metadata and other special-purpose addresses remain blocked for custom servers. Custom self-hosted ntfy connections bypass HTTP proxy environment settings to connect directly to validated addresses. Detected integrations and operator defaults retain their existing connection behavior.
StartOS note: StartOS packages can provision a scoped local ntfy publisher and pass it to Canary Wallet with
CANARY_NTFY_SERVER_URL,CANARY_NTFY_TOKEN, andCANARY_NTFY_TOPIC. These values are used as defaults; settings saved in Canary Wallet remain authoritative.Nostr .onion relays: NIP-17 delivery to
.onioninbox relays needs system Tor (or equivalent SOCKS5). SetCANARY_NOSTR_SOCKS_PROXYto the SOCKS port, typically127.0.0.1:9050. Public clearnet relays keep using a direct connection.
Self-Hosted vs. canarybitcoin.com
| Self-Hosted | canarybitcoin.com | |
|---|---|---|
| Users | Single user, no auth required | Multi-user with email/password authentication |
| Notifications | ntfy + Nostr DM + JSON webhook + Telegram | ntfy + SMS + Email |
| Billing | Free | Subscription plans (Personal & Team) |
| Wallet sync | Fixed interval | Tier-based (faster sync on higher plans) |
Quick Start
Prerequisites
- Rust toolchain
- Node.js 18+
- Docker and Docker Compose (for local Bitcoin regtest)
Configuration
# Backend - choose your mode
cd backend
cp .env.example.self-hosted .env # or .env.example.cloud
# Frontend
cd frontend
cp .env.example.self-hosted .env.local # or .env.example.cloud
Development
# Start local Bitcoin regtest environment
cd scripts && docker-compose up -d
# Start backend (requires Stripe CLI for cloud mode)
cd backend && cargo run
# Start frontend
cd frontend && pnpm dev
Development & Testing
Displaying Git Version in Footer
The frontend displays the git version and commit hash in the footer. To generate this build info locally:
# Generate build info (creates src/lib/build-info.json)
cd frontend && node scripts/generate-build-info.js
# Then start the dev server
pnpm dev
The footer will display in format: v0.13.0 • 5e66fe3 (tag and commit) or just the commit hash if no tag exists.
Note: The build info is automatically generated during production builds via the webpack configuration. For local development, you need to run the script manually.
Running System Tests
The project includes comprehensive system tests that use Docker to create isolated Bitcoin regtest environments. These tests cover:
- Advanced Transactions: RBF (Replace-By-Fee) and CPFP (Child-Pays-For-Parent) scenarios
- High Index Scanning: Deep wallet address discovery for funds at high indexes
- Direct Mining: Transactions that get mined directly without mempool delays
- Two-Stage Scenarios: Complex transaction flows with multiple confirmations
- Balance Alerts: Threshold-based balance monitoring
Prerequisites
- Docker and Docker Compose installed
- Rust toolchain for building
Run All System Tests
# Run all system tests (sequential to avoid Docker conflicts)
cd backend
cargo test --test advanced_transactions --test mined_directly_scenarios --test two_stage_send_scenarios --test high_index_scanning --test balance_alert_scenarios -- --ignored --test-threads=1
Run Individual Test Categories
cd backend
# Advanced transactions (RBF, CPFP) - 3 tests
cargo test --test advanced_transactions -- --ignored
# High index scanning - 1 test
cargo test --test high_index_scanning -- --ignored
# Mined directly scenarios - 3 tests
cargo test --test mined_directly_scenarios -- --ignored
# Two-stage send scenarios - 3 tests
cargo test --test two_stage_send_scenarios -- --ignored
# Balance alert scenarios
cargo test --test balance_alert_scenarios -- --ignored
Note: System tests must run sequentially (--test-threads=1) to avoid Docker resource conflicts between parallel test environments.
Documentation
See CLAUDE.md for comprehensive documentation including:
- API endpoints
- Database schema
- Notification setup
- Stripe integration
- Architecture details
See JSON webhook notifications for the self-hosted webhook contract and deployment guidance.
See Telegram Bot notifications for bot token setup and destination rules.
License
See LICENSE.md for license information.