Repository navigation
Releases
v0.2.6 — the three M3 acceptance items
Closes the three items Logos listed in logos-co/rfp#123 as blocking M3 acceptance.
Documentation and one example only. No crate behaviour, deployment, or protocol code changed from v0.2.5 (c99ff8ce). The three demo recordings stay attached to the v0.2.5 release; they are not duplicated here.
The LEZ/BTC SDK now has a name and a map
docs/sdk-lez-btc.md says the artefact is lez-btc-swap-sdk (crates/btc-swap-sdk) with lez-swap-sdk-core (crates/swap-sdk-core), and maps offer discovery, negotiation, escrow creation, claim, and refund to the public API and to the test that drives each one. It also states the boundaries: discovery and negotiation are ports with no shipped Delivery or Chat transport, and LEZ transactions are built in lez-bridge-adapter, not in the SDK.
crates/btc-swap-sdk/examples/full-lifecycle.rs is a runnable walk through all five stages:
cargo run -p lez-btc-swap-sdk --example full-lifecycleIt publishes an offer, discovers it, negotiates a countersigned agreement, activates, drives both locks and both claims to Completed, then replays the same agreement on a swap nobody claims and takes it through both ordered refunds. Fixed secrets, no I/O, and it compiles under --all-targets with pedantic Clippy denied.
The testnet guide documents the route we actually ran
docs/bitcoin-testnet4-setup.md previously described a self-hosted Testnet4 node and an operator-allowlisted HTTPS gateway. It did not describe the keyless public RPC provider on Testnet3 that docs/evidence/testnet3-provider-20260918/ records, and it never said which swap direction that route serves.
It now opens with a route table and covers three routes, each with wallet creation, funding, and the directions it serves:
| Route | Network | Node wallet | Directions |
|---|---|---|---|
| A — self-hosted Core 31.1 | Testnet4 | required | both |
| B — exact allowlisted HTTPS gateway | Testnet4 | required | both |
| C — keyless public RPC provider | Testnet3 | none | TakerSellsForeign only |
The walletless public-provider route serves TakerSellsForeign only. A provider exposes no wallet RPCs, and in TakerSellsLez the Maker funds the Bitcoin second lock from bitcoin.wallet on its own node. In TakerSellsForeign the Taker's first lock is signed externally and handed over as funding_transaction_hex, and the Maker's only Bitcoin action is the follow-up claim, which needs no wallet.
The guide's "no public RPC, peer, gateway, faucet, funds, or transaction was used for certification" line is now scoped to the M3 private-local certification it describes, since later public runs exist.
Traceability
Rows U1, U8, S8 and D1 updated with evidence links, marked BTC-done with XMR and ZEC still planned. F2 is deliberately untouched: it turns on Logos's acceptance, not on our documentation. docs/milestone-3-review.md names the SDK artefact and carries a note that no gate result, evidence hash, run identity, or claim boundary in that dated review was changed.
v0.2.5
v0.2.5
Answers the Logos QA review of v0.2.4 (98f492ad) — the findings Danish named for this
release. Two product fixes, three new end-to-end scenarios that pin behaviour nothing
asserted before, and the operator packaging that makes chain-outage reporting work.
Product fixes
A claim now requires both legs funded, not a phase that once said so (CODE-4, #97)
SwapCoordinator kept no per-leg funding state: confirmation depth arrived as a transient
proof, was compared inline and discarded, so phase alone carried both legs. Both claim
gates therefore accepted a claim whenever the phase was BothLegsLocked. A presence check
would not have been enough — on the double-removal path the maker transaction id is
retained, so is_some() misses exactly the reported case.
Two per-leg flags now record "met its own confirmation policy and has not regressed
since", maintained in the four observers and required by both claim gates. Three new
lifecycle tests cover it, and all three fail without the fix.
Worth stating plainly: this was never reachable in a released Bitcoin swap. The BTC
path does not call the coordinator's removal entry points; remove-then-re-add exists only
on the Zcash path. It is a latent hole in shared shipped code.
One missing chain tool no longer stops the Maker, and outages get reported
(CODE-3 + PKG-1, #96)
The bug was an asymmetry. At runtime a missing or hash-changed route-health probe already
degraded just its own route to unavailable. Only at startup parse was it fatal, and it
happened six lines before the owner socket is bound — so with Type=notify there was no
socket, no ready file and no sd_notify, and systemd reported a start timeout rather than
a bad config. Startup is now as tolerant as runtime: the route is kept, reads unavailable,
and recovers by itself once the operator installs the executable the digest names. Two
further fatal exits — the initial reconciliation and the periodic tick, which killed the
daemon on any error including a transient one — are now logged and retried.
Packaging ships what was missing: a route-health example config, an operator guide, and
both installed by install-maker-node-service.sh. The guide leads with the sharp edge —
a route left out of the file reads unavailable, not unprobed, so the Maker will
refuse to quote or publish on it and will withdraw its live offers there. That is
deliberate fail-closed behaviour, but it has to be documented to be safe.
Test coverage the review asked for
- The cooperative claim is a plain Taproot key-path spend (COV-1, #98) — asserted on a
real chain transaction now, not only in prose: one input, one 64-byte Schnorr signature,
no script. Production has always refused anything else; nothing checked it end to end. - The Maker will not lock before the Taker's lock confirms (COV-4, #98) — the miner is
held so the Taker's lock sits unconfirmed, and the Maker must sit with it for 90 s
before the block arrives. - A swap in flight needs nothing off chain (COV-3, #99) — Logos Chat and Delivery are
both cut after the first lock and stay down until the swap completes. The Maker reports
both unavailable and degraded, the swap finishes on chain state alone, and degraded
clears by itself when they return. The outage tests we had all acted before a swap
started.
Fixed reported issues
- #91 — the desks show the real connection state (a local RPC client was answering an
undeliverable call with its ownok:falseenvelope as a successful call, so the desks
read as connected with both Nodes stopped) - #92 — native bridge command
Not in this release, by the milestone split
CODE-1 and CODE-2 (Zcash refund-deadline ordering) belong to the Zcash milestone, DOC-1
(Monero setup docs) to the Monero milestone, and DOC-3 (doc packets, third-party review
reports) to the audit milestone.
COV-6 says all v0.2.4 evidence is regtest/devnet. That is not right — three
public-network evidence folders ship in the v0.2.4 tag, covering both directions plus a
refund run with corrected timings on LEZ testnet and Bitcoin testnet4.
Images
Published to ghcr.io/gateway-fm/lez-atomic-swaps/ at tag v0.2.5, from release-images
run 36473887545 —
green including the job that pulls the published images and runs the bundle's start.sh on a
fresh runner, which is the check that matters for anyone installing this.
Every digest below was read back anonymously, so each line also proves the package is public:
| Image | Digest at v0.2.5 |
|---|---|
lez-maker-node |
sha256:8aa3fcfd9c501697fa6772d5d4fb95b2956298ea1c6653a3e189f5a547c94db4 |
lez-taker-node |
sha256:7f01f407e1e4cc3f59ecf1ccf32f3288043341f200fe1a42a67a39f2b8bc747d |
lez-services |
sha256:2449e3ef47dc49a762768540592dbe110afb287969787e2a96ff4661de797d6c |
lez-basecamp-ui |
sha256:225bcdc6f31e04f02fc3b30ffd495eaa794ee35feff512bd8aede2cfb8e15a2c |
lez-bitcoin-core |
sha256:1d0d9f7b5b86dd4625f13075ee9ca4af394f4581342983d5b61ffbd1d708a54b |
lez-btc-explorer |
sha256:189404fb79ef5dc2fce3cd398b64936631c02dc59974584169d1e4cb497088db |
lez-btc-miner |
sha256:1051c6ba6e11ce6f68a88df6597b388dfaad476deee2a9cd01bf254cc398475d |
lez-explorer |
sha256:7ce87ca7e3120d0ecc974c8d947f2ac394a29de479336e8cc3b4f71ce0aa3158 |
lez-tools |
sha256:70967d5f828250fa3fe27fde17b68d7eb3469693c5d522427cbe907f224c074c |
To verify one without docker:
img=lez-maker-node
tok=$(curl -sf "https://ghcr.io/token?scope=repository:gateway-fm/lez-atomic-swaps/$img:pull" | jq -r .token)
curl -sfI -H "Authorization: Bearer $tok" \
-H 'Accept: application/vnd.oci.image.index.v1+json' \
"https://ghcr.io/v2/gateway-fm/lez-atomic-swaps/$img/manifests/v0.2.5" | grep -i docker-content-digestBasecamp apps for this release are lez_atomic_swap_maker and lez_atomic_swap_taker at
0.2.5 in the module catalog, built from this tag.
Evidence
Full local regression: 43 of 43 passed, none failed. 26 node-e2e.py scenarios (13 in
each direction), both Basecamp desk suites, and 15 desk scenarios (8 forward, 7 reversed).
Both phases closed rc=0. Ran 14:00 UTC 2026-09-26 → 02:21 UTC 2026-09-27 and is attached
as regression-v0.2.5.tar.gz, which carries both logs, a RESULTS.txt of every result line,
and a PROVENANCE.md recording exactly what ran against what.
Two scenarios in this release are new: early-lock (the Maker must not lock before the
Taker's lock confirms) and offline-after-lock (Logos Chat and Delivery cut after the first
lock). Both passed in every direction they support.
The run absorbed eight stalls of the upstream Bedrock defect — the sequencer keeps
producing blocks while nothing finalizes — each one detected and recovered by recreating the
LEZ chain. The last two desk scenarios ran in a second runner invocation after one of those
recreations produced a chain that never finalized at all; the log marks the boundary and
PROVENANCE.md explains it rather than leaving it to be inferred from timestamps.
Demo recordings (DOC-2), attached to this release. Each is a by-product of a scenario
that passed while being recorded, with the desk's own narration burned in as subtitles, every
step driven through the QML inspector:
| Recording | Shows |
|---|---|
TakerSellsForeign-happy.mp4 |
take → lock → Maker locks → claim → Maker claims → completed |
TakerSellsForeign-maker-refund.mp4 |
the Taker never claims; both legs refund, in timelock order |
TakerSellsForeign-concurrent.mp4 |
two swaps taken, locked and claimed interleaved |
media/README.md said refund and overlapping-swap cases were "not visually demonstrated";
that sentence was the DOC-2 gap and is now corrected rather than left to understate what
ships.
Verification
Both product fixes have a test that was checked to fail without the fix, not merely to
pass with it:
- CODE-4 —
crates/swap-core/tests/transition_properties.rs. The generated model had no
RemoveMakerLockaction at all, so across 512 cases per run it never removed two locks,
which is why the defect survived a property suite. With that action added and the
invariant "an accepted claim means both legs are funded now", proptest shrinks to exactly
the reported shape —TakerLock(2), MakerLock, MakerClaim, TakerClaim, RemoveMakerLock, TakerClaim, the last claim accepted after the maker leg left the chain. Removing the two
both_legs_funded()calls fails it in 26 cases. The seed is checked in. - CODE-3 —
a_missing_probe_executable_degrades_its_route_and_the_daemon_still_starts
incrates/maker-node/tests/route_health.rs, which runs the real daemon binary. Reverting
the startup tolerance makes it fail with "Maker daemon exited early", which is the
reported symptom itself.
Five defects were found in this work while reviewing it, and CI caught none of them: an
early-lock assertion that filtered Bitcoin effects for a lock the Maker makes on LEZ; a
refund assertion that treated "no refund recorded" as "refund had the right shape"; an
unthrottled failure log in a one-second tick; and two probe requirements missing from the
operator guide (a symlinked probe is refused, and the probe's directory is validated too).
Four of the five were assertions or documentation that could not fail — the specific hazard
of closing coverage findings, since such work looks like progress either way.
The whole stack was then regressed again after merging, as one commit rather than as the
pre-merge branch head, so the evidence is for what this tag actually contains: 45 of 45,
zero failures, both phases rc=0. Committed under
docs/evidence/regression-v0.2.5-20260928/ and attached as regression-v0.2.5.tar.gz.
| Phase | Result |
|---|---|
node-e2e.py, TakerSellsForeign |
14 / 14 |
node-e2e.py, TakerSellsLez |
14 / 14 |
| ... |
v0.2.4
v0.2.4 answers the Logos review of v0.2.3 (logos-co/ecosystem#182) and what the
public-network runs that followed it turned up. Swaps now settle unattended on the
official LEZ testnet against a Bitcoin test network, in both directions, with both
refund paths recorded; a Taker no longer needs a Bitcoin node or a Bitcoin wallet
of its own; and four recovery and safety defects that only a public network shows
are fixed.
Evidence on public networks
Every folder says what created each transaction, lists every intervention, and
looks each transaction up on its chain.
| Run | Bitcoin served by | What it shows |
|---|---|---|
testnet4-20260919 |
our own Bitcoin Core (internal node), testnet4 | five swaps on the official LEZ testnet: both directions completed, both directions refunded on both legs, and a swap whose Maker never locked, refunded — no Maker action in any of them |
testnet3-provider-20260918 |
a keyless public RPC provider (external node, PublicNode), testnet3 | one swap between two Nodes with no Bitcoin node and no Bitcoin wallet: the Taker's lock signed in an offline owner wallet, every read and broadcast through the provider, the Maker's claim unattended |
testnet-20260918 |
our own Bitcoin Core, testnet4 | the first public runs and the traced swap behind #68: the Maker's follow-up claim, unattended |
| corrected timing profile | our own Bitcoin Core, testnet4 | one TakerSellsLez swap, both sides locked and no claim, both legs refunded on the profile this release ships — the Bitcoin came back 7 h 16 min before the later LEZ refund window. Attached to this release as evidence-corrected-timings-refund-v0.2.4.tar.gz (run on 22–23 September, after the tag; it changes no code) |
How to run it yourself: docs/testnet-run.md.
What changed
Found on the public networks
- The Maker finishes a swap on its own (#68, fixes #67): once its lock was
projected after the cutoff, the Maker never sent its follow-up claim until an
operator queued one. The review flagged this as gating M3. - A first-lock refund no longer strands the Taker (#64): a Maker lock that
arrived late, an observer that froze after a refund was admitted, and a
finalized LEZ refund rejected because its window end lagged the clock. - The order of the two refunds is checked (#88): a Bitcoin claim has no
deadline on chain, so only the order of the refunds protects either side, and
nothing checked it. With the first public profile a Taker selling LEZ could have
refunded its LEZ and still claimed the Maker's Bitcoin. The Bitcoin refund delay
now differs by direction, a profile states the pace the chain may keep, and a
Node refuses to load a profile that breaks the order. - A reorganisation no longer makes a lock unrefundable (#88): a lock mined
below its planned height was judged impossible, for good. Seen after a
nine-block testnet4 reorg; the refund now waits for the height both roles signed. - A Maker refuses a swap it cannot serve in time (#88): it prepares its LEZ
escrows one at a time and had accepted a second Taker-sells-BTC swap it could
not reach before the cutoff. - The Node prices its own Bitcoin lock, under a cap, or refuses it (#75, part
of #70): two 10,000 sat locks had each paid 56,064 sat. The same lock paid
3,100 sat in this release's runs. The Taker sees the fee before sending
(#79, fixes #70). - The desks say what is happening (#76, fixes #69 and #71): a sent,
unconfirmed claim is shown as sent; a failed Maker is reported first, with its
reason; the refund height is named. - The owner can move an open swap to an upgraded actor (#86, fixes #73):
maker_actor_repin_v1, for the swap a Node upgrade stops as
actor_deployment_invalid. - A node's warnings block readiness on mainnet only (#88); the testnet profile's
LEZ discovery window fits one-minute blocks (#88).
Networks and wallets
- The stack runs on the official LEZ testnet and Bitcoin testnet4 (#58), on
LEZ v0.2.4 and spel7f13e71with the escrow guest rebuilt for them (#59);
the local devnet runs LEZ v0.2.4 too (#83, fixes #82). - testnet3, and mainnet settles only against mainnet (#78): the network is
configuration only, and a Node refuses to pair mainnet with a test chain. - Observe through a node that is not yours (#80): any Bitcoin Core from 24,
no spender index, JSON-RPC 1.x replies accepted. A Taker without a Bitcoin
wallet locks from the owner's own wallet (#81, both for #49): the Node answers
-32018 bitcoin_funding_requiredwith the address and amount, and the take is
replayed with a transaction signed elsewhere. - A role can pay its Bitcoin claims into its own wallet (#61).
Desks, devnet and records
- Catalog packages ship the shared QML kit, and a native macOS desk route (#56,
fixes #50). The Taker desk can act on a swap again (#88; a regression from #64,
never released). maker_offer_listfilters by state and the desk asks only for what it renders
(#77, part of #52).- The devnet's LEZ services stop on the signal they handle (#84), and recreating
the LEZ chain survives a chain that dies in its first minute (#88). - The release bundle starts again (#89): its tools image lacked the library the
LEZ v0.2.4 wallet code links, sostart.shcould not mint an identity. Found by
running the release workflow before the tag. - A bundle's evidence export names its commit (#74, fixes #72); escrow compute
units measured against the deployed testnet program (#66); the planned ZEC flow
reconciled with what exists (#85).
Verified
- Public networks: the three evidence folders above.
- Full regression on the local devnet (LEZ v0.2.4), one run on the tree that
was merged: everynode-e2e.pyscenario in both directions (11/11 and 12/12),
both desk suites, every desk scenario in both directions (7/7 and 7/7) —
39 passed, 0 failed. - Basic regression on the release commit's tree after the stack was merged and
the version set:happyandconcurrentin both directions, a Taker refund and
a Maker refund, both desk suites and the deskhappyin both directions —
10 passed, 0 failed. The result lines and full logs of both runs are attached
to this release (regression-v0.2.4.tar.gz); the tables are in #88. - All 14 CI checks on the release commit, and the release workflow end to end
before the tag (every image built, then the bundle pulled them on a fresh runner
and brought the stack up, Nodes ready and both desk suites green), and again on the tag.
Known, upstream
The local LEZ v0.2.4 chain stops finalizing after anything from a minute to a few
hours: Bedrock 0.2.1 drops a sequencer inscription that is in flight when an epoch
turns, and the channel never finalizes again. It is not ours and cannot be dodged
from our side; up.sh --fresh-lez is the remedy and node-e2e.py checks finality
before each scenario
(deploy/README.md).
We have not seen it on the official LEZ testnet.
Install
- Prebuilt stack: download the bundle attached to this release and run
scripts/start.sh(pullsghcr.io/gateway-fm/lez-atomic-swaps/lez-*:v0.2.4);
scripts/start.sh --swapadds one complete swap through the two desks. - Basecamp apps: add the catalog
https://raw.githubusercontent.com/mandrigin/logos-modules-release-base/main/logos-repo.json
in Basecamp's package manager and install LEZ / BTC Maker and
LEZ / BTC Taker 0.2.4.
Not in this release
- Mainnet. Networks are chosen by configuration and mainnet never pairs with a
test chain, but nothing here has run on mainnet. - ZEC in the desks: designed and proven at the service layer, not delivered by the
apps (docs/m6-zec-reconciliation.md).
Container images
Every image deploy/compose.yaml pulls, published to GHCR at this tag. linux/arm64 only.
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-bitcoin-core:v0.2.4 # (sha256:ce06a6edf137031c48416196189753d1916eb42791896864582e4b7f1bd18bb7)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-btc-miner:v0.2.4 # (sha256:28f7349b4304c377a3f69e8cf1f9103b39e0c3c398659e95999028ad96dc8973)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-btc-explorer:v0.2.4 # (sha256:6efc21b7677e5baf28c9969eb44bdd33a7913d5282592963bf49bfa2f85d8200)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-services:v0.2.4 # (sha256:fd4975ef1e20f116036e099d7a548d167e945a632ddc5e149f2d08eaaadc55da)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-explorer:v0.2.4 # (sha256:bb6f58b395cffd5d0faafbd1e3326d2d0f4b68d6d7634eac7a7c48751ac1357c)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-maker-node:v0.2.4 # (sha256:36217255d7c0ba40d65dfff35fdfd94a5bd46c45a1d55fefe999fc35d11cc82e)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-taker-node:v0.2.4 # (sha256:502b550da361a93575b3c3614260c443492742ce66f10938d71195980a887062)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-basecamp-ui:v0.2.4 # (sha256:f58dae8515b2d4accefe81fc0310c205da52edaffaedd9814fb425dd595302e2)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-tools:v0.2.4 # (sha256:f6c5aaccf7e22b3882df9f9ba07bd13e72ceb1e3af5fbfb693f2cb6a8900f4c3)Entry points
- Product README
- [Local stack and scr...
v0.2.3 — dependency advisory fixed, refund and desk follow-ups
A maintenance release on top of v0.2.2: the TLS dependency moves past a new
advisory, the maker-refund scenario no longer aborts on a stale action
generation, and the Maker desk names the right asset while it waits for the
Taker's claim.
What changed
- rustls 0.23.45 (#51): RUSTSEC-2026-0285 (rustls 0.23.42 accepted TLS 1.3
handshake messages across encryption-level boundaries) was published after
v0.2.2; every audited host graph moves to rustls 0.23.45 and
rustls-webpki 0.103.15. The crate is reachable only through the JSON-RPC
HTTP client the Nodes use over loopback to their sidecars. The pinned
escrow guest graph carries a documented exception. - DCO on pull requests only (#51): the sign-off check no longer runs on
pushes to main, where GitHub's squash commit is authored with the merger's
noreply address and failed every merge without checking anything new. - maker-refund retries a stale action generation (#53, fixes #47): the
scenario's Maker refund request re-reads the swap's lease generation and
resends the same request id when the Node answers that the generation is
stale, instead of aborting. - The Maker desk names the asset the Taker claims (#54, fixes #48): with
both legs locked the row reads "Waiting for the Taker's LEZ claim" when the
Taker sells BTC and "Waiting for the Taker's Bitcoin claim" when the Taker
sells LEZ; the desk runner asserts that exact label in both directions.
Verified
Every change landed with its own verification: #53's maker-refund
retry in both directions through the Node APIs, #54's desk label asserted by
the desk runner in both directions, and #51's dependency audits over every
host graph. On the release commit: all 14 CI checks, and the release
workflow end to end on the release branch (every stack image built, then
the bundle pulled those images on a fresh runner and brought the stack up,
Nodes ready and both desk suites green).
Install
- Prebuilt stack: download the bundle attached to this release and run
scripts/start.sh(pullsghcr.io/gateway-fm/lez-atomic-swaps/lez-*:v0.2.3);
scripts/start.sh --swapadds one complete swap through the two desks. - Basecamp apps: add the catalog
https://raw.githubusercontent.com/mandrigin/logos-modules-release-base/main/logos-repo.json
in Basecamp's package manager and install LEZ / BTC Maker and
LEZ / BTC Taker 0.2.3.
Container images
Every image deploy/compose.yaml pulls, published to GHCR at this tag. linux/arm64 only.
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-bitcoin-core:v0.2.3 # (sha256:e364b36ecc34fdbc2ba24444a45d9cf7f2a9075ad325be004111382e71682bc6)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-btc-miner:v0.2.3 # (sha256:20f0e1c539ea128df72ea319dd28bbd873e84f529f68a1c291670c5bd7905b04)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-btc-explorer:v0.2.3 # (sha256:f13170fa290b39389166ecd4b366494cd63cf504b69eb98cac252a44b5417530)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-services:v0.2.3 # (sha256:50957f59bfadcbd8a92b3cfd8add5574f96e3f494fda49cd133618c56075337b)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-explorer:v0.2.3 # (sha256:2818ac10e94f02d2b59b514f0c34418c2068f4879d086e1e1b97215f3ffe4cc4)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-maker-node:v0.2.3 # (sha256:6b471c6a94d13203eb819e1260b8b25b4d7ab9745cc59d771ed539b97da9a4b9)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-taker-node:v0.2.3 # (sha256:29e07ae4accffafd7300edfb25387662083514fb0d8417916770bd218ed9c971)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-basecamp-ui:v0.2.3 # (sha256:49350820016ceec723f79e958d8ffbd2a7932a62c522bf3263ed9f0d0da59908)
docker pull ghcr.io/gateway-fm/lez-atomic-swaps/lez-tools:v0.2.3 # (sha256:3b819b1d3d572688f040695ad19ac21af8bb062b9afa9bcbbe7d5b63101be3e7)Entry points
v0.2.2 — every scenario proven both ways, in both directions
v0.2.2 — every scenario proven both ways, in both directions
The whole scenario matrix now passes twice on the same Node methods: through
the Nodes' owner APIs and by pressing the real Basecamp desks, in both
Bitcoin directions (the Taker sells BTC, the Taker sells LEZ), including both
refund cases, overlapping swaps, Node restarts, and the two review
follow-ups on configuration and late-observed claims. Doing that on a stack
that had run for a day exposed and fixed a set of defects in the Nodes, the
desks and the local chain tooling. Fourteen narrated recordings and a
per-scenario reproduction guide ship with the evidence.
What changed
- The Taker sells LEZ (#41, via #42): the reverse direction end to end.
The Taker locks LEZ first, the Maker locks Bitcoin, the Taker claims
Bitcoin; refunds and recovery in that direction; both desks label the legs
by what the owner locks and claims. - Wallet balances (#40): each Node reports its own Bitcoin wallet and LEZ
owner account (maker_wallet_balances_v1,taker_wallet_balances_v1);
the desks show them under the account selector. - Refund only after the cutoff (#43): the Taker desk offers the refund
once the Maker's lock cutoff has passed, not at the first observation. - Fixes found by the scenario runs (#42), each reproduced on the stack,
fixed and run again in both directions and both ways:- an unsent Maker lock is never sent past the cutoff. The recovery path's
freshness read consults the chain clock, which trails the wall clock
(Bitcoin's median time by about an hour on mainnet, ten minutes on
regtest); a Maker restarted just after its cutoff still locked, and the
Taker then saw a late lock it could neither claim nor refund against. - the Taker's second sell-LEZ lock waits for the previous one at the
sequencer, not in the finalized view, which the devnet's L1 pauses for
minutes at a time. - a submitted Taker claim stays observed across the claim window's close
(the #32 follow-up); a Maker past its cutoff still projects a lock it
sent in time; a Maker lock spent by the Taker's claim, and a Maker LEZ
funding the Taker has claimed, are still canonical locks; exact and
discovered LEZ refund lookups trail the finalized tip. - the LEZ v0.2.0 indexer kept losing its breakpoints on a restart
(carried source patch); the Node's sidecar client repeats a request
whose transport failed; owner replies may be 4 MiB. - desks: one silent market read in flight at a time and explicit reads
never dropped; the refunded Maker leg reported as such; the market
snapshot and the replies that embed one (publish, withdraw, take, lock,
claim, refund) use a 4 MiB budget while ordinary calls keep 64 KiB.
- an unsent Maker lock is never sent past the cutoff. The recovery path's
- Configuration regression scenarios (#42, the #28 follow-up):
node-e2e.py regenerated-config(re-rendered live configuration and a
Taker restart; the swap reloads and completes) andtampered-config(one
altered byte in a swap's saved copy; the swap is refused after a restart). - Test tooling (#42):
deploy/scripts/node-e2e.py all [--direction TakerSellsLez]anddeploy/scripts/ui-e2e.sh all [--direction TakerSellsLez] [--record]drive the same scenarios through the APIs and
through the desks;--recordfilms each scenario with narrated subtitles;
LEZ_BTC_ACTOR_TRACE=1names every actor decision;dump-swaps.sh
keeps both Nodes' state before a reset;up.sh --freshis one unattended
clean bring-up (#38); the release jobs pull the pinned builder image (#39). - Evidence for the review (#42):
docs/evidence/review-2026-09-12/
answers the ecosystem review index item by item, with the harness
summaries of every scenario, the recorded swaps' on-chain exports and a
reproduction guide per scenario (REPRODUCE.md).
Verified
On the release commit: workspace clippy and tests; verify-all with both desk
suites; the nine scenarios plus the two configuration scenarios through the
APIs in both directions (22/22); the seven desk scenarios in both directions
(14/14), on clean history (filmed) and again on a day of accumulated history;
all 14 CI checks. Fast timing profile (cutoff 600 s, refunds 900 s/1200 s,
CSV 6 blocks).
Install
- Prebuilt stack: download the bundle attached to this release and run
scripts/start.sh(pullsghcr.io/gateway-fm/lez-atomic-swaps/lez-*:v0.2.2);
scripts/start.sh --swapadds one complete swap through the two desks. - Basecamp apps: add the catalog
https://raw.githubusercontent.com/mandrigin/logos-modules-release-base/main/logos-repo.json
in Basecamp's package manager and install LEZ / BTC Maker and
LEZ / BTC Taker 0.2.2.
Not in this release
The Maker's offer list still returns the Node's whole offer history, so a
desk snapshot grows with age (a state filter is the next change). The
verified desk path is the bundled VNC environment; a native Basecamp with the
catalog modules is published but not exercised by these runs. XMR and ZEC
pairs are unchanged. Remote signing with external wallets remains a plan (#30).
Entry points
v0.2.1 — the desks show the terms and the clock; the Nodes recover a late claim
v0.2.1 — the desks show the terms and the clock; the Nodes recover a late claim
Both Basecamp desks now run on the Nodes' own APIs, share one UI kit, and show
what a swap is worth and when each window closes. The Nodes expose the
countersigned schedule and every on-chain effect of a swap, and they recover
on their own when a revealing claim can no longer land. The release ships
prebuilt images with a start-script bundle, and both apps are installable from
the Logos module catalog at this version.
What changed
- Maker terms and Taker amount (#21): the fixed offer preset is gone. The
Maker desk publishes offers from a swap-shaped form (amounts on both legs,
minimum, lifetime; the Node's integer-lot price is derived), through the
guardedmaker_offer_publish_v1. The Taker picks any in-bounds amount. - One UI kit, two desks (#21):
apps/basecamp/common/qmland one
generated skeleton for both desks; an activity log on each that records every
request, reply and poll-observed change; on/off swap filters ordered by what
needs the owner first; no decoration that carries no information. - Timelines (#26):
termsontaker_swap_monitor_v1/taker_swap_list_v1
andmaker_actor_monitor_v1(amounts, required confirmations, Bitcoin refund
height, the Maker's lock cutoff, the earlier and later refund instants). Every
running swap row carries the schedule with live countdowns; Maker rows show
the fill, the offer form shows the spread against the Node's stored price,
the Taker's order book shows rate, distance from the best, the book spread,
each offer's expiry and a share slider. - Late claim recovery (#32, fixes #25): a revealing claim sent after the
earlier refund's deadline is dropped by the sequencer with
OutOfValidityWindow. Both actors now route revision two past that instant
torecover_maker_leg; the Maker supervisor alternates observation and
recovery; the Taker Node stops offeringclaim, watches the Maker's refund,
retires the stale admission and offersrefundat the next generation.
Verified live: both legs refunded without anyone touching the Maker. - Taker restart (#28): persisted swaps pin a per-swap copy of the role
configuration instead of the live file the entrypoint rewrites on every
start, so a rebuild or re-bootstrap no longer turns every swap into
attention_required. - On-chain details (#29, closes #22):
effectson both monitor methods
(each lifecycle evidence row with chain, transaction id and confirmations,
plus the Maker's LEZ lock steps) and a "Details" popup per swap with copyable
ids and explorer links. - Stack lifecycle scripts (#24):
deploy/scripts/up.sh(config, images,
chains, market, Nodes, UI and its suites;--build,--fresh-lez,
--fresh) anddown.sh(--wipe); the market bootstrap runs in the
throwaway builder container. - Prebuilt release (#20, ADR 0215): every image of
deploy/compose.yaml
built for linux/arm64 and published to GHCR on release, with a bundle
(compose file,start.sh, pinned config,release.env) attached below. - Module catalog (#19): per-package flakes; both apps at version 0.2.1 in
https://github.com/mandrigin/logos-modules-release-base. - Third-party API documentation (#16) and reproducible swap evidence
(#17):docs/api/README.mdfor integrators;deploy/scripts/export-node-evidence.py
feeds the LEZ explorer's evidence view. - Validity-window reproducers (#18):
compat/lez-v0.2-sequencer-reproducers
runs the reviewer's cases (valid when queued, expired before inclusion, both
window bounds) on the real v0.2.0 block builder in CI.
Verified
Maker and Taker desk suites, the package contract, verify-market.py and the
Node-API scenarios on the local stack; the late-claim recovery and the Taker
restart reproduced live on that stack; Linux clippy and the crate test suites.
Install
- Prebuilt stack: download the bundle attached to this release and run
scripts/start.sh(pullsghcr.io/gateway-fm/lez-atomic-swaps/lez-*:v0.2.1). - Basecamp apps: add the catalog
https://raw.githubusercontent.com/mandrigin/logos-modules-release-base/main/logos-repo.json
in Basecamp's package manager and install LEZ / BTC Maker and
LEZ / BTC Taker 0.2.1.
Not in this release
The claim-window routing is wall-clock based like the second-lock cutoff; the
recovery itself still waits for the chain clocks. The reverse direction
(TakerSellsLez) has no Taker LEZ lock action yet. Remote signing with
external wallets is a plan (#30), not code.
Entry points
v0.2.0 — the Nodes own the BTC↔LEZ swap
v0.2.0 — the Nodes own the BTC↔LEZ swap
The Maker Node and the Taker Node now run the whole BTC↔LEZ lifecycle
themselves: reservation, the signing ceremony over Chat, the Bitcoin lock, the
LEZ escrow, claims and both refunds. The demo controller, the launcher and the
long-lived runner host that carried the M3 proof-of-concept lane are gone; the
Basecamp desks talk to the Nodes and nothing else. Everything still runs on one
machine against a standing Bitcoin regtest chain and a standing LEZ v0.2
devnet, and the chains are chosen by configuration alone (ADR 0213, stages 1
to 3).
What changed
- Node-owned lifecycle (#12):
taker_swap_initiate_v1reserves, plans the
Bitcoin funding from the Taker's own Core wallet, prepares the LEZ claim
through the Taker's own sidecar and drives the three-round adaptor ceremony
in-process on both Nodes;taker_swap_lock_v1broadcasts the lock; the
Maker Node supervises its actor to fund the LEZ escrow and claim Bitcoin;
taker_swap_claim_v1andtaker_swap_refund_v1/maker_actor_refund_v1
are the owner's terminal actions. One sidecar per swap, spawned by the Node
that owns it. - Runner lane deleted (#13): 92 scripts, the
reference-m3-btc-v1profile,
thebtc-local-poc-provisioncrate, thebtc-role-preflightbinary and the
lane's manuals (about 50k lines). Builds and the market bootstrap run in
throwaway containers ofdeploy/builder; no long-lived container holds the
Docker socket. - Node-API scenario harness (#13):
deploy/scripts/node-e2e.py <scenario>
drives both Nodes over their owner sockets with no UI, each scenario its
own job in.github/workflows/node-e2e.ymlon a self-hosted stack. The
recovery timing is a configuration profile (LEZ_TIMING_PROFILE=local|fast). - Liveness fixes the scenarios found (#13): sidecar request timeout on a
cold respawn; input locking for concurrent Bitcoin funding plans; a moving
LEZ finality clock is retried; the LEZ discovery window joins the timing
profile (2048 blocks meant almost six hours before a refund could be
asserted); the sidecar accepts a tip that merely extended during a scan; the
Bitcoin adapter accepts a funding confirmed at or above the signed anchor;
an admitted Taker refund is driven to completion by the Node; the Maker
supervisor recovers instead of driving a lock past the cutoff; Maker LEZ
escrows are prepared one at a time (two prepared together shared a nonce
pair and the second was dropped after acceptance); the Taker watches the
Maker's leg atboth_legs_lockedso a Maker refund is offered as a Taker
refund; owner requests wait for a swap's actor lock instead of failing. - Audited runtime boundaries (#9): checked runtime profiles, an exact
executable catalog with CI drift rejection, no Maker private-key access from
Taker initialization. - Honest Taker lifecycle reporting (#10):
taker_healthnames what each
pair's initiation, claim and refund actually are. - Hardening: vetted, no-follow bounded file readers on every configured
path; the actionable Aikido findings resolved. - CI: the ZEC and XMR pairs still lint under
--all-features; their tests
are parked while BTC↔LEZ is the product. Dependabot pins updated.
Verified
All nine Node-API scenarios pass on the local stack with the fast timing
profile (Bitcoin regtest, LEZ v0.2 devnet, no UI): happy, replay,
wrong-inputs, restart-taker, restart-maker, survivor, concurrent, taker-refund
and maker-refund. The Basecamp Maker and Taker desks complete a swap through
the Nodes (deploy/scripts/swap-through-ui.sh).
Not in this release
The reverse direction (TakerSellsLez) has no Taker LEZ lock action yet.
ZEC and XMR are untested. The recovery deadlines are local profiles, not
network policy.
Entry points
- Product README
- Local stack, scenarios and manual walkthrough
- ADR 0213: the Nodes own the BTC lifecycle
- Components, binaries, RPCs, keys and signing
- Ephemeral builder
No assets are attached; the v0.1.1 and v0.1.2 reviewer evidence remains
available on those releases.
v0.1.2 — BTC/LEZ product and public-readiness update
v0.1.2 — BTC/LEZ product and public-readiness update
This additive maintenance release keeps the M1, M3, and M6 submission scope of
v0.1.1
while publishing the public-readiness and CI hardening completed on the canonical
main branch. The v0.1.1 release remains available and unchanged.
What changed
- resolved the actionable Aikido and publication-gate findings, including safe
path handling, least-privileged workflows, immutable Action/image pins,
full-history secret scanning, dependency and licence enforcement, and
deterministic shell/Docker/Compose validation; - aligned the active public CI surface with the submitted M1/M3/M6 scope while
preserving the Bitcoin/LEZ implementation, Basecamp Maker/Taker flows, and
Logos Chat/Delivery discovery and negotiation tests; - replaced the publication-oriented README with a product-first introduction,
Apple Silicon quickstart, architecture tour, and focused contributor paths; - updated the pinned
dtolnay/rust-toolchain,actions/checkout, and
actions/setup-nodedependencies through reviewed Dependabot changes; - made the network-disabled local E2E fail clearly on mismatched Docker image
architectures and support native cached Rust images on Apple Silicon; - retained fail-hard treatment for repository-owned security findings while
keeping explicitly classified upstream build-image findings visible.
Preserved reviewer evidence
The attached HTML deck, PDF, Basecamp walkthrough, English captions, and
SHA256SUMS are byte-for-byte identical to the reviewed v0.1.1 assets. The
maintenance work therefore changes the code and validation posture, not the
demonstrated five-effect, zero-replay BTC-to-LEZ result.
| Asset | SHA-256 |
|---|---|
lez-btc-m1-m3-m6-submission.html |
5c90bfa301d43c7aadb072ad5e8e87e0476666d449af33aee199f37ca09ef233 |
lez-btc-m1-m3-m6-submission.pdf |
d084df2cec8d23cb9982c0e237f81d9c882554b78d059b308f0d001c17454637 |
lez-btc-ui-swap-demo.mp4 |
bb5ec36055e5f8a53f367d6bf03147e4eb78f17a601d305260b30d8229275703 |
lez-btc-ui-swap-demo.en.vtt |
ea89663fc45c8fd2881b28fc509841eca86d5739ea16086b1fda1694b353b49c |
SHA256SUMS |
696f09d79a9b471e03b934c94109729824653a0ae10679bdee5d31438e5095ed |
Reviewer entry points
v0.1.1 — RFP-003 M1, M3, and M6 source release
v0.1.1 — RFP-003 M1 + M3 + M6 source release
This is Gateway's corrected public source and reviewer release for the LEZ ⇄
Bitcoin vertical slice. It binds the directly browsable, buildable Rust
workspace, the M1 protocol foundation, the M3 BTC/LEZ implementation and
evidence, and the M6 Maker/Taker product surface to one versioned repository
state.
Release: https://github.com/gateway-fm/lez-atomic-swaps/releases/tag/v0.1.1
The default main branch and this tag contain Cargo.toml, Cargo.lock,
crates/, compat/, apps/, tests, and build scripts directly. No patch
series, reconstruction script, personal-remote checkout, or generated binary
is needed to inspect the source.
Release assets
| Asset | Purpose |
|---|---|
lez-btc-m1-m3-m6-submission.html |
Self-contained, interactive 28-slide deck with no external runtime dependency |
lez-btc-m1-m3-m6-submission.pdf |
Print-ready 28-page export of the deck |
lez-btc-ui-swap-demo.mp4 |
1:53 actual Basecamp BTC→LEZ walkthrough, from offer publication through both chain claims and reconciliation |
lez-btc-ui-swap-demo.en.vtt |
English captions for the walkthrough |
SHA256SUMS |
Digests for release media, evidence, and reviewer documents |
Milestone review map
M1 — protocol foundation
The M1 issue maps to the per-leg
protocol and atomicity design, LEZ escrow/SPEL sketch, threat model, PR #48
reproducers, Zcash stack ADR, common SDK surface, persistence ADR, and Logos
daemon integration/fallback design listed in MILESTONES.md.
The complete entry point is docs/milestone-1/README.md.
M3 — BTC/LEZ leg
The M3 issue maps to the witnessed
LEZ settlement ADRs, full-lifecycle SDK/runner source, cryptographic fixtures,
Bitcoin Testnet4 guide, and inline security references listed in
MILESTONES.md.
The D1 behaviours are reviewable as:
| Behaviour | Public evidence | Reproduction |
|---|---|---|
| Happy settlement | Actual Basecamp walkthrough and matching passed record | REPRODUCE.md |
| Refund/timeout | Both-direction two-lock refund record | Timeout/refund procedure |
| Concurrent swaps | Opposite-direction overlap record | Overlap procedure |
All three are private-local functional claims using Bitcoin Core regtest and a
private LEZ v0.2 devnet; no public funds or private key material are published.
M6 — Maker and Taker mini-apps
The M6 issue maps to signed-off
interactive HTML prototypes, Maker pair/price/active/history surfaces, Taker
offer/initiation/progress/ZEC-shield guidance, and Basecamp-loadable role
packages with local-build instructions. Start with
apps/m6-prototypes/,
apps/basecamp/, and the M6 section of
MILESTONES.md.
Verification gates
The release candidate is accepted only after:
./scripts/verify-public-repository.sh
./scripts/run-public-offline-e2e.sh
./scripts/check-architecture-diagrams.sh
./scripts/check-requirements-traceability.sh
node scripts/check-m6-prototype-contract.mjs
shasum -a 256 -c submission/SHA256SUMSThe running-stack verification is read-only for settlement: it starts no swap
and submits no chain effect; its market check creates and withdraws one uniquely
named offer. The dated result is recorded under submission/.
Claim boundary
This release is submitted for Logos review; it does not mark the upstream issue
checkboxes or claim formal acceptance. It does not claim public-network
deployment, production custody, independent cryptographic audit, M2, M4,
complete M5 operations, or M7 mainnet readiness. The normative boundary is
LIMITATIONS.md.