Current release: v1.0 — Self-custodial EVM wallet as a browser extension: vault password, encrypted multi-wallet vault, EIP-1193 / EIP-6963 for dApps, React popup UI. Built on the Tether Wallet Development Kit (WDK), WXT, and React 19.
The npm/extension manifest version is 1.0.0 (see package.json). Larger roadmap items are tracked below.
- Non-custodial: mnemonic stays on-device; encrypted with your vault implementation (
lib/crypto/vault.ts). - EVM via
@tetherto/wdk-wallet-evm, ethers.js 6, BIP-39 mnemonics. - Extension: WXT (Chrome MV3, Firefox), background session + messaging (
lib/transport/). - dApps: EIP-1193 provider + EIP-6963 announcement (
entrypoints/inpage.ts,lib/providers/). - UI: React 19, Tailwind v4, shadcn-style components.
Assets live under docs/assets/v1.0/.
Demo video
- Full flow demo
Onboarding, wallets, networks, and typical popup interactions.
Screenshots
- Set vault password
Choose the password that encrypts every wallet in your vault.
- Create a new wallet
Generate a fresh recovery phrase for your first or additional wallet.
- Import with recovery phrase
Paste a BIP-39 phrase to add another wallet (masked in the UI).
- Wallet home
Active account, balance, network, and lock / add-wallet actions.
- Switch wallet
Pick which saved wallet is active in the extension.
- Switch network
Choose the EVM chain used for balance and dApp requests.
- Node.js — see
.nvmrcfor the recommended version (project CI/tooling aligned with Vite / WXT).
- WDK —
@tetherto/wdk-wallet-evmfor EVM / BIP-39 / BIP-44 style usage - ethers.js 6 — RPC / ABI helpers
- bip39 — mnemonic generation and validation
- WXT — build, HMR, cross-browser targets
- TypeScript 5.9 — strict
- Tailwind CSS v4, shadcn/ui-style components, CVA, lucide-react
- Vitest + Testing Library — unit / component tests
- EVM wallet core (
@tetherto/wdk-wallet-evm) with BIP-39 create / import - Vault password and encrypted vault (PBKDF2 + AES-256-GCM —
lib/crypto/vault.ts) - Multi-wallet vault: add wallets, switch active wallet, duplicate-import guard
- Popup flows: onboarding, unlock, lock, balance display
- EIP-1193 (
window.ethereum) + EIP-6963 wallet discovery - Chain/network switching (configured chains in
lib/network/network-config.ts) - Background ↔ popup messaging (
lib/transport/+entrypoints/background.ts) - Automated tests (Vitest)
- Lock wallet — dedicated lock control in the popup plus auto-lock after idle timeout
- Active wallet sync with dApps — if the user changes the active wallet while a tab is connected, propagate the update to the in-page provider without forcing a full page reload
- Other networks — Solana, TRON, Bitcoin, and additional chains (via WDK modules or dedicated integrations as they land)
- Settings page — preferences UI (e.g. RPC overrides, display options, security toggles)
- Richer transaction UX — full
eth_sendTransaction/ signing flows beyond demo limitations - More features — hardware wallets, address book, token lists, i18n, etc.
(Roadmap will grow as development continues.)
- Vault format and KDF details live in
lib/crypto/vault.ts(PBKDF2 + AES-GCM). - Persistence uses WXT storage (
lib/storage/vault-storage.ts), not rawchrome.storagecalls everywhere. - Isolation: inpage → content → background; signing/decryption happen in the background context.
See inline comments in entrypoints/ and lib/session/ for session lock and multi-wallet flows.
The name and EIP-6963 icon shown to dApps are configured in lib/branding.ts; the JPEG bytes match public/icon.jpeg via lib/wallet-provider-icon.ts (regenerate that file after replacing the JPEG).
./
├── entrypoints/
│ ├── popup/
│ │ ├── components/ # Forms, wallet views, network selector, etc.
│ │ ├── App.tsx
│ │ ├── main.tsx
│ │ └── index.html
│ ├── background.ts # Service worker, session + alarms
│ ├── content.ts # Bridge page ↔ extension
│ └── inpage.ts # EIP-1193 / EIP-6963 injection
├── lib/
│ ├── crypto/ # Vault encrypt/decrypt
│ ├── storage/ # Multi-wallet vault persistence (WXT storage)
│ ├── session/ # WalletSession, unlock/lock, restore
│ ├── providers/ # EIP-1193, EIP-6963 helpers & tests
│ ├── transport/ # Message types + MessageHandler
│ ├── balance/ # Balance helpers
│ ├── network/ # Chain config & switching
│ ├── wallet/ # Mnemonic normalization / validation
│ ├── utils.ts
│ └── index.ts # Library exports
├── components/
│ └── ui/ # Shared UI primitives (e.g. Button)
├── assets/
│ └── tailwind.css
├── public/ # Static assets (e.g. icon.jpeg for auto-icons)
├── docs/
│ └── assets/
│ └── v1.0/ # README screenshots + demo video for v1.0
├── chrome-extension.d.ts # Chrome global typings reference
├── components.json # shadcn/ui config
├── wxt.config.ts
├── vitest.config.ts
├── tsconfig.json
├── package.json
├── README.md
└── LICENSE
Build output is generated under .output/ (not committed).
npm install
# Dev (Chrome target by default)
npm run dev
npm run dev:firefox
# Production build
npm run build
npm run build:firefox
# Store-ready zips
npm run zip
npm run zip:firefox
# Types & tests
npm run compile
npm run test # vitest watch
npm run test:run # CI-style single runnpm run buildchrome://extensions/→ Developer mode → Load unpacked- Choose
.output/chrome-mv3/
npm run build:firefoxabout:debugging#/runtime/this-firefox→ Load Temporary Add-on- Pick a file under
.output/firefox-mv3/
- EIP-1193 — Ethereum provider API
- EIP-6963 — Multi-wallet discovery
- BIP-39 — Mnemonics
- BIP-44 — HD paths
MIT — see LICENSE.
- WDK and starter patterns: Tether WDK / base58-io starter.
- WXT: wxt.dev.





