This document provides a top-level map of the wavelength codebase: an Ark protocol client daemon that manages VTXOs, participates in rounds, and communicates with the Ark operator via a mailbox-based RPC protocol.
The codebase is organized into four layers. Dependencies flow downward; no package may import from a higher layer.
| Package | Purpose |
|---|---|
round |
Client-side Ark round participation FSM (boarding, refresh, leave) |
vtxo |
VTXO lifecycle FSM (live, forfeiting, forfeited, spent, expiring) |
oor |
Out-of-round transfer coordination FSM |
wallet |
On-chain boarding wallet actor (address derivation, UTXO monitoring) |
ledger |
Client-side durable ledger actor for double-entry fee accounting |
lib |
Shared domain utilities: tree paths, BIP-322, arkscript policy, types |
lib/arkscript |
Tapscript AST compiler and policy system for Ark taproot outputs |
lib/bip322 |
BIP-322 intent-bound message authentication |
lib/tx/arktx |
Canonical Ark transaction ordering and validation |
lib/tx/checkpoint |
Checkpoint PSBT construction for OOR transfers |
lib/tx/oor |
OOR submit/finalize package builders and validators |
lib/tx/psbtutil |
PSBT encoding, decoding, and signature attachment helpers |
lib/recovery |
Immutable recovery proof graph, session state machine, TLV codec for unilateral exit |
unrollplan |
Pure dependency-resolution planner driving unilateral-exit broadcast/sweep ordering |
vhtlcrecovery |
Durable control-plane types for vHTLC on-chain recovery jobs (action, state, script parameters, swap linkage) |
credit |
Client-side credit subsystem: supervisor/per-operation-actor pair driving fault-tolerant sub-floor pay, credit-receive, and redeem flows against the authoritative server ledger |
coinselect |
Single coin-type-agnostic coin-selection algorithm shared across wallet backends |
| Package | Purpose |
|---|---|
baselib |
Actor framework (baselib/actor) and protofsm state machine engine (baselib/protofsm) |
build |
Cross-cutting build metadata and logging infrastructure: deployment mode, build-tag-controlled log type/level, context logger propagation, subsystem logger factory, version string. Imports no repo package |
chainsource |
ChainBackend interface: fee estimation, block/conf/spend notifications |
chainbackends |
LND-backed ChainBackend implementation plus lndclient adapters (TxBroadcaster, PackageSubmitter) |
chainbackends/lndsubmitter |
chainbackends.PackageSubmitter over lnd's WalletKit; the default LND package-relay submitter |
chainfees |
Reusable chainfee.Estimator implementations and combinators for pricing transactions |
chain |
Bitcoind RPC utilities (package relay, SubmitPackage) |
txconfirm |
Generic "broadcast + CPFP fee-bump + notify on confirm" actor with per-parent fee-input reservations and BIP-125 Rule 3/4 enforcement |
unroll |
Durable per-target unilateral-exit actor + thin registry: owns proof assembly, materialization, CSV maturity, final sweep build, persist-before-broadcast, and control-plane record persistence |
lndbackend |
BoardingBackend implementation via LND's wallet kit |
lwwallet |
Lightweight in-process wallet (btcwallet + Esplora, no external LND) |
btcwbackend |
Neutrino-backed wallet backend (btcwallet + compact block filters) |
walletcore |
Shared wallet abstractions and boarding logic used by lwwallet and btcwbackend |
proofkeys |
Interface for wallet-managed key derivation and indexer proof signing |
fraud |
Fraud detection actor: watches OOR ancestor outpoints on-chain and triggers unilateral exit when an ancestor is spent |
vhtlcrecovery/coordinator |
Runtime coordinator for durable vHTLC recovery jobs: arms, escalates into unroll, cancels, and reconciles after restart |
vhtlcrecovery/unrollpolicy |
Adapter that resolves (exit_policy_kind, recovery_id) into a concrete unroll.ExitSpendPolicy for vHTLC claim and refund exits |
db |
SQLite/PostgreSQL persistence: boarding, rounds, VTXOs, OOR artifacts, fee ledger |
mailbox |
Mailbox protocol primitives across three sub-packages (pb, rpc, conn) |
serverconn |
Unified server connector: durable egress, ingress polling, unary RPC facade |
serverconn/mailboxpull |
Shared exponential-backoff retry primitives for mailbox pull loops (used by serverconn ingress and SDK swap consumers) |
rpcauth |
Shared macaroon and TLS helpers securing gRPC/REST connections |
metrics |
Prometheus instrumentation namespaced under waved_: event-driven counter actor pool plus a scrape-time SystemCollector for live gauges, and an opt-in /metrics HTTP server |
internal/sqlbase |
walletdb-compatible key/value backend over database/sql (js/wasm walletdb storage for lwwallet browser builds) |
internal/wasmhost |
js/wasm host detection (browser vs Node) and the durable SQLite VFS name that follows from it; imported by db, lwwallet, and cmd/wavewalletdk-wasm |
| Package | Purpose |
|---|---|
waved |
Daemon orchestrator: wires all subsystems, exposes gRPC API |
gateway |
HTTP gateway utilities (mux options, CORS, endpoint normalization) for grpc-gateway integration |
sdk/ark |
Consumer-facing Go SDK facade: remote or embedded daemon access with typed models |
sdk/swaps |
Lightning-to-Ark / Ark-to-Lightning atomic swap SDK with durable FSM flows |
sdk/wavewalletdk |
Wallet-shaped SDK facade for host apps: embeds the daemon in-process, dials it over a private bufconn transport, exposes typed methods for the seven core wallet verbs (create, unlock, send, recv, list, balance, exit). The highest-level layer in the stack; wraps wavewalletrpc.WalletService. Wallet RPC methods gated behind wavewalletrpc (which transitively requires swapruntime) |
sdk/wavewalletdk/mobile |
Gomobile-safe facade over sdk/wavewalletdk for Android/iOS host apps: drives an embedded in-process wallet over the private bufconn transport |
swapwallet |
Optional daemon-side wavewalletrpc.WalletService implementation (build tags wavewalletrpc swapruntime): composes the swap subsystem, cooperative leave, boarding, ledger, and unilateral-exit registry behind one flat, swap-vocabulary-free wallet API |
swapclientserver |
Optional daemon-side swap subserver (build tag swapruntime): translates swapclientrpc RPCs into sdk/swaps operations and manages the daemon-local worker registry |
cmd/waved |
Daemon entry point |
cmd/wavecli |
CLI client |
cmd/wavewalletdk-wasm |
Command compiling the embedded wavewalletdk runtime to a browser WASM binary |
timeout |
Generic timeout scheduling actor |
indexer |
Server indexing client for receive script registration |
arkrpc |
Server-side gRPC service definitions (ArkService, IndexerService) |
arkrpc/treeconv |
Narrow re-export of tree-path conversion helpers without the full gRPC surface |
rpc |
Client-side RPC message definitions (roundpb, oorpb, swapclientrpc, wavewalletrpc) and HTTP transport (rpc/restclient) |
rpc/wavewalletrpc |
Highest-level gRPC surface: WalletService with the seven core wallet verbs. Composes waverpc and rpc/swapclientrpc server-side via swapwallet |
rpc/restclient |
HTTP/protoJSON transport adapter: Client, StreamClient[T], and per-service factory functions implementing the same gRPC stub interfaces over REST |
waverpc |
Daemon gRPC API definitions |
swaprpc |
Generated gRPC/REST/mailbox-RPC stubs for the external SwapService |
| Package | Purpose |
|---|---|
p-models |
Executable P formal models and Go conformance bridge for distributed-systems properties (durable mailbox, Read/Commit fence, ingress deferral and redrive) |
p-models/durableactor/bridge |
Go conformance harness: replays P model mailbox traces against the real db/actordelivery store |
harness |
Docker-based Bitcoin/LND integration test environment |
systest |
System-level end-to-end tests |
internal/actortest |
Durable actor integration tests with real DB backends |
internal/testutils |
Deterministic key/signature generation for tests |
internal/indexerlimits |
Client-side bounds for indexer pagination cursors (defense-in-depth against misbehaving remotes) |
rules |
ast-grep linting rules for code style enforcement |
tools |
Development tool dependencies (protoc plugins, sqlc) |
cmd/protoc-gen-mailboxrpc |
protoc plugin generating typed mailbox/rpc client/server stubs from .proto service definitions |
scripts |
Build and verification scripts |
waved (orchestrator)
├── round ──────────┐
│ ├── vtxo │ (bidirectional: forfeit requests/confirmations)
│ ├── serverconn │ (outbound RPCs to operator)
│ ├── timeout │ (scheduling)
│ ├── wallet │ (boarding intents)
│ ├── ledger │ (VTXOReceivedMsg / FeePaidMsg via ledger.Sink)
│ └── lib │ (tree, types, arkscript, bip322)
├── vtxo │
│ ├── chainsource │ (block epoch events)
│ ├── ledger │ (ExitCostMsg via ledger.Sink — emission planned)
│ └── db │ (vtxo store)
├── wallet │
│ ├── chainsource │ (UTXO confirmation monitoring)
│ ├── ledger │ (UTXOCreatedMsg via ledger.Sink)
│ └── db │ (boarding store)
├── oor │
│ ├── db │ (oor artifact store)
│ ├── ledger │ (VTXOSentMsg / VTXOReceivedMsg via ledger.Sink)
│ └── lib/tx │ (arktx, checkpoint, oor, psbtutil)
├── unroll │ (unilateral-exit registry + per-target actor)
│ ├── txconfirm │ (CPFP / confirmation tracking)
│ ├── lib/recovery│ (recovery proof graph)
│ ├── unrollplan │ (pure dependency-resolution planner)
│ └── db │ (unilateral_exit_jobs store)
├── txconfirm │ (shared tx confirmation + CPFP actor; wired by waved)
├── ledger │
│ ├── baselib/actor (durable mailbox, TLV codec)
│ └── db │ (LedgerStoreDB + UTXOAuditStoreDB adapters)
├── serverconn │
│ ├── mailbox │ (protocol primitives)
│ └── db │ (durable delivery store)
├── proofkeys │ (wallet key derivation for indexer proofs)
│ └── walletcore / lndbackend (implementations)
├── chainsource │
│ └── chainbackends (pluggable: LND, lwwallet, or btcwbackend)
└── db │
└── (SQLite | PostgreSQL)
Business logic lives in pure FSM transition functions that take (State, Event) → (State, []OutboxEvent). Side effects are separated into outbox messages
dispatched by the actor runtime. See baselib/protofsm.
Concurrent, message-driven components communicate via Tell (fire-and-forget)
and Ask (request-response). Actors are registered with a Receptionist for
service discovery. See baselib/actor.
Crash-safe actors persist FSM state + outbox atomically. On restart, undelivered
outbox messages are replayed. At-least-once delivery with deduplication ensures
exactly-once semantics. See docs/durable_actor_architecture.md.
All server communication flows through serverconn, which implements unary RPCs
(low-latency) and durable event egress (crash-safe) over the mailbox protocol.
Inbound events are dispatched via EventRouter. Registered routes currently
include OOR lifecycle pushes, round progress pushes, and MethodIncomingVTXO
(which delivers arkrpc.IncomingVTXOEvent notifications to the
vtxo.IncomingVTXOHandler actor for local materialization of round-produced
VTXOs owned by the local wallet). See docs/mailbox_architecture.md.
Local wallet ownership of a VTXO is resolved at round confirmation time by
looking up its pkScript in a persistent "owned receive scripts" table (the OOR
artifact store). The round FSM calls OwnedScriptChecker.IsOwnedScript for
every VTXO in a completed round and only persists the ones the wallet
recognizes. The round actor populates this table via OwnedScriptRegistrar
when it builds change/refresh intents and when it accepts a RegisterIntentMsg
whose owner key has a non-zero KeyLocator. Directed-send recipient keys
intentionally carry a zero KeyLocator so they are not registered on the
sender side — the recipient materializes those VTXOs via the incoming VTXO
push path instead.
FSMs emit messages as data (outbox events). The actor runtime dispatches them after state is persisted. This ensures no message is sent without the corresponding state transition being durable.
| Type | Package | Purpose |
|---|---|---|
ChainBackend |
chainsource | Fee estimation, block/conf/spend notifications |
BoardingBackend |
wallet | Key derivation, taproot import, UTXO enumeration |
VTXO.Descriptor |
vtxo | Canonical VTXO: outpoint, amount, tapscript, tree path, CSV expiry |
RoundClientActor |
round | Primary FSM actor for interactive round phases |
IntentPackage |
round | Accumulated boarding/VTXO/forfeit/leave pools |
BoardingAddress |
wallet | 2-of-2 multisig (client+operator) with CSV timeout |
Envelope |
mailbox/pb | Durable unit of mailbox transport |
RPCClient |
mailbox/rpc | SendRPC/AwaitRPC interface for generated stubs |
Message |
baselib/actor | Sealed interface for actor messages |
Ref[Msg, Resp] |
baselib/actor | Typed actor reference (Tell, Ask) |
ClientWallet |
round | MuSig2 signing + key derivation interface for round participation |
OwnedScriptChecker |
round | Data-driven pkScript ownership lookup used by the round FSM at confirmation time (replaces the old IsOwner flag) |
OwnedScriptRegistrar |
round | Persists locally-owned pkScripts when the round actor builds/accepts VTXO intents so the checker recognizes them on confirmation |
IncomingVTXOHandler |
vtxo | Materializes round-produced VTXOs from indexer push notifications when the local wallet owns the receive script |
OwnedScriptLookup |
vtxo | Read-only view of the owned receive scripts store used by IncomingVTXOHandler |
VTXOReader |
wallet | Read-only VTXO descriptor access (breaks import cycle) |
SelectedVTXO |
wallet | Locked VTXO descriptor for transfer inputs (breaks import cycle) |
TxInfo |
wallet | Confirmed transaction with block hash and height |
Backend |
proofkeys | Wallet key derivation and proof signing interface |
Node |
lib/arkscript | Sealed AST node interface for tapscript compilation |
VTXOPolicy |
lib/arkscript | Compiled VTXO taproot policy with collab/exit spend paths |
Idle → PendingRoundAssembly → RegistrationSent → RoundJoined →
CommitmentTxReceived → CommitmentTxValidated → NoncesSent →
NoncesAggregated → PartialSigsSent → [ForfeitSignaturesCollecting] →
InputSigSent → Confirmed → Idle
ForfeitSignaturesCollecting is entered only when len(ForfeitMappings) > 0
(i.e., the round includes refresh or leave VTXOs). Boarding-only rounds
skip directly from PartialSigsSent to InputSigSent. Forfeit collection
happens after VTXO tree signing to ensure clients only forfeit old VTXOs
once new ones are confirmed signed.
Live → PendingForfeit → Forfeiting → Forfeited
Live → Forfeiting → Forfeited (fast path: ForfeitRequestEvent in LiveState)
PendingForfeit → UnilateralExit (critical expiry while pending)
Live → UnilateralExit (critical expiry)
Live → Spent
Any → Failed
Manages outgoing/incoming transfer state through checkpoint signing with
deterministic retry semantics. See oor/README.md (if present) or oor/doc.go.
Each major package contains a CLAUDE.md/AGENTS.md with:
- Purpose, key types, relationships (imports/imported-by)
- Actor message flows and invariants
- Links to deeper documentation
These files form a navigable graph. Start here, then follow links into packages relevant to your task.