Avato: multi-chain P2P wallet and MLS-secured messaging. Hard-forked from freenet/river (LGPL-3.0) on 2026-07-11. See Avato Architecture Spec v0.2 for design intent.
  • Rust 96.8%
  • TypeScript 2.2%
  • Shell 0.5%
  • CSS 0.3%
  • HTML 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Arthur Zhang f987988a48
Some checks failed
Build / build (push) Has been cancelled
Build / ui-playwright-tests (push) Has been cancelled
Check CLI WASM Sync / check-wasm-sync (push) Has been cancelled
Clippy / clippy (push) Has been cancelled
Build / Claude CI Analysis (push) Has been cancelled
feat: enforce HD wallet host and delegate boundaries
2026-07-13 16:34:43 +08:00
.cargo chore: clean up left overs 2026-03-26 17:35:56 +01:00
.claude fix: harden production chat wallet and replication paths 2026-07-13 09:13:06 +08:00
.githooks feat(common): in-room encrypted direct messages between members (#230 Phase 1) (#240) 2026-05-13 10:17:26 -05:00
.github/workflows feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
.mavis/plans feat: integrate wallet host and harden Avato architecture 2026-07-13 14:00:53 +08:00
.swarm fix: Update dependencies to resolve tokio-tungstenite version conflict 2025-09-05 01:43:49 +02:00
.vscode missing files 2024-12-15 18:22:32 -06:00
.zed checkpoint before aider on tests 2024-08-17 16:06:54 -05:00
cli feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
common feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
contracts/web-container-contract feat: integrate wallet host and harden Avato architecture 2026-07-13 14:00:53 +08:00
crypto feat(crypto): support verifier-only HPKE builds 2026-07-13 14:08:51 +08:00
docs feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
fuzz test(fuzz): P2-8 G.4 — add 3 adversarial targets (capability_acl + 2 aliases) 2026-07-12 23:38:30 +08:00
protocol feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
published-contract test(common): V2 envelope integration tests + version bump + spec §7.5 2026-07-13 00:38:08 +08:00
replication feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
room feat: integrate wallet host and harden Avato architecture 2026-07-13 14:00:53 +08:00
scripts feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
storage/local-vault feat: integrate wallet host and harden Avato architecture 2026-07-13 14:00:53 +08:00
tests/adversarial-network test(e2e): adversarial net-sim + freenet-core workflow doc (P1-3) 2026-07-13 00:13:06 +08:00
ui feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
wallet feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
.gitignore chore: remove macOS metadata from the repository 2026-07-13 14:03:22 +08:00
.gitmodules Remove stdlib submodule, and used published versions of scaffold and scaffold-macro 2025-04-18 09:58:00 -05:00
.prettierrc readme 2024-10-14 09:46:29 -05:00
AGENTS.md rebrand: River -> Avato (hard-fork, sever upstream, retarget at Avato Architecture Spec v0.2) 2026-07-11 13:49:52 +08:00
Cargo.lock feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
Cargo.toml feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
CLAUDE.md docs: add agent instructions include 2025-11-05 21:35:27 +01:00
clippy.toml chore(governance): re-enable clippy with scoped lint set (F-TA-006) 2026-07-12 23:34:29 +08:00
CONTRIBUTING.md docs: add CONTRIBUTING.md with AI tooling requirements 2026-02-11 22:36:43 -06:00
CONVENTIONS.md rebrand: River -> Avato (hard-fork, sever upstream, retarget at Avato Architecture Spec v0.2) 2026-07-11 13:49:52 +08:00
DEVNOTES.md rebrand: River -> Avato (hard-fork, sever upstream, retarget at Avato Architecture Spec v0.2) 2026-07-11 13:49:52 +08:00
legacy_delegates.toml feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
LICENSE chore: update LICENSE to LGPL-3.0 to match crate manifests 2026-04-23 08:57:38 -05:00
Makefile.toml feat: integrate wallet host and harden Avato architecture 2026-07-13 14:00:53 +08:00
README.md feat: enforce HD wallet host and delegate boundaries 2026-07-13 16:34:43 +08:00
rust-toolchain.toml fix: make committed WASM the authoritative source for delegate migration 2026-04-12 12:58:33 -05:00
screenshot.png docs: update README with current screenshot and roadmap 2026-01-15 10:31:05 -06:00

Avato

Conversation is where value gets meaning.

Avato is a crypto-native communication and social wallet: rooms are replicated as verifiable state, identities are scoped instead of globally exposed, and payments begin as human intent rather than opaque transaction bytes.

Avato is CKB-first and chain-extensible. CKB is the reference integration for account derivation, lock semantics, cell selection, transaction review, signing and receipts. Bitcoin and Kaspa use the same typed adapter boundary without leaking chain-specific formats into the room protocol.

Source · Architecture · Protocol versions · Readiness

Avato chat interface

Development status

Avato is under active development. Public rooms and the established V1 room path are usable today. MLS V2 types, epoch validation and client-side crypto components have landed, but production private messaging remains on the authenticated V1 compatibility path while persistent per-room MLS sessions, Welcome/Commit lifecycle and device-leaf management are completed. The wallet host and chain adapters are present; real funding selection and broadcast require a configured chain-state gateway.

Why Avato exists

People do not think in witness bytes, signature domains or transaction hashes. They think in context:

  • “This is the room where we agreed to pay.”
  • “Send 100 CKB to this address.”
  • “Show me exactly what will leave my wallet before I approve it.”
  • “Remove this device without turning off the whole identity.”

Avato keeps that human context attached to the cryptography. A payment request is typed and bound to its room. A review shows the exact chain, network, inputs, outputs and fee. Signing happens only after explicit approval, inside a local wallet security boundary. A receipt can return to the conversation that gave the payment meaning.

The same rule applies to messaging: the network may replicate room state, but it does not become the authority for identity, plaintext or wallet keys.

The architecture in one picture

The intended boundary is deliberately split into small authorities. No single UI process should own every secret.

flowchart LR
    PERSON["Person"] --> UI["Avato UI\npresentation + consent"]

    UI -->|"typed room commands"| DELEGATE["Avato Delegate\ndevice keys + MLS + orchestration"]
    UI -->|"review / approve"| WSH["Wallet Security Host\nmnemonic + identity root + chain roots"]

    DELEGATE --> VAULT["Encrypted local store"]
    DELEGATE --> REPLICATION["ReplicationBackend"]
    REPLICATION --> FREENET["Freenet\nreplicated availability"]
    FREENET <--> CONTRACT["Room contracts\nverifiable public state"]

    WSH --> ADAPTERS["Typed chain adapters"]
    ADAPTERS --> CKB["CKB node / light client"]
    ADAPTERS --> BTC["Bitcoin node / light client"]
    ADAPTERS --> KASPA["Kaspa node / light client"]

    WSH -->|"device certificate / wallet proof"| DELEGATE
    DELEGATE -->|"signed state + ciphertext"| CONTRACT

This separation gives each component one job:

  • Freenet makes room state available without becoming a trusted database.
  • Room contracts validate membership, moderation and canonical state.
  • The Delegate owns messaging protocol state and talks to replication.
  • The Wallet Security Host owns recovery and spending authority.
  • The UI explains what is happening and captures meaningful consent.

Crypto-native means keys have one job

A single recovery phrase can restore multiple public identities and chain accounts without making those keys interchangeable. Avato treats key separation as a protocol invariant, not a naming convention.

flowchart TD
    MNEMONIC["BIP-39 recovery root\nWallet Host only"]

    MNEMONIC --> APPROOT["Avato identity root"]
    MNEMONIC --> CKBROOT["CKB account root\nm/44'/309'/..."]
    MNEMONIC --> BTCROOT["Bitcoin account root"]
    MNEMONIC --> KASROOT["Kaspa account root"]

    RNG["OS randomness"] --> DEVICE["Device auth key"]
    RNG --> MLSSIG["MLS signature key"]
    RNG --> MLSHPKE["MLS HPKE key"]

    APPROOT -->|"authorises public device keys"| CERT["Device certificate"]
    APPROOT -->|"room-scoped derivation"| ROOMID["Room member credential"]
    CERT --> LEAF["One device = one MLS leaf"]
    MLSSIG --> LEAF
    MLSHPKE --> LEAF

The arrows describe derivation or authorisation, never key reuse. In particular:

  • wallet keys are not chat keys;
  • Ed25519 signing keys are not converted into X25519 private keys;
  • MLS epoch and message secrets are random, not derived from the mnemonic;
  • wallet-binding signatures and transaction signatures use different domains;
  • the formal signing transcript binds protocol, network, object type, version and payload hash using canonical CBOR.

Why CKB first

CKB makes authority explicit through cells, lock scripts and witnesses. That fits Avato's goal: show the user exactly which authority is being exercised, then bind approval to those exact bytes.

The CKB adapter currently models:

  • BIP-44 account derivation at m/44'/309'/account'/change/index;
  • CKB mainnet and testnet address parsing;
  • the standard secp256k1-blake160 lock profile;
  • live cells as explicit funding inputs;
  • capacity transfer, change output, cell deps and witness signing;
  • chain- and approval-bound transaction signing.

CKB-first does not mean CKB-only. ChainAdapter keeps the room and intent formats chain-neutral. Bitcoin and Kaspa implement their own address, funding, fee and signing semantics behind the same boundary.

From a message to a reviewed CKB payment

Avato never treats text that looks like a payment as permission to spend.

sequenceDiagram
    actor Person
    participant UI as Avato UI
    participant Host as Wallet Security Host
    participant State as Chain-state gateway
    participant CKB as CKB
    participant Room as Room contract

    Person->>UI: “Pay 100 CKB”
    UI->>Host: PaymentRequestV1 + room_scope_id + account
    Host->>State: Select live cells and estimate fee
    State-->>Host: Exact inputs + evidence tier
    Host-->>UI: Human-readable transaction review
    UI-->>Person: Inputs, recipient, amount, change, fee
    Person->>UI: Approve this exact review
    UI->>Host: Execute unchanged intent + review
    Host->>State: Revalidate inputs
    Host->>CKB: Broadcast signed transaction
    CKB-->>Host: Transaction id
    Host-->>UI: Signed receipt
    UI->>Room: Publish receipt message

The review and execute steps are intentionally separate. Changing the recipient, amount, fee or selected inputs invalidates the approval.

Rooms and private messaging

An Avato room is replicated state with cryptographically validated changes. It can remain available when its creator is offline, and an untrusted peer can store or forward it without gaining permission to forge membership or content.

Public rooms expose their content to anyone who can resolve the contract. Private rooms encrypt content but do not promise traffic-analysis resistance: room existence, approximate timing, ciphertext sizes and activity patterns may remain observable.

The private-room transition is explicit rather than hidden behind marketing:

flowchart LR
    V1["Existing V1 private room\nauthenticated AES-256-GCM"]
    SNAPSHOT["Signed final V1 commitment\n+ roster snapshot"]
    GENESIS["MLS V2 genesis\n+ device leaves"]
    EPOCH["MLS epochs\nProposal → Commit → Cutover"]

    V1 -->|"local legacy read"| SNAPSHOT
    SNAPSHOT -->|"no history replay or re-encryption"| GENESIS
    GENESIS --> EPOCH
    EPOCH -->|"remove / update"| EPOCH

New private-room creation remains disabled until the production clients can persist a genuine per-room MLS session and prove join, removal, restart and no-pre-join-history behaviour end to end. See the architecture specification for the full threat model and acceptance criteria.

What is in the repository

Area Responsibility
protocol/ Canonical CBOR and domain-separated signing transcripts
crypto/ MLS, HPKE envelopes, secure memory and attachment crypto
room/ Epoch coordination, credentials, migration, recovery and message envelopes
wallet/ HD wallet core, CKB/BTC/Kaspa adapters, intents, device certificates and Wallet Host
replication/ Backend abstraction, Freenet adapter, room contract and Delegate
storage/ Encrypted local vault
common/ Shared room-state and compatibility types
ui/ Dioxus web UI compiled to WebAssembly
cli/ avatoctl for operators, automation and testing
tests/ and fuzz/ Adversarial simulation, property tests and fuzz targets

Run Avato locally

Prerequisites

  • Rust through rustup — the repository pins its own toolchain and WASM target;
  • Node.js 20 or newer and npm;
  • cargo-make;
  • Dioxus CLI.
cargo install cargo-make
cargo install dioxus-cli

Clone and start the UI with local example data

This path is the quickest way to explore the interface. It does not require a Freenet node and does not touch real wallet keys.

git clone ssh://forgejo@git.avato.online/AvatoLabs/avato.git
cd avato

cargo make setup
cd ui && npm install && cd ..
cargo make dev-example

Open the URL printed by Dioxus, normally http://localhost:8080.

To run against a local Freenet node, follow the Freenet quickstart and use:

cargo make dev

Wallet Host development

Create or import a wallet through the host's private terminal so the recovery phrase is never sent through the browser:

cargo run -p avato-wallet-host-service --bin avato-wallet-host -- create
# or
cargo run -p avato-wallet-host-service --bin avato-wallet-host -- import

Start the loopback service:

AVATO_CHAIN_GATEWAY_URL=http://127.0.0.1:7820 \
  cargo run -p avato-wallet-host-service --bin avato-wallet-host -- serve

The host prints a process-scoped pairing token. A trusted desktop shell injects the loopback URL and token into the UI. Without a configured chain-state gateway, funding selection and transaction broadcast fail closed.

CLI

avatoctl provides room operations and machine-readable output for operators, bots and test environments.

cargo install avatoctl
avatoctl --help

# From this checkout instead:
cargo run -p avatoctl -- --help

Use --format json when another program consumes the output. The CLI remains subject to the same protocol-version and private-room migration boundaries as the UI.

Build and verify

cargo make test                 # workspace test gate
cargo make test-adversarial     # malicious network simulation
cargo make clippy               # correctness and suspicious lint gate
cargo make build                # release UI + contracts
cargo make package-desktop      # reproducible host package

Contract and Delegate WASM identities are content-addressed. Before changing their toolchain, dependencies or bytes, read the migration rules in AGENTS.md and docs/PROTOCOL_VERSIONS.md.

Security posture

Avato is designed to fail closed:

  • unavailable private-room secrets must not downgrade a message to plaintext;
  • a payment message must not trigger signing by itself;
  • signatures from the wrong object, chain or network domain are rejected;
  • stale or unverified funding must not reach transaction signing;
  • replication peers are treated as adversarial availability providers.

This is not a promise of anonymity or complete metadata hiding. It is a design for local key custody, explicit authority and verifiable state. Please report security-sensitive findings privately to the maintainers rather than opening a public exploit issue.

Contributing

Start with CONTRIBUTING.md, then read the architecture and protocol-version documents relevant to your change. Issues and development discussion live at git.avato.online.

License

Avato is free software distributed under the GNU Lesser General Public License v3.0 (LGPL-3.0). See LICENSE for the complete license text. Existing copyright and license notices in individual files remain in force.