From 903ad55b0bd58542fe0f15a8df1d38aaec664674 Mon Sep 17 00:00:00 2001 From: bitromortac Date: Thu, 10 Dec 2020 08:29:53 +0100 Subject: [PATCH 1/3] swaps: disable button if no channel present --- electrum/gui/qt/channels_list.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py index 5f8e678c0..3f7e96469 100644 --- a/electrum/gui/qt/channels_list.py +++ b/electrum/gui/qt/channels_list.py @@ -225,6 +225,7 @@ class ChannelsList(MyTreeView): self._update_chan_frozen_bg(chan=chan, items=items) if wallet.lnworker: self.update_can_send(wallet.lnworker) + self.update_swap_button(wallet.lnworker) @QtCore.pyqtSlot() def on_gossip_db(self): @@ -280,13 +281,20 @@ class ChannelsList(MyTreeView): + ' ' + self.parent.base_unit() self.can_send_label.setText(msg) + def update_swap_button(self, lnworker: LNWallet): + if lnworker.num_sats_can_send() or lnworker.num_sats_can_receive(): + self.swap_button.setEnabled(True) + else: + self.swap_button.setEnabled(False) + def get_toolbar(self): h = QHBoxLayout() self.can_send_label = QLabel('') h.addWidget(self.can_send_label) h.addStretch() self.swap_button = EnterButton(_('Swap'), self.swap_dialog) - self.swap_button.setEnabled(self.parent.wallet.has_lightning()) + self.swap_button.setToolTip("Have at least one channel to do swaps.") + self.swap_button.setDisabled(True) self.new_channel_button = EnterButton(_('Open Channel'), self.new_channel_with_warning) self.new_channel_button.setEnabled(self.parent.wallet.has_lightning()) h.addWidget(self.new_channel_button) From c3776943477343d7bf943afee6e76969d8fdda3f Mon Sep 17 00:00:00 2001 From: bitromortac Date: Thu, 17 Dec 2020 06:44:27 +0100 Subject: [PATCH 2/3] swaps: limit forward amount to receivable amount on lightning --- electrum/gui/qt/swap_dialog.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py index 828e7c984..d2aaf7089 100644 --- a/electrum/gui/qt/swap_dialog.py +++ b/electrum/gui/qt/swap_dialog.py @@ -126,14 +126,15 @@ class SwapDialog(WindowModalDialog): self._update_tx('!') if self.tx: amount = self.tx.output_value_for_address(ln_dummy_address()) - max_amt = self.swap_manager.get_max_amount() + max_swap_amt = self.swap_manager.get_max_amount() + max_recv_amt = int(self.lnworker.num_sats_can_receive()) + max_amt = min(max_swap_amt, max_recv_amt) if amount > max_amt: amount = max_amt self._update_tx(amount) if self.tx: amount = self.tx.output_value_for_address(ln_dummy_address()) assert amount <= max_amt - # TODO: limit onchain amount if lightning cannot receive this much self.send_amount_e.setAmount(amount) def _spend_max_reverse_swap(self): From 64ecf8539a53d467af55036282281c4cc31746b9 Mon Sep 17 00:00:00 2001 From: bitromortac Date: Fri, 11 Dec 2020 10:44:23 +0100 Subject: [PATCH 3/3] swaps: fix normal amount formulas In a normal (forward) swap (onchain->offchain): send_amount = receive_amount * (1 + service_percentage) + normal_fee , and vice versa: receive_amount = (send_amount + normal_fee) / (1 + service_percentage) , i.e., the service fee is charged on the received offchain amount. --- electrum/submarine_swaps.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py index c71ecfa3a..51a0f806d 100644 --- a/electrum/submarine_swaps.py +++ b/electrum/submarine_swaps.py @@ -281,7 +281,7 @@ class SwapManager(Logger): if locktime - self.network.get_local_height() >= 144: raise Exception("fswap check failed: locktime too far in future") # create funding tx - funding_output = PartialTxOutput.from_address_and_value(lockup_address, expected_onchain_amount) + funding_output = PartialTxOutput.from_address_and_value(lockup_address, onchain_amount) if tx is None: tx = self.wallet.create_transaction(outputs=[funding_output], rbf=False, password=password) else: @@ -310,7 +310,7 @@ class SwapManager(Logger): await self.network.broadcast_transaction(tx) return tx.txid() - async def reverse_swap(self, amount_sat: int, expected_amount: int) -> bool: + async def reverse_swap(self, lightning_amount: int, expected_onchain_amount: int) -> bool: """send on Lightning, receive on-chain - User generates preimage, RHASH. Sends RHASH to server. @@ -330,7 +330,7 @@ class SwapManager(Logger): "type": "reversesubmarine", "pairId": "BTC/BTC", "orderSide": "buy", - "invoiceAmount": amount_sat, + "invoiceAmount": lightning_amount, "preimageHash": preimage_hash.hex(), "claimPublicKey": pubkey.hex() } @@ -361,9 +361,9 @@ class SwapManager(Logger): if locktime != int.from_bytes(parsed_script[10][1], byteorder='little'): raise Exception("rswap check failed: inconsistent locktime and script") # check that the onchain amount is what we expected - if onchain_amount < expected_amount: + if onchain_amount < expected_onchain_amount: raise Exception(f"rswap check failed: onchain_amount is less than what we expected: " - f"{onchain_amount} < {expected_amount}") + f"{onchain_amount} < {expected_onchain_amount}") # verify that we will have enough time to get our tx confirmed if locktime - self.network.get_local_height() <= 60: raise Exception("rswap check failed: locktime too close") @@ -379,9 +379,9 @@ class SwapManager(Logger): prepay_hash = fee_lnaddr.paymenthash else: prepay_hash = None - if int(invoice_amount) != amount_sat: + if int(invoice_amount) != lightning_amount: raise Exception(f"rswap check failed: invoice_amount ({invoice_amount}) " - f"not what we requested ({amount_sat})") + f"not what we requested ({lightning_amount})") # save swap data to wallet file swap = SwapData( redeem_script = redeem_script, @@ -391,7 +391,7 @@ class SwapManager(Logger): prepay_hash = prepay_hash, lockup_address = lockup_address, onchain_amount = onchain_amount, - lightning_amount = amount_sat, + lightning_amount = lightning_amount, is_reverse = True, is_redeemed = False, funding_txid = None, @@ -443,7 +443,7 @@ class SwapManager(Logger): return else: x -= self.normal_fee - x = int(x * (100 - self.percentage) / 100) + x = int(x / ((100 + self.percentage) / 100)) if not self.check_invoice_amount(x): return return x @@ -461,7 +461,7 @@ class SwapManager(Logger): else: if not self.check_invoice_amount(x): return - x = int(x * 100 / (100 - self.percentage)) + 1 + x = int(x * 100 / (100 + self.percentage)) + 1 x += self.normal_fee return x