Non-custodial multi-currency wallet for Telegram, Discord, and the web.
- GitHub Releases - Manual install
- Chrome Web Store - Coming soon
See docs/installation.md for installation instructions.
- Non-custodial: Your keys never leave your device
- Multi-currency: BTC, LTC, XMR, WOW, GRIN
- Social media tipping: Tip users by Telegram or Discord username
- Encrypted tips: Tips targeted at specific users are encrypted with their public key
- Website integration:
window.smirkAPI for web apps (like MetaMask'swindow.ethereum)
src/
├── background/ # Service worker (modular)
│ ├── index.ts # Message routing
│ ├── state.ts # Global state, session persistence
│ ├── wallet/ # Wallet lifecycle (modular)
│ │ ├── create.ts # Mnemonic generation, wallet creation
│ │ ├── restore.ts # Wallet restoration
│ │ ├── session.ts # Unlock/lock, auth
│ │ └── security.ts # Seed reveal, password change
│ ├── grin/ # Grin WASM operations (modular)
│ │ ├── send.ts # Send flow (create, finalize)
│ │ ├── receive.ts # Sign incoming slatepacks
│ │ └── invoice.ts # RSR invoice flow
│ ├── social/ # Social tipping (modular)
│ │ ├── create.ts # Tip creation
│ │ ├── claim.ts # Tip claiming
│ │ └── sweep.ts # Unified sweep logic
│ ├── balance.ts # Balance queries for all assets
│ ├── send.ts # BTC/LTC transaction building
│ └── tips.ts # Tip decryption and claiming
├── content/ # Content script - injects window.smirk
├── inject/ # Injected script - window.smirk API implementation
├── popup/ # Main UI (Preact components)
├── lib/
│ ├── crypto.ts # BIP39, BIP44 key derivation
│ ├── xmr-tx.ts # XMR/WOW transaction signing via WASM
│ ├── btc-tx.ts # BTC/LTC transaction signing
│ ├── grin/ # Grin wallet (client-side WASM)
│ └── api/ # Backend API client (modular)
│ ├── client.ts # Base HTTP client, retry, timeout
│ ├── parse.ts # Response validation, snake→camel
│ ├── auth.ts # Authentication methods
│ ├── social.ts # Social tipping methods
│ ├── grin.ts # Grin wallet methods
│ ├── wallet-lws.ts # XMR/WOW light wallet methods
│ └── index.ts # Combined API client
└── types/ # TypeScript types
- Password-protected keys: All private keys are encrypted with your password
- Keys never leave extension: Crypto operations happen in the background script
- ECDH for encrypted tips: Sender uses recipient's public key for encryption
- URL fragment for public tips: Key in
#fragmentnever sent to server
| Chain | Key Type | Notes |
|---|---|---|
| BTC | secp256k1 (BIP44) | Balance via Electrum |
| LTC | secp256k1 (BIP44) | Balance via Electrum |
| XMR | ed25519 | View key registered with LWS |
| WOW | ed25519 | Same as XMR |
| GRIN | secp256k1 | Interactive transactions via slatepack |
Cryptographic operations run client-side via WebAssembly. All keys stay in your browser.
From Nicolas Flamel's MWC Wallet:
| Library | Source | Purpose |
|---|---|---|
| secp256k1-zkp | GitHub | Elliptic curve + zero-knowledge proofs |
| Ed25519 | GitHub | Digital signatures |
| X25519 | GitHub | Key exchange |
| BLAKE2b | GitHub | Cryptographic hashing |
Custom WASM built from Rust:
| Library | Source | Purpose |
|---|---|---|
| smirk-wasm-monero | GitHub | Transaction signing, key images |
| monero-oxide | GitHub | Monero protocol implementation |
All source code is open. See docs/building.md for compilation instructions.
The extension injects a window.smirk API into web pages:
if (window.smirk) {
// Request connection (shows approval popup)
const publicKeys = await window.smirk.connect();
// Returns: { btc, ltc, xmr, wow, grin }
// Request message signature
const result = await window.smirk.signMessage('Sign to authenticate');
// Returns: { message, signatures: [{ asset, signature, publicKey }] }
// Disconnect
await window.smirk.disconnect();
}See docs/building.md for build instructions and store submission guides.
MIT