Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
163 changes: 129 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,174 @@
# Miden Multisig

This repository provides the infrastructure for managing multi-signature accounts on the Miden network. It houses three main components:

- **miden-multisig-coordinator**: A backend coordinator server that manages multisig accounts, transaction proposals, and signature collection
- **coordinator-frontend**: A Next.js web frontend for interacting with the multisig coordinator
- **miden-multisig-client**: Client libraries for interacting with multisig accounts and the coordinator service
Multi-signature account management on the [Miden](https://miden.io) network. Multiple parties collectively control an account, requiring a configurable threshold of signatures to execute transactions.

## Status

This project is under **active development**. The APIs, data structures, and workflows are subject to change. **Expect breaking changes** as we iterate on the design and implementation.

## Overview
## Architecture

The frontend communicates directly with the [PSM (Private State Manager)](https://docs.openzeppelin.com) SDK for proposal coordination and state synchronization. The coordinator server is available as an optional backend for deployments that need centralized API access or audit trails.

```text
Frontend (Next.js + WASM)
├── WebClient (@miden-sdk/miden-sdk) ──────► Miden RPC Node
├── MultisigClient (@openzeppelin/miden-multisig-client) ──► PSM Endpoint
└── Para Wallet (@getpara/react-sdk-lite) ──► External ECDSA wallets

Coordinator Server (Rust/Axum) [optional]
├── MultisigEngine ──► Miden RPC Node
└── MultisigStore ──► PostgreSQL
```

### Components

- **coordinator-frontend** — Next.js web application. Runs a WASM-compiled Miden client in the browser, connects to PSM for proposal coordination, and supports multiple wallet types for signing.
- **coordinator-server** — Rust/Axum HTTP server that wraps the multisig engine. Provides a REST API for account creation, transaction proposals, and signature collection. See [`bin/coordinator-server/README.md`](bin/coordinator-server/README.md) for the full API reference.
- **miden-multisig-client** — Rust client library for multisig operations, used by the coordinator engine.

### Wallet Support

The Miden MultiSig system enables multiple parties to collectively control an account, requiring a threshold of signatures to execute transactions. The coordinator server acts as a central point for:
The frontend supports three wallet sources for signing:

- Creating and managing multisig accounts
- Coordinating transaction proposals
- Collecting and verifying signatures from approvers
- Executing transactions once the signature threshold is met
| Source | Scheme | Description |
|--------|--------|-------------|
| **Local keys** | Falcon / ECDSA | Browser-generated keys stored in IndexedDB |
| **[Para](https://getpara.com)** | ECDSA | External EVM wallets (MetaMask, etc.) via Para SDK |
| **[Miden Wallet](https://github.com/demox-labs/miden-wallet)** | Falcon / ECDSA | Miden Wallet browser extension |

## Workspace Structure

```text
.
├── bin/
│ ├── coordinator-frontend/ # Web frontend application
│ └── coordinator-server/ # Coordinator server binary and configuration
│ ├── coordinator-frontend/ # Next.js web frontend (PSM SDK + WASM)
│ └── coordinator-server/ # Rust coordinator server (Axum + PostgreSQL)
├── crates/
│ ├── coordinator/
│ │ ├── domain/ # Core domain models and types
│ │ ├── engine/ # Business logic and multisig engine
│ │ ├── store/ # Database layer and persistence
│ │ ├── store/ # PostgreSQL persistence (Diesel ORM)
│ │ └── utils/ # Shared utilities
│ └── miden-multisig-client/ # Client library for multisig operations
│ └── miden-multisig-client/ # Rust client library for multisig operations
├── Dockerfile.coordinator # Docker image for coordinator server
├── Dockerfile.coordinator-frontend # Docker image for frontend
└── docker-compose.yml # Docker compose setup (frontend + server + PostgreSQL)
└── docker-compose.yml # Full stack: frontend + server + PostgreSQL
```

## Quick Start with Docker

For local development and testing, you can quickly spin up the entire stack (frontend, coordinator server, and PostgreSQL) using make targets:

### Start the Coordinator Server + Frontend application
Spin up the full stack (frontend, coordinator server, and PostgreSQL) locally:

```bash
make docker-run-coordinator
```

This will:

- Build the Docker images for the frontend and coordinator server
- Start PostgreSQL database with the required schema (see [migrations](crates/coordinator/store/migrations))
- Start the coordinator server listening on `http://localhost:59059`
- Start the frontend web application at `http://localhost:3000`
This builds the Docker images and starts:

The server exposes a REST API for multisig operations and includes a `/health` endpoint for monitoring. The frontend provides a user-friendly interface for managing multisig accounts and transactions.
| Service | URL | Description |
|---------|-----|-------------|
| Frontend | `http://localhost:3000` | Web UI |
| Coordinator Server | `http://localhost:59059` | REST API (+ `/health` endpoint) |
| PostgreSQL | `localhost:5432` | Database |

### Stop All Services
To stop and remove all containers:

```bash
make docker-stop-coordinator
```

This will stop and remove all containers. Note that the multisig client store and the PostgreSQL database are ephemeral (no persistent volumes), so all data will be lost when containers are stopped.
> **Note:** The PostgreSQL database is ephemeral (no persistent volumes). All data is lost when containers stop.

## Configuration

### Frontend Environment Variables

The frontend is configured via `NEXT_PUBLIC_*` environment variables, set at build time. In Docker, these are defined in the `frontend` service in `docker-compose.yml`.

| Variable | Description | Default |
|----------|-------------|---------|
| `NEXT_PUBLIC_PSM_ENDPOINT` | PSM service URL for proposal coordination | `https://psm-stg.openzeppelin.com` |
| `NEXT_PUBLIC_MIDEN_RPC_URL` | Miden node RPC endpoint | `https://rpc.devnet.miden.io` |
| `NEXT_PUBLIC_PARA_API_KEY` | [Para](https://getpara.com) wallet API key (enables Para wallet support) | _(empty — Para disabled)_ |
| `NEXT_PUBLIC_PARA_ENVIRONMENT` | Para environment (`development` or `production`) | `development` |
| `NEXT_PUBLIC_COORDINATOR_API_URL` | Coordinator server URL (internal, for server-side requests) | — |
| `NEXT_PUBLIC_EXTERNAL_COORDINATOR_API_URL` | Coordinator server URL (external, for browser requests) | — |

> `VITE_PARA_API_KEY` is also accepted as a compatibility alias for `NEXT_PUBLIC_PARA_API_KEY`.

### Coordinator Server Environment Variables

The server reads `bin/coordinator-server/src/base_config.ron` as defaults and overrides values with environment variables prefixed `MIDENMULTISIG_`. Use `__` for nested keys.

| Variable | Description | Default |
|----------|-------------|---------|
| `MIDENMULTISIG_APP__LISTEN` | Server bind address | `localhost:59059` |
| `MIDENMULTISIG_APP__NETWORK_ID_HRP` | Bech32 human-readable prefix | `mtst` |
| `MIDENMULTISIG_APP__CORS_ALLOWED_ORIGINS` | JSON array of allowed origins | `["*"]` |
| `MIDENMULTISIG_DB__DB_URL` | PostgreSQL connection string | `postgres://multisig:multisig_password@localhost:5432/multisig` |
| `MIDENMULTISIG_DB__MAX_CONN` | Connection pool size | `10` |
| `MIDENMULTISIG_MIDEN__NODE_URL` | Miden node RPC URL | `https://rpc.testnet.miden.io:443` |
| `MIDENMULTISIG_MIDEN__STORE_PATH` | Local Miden client store path | `./store` |
| `MIDENMULTISIG_MIDEN__KEYSTORE_PATH` | Keystore directory path | `./keystore` |
| `MIDENMULTISIG_MIDEN__TIMEOUT` | Request timeout | `30s` |
| `RUST_LOG` | Log level (`debug`, `info`, `warn`, `error`) | `info` |

For full server configuration details, see [`bin/coordinator-server/README.md`](bin/coordinator-server/README.md).

## Local Development

### Prerequisites

- **Rust** 1.90+ (see [`rust-toolchain.toml`](rust-toolchain.toml))
- **Node.js** 18+
- **PostgreSQL** 13+ (or use Docker)
- **Docker** (for containerized setup)

### Development Tools

```bash
# Check which tools are installed
make check-tools

# Install all required dev tools (typos, nextest, taplo, machete)
make install-tools
```

### Frontend

```bash
cd bin/coordinator-frontend
npm install
npm run dev
# → http://localhost:3000
```

Create a `.env.local` file for local development:

```bash
NEXT_PUBLIC_PSM_ENDPOINT=https://psm-stg.openzeppelin.com
NEXT_PUBLIC_MIDEN_RPC_URL=https://rpc.devnet.miden.io
NEXT_PUBLIC_PARA_API_KEY=<your-para-api-key>
NEXT_PUBLIC_PARA_ENVIRONMENT=development
```

### Server

### Configuration
See the [database migrations section](crates/coordinator/store/README.md#database-migrations) for PostgreSQL setup, then:

The coordinator server is configured via environment variables in `docker-compose.yml`. Key settings include:
```bash
cargo run --release --bin miden-multisig-coordinator-server
```

- **Application**: Listen address, network ID
- **Database**: PostgreSQL connection string and pool settings
- **Miden**: Node RPC URL, store path, keystore path
### Common Make Targets

For detailed configuration options, see `bin/coordinator-server/src/base_config.ron` and the environment variables in `docker-compose.yml`.
```bash
make build # Build all Rust crates (release)
make test # Run tests
make lint # Run all linters (clippy, fmt, taplo, typos, machete)
make check # Check all targets for errors
```

## License

Expand Down
79 changes: 56 additions & 23 deletions bin/coordinator-frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,90 @@
## Coordinator Frontend

The coordinator frontend is built with Next.js and connects to the multisig coordinator backend. This document focuses on the pieces you need to run and develop the UI locally.
Next.js web application for managing Miden multisig accounts. Uses the [PSM SDK](https://docs.openzeppelin.com) (`@openzeppelin/miden-multisig-client`) for proposal coordination and a WASM-compiled Miden client (`@miden-sdk/miden-sdk`) running in the browser.

> [!NOTE]
> After v0.13.x testnet, the frontend only coordinates using [PSM](https://github.com/OpenZeppelin/private-state-manager.git). The coordinator server backend present in this repository is ignored even when running.

## Prerequisites

- Node.js 18+
- pnpm, npm, yarn, or bun
- Access to a running coordinator backend (local or remote)
- npm, pnpm, yarn, or bun

## Environment setup
## Environment Setup

Create `.env.local` in the project root:

```bash
# Required
NEXT_PUBLIC_PSM_ENDPOINT=https://psm-stg.openzeppelin.com
NEXT_PUBLIC_MIDEN_RPC_URL=https://rpc.devnet.miden.io

# Para wallet support (optional — enables external EVM wallet signing)
NEXT_PUBLIC_PARA_API_KEY=<your-para-api-key>
NEXT_PUBLIC_PARA_ENVIRONMENT=development

# Coordinator server (optional — only needed if running the coordinator backend)
NEXT_PUBLIC_COORDINATOR_API_URL=http://localhost:59059
NEXT_PUBLIC_MIDEN_NODE_ENDPOINT=https://rpc.testnet.miden.io:443
NEXT_PUBLIC_EXTERNAL_COORDINATOR_API_URL=http://localhost:59059
```

Additional environment options are documented in [ENV_CONFIG.md](./ENV_CONFIG.md).
| Variable | Description | Default |
|----------|-------------|---------|
| `NEXT_PUBLIC_PSM_ENDPOINT` | PSM service URL | `https://psm-stg.openzeppelin.com` |
| `NEXT_PUBLIC_MIDEN_RPC_URL` | Miden node RPC endpoint | `https://rpc.devnet.miden.io` |
| `NEXT_PUBLIC_PARA_API_KEY` | Para wallet API key | _(empty — disabled)_ |
| `NEXT_PUBLIC_PARA_ENVIRONMENT` | Para environment (`development` / `production`) | `development` |

## Install dependencies
## Install Dependencies

```bash
pnpm install
# or
npm install
```

## Run the development server
## Run the Development Server

```bash
pnpm dev
# or
npm run dev
```

Open <http://localhost:3000> to view the app. Changes in `src` hot-reload automatically.
Open <http://localhost:3000> to view the app. Changes in `src/` hot-reload automatically.

## Available scripts
## Available Scripts

```bash
pnpm build # Create a production build
pnpm start # Serve the production build
pnpm lint # Run lint checks
npm run build # Create a production build (standalone output)
npm run start # Serve the production build
npm run lint # Run lint checks
```

## Project Structure

```text
src/
├── app/ # Next.js app router (pages and layouts)
│ ├── login/ # Account creation and loading flows
│ └── dashboard/ # Main dashboard (home, assets, transactions, settings)
├── components/ # Shared UI components (AppHeader, Providers)
├── contexts/ # MultisigContext — central state manager
├── hooks/ # useParaSession, useMidenWallet
├── interactions/ # Modal flows (send, receive, sign, approve)
├── lib/ # Core logic (initClient, multisigApi, procedures)
├── store/ # Redux store (wallet form state)
├── types/ # TypeScript type definitions
└── wallets/ # Wallet source types and abstractions
```

## Project structure
### Key Files

- `src/app` – Next.js app directory for routes and UI
- `src/services` – API clients and async thunks
- `src/interactions` – Wallet interactions and modal flows
- `src/contexts` – React context providers
- **`src/contexts/MultisigContext.tsx`** — Central state manager. Initializes the WebClient and MultisigClient, manages account state, proposals, and signing operations.
- **`src/lib/initClient.ts`** — WebClient (WASM) and signer key initialization.
- **`src/lib/multisigApi.ts`** — MultisigClient creation and signer factory.
- **`src/config/psm.ts`** — PSM, Miden RPC, and Para configuration constants.
- **`src/hooks/useParaSession.ts`** — Para wallet connection and ECDSA key derivation.
- **`src/hooks/useMidenWallet.ts`** — Miden Wallet browser extension integration.

## Troubleshooting

If the UI fails to reach the coordinator API, confirm the values in `.env.local` and ensure the backend is reachable from your machine.
- **WASM loading fails** — Ensure `public/miden_client_web.wasm` exists. The webpack config in `next.config.mjs` copies it to the required locations during build.
- **Para wallet not showing** — Verify `NEXT_PUBLIC_PARA_API_KEY` is set. The Para modal only renders when an API key is present.
- **State issues after upgrade** — The app clears IndexedDB (`MidenClientDB`) on initialization. If you see stale data, try clearing browser storage manually.