Skip to content

Repository files navigation

Blonk Wallet

A browser extension Ethereum smart wallet built for two underserved use cases: first-class ENS identity management and agent ergonomics -- a system where humans grant bounded on-chain permissions to AI agents and automated processes.

Blonk uses ERC-4337 account abstraction (ZeroDev Kernel) so that agent permissions are enforced both off-chain by the backend and on-chain by smart contract policy validators. ENS is a primary feature, not an afterthought -- registration, renewal, record editing, subname management, and ENS-specific activity history are all built in.


Table of Contents


Features

Smart Wallet

  • ERC-4337 account abstraction via ZeroDev Kernel v3.1
  • Password-encrypted key storage (PBKDF2 600K iterations + AES-256-GCM)
  • Lock/unlock state machine with session-based key management
  • Multi-chain support (Ethereum mainnet + Sepolia testnet)
  • Counterfactual smart account addresses

ENS Identity Management

  • Name registration with commit-reveal anti-frontrunning (60-second wait, alarm-based timing that survives service worker restarts)
  • Name renewal with duration picker and price calculator
  • Record editor for text records (twitter, github, discord, url, avatar, description, email), ETH address, and content hash
  • Subname manager -- create subnames like agent.yourname.eth for free under names you own
  • ENS activity history -- filtered transaction view showing only ENS-related operations
  • Expiry warnings on the dashboard for names expiring within 90 days

Agent Permission System ("Licenses")

  • Session key generation -- create bounded ECDSA keypairs for agents with:
    • Per-token spending limits (daily and total)
    • Contract interaction whitelists (address + optional function selector restrictions)
    • Rate limiting (max operations per time window)
    • Expiration timestamps
  • Challenge-response authentication -- agents prove identity by signing a nonce with their session key, receive a JWT
  • Double validation -- every agent transaction is checked off-chain (backend: daily spending, rate limits, whitelists) AND on-chain (Kernel permission validator policies)
  • Transaction relay -- agents submit transactions to the backend API, which validates and relays to the bundler
  • License dashboard with spending progress bars, transaction history, and one-click revocation
  • Alerts for approaching spending limits and expiring licenses

dApp Connections

  • EIP-1193 provider injected as window.ethereum for browser dApp compatibility
  • EIP-6963 announcement for multi-wallet discovery
  • WalletConnect v2 -- paste a WC URI to connect to mobile/cross-platform dApps
  • Approval flow -- connect, sign, and transaction requests all surface as modal overlays for user confirmation
  • Connected sites manager with per-site disconnect

Signing

  • personal_sign / eth_sign for message signing
  • EIP-712 eth_signTypedData_v4 with structured type display
  • eth_sendTransaction with decoded calldata display, value formatting, and gas estimation

Portfolio

  • Token balances fetched via Alchemy (ETH + all ERC-20s) with USD price display
  • Transaction history with event decoding (Transfer, Approval, ENS events)
  • Token approval checker -- check and revoke ERC-20 allowances for any spender

Architecture

┌──────────────────────────────────────────────────────┐
│                   Browser Extension                   │
│                                                      │
│  ┌──────────┐  ┌────────────┐  ┌──────────────────┐ │
│  │  Popup   │  │  Content   │  │  Service Worker  │ │
│  │  (React) │  │  Script    │  │  (Background)    │ │
│  │          │◄─┤  (Relay)   │◄─┤                  │ │
│  │  Wallet  │  │            │  │  WalletController│ │
│  │  ENS     │  └────────────┘  │  TxController    │ │
│  │  Agents  │                  │  EnsController   │ │
│  │  Settings│  ┌────────────┐  │  SessionManager  │ │
│  └──────────┘  │  Inpage    │  │  RpcHandler      │ │
│                │  (Provider) │  │  ApprovalManager │ │
│                │  window.    │  │  WCManager       │ │
│                │  ethereum   │  │  ConnectionMgr   │ │
│                └────────────┘  └──────────────────┘ │
└──────────────────────────────────────────────────────┘
                         │
                    REST API
                         │
              ┌──────────▼──────────┐
              │   Fastify Backend   │
              │                     │
              │  Wallet routes      │
              │  Agent auth (JWT)   │
              │  License CRUD       │
              │  Tx validation      │
              │  ENS indexer        │
              │  Alchemy service    │
              │  Tx decoder         │
              └─────────┬───────────┘
                        │
                ┌───────▼───────┐
                │  PostgreSQL   │
                │  13 tables    │
                └───────────────┘

Communication Flow (dApp Interaction)

dApp page          Content Script       Service Worker      Popup UI
(window.ethereum)  (message relay)      (RPC handler)       (approval modals)
    │                   │                    │                   │
    │ request()         │                    │                   │
    ├──────────────────►│                    │                   │
    │                   │ sendMessage()      │                   │
    │                   ├───────────────────►│                   │
    │                   │                    │ (needs approval?) │
    │                   │                    ├──────────────────►│
    │                   │                    │                   │ user confirms
    │                   │                    │◄──────────────────┤
    │                   │    response        │                   │
    │                   │◄───────────────────┤                   │
    │ result            │                    │                   │
    │◄──────────────────┤                    │                   │

Tech Stack

Layer Technology
Monorepo pnpm workspaces
Extension build Vite + CRXJS (Manifest V3)
Extension UI React 18 + Tailwind CSS + React Router
Blockchain viem, permissionless.js
Smart wallet ZeroDev SDK (Kernel v3.1, ERC-4337)
ENS @ensdomains/ensjs, direct contract calls
WalletConnect @walletconnect/web3wallet v2
Backend Fastify + TypeScript
Database PostgreSQL (raw SQL via pg driver)
Auth JWT (jsonwebtoken), EIP-712 signatures
Validation Zod
Data provider Alchemy (Token API, Transfer API)

Project Structure

blonk-wallet/
├── package.json                  # pnpm workspace root
├── pnpm-workspace.yaml
├── tsconfig.base.json            # shared TypeScript config
├── .env.example                  # environment variable template
│
├── packages/
│   ├── shared/                   # @blonk/shared - types, constants, utilities
│   │   └── src/
│   │       ├── types/            # wallet, agent, ens, transaction, api types
│   │       ├── constants/        # chain configs, ENS contracts, known tokens
│   │       └── utils/            # zod schemas, formatting helpers
│   │
│   ├── extension/                # @blonk/extension - Chrome extension
│   │   ├── vite.config.ts        # Vite + CRXJS build config
│   │   ├── tailwind.config.js
│   │   └── src/
│   │       ├── background/       # Service worker (13 controllers)
│   │       │   ├── index.ts              # entry, wires everything together
│   │       │   ├── wallet-controller.ts  # key gen, encryption, smart account
│   │       │   ├── lock-controller.ts    # lock/unlock state machine
│   │       │   ├── chain-manager.ts      # viem clients per chain
│   │       │   ├── connection-manager.ts # dApp origin tracking
│   │       │   ├── approval-manager.ts   # pending request queue
│   │       │   ├── approval-controller.ts# ERC-20 allowance checks
│   │       │   ├── tx-controller.ts      # signing + tx sending
│   │       │   ├── ens-controller.ts     # ENS operations
│   │       │   ├── session-manager.ts    # agent session keys
│   │       │   ├── walletconnect-manager.ts # WC v2
│   │       │   ├── rpc-handler.ts        # EIP-1193 RPC methods
│   │       │   ├── message-router.ts     # message dispatch
│   │       │   └── storage.ts            # chrome.storage wrapper
│   │       ├── content/          # content script (message relay)
│   │       ├── inpage/           # injected provider (window.ethereum)
│   │       ├── popup/            # React UI
│   │       │   ├── App.tsx
│   │       │   ├── contexts/     # WalletContext
│   │       │   ├── hooks/        # useTokens, useTransactions, useENS,
│   │       │   │                 # useLicenses, useApprovals, useConnections
│   │       │   ├── lib/          # api-client.ts (backend communication)
│   │       │   └── components/   # 28 components organized by feature
│   │       │       ├── auth/         # CreateWallet, UnlockScreen
│   │       │       ├── wallet/       # BalanceCard, TokenList, ActivityList,
│   │       │       │                 # TokenApprovals, WalletHome
│   │       │       ├── ens/          # ENSDashboard, RegisterFlow, RenewFlow,
│   │       │       │                 # RecordEditor, SubnameManager, ENSActivityList
│   │       │       ├── agents/       # LicenseList, LicenseDetail, CreateLicense
│   │       │       ├── connections/  # ConnectedDApps, WalletConnectScan, WCSessions
│   │       │       ├── signing/      # ApprovalOverlay, ConnectRequest,
│   │       │       │                 # SignRequest, TxConfirm
│   │       │       ├── layout/       # AppShell, Header, BottomNav, ErrorBoundary
│   │       │       └── settings/     # SettingsPage
│   │       └── types/            # message type definitions
│   │
│   └── backend/                  # @blonk/backend - Fastify API
│       └── src/
│           ├── index.ts          # server bootstrap
│           ├── config.ts         # env validation (Zod)
│           ├── server.ts         # Fastify setup + plugin registration
│           ├── db/
│           │   ├── pool.ts               # pg connection pool
│           │   ├── migrate.ts            # SQL migration runner
│           │   ├── migrations/           # sequential .sql files
│           │   └── queries/              # typed SQL query functions
│           ├── routes/           # 7 route modules, 22 endpoints
│           ├── middleware/       # wallet-auth, agent-auth, rate-limit, errors
│           └── services/         # alchemy, ens-indexer, tx-decoder,
│                                 # validation, chain-service

Setup

Prerequisites

  • Node.js >= 18
  • pnpm >= 8 (npm install -g pnpm)
  • PostgreSQL >= 14
  • Chrome (or Chromium-based browser)

1. Clone and Install

git clone <repo-url> blonk-wallet
cd blonk-wallet
pnpm install

2. Configure Environment

cp .env.example .env

Edit .env with your credentials:

# Required
DATABASE_URL=postgresql://localhost:5432/blonk_wallet
JWT_SECRET=your-secret-at-least-16-chars

# Required for balance/tx fetching
ALCHEMY_API_KEY=your_alchemy_api_key

# Optional (for full smart wallet deployment)
ZERODEV_PROJECT_ID=your_zerodev_project_id

# Optional
PORT=3001

Getting API keys:

  • Alchemy: Sign up at alchemy.com and create an app for Ethereum mainnet + Sepolia
  • ZeroDev: Sign up at zerodev.app and create a project (needed for full Kernel smart wallet deployment)

3. Set Up Database

createdb blonk_wallet
pnpm --filter @blonk/backend migrate

4. Build Shared Package

pnpm --filter @blonk/shared build

5. Start Development

In two terminals:

# Terminal 1: Backend
pnpm dev:backend

# Terminal 2: Extension
pnpm dev:extension

6. Load the Extension in Chrome

  1. Open chrome://extensions/
  2. Enable Developer mode (top right toggle)
  3. Click Load unpacked
  4. Select the packages/extension/dist directory
  5. The Blonk Wallet icon appears in your toolbar

Development

Commands

# Build all packages
pnpm build

# Typecheck all packages
pnpm typecheck

# Build shared types (run after changing shared/)
pnpm build:shared

# Dev mode (hot reload)
pnpm dev:extension    # extension with HMR
pnpm dev:backend      # backend with watch mode

# Database
pnpm --filter @blonk/backend migrate   # run migrations

Architecture Notes

  • The service worker is the brain of the extension. All wallet logic, signing, ENS operations, and session key management run here. The popup UI communicates with it via chrome.runtime.sendMessage.
  • The content script runs in an isolated world on every page. It injects the inpage script and relays messages between the page and service worker.
  • The inpage script runs in the page's main world and creates window.ethereum (the EIP-1193 provider). dApps interact with this provider.
  • Chrome's Manifest V3 terminates service workers after ~30 seconds of inactivity. All state is persisted in chrome.storage and operations use chrome.alarms for timing (e.g., ENS commit-reveal).
  • The backend is a Fastify server that caches blockchain data (balances, transactions, ENS names) in PostgreSQL and hosts the agent authentication/relay API.

Extension Usage

Creating a Wallet

  1. Click the Blonk extension icon
  2. Enter a password (minimum 8 characters) and confirm
  3. Your smart wallet is created with an encrypted key vault stored locally
  4. You're automatically unlocked and see the main wallet view

Wallet Tab

  • Balance card shows ETH balance with USD value
  • Token list displays all ERC-20 tokens with balances
  • Activity feed shows decoded transaction history
  • Click Refresh to fetch latest balances from Alchemy
  • Click Sync to pull transaction history from the chain

ENS Tab

  • Register: Search for available .eth names, select duration (1-5 years), see the price, then go through the 2-step commit-reveal process (60-second mandatory wait between steps)
  • Renew: Select names approaching expiry and extend them
  • Records: Edit text records (social links, avatar, description), set the ETH address, or update the content hash
  • Subnames: Create subnames under your owned names (e.g., bot.yourname.eth) -- useful for giving agents their own ENS identity
  • ENS Activity: Filtered transaction history showing only ENS operations

Agents Tab

  • Create License: Multi-step wizard:
    1. Set expiration (1/7/30/90 days) and rate limit (ops per day)
    2. Add whitelisted contracts (address + label)
    3. Set per-token spending limits (daily + total)
    4. Review and confirm
    5. Copy the session key and approval bundle to give to your agent
  • License List: View all licenses with status (active/expired), contract and limit counts
  • License Detail: Full policy view, spending progress bars, revoke button

Settings Tab

  • View account addresses (smart account + EOA owner)
  • Manage connected dApp sites (view and disconnect)
  • WalletConnect: paste a WC URI to connect to any WC-compatible dApp
  • Token Approvals: check and revoke ERC-20 allowances
  • Lock wallet

Connecting to dApps

When a dApp calls eth_requestAccounts, a connect request modal appears showing the site and requested permissions. Approve or reject. Once connected, signing and transaction requests surface as overlay modals with full data display.


Agent API

Agents interact with the Blonk backend API using session keys issued by the human wallet owner.

Authentication Flow

1. Agent requests a challenge:
   POST /api/agents/challenge
   Body: { "agentAddress": "0x..." }
   Response: { "challenge": "blonk-auth:...", "expiresAt": 1234567890 }

2. Agent signs the challenge with their session private key (EIP-191 personal_sign)

3. Agent submits the signed challenge:
   POST /api/agents/authenticate
   Body: { "agentAddress": "0x...", "challenge": "blonk-auth:...", "signature": "0x..." }
   Response: { "token": "eyJ...", "expiresAt": ..., "licenses": [...] }

4. Agent includes JWT in all subsequent requests:
   Authorization: Bearer eyJ...

Submitting Transactions

POST /api/agents/transactions/relay
Authorization: Bearer <jwt>

{
  "licenseId": "uuid",
  "chainId": 1,
  "calls": [
    {
      "to": "0x...token...",
      "value": "0",
      "data": "0xa9059cbb..."
    }
  ]
}

The backend validates:

  1. License exists, is active, and not expired
  2. Target contracts are in the whitelist
  3. Function selectors are allowed (if restricted)
  4. Token spending is within daily and total limits
  5. Rate limit is not exceeded

If all checks pass, the transaction is logged and spending is tracked.

Checking Agent Context

GET /api/agents/me
Authorization: Bearer <jwt>

Response: {
  "agentAddress": "0x...",
  "licenses": [{ id, agent_name, chain_id, status, token_limits, contract_whitelist, ... }]
}

Database Schema

13 tables organized by domain:

Domain Tables Purpose
Wallet wallets, token_balances Account registration, cached balances
Transactions transactions, transaction_events Cached tx history with decoded events
ENS ens_names, ens_records Cached ENS name ownership and records
Agents licenses, spending_tracking, transaction_logs, auth_challenges, agent_sessions, alerts License policies, spending tracking, auth, audit trail

Run migrations:

pnpm --filter @blonk/backend migrate

API Reference

Wallet Endpoints

Method Path Description
POST /api/wallets/register Register a smart wallet
GET /api/wallets/:address Get wallet info
GET /api/wallets/:address/balances?chainId=&refresh= Token balances

Transaction Endpoints

Method Path Description
GET /api/wallets/:address/transactions?chainId=&page=&limit= Paginated tx history
GET /api/wallets/:address/transactions/ens ENS-only tx history
POST /api/wallets/:address/transactions/sync Sync from Alchemy

ENS Endpoints

Method Path Description
GET /api/wallets/:address/ens/names Owned ENS names + records
GET /api/ens/:name/records Get records for a name
POST /api/wallets/:address/ens/sync Sync ENS data from chain

License Endpoints

Method Path Description
POST /api/wallets/:address/licenses Create a license
GET /api/wallets/:address/licenses List all licenses
GET /api/wallets/:address/licenses/:id License detail + spending
PATCH /api/wallets/:address/licenses/:id/revoke Revoke a license
GET /api/wallets/:address/alerts Get alerts

Agent Endpoints

Method Path Description
POST /api/agents/challenge Request auth challenge
POST /api/agents/authenticate Sign challenge, get JWT
GET /api/agents/me Agent context + licenses
POST /api/agents/transactions/relay Validate + relay transaction
GET /api/agents/transactions?licenseId= Agent tx history

Health

Method Path Description
GET /api/health Database connectivity check

Configuration

Environment Variables

Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
JWT_SECRET Yes Secret for signing agent JWTs (min 16 chars)
ALCHEMY_API_KEY Yes Alchemy API key for balance/tx fetching
ZERODEV_PROJECT_ID No ZeroDev project ID for Kernel deployment
PORT No Backend port (default: 3001)
MAINNET_RPC_URL No Override mainnet RPC URL
SEPOLIA_RPC_URL No Override Sepolia RPC URL

Supported Chains

Chain ID ENS Status
Ethereum Mainnet 1 Yes Production
Sepolia Testnet 11155111 Yes (testnet contracts) Development

The architecture supports adding new chains by extending SUPPORTED_CHAINS in packages/shared/src/constants/chains.ts.


Security Model

Key Storage

  • Private keys are encrypted at rest with AES-256-GCM using a key derived from the user's password via PBKDF2 (600,000 iterations)
  • Encrypted vault stored in chrome.storage.local (persistent)
  • Decrypted key held in chrome.storage.session only while unlocked (volatile, clears on browser restart)

Agent Permission Enforcement

  • Off-chain (backend): Daily/total spending limits, rate limiting, contract whitelist, function selector checks -- prevents invalid transactions from wasting gas
  • On-chain (Kernel policies): Per-call value limits, argument constraints, expiration, rate limits -- enforces bounds even if the backend is bypassed
  • If the backend is compromised: on-chain policies still enforce bounds; attacker cannot forge session key signatures
  • If an agent key is compromised: human can revoke on-chain + backend; on-chain limits cap the damage window

Extension Security

  • Manifest V3 with no eval() or inline scripts (CSP enforced)
  • Service worker uses Web Crypto API for all cryptographic operations
  • Content script runs in an isolated world; inpage script cannot access extension storage
  • Connected dApp origins are tracked and can be revoked individually

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages