Monero <-> Ethereum atomic swap engine
|
|
5 hours ago | |
|---|---|---|
| .githooks | 1 week ago | |
| contracts | 6 days ago | |
| docs | 6 hours ago | |
| engine | 5 hours ago | |
| packaging | 6 days ago | |
| tools | 6 hours ago | |
| .gitignore | 3 days ago | |
| AGENTS.md | 2 days ago | |
| LICENSE | 1 week ago | |
| README.md | 6 hours ago | |
| moos | 1 week ago | |
| moos-tui | 6 days ago | |
| whitepaper.md | 10 hours ago |
moos is a Monero⟷Ethereum atomic swap engine: a swap daemon, a terminal UI,
a GTK desktop shell and a P2P offer book, all in one repository. Swaps run
trust-minimized against a pinned SwapCreator contract on Ethereum mainnet;
chain traffic is tor-only. Licensed GPL-3.0 — see LICENSE.
Alpha software. This is early software running with real funds on mainnet. Swap small amounts only, verify every address before sending, and expect no guarantees. Read docs/OPERATIONS.md before running a funded swap.
Status: version 0.1.1 (binaries answer --version as
moos 0.1.1 (rev <git-describe>); the TUI and GUI banners show the same
rev). Working today: the ETH-provides swap (the maker locks ETH, the taker
sends XMR and claims it), the tor transport (mainnet is tor-only), and the
P2P offer book (DHT-backed, with direct dial to a known maker).
git clone https://git.moos.st/moos/moos.git
cd moos
The same history is on Radicle (rad clone rad:z3vS8s9mTztnMwo1gK6pmatiFeBBc moos);
the git mirror exists so a plain git clone is enough. AGENTS.md has the
build and test commands; the build is offline from the vendored crates.
Source build (Linux x86_64):
rustc, cargo);cc — e.g. sudo apt install build-essential);curl, tar, sha256sum for the one-time pinned Monero CLI download.Linking uses the system linker (cc → ld); mold is not required and
not requested by the build. If cc cannot link a trivial program (missing
binutils, or a compiler/linker version mismatch — common on minimal
templates), the launcher stops before the build and prints the linker's
own error. On a low-RAM VM a large link can be OOM-killed (ld terminated
with signal 9); opt into the lighter mold linker per shell:
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-arg=-fuse-ld=mold".
The build itself is offline: all crates.io dependencies are vendored under
engine/vendor and no CMake is needed.
Desktop shell only (in addition to the above): python3 with PyGObject,
GTK 3 and WebKit2GTK 4.1 — e.g. sudo apt install python3-gi
gir1.2-gtk-3.0 gir1.2-webkit2-4.1.
./moos-tui
./moos-tui builds what it needs (--offline), fetches the pinned Monero
CLI itself if tools/fetch-monero.sh was skipped, and injects --mainnet.
This is real funds: fund small, check every address.
sudo apt install tor; no daemon mode or group setup needed).
MOOS_TOR_SOCKS / MOOS_TOR_CONTROL / MOOS_TOR_COOKIE point moos at a
tor you run yourself instead..onion nodes; override with
MOOS_MONEROD_HOST (loopback or .onion — a clearnet monerod is
refused) / MOOS_ETH_ENDPOINT (loopback, .onion or clearnet; clearnet
is dialed through moos's own tor). Decisive ETH reads are corroborated by a
second, independent provider — eth.drpc.org by default (MOOS_ETH_VERIFY_ENDPOINT
overrides; it must not be the primary's host).
The SwapCreator v3 address defaults
to the pinned mainnet deployment
(0xb39074e5f5bb5fd3a5fd48df867115d5c8b97e71; override with
--contract-address / MOOS_CONTRACT_ADDRESS, stagenet always needs
one) and its pinned bytecode hash is verified at launch../moos
Same launcher and daemon as the TUI, but opens a GTK3/WebKit2GTK window (no JavaScript; plain form posts served over loopback). Needs the GUI prerequisites above plus a graphical session (Wayland or X11).
There is no binary download: run from this checkout. An install tree that
bundles the binaries, tor and monero-wallet-rpc can still be assembled
locally with packaging/fetch.sh → packaging/build.sh →
tools/pack/pack.sh and checked with packaging/verify.sh; the layout is
in docs/PACKAGING.md. A packaged install defaults to
--mainnet.
| What | Source checkout | Packaged install |
|---|---|---|
| identity (ETH key + swap wallet) | rundir-mainnet/identity/ in the repo if it exists, else <state>/identity/ |
<state>/identity/ |
| tor root (DataDirectory, cookie) | rundir-mainnet/tor/ if it exists, else <state>/tor/ |
<state>/tor/ |
| per-run logs | <state>/run/mainnet/moos-<secs>-<pid>/ |
same |
<state> is $MOOS_STATE_DIR, else $XDG_DATA_HOME/moos, else
~/.local/share/moos (macOS: ~/Library/Application Support/moos).
An existing source identity is reused in place, never copied.
MOOS_MAINNET_IDENTITY_DIR relocates the identity (also how two instances
coexist on one machine). Details: docs/PACKAGING.md.
./moos shows its log stream in the launching terminal and writes the full
lines to taker.log; ./moos-tui keeps the terminal clean and writes the
file only. The terminal takes the short form in UTC —
15:36:47 [WARN] [tui] dial … — and collapses a repeat only when the line
differs solely in a timing/count field (attempt=, latency_ms=, conns=,
size_bytes= …), as (×28 more in 5s) at INFO/DEBUG and
(×28 more in 30s) at WARN/ERROR; a line carrying an id, height, amount or
balance (swap_id=, txid=, height=, amount=, balance= …) always
prints because the number is the information. The terminal is capped at 50
lines per second, while the file keeps the precise
2026-10-26T14:58:22.146Z WARN [tui] [TUI-003] dial … line, uncapped and
uncollapsed. Each run gets its own directory,
<state>/run/mainnet/moos-<secs>-<pid>/, and latest in the run root points
at the newest one (a spawned daemon's maker.log and the chain sidecar logs
land there too).
MOOS_LOG=debug ./moos # verbosity: debug|info|warn|error (default info)
MOOS_LOG_DEST=file ./moos # destinations: file|stderr|both
MOOS_LOG_TARGETS="p2p=debug,tor=warn,!tui" ./moos # per-component levels/mutes
./moos --logs # state root, newest logs, follow command
tail -f ~/.local/share/moos/run/mainnet/latest/taker.log
MOOS_LOG_TARGETS is comma-separated component=level (error|warn|info|
debug) and/or !component to mute it; the longest matching component prefix
wins (p2p covers p2p.transport), a mute beats a level, and it filters the
file as well as the terminal. MOOS_LOG_DEST=both is the desktop shell's
default; the terminal UI defaults to file and accepts both/stderr too.
Logs are local files and are never uploaded.
SwapCreator
contract.GPL-3.0 — see LICENSE.