Skip to content

Commit 2fb0dd0

Browse files
oren-z0f321xecdsa
authored
Timelock Recovery Extension (spesmilo#9589)
* Timelock Recovery Extension * Timelock Recovery Extension tests * Use fee_policy instead of fee_est Following 3f327ee * making tx with base_tx Following ab14c3e * move plugin metadata from __init__.py to manifest.json * removing json large indentation * timelock recovery icon * timelock recovery plugin: fix typos * timelock recovery plugin: use menu instead of status bar. The status bar should be used for displaying status. For example, hardware wallet plugins use it because their connection status is changing and needs to be displayed. * timelock recovery plugin: ask for password only once * timelock recovery plugin: ask whether to create cancellation tx in the initial window * remove unnecessary code. (calling run_hook from a plugin does not make sense) * show alert and cancellation address at the end. skip unnecessary dialog * timelock recovery plugin: do not show transactions one by one. Set the fee policy in the first dialog, and use the same fee policy for all tx. We could add 3 sliders to this dialog, if different fees are needed, but I think this really isn't really necessary. * simplify default_wallet for tests All the lightning-related stuff is irrelevant for this plugin. Also use a different destination address for the test recovery-plan (an address that does not belong to the same wallet). * Fee selection should be above fee calculation also show fee calculation result with "fee: " label. * hide Sign and Broadcast buttons during view * recalculate cancellation transaction The checkbox could be clicked after the fee rate has been set. Calling update_transactions() may seem inefficient, but it's the simplest way to avoid such edge-cases. Also set the context's cancellation transaction to None when the checkbox is unset. * use context.cancellation_tx instead of checkbox value context.cancellation_tx will be None iff the checkbox was unset * hide cancellation address if not used * init monospace font correctly * timelock recovery plugin: add input info at signing time. Fixes trezor exception: 'Missing previous tx' * timelock recovery: remove unused parameters * avoid saving the tx in a separate var fixing the assertions * avoid caching recovery & cancellation inputs * timelock recovery: separate help window from agreement. move agreement at the end of the flow, rephrase it * do not cache alert_tx_outputs * do not crash when not enough funds not enough funds can happen when multiple addresses are specified in payto_e, with an amount larger than the wallet has - so we set the payto_e color to red. It can also happen when the user selects a really high fee, but this is not common in a "recovery" wallet with significant funds. * If files not saved - ask before closing * move the checkbox above the save buttons people read the text from top to bottom and may not understand why the buttons are disabled --------- Co-authored-by: f321x <[email protected]> Co-authored-by: ThomasV <[email protected]>
1 parent c12eb31 commit 2fb0dd0

File tree

11 files changed

+3081
-1
lines changed

11 files changed

+3081
-1
lines changed

electrum/gui/qt/main_window.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -1118,8 +1118,17 @@ def show_transaction(
11181118
*,
11191119
external_keypairs: Mapping[bytes, bytes] = None,
11201120
payment_identifier: PaymentIdentifier = None,
1121+
show_sign_button: bool = True,
1122+
show_broadcast_button: bool = True,
11211123
):
1122-
show_transaction(tx, parent=self, external_keypairs=external_keypairs, payment_identifier=payment_identifier)
1124+
show_transaction(
1125+
tx,
1126+
parent=self,
1127+
external_keypairs=external_keypairs,
1128+
payment_identifier=payment_identifier,
1129+
show_sign_button=show_sign_button,
1130+
show_broadcast_button=show_broadcast_button,
1131+
)
11231132

11241133
def show_lightning_transaction(self, tx_item):
11251134
from .lightning_tx_dialog import LightningTxDialog

electrum/gui/qt/transaction_dialog.py

+6
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,8 @@ def show_transaction(
411411
external_keypairs: Mapping[bytes, bytes] = None,
412412
payment_identifier: 'PaymentIdentifier' = None,
413413
on_closed: Callable[[], None] = None,
414+
show_sign_button: bool = True,
415+
show_broadcast_button: bool = True,
414416
):
415417
try:
416418
d = TxDialog(
@@ -421,6 +423,10 @@ def show_transaction(
421423
payment_identifier=payment_identifier,
422424
on_closed=on_closed,
423425
)
426+
if not show_sign_button:
427+
d.sign_button.setVisible(False)
428+
if not show_broadcast_button:
429+
d.broadcast_button.setVisible(False)
424430
except SerializationError as e:
425431
_logger.exception('unable to deserialize the transaction')
426432
parent.show_critical(_("Electrum was unable to deserialize the transaction:") + "\n" + str(e))

electrum/plugins/timelock_recovery/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
Timelock Recovery is a mechanism which, in case of a catastrophic event
2+
(death or loss of your master key), can send your Bitcoin to a secondary wallet of your choice
3+
within a time-window (i.e. 90 days).
4+
<br />
5+
During that time-window, you can see that the Timelock Recovery mechanism has been triggered (a
6+
transaction from your wallet to itself is created on the Bitcoin blockchain), and if this
7+
has happened against your will, you can use your master key to cancel the process (by moving
8+
the funds elsewhere before the time-window expires).
9+
<br />
10+
The implementation of Timelock Recovery is done with two transactions that are signed in advance,
11+
but broadcast only when needed:
12+
<ol>
13+
<li>
14+
An <i>Alert Transaction</i> which sends the funds from the wallet to itself (consolidating the UTXOs).
15+
</li>
16+
<li>
17+
A <i>Recovery Transaction</i> which sends the funds to a secondary wallet of your choice and can
18+
be added to the blockchain only X days after the <i>Alert Transaction</i> has been broadcast (and mined).
19+
</li>
20+
</ol>
21+
Optionally, this extension will also let you sign-in-advance a <i>Cancellation Transaction</i> which can be
22+
used to cancel the Timelock Recovery process, by broadcasting it before the time-window expires.
23+
If the <i>Alert Transaction</i> has been broadcast, the Cancellation Transaction will send the funds again to
24+
the same wallet, which would invalidate the <i>Recovery Transaction</i> (technically: the <i>Recovery Transaction</i>
25+
will be seen as a transaction that is trying to spend a UTXO that has already been spent).
26+
<br />
27+
Timelock Recovery plans do not require any involvement of a third party.
28+
However, two precautions should be taken:
29+
<ol>
30+
<li>
31+
Due to the way Bitcoin transactions and UTXOs work, spending funds from the wallet might break
32+
the entire Timelock Recovery plan.
33+
</li>
34+
<li>
35+
Adding more funds to the wallet will not be covered by the Timelock Recovery plan.
36+
</li>
37+
</ol>
38+
<br />
39+
Therefore it is highly recommended not to use the wallet for any purpose after creating a
40+
Timelock Recovery plan (other than long-term storage).
41+
Instead, for daily purposes use a separate wallet (with a seed in a place that
42+
your loved ones could easily find) and only after accumulating enough funds relevant for long-term
43+
storage, move them to a new highly secured wallet (i.e. with a long passphrase that only you memorize) for
44+
which you create a new Timelock Recovery plan (back to the daily-purpose wallet or to your inheritors' wallet).
45+
<br />
46+
Each accumulation should be done in a new highly secured wallet, but these are easy to create, i.e. you can
47+
memorize a long passphrase and add a counter at the end (1 for the first accumlation, 2 for the second, etc.).
48+
<br />
49+
For more details, visit: <a target="_blank" href="https://timelockrecovery.com" rel="noopener noreferrer">https://timelockrecovery.com</a>.
50+
<br />
51+
Before we begin, please note:
52+
<ol>
53+
<li>
54+
Please prepare in advance the addresses of your inheritors/backup-wallets.
55+
</li>
56+
<li>
57+
Since we are preparing this recovery plan for the long future, it is hard
58+
to estimate what the required mining fees will be.
59+
If the fee is too low, your inheritors, who don't have access to the master
60+
keys, will not be able to simply "replace-by-fee" and use a higher fee.
61+
At the moment of writing this code (year 2025) this is not a big deal, because
62+
there are acceleration-services, such as
63+
<a target="_blank" href="https://mempool.space/accelerator" rel="noopener noreferrer">
64+
mempool.space's accelerator
65+
</a>, that allows to boost selected transactions for direct payment.
66+
Just in case this service will not be available in the future, the
67+
<i>Alert Transaction</i> will send a small amount of 600 sats to each
68+
destination address. This will allow advance users to boost the
69+
first transaction by spending their unmined UTXO in a mechanism called
70+
Child-Pay-For-Parent.
71+
</li>
72+
</ol>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"fullname": "Timelock Recovery Utility",
3+
"description": "<br/>This plug-in allows you to create Timelock Recovery Plans for your wallet. See: <a href='https://timelockrecovery.com'>timelockrecovery.com</a>",
4+
"author": "[email protected]",
5+
"available_for": ["qt"],
6+
"icon":"timelock_recovery_60.png",
7+
"version": "0.1.0"
8+
}

0 commit comments

Comments
 (0)