171 lines
7.4 KiB
Markdown
171 lines
7.4 KiB
Markdown
# aldabra
|
|
|
|
Rust-native Cardano lite wallet with an MCP-server interface. Built
|
|
for LLM-first usage — send/receive ADA + native assets, mint, Plutus
|
|
script interaction, Conway governance, and a full Agora-on-Cardano
|
|
DAO client.
|
|
|
|
Named for the Aldabra giant tortoise: long-lived, defended, slow but
|
|
unstoppable.
|
|
|
|
## What it does
|
|
|
|
- **Wallet primitives.** Address derivation (CIP-1852), balance +
|
|
UTXO queries, ADA + native-asset transfers, multi-sig partial
|
|
signing, encrypted-at-rest mnemonic.
|
|
- **Minting.** CIP-25 + CIP-68 native assets, custom timelock /
|
|
multisig policies, unsigned-tx flows for cold signing.
|
|
- **Plutus V3.** Spending script-locked UTXOs with redeemers,
|
|
reference scripts, inline datum support.
|
|
- **Stake + Conway governance.** Pool delegation, DRep registration
|
|
+ deregistration, vote delegation, DRep vote casting on governance
|
|
actions.
|
|
- **DAO.** Agora-on-Cardano client — register multiple DAOs, view
|
|
stakes, create + cosign + vote on proposals, advance state-machine,
|
|
retract votes, destroy stakes.
|
|
- **Escrow.** Two-party agreement-with-veto Plutus V3 validator with
|
|
off-chain builders for the full open / deposit / agree / veto /
|
|
settle / refund lifecycle.
|
|
|
|
## Architecture
|
|
|
|
Cargo workspace with four crates:
|
|
|
|
| Crate | Responsibility |
|
|
|---|---|
|
|
| `aldabra-core` | Pure crypto + types. Mnemonic → root key (CIP-3), root → payment + stake keys (CIP-1852), address construction, signing. **No I/O, no network.** This is the security boundary. |
|
|
| `aldabra-chain` | Pluggable backends for chain queries. `ChainBackend` trait, with Koios as the default implementation. |
|
|
| `aldabra-dao` | Off-chain side of the Agora DAO + escrow validators. Codecs + unsigned-tx builders. |
|
|
| `aldabra-mcp` | Binary. MCP server speaking stdio. Wires the other crates together and exposes tools to the LLM client. |
|
|
|
|
```
|
|
┌─────────────────────────────┐
|
|
LLM client │ aldabra-mcp (bin) │ stdio
|
|
─────────► │ tool handlers, lifecycle │ ────►
|
|
└──────────┬──────────────────┘
|
|
│
|
|
┌────────┼────────┐
|
|
▼ ▼ ▼
|
|
┌──────────┐ ┌──────┐ ┌─────────┐
|
|
│ -core │ │-chain│ │ -dao │
|
|
│ keys/sig │ │ Koios│ │ Agora/ │
|
|
│ │ │ │ │ escrow │
|
|
└──────────┘ └──────┘ └─────────┘
|
|
```
|
|
|
|
## Build
|
|
|
|
```bash
|
|
# Requires rustc 1.75+
|
|
cargo build --release
|
|
```
|
|
|
|
For the Plutus validators (escrow) you also need [Aiken](https://aiken-lang.org/):
|
|
|
|
```bash
|
|
cd aiken-escrow
|
|
aiken build # produces plutus.json blueprint
|
|
```
|
|
|
|
## Run
|
|
|
|
```bash
|
|
# Smoke test (does nothing useful standalone — needs an MCP client)
|
|
./target/release/aldabra
|
|
|
|
# As an MCP server registered with Claude Code, add to ~/.claude.json:
|
|
# "aldabra": {
|
|
# "command": "/path/to/aldabra",
|
|
# "env": {
|
|
# "ALDABRA_DATA": "/path/to/wallet-data-dir",
|
|
# "ALDABRA_NETWORK": "preprod",
|
|
# "ALDABRA_KOIOS_BASE": "https://preprod.koios.rest/api/v1"
|
|
# }
|
|
# }
|
|
```
|
|
|
|
Bootstrap a wallet on first run by setting `ALDABRA_BOOTSTRAP=new`
|
|
or `ALDABRA_BOOTSTRAP=import` in env — the binary prompts for a
|
|
passphrase, generates or imports a mnemonic, and writes an
|
|
age-encrypted `mnemonic.age` to `ALDABRA_DATA`.
|
|
|
|
## Configuration
|
|
|
|
Environment variables consumed at startup:
|
|
|
|
| Var | Required | Default | Notes |
|
|
|---|---|---|---|
|
|
| `ALDABRA_DATA` | yes | — | Directory holding `mnemonic.age`. Must exist; bootstrap before first MCP run. |
|
|
| `ALDABRA_NETWORK` | no | `preprod` | One of `mainnet`, `preview`, `preprod`. |
|
|
| `ALDABRA_KOIOS_BASE` | no | public Koios for the chosen network | Override to point at a self-hosted Koios. |
|
|
| `ALDABRA_PASSPHRASE` | yes | — | Unlocks `mnemonic.age`. Source from a docker secret or systemd `EnvironmentFile` — never commit it. |
|
|
| `ALDABRA_BOOTSTRAP` | no | (unset) | Set to `new` or `import` to enter bootstrap mode on next launch. |
|
|
| `ALDABRA_MAX_SEND_LOVELACE` | no | mainnet 10 ADA / preprod\|preview 100 tADA | Hard cap on lovelace flowing to any non-self destination. Enforced by every tool that signs or submits; pass `force=true` per-tool to override. |
|
|
| `ALDABRA_SAFE_READS_ROOT` | no | `$ALDABRA_DATA/scripts/` | Sandbox dir for the `reference_script_path` / `policy_cbor_path` tool args. Files outside this dir (canonical) are refused. Created with 0o700 at startup if missing. |
|
|
|
|
## MCP tools
|
|
|
|
The server exposes ~40 tools across four prefixes. A summary:
|
|
|
|
- `wallet_*` — read (address/balance/utxos/network/stake_address),
|
|
send (with optional inline datum for script locks), mint, Plutus
|
|
script spending, stake delegation, Conway governance (vote
|
|
delegation, DRep operations).
|
|
- `chain_*` — read-only Koios passthroughs (tx info, address info,
|
|
pool list/info, epoch params, asset info, account info, tip).
|
|
- `dao_*` — Agora DAO client. Multi-DAO via config files. Live reads
|
|
(governor state, stake list, my stake) plus the full write set:
|
|
proposal create / cosign / vote / advance / retract-votes /
|
|
stake-destroy.
|
|
- `escrow_*` — two-party agreement-with-veto escrow. Build unsigned
|
|
txs for open / deposit / agree / veto / settle / refund-timeout.
|
|
|
|
Every write tool produces an unsigned tx for the caller to sign +
|
|
submit. No tool ever holds private keys outside the in-memory
|
|
derived-key scope.
|
|
|
|
## Security model
|
|
|
|
- **Mnemonic source:** interactive bootstrap on first run, paste once
|
|
or generate, encrypted at rest with
|
|
[age](https://github.com/FiloSottile/age). Never written to disk
|
|
in plaintext.
|
|
- **Derived keys:** in-memory only, `ZeroizeOnDrop` on every container.
|
|
- **Network exposure:** stdio MCP transport — the binary never opens
|
|
a TCP listener. Only the spawning client process can talk to it.
|
|
- **Multi-network:** safe to point at preprod for development; the
|
|
same binary handles mainnet when you flip `ALDABRA_NETWORK`.
|
|
|
|
## Status
|
|
|
|
Wallet + governance paths exercised on **mainnet**. DAO + escrow
|
|
paths exercised end-to-end on **preprod**; the escrow validator has
|
|
had a code review but **no third-party security audit**. Treat the
|
|
escrow flows as use-at-own-risk until external review lands — see
|
|
`aiken-escrow/README.md` for the WIP threat model.
|
|
|
|
## Contributing
|
|
|
|
Issues and pull requests are welcome. Before opening a PR, run
|
|
`cargo fmt`, `cargo clippy --all-targets`, and `cargo test`. Changes
|
|
that touch the on-chain validator (`aiken-escrow/`) or the signing
|
|
path (`aldabra-core`) should spell out the security reasoning in the
|
|
PR description.
|
|
|
|
## License
|
|
|
|
Licensed under the GNU Affero General Public License v3.0 or later
|
|
(**AGPL-3.0-or-later**). See [`LICENSE`](LICENSE) for the full text.
|
|
|
|
## Dependencies of note
|
|
|
|
- [txpipe/pallas](https://github.com/txpipe/pallas) — Rust Cardano
|
|
primitives. Aldabra uses a [fork](https://github.com/Sulkta-Coop/pallas)
|
|
on the `feat-aux-data` branch that adds `auxiliary_data` +
|
|
`voting_procedures` support to `pallas-txbuilder`. PR upstream
|
|
pending.
|
|
- [Aiken](https://aiken-lang.org/) — Plutus V3 validator language
|
|
used for the escrow contract.
|
|
- [modelcontextprotocol/rust-sdk](https://github.com/modelcontextprotocol/rust-sdk)
|
|
(`rmcp`) — MCP server framework.
|
|
- [age](https://github.com/FiloSottile/age) — at-rest encryption.
|