The LnAddr, lndecode and lnencode naming didn't imply that it is
bolt 11 specific, making it confusing to work with, now that there are
also bolt 12 "lnaddr".
Renaming it to *bolt11* creates a clear separation to bolt 12 things and
reduces mental load.
This commit is pure renaming (using the PyCharm IDE refactor function),
except for the removal of the `object` inheritance of LnAddr/BOLT11Addr,
this is Python 2 legacy.
If SwapManager.percentage was a 0.2 float, rounding differences would
cause an exception in the fee calculation inverse sanity check when entering 20
000 sats into the SwapDialog. By making self.percentage a decimal we can
prevent this kind of issue.
```
File "/home/user/code/vibecoding_vm/electrum/electrum/gui/qt/swap_dialog.py", line 294, in on_send_edited
recv_amount = self.swap_manager.get_recv_amount(send_amount, is_reverse=self.is_reverse)
File "/home/user/code/vibecoding_vm/electrum/electrum/submarine_swaps.py", line 1320, in get_recv_amount
if abs(send_amount - inverted_send_amount) > 1:
~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
TypeError: unsupported operand type(s) for -: 'int' and 'NoneType'
```
The `until` filter would limit the relay to only send us events created
up until this timestamp. If the user opens a swap transport by opening
the swap dialog, and keeps the dialog open the dialog will naturally age
above this limit and the relay will stop sending the client swapserver
events as they have (legitimately) been created after this timestamp.
As sanity check we still have the comparison against the current
timestamp in the event parsing loop to prevent pre/backdating.
Fixes https://github.com/spesmilo/electrum/issues/10520
"When should we reveal preimages onchain?"
This commit tries to simplify the thinking by making the observation:
- we can reveal preimages (actually in any context) if they are already public
- a preimage is public if any other lightning node knows it besides us
- if we learn the preimage from another LN node, it is public
- if we send update_fulfill_htlc, it becomes public
- if we see a preimage onchain, it is public
- in lnsweep._maybe_reveal_preimage_for_htlc:
- partial mpp check is not relevant if preimage is already public
- let's just always do KeepWatchingTXO, for sanity/safety
Co-authored-by: ThomasV <thomasv@electrum.org>
Allows storing two different payment info of the same payment hash by
including the direction into the db key.
We create and store PaymentInfo for sending attempts and for requests (receiving),
if we try to pay ourself (e.g. through a channel rebalance) the checks
in `save_payment_info` would prevent this and throw an exception.
By storing the PaymentInfos of outgoing and incoming payments separately in
the db this collision is avoided and it makes it easier to reason about
which PaymentInfo belongs where.
refactor `htlc_switch` to new architecture to make it more robust
against partial settlement of htlc sets and increase maintainability.
Htlcs are now processed in two steps, first the htlcs are collected into
sets from the channels, and potentially failed on their own already.
Then a second loop iterates over the htlc sets and finalizes only on
whole sets.
# Conflicts:
# electrum/lnpeer.py
Exposes reverse submarine swaps to an external/specific address in the
TxEditor gui as "Submarine Payments". The user can enter a onchain
address in the Send Tab and then pay it from the lightning balance in
the send tab by enabling the Submarine Payments option in the TxEditor
dialog menu and switching to the Submarine Payment tab in the Tab bar.
Implement logic to claim a reverse swap funding output to any given
address. This allows to do onchain payments to external recipients
through a submarine swap.
Enforce that the information used to create a bolt11 invoice using
`get_bolt11_invoice()` is similar to the related instance of PaymentInfo
by requiring a PaymentInfo as argument for `get_bolt11_invoice()`.
This way the invoice cannot differ from the created PaymentInfo.
This allows to use the information in PaymentInfo for validation of
incoming htlcs more reliably.
To cover all required information for the creation of a b11 invoice the
PaymentInfo class has to be extended with a expiry and
min_final_cltv_expiry. This requires a db upgrade.
For forward swaps this will ensure that the swap only gets set redeemed
and cleaned up after the preimage has been extracted, as it could happen
that `current_height - spent_height > REDEEM_AFTER_DOUBLE_SPENT_DELAY`
is true even if the preimage has not been extracted yet.
For reverse swaps this changes nothing as they always have the preimage.
instead of hardcoding 20_000 sat directly in the code, make
MIN_SWAP_AMOUNT_SAT a const variable outside of SwapManager so it can be
used for other code too.
Removes the persisted payment info from lnworker once a swap got failed.
Stops persisting the OnionRoutingFailure as it is sufficient to delete
the payment info to fail potential incoming htlcs.
Deletes stored swap leftovers in lnworker and SwapManager
'prepayment', which corresponds to the trusted part of the
lightning payment.
We use 2*sm.mining_fee, where 'mining_fee' is the flat part of
the server fee. However, future protocol should probably allow
to set a value that does not depend on 'mining_fee'.
(note that LND uses a hardcoded amount).
Adds logic to retry sending a direct message in
`NostrTransport.send_direct_message()` on `TimeoutError`.
Handles `TimeoutError` exception more gracefully by catching it and
returning `None`.
`NostrTransport.update_relays()` raises a `KeyError` when the offer of
the configured swapserver (`config.SWAPSERVER_NPUB`) is not in
`self._offers` even though `sm.pairs_updated` gets triggered. This
happens because `NostrTransport.get_pairs()` called `sm.update_pairs()`
before adding the received offer to `self._offers`.
- if fee estimates are high atm, some outputs are not worth to sweep
- however, fee estimates might be only-temporarily very high
- previously in such a case lnwatcher would just discard outputs as dust,
and mark the channel REDEEMED (and hence never watch it or try again)
- now, instead, if the outputs would not be dust if fee estimates were lower,
lnwatcher will keep watching the channel
- and if estimates go down, lnwatcher will sweep them then
- relatedly, previously txbatcher.is_dust() used allow_fallback_to_static_rates=True,
and it erroneously almost always fell back to the static rates (150 s/b) during
startup (race: lnwatcher was faster than the network managed to get estimates)
- now, instead, txbatcher.is_dust() does not fallback to static rates,
and the callers are supposed to handle NoDynamicFeeEstimates.
- I think this makes much more sense. The previous meaning of "is_dust"
with the fallback was weird. Now it means: "is dust at current feerates".
fixes https://github.com/spesmilo/electrum/issues/9980
and differenciate between a single 'provider' and multiple or 0
'providers'. Also update SwapDialog and SwapServerDialog
when new offers are incoming. Stops translating f-string.
If `_fail_swap()` gets called multiple times (e.g. from callbacks) this
would race a `KeyError` as the swap got already popped from
`self._swaps`.
In theory `_fail_swap` unregisters itself from the lnwatcher callback
but the callback may is scheduled multiple times before it has the
chance to unregister itself.
disables the fee slider in the swap dialog for reverse swaps as the tx
fee for claiming is not configurable by the user. Also replaces calls to
`sm.get_swap_tx_fee()` with `sm.get_fee_for_txbatcher()` as this is the
correct fee estimate for claim transactions, instead of the config fee
eta used by `get_swap_tx_fee()`.
changes qeswaphelper to shate a single, long lived transport instance
instead of opening new transports to do swaps and fetch offers.
This allows to continuosly fetch offers, so events which get returned
later by slow relays don't get missed and the fee values stay updated.
Also fixes a race causing the list to miss some swapservers, as the
current implementation fetches only until
`swap_manager.is_initialized()` is set, which will get set as soon as an
event of the configured swapserver is received. So if the event of the
configured swapserver is received as first, all server events coming in
after it would get ignored.