Merge pull request #319 from ksedgwic/2026-06-signet-support
Some checks are pending
Code Base Sanity Check / tests (push) Waiting to run
Code Base Sanity Check / coverage (push) Waiting to run
Code Base Sanity Check / build-clang (push) Waiting to run

Signet support for the Boltz swapper
This commit is contained in:
Ken Sedgwick 2026-06-22 16:26:18 -07:00 committed by GitHub
commit ba3681be3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 111 additions and 46 deletions

View file

@ -5,59 +5,67 @@
namespace {
auto const boltz_instances = std::map< Boss::Msg::Network
, std::vector<Boss::Mod::BoltzSwapper::Instance>
>
{ { Boss::Msg::Network_Bitcoin
/* Historically, the clearnet API endpoint was used as the in-database label
* for Boltz services.
* The boltz.exchange service thus uses the API endpoint as the label for
* back-compatibility.
* Other services since then were added after we had a separate label.
*/
, { { "https://boltz.exchange/api"
, "https://boltz.exchange/api"
, "http://boltzzzbnus4m7mta3cxmflnps4fp7dueu2tgurstbvrbt6xswzcocyd.onion/api"
auto const boltz_instances = std::map< Boss::Msg::Network, std::vector<Boss::Mod::BoltzSwapper::Instance> >
{
{ Boss::Msg::Network_Bitcoin,
/* Historically, the clearnet API endpoint was used as the in-database label
* for Boltz services.
* The boltz.exchange service thus uses the API endpoint as the label for
* back-compatibility.
* Other services since then were added after we had a separate label.
*/
{
{ "https://boltz.exchange/api",
"https://boltz.exchange/api",
"http://boltzzzbnus4m7mta3cxmflnps4fp7dueu2tgurstbvrbt6xswzcocyd.onion/api"
},
{ "AutonomousOrganization@github.com",
"",
"http://jsyqqszgfrya6nj7nhi4hu4tdpuvfursl7dyxeiukzit5mvckqbzxpad.onion"
}
}
, { "AutonomousOrganization@github.com"
, ""
, "http://jsyqqszgfrya6nj7nhi4hu4tdpuvfursl7dyxeiukzit5mvckqbzxpad.onion"
}
}
}
, { Boss::Msg::Network_Testnet
, { { "https://testnet.boltz.exchange/api"
, "https://testnet.boltz.exchange/api"
, "http://tboltzzrsoc3npe6sydcrh37mtnfhnbrilqi45nao6cgc6dr7n2eo3id.onion/api"
}
}
}
};
},
{ Boss::Msg::Network_Signet,
{
{ "signet-boltz-backend-for-clboss",
"http://127.0.0.1:8080",
"http://boltz7ckqss7j66wjjqlm334qccsrjie552gdnvn6vwztnzk7bqwsdad.onion"
}
}
},
{ Boss::Msg::Network_Testnet,
{
{ "https://testnet.boltz.exchange/api",
"https://testnet.boltz.exchange/api",
"http://tboltzzrsoc3npe6sydcrh37mtnfhnbrilqi45nao6cgc6dr7n2eo3id.onion/api"
}
}
}
};
}
namespace Boss { namespace Mod { namespace BoltzSwapper {
class Main::Impl {
private:
Env env;
ServiceCreator creator;
class Main::Impl {
private:
Env env;
ServiceCreator creator;
public:
Impl(S::Bus& bus, Ev::ThreadPool& threadpool)
: env(bus)
, creator(bus, threadpool, env, boltz_instances)
{ }
};
public:
Impl(S::Bus& bus, Ev::ThreadPool& threadpool)
: env(bus)
, creator(bus, threadpool, env, boltz_instances)
{ }
};
Main::Main(Main&&) =default;
Main& Main::operator=(Main&&) =default;
Main::~Main() =default;
Main::Main(Main&&) =default;
Main& Main::operator=(Main&&) =default;
Main::~Main() =default;
Main::Main( S::Bus& bus
, Ev::ThreadPool& threadpool
) : pimpl(Util::make_unique<Impl>(bus, threadpool))
{ }
Main::Main( S::Bus& bus
, Ev::ThreadPool& threadpool
) : pimpl(Util::make_unique<Impl>(bus, threadpool))
{ }
}}}

View file

@ -228,6 +228,53 @@ Installing `lcov`:
* Debian/Ubuntu: `sudo apt-get install lcov`
* Or via Nix (without installing system-wide): `nix shell nixpkgs#lcov --command make coverage-report`
### Testing on signet w/ swaps
CLBOSS can run its `boltz.exchange` swaps against a signet Boltz backend,
which is useful for exercising the swap machinery without spending real
funds. This needs a CLBOSS built with signet support, which ships a
`Network_Signet` Boltz instance.
The signet Boltz service has no public clearnet endpoint, so CLBOSS
reaches it at a local address (`http://127.0.0.1:8080`) that you front
with a forward to the service. The service is reachable over I2P
(preferred) or Tor — its `.onion` is also configured, but has been
unreliable in practice.
To forward the local port over I2P:
1. Install and run [i2pd](https://i2pd.readthedocs.io/). Its SOCKS5 proxy
listens on `127.0.0.1:4447` by default; no extra configuration is
required.
2. Forward `127.0.0.1:8080` to the signet Boltz I2P address through that
SOCKS5 proxy with `socat`. A systemd unit keeps it running:
```
[Unit]
Description=socat proxy: 127.0.0.1:8080 -> Boltz signet I2P (via i2pd SOCKS5)
After=i2pd.service network-online.target
Wants=i2pd.service
[Service]
Type=simple
ExecStart=/usr/bin/socat --experimental -d TCP4-LISTEN:8080,bind=127.0.0.1,fork,reuseaddr SOCKS5-CONNECT:127.0.0.1:4447:boltz7c3f7bb5pe7k25uv2wdd57oayoazacorwdvzksz6q7hicxq.b32.i2p:80
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
For a one-off test, run just the `socat …` command from `ExecStart`
directly. With i2pd and this forward running, a signet CLBOSS uses the
Boltz signet backend automatically.
To smoke-test the backend without CLBOSS, the `dev-boltz-api` helper
honors two environment variables: set `BOLTZ_PROXY=socks5h://127.0.0.1:4447`
and `BOLTZ_API_BASE=http://boltz7c3f7bb5pe7k25uv2wdd57oayoazacorwdvzksz6q7hicxq.b32.i2p`
to reach the service directly over I2P.
### Contributed Utilities
There are a number of contributed utilities in the `contrib` directory. See

View file

@ -5,12 +5,17 @@
#include"Jsmn/Object.hpp"
#include"Json/Out.hpp"
#include"Util/make_unique.hpp"
#include<cstdlib>
#include<iostream>
#include<sstream>
#include<string>
/* argv[1] == /api
* argv[2] == JSON
*
* Environment overrides:
* BOLTZ_API_BASE URL prefix (default: https://boltz.exchange/api)
* BOLTZ_PROXY libcurl proxy (e.g. socks5h://127.0.0.1:9050)
*/
int main(int argc, char** argv) {
if (argc < 2 || argc > 3) {
@ -31,8 +36,13 @@ int main(int argc, char** argv) {
);
}
auto base = std::string("https://boltz.exchange/api");
if (auto e = std::getenv("BOLTZ_API_BASE")) base = e;
auto proxy = std::string("");
if (auto e = std::getenv("BOLTZ_PROXY")) proxy = e;
Ev::ThreadPool tp;
auto cc = Boltz::Connection(tp);
auto cc = Boltz::Connection(tp, base, proxy);
auto code = Ev::lift().then([&]() {
return cc.api(api, std::move(json));