Skip to content

Instantly share code, notes, and snippets.

@t-bast
Last active May 23, 2023 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save t-bast/5fd89979a8088b99d0b95c124902aa56 to your computer and use it in GitHub Desktop.
Save t-bast/5fd89979a8088b99d0b95c124902aa56 to your computer and use it in GitHub Desktop.
Explore usage of swap-in potentiam for Phoenix

Swap-in potentiam for Phoenix

The current swap-in flow for Phoenix uses the following steps:

  1. Derive a BIP 32 p2wpkh address from the user's seed
  2. Send funds to that address from an external on-chain wallet
  3. Wait for confirmations
  4. Fund a channel with ACINQ with utxos from that address
  5. Wait for confirmations

We have to wait for confirmations in step 5 because the user may double-spend the funding transaction, since they have full control of the address they're spending from. This creates some UX issues: while a swap-in is unconfirmed, it's hard for the user to understand the state of its channel and how much they can spend/receive. They cannot use the swapped funds yet, and other on-chain operations (e.g. splice-out, pay-to-splice) are stacked on top of the swap-in and the corresponding balance cannot be used yet (even though the user has released the preimage for the corresponding HTLCs). But it makes recovery very simple: the user can simply import its seed in Electrum, and will directly have access to all of its on-chain funds, including incomplete swap-ins.

We can avoid waiting for confirmations in step 5 by changing the swap-in address. Instead of using a p2wpkh address, we use a p2wsh address with the following two script branches:

  • multisig 2-of-2 (ACINQ + Phoenix)
  • relative delay + signature from Phoenix

Once funds have been confirmed on that p2wsh address, Phoenix and ACINQ use the multisig 2-of-2 branch to fund or splice into a channel. This can then use 0-conf, as long as we are not too close to the relative delay. That is the core idea of the swap-in potentiam proposal.

What's really nice is that from a UX point-of-view:

  • we can track unconfirmed swap-in funds separately from our channel funds
  • once they are confirmed, we can immediately "move them" to our channel balance
  • while a swap-in is unconfirmed, the channel can still be updated with 0-conf operations (e.g. splice-out, pay-to-splice)
  • every change to the channel is 0-conf, which makes it clear to the user how much they can send/receive at any time

There are drawbacks though:

  • it creates bigger transactions, because spending a 2-of-2 is more expensive than spending a p2wpkh, so it costs more on-chain fees (this can be addressed in the future by using taproot and musig2)
  • recovery is harder: if the user initiates a swap-in, uninstall Phoenix and imports its seed into Electrum, they won't see the swap-in funds (we'd need support for script descriptors which is still WIP)
    • we'll need a custom tool to let them recover their funds in that case (or build it into Phoenix directly)
    • it's simple to implement, but it isn't a great UX
    • but maybe this is a rare enough edge case that we can handle through support?
  • if the user initiates a swap-in, but its liquidity policy blocks the channel open/splice, the funds are hard to recover:
    • if we get close to the relative delay, we cannot safely open the channel anymore and need to send the funds back to the user
    • if the user wants to "cancel" the swap-in, they'll still have to pay fees to send the money back to their standard p2wpkh wallet
  • ACINQ needs to make sure the 0-conf transactions confirm before reaching the relative delay (so we need to use a large relative delay)

The relative delay is only really necessary if ACINQ disappear, so we can probably use 6 months. This gives us enough time to hope that transactions will confirm, even if we set a relatively low feerate (that's part of our risk model). ACINQ may have to CPFP chains of unconfirmed transactions when they get too large: but that's true in both models, because we're otherwise limited by bitcoin relay policy (no more than 25 unconfirmed transactions)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment