BTC Prague 2026
Introduction into the Electrum Swap implementation.
Not just client <-> server, decentralised marketplace on Nostr.
AA0B C682 4B39 7BBA 9977 6E15 7ED8 D82B 3719 2688Brief personal intro and what I work on @ Electrum.
Atomic, (possibly) trustless exchange between on-chain and Lightning balances.
Throughout this talk: Alice (client) does a reverse swap with Bob (provider).
"Trustless" is implementation-dependent — we'll see why.
A reverse swap = Alice sends Lightning and receives on-chain (most common one).
Talk is Electrum focused, some things might work differently elsewhere.
How it bootstrapped:
Now:
Whales Exchange)Reverse swap: Alice sends Lightning, receives on-chain.
1# Unified P2WSH witness script for all swaps
2WITNESS_TEMPLATE_SWAP = [
3 OP_SIZE, # --- claim branch ---
4 OPPushDataGeneric(None), # preimage length
5 OP_EQUAL,
6 OP_IF,
7 OP_HASH160,
8 OPPushDataGeneric(lambda x: x == 20), # payment_hash
9 OP_EQUALVERIFY,
10 OPPushDataPubkey, # claim_pubkey
11 OP_ELSE, # --- refund branch ---
12 OP_DROP,
13 OPPushDataGeneric(None), # locktime
14 OP_CHECKLOCKTIMEVERIFY,
15 OP_DROP,
16 OPPushDataPubkey, # refund_pubkey
17 OP_ENDIF,
18 OP_CHECKSIG,
19]
— electrum/submarine_swaps.py
Show previous slide with blue address
Electrum splits the swap into two Lightning invoices:
The provider settles the prepayment only once all HTLCs for both invoices arrive.
Worst case: the provider steals the prepayment — limited harm and loss of reputation.
Alice does a reverse swap over Lightning, messaging via Nostr:
"Notes and Other Stuff Transmitted by Relays"
Discovery: swap servers announce themselves on Nostr
Library: electrum-aionostr — asyncio, shares Electrum's dependencies
1{
2 "pubkey": "ba3aa04a...", // persistent identity
3 "created_at": 1779375552, // re-announced every 10 min
4 "kind": 30315, // NIP-38 status (replaceable)
5 "content": {
6 "percentage_fee": 0.39, // currently symmetric
7 "mining_fee": 285, // charged for the funding tx
8 "min_amount": 20000,
9 "max_forward_amount": 1200000, // server receives LN
10 "max_reverse_amount": 8900000, // server sends LN
11 "pow_nonce": "0x41d00190", // anti-spam proof-of-work
12 "relays": ["wss://relay.damus.io", "..."]
13 },
14 "sig": "5c26c159..." // schnorr signature over the id
15}
relay list (client rebroadcasts)
no symmetric fees (future)
Swaps on Mutinynet — live in the GUI.
Three demos, in order: 1. A regular swap via the Swap Dialog. 1. A Submarine Payment — Lightning → on-chain to an external address. 1. Send change to Lightning — an on-chain tx's change goes out over Lightning.
Pre-flight: Mutinynet wallet funded, Lightning channels open and balanced, a target external address ready. Have a fallback screen recording in case the network misbehaves.
Same codebase as the Android & desktop apps — just config vars.
plugins.swapserver.enableddocs.electrum.org)Time is the limiting factor — wishlist:
Currently swap providers can only configure a single feerate.
Use a Taproot funding UTXO; the collaborative claim uses MuSig2.
Idea: Make swap requests costly for clients.
Interested in any of these ideas? I'll be around the next days.
⛓️ ⚡ Electrum Submarine Swaps
AA0B C682 4B39 7BBA 9977 6E15 7ED8 D82B 3719 2688
Please talk to me if you'd like to discuss any of these points or ideas. Thank you — I hope this was interesting!
| Table of Contents | t |
|---|---|
| Exposé | ESC |
| Full screen slides | e |
| Presenter View | p |
| Source Files | s |
| Slide Numbers | n |
| Toggle screen blanking | b |
| Show/hide slide context | c |
| Notes | 2 |
| Help | h |