Lunark
AI companion platform that makes blockchain human-friendly through natural language interactions.
## What is Lunark?

Blockchain technology is powerful, but interacting with it remains frustratingly complex. Users need to navigate hex addresses, understand gas mechanics, manage token approvals, and memorize contract interactions across different networks. For most people, this complexity creates an insurmountable barrier to entry. Lunark exists to eliminate that barrier entirely.
Lunark is an AI companion that transforms natural language into blockchain operations. Instead of wrestling with wallet interfaces and transaction parameters, you simply describe what you want: "Send 0.5 ETH to Alice" or "Swap my USDC for ETH on Arbitrum." The AI understands your intent, resolves contacts and ENS names, finds optimal swap routes across multiple DEXes, and prepares everything for you to approve with a single click.
Built on the [Astreus](https://astreus.org) AI agent framework, Lunark combines the conversational intelligence of GPT-4o-mini with 13 specialized blockchain tools. It supports 8 EVM-compatible networks including Ethereum, Polygon, Arbitrum, and Base. Most importantly, it follows a strict non-custodial architecture: your private keys never leave your browser. The server prepares transactions, but only your wallet can sign them. This means you get the convenience of AI assistance without sacrificing the security guarantees that make self-custody valuable in the first place.
## Tech Stack
| Layer | Technologies |
|-------|-------------|
| Frontend | Next.js 16, React 19, Reown AppKit |
| Backend | Node.js, Express, Socket.IO |
| AI | Astreus Framework, OpenAI GPT-4o-mini |
| Database | PostgreSQL |
| Networks | Ethereum, Polygon, Arbitrum, Optimism, Base, BNB, Avalanche, Sepolia |

## Architecture Overview
```mermaid
flowchart TD
User[User]
User --> Browser
subgraph Browser["Your Browser"]
Frontend[Lunark UI]
Wallet[Wallet + Keys]
end
subgraph Server["Lunark Server"]
API[API + Socket.IO]
Agent[AI Agent + Tools]
DB[(PostgreSQL)]
end
subgraph External["External Services"]
OpenAI[OpenAI GPT-4o-mini]
Blockchain[EVM Networks]
end
Frontend --> API
API --> Agent
Agent --> OpenAI
Agent --> Blockchain
Agent --> DB
Wallet --> Blockchain
```
The architecture enforces a deliberate separation between what the server can do and what only the user can authorize. The frontend manages wallet connections, UI rendering, and most critically, transaction signing. The backend handles everything else: AI processing, tool execution, blockchain queries, and transaction preparation. This split isn't arbitrary. By keeping private keys exclusively in the browser and limiting the server to read operations and unsigned transaction construction, the system ensures that even a fully compromised backend cannot steal user funds. The worst an attacker could do is prepare malicious transactions, which the user would still need to explicitly approve in their wallet.

## How It Works
Every blockchain transaction in Lunark follows a prepare-sign-submit pattern designed to maintain security while providing a seamless experience. The flow begins when a user makes a natural language request. The AI agent interprets the intent, determines which tool to invoke, and executes it on the server. For read operations like balance checks, the result streams back immediately. For write operations, the tool constructs an unsigned transaction containing the recipient, value, and calldata, then emits it to the frontend via Socket.IO.
The critical moment happens in the browser. When the frontend receives a prepared transaction, it prompts the user's wallet for approval. The user sees exactly what they're signing: the destination address, the amount, the network. Only after they explicitly confirm does the signed transaction get broadcast to the blockchain. This pattern means the server never handles private keys, never has signing authority, and never could execute a transaction without user consent.
1. **User Request** - User asks the agent to perform a transaction (e.g., "send 1 ETH to alice")
2. **Agent Processes** - AI interprets the request and selects the appropriate tool
3. **Tool Prepares TX** - Server builds the unsigned transaction (to, value, data)
4. **Emit via Socket** - Transaction details sent to frontend via Socket.IO
5. **User Signs in Wallet** - User approves and signs in MetaMask/wallet (keys never leave browser)
6. **Submit to Blockchain** - Signed transaction broadcast to the network
Response streaming deserves special attention. Rather than waiting for the AI to generate a complete response before displaying anything, Lunark streams tokens as they're produced. This creates a responsive, conversational feel where users see the AI "thinking" in real-time.
```mermaid
sequenceDiagram
participant User
participant Frontend
participant Backend
participant Agent
participant OpenAI
User->>Frontend: Send message
Frontend->>Backend: POST /message
Backend->>Agent: agent.ask(message)
Agent->>OpenAI: Stream request
loop For each token
OpenAI-->>Agent: Token chunk
Agent-->>Backend: Yield chunk
Backend-->>Frontend: Socket: streamResponse
Frontend-->>User: Update UI
end
Backend-->>Frontend: Socket: streamEnd
```

## The AI Agent
At the heart of Lunark sits the LunarkAgent class, which orchestrates all AI-powered blockchain operations. Creating an AI agent isn't cheap. It requires loading model configurations, registering tools, building context-aware system prompts, and establishing connections. Doing this on every request would create noticeable latency and waste resources. Instead, Lunark maintains a per-user agent cache with a 30-minute TTL. When a user sends a message, the system checks if a warm agent instance exists for their wallet address. If so, it reuses it immediately. If not, or if the cache has expired, it spins up a fresh instance. This approach balances responsiveness with resource efficiency.
```typescript:src/agent/LunarkAgent.ts
class LunarkAgent {
private static agentCache = new Map<string, { agent: Agent; lastUsed: number }>();
private static CACHE_TTL = 30 * 60 * 1000; // 30 minutes
async initialize() {
const cached = LunarkAgent.agentCache.get(this.userAddress);
if (cached && Date.now() - cached.lastUsed < LunarkAgent.CACHE_TTL) {
return cached.agent;
}
const agent = new Agent({
name: `lunark-agent-${this.userAddress.slice(0, 8)}`,
model: 'openai/gpt-4o-mini',
systemPrompt: this.buildSystemPrompt(),
});
agent.registerPlugin(lunarkPlugin);
LunarkAgent.agentCache.set(this.userAddress, { agent, lastUsed: Date.now() });
return agent;
}
}
```
The agent's capabilities come from 13 specialized tools, each handling a specific aspect of blockchain interaction. Some are simple lookups, others orchestrate complex multi-step operations like DEX swaps that require price quotes, approval checks, and route optimization. Together, they give the AI everything it needs to fulfill natural language requests across the full spectrum of common blockchain operations.
- **get_wallet_balance** - Platform USD balance for AI usage
- **get_balance** - Query native and ERC20 token balances
- **transfer** - Prepare token transfers with contact/ENS resolution
- **swap_tokens** - Execute DEX swaps with best rate selection
- **approve_token** - Manage ERC20 approvals for DEX interactions
- **resolve_token** - Map token symbols to contract addresses
- **is_native_token** - Check if symbol is network's native token
- **switch_network** - Change active blockchain network
- **list_tools** - Return available tools with descriptions
- **add_contact** - Save address with human-readable name
- **list_contacts** - Return all saved contacts
- **resolve_contact** - Look up address by contact name
- **delete_contact** - Remove contact from address book

## Security Model
Security in a blockchain application isn't a feature, it's the foundation everything else rests on. Lunark's security model starts from a simple principle: the server should never be trusted with anything that could directly result in fund loss. This shapes every architectural decision, from how authentication works to how transactions flow through the system.
- **Authentication** - ECDSA signature verification with 5-minute timestamp window, JWT tokens with 30-day expiry
- **API Protection** - Helmet for security headers, HPP for parameter pollution prevention, rate limiting at 100 requests per 15 minutes
- **Transaction Security** - All transactions prepared server-side, signed exclusively client-side. No private keys ever touch the server
- **User Isolation** - All database queries filtered by user address, agent instances isolated per user
## More Slices From This Pzza
Dive deeper into the ideas and technology behind this project:
- [Building Lunark: AI Agent Architecture for Blockchain Operations](/oven/building-lunark-ai-agent-blockchain) - How Lunark uses the Astreus framework to create an AI agent that executes blockchain operations
- [Real-Time Streaming with Socket.IO: Building Responsive Web3 Chat](/oven/real-time-streaming-socketio-web3-chat) - Implementing real-time message streaming and transaction notifications
- [Multi-Chain DEX Aggregation: How Lunark Finds the Best Swap Rates](/oven/multi-chain-dex-aggregation-lunark) - Technical walkthrough of the DEX aggregation system