Skip to content

Add swap-in wallet and splice-in via Electrum backend#226

Open
matthiasdebernardini wants to merge 1 commit intoACINQ:masterfrom
matthiasdebernardini:feat/swap-in-electrum
Open

Add swap-in wallet and splice-in via Electrum backend#226
matthiasdebernardini wants to merge 1 commit intoACINQ:masterfrom
matthiasdebernardini:feat/swap-in-electrum

Conversation

@matthiasdebernardini
Copy link
Copy Markdown

Summary

  • Switches the blockchain backend from MempoolSpaceClient to ElectrumClient/ElectrumWatcher, enabling peer.swapInWallet and peer.finalWallet (which require IElectrumClient)
  • Adds three new API endpoints: GET /getswapinaddress, GET /swapinwalletbalance, POST /splicein
  • Adds corresponding CLI commands: phoenix-cli getswapinaddress, swapinwalletbalance, splicein
  • Calls peer.startWatchSwapInWallet() after both Electrum and peer connections are established, enabling automatic swap-in to channel
  • Adds --electrum-server CLI option with per-chain defaults, deprecates --mempool-space-url and --mempool-space-polling-interval-minutes

This is based on the approach from #69 but ported to the current codebase and API surface.

Motivation

Phoenixd currently uses MempoolSpaceClient which only implements IClient, not IElectrumClient. This means peer.swapInWallet and peer.finalWallet are always null — users cannot receive on-chain funds and splice them into channels. The Phoenix mobile app uses ElectrumClient and has full swap-in support; this PR brings phoenixd to parity.

Changes

File Change
Phoenixd.kt Replace MempoolSpace with ElectrumClient/Watcher, add --electrum-server option, Electrum connection loop, startWatchSwapInWallet() call, deprecate mempool options
Api.kt Add getswapinaddress, swapinwalletbalance (read-only), splicein (full-access) endpoints
JsonSerializers.kt Add SwapInAddress and SwapInWalletBalance response types
PhoenixCli.kt Add GetSwapInAddress, GetSwapInWalletBalance, SpliceIn CLI commands

Mainnet E2E Test Results

Tested on mainnet with real sats (22,333 sat across 3 deposits):

  • ✅ Electrum connection to electrum.acinq.co:50002
  • ✅ Swap-in address generation with auto-rotation (taproot addresses, derivation indices)
  • ✅ Near-instant UTXO detection via Electrum push notifications
  • ✅ Confirmation tracking (unconfirmed → weaklyConfirmed → deeplyConfirmed)
  • ✅ Automatic channel request triggered at deeplyConfirmed threshold
  • sendtoaddress splice-out worked (19,000 sat sent on-chain, tx 15539c9a61114c3bb2940dce83badaa58c540ba8064f553cf416ee1761c41969)
  • ✅ All existing endpoints unaffected

Known Issue: Feerate Estimation

The Electrum server's blockchain.estimatefee returned very low values (1 sat/vB), causing fundingFeerate=253 sat/kw. The ACINQ LSP aborted channel creation during interactive-tx with channel funding error. The channel was ultimately opened via Phoenix mobile (same seed), after which phoenixd synced the state and successfully performed splice-out.

Possible fixes:

  • Add a minimum feerate floor
  • Use a hybrid approach (Electrum for address monitoring, mempool.space for fee estimation)
  • Investigate why electrum.acinq.co returns low fee estimates

Other Notes

  • Default testnet Electrum server testnet.acinq.co:51002 doesn't resolve — needs a working default
  • Channel opening fees are ~21k sat, so minimum recommended deposit is ~25k sat
  • No build.gradle.kts changes needed — ElectrumClient/ElectrumWatcher are part of lightning-kmp-core (already a dependency)

Test plan

  • Build compiles cleanly with zero warnings
  • GET /getswapinaddress returns valid taproot address with derivation index
  • GET /swapinwalletbalance correctly reports total and unconfirmed balances
  • Address auto-rotates when previous address receives funds
  • UTXO confirmation tracking works (unconfirmed → weakly → deeply)
  • Auto channel creation triggers at deeplyConfirmed
  • POST /sendtoaddress splice-out works from an open channel
  • Channel creation succeeds autonomously (blocked by feerate issue)
  • POST /splicein manual splice-in (not tested — auto flow triggered first)
  • Testnet with working Electrum server

🤖 Generated with Claude Code

…kend

Port swap-in functionality from PR ACINQ#69 to current master by switching the
blockchain backend from MempoolSpaceClient to ElectrumClient. This enables
peer.swapInWallet (which requires IElectrumClient) and adds three new API
endpoints: getswapinaddress, swapinwalletbalance, and splicein.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant