Pull-mirror of github.com/Sulkta-Coop/aldabra. Canonical lives on GitHub; this is a LAN-fast read-only cache.
Find a file
Kayos d007817796 feat(dao): proposal_advance state machine + stake_destroy + MCP tools
Phase 4c + 4d. Closes the DAO write-path arc (excluding GAT minting,
which is Phase 4c-bis since Sulkta has never executed a proposal).

## proposal_advance (Phase 4c)

State-machine builder with 5 transitions:
- Draft → VotingReady (cosigner threshold met, all cosigner stakes
  ref'd as txInfo.referenceInputs, sum staked_amount ≥ to_voting)
- Draft → Finished (drafting period elapsed without enough cosigners)
- VotingReady → Locked (winner outcome exists with votes ≥ execute,
  no tie)
- VotingReady → Finished (locking period elapsed without winner)
- Locked → Finished (executing period elapsed; for InfoOnly proposals)

Validator (PAdvanceProposal in Proposal/Scripts.hs:657) requires
output proposal datum equals input with ONLY status mutated. Builder
mirrors exactly. Per-transition preflights match validator gates.

Cosigner stake refs go in as txInfo.referenceInputs (not regular
inputs) per witnessStakes pattern (Proposal/Scripts.hs:366) — sum
of staked_amount is computed from the ref-input set.

GAT-minting Locked→Finished path (effected proposals) deferred to
4c-bis. The pmintGATs governor redeemer is a separate tx that fires
ONLY when the executing period is in window AND the winner outcome
has effects to mint GATs for. Sulkta's first proposal was InfoOnly
so this path never exercised on chain yet.

11 unit tests covering every transition + every preflight reject.

## stake_destroy (Phase 4d)

Burns StakeST token + returns gov-tokens to owner. From
Stake/Redeemers.hs pdestroy (~L432): owner signs (no delegatees),
all locks empty, no stake output at stakes_addr. From stakePolicy
burn branch (~L161): burntST quantity = -spentST.

Tx shape: spend stake (Destroy redeemer) + maybe a funding utxo +
collateral; mint -1 StakeST; one wallet output carrying gov-tokens
+ (stake.lovelace + funding - fee). Funding optional — stake's own
lovelace usually covers fees.

4 unit tests including the funding-optional path.

## MCP tools

dao_proposal_advance_unsigned auto-picks the right transition from
proposal status + chain tip vs window boundaries. Mainnet-only gate.
Fetches cosigner stake refs by matching owner pkh against
proposal.cosigners.

dao_stake_destroy_unsigned fetches the wallet's stake (via owner
pkh match), pulls StakeST asset name from chain, burns it.
2026-05-06 07:00:48 -07:00
crates feat(dao): proposal_advance state machine + stake_destroy + MCP tools 2026-05-06 07:00:48 -07:00
docs rename: sulkta-wallet → aldabra (per Cobb 2026-05-04) 2026-05-04 10:11:23 -07:00
.dockerignore phase 1: full read path — bip39 + cip-3 + cip-1852 + koios + age-mnemonic + rmcp 2026-05-04 11:09:00 -07:00
.gitignore phase 1 scaffold: cargo workspace + 3 crates + roadmap + architecture 2026-05-04 10:02:32 -07:00
Cargo.lock audit fixes: all 9 findings resolved + wallet generation tooling 2026-05-04 14:52:08 -07:00
Cargo.toml feat(dao): scaffold aldabra-dao crate (Phase 1 reads) 2026-05-05 13:40:12 -07:00
Dockerfile phase 1: full read path — bip39 + cip-3 + cip-1852 + koios + age-mnemonic + rmcp 2026-05-04 11:09:00 -07:00
LICENSE phase 1 scaffold: cargo workspace + 3 crates + roadmap + architecture 2026-05-04 10:02:32 -07:00
README.md rename: sulkta-wallet → aldabra (per Cobb 2026-05-04) 2026-05-04 10:11:23 -07:00
ROADMAP.md rename: sulkta-wallet → aldabra (per Cobb 2026-05-04) 2026-05-04 10:11:23 -07:00

aldabra

Rust-native Cardano lite wallet with an MCP-server interface — built for LLM-first usage (send, receive, mint, Plutus interaction).

Status: Phase 1 scaffold (2026-05-04). Compiles, structure in place, real wallet primitives still landing. See ROADMAP.md.

Why

The existing Cardano MCP servers are either read-only doc gateways (Jimmyh-world/Cardano_MCP) or built on Blockfrost (web3-mcp) which is a centralized API we deliberately don't depend on. Sulkta runs its own Koios + Ogmios endpoints on Rackham; we want a wallet that talks directly to those.

Also: it's the first Sulkta Rust project — useful as a workout for crafting-table's Rust toolchain (per Sulkta-Coop/lucy-infra spec-crafting-table.md).

Architecture

Three crates in a Cargo workspace:

Crate Responsibility
aldabra-core Pure crypto + types. Mnemonic → root key (CIP-3), root → payment + stake key (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 phase-1 implementation. Ogmios + submission paths in phase 2.
aldabra-mcp Binary. MCP server speaking stdio. Glues core + chain together, exposes tools to the LLM client.
            ┌─────────────────────────────┐
LLM client  │       aldabra-mcp (bin)      │  stdio
─────────►  │   tool handlers, lifecycle  │  ────►
            └──────────┬──────────────────┘
                       │
              ┌────────┴────────┐
              ▼                 ▼
       ┌──────────────┐  ┌──────────────┐
       │ aldabra-core  │  │ aldabra-chain │
       │ keys, sign   │  │ Koios/Ogmios │
       └──────────────┘  └──────────────┘

MCP tools (target)

Phase 1:

  • wallet.address — derived base address at account 0, index 0
  • wallet.balance — ADA + native asset balance at the wallet's address
  • wallet.utxos — list UTXOs

Phase 2:

  • wallet.send — build, sign, submit a payment (ADA or native)
  • wallet.tx_status — poll a submitted tx hash

Phase 3:

  • wallet.mint — mint a CIP-25 / CIP-68 native asset
  • wallet.policy.create — generate a policy script (timelock, multisig)

Phase 4:

  • wallet.script.attach — attach an inline datum + reference script
  • wallet.script.spend — spend a Plutus-locked UTXO with redeemer
  • wallet.stake.delegate — delegate to a pool

Build

# Local (requires rustc 1.75+)
cargo build --release

# Through crafting-table (preferred — validates the toolchain there)
crafting-table build aldabra

Run

# Direct invocation (smoke test only — does nothing useful in phase 1)
./target/release/aldabra

# As an MCP server registered with Claude Code:
# add to ~/.claude.json:
#   "aldabra": {
#     "command": "/path/to/aldabra",
#     "env": {
#       "ALDABRA_DATA": "/mnt/cache/appdata/aldabra"
#     }
#   }

Security model

  • Mnemonic source: interactive bootstrap on first run, paste once, encrypted at rest with age. Never written to disk in plaintext.
  • Derived keys: in-memory only, ZeroizeOnDrop on every container.
  • Network exposure: stdio MCP transport — never opens a TCP socket. Only the spawning client process can reach it.
  • Multi-network: mainnet by default, but --network preview / --network preprod for testing without real ADA.

See also