
Using @charmbracelet to create an Ethereum browser with style
A beautiful, terminal-based Ethereum wallet and smart contract browser built for sovereignty, security, and style.
━━━━━━━━━━━━━━━━━━━━
domestic system
━━━━━━━━━━━━━━━━━━━━

The Domestic System is a terminal user interface (TUI) designed for browsing Ethereum (EVM) accounts and smart contracts. It brings together three core principles that make terminal-based blockchain interaction not just practical, but preferable.
Client-side only. No centralized servers. Just you and the blockchain.
The Domestic System connects directly to Ethereum RPC endpoints of your choosing. No intermediaries. No analytics. No tracking. Your interaction with the blockchain is direct and unmediated. This is how Web3 was meant to work.
No private key management. Hardware wallet ready.
Your private keys never touch this application. All transactions are generated as QR codes following EIP-4527, designed specifically for signing with hardware wallet devices. View your accounts, prepare transactions, and sign them safely on your hardware wallet.
Built with Charm.sh. Terminal interfaces, beautifully done.
Using the gorgeous Charm.land ecosystem (Bubble Tea, Lip Gloss, Huh), The Domestic System proves that CLIs don't have to be austere. Rich colors, smooth interactions, and thoughtful UI design bring a retro-future aesthetic to blockchain interaction.
These three principles—sovereignty, security, and aesthetics—converge perfectly in the terminal. Terminal applications are:
The Domestic System occupies a unique intersection of niche use cases, serving those who value control, security, and craft.
git clone https://github.com/yourusername/domestic-system.git
cd domestic-system
go build
go run .
The Domestic System stores its configuration in ~/.charm-wallet-config.json.
Add Ethereum RPC endpoints in the "s" settings page or by setting the ETH_RPC_URL environment variable:
export ETH_RPC_URL="https://eth.llamarpc.com"
go run .
Customize which ERC-20 tokens to display by editing the token watchlist in main.go (UI configuration coming soon).
x from Accounts): Manage signing keys, scan EIP-4527 QR codes via webcam, and sign transactionsa to add a new walletThe active account (marked with ★) determines which wallet is used for transactions. To switch accounts:
Alternatively, navigate to the Wallets page and press Enter on any wallet to view its details and activate it.
The Domestic System includes a full EIP-4527 transaction signing workflow usable both inside the TUI and independently from the terminal.
TUI (any page) → packages unsigned tx → displays EIP-4527 QR code
↓
Signer page scans QR via webcam
↓
Decodes UR → signs with stored key
↓
Displays raw signed transaction hex
Keys are stored in ~/.charm-wallet-private-keys.json (mode 600, outside the repo). On first run a NotForProduction demo key is bootstrapped automatically and its address is registered in ~/.charm-wallet-config.json.
{
"private_keys": [
{
"address": "0x29c73B201bEE86C4d1Fe4f598C4355Bb210251e3",
"name": "NotForProduction",
"private_key": "0xc0054..."
}
]
}
Press x from the Accounts page to open the Signer. From there:
The signed transaction (raw hex, tx hash, r/s/v) is shown immediately after scanning.
signer/eth_signer.py)The Python signer runs independently without the TUI. Install dependencies once:
pip install -r requirements.txt
All output is JSON. The --scan mode opens an OpenCV window showing the live camera feed and emits signed transactions to stdout as they are detected.
cmd/txtest)Exercises the full pack → decode → sign round-trip using the Go modules directly:
# Offline (hardcoded test params — no RPC needed)
go run ./cmd/txtest
# With live nonce/gasPrice/chainId from an RPC endpoint
go run ./cmd/txtest --rpc https://eth.llamarpc.com
# Custom recipient and amount
go run ./cmd/txtest --to 0xYourAddr --value 0.5 --chainid 11155111
Output shows both steps clearly:
STEP 1 — Pack unsigned transaction (EIP-4527)
─────────────────────────────────────────────
Transaction fields: { "from": "0x29c7...", "to": "0xd8dA...", ... }
UR: ur:eth-sign-request/onadtpdagd...
STEP 2 — Decode + sign with stored key
───────────────────────────────────────
Decoded transaction: { "from": "0x29c7...", "value": "0.001000 ETH", ... }
Signed transaction: { "txHash": "0x5989...", "raw_transaction": "0xf86b...", ... }
✓ Round-trip complete
ss -ntlp | grep 8545
ssh -N -L 8545:localhost:8545 user@node_machine_ip_address #for http
ssh -N -L 8546:localhost:8546 user@node_machine_ip_address #for ws websocket
Your application, running on the app machine, can now access the Ethereum node's RPC via http://localhost:8545
go run helpers/uniswap_v4_listener.go -ws -poolmanager
[-from ]go run ./cmd/v4listener
-ws ws://localhost:8546
-poolmanager 0x000000000004444c5dc75cB358380D2e3dE08A90
go run ./cmd/v4listener
-ws ws://localhost:8546 \ #or ws://mainnet.infura.io/ws/v3/YOUR_KEY
-poolmanager 0x000000000004444c5dc75cB358380D2e3dE08A90
-from 21688000
domestic-system/
├── main.go # Entry point — wires Bubble Tea program
├── model.go # App state struct + Init()
├── update.go # All Update() message handlers
├── view.go # Top-level View() dispatch
├── cmd/
│ ├── txtest/ # End-to-end pack → sign test CLI
│ └── v4listener/ # Standalone Uniswap V4 event listener
├── config/ # JSON config load/save, type definitions
├── helpers/ # ENS resolution, address formatting, Uniswap V2/V4
├── rpc/ # Ethereum RPC client, EIP-4527 transaction packaging
├── signer/
│ ├── signer.go # Go package: key management, EIP-4527 decode, ECDSA sign
│ └── eth_signer.py # Standalone Python CLI (same functionality)
├── styles/ # Lip Gloss colors and shared styles
├── views/ # Per-page renderers
│ ├── wallets/
│ ├── details/
│ ├── settings/
│ ├── dapps/
│ ├── uniswap/
│ ├── terra/
│ └── signer/ # Signer page renderer
└── webcam/ # Camera capture and half-block video rendering
# RPC package tests (requires RPC endpoint)
ETH_RPC_URL="https://eth.llamarpc.com" go test ./rpc -v
# All tests
go test ./... -v
Contributions are welcome! This project values:
Please open an issue before starting major work.
MIT License - See LICENSE file for details
Built with:
Inspired by the ethos of self-sovereignty and the aesthetics of retrocomputing.
The Domestic System: Your terminal, your keys, your blockchain.
| Key | Action |
|---|
↑/↓ | Select signing key |
s | Open webcam — auto-signs the first EIP-4527 QR detected |
a | Reload keys from disk |
c | Clear current result |
Esc | Return to Accounts |
| Command | Description |
|---|
python signer/eth_signer.py --generate-keys | Generate a new ECDSA keypair |
python signer/eth_signer.py --derive-address 0x... | Derive address from private key |
python signer/eth_signer.py --private-key 0x... --to 0x... --value 1000000000000000000 | Sign a transaction |
python signer/eth_signer.py --scan | Webcam scan: detect and sign EIP-4527 QR codes |
python signer/eth_signer.py --add-key --private-key 0x... --name "Wallet" | Add a key to the store |
python signer/eth_signer.py --list-keys | List stored addresses |