Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
9530592
add 2fa telegram callback
tiero Feb 14, 2026
d1e3bc5
chore: use the right hashes lib
tiero Feb 14, 2026
fbb6510
new deploy
tiero Feb 14, 2026
88c845d
chore: readme
tiero Feb 14, 2026
f246604
add e2e tests
tiero Feb 14, 2026
b0e7b58
teegram deep link
tiero Feb 14, 2026
f45b13d
refactor: rename wallet to identity throughout the codebase
tiero Feb 14, 2026
9977cf3
feat: implement sealed key backup and restore mechanism with Evervaul…
tiero Feb 14, 2026
b2237e0
feat: add skills module with Bitcoin, Lightning, and LendaSwap functi…
tiero Feb 14, 2026
f621208
fix: correct naming of ArkadeLightningSkill and related configurations
tiero Feb 14, 2026
620614f
feat: implement Telegram bot session authentication and identity rest…
tiero Feb 15, 2026
cd014e7
feat: enhance send command with stablecoin support and add unit conve…
tiero Feb 15, 2026
a56b66a
feat: add web package for payment interface
tiero Feb 15, 2026
c672610
feat: add shared package with graceful shutdown functionality and upd…
tiero Feb 15, 2026
410bda2
feat: enhance payment processing and UI updates
tiero Feb 15, 2026
81251be
feat(ui): enhance payment flow with progress indicators and new branding
tiero Feb 15, 2026
3f0f43b
feat: enhance token approval process and UI updates
tiero Feb 15, 2026
12e8327
feat: migrate graceful shutdown functionality to enclave and remove s…
tiero Feb 15, 2026
ffa9aab
fix(attestation): update PCR0 and PCR2 values for correct attestation
tiero Feb 15, 2026
d301f89
fix(login): remove telegram_user_id from challenge request for produc…
tiero Feb 15, 2026
41dd3e0
fix(package): correct project name from "claw-cash" to "clw-cash"
tiero Feb 15, 2026
7069e59
feat: add initial README for clw-cash CLI with installation and usage…
tiero Feb 15, 2026
e8eefc3
v0.1.1
tiero Feb 15, 2026
9c5b62f
fix(package): add missing entry for clw-cash in bin section of packag…
tiero Feb 15, 2026
4cb0224
v0.1.2
tiero Feb 15, 2026
a78301b
fix(tsup): add lendasat/lendaswap-sdk-pure to noExternal dependencies
tiero Feb 15, 2026
ce1b537
chore: update version
tiero Feb 15, 2026
341e6cd
fix: update dependencies
tiero Feb 15, 2026
ca31fe4
fix: update dependencies
tiero Feb 15, 2026
aa437da
v0.1.8
tiero Feb 15, 2026
4fe8b85
fix: add better-sqlite3 dependency and remove optional flags from sev…
tiero Feb 15, 2026
c3d1856
fix: update version to 0.1.9
tiero Feb 15, 2026
dd2fe26
fix: improve authentication flow by removing test user ID and adding …
tiero Feb 15, 2026
60911e2
chore: v0.1.10
tiero Feb 15, 2026
54034ee
http 202
tiero Feb 15, 2026
f8092b1
v0.1.11
tiero Feb 15, 2026
59012ab
feat: add redirects configuration for index.html
tiero Feb 15, 2026
1a2bbb5
fix: update payment URL generation to use correct base URL and improv…
tiero Feb 15, 2026
fa8ca5d
fix: set envDir to parent directory in Vite configuration
tiero Feb 15, 2026
d96cc4c
docs: update README with detailed initialization and command usage in…
tiero Feb 15, 2026
a8a66bf
v0.1.12
tiero Feb 16, 2026
0a389ae
landing page
tiero Feb 16, 2026
739c57d
Add landing page and markdown documentation for Claw Cash
tiero Feb 16, 2026
b96f789
refactor: remove KV_CHALLENGES and migrate challenge storage to D1 da…
tiero Feb 16, 2026
453251f
fix: update author information and links in index.html
tiero Feb 16, 2026
6a20c0d
fix: strip wrapping quotes from sealed keys in backup restoration
tiero Feb 16, 2026
c40812a
fix: update PCR values in enclave configuration for attestation
tiero Feb 16, 2026
eeca307
fix: remove KV_CHALLENGES namespace creation from runbook
tiero Feb 16, 2026
59c9331
fix: add white-space pre property to code block styling
tiero Feb 16, 2026
6d1ff7f
feat: add payment links and use cases sections to landing page
tiero Feb 16, 2026
e179e88
feat: implement configuration loading and display command
tiero Feb 16, 2026
d7494af
fix: update skill.md for clarity and additional command details
tiero Feb 16, 2026
563e5cb
feat: add identity and authentication sections to documentation
tiero Feb 16, 2026
d8bf7a2
feat: enhance currency handling by adding support for 'sats' and norm…
tiero Feb 16, 2026
55a18ec
feat: implement parseBtcAmount function for BTC/sats conversion and u…
tiero Feb 16, 2026
0299b13
fix: update version to 0.1.13 in package.json
tiero Feb 16, 2026
54bc9ec
fix: update version to 0.1.14 in package.json and add prepublishOnly …
tiero Feb 16, 2026
d5f28be
refactor: update landing page titles and descriptions for clarity and…
tiero Feb 16, 2026
9ab38c7
Refactor: Move remote signer identity functionality to a new package
tiero Feb 16, 2026
cdf5088
style: update landing page styles and add copy command functionality
tiero Feb 16, 2026
f902fd2
style: add lobster emoji to Claw Cash title for branding enhancement
tiero Feb 16, 2026
a40bb0f
refactor: update package links to use remote-signer-identity instead …
tiero Feb 16, 2026
b457bb5
docs: enhance project documentation with core principles, roadmap, an…
tiero Feb 16, 2026
b925a64
feat: implement non-blocking authentication with Telegram integration…
tiero Feb 16, 2026
41bef74
chore: bump version to 0.1.15 in package.json
tiero Feb 16, 2026
1cc3279
docs: update SKILL.md with agent rules and non-blocking authenticatio…
tiero Feb 16, 2026
13c39a6
chore: bump version to 0.1.16 in package.json
tiero Feb 16, 2026
3079ee7
docs: update roadmap and FAQ for x402 client support and ECDSA signin…
tiero Feb 16, 2026
448b808
feat: add identity listing and recovery functionality, update documen…
tiero Feb 16, 2026
f3f5454
v0.1.17
tiero Feb 16, 2026
45ca4f8
feat: update links to SKILL.md and restructure documentation
tiero Feb 16, 2026
2c73e0b
feat: update command references from clw-cash to cash and improve ins…
tiero Feb 16, 2026
54905ce
feat: update installation instructions to use npx for clw-cash initia…
tiero Feb 16, 2026
799888c
feat: refactor daemon startup to use current node binary and entrypoint
tiero Feb 16, 2026
fa131b7
feat: bump version to 0.1.18
tiero Feb 16, 2026
61ff6a2
feat: update backup methods to use encrypted keys and improve documen…
tiero Feb 16, 2026
324e4ef
Add payment links section, roadmap page, and style updates; enhance '…
tiero Feb 16, 2026
86689f5
Add payment links section, roadmap page, and style updates; enhance '…
tiero Feb 16, 2026
05b7a30
feat: add ECDSA signing support and related changes
tiero Feb 16, 2026
47350ae
feat: update .gitignore to include api/api-data/ and remove key-backu…
tiero Feb 16, 2026
da6ca33
feat: enhance payment handling in fetch command with EVM and Bitcoin …
tiero Feb 16, 2026
0cfb438
feat: add x402 payment handling and update roadmap with new features
tiero Feb 16, 2026
efb724c
feat: update currency references from btc to sats in commands and doc…
tiero Feb 16, 2026
a430141
feat: implement webhook notifications for swap events and update rela…
tiero Feb 16, 2026
1a14877
feat: bump version to 0.1.19
tiero Feb 16, 2026
c03bc46
feat: add 'cash skill' command to display agent instructions and reor…
tiero Feb 16, 2026
6284053
feat: bump version to 0.1.20
tiero Feb 16, 2026
f15a48f
feat: enhance agent rules and add reactive polling guidelines in SKIL…
tiero Feb 16, 2026
3f10810
v0.1.21
tiero Feb 16, 2026
287da89
deploy script (#4)
tiero Feb 16, 2026
4924cb1
production hardening (#3)
tiero Feb 16, 2026
609e981
Merge origin/main into x402-pay
tiero Feb 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Typecheck
run: pnpm typecheck

- name: E2E tests
run: pnpm test
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ node_modules
dist
enclave.eif

# Wrangler
.wrangler

# Environment & secrets
.env*
*.pem
api/api-data/

# Logs
*.log
Expand All @@ -23,4 +27,5 @@ Thumbs.db
.vscode


.claude
.claude
branding/
11 changes: 11 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Project Rules

## Core Principle

Agents hold Bitcoin (sats) as their treasury. When an agent needs to pay for something — an x402 API, a stablecoin transfer, any fiat-denominated cost — it swaps BTC to stablecoins on the fly via the existing swap infrastructure (LendaSwap + Boltz). The agent never holds stablecoins as a reserve. Bitcoin in, stablecoins out, on demand.

This applies to all payment integrations: x402, direct stablecoin sends, Lightning invoices. The CLI command `cash send --currency usdc --where polygon --to <address>` already handles the BTC→stablecoin atomic swap. New payment protocols (like x402) should build on this, not bypass it.

## Landing Page

When editing `landing-page/index.html`, always update `landing-page/index.md` to reflect the same content. The markdown file is the machine-readable version served to LLMs and agents via `<link rel="alternate" type="text/markdown">`. Keep both files in sync.
226 changes: 205 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,233 @@
# clw.cash MVP
# clw.cash

Backend scaffold for key management with create/sign/destroy flows where signing is delegated to an enclave service.
Privy, for AI Agents.

Secure identity infrastructure that lets AI agents hold, sign, and transact with Bitcoin and stablecoins. Private keys live inside hardware enclaves — your agent gets a simple CLI, never touches the raw key material.

## Vision: Agents Hold Sats, Pay the World

Agents accumulate and hold Bitcoin (sats). When they need to pay for something — an API behind a paywall, a stablecoin transfer, an x402-protected resource — they swap BTC to stablecoins on the fly and send. The agent never needs to hold stablecoins as a reserve; Bitcoin is the treasury, stablecoins are the payment rail.

This means clw.cash is **x402-compatible by design**. When an agent hits a `402 Payment Required` response demanding USDC on Polygon, it already has everything it needs: `cash send --amount 10 --currency usdc --where polygon --to <address>` swaps BTC→USDC atomically and delivers the payment. The swap infrastructure (LendaSwap + Boltz) handles the cross-chain bridge. The agent just says "pay X in currency Y" and it works.

## How it works

```
Agent ──► cash CLI ──► skills/ ──► sdk/ ──► clw.cash API ──► Enclave (secp256k1)
└── audit log, rate limits, 2FA via Telegram
```

## Layout

- `api/`: external API service
- `enclave/`: enclave signer service (Dockerized HTTP app)
- `schemas/`: OpenAPI + JSON schemas
- `infra/`: enclave config and deployment notes
- `docs/`: runbook and threat model
```
api/ Public-facing REST API (auth, identities, signing)
enclave/ Signer service (runs inside Evervault Enclave)
sdk/ TypeScript SDK — RemoteSignerIdentity, API client, signing utils
skills/ Bitcoin, Lightning, and Stablecoin skills (Ark, Boltz, LendaSwap)
cli/ Agent-friendly CLI ("cash") — send, receive, balance
schemas/ OpenAPI + JSON schemas
infra/ Enclave config and deployment
```

## CLI — `cash`

```bash
npm i -g claw-cash
```

The CLI outputs JSON to stdout, designed to be called by AI agents as a subprocess tool. Full command reference and agent tips: [SKILL.md](https://clw.cash/SKILL.md).

## Local quickstart
## Quickstart

```bash
pnpm install
pnpm --filter ./enclave start
pnpm --filter ./api start
```

API defaults to `http://127.0.0.1:4000`, enclave defaults to `http://127.0.0.1:7000`.
### 1. Start services locally

## Evervault Enclave Deployment
```bash
# Terminal 1 — enclave signer (runs on :7000)
pnpm start:enclave

# Terminal 2 — API (runs on :4000)
pnpm start:api
```

No enclave redeploy needed for local development. The enclave service runs as a regular Node process locally — it only runs inside Evervault in production.

### 2. Initialize the CLI

```bash
# Auto-authenticates, creates an identity, saves config, starts daemon
pnpm --filter ./cli dev -- init \
--api-url http://127.0.0.1:4000 \
--ark-server https://server.arkade.fun
```

### Prerequisites
In test mode (no `TELEGRAM_BOT_TOKEN` set), authentication resolves automatically. In production, a Telegram deep link is shown for 2FA confirmation.

Install the [Evervault CLI](https://docs.evervault.com/cli).
This creates `~/.clw-cash/config.json` with your identity credentials and starts a background daemon for monitoring swaps (Lightning HTLC claiming and LendaSwap polling).

### Initialize (one-time)
You can also pass a token explicitly: `--token <jwt>`.

Generate signing certificates:
### 3. Use the CLI

```bash
ev enclave cert new --output ./infra
# Check balance (requires Ark server to be reachable)
pnpm --filter ./cli dev -- balance

# Receive — get an Ark address
pnpm --filter ./cli dev -- receive --amount 100000 --currency btc --where arkade

# Receive — create a Lightning invoice
pnpm --filter ./cli dev -- receive --amount 50000 --currency btc --where lightning
```

### Build
You can also set env vars instead of using the config file:

```bash
ev enclave build -v --output . -c ./infra/enclave.toml ./enclave
export CLW_API_URL=http://127.0.0.1:4000
export CLW_SESSION_TOKEN=<jwt>
export CLW_IDENTITY_ID=<uuid>
export CLW_PUBLIC_KEY=<hex>
export CLW_ARK_SERVER_URL=https://server.arkade.fun
```

## Testing

### E2E tests (API + Enclave only)

```bash
pnpm test:e2e
```

This spins up the enclave and API on random ports, runs the full user journey (auth, identity, sign, destroy, backup/restore), and tears down. No external dependencies needed.

### Typecheck all packages

```bash
pnpm typecheck
```

## API Endpoints

| Method | Path | Auth | Description |
| ------ | ---- | ---- | ----------- |
| GET | `/health` | No | Health check |
| POST | `/v1/auth/challenge` | No | Create auth challenge |
| POST | `/v1/auth/verify` | No | Verify challenge, get JWT |
| POST | `/v1/auth/bot-session` | Bot key | Get session for a Telegram user (bot-to-bot) |
| POST | `/v1/identities` | Yes | Create identity (key generated in enclave) |
| POST | `/v1/identities/:id/restore` | Yes | Restore identity from backup |
| POST | `/v1/identities/:id/sign-intent` | Yes | Get signing ticket |
| POST | `/v1/identities/:id/sign` | Yes | Sign with ticket |
| POST | `/v1/identities/:id/sign-batch` | Yes | Batch sign multiple digests |
| DELETE | `/v1/identities/:id` | Yes | Destroy identity |
| GET | `/v1/audit` | Yes | Audit trail |

## Bot Integration (Factory Bot)

clw.cash acts as a **factory bot** — a backend service that other Telegram bots use to give their users Bitcoin wallets. Your bot authenticates with a shared API key and gets per-user sessions without any user-facing auth flow.

### How it works

```text
User (Telegram) Your Bot clw.cash API Enclave
│ │ │ │
│ "send 1000 sats" │ │ │
│ from.id = 98765 │ │ │
│──────────────────────►│ │ │
│ │ POST /v1/auth/bot-session │ │
│ │ x-bot-api-key: <secret> │ │
│ │ { telegram_user_id: 98765 } │
│ │───────────────────────────►│ │
│ │ ◄── { token, user } │ │
│ │ │ │
│ │ SDK: wallet.sendBitcoin() │ sign digest │
│ │───────────────────────────►│───────────────────►│
│ │ ◄── { txid } │ ◄── { signature } │
│ ◄── "Sent!" │ │ │
```

**Telegram guarantees `from.id` can't be faked** — only your bot (with the API key) can create sessions, and it only does so for verified Telegram users. No impersonation is possible.

### Configuration

1. **Create a Telegram bot** via [@BotFather](https://t.me/BotFather) — this is the "factory" auth bot
1. **Generate a bot API key** — any random secret string
1. **Set env vars** on the clw.cash API server:

```bash
TELEGRAM_BOT_TOKEN=<token from BotFather>
TELEGRAM_BOT_USERNAME=<your_bot_username>
BOT_API_KEY=<your random secret>
```

This produces `enclave.eif`.
1. **In your bot code**, use the SDK directly (not the CLI):

```typescript
import { createClwBitcoinSkill } from "@clw-cash/skills";

// Get a session for this Telegram user
const session = await fetch("https://api.clw.cash/v1/auth/bot-session", {
method: "POST",
headers: {
"content-type": "application/json",
"x-bot-api-key": process.env.BOT_API_KEY,
},
body: JSON.stringify({ telegram_user_id: String(msg.from.id) }),
}).then(r => r.json());

// Create a wallet skill for this user
const bitcoin = await createClwBitcoinSkill({
apiBaseUrl: "https://api.clw.cash",
sessionToken: session.token,
identityId: user.identityId,
publicKey: user.publicKey,
arkServerUrl: "https://server.arkade.fun",
});

// Use it
const result = await bitcoin.send({ address: "ark1q...", amount: 1000 });
```

### Auth modes

| Mode | How it works | Use case |
| ---- | ------------ | -------- |
| **CLI** (`cash init`) | Challenge → Telegram deep link → human confirms | Developer testing, standalone agent |
| **Bot session** | Bot API key + `telegram_user_id` → instant JWT | Telegram bot serving many users |
| **Test mode** | No `TELEGRAM_BOT_TOKEN` → auto-resolves | Local dev, CI |

## Deploy to Evervault

### Deploy
Install the [Evervault CLI](https://docs.evervault.com/cli), then:

```bash
# one-time: generate signing certs
ev enclave cert new --output ./infra

# build enclave image
ev enclave build -v --output . -c ./infra/enclave.toml ./enclave

# deploy
ev enclave deploy -v --eif-path ./enclave.eif -c ./infra/enclave.toml
```

## Roadmap

### Now

- [ ] **MCP server** — Claude Code / Claude Desktop tool-use integration

### Next

- [ ] **x402 client support** — `cash pay <url>` command, auto-swap BTC→stablecoin, retry with proof. Blocked on ECDSA signing in enclave ([#5](https://github.com/tiero/clw.cash/issues/5))
- [ ] **Spending policies** — per-agent limits, allowlists, time-based rules, enforced at enclave level
- [ ] **More auth providers** — Slack, Google, 1Password, YubiKey, Passkeys

### Later

- [ ] **Persistent storage** — replace in-memory store with PostgreSQL
- [ ] **Webhook notifications** — push events for transaction completion, swap settlement, balance changes
55 changes: 48 additions & 7 deletions api/README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
# API Service

External API service for user/session management, wallet metadata, ticket issuance, audit logs, and orchestration of enclave key operations.
External API service for user/session management, identity metadata, ticket issuance, audit logs, and orchestration of enclave key operations.

## Endpoints

- `POST /v1/users`
- `POST /v1/sessions`
- `POST /v1/wallets`
- `POST /v1/wallets/:id/sign-intent`
- `POST /v1/wallets/:id/sign`
- `DELETE /v1/wallets/:id`
- `POST /v1/users` — create or get user (returns `confirm_token` if pending)
- `POST /v1/users/confirm` — confirm user account with token
- `POST /v1/sessions` — create session (requires confirmed user)
- `GET /v1/identities` — list active identities for authenticated user
- `POST /v1/identities`
- `POST /v1/identities/:id/restore` — restore identity from sealed backup
- `POST /v1/identities/:id/sign-intent`
- `POST /v1/identities/:id/sign`
- `DELETE /v1/identities/:id`
- `GET /v1/audit`
- `GET /health`

## User confirmation flow

New users start with `status: "pending"` and must confirm before they can create sessions.

```text
1. POST /v1/users { "telegram_user_id": "123" }
→ 201 { id, telegram_user_id, status: "pending", confirm_token: "<jwt>" }

2. Bot/CLI presents the confirm_token to the user via Telegram

3. POST /v1/users/confirm { "telegram_user_id": "123", "confirm_token": "<jwt>" }
→ 200 { id, telegram_user_id, status: "active" }

4. POST /v1/sessions { "telegram_user_id": "123" }
→ 200 { token, expires_in } (only works for active users)
```

## Agent Tips

All endpoints return JSON. Use `curl` + `jq` to extract specific fields:

```bash
# Check if API is healthy
curl -s https://api.clw.cash/health | jq .status

# Create a user and extract confirm_token
curl -s -X POST https://api.clw.cash/v1/users \
-H "Content-Type: application/json" \
-d '{"telegram_user_id": "123"}' | jq -r .confirm_token

# Create a session and extract the JWT
curl -s -X POST https://api.clw.cash/v1/sessions \
-H "Content-Type: application/json" \
-d '{"telegram_user_id": "123"}' | jq -r .token
```

Note: The CLI (`cash init`, `cash login`) handles the full auth flow automatically. Direct API calls are only needed for custom integrations.

## Local run

```bash
Expand Down
Loading