diff --git a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py index a32676442..c619fad83 100644 --- a/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/connect_wallet_flow.py @@ -25,7 +25,7 @@ get_deriv_path_from_addr_type_and_acct, get_addr_type_from_deriv, derive_address) -from public_constants import TRUST_PSBT +from public_constants import MUSIG_SKIP from wallets.constants import EXPORT_MODE_MICROSD, EXPORT_MODE_QR from wallets.sw_wallets import supported_software_wallets from utils import random_hex, spinner_task @@ -306,7 +306,7 @@ async def export_by_qr(self): self.set_result(False) return else: - common.settings.set('multisig_policy', TRUST_PSBT) + common.settings.set('multisig_policy', MUSIG_SKIP) self.goto(self.complete) else: self.goto(self.complete) @@ -375,7 +375,7 @@ async def export_by_microsd(self): self.set_result(False) return else: - common.settings.set('multisig_policy', TRUST_PSBT) + common.settings.set('multisig_policy', MUSIG_SKIP) self.goto(self.complete) else: self.goto(self.complete) @@ -475,7 +475,7 @@ async def do_multisig_config_import(self): self.set_result(False) return else: - common.settings.set('multisig_policy', TRUST_PSBT) + common.settings.set('multisig_policy', MUSIG_SKIP) self.goto(self.complete) else: self.goto(self.complete) diff --git a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py index 32899264a..cbce14c55 100644 --- a/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/import_multisig_wallet_flow.py @@ -16,35 +16,50 @@ async def show_overview(self): msg, is_dup = self.ms.format_overview() if is_dup: - await ErrorPage(text="Duplicate wallet will not be imported.").show() + await ErrorPage(text="Duplicate multisig wallet will not be imported.").show() self.set_result(False) return - else: - result = await LongTextPage(card_header={'title': 'Confirm Import'}, text=msg, centered=True).show() - if not result: - self.set_result(False) - return + + await LongTextPage(card_header={'title': 'Confirm Import'}, text=msg, centered=True, left_micron=None).show() self.goto(self.show_details) async def show_details(self): - from errors import Error - from utils import spinner_task, escape_text - from tasks import save_multisig_wallet_task + from utils import escape_text msg = self.ms.format_details() result = await LongTextPage(card_header={'title': escape_text(self.ms.name)}, text=msg, centered=True).show() + if not result: self.back() + return + + self.goto(self.confirm_import) + + async def confirm_import(self): + from pages import QuestionPage + + result = await QuestionPage('Import new multisig wallet?').show() + + if not result: + self.set_result(False) + return + + self.goto(self.import_wallet) + + async def import_wallet(self): + from utils import spinner_task + from errors import Error + from tasks import save_multisig_wallet_task + + # User confirmed the import, so save + (error,) = await spinner_task('Saving multisig', save_multisig_wallet_task, args=[self.ms]) + if not error: + self.set_result(True) + elif error is Error.USER_SETTINGS_FULL: + await ErrorPage(text='Out of space in user settings. Too many multisig configs?').show() + self.set_result(False) else: - # User confirmed the import, so save - (error,) = await spinner_task('Saving multisig', save_multisig_wallet_task, args=[self.ms]) - if not error: - self.set_result(True) - elif error is Error.USER_SETTINGS_FULL: - await ErrorPage(text='Out of space in user settings. Too many multisig configs?').show() - self.set_result(False) - else: - await ErrorPage(text='Unable to save multisig config.').show() - self.set_result(False) + await ErrorPage(text='Unable to save multisig config.').show() + self.set_result(False) diff --git a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py index dc74b1835..1624de0be 100644 --- a/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py +++ b/ports/stm32/boards/Passport/modules/flows/sign_psbt_common_flow.py @@ -49,8 +49,10 @@ async def check_multisig_import(self): if self.psbt.multisig_import_needs_approval: result = await ImportMultisigWalletFlow(self.psbt.active_multisig).run() if not result: - await ErrorPage( - 'The transaction can still be signed, but this multisig config will not be saved.').show() + text = 'The transaction can still be signed, but this multisig config will not be saved.' + result2 = await ErrorPage(text=text, left_micron=microns.Back).show() + if not result2: + return self.goto(self.show_transaction_details) diff --git a/ports/stm32/boards/Passport/modules/multisig_wallet.py b/ports/stm32/boards/Passport/modules/multisig_wallet.py index 240bf1215..b50f9d41f 100644 --- a/ports/stm32/boards/Passport/modules/multisig_wallet.py +++ b/ports/stm32/boards/Passport/modules/multisig_wallet.py @@ -18,7 +18,7 @@ from ubinascii import hexlify as b2a_hex from utils import xfp2str, str2xfp, cleanup_deriv_path, keypath_to_str, str_to_keypath from public_constants import (AF_P2SH, AF_P2WSH_P2SH, AF_P2WSH, AFC_SCRIPT, - TRUST_OFFER, TRUST_PSBT, TRUST_VERIFY, MAX_SIGNERS) + MUSIG_DEFAULT, MUSIG_SKIP, MUSIG_REQUIRE, MAX_SIGNERS) from constants import MAX_MULTISIG_NAME_LEN from exceptions import FatalPSBTIssue from opcodes import OP_CHECKMULTISIG @@ -158,14 +158,8 @@ def chain(self): @classmethod def get_trust_policy(cls): - from common import settings - - which = settings.get('multisig_policy', None) - - if which is None: - which = TRUST_VERIFY if cls.exists() else TRUST_OFFER - - return which + from utils import get_multisig_policy + return get_multisig_policy() def serialize(self): # return a JSON-able object @@ -329,12 +323,6 @@ def get_all(cls): # return them all, as a generator return cls.iter_wallets() - @classmethod - def exists(cls): - # are there any wallets defined? - from common import settings - return bool(settings.get('multisig', False)) - @classmethod def get_count(cls): from common import settings @@ -876,9 +864,9 @@ def import_from_psbt(cls, M, N, xpubs_list): trust_mode = cls.get_trust_policy() # print('import_from_psbt(): trust_mode = {}'.format(trust_mode)) - if trust_mode == TRUST_VERIFY: + if trust_mode == MUSIG_REQUIRE: # already checked for existing import and wasn't found, so fail - raise FatalPSBTIssue("XPUBs in PSBT do not match any existing wallet") + raise FatalPSBTIssue("XPUBs in PSBT do not match any existing wallet as required by multisig policy") # build up an in-memory version of the wallet. # - capture address format based on path used for my leg (if standards compliant) @@ -907,7 +895,7 @@ def import_from_psbt(cls, M, N, xpubs_list): # may just keep just in-memory version, no approval required, if we are # trusting PSBT's today, otherwise caller will need to handle UX w.r.t new wallet - return ms, (trust_mode != TRUST_PSBT) + return ms, (trust_mode != MUSIG_SKIP) def validate_psbt_xpubs(self, xpubs_list): # The xpubs provided in PSBT must be exactly right, compared to our record. @@ -988,18 +976,13 @@ def format_overview(self, importing=True): wallet first. Differences: '''.format(recolor(COPPER_HEX, 'WARNING:')) + ', '.join(diff_items) is_dup = True elif importing and num_dups: - msg = 'Duplicate wallet. All details are the same as an existing wallet, so it will not be added.' + msg = 'Duplicate wallet. All details are the same as an existing wallet, so it will not be added.\n\n' is_dup = True - elif not importing: - msg = '' else: - msg = 'Create new multisig wallet?' + msg = '' derivs, dsum = self.get_deriv_paths() - if importing: - msg += '\n\n' - msg += '''{name_title} {name} diff --git a/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py b/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py index beaeecc4e..92e2b1248 100644 --- a/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py +++ b/ports/stm32/boards/Passport/modules/pages/multisig_policy_setting_page.py @@ -4,18 +4,19 @@ # multisig_policy_setting_page.py - Set the multisig policy from pages import SettingPage -from public_constants import TRUST_OFFER, TRUST_VERIFY, TRUST_PSBT +from public_constants import MUSIG_ASK, MUSIG_REQUIRE, MUSIG_SKIP, MUSIG_DEFAULT +from utils import get_multisig_policy # Chooser for trust policy ch = ['Ask to Import', 'Require Existing', 'Skip Verification'] -values = [TRUST_OFFER, TRUST_VERIFY, TRUST_PSBT] +values = [MUSIG_ASK, MUSIG_REQUIRE, MUSIG_SKIP] class MultisigPolicySettingPage(SettingPage): OPTIONS = [ - {'label': 'Ask to Import', 'value': TRUST_OFFER}, - {'label': 'Require Existing', 'value': TRUST_VERIFY}, - {'label': 'Skip Verification', 'value': TRUST_PSBT}, + {'label': 'Ask to Import', 'value': MUSIG_ASK}, + {'label': 'Require Existing', 'value': MUSIG_REQUIRE}, + {'label': 'Skip Verification', 'value': MUSIG_SKIP}, ] def __init__(self, card_header=None, statusbar=None): @@ -24,4 +25,4 @@ def __init__(self, card_header=None, statusbar=None): statusbar=statusbar, setting_name='multisig_policy', options=self.OPTIONS, - default_value=self.OPTIONS[1].get('value')) + default_value=get_multisig_policy()) diff --git a/ports/stm32/boards/Passport/modules/pages/page.py b/ports/stm32/boards/Passport/modules/pages/page.py index 452276dfc..b7aca95c8 100644 --- a/ports/stm32/boards/Passport/modules/pages/page.py +++ b/ports/stm32/boards/Passport/modules/pages/page.py @@ -60,12 +60,12 @@ def detach(self): def left_action(self, is_pressed): # print('Page.right_action()') - if not is_pressed: + if not is_pressed and self.left_micron: self.set_result(False) def right_action(self, is_pressed): # print('Page.right_action()') - if not is_pressed: + if not is_pressed and self.right_micron: self.set_result(True) # By default, returns None so caller can differentiate between user pressing a button to back out diff --git a/ports/stm32/boards/Passport/modules/public_constants.py b/ports/stm32/boards/Passport/modules/public_constants.py index 3bfc79e3f..43fb6f975 100644 --- a/ports/stm32/boards/Passport/modules/public_constants.py +++ b/ports/stm32/boards/Passport/modules/public_constants.py @@ -109,9 +109,11 @@ MAX_SIGNERS = const(15) # PSBT Xpub trust policies -TRUST_VERIFY = const(0) -TRUST_OFFER = const(1) -TRUST_PSBT = const(2) +MUSIG_REQUIRE = const(0) +MUSIG_ASK = const(1) +MUSIG_SKIP = const(2) +MUSIG_DEFAULT = MUSIG_ASK +MUSIG_TEMP_DEFAULT = MUSIG_SKIP # Default Directories DIR_BACKUPS = 'backups' diff --git a/ports/stm32/boards/Passport/modules/utils.py b/ports/stm32/boards/Passport/modules/utils.py index ecb1528a1..259626a62 100644 --- a/ports/stm32/boards/Passport/modules/utils.py +++ b/ports/stm32/boards/Passport/modules/utils.py @@ -12,7 +12,7 @@ import lvgl as lv from constants import NUM_BACKUP_CODE_SECTIONS, NUM_DIGITS_PER_BACKUP_CODE_SECTION -from public_constants import DIR_BACKUPS +from public_constants import DIR_BACKUPS, MUSIG_DEFAULT, MUSIG_TEMP_DEFAULT from files import CardSlot from styles.colors import DEFAULT_LARGE_ICON_COLOR import ustruct @@ -1569,4 +1569,9 @@ def insufficient_randomness(seed_words): return False +def get_multisig_policy(): + default = MUSIG_TEMP_DEFAULT if has_temporary_seed() else MUSIG_DEFAULT + return common.settings.get('multisig_policy', default) + + # EOF diff --git a/ports/stm32/boards/Passport/modules/wallets/theya.py b/ports/stm32/boards/Passport/modules/wallets/theya.py index 343a9af2c..91a698dfc 100644 --- a/ports/stm32/boards/Passport/modules/wallets/theya.py +++ b/ports/stm32/boards/Passport/modules/wallets/theya.py @@ -22,7 +22,4 @@ 'filename_pattern_multisig': '{xfp}-theya-multisig.json'} ], 'export_fw_version': True, - # 'skip_address_validation': True, - # 'skip_multisig_import': True, - # 'force_multisig_policy': True }