-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add ability to import multisig wallet to Coldcard via USB #7682
Open
scgbckbone
wants to merge
2
commits into
spesmilo:master
Choose a base branch
from
scgbckbone:coldcard_import_multisig_walet_via_usb
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,15 @@ | ||
import time, os | ||
from functools import partial | ||
import copy | ||
|
||
from PyQt5.QtCore import Qt, pyqtSignal | ||
from PyQt5.QtCore import Qt | ||
from PyQt5.QtWidgets import QPushButton, QLabel, QVBoxLayout, QWidget, QGridLayout | ||
|
||
from electrum.gui.qt.util import (WindowModalDialog, CloseButton, Buttons, getOpenFileName, | ||
from electrum.gui.qt.util import (WindowModalDialog, CloseButton, getOpenFileName, | ||
getSaveFileName) | ||
from electrum.gui.qt.transaction_dialog import TxDialog | ||
from electrum.gui.qt.main_window import ElectrumWindow | ||
|
||
from electrum.i18n import _ | ||
from electrum.plugin import hook | ||
from electrum.wallet import Multisig_Wallet | ||
from electrum.transaction import PartialTransaction | ||
|
||
from .coldcard import ColdcardPlugin, xfp2str | ||
from ..hw_wallet.qt import QtHandlerBase, QtPluginBase | ||
|
@@ -29,6 +25,10 @@ class Plugin(ColdcardPlugin, QtPluginBase): | |
def create_handler(self, window): | ||
return Coldcard_Handler(window) | ||
|
||
@staticmethod | ||
def trim_file_suffix(path): | ||
return path.rsplit('.', 1)[0] | ||
|
||
@only_hook_if_libraries_available | ||
@hook | ||
def receive_menu(self, menu, addrs, wallet): | ||
|
@@ -47,23 +47,58 @@ def show_address(keystore=keystore): | |
def wallet_info_buttons(self, main_window, dialog): | ||
# user is about to see the "Wallet Information" dialog | ||
# - add a button if multisig wallet, and a Coldcard is a cosigner. | ||
buttons = [] | ||
wallet = main_window.wallet | ||
|
||
if type(wallet) is not Multisig_Wallet: | ||
return | ||
|
||
if not any(type(ks) == self.keystore_class for ks in wallet.get_keystores()): | ||
coldcard_keystores = [ | ||
ks | ||
for ks in wallet.get_keystores() | ||
if type(ks) == self.keystore_class | ||
] | ||
if not coldcard_keystores: | ||
# doesn't involve a Coldcard wallet, hide feature | ||
return | ||
|
||
btn = QPushButton(_("Export for Coldcard")) | ||
btn.clicked.connect(lambda unused: self.export_multisig_setup(main_window, wallet)) | ||
btn_export = QPushButton(_("Export multisig for Coldcard as file")) | ||
btn_export.clicked.connect(lambda unused: self.export_multisig_setup(main_window, wallet)) | ||
buttons.append(btn_export) | ||
btn_import_usb = QPushButton(_("Import multisig to Coldcard via USB")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Button texts are kind of long - but imo more comprehensible |
||
btn_import_usb.clicked.connect(lambda unused: self.import_multisig_wallet_to_cc(main_window, coldcard_keystores)) | ||
buttons.append(btn_import_usb) | ||
return buttons | ||
|
||
def import_multisig_wallet_to_cc(self, main_window, coldcard_keystores): | ||
from io import StringIO | ||
from ckcc.protocol import CCProtocolPacker | ||
|
||
return btn | ||
index = main_window.query_choice( | ||
_("Please select which {} device to use:".format(self.device)), | ||
[ks.label for ks in coldcard_keystores] | ||
) | ||
if index is not None: | ||
selected_keystore = coldcard_keystores[index] | ||
client = self.get_client(selected_keystore, force_pair=True, allow_user_interaction=False) | ||
if client is None: | ||
main_window.show_error("{} not connected.".format(selected_keystore.label)) | ||
return | ||
|
||
wallet = main_window.wallet | ||
sio = StringIO() | ||
basename = self.trim_file_suffix(wallet.basename()) | ||
ColdcardPlugin.export_ms_wallet(wallet, sio, basename) | ||
sio.seek(0) | ||
file_len, sha = client.dev.upload_file(sio.read().encode("utf-8"), verify=True) | ||
client.dev.send_recv(CCProtocolPacker.multisig_enroll(file_len, sha)) | ||
main_window.show_message('\n'.join([ | ||
_("Wallet setup file '{}' imported successfully.".format(basename)), | ||
_("Confirm import on your {} device.".format(selected_keystore.label)) | ||
])) | ||
|
||
def export_multisig_setup(self, main_window, wallet): | ||
|
||
basename = wallet.basename().rsplit('.', 1)[0] # trim .json | ||
basename = self.trim_file_suffix(wallet.basename()) | ||
name = f'{basename}-cc-export.txt'.replace(' ', '-') | ||
fileName = getSaveFileName( | ||
parent=main_window, | ||
|
@@ -75,7 +110,7 @@ def export_multisig_setup(self, main_window, wallet): | |
if fileName: | ||
with open(fileName, "wt") as f: | ||
ColdcardPlugin.export_ms_wallet(wallet, f, basename) | ||
main_window.show_message(_("Wallet setup file exported successfully")) | ||
main_window.show_message(_("Wallet setup file '{}' exported successfully".format(name))) | ||
|
||
def show_settings_dialog(self, window, keystore): | ||
# When they click on the icon for CC we come here. | ||
|
@@ -211,7 +246,6 @@ def start_upgrade(self, client): | |
from ckcc.utils import dfu_parse | ||
from ckcc.sigheader import FW_HEADER_SIZE, FW_HEADER_OFFSET, FW_HEADER_MAGIC | ||
from ckcc.protocol import CCProtocolPacker | ||
from hashlib import sha256 | ||
import struct | ||
|
||
try: | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed unused imports