Browser extension wallet for Counterparty on Bitcoin.
- Multiple wallets and address types (SegWit, Taproot, Legacy)
- Send/receive BTC and Counterparty assets
- Create dispensers and DEX orders
- Provide liquidity to AMM pools (deposit/withdraw)
- UTXO consolidation
- Issue and manage assets
- Connect to dApps via provider API
- BIP-322 message signing
- Hardware wallet support (Trezor)
Not yet independently audited. See AUDIT.md for our self-reported security feature checklist.
Key protections:
- AES-256-GCM encryption with PBKDF2 (600k iterations)
- Local transaction verification (detects malicious API responses)
- Audited crypto libraries (noble family, Cure53 audited)
- Minimal permissions, MV3 strict CSP, no remote code
- Hardware wallet support: private keys never leave device
Does not protect against: compromised OS, malicious extensions with higher privileges, physical access to unlocked device.
Report vulnerabilities via GitHub Security Advisories or see our bug bounty.
We intentionally minimized runtime dependencies—most wallets ship dozens, we ship 14. What remains is carefully vetted.
| Package | Purpose |
|---|---|
| @noble/curves, @noble/hashes, @scure/* | Audited cryptography |
| bignumber.js | Arbitrary precision arithmetic |
| react, react-router | UI framework |
| @headlessui/react | Accessible components |
| webext-bridge | Extension messaging |
npm install # plain install — never --legacy-peer-deps, it prunes @testing-library/dom
npm run dev # Chrome
npm run dev:firefoxAfter changing package.json or package-lock.json, run:
npm run check:lockfileCI installs with npm ci, which builds from the lockfile alone and fails if it
does not record everything the tree needs. lint, compile and the test suite
all run against your existing node_modules, so they pass either way — this is
the only local check that catches a lockfile drift before CI does.
npm run build # Production build
npm run zip # Create extension ZIPnpm version X.Y.Z --no-git-tag-version # bumps package.json AND package-lock.json
npm run zip # .output/xcp-wallet-X.Y.Z-chrome.zipBump with npm version, not by editing package.json. The lockfile records the version
too, and CI builds from the lockfile alone.
The Chrome Web Store package is uploaded manually through the developer dashboard. Note that a new submission replaces any pending review rather than queueing behind it, so check that the previous version has published before uploading the next one.
npm test # All tests
npm run test:unit # Unit only
npm run test:e2e # E2E onlyTelegram for support, feedback, and discussion.
MIT