Merge pull request #9862 from oren-z0/fix-timelock-recovery-watch-wallets
Fix Timelock Recovery plugin for watch wallets
This commit is contained in:
@@ -1181,16 +1181,20 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
self,
|
self,
|
||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
*,
|
*,
|
||||||
|
prompt_if_complete_unsaved: bool = True,
|
||||||
external_keypairs: Mapping[bytes, bytes] = None,
|
external_keypairs: Mapping[bytes, bytes] = None,
|
||||||
invoice: Invoice = None,
|
invoice: Invoice = None,
|
||||||
|
on_closed: Callable[[Optional[Transaction]], None] = None,
|
||||||
show_sign_button: bool = True,
|
show_sign_button: bool = True,
|
||||||
show_broadcast_button: bool = True,
|
show_broadcast_button: bool = True,
|
||||||
):
|
):
|
||||||
show_transaction(
|
show_transaction(
|
||||||
tx,
|
tx,
|
||||||
parent=self,
|
parent=self,
|
||||||
|
prompt_if_complete_unsaved=prompt_if_complete_unsaved,
|
||||||
external_keypairs=external_keypairs,
|
external_keypairs=external_keypairs,
|
||||||
invoice=invoice,
|
invoice=invoice,
|
||||||
|
on_closed=on_closed,
|
||||||
show_sign_button=show_sign_button,
|
show_sign_button=show_sign_button,
|
||||||
show_broadcast_button=show_broadcast_button,
|
show_broadcast_button=show_broadcast_button,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -425,9 +425,10 @@ def show_transaction(
|
|||||||
*,
|
*,
|
||||||
parent: 'ElectrumWindow',
|
parent: 'ElectrumWindow',
|
||||||
prompt_if_unsaved: bool = False,
|
prompt_if_unsaved: bool = False,
|
||||||
|
prompt_if_complete_unsaved: bool = True,
|
||||||
external_keypairs: Mapping[bytes, bytes] = None,
|
external_keypairs: Mapping[bytes, bytes] = None,
|
||||||
invoice: 'Invoice' = None,
|
invoice: 'Invoice' = None,
|
||||||
on_closed: Callable[[], None] = None,
|
on_closed: Callable[[Optional[Transaction]], None] = None,
|
||||||
show_sign_button: bool = True,
|
show_sign_button: bool = True,
|
||||||
show_broadcast_button: bool = True,
|
show_broadcast_button: bool = True,
|
||||||
):
|
):
|
||||||
@@ -436,6 +437,7 @@ def show_transaction(
|
|||||||
tx,
|
tx,
|
||||||
parent=parent,
|
parent=parent,
|
||||||
prompt_if_unsaved=prompt_if_unsaved,
|
prompt_if_unsaved=prompt_if_unsaved,
|
||||||
|
prompt_if_complete_unsaved=prompt_if_complete_unsaved,
|
||||||
external_keypairs=external_keypairs,
|
external_keypairs=external_keypairs,
|
||||||
invoice=invoice,
|
invoice=invoice,
|
||||||
on_closed=on_closed,
|
on_closed=on_closed,
|
||||||
@@ -461,9 +463,10 @@ class TxDialog(QDialog, MessageBoxMixin):
|
|||||||
*,
|
*,
|
||||||
parent: 'ElectrumWindow',
|
parent: 'ElectrumWindow',
|
||||||
prompt_if_unsaved: bool,
|
prompt_if_unsaved: bool,
|
||||||
|
prompt_if_complete_unsaved: bool = True,
|
||||||
external_keypairs: Mapping[bytes, bytes] = None,
|
external_keypairs: Mapping[bytes, bytes] = None,
|
||||||
invoice: 'Invoice' = None,
|
invoice: 'Invoice' = None,
|
||||||
on_closed: Callable[[], None] = None,
|
on_closed: Callable[[Optional[Transaction]], None] = None,
|
||||||
):
|
):
|
||||||
'''Transactions in the wallet will show their description.
|
'''Transactions in the wallet will show their description.
|
||||||
Pass desc to give a description for txs not yet in the wallet.
|
Pass desc to give a description for txs not yet in the wallet.
|
||||||
@@ -477,6 +480,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
|||||||
self.wallet = parent.wallet
|
self.wallet = parent.wallet
|
||||||
self.invoice = invoice
|
self.invoice = invoice
|
||||||
self.prompt_if_unsaved = prompt_if_unsaved
|
self.prompt_if_unsaved = prompt_if_unsaved
|
||||||
|
self.prompt_if_complete_unsaved = prompt_if_complete_unsaved
|
||||||
self.on_closed = on_closed
|
self.on_closed = on_closed
|
||||||
self.saved = False
|
self.saved = False
|
||||||
self.desc = None
|
self.desc = None
|
||||||
@@ -640,7 +644,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
|||||||
self._fetch_txin_data_fut = None
|
self._fetch_txin_data_fut = None
|
||||||
|
|
||||||
if self.on_closed:
|
if self.on_closed:
|
||||||
self.on_closed()
|
self.on_closed(self.tx)
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
# Override escape-key to close normally (and invoke closeEvent)
|
# Override escape-key to close normally (and invoke closeEvent)
|
||||||
@@ -711,7 +715,7 @@ class TxDialog(QDialog, MessageBoxMixin):
|
|||||||
|
|
||||||
def sign(self):
|
def sign(self):
|
||||||
def sign_done(success):
|
def sign_done(success):
|
||||||
if self.tx.is_complete():
|
if self.tx.is_complete() and self.prompt_if_complete_unsaved:
|
||||||
self.prompt_if_unsaved = True
|
self.prompt_if_unsaved = True
|
||||||
self.saved = False
|
self.saved = False
|
||||||
self.update()
|
self.update()
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class QtCosignerWallet(EventListener, CosignerWallet):
|
|||||||
self.add_transaction_to_wallet(tx, label=label, on_failure=self.on_add_fail)
|
self.add_transaction_to_wallet(tx, label=label, on_failure=self.on_add_fail)
|
||||||
self.window.update_tabs()
|
self.window.update_tabs()
|
||||||
|
|
||||||
def on_tx_dialog_closed(self, event_id):
|
def on_tx_dialog_closed(self, event_id, _tx: Optional['Transaction']):
|
||||||
self.mark_pending_event_rcvd(event_id)
|
self.mark_pending_event_rcvd(event_id)
|
||||||
|
|
||||||
def on_add_fail(self, msg: str):
|
def on_add_fail(self, msg: str):
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ from electrum.gui.qt.paytoedit import PayToEdit
|
|||||||
from electrum.payment_identifier import PaymentIdentifierType
|
from electrum.payment_identifier import PaymentIdentifierType
|
||||||
from electrum.plugin import hook
|
from electrum.plugin import hook
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.transaction import PartialTxOutput
|
from electrum.transaction import PartialTxOutput, Transaction
|
||||||
from electrum.util import NotEnoughFunds, make_dir
|
from electrum.util import NotEnoughFunds, make_dir
|
||||||
from electrum.gui.qt.util import ColorScheme, WindowModalDialog, Buttons, HelpLabel
|
from electrum.gui.qt.util import ColorScheme, WindowModalDialog, Buttons, HelpLabel
|
||||||
from electrum.gui.qt.util import read_QIcon_from_bytes, read_QPixmap_from_bytes, WaitingDialog
|
from electrum.gui.qt.util import read_QIcon_from_bytes, read_QPixmap_from_bytes, WaitingDialog
|
||||||
@@ -176,12 +176,14 @@ class Plugin(TimelockRecoveryPlugin):
|
|||||||
plan_dialog = WindowModalDialog(context.main_window, "Timelock Recovery")
|
plan_dialog = WindowModalDialog(context.main_window, "Timelock Recovery")
|
||||||
plan_dialog.setContentsMargins(11, 11, 1, 1)
|
plan_dialog.setContentsMargins(11, 11, 1, 1)
|
||||||
plan_dialog.resize(800, plan_dialog.height())
|
plan_dialog.resize(800, plan_dialog.height())
|
||||||
|
fee_policy = FeePolicy('eta:1')
|
||||||
fee_policy = FeePolicy(context.main_window.config.FEE_POLICY)
|
|
||||||
create_cancel_cb = QCheckBox('', checked=False)
|
create_cancel_cb = QCheckBox('', checked=False)
|
||||||
alert_tx_label = QLabel('')
|
alert_tx_fee_label = QLabel('')
|
||||||
recovery_tx_label = QLabel('')
|
alert_tx_complete_label = QLabel('')
|
||||||
cancellation_tx_label = QLabel('')
|
recovery_tx_fee_label = QLabel('')
|
||||||
|
recovery_tx_complete_label = QLabel('')
|
||||||
|
cancellation_tx_fee_label = QLabel('')
|
||||||
|
cancellation_tx_complete_label = QLabel('')
|
||||||
|
|
||||||
if not context.get_alert_address():
|
if not context.get_alert_address():
|
||||||
plan_dialog.show_error(''.join([
|
plan_dialog.show_error(''.join([
|
||||||
@@ -227,34 +229,62 @@ class Plugin(TimelockRecoveryPlugin):
|
|||||||
view_recovery_tx_button.setEnabled(False)
|
view_recovery_tx_button.setEnabled(False)
|
||||||
view_cancellation_tx_button.setEnabled(False)
|
view_cancellation_tx_button.setEnabled(False)
|
||||||
next_button.setEnabled(False)
|
next_button.setEnabled(False)
|
||||||
|
next_button.setToolTip("")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
context.alert_tx = context.make_unsigned_alert_tx(fee_policy)
|
new_alert_tx = context.make_unsigned_alert_tx(fee_policy)
|
||||||
|
alert_changed = False
|
||||||
|
if not context.alert_tx or context.alert_tx.txid() != new_alert_tx.txid():
|
||||||
|
context.alert_tx = new_alert_tx
|
||||||
|
alert_changed = True
|
||||||
assert all(tx_input.is_segwit() for tx_input in context.alert_tx.inputs())
|
assert all(tx_input.is_segwit() for tx_input in context.alert_tx.inputs())
|
||||||
alert_tx_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.alert_tx.get_fee())))
|
alert_tx_complete_label.setText(_("✓ Signed") if context.alert_tx.is_complete() else "")
|
||||||
context.recovery_tx = context.make_unsigned_recovery_tx(fee_policy)
|
alert_tx_fee_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.alert_tx.get_fee())))
|
||||||
|
new_recovery_tx = context.make_unsigned_recovery_tx(fee_policy)
|
||||||
|
if alert_changed or not context.recovery_tx or context.recovery_tx.txid() != new_recovery_tx.txid():
|
||||||
|
context.recovery_tx = new_recovery_tx
|
||||||
|
context.add_input_info_to_recovery_tx()
|
||||||
assert all(tx_input.is_segwit() for tx_input in context.recovery_tx.inputs())
|
assert all(tx_input.is_segwit() for tx_input in context.recovery_tx.inputs())
|
||||||
recovery_tx_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.recovery_tx.get_fee())))
|
recovery_tx_complete_label.setText(_("✓ Signed") if context.recovery_tx.is_complete() else "")
|
||||||
|
recovery_tx_fee_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.recovery_tx.get_fee())))
|
||||||
if create_cancel_cb.isChecked():
|
if create_cancel_cb.isChecked():
|
||||||
context.cancellation_tx = context.make_unsigned_cancellation_tx(fee_policy)
|
new_cancellation_tx = context.make_unsigned_cancellation_tx(fee_policy)
|
||||||
|
if alert_changed or not context.cancellation_tx or context.cancellation_tx.txid() != new_cancellation_tx.txid():
|
||||||
|
context.cancellation_tx = new_cancellation_tx
|
||||||
|
context.add_input_info_to_cancellation_tx()
|
||||||
assert all(tx_input.is_segwit() for tx_input in context.cancellation_tx.inputs())
|
assert all(tx_input.is_segwit() for tx_input in context.cancellation_tx.inputs())
|
||||||
cancellation_tx_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.cancellation_tx.get_fee())))
|
cancellation_tx_complete_label.setText(_("✓ Signed") if context.cancellation_tx.is_complete() else "")
|
||||||
|
cancellation_tx_fee_label.setText(_("Fee: {}").format(self.config.format_amount_and_units(context.cancellation_tx.get_fee())))
|
||||||
else:
|
else:
|
||||||
context.cancellation_tx = None
|
context.cancellation_tx = None
|
||||||
|
cancellation_tx_complete_label.setText(_("✓ Signed") if context.cancellation_tx is not None and context.cancellation_tx.is_complete() else "")
|
||||||
except NotEnoughFunds:
|
except NotEnoughFunds:
|
||||||
view_alert_tx_button.setEnabled(False)
|
view_alert_tx_button.setEnabled(False)
|
||||||
|
alert_tx_complete_label.setText("")
|
||||||
|
alert_tx_fee_label.setText("")
|
||||||
view_recovery_tx_button.setEnabled(False)
|
view_recovery_tx_button.setEnabled(False)
|
||||||
|
recovery_tx_complete_label.setText("")
|
||||||
|
recovery_tx_fee_label.setText("")
|
||||||
view_cancellation_tx_button.setEnabled(False)
|
view_cancellation_tx_button.setEnabled(False)
|
||||||
|
cancellation_tx_complete_label.setText("")
|
||||||
|
cancellation_tx_fee_label.setText("")
|
||||||
payto_e.setStyleSheet(ColorScheme.RED.as_stylesheet(True))
|
payto_e.setStyleSheet(ColorScheme.RED.as_stylesheet(True))
|
||||||
payto_e.setToolTip("Not enough funds to create the transactions.")
|
payto_e.setToolTip("Not enough funds to create the transactions.")
|
||||||
next_button.setEnabled(False)
|
next_button.setEnabled(False)
|
||||||
|
next_button.setToolTip("")
|
||||||
return
|
return
|
||||||
view_alert_tx_button.setEnabled(True)
|
view_alert_tx_button.setEnabled(True)
|
||||||
view_recovery_tx_button.setEnabled(True)
|
view_recovery_tx_button.setEnabled(True)
|
||||||
view_cancellation_tx_button.setEnabled(True)
|
view_cancellation_tx_button.setEnabled(True)
|
||||||
payto_e.setStyleSheet(ColorScheme.GREEN.as_stylesheet(True))
|
payto_e.setStyleSheet(ColorScheme.GREEN.as_stylesheet(True))
|
||||||
payto_e.setToolTip("")
|
payto_e.setToolTip("")
|
||||||
|
if context.main_window.wallet.is_watching_only():
|
||||||
|
if not context.alert_tx.is_complete() or not context.recovery_tx.is_complete() or (context.cancellation_tx is not None and not context.cancellation_tx.is_complete()):
|
||||||
|
next_button.setEnabled(False)
|
||||||
|
next_button.setToolTip(_("This is a watching-only wallet. You must sign the transactions externally - use the View button of each transaction."))
|
||||||
|
return
|
||||||
next_button.setEnabled(True)
|
next_button.setEnabled(True)
|
||||||
|
next_button.setToolTip("")
|
||||||
|
|
||||||
|
|
||||||
payto_e.paymentIdentifierChanged.connect(update_transactions)
|
payto_e.paymentIdentifierChanged.connect(update_transactions)
|
||||||
@@ -315,24 +345,58 @@ class Plugin(TimelockRecoveryPlugin):
|
|||||||
grid_row += 1
|
grid_row += 1
|
||||||
|
|
||||||
plan_grid.addWidget(QLabel('Alert transaction'), grid_row, 0)
|
plan_grid.addWidget(QLabel('Alert transaction'), grid_row, 0)
|
||||||
plan_grid.addWidget(alert_tx_label, grid_row, 1, 1, 3)
|
plan_grid.addWidget(alert_tx_fee_label, grid_row, 1, 1, 2)
|
||||||
|
plan_grid.addWidget(alert_tx_complete_label, grid_row, 3)
|
||||||
view_alert_tx_button = QPushButton(_('View'))
|
view_alert_tx_button = QPushButton(_('View'))
|
||||||
view_alert_tx_button.clicked.connect(lambda: context.main_window.show_transaction(context.alert_tx, show_sign_button=False, show_broadcast_button=False))
|
def on_alert_tx_closed(tx: Optional[Transaction]):
|
||||||
|
if tx is not None and context.alert_tx is not None and tx.txid() == context.alert_tx.txid() and tx.is_complete():
|
||||||
|
old_alert_tx_complete = context.alert_tx and context.alert_tx.is_complete()
|
||||||
|
context.alert_tx = tx
|
||||||
|
if not old_alert_tx_complete and context.alert_tx.is_complete():
|
||||||
|
context.add_input_info_to_recovery_tx()
|
||||||
|
context.add_input_info_to_cancellation_tx()
|
||||||
|
update_transactions()
|
||||||
|
view_alert_tx_button.clicked.connect(lambda: context.main_window.show_transaction(
|
||||||
|
context.alert_tx,
|
||||||
|
prompt_if_complete_unsaved=False,
|
||||||
|
show_broadcast_button=False,
|
||||||
|
on_closed=on_alert_tx_closed
|
||||||
|
))
|
||||||
plan_grid.addWidget(view_alert_tx_button, grid_row, 4)
|
plan_grid.addWidget(view_alert_tx_button, grid_row, 4)
|
||||||
grid_row += 1
|
grid_row += 1
|
||||||
|
|
||||||
plan_grid.addWidget(QLabel('Recovery transaction'), grid_row, 0)
|
plan_grid.addWidget(QLabel('Recovery transaction'), grid_row, 0)
|
||||||
plan_grid.addWidget(recovery_tx_label, grid_row, 1, 1, 3)
|
plan_grid.addWidget(recovery_tx_fee_label, grid_row, 1, 1, 2)
|
||||||
|
plan_grid.addWidget(recovery_tx_complete_label, grid_row, 3)
|
||||||
view_recovery_tx_button = QPushButton(_('View'))
|
view_recovery_tx_button = QPushButton(_('View'))
|
||||||
view_recovery_tx_button.clicked.connect(lambda: context.main_window.show_transaction(context.recovery_tx, show_sign_button=False, show_broadcast_button=False))
|
def on_recovery_tx_closed(tx: Optional[Transaction]):
|
||||||
|
if tx is not None and context.recovery_tx is not None and tx.txid() == context.recovery_tx.txid() and tx.is_complete():
|
||||||
|
context.recovery_tx = tx
|
||||||
|
update_transactions()
|
||||||
|
view_recovery_tx_button.clicked.connect(lambda: context.main_window.show_transaction(
|
||||||
|
context.recovery_tx,
|
||||||
|
prompt_if_complete_unsaved=False,
|
||||||
|
show_broadcast_button=False,
|
||||||
|
on_closed=on_recovery_tx_closed
|
||||||
|
))
|
||||||
plan_grid.addWidget(view_recovery_tx_button, grid_row, 4)
|
plan_grid.addWidget(view_recovery_tx_button, grid_row, 4)
|
||||||
grid_row += 1
|
grid_row += 1
|
||||||
|
|
||||||
cancellation_label = QLabel('Cancellation transaction')
|
cancellation_label = QLabel('Cancellation transaction')
|
||||||
plan_grid.addWidget(cancellation_label, grid_row, 0)
|
plan_grid.addWidget(cancellation_label, grid_row, 0)
|
||||||
plan_grid.addWidget(cancellation_tx_label, grid_row, 1, 1, 3)
|
plan_grid.addWidget(cancellation_tx_fee_label, grid_row, 1, 1, 2)
|
||||||
|
plan_grid.addWidget(cancellation_tx_complete_label, grid_row, 3)
|
||||||
view_cancellation_tx_button = QPushButton(_('View'))
|
view_cancellation_tx_button = QPushButton(_('View'))
|
||||||
view_cancellation_tx_button.clicked.connect(lambda: context.main_window.show_transaction(context.cancellation_tx, show_sign_button=False, show_broadcast_button=False))
|
def on_cancellation_tx_closed(tx: Optional[Transaction]):
|
||||||
|
if tx is not None and context.cancellation_tx is not None and tx.txid() == context.cancellation_tx.txid() and tx.is_complete():
|
||||||
|
context.cancellation_tx = tx
|
||||||
|
update_transactions()
|
||||||
|
view_cancellation_tx_button.clicked.connect(lambda: context.main_window.show_transaction(
|
||||||
|
context.cancellation_tx,
|
||||||
|
prompt_if_complete_unsaved=False,
|
||||||
|
show_broadcast_button=False,
|
||||||
|
on_closed=on_cancellation_tx_closed
|
||||||
|
))
|
||||||
plan_grid.addWidget(view_cancellation_tx_button, grid_row, 4)
|
plan_grid.addWidget(view_cancellation_tx_button, grid_row, 4)
|
||||||
grid_row += 1
|
grid_row += 1
|
||||||
|
|
||||||
@@ -342,7 +406,7 @@ class Plugin(TimelockRecoveryPlugin):
|
|||||||
|
|
||||||
def on_cb_change(x):
|
def on_cb_change(x):
|
||||||
cancellation_label.setVisible(x)
|
cancellation_label.setVisible(x)
|
||||||
cancellation_tx_label.setVisible(x)
|
cancellation_tx_fee_label.setVisible(x)
|
||||||
view_cancellation_tx_button.setVisible(x)
|
view_cancellation_tx_button.setVisible(x)
|
||||||
update_transactions()
|
update_transactions()
|
||||||
create_cancel_cb.stateChanged.connect(on_cb_change)
|
create_cancel_cb.stateChanged.connect(on_cb_change)
|
||||||
@@ -415,11 +479,21 @@ class Plugin(TimelockRecoveryPlugin):
|
|||||||
password = main_window.get_password()
|
password = main_window.get_password()
|
||||||
|
|
||||||
def task():
|
def task():
|
||||||
wallet.sign_transaction(context.alert_tx, password, ignore_warnings=True)
|
if not context.alert_tx.is_complete():
|
||||||
context.add_input_info()
|
wallet.sign_transaction(context.alert_tx, password, ignore_warnings=True)
|
||||||
wallet.sign_transaction(context.recovery_tx, password, ignore_warnings=True)
|
context.add_input_info_to_recovery_tx()
|
||||||
|
context.add_input_info_to_cancellation_tx()
|
||||||
|
if not context.alert_tx.is_complete():
|
||||||
|
raise Exception(_("Alert transaction signing was not completed"))
|
||||||
|
if not context.recovery_tx.is_complete():
|
||||||
|
wallet.sign_transaction(context.recovery_tx, password, ignore_warnings=True)
|
||||||
|
if not context.recovery_tx.is_complete():
|
||||||
|
raise Exception(_("Recovery transaction signing was not completed"))
|
||||||
if context.cancellation_tx is not None:
|
if context.cancellation_tx is not None:
|
||||||
wallet.sign_transaction(context.cancellation_tx, password, ignore_warnings=True)
|
if not context.cancellation_tx.is_complete():
|
||||||
|
wallet.sign_transaction(context.cancellation_tx, password, ignore_warnings=True)
|
||||||
|
if not context.cancellation_tx.is_complete():
|
||||||
|
raise Exception(_("Cancellation transaction signing was not completed"))
|
||||||
|
|
||||||
def on_success(result):
|
def on_success(result):
|
||||||
self.create_download_dialog(context)
|
self.create_download_dialog(context)
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ class TimelockRecoveryContext:
|
|||||||
outputs=alert_tx_outputs,
|
outputs=alert_tx_outputs,
|
||||||
fee_policy=fee_policy,
|
fee_policy=fee_policy,
|
||||||
is_sweep=False,
|
is_sweep=False,
|
||||||
|
locktime=self.alert_tx.locktime if self.alert_tx else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _alert_tx_output(self) -> Tuple[int, 'TxOutput']:
|
def _alert_tx_output(self) -> Tuple[int, 'TxOutput']:
|
||||||
@@ -122,11 +123,15 @@ class TimelockRecoveryContext:
|
|||||||
outputs=[output for output in self.outputs if output.value != 0],
|
outputs=[output for output in self.outputs if output.value != 0],
|
||||||
fee_policy=fee_policy,
|
fee_policy=fee_policy,
|
||||||
is_sweep=False,
|
is_sweep=False,
|
||||||
|
locktime=self.recovery_tx.locktime if self.recovery_tx else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
def add_input_info(self):
|
def add_input_info_to_recovery_tx(self):
|
||||||
self.recovery_tx.inputs()[0].utxo = self.alert_tx
|
if self.recovery_tx and self.alert_tx.is_complete():
|
||||||
if self.cancellation_tx:
|
self.recovery_tx.inputs()[0].utxo = self.alert_tx
|
||||||
|
|
||||||
|
def add_input_info_to_cancellation_tx(self):
|
||||||
|
if self.cancellation_tx and self.alert_tx.is_complete():
|
||||||
self.cancellation_tx.inputs()[0].utxo = self.alert_tx
|
self.cancellation_tx.inputs()[0].utxo = self.alert_tx
|
||||||
|
|
||||||
def make_unsigned_cancellation_tx(self, fee_policy) -> 'PartialTransaction':
|
def make_unsigned_cancellation_tx(self, fee_policy) -> 'PartialTransaction':
|
||||||
@@ -143,6 +148,7 @@ class TimelockRecoveryContext:
|
|||||||
],
|
],
|
||||||
fee_policy=fee_policy,
|
fee_policy=fee_policy,
|
||||||
is_sweep=False,
|
is_sweep=False,
|
||||||
|
locktime=self.cancellation_tx.locktime if self.cancellation_tx else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
class TimelockRecoveryPlugin(BasePlugin):
|
class TimelockRecoveryPlugin(BasePlugin):
|
||||||
|
|||||||
Reference in New Issue
Block a user