phase 1 scaffold: cargo workspace + 3 crates + roadmap + architecture

Repo skeleton for aldabra, the rust-native cardano lite wallet
with MCP server interface. Builds end-to-end, types in place,
real cardano primitives land next pass.

Crates:
  wallet-core   — pure crypto + types. mnemonic, key derivation,
                  signing. No I/O. Security boundary.
  wallet-chain  — pluggable backends. ChainBackend trait, Koios
                  client (stub for now). Ogmios + submit in phase 2.
  wallet-mcp    — the binary. stdio MCP transport via rmcp.

Phase plan in ROADMAP.md, threat model in docs/architecture.md.

This is also Sulkta's first Rust project + a real-world workout for
ci-runner's rust toolchain.
This commit is contained in:
Sulkta 2026-05-04 10:02:32 -07:00
commit 56bcceb593
11 changed files with 735 additions and 0 deletions

View file

@ -0,0 +1,30 @@
# wallet-mcp — the binary. MCP server speaking stdio that exposes
# the wallet's tools to an LLM. Spawned as a subprocess from any MCP
# client (e.g. Claude Code).
#
# Owns: process lifecycle, stdio transport, config loading, glue
# between core + chain crates.
[package]
name = "wallet-mcp"
version.workspace = true
edition.workspace = true
license-file.workspace = true
repository.workspace = true
authors.workspace = true
[[bin]]
name = "aldabra"
path = "src/main.rs"
[dependencies]
wallet-core = { path = "../wallet-core" }
wallet-chain = { path = "../wallet-chain" }
tokio = { workspace = true }
anyhow = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
rmcp = { workspace = true }

View file

@ -0,0 +1,74 @@
//! aldabra — MCP server entry point.
//!
//! Speaks MCP over stdio. Any MCP client (e.g. Claude Code)
//! launches this as a subprocess and gets a wallet's worth of tools.
//!
//! ## Phase 1 tools
//!
//! - `wallet.address` — return the derived base address (placeholder
//! until wallet-core's CIP-1852 derivation lands)
//! - `wallet.balance` — query balance via the configured chain backend
//!
//! ## Phase 2-4 tools (TODO)
//!
//! See ROADMAP.md at the repo root.
//!
//! ## Config
//!
//! For now: hardcoded mainnet + a stub Koios client. Real config
//! loading + mnemonic-from-encrypted-file lands once the core
//! derivation API is real.
//!
//! ## Logging
//!
//! Stderr only — stdout is the MCP transport, must stay clean.
use anyhow::Result;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> Result<()> {
// Stderr only — stdout is MCP transport
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()))
.init();
tracing::info!("aldabra starting (phase 1 scaffold)");
// TODO(phase 1):
// 1. Load config (network, koios url, mnemonic path)
// 2. Bootstrap mnemonic (interactive on first run, age-decrypt thereafter)
// 3. Derive root key
// 4. Build the chain backend
// 5. Construct the MCP server with tool handlers
// 6. Run it on stdio
// For now: a smoke-test print so the binary actually does something
// when invoked manually (not through MCP).
tracing::info!(
target_address = %wallet_core::derive_base_address(
&dummy_root_key()?,
wallet_core::Network::Mainnet,
0,
0,
)?,
"scaffold smoke test — derived placeholder address",
);
Ok(())
}
/// Phase 1 only — produces a zero-bytes RootKey so the placeholder
/// address derivation runs. Will be deleted once real mnemonic loading
/// lands.
fn dummy_root_key() -> Result<wallet_core::RootKey> {
// Need a way to construct one from this crate without exposing
// private fields. Phase 1: temporary public constructor on
// wallet-core, gated behind a #[cfg(test)] or feature flag and
// removed before phase 2.
//
// For tonight: this fn is a TODO marker — the smoke test won't
// actually run until we finish wallet-core::Mnemonic::into_root_key.
anyhow::bail!("phase 1 scaffold: real mnemonic loading not yet implemented")
}