diff --git a/src/seedsigner/controller.py b/src/seedsigner/controller.py index 5431f62c..8c91e9d4 100644 --- a/src/seedsigner/controller.py +++ b/src/seedsigner/controller.py @@ -49,7 +49,7 @@ class Controller(Singleton): rather than at the top in order avoid circular imports. """ - VERSION = "0.5.0 Pre-Release 3" + VERSION = "0.5.0" # Declare class member vars with type hints to enable richer IDE support throughout # the code. @@ -185,15 +185,6 @@ class Controller(Singleton): opening_splash = OpeningSplashView() opening_splash.start() - # TODO: Remove for v0.5.0 production release - WarningScreen( - title="Warning", - status_headline="Pre-Release Code", - text="Do not use this with real funds or to create new secure keys!", - show_back_button=False, - ).display() - - """ Class references can be stored as variables in python! This loop receives a View class to execute and stores it in the `View_cls` diff --git a/src/seedsigner/gui/components.py b/src/seedsigner/gui/components.py index ce723dce..18bff593 100644 --- a/src/seedsigner/gui/components.py +++ b/src/seedsigner/gui/components.py @@ -1,5 +1,4 @@ import math -from operator import is_ import os import pathlib @@ -33,7 +32,7 @@ class GUIConstants: ICON_FONT_SIZE = 22 ICON_INLINE_FONT_SIZE = 24 ICON_LARGE_BUTTON_SIZE = 36 - ICON_PRIMARY_SCREEN_SIZE = 44 + ICON_PRIMARY_SCREEN_SIZE = 60 TOP_NAV_TITLE_FONT_NAME = "OpenSans-SemiBold" TOP_NAV_TITLE_FONT_SIZE = 20 @@ -109,18 +108,19 @@ class FontAwesomeIconConstants: class SeedSignerCustomIconConstants: LARGE_CHEVRON_LEFT = "\ue900" SMALL_CHEVRON_RIGHT = "\ue901" - PAGE_DOWN = "\ue902" PAGE_UP = "\ue903" - CIRCLE_X = "\ue904" - CIRCLE_EXCLAMATION = "\ue905" - CIRCLE_CHECK = "\ue906" - FINGERPRINT = "\ue907" - PATH = "\ue908" - BITCOIN_LOGO = "\ue909" - BITCOIN_LOGO_2 = "\ue90a" + PAGE_DOWN = "\ue902" + PLUS = "\ue904" + CIRCLE_CHECK = "\ue907" + CIRCLE_EXCLAMATION = "\ue908" + CIRCLE_X = "\ue909" + FINGERPRINT = "\ue90a" + PATH = "\ue90b" + BITCOIN_LOGO_STRAIGHT = "\ue90c" + BITCOIN_LOGO_TILTED = "\ue90d" MIN_VALUE = LARGE_CHEVRON_LEFT - MAX_VALUE = BITCOIN_LOGO_2 + MAX_VALUE = BITCOIN_LOGO_TILTED @@ -419,7 +419,7 @@ class TextArea(BaseComponent): class Icon(BaseComponent): screen_x: int = 0 screen_y: int = 0 - icon_name: str = SeedSignerCustomIconConstants.BITCOIN_LOGO + icon_name: str = SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED icon_size: int = GUIConstants.ICON_FONT_SIZE icon_color: str = GUIConstants.BODY_FONT_COLOR @@ -438,11 +438,11 @@ class Icon(BaseComponent): def render(self): self.image_draw.text( - (self.screen_x, self.screen_y), + (self.screen_x, self.screen_y + self.height), text=self.icon_name, font=self.icon_font, fill=self.icon_color, - anchor="lt", # left, top anchor to avoid "ascender" gap space + anchor="ls", ) @@ -539,7 +539,8 @@ class IconTextLine(BaseComponent): if self.icon_name: icon_y = self.screen_y + int((self.height - self.icon.height)/2) self.icon.screen_y = icon_y - self.height = self.icon.height + + self.height = max(self.icon.height, self.height) if self.is_text_centered: if self.icon_name: @@ -762,8 +763,6 @@ class BtcAmount(BaseComponent): denomination = Settings.get_instance().get_value(SettingsConstants.SETTING__BTC_DENOMINATION) network = Settings.get_instance().get_value(SettingsConstants.SETTING__NETWORK) - print(self.total_sats) - btc_unit = "tBtc" sats_unit = "tSats" if network == SettingsConstants.MAINNET: @@ -789,7 +788,7 @@ class BtcAmount(BaseComponent): btc_icon = Icon( image_draw=draw, canvas=self.paste_image, - icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO, + icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED, icon_color=btc_color, icon_size=self.icon_size, screen_x=0, @@ -877,7 +876,7 @@ class BtcAmount(BaseComponent): btc_icon = Icon( image_draw=draw, canvas=self.paste_image, - icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO, + icon_name=SeedSignerCustomIconConstants.BITCOIN_LOGO_TILTED, icon_color=btc_color, icon_size=self.icon_size, screen_x=0, @@ -1047,7 +1046,6 @@ class Button(BaseComponent): self.icon_selected = Icon(icon_name=self.icon_name, icon_size=self.icon_size, icon_color=self.selected_icon_color) if self.is_icon_inline: - # TODO: Only apply screen_* at render if self.is_text_centered: # Shift the text's centering if self.text: @@ -1077,6 +1075,7 @@ class Button(BaseComponent): self.right_icon_y = math.ceil((self.height - self.right_icon.height)/2) + def render(self): if self.is_selected: background_color = self.selected_color diff --git a/src/seedsigner/gui/renderer.py b/src/seedsigner/gui/renderer.py index e0e321e5..cd3d031c 100644 --- a/src/seedsigner/gui/renderer.py +++ b/src/seedsigner/gui/renderer.py @@ -18,17 +18,13 @@ class Renderer(ConfigurableSingleton): @classmethod - def configure_instance(cls, config={}): + def configure_instance(cls): from seedsigner.models.settings import Settings - super().configure_instance(config) # Instantiate the one and only Renderer instance renderer = cls.__new__(cls) cls._instance = renderer - # TODO: Use Settings values to wire up diff hardware params - settings = Settings.get_instance() - # Eventually we'll be able to plug in other display controllers renderer.disp = ST7789() renderer.canvas_width = renderer.disp.width diff --git a/src/seedsigner/gui/screens/psbt_screens.py b/src/seedsigner/gui/screens/psbt_screens.py index 9cb482d2..62b606ef 100644 --- a/src/seedsigner/gui/screens/psbt_screens.py +++ b/src/seedsigner/gui/screens/psbt_screens.py @@ -38,7 +38,6 @@ class PSBTOverviewScreen(ButtonListScreen): # icon_text_lines_y = self.components[-1].screen_y + self.components[-1].height icon_text_lines_y = self.top_nav.height + GUIConstants.COMPONENT_PADDING - if not self.destination_addresses: # This is a self-transfer spend_amount = self.change_amount @@ -52,7 +51,7 @@ class PSBTOverviewScreen(ButtonListScreen): # Prep the transaction flow chart self.chart_x = 0 - self.chart_y = self.components[-1].screen_y + self.components[-1].height + GUIConstants.COMPONENT_PADDING + self.chart_y = self.components[-1].screen_y + self.components[-1].height + int(GUIConstants.COMPONENT_PADDING/2) chart_height = self.buttons[0].screen_y - self.chart_y - GUIConstants.COMPONENT_PADDING # We need to supersample the whole panel so that small/thin elements render @@ -70,7 +69,8 @@ class PSBTOverviewScreen(ButtonListScreen): font_size = GUIConstants.BODY_FONT_MIN_SIZE * ssf font = Fonts.get_font(GUIConstants.BODY_FONT_NAME, font_size) - tw, chart_text_height = font.getsize("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") # All possible chars for max range + # Measure from anchor "top" to include font pixels below baseline (e.g. the "g" in "change") + (left, top, right, chart_text_height) = font.getbbox(text="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", anchor="lt") vertical_center = int(image.height/2) # Supersampling renders thin elements poorly if they land on an even line before scaling down if vertical_center % 2 == 1: diff --git a/src/seedsigner/gui/screens/screen.py b/src/seedsigner/gui/screens/screen.py index dda658cf..ba64f741 100644 --- a/src/seedsigner/gui/screens/screen.py +++ b/src/seedsigner/gui/screens/screen.py @@ -56,8 +56,6 @@ class BaseScreen(BaseComponent): return self._run() except Exception as e: - print(e) - print("------") repr(e) raise e finally: @@ -214,7 +212,42 @@ class BaseTopNavScreen(BaseScreen): def _run(self): - raise Exception("Must implement in a child class") + while True: + if not self.top_nav.show_back_button and not self.top_nav.show_power_button: + # There's no navigation away from this screen; nothing to do here + time.sleep(0.1) + continue + + user_input = self.hw_inputs.wait_for( + HardwareButtonsConstants.ALL_KEYS, + check_release=True, + release_keys=HardwareButtonsConstants.KEYS__ANYCLICK + ) + + with self.renderer.lock: + if not self.top_nav.is_selected and user_input in [ + HardwareButtonsConstants.KEY_LEFT, + HardwareButtonsConstants.KEY_UP + ]: + self.top_nav.is_selected = True + self.top_nav.render_buttons() + + elif self.top_nav.is_selected and user_input in [ + HardwareButtonsConstants.KEY_DOWN, + HardwareButtonsConstants.KEY_RIGHT + ]: + self.top_nav.is_selected = False + self.top_nav.render_buttons() + + elif self.top_nav.is_selected and user_input in HardwareButtonsConstants.KEYS__ANYCLICK: + return self.top_nav.selected_button + + else: + # Nothing to do with this input + continue + + # Write the screen updates + self.renderer.show_image() @@ -810,6 +843,7 @@ class DireWarningScreen(WarningScreen): status_color: str = GUIConstants.DIRE_WARNING_COLOR + @dataclass class ResetScreen(BaseTopNavScreen): def __post_init__(self): @@ -822,10 +856,6 @@ class ResetScreen(BaseTopNavScreen): screen_y=self.top_nav.height, height=self.canvas_height - self.top_nav.height, )) - - def _run(self): - while True: - pass @@ -841,7 +871,3 @@ class PowerOffScreen(BaseTopNavScreen): screen_y=self.top_nav.height, height=self.canvas_height - self.top_nav.height, )) - - def _run(self): - while True: - pass diff --git a/src/seedsigner/gui/screens/settings_screens.py b/src/seedsigner/gui/screens/settings_screens.py index d7340ad4..7bfc729c 100644 --- a/src/seedsigner/gui/screens/settings_screens.py +++ b/src/seedsigner/gui/screens/settings_screens.py @@ -5,7 +5,7 @@ from typing import List from seedsigner.gui.components import Button, CheckboxButton, CheckedSelectionButton, FontAwesomeIconConstants, GUIConstants, IconButton, TextArea from seedsigner.gui.screens.scan_screens import ScanScreen -from seedsigner.gui.screens.screen import ButtonListScreen +from seedsigner.gui.screens.screen import BaseTopNavScreen, ButtonListScreen from seedsigner.hardware.buttons import HardwareButtonsConstants from seedsigner.models.settings import SettingsConstants @@ -190,3 +190,24 @@ class IOTestScreen(ScanScreen): cur_selected_button.is_selected = True time.sleep(0.1) + + + +@dataclass +class DonateScreen(BaseTopNavScreen): + def __post_init__(self): + self.title = "Donate" + super().__post_init__() + + self.components.append(TextArea( + text="SeedSigner is 100% free & open source, funded solely by the Bitcoin community.\n\nDonate onchain or LN at:", + screen_y=self.top_nav.height + 3*GUIConstants.COMPONENT_PADDING, + )) + + self.components.append(TextArea( + text="seedsigner.com", + font_size=GUIConstants.TOP_NAV_TITLE_FONT_SIZE + 8, + font_color=GUIConstants.ACCENT_COLOR, + supersampling_factor=1, + screen_y=self.components[-1].screen_y + self.components[-1].height + GUIConstants.COMPONENT_PADDING + )) diff --git a/src/seedsigner/models/decode_qr.py b/src/seedsigner/models/decode_qr.py index 7578ea9d..b0c034b2 100644 --- a/src/seedsigner/models/decode_qr.py +++ b/src/seedsigner/models/decode_qr.py @@ -60,8 +60,6 @@ class DecodeQR: qr_type = DecodeQR.detect_segment_type(data, wordlist_language_code=self.wordlist_language_code) - print(qr_type) - if self.qr_type == None: self.qr_type = qr_type @@ -97,6 +95,10 @@ class DecodeQR: elif self.qr_type != qr_type: raise Exception('QR Fragment Unexpected Type Change') + + if not self.decoder: + # Did not find any recognizable format + return DecodeQRStatus.INVALID # Process the binary formats first if self.qr_type == QRType.SEED__COMPACTSEEDQR: diff --git a/src/seedsigner/models/psbt_parser.py b/src/seedsigner/models/psbt_parser.py index c3518743..af29a882 100644 --- a/src/seedsigner/models/psbt_parser.py +++ b/src/seedsigner/models/psbt_parser.py @@ -58,7 +58,6 @@ class PSBTParser(): def _set_root(self): self.root = bip32.HDKey.from_seed(self.seed.seed_bytes, version=NETWORKS[SettingsConstants.map_network_to_embit(self.network)]["xprv"]) - print(f"root: {self.root}") def parse(self): @@ -85,7 +84,6 @@ class PSBTParser(): def _parse_inputs(self): self.input_amount = 0 - print(f"psbt.inputs: {self.psbt.inputs}") self.num_inputs = len(self.psbt.inputs) for inp in self.psbt.inputs: if inp.witness_utxo: @@ -343,5 +341,5 @@ class PSBTParser(): i = change_data["output_index"] output = self.psbt.outputs[i] is_owner = descriptor.owns(output) - print(f"{self.psbt.tx.vout[i].script_pubkey.address()} | {output.value} | {is_owner}") + # print(f"{self.psbt.tx.vout[i].script_pubkey.address()} | {output.value} | {is_owner}") return is_owner diff --git a/src/seedsigner/models/settings_definition.py b/src/seedsigner/models/settings_definition.py index cf1f009a..4687e1fa 100644 --- a/src/seedsigner/models/settings_definition.py +++ b/src/seedsigner/models/settings_definition.py @@ -513,8 +513,6 @@ class SettingsDefinition: if __name__ == "__main__": import json - import os - print("Exporting SettingsDefinition to json") output_file = "settings_definition.json" with open(output_file, 'w') as json_file: diff --git a/src/seedsigner/resources/fonts/seedsigner-glyphs.otf b/src/seedsigner/resources/fonts/seedsigner-glyphs.otf index 3edea9f5..63a0008c 100644 Binary files a/src/seedsigner/resources/fonts/seedsigner-glyphs.otf and b/src/seedsigner/resources/fonts/seedsigner-glyphs.otf differ diff --git a/src/seedsigner/views/psbt_views.py b/src/seedsigner/views/psbt_views.py index ced51a9b..ec198129 100644 --- a/src/seedsigner/views/psbt_views.py +++ b/src/seedsigner/views/psbt_views.py @@ -109,7 +109,7 @@ class PSBTOverviewView(View): num_change_outputs = 0 num_self_transfer_outputs = 0 for change_output in change_data: - print(f"""{change_output["derivation_path"][0]}""") + # print(f"""{change_output["derivation_path"][0]}""") if change_output["derivation_path"][0].split("/")[-2] == "1": num_change_outputs += 1 else: @@ -277,8 +277,6 @@ class PSBTChangeDetailsView(View): # Single-sig verification is easy. We expect to find a single fingerprint # and derivation path. seed_fingerprint = self.controller.psbt_seed.get_fingerprint(self.settings.get_value(SettingsConstants.SETTING__NETWORK)) - print(f"seed fingerprint: {seed_fingerprint}") - print(change_data) if seed_fingerprint not in change_data.get("fingerprint"): # TODO: Something is wrong with this psbt(?). Reroute to warning? diff --git a/src/seedsigner/views/seed_views.py b/src/seedsigner/views/seed_views.py index da7b2bab..1179af00 100644 --- a/src/seedsigner/views/seed_views.py +++ b/src/seedsigner/views/seed_views.py @@ -256,7 +256,6 @@ class SeedReviewPassphraseView(View): def __init__(self): super().__init__() self.seed = self.controller.storage.get_pending_seed() - print(f"SeedReviewPassphraseView self.seed: {self.seed}") def run(self): @@ -348,7 +347,7 @@ class SeedOptionsView(View): REVIEW_PSBT = "Review PSBT" VERIFY_ADDRESS = "Verify Addr" EXPORT_XPUB = "Export Xpub" - BACKUP = ("Backup Seed", None, None, None, FontAwesomeIconConstants.CIRCLE_CHEVRON_RIGHT) + BACKUP = ("Backup Seed", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT) DISCARD = ("Discard Seed", None, None, "red") button_data = [] @@ -366,7 +365,7 @@ class SeedOptionsView(View): if self.controller.psbt: if PSBTParser.has_matching_input_fingerprint(self.controller.psbt, self.seed, network=self.settings.get_value(SettingsConstants.SETTING__NETWORK)): if self.controller.resume_main_flow and self.controller.resume_main_flow == Controller.FLOW__PSBT: - # Re-route us directly back to the start of the PSBT flow + # Re-route us directly back to the start of the PSBT flow self.controller.resume_main_flow = None self.controller.psbt_seed = self.seed return Destination(PSBTOverviewView, skip_current_view=True) @@ -1122,9 +1121,6 @@ class AddressVerificationStartView(View): self.controller.unverified_address["sig_type"] = sig_type self.controller.unverified_address["derivation_path"] = derivation_path - import json - print(json.dumps(self.controller.unverified_address, indent=4)) - return destination @@ -1332,8 +1328,6 @@ class SeedAddressVerificationView(View): # Successfully verified the addr; update the data self.controller.unverified_address["verified_index"] = self.verified_index.cur_count self.controller.unverified_address["verified_index_is_change"] = self.verified_index_is_change.cur_count == 1 - import json - print(json.dumps(self.controller.unverified_address, indent=4)) return Destination(AddressVerificationSuccessView, view_args=dict(seed_num=self.seed_num)) else: @@ -1379,14 +1373,12 @@ class SeedAddressVerificationView(View): (receive_address, change_address) = self.derive_single_sig(i) if self.address == receive_address: - print(f"Verified receive addr #{i}!") self.verified_index.set_value(i) self.verified_index_is_change.set_value(0) self.keep_running = False break elif self.address == change_address: - print(f"Verified change addr #{i}!") self.verified_index.set_value(i) self.verified_index_is_change.set_value(1) self.keep_running = False @@ -1490,8 +1482,6 @@ class MultisigWalletDescriptorView(View): policy = descriptor.brief_policy.split("multisig")[0].strip() - print(fingerprints) - RETURN = "Return to PSBT" VERIFY = "Verify Addr" OK = "OK" diff --git a/src/seedsigner/views/settings_views.py b/src/seedsigner/views/settings_views.py index e3c46b31..5a705e08 100644 --- a/src/seedsigner/views/settings_views.py +++ b/src/seedsigner/views/settings_views.py @@ -1,4 +1,4 @@ -from seedsigner.gui.components import FontAwesomeIconConstants +from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerCustomIconConstants from seedsigner.models.decode_qr import DecodeQR from .view import View, Destination, BackStackView, MainMenuView @@ -16,6 +16,9 @@ class SettingsMenuView(View): def run(self): + IO_TEST = "I/O test" + DONATE = "Donate" + settings_entries = SettingsDefinition.get_settings_entries( visibiilty=self.visibility ) @@ -32,16 +35,17 @@ class SettingsMenuView(View): title = "Settings" # Set up the next nested level of menuing - button_data.append(("Advanced", None, None, None, FontAwesomeIconConstants.CIRCLE_CHEVRON_RIGHT)) + button_data.append(("Advanced", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT)) next = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__ADVANCED}) - button_data.append("I/O test") + button_data.append(IO_TEST) + button_data.append(DONATE) elif self.visibility == SettingsConstants.VISIBILITY__ADVANCED: title = "Advanced" # So far there are no real Developer options; disabling for now - # button_data.append(("Developer Options", None, None, None, FontAwesomeIconConstants.CIRCLE_CHEVRON_RIGHT)) + # button_data.append(("Developer Options", None, None, None, SeedSignerCustomIconConstants.SMALL_CHEVRON_RIGHT)) # next = Destination(SettingsMenuView, view_args={"visibility": SettingsConstants.VISIBILITY__DEVELOPER}) next = None @@ -67,9 +71,12 @@ class SettingsMenuView(View): elif selected_menu_num == len(settings_entries): return next - elif selected_menu_num == len(settings_entries) + 1: + elif len(button_data) > selected_menu_num and button_data[selected_menu_num] == IO_TEST: return Destination(IOTestView) + elif len(button_data) > selected_menu_num and button_data[selected_menu_num] == DONATE: + return Destination(DonateView) + else: # TODO: Free-entry types (are there any?) will need their own SettingsEntryUpdateFreeEntryView(?). return Destination(SettingsEntryUpdateSelectionView, view_args={"attr_name": settings_entries[selected_menu_num].attr_name}) @@ -179,3 +186,11 @@ class IOTestView(View): ).display() return Destination(SettingsMenuView) + + + +class DonateView(View): + def run(self): + settings_screens.DonateScreen().display() + + return Destination(SettingsMenuView) diff --git a/src/seedsigner/views/tools_views.py b/src/seedsigner/views/tools_views.py index bcc8c2f8..8c6b2216 100644 --- a/src/seedsigner/views/tools_views.py +++ b/src/seedsigner/views/tools_views.py @@ -4,7 +4,6 @@ import time from PIL import Image from PIL.ImageOps import autocontrast -from seedsigner.gui.screens.screen import LargeButtonScreen from seedsigner.hardware.camera import Camera from seedsigner.gui.components import FontAwesomeIconConstants @@ -13,9 +12,9 @@ from seedsigner.gui.screens.tools_screens import ToolsDiceEntropyEntryScreen, To from seedsigner.helpers import mnemonic_generation from seedsigner.models.seed import Seed from seedsigner.models.settings_definition import SettingsConstants -from seedsigner.views.seed_views import SeedDiscardView, SeedFinalizeView, SeedMnemonicEntryView, SeedWordsView, SeedWordsWarningView +from seedsigner.views.seed_views import SeedDiscardView, SeedFinalizeView, SeedMnemonicEntryView, SeedWordsWarningView -from .view import NotYetImplementedView, View, Destination, BackStackView, MainMenuView +from .view import View, Destination, BackStackView @@ -207,9 +206,9 @@ class ToolsDiceEntropyEntryView(View): if ret == RET_CODE__BACK_BUTTON: return Destination(BackStackView) - print(ret) + print(f"Dice rolls: {ret}") dice_seed_phrase = mnemonic_generation.generate_mnemonic_from_dice(ret) - print(dice_seed_phrase) + print(f"""Mnemonic: "{dice_seed_phrase}" """) # Add the mnemonic as an in-memory Seed seed = Seed(dice_seed_phrase, wordlist_language_code=self.settings.get_value(SettingsConstants.SETTING__WORDLIST_LANGUAGE)) diff --git a/tests/test_controller.py b/tests/test_controller.py index ef3e7ea3..b6887369 100644 --- a/tests/test_controller.py +++ b/tests/test_controller.py @@ -3,6 +3,7 @@ import pytest from mock import MagicMock from seedsigner.controller import Controller from seedsigner.models.settings import Settings +from seedsigner.models.settings_definition import SettingsConstants @@ -11,10 +12,6 @@ def test_singleton_init_fails(): with pytest.raises(Exception): c = Controller() -def test_singleton_get_instance_without_configure_fails(): - """ Calling get_instance() without first calling configure_instance() should fail """ - with pytest.raises(Exception): - c = Controller.get_instance() def test_singleton_get_instance_preserves_state(): """ Changes to the Controller singleton should be preserved across calls to get_instance() """ @@ -25,38 +22,17 @@ def test_singleton_get_instance_preserves_state(): Settings._instance = None Controller._instance = None - settings = """ - [system] - debug = False - default_language = en - persistent_settings = False - - [display] - text_color = ORANGE - qr_background_color = FFFFFF - camera_rotation = 0 - - [wallet] - network = main - software = Prompt - qr_density = 2 - custom_derivation = m/0/0 - compact_seedqr_enabled = False - """ - config = configparser.ConfigParser() - config.read_string(settings) - # Initialize the instance and verify that it read the config settings - Controller.configure_instance(config, disable_hardware=True) + Controller.configure_instance(disable_hardware=True) controller = Controller.get_instance() - assert controller.color == "ORANGE" + assert controller.unverified_address is None # Change a value in the instance... - controller.color = "purple" + controller.unverified_address = "123abc" # ...get a new copy of the instance and confirm change controller = Controller.get_instance() - assert controller.color == "purple" + assert controller.unverified_address == "123abc" def test_missing_settings_get_defaults(): @@ -69,30 +45,9 @@ def test_missing_settings_get_defaults(): Settings._instance = None Controller._instance = None - # Intentionally omit `compact_seedqr_enabled` from settings: - settings = """ - [system] - debug = False - default_language = en - persistent_settings = False - - [display] - text_color = ORANGE - qr_background_color = FFFFFF - camera_rotation = 0 - - [wallet] - network = main - software = Prompt - qr_density = 2 - custom_derivation = m/0/0 - """ - config = configparser.ConfigParser() - config.read_string(settings) - # Controller should parse the settings fine, even though a field is missing - Controller.configure_instance(config, disable_hardware=True) + Controller.configure_instance(disable_hardware=True) # Controller should still have a default value controller = Controller.get_instance() - assert controller.settings.compact_seedqr_enabled is False + assert controller.settings.get_value(SettingsConstants.SETTING__COMPACT_SEEDQR) == SettingsConstants.OPTION__DISABLED diff --git a/tests/test_decodepsbtqr.py b/tests/test_decodepsbtqr.py index 4891c882..ef9baa4a 100644 --- a/tests/test_decodepsbtqr.py +++ b/tests/test_decodepsbtqr.py @@ -3,6 +3,8 @@ from mock import MagicMock from seedsigner.models import Seed, DecodeQR, DecodeQRStatus, QRType, PSBTParser from embit import psbt, bip39 +from seedsigner.models.settings_definition import SettingsConstants + # this is an of this bug: https://github.com/Foundation-Devices/foundation-ur-py/issues/3 @@ -78,15 +80,15 @@ def test_base64_single_frame_singlsig(): assert str(tx) == base64_psbt - mnemonic = "height demise useless trap grow lion found off key clown transfer enroll" + mnemonic = "height demise useless trap grow lion found off key clown transfer enroll".split() pw = "" seed = Seed(mnemonic, passphrase=pw) - assert seed.mnemonic_str == mnemonic + assert seed.mnemonic_str == " ".join(mnemonic) assert seed.seed_bytes != None - pp = PSBTParser(tx,seed,"test") + pp = PSBTParser(p=tx, seed=seed, network=SettingsConstants.TESTNET) assert tx.inputs[0].witness_utxo.value == 25000 # input amount in psbt @@ -135,8 +137,8 @@ def test_base64_2_input_p2wsh(): assert str(tx) == base64_psbt - mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" - pp = PSBTParser(tx, Seed(mnemonic), "test") + mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".split() + pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET) assert tx.inputs[0].witness_utxo.value == 10000000 # input amount 1 in psbt @@ -162,8 +164,8 @@ def test_base64_1_input_p2sh_p2wsh(): assert str(tx) == base64_psbt - mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" - pp = PSBTParser(tx,Seed(mnemonic, wordlist=bip39.WORDLIST),"test") + mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about".split() + pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET) assert tx.inputs[0].witness_utxo.value == 100000000 # input amount 1 in psbt @@ -175,62 +177,6 @@ def test_base64_1_input_p2sh_p2wsh(): assert len(pp.destination_addresses) == 1 -def test_ur_legacy(): - - qrcodes = [ - "UR:BYTES/2OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3DJV07U94KMSQQQQQQQQZQ8A0CQSYQQQQQQQZQHA78FG5TANFV9Z2TPDWE57AUVCN2T06TDGCAJNYPAT9LVG5QFMU5QSQQQQQRLLLLLL3NZ3KK6TMJ2TTRH6SKU05V76GHEANAT2QSDCDPFG67YZQQPFFZKSZQQQQQQ0LLLLLUPYQRGRQQQQQQQQYGQZP4XCCZ3WFNWK" - , "UR:BYTES/2OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3DJV07U94KMSQQQQQQQQZQ8A0CQSYQQQQQQQZQHA78FG5TANFV9Z2TPDWE57AUVCN2T06TDGCAJNYPAT9LVG5QFMU5QSQQQQQRLLLLLL3NZ3KK6TMJ2TTRH6SKU05V76GHEANAT2QSDCDPFG67YZQQPFFZKSZQQQQQQ0LLLLLUPYQRGRQQQQQQQQYGQZP4XCCZ3WFNWK" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/4OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3Y0PYQFPQW6EJAC7ZGZUYVSCVLPJUS8CVFT8389KFXX82VM3YQMT26FRVHLVUQJ8XPZQYGR9FH3H26HSK99ZH3MQ4D7EHCS7Y752EP37HGG2X6RU5V3PKD7PMSPZQF9L7DESNZNS0H4V56978HCMAEG9D99CNY5LYCV247F58T7M66QUQYSS907LVPMZLKYAWMDGRRKT" - , "UR:BYTES/4OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3Y0PYQFPQW6EJAC7ZGZUYVSCVLPJUS8CVFT8389KFXX82VM3YQMT26FRVHLVUQJ8XPZQYGR9FH3H26HSK99ZH3MQ4D7EHCS7Y752EP37HGG2X6RU5V3PKD7PMSPZQF9L7DESNZNS0H4V56978HCMAEG9D99CNY5LYCV247F58T7M66QUQYSS907LVPMZLKYAWMDGRRKT" - , "UR:BYTES/5OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/GX8KAW6FYVRQ2HKD5T4WUJJ7K68T5262QQQQQQQPQY45QRGRQQQQQQQQYGQZP4XCCZ3WFNWK0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GQYZ5W53PQFMWVTS2CUAWJ43C87WR6ZZ705V5LU2AEKGEF8AM8FWP6TQFTD7AZGGZMKAVTUW8HDRTKMEET55FK6MX" - , "UR:BYTES/5OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/GX8KAW6FYVRQ2HKD5T4WUJJ7K68T5262QQQQQQQPQY45QRGRQQQQQQQQYGQZP4XCCZ3WFNWK0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GQYZ5W53PQFMWVTS2CUAWJ43C87WR6ZZ705V5LU2AEKGEF8AM8FWP6TQFTD7AZGGZMKAVTUW8HDRTKMEET55FK6MX" - , "UR:BYTES/5OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/GX8KAW6FYVRQ2HKD5T4WUJJ7K68T5262QQQQQQQPQY45QRGRQQQQQQQQYGQZP4XCCZ3WFNWK0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GQYZ5W53PQFMWVTS2CUAWJ43C87WR6ZZ705V5LU2AEKGEF8AM8FWP6TQFTD7AZGGZMKAVTUW8HDRTKMEET55FK6MX" - , "UR:BYTES/6OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/KTS8U3XQP95WYR8VQ9V2KWHCTS399T3ZQCP8DE3WPTRN462K8QLEC0GGTE73JNL3THXER9YLHVA9C8FVP9DHM5GUKUGYR2PSQQQGQQGQQZQQQQQQSQPQQQYQQQQQQQQRQQQQQGSXQTWM4303C7A5DWM089WJ3XMTV6EWQLJYCQYK3CSVASQ432E6LPWZY8XYUTHDXVQQ" - , "UR:BYTES/6OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/KTS8U3XQP95WYR8VQ9V2KWHCTS399T3ZQCP8DE3WPTRN462K8QLEC0GGTE73JNL3THXER9YLHVA9C8FVP9DHM5GUKUGYR2PSQQQGQQGQQZQQQQQQSQPQQQYQQQQQQQQRQQQQQGSXQTWM4303C7A5DWM089WJ3XMTV6EWQLJYCQYK3CSVASQ432E6LPWZY8XYUTHDXVQQ" - , "UR:BYTES/7OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/QZQQZQQQSQQQQQYQQGQQPQQQQQQQQQCQQQQQQQQPQ9R4YGGZDYQESZAAQHLY3L9L5VMSYRCQAXPWR6ES83NEC5XTMD4HPKVNGF4ZZQ4XNF7SKKG5KVH0UZPD3XXVNDWVP2CQAP0GLNRGQP2DHAD0U9HYLAF2UGSZQF5SRXQTH5ZLUJ8UH73NWQS0QR5C9C0TXQ7X08ZS" - , "UR:BYTES/7OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/QZQQZQQQSQQQQQYQQGQQPQQQQQQQQQCQQQQQQQQPQ9R4YGGZDYQESZAAQHLY3L9L5VMSYRCQAXPWR6ES83NEC5XTMD4HPKVNGF4ZZQ4XNF7SKKG5KVH0UZPD3XXVNDWVP2CQAP0GLNRGQP2DHAD0U9HYLAF2UGSZQF5SRXQTH5ZLUJ8UH73NWQS0QR5C9C0TXQ7X08ZS" - , "UR:BYTES/1OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/TYPUUURNVF607QGQ05PQQQQQQ9VXGQQDUMWH3LD9GH8XF4ZYJQNMQ80L6MC0KMV6JMVV22RDPZP0SQQQQQQQPLLLLLLSYS8ZQYQQQQQQQQTQQ9P6MG599TND0NJ54AZSE0ZHSHLY7Q4P94C79GQSQQQQQQQZYQPQ68Q0NLXPZYTUVURY6X4G8U7T5H4QVCHY3KKXAW0R" - , "UR:BYTES/1OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/TYPUUURNVF607QGQ05PQQQQQQ9VXGQQDUMWH3LD9GH8XF4ZYJQNMQ80L6MC0KMV6JMVV22RDPZP0SQQQQQQQPLLLLLLSYS8ZQYQQQQQQQQTQQ9P6MG599TND0NJ54AZSE0ZHSHLY7Q4P94C79GQSQQQQQQQZYQPQ68Q0NLXPZYTUVURY6X4G8U7T5H4QVCHY3KKXAW0R" - , "UR:BYTES/2OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3DJV07U94KMSQQQQQQQQZQ8A0CQSYQQQQQQQZQHA78FG5TANFV9Z2TPDWE57AUVCN2T06TDGCAJNYPAT9LVG5QFMU5QSQQQQQRLLLLLL3NZ3KK6TMJ2TTRH6SKU05V76GHEANAT2QSDCDPFG67YZQQPFFZKSZQQQQQQ0LLLLLUPYQRGRQQQQQQQQYGQZP4XCCZ3WFNWK" - , "UR:BYTES/2OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3DJV07U94KMSQQQQQQQQZQ8A0CQSYQQQQQQQZQHA78FG5TANFV9Z2TPDWE57AUVCN2T06TDGCAJNYPAT9LVG5QFMU5QSQQQQQRLLLLLL3NZ3KK6TMJ2TTRH6SKU05V76GHEANAT2QSDCDPFG67YZQQPFFZKSZQQQQQQ0LLLLLUPYQRGRQQQQQQQQYGQZP4XCCZ3WFNWK" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/3OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/0QXPCDECDVJ8PS0DPW59YDWSH262DUZV6VAT4E4GMPEQQQQQQQQQQ9SQZSRR3CY9AYW5V4Y0A5DMWD57JD7FXX9G95PYWVZYQGSX2Y0YENNVNLEHXVMTDS86QM4VNDHG9V0K3PNDMGAJLWLSTS6504SZYP80TGGDPFZR8AM7XZNM77XWKRHP0D0Y540FLPTA5C2HRUQ0" - , "UR:BYTES/4OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3Y0PYQFPQW6EJAC7ZGZUYVSCVLPJUS8CVFT8389KFXX82VM3YQMT26FRVHLVUQJ8XPZQYGR9FH3H26HSK99ZH3MQ4D7EHCS7Y752EP37HGG2X6RU5V3PKD7PMSPZQF9L7DESNZNS0H4V56978HCMAEG9D99CNY5LYCV247F58T7M66QUQYSS907LVPMZLKYAWMDGRRKT" - , "UR:BYTES/4OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/3Y0PYQFPQW6EJAC7ZGZUYVSCVLPJUS8CVFT8389KFXX82VM3YQMT26FRVHLVUQJ8XPZQYGR9FH3H26HSK99ZH3MQ4D7EHCS7Y752EP37HGG2X6RU5V3PKD7PMSPZQF9L7DESNZNS0H4V56978HCMAEG9D99CNY5LYCV247F58T7M66QUQYSS907LVPMZLKYAWMDGRRKT" - , "UR:BYTES/6OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/KTS8U3XQP95WYR8VQ9V2KWHCTS399T3ZQCP8DE3WPTRN462K8QLEC0GGTE73JNL3THXER9YLHVA9C8FVP9DHM5GUKUGYR2PSQQQGQQGQQZQQQQQQSQPQQQYQQQQQQQQRQQQQQGSXQTWM4303C7A5DWM089WJ3XMTV6EWQLJYCQYK3CSVASQ432E6LPWZY8XYUTHDXVQQ" - , "UR:BYTES/7OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/QZQQZQQQSQQQQQYQQGQQPQQQQQQQQQCQQQQQQQQPQ9R4YGGZDYQESZAAQHLY3L9L5VMSYRCQAXPWR6ES83NEC5XTMD4HPKVNGF4ZZQ4XNF7SKKG5KVH0UZPD3XXVNDWVP2CQAP0GLNRGQP2DHAD0U9HYLAF2UGSZQF5SRXQTH5ZLUJ8UH73NWQS0QR5C9C0TXQ7X08ZS" - , "UR:BYTES/7OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/QZQQZQQQSQQQQQYQQGQQPQQQQQQQQQCQQQQQQQQPQ9R4YGGZDYQESZAAQHLY3L9L5VMSYRCQAXPWR6ES83NEC5XTMD4HPKVNGF4ZZQ4XNF7SKKG5KVH0UZPD3XXVNDWVP2CQAP0GLNRGQP2DHAD0U9HYLAF2UGSZQF5SRXQTH5ZLUJ8UH73NWQS0QR5C9C0TXQ7X08ZS" - , "UR:BYTES/8OF8/MMH5LDF9RK3QKCUL3VM26M6270FFJU50CU6YT5WM65783GL5EJMQPG3WV3/E0DKKUXEJDPX589HZPQ6SVQQQZQQZQQQSQQQQQYQQGQQPQQPQQQQQPQQQQQZYQSZ56D86Z6EZJEJALSG9KYCEJD4ES9TQR59AR7VDQQ9FKL44LSKUNL3E38ZAMFNQQQQSQQSQQYQQQQQPQQZQQQGQQGQQQQQGQQQQQQQ0P6SEH" - ] - - d = DecodeQR() - for i in qrcodes: - if d.add_data(i) == DecodeQRStatus.COMPLETE: - break - assert d.qr_type == QRType.PSBT__LEGACY_UR - - #complete should be true - assert d.is_complete - - tx = d.get_psbt() - - mnemonic = "zone zone zone zone zone abandon ability able abandon ability able abstract" - pp = PSBTParser(tx,Seed(mnemonic, wordlist=bip39.WORDLIST),"test") - - assert pp.input_amount == 200000 - - assert pp.fee_amount == 226 - - assert pp.spend_amount == 123456 - - assert pp.change_amount == (pp.input_amount - pp.spend_amount - pp.fee_amount) - - assert pp.change_amount == 76318 - def test_specter_multisig_animated_qr(): qrcodes = [ @@ -252,8 +198,8 @@ def test_specter_multisig_animated_qr(): tx = d.get_psbt() - mnemonic = "zone zone zone zone zone abandon ability able abandon ability able abstract" - pp = PSBTParser(tx,Seed(mnemonic, wordlist=bip39.WORDLIST),"test") + mnemonic = "zone zone zone zone zone abandon ability able abandon ability able abstract".split() + pp = PSBTParser(p=tx, seed=Seed(mnemonic), network=SettingsConstants.TESTNET) assert pp.input_amount == 1052818 @@ -290,8 +236,8 @@ def test_specter_multisig_animated_qr(): tx2 = d2.get_psbt() - mnemonic2 = "able bacon cable able bacon cable abandon abandon abandon abandon abandon access" - pp2 = PSBTParser(tx2,Seed(mnemonic2, wordlist=bip39.WORDLIST),"test") + mnemonic2 = "able bacon cable able bacon cable abandon abandon abandon abandon abandon access".split() + pp2 = PSBTParser(p=tx2, seed=Seed(mnemonic2), network=SettingsConstants.TESTNET) assert pp2.input_amount == 1052818 @@ -334,8 +280,8 @@ def test_short_4_letter_mnemonic_qr(): assert d.is_complete assert d.get_seed_phrase() == ["height", "demise", "useless", "trap", "grow", "lion", "found", "off", "key", "clown", "transfer", "enroll"] -def test_bitcoin_address(): - + +def test_bitcoin_address(): bad1 = "loremipsum" bad2 = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae" bad3 = "121802020768124106400009195602431595117715840445" @@ -361,49 +307,44 @@ def test_bitcoin_address(): d.add_data(legacy_address1) assert d.get_address() == legacy_address1 - assert d.get_address_type() == "P2PKH-main" + assert d.get_address_type() == (SettingsConstants.LEGACY_P2PKH, SettingsConstants.MAINNET) d = DecodeQR() d.add_data(legacy_address2) assert d.get_address() == legacy_address2 - assert d.get_address_type() == "P2PKH-main" + assert d.get_address_type() == (SettingsConstants.LEGACY_P2PKH, SettingsConstants.MAINNET) d = DecodeQR() d.add_data(main_bech32_address) assert d.get_address() == main_bech32_address - assert d.get_address_type() == "Bech32-main" + assert d.get_address_type() == (SettingsConstants.NATIVE_SEGWIT, SettingsConstants.MAINNET) d = DecodeQR() d.add_data(test_bech32_address) assert d.get_address() == test_bech32_address - assert d.get_address_type() == "Bech32-test" + assert d.get_address_type() == (SettingsConstants.NATIVE_SEGWIT, SettingsConstants.TESTNET) d = DecodeQR() d.add_data(main_nested_segwit_address) assert d.get_address() == main_nested_segwit_address - assert d.get_address_type() == "P2SH-main" + assert d.get_address_type() == (SettingsConstants.NESTED_SEGWIT, SettingsConstants.MAINNET) d = DecodeQR() d.add_data(test_nested_segwit_address) - + assert d.get_address() == test_nested_segwit_address - assert d.get_address_type() == "P2SH-test" - + assert d.get_address_type() == (SettingsConstants.NESTED_SEGWIT, SettingsConstants.TESTNET) + d = DecodeQR() d.add_data(main_bech32_address2) assert d.get_address() == "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" - assert d.get_address_type() == "Bech32-main" - - d = DecodeQR() - d.add_data(main_bech32_address3) - - assert d.get_address() == "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq" - assert d.get_address_type() == "Bech32-main" + assert d.get_address_type() == (SettingsConstants.NATIVE_SEGWIT, SettingsConstants.MAINNET) + def test_seed_qr(): diff --git a/tests/test_encodepsbtqr.py b/tests/test_encodepsbtqr.py index 71a7a3b3..380a446d 100644 --- a/tests/test_encodepsbtqr.py +++ b/tests/test_encodepsbtqr.py @@ -1,7 +1,7 @@ import pytest from mock import MagicMock -from seedsigner.models import EncodeQR, QRType, EncodeQRDensity -from embit import psbt, bip39 +from seedsigner.models import EncodeQR, QRType +from embit import psbt from binascii import a2b_base64 from seedsigner.models.settings import SettingsConstants @@ -9,7 +9,6 @@ from seedsigner.models.settings import SettingsConstants def test_ur_qr_encode(): - base64_psbt = "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" tx = psbt.PSBT.parse(a2b_base64(base64_psbt)) @@ -23,8 +22,8 @@ def test_ur_qr_encode(): cnt += 1 -def test_specter_qr_encode(): +def test_specter_qr_encode(): base64_psbt = "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" tx = psbt.PSBT.parse(a2b_base64(base64_psbt)) @@ -60,43 +59,54 @@ def test_specter_qr_encode(): img = e.part_to_image(fragment) cnt += 1 -def test_seedsigner_qr(): + +def test_seedsigner_qr(): mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash" - e = EncodeQR(seed_phrase=mnemonic.split(" "), qr_type=QRType.SEED__SEEDQR) + e = EncodeQR(seed_phrase=mnemonic.split(), qr_type=QRType.SEED__SEEDQR) print(e.next_part()) assert e.next_part() == "121802020768124106400009195602431595117715840445" -def test_xpub_qr(): + +def test_xpub_qr(): mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash" - e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB, network="test", derivation="m/48h/1h/0h/2h") + e = EncodeQR(seed_phrase=mnemonic.split(), passphrase="pass", qr_type=QRType.XPUB, network=SettingsConstants.TESTNET, derivation="m/48h/1h/0h/2h") assert e.next_part() == "[c49122a5/48h/1h/0h/2h]Vpub5mXgECaX5yYDNc5VnUG4jVNptyEg65qUjuofWchQeuMWWiq8rcPBoMxfrVggXj5NJmaNEToWpax8GMMucozvAdqf1bW1JsZsfdBzsK3VUC5" -def test_specter_xpub_qr(): + +def test_specter_xpub_qr(): mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash" - e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB__SPECTER, network="test", derivation="m/48h/1h/0h/2h", qr_density=SettingsConstants.DENSITY__LOW) + e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB__SPECTER, network=SettingsConstants.TESTNET, derivation="m/48h/1h/0h/2h", qr_density=SettingsConstants.DENSITY__LOW) assert e.next_part() == "p1of4 [c49122a5/48h/1h/0h/2h]Vpub5mXgECaX5yYDN" assert e.next_part() == "p2of4 c5VnUG4jVNptyEg65qUjuofWchQeuMWWiq8rcPBo" assert e.next_part() == "p3of4 MxfrVggXj5NJmaNEToWpax8GMMucozvAdqf1bW1J" assert e.next_part() == "p4of4 sZsfdBzsK3VUC5" -def test_ur_xpub_qr(): - + + +def test_ur_xpub_qr(): mnemonic = "obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash" - e = EncodeQR(seed_phrase=mnemonic.split(" "), passphrase="pass", qr_type=QRType.XPUB__UR, network="test", derivation="m/48h/1h/0h/2h", qr_density=SettingsConstants.DENSITY__MEDIUM) + e = EncodeQR( + seed_phrase=mnemonic.split(), + passphrase="pass", + qr_type=QRType.XPUB__UR, + network=SettingsConstants.TESTNET, + derivation="m/48h/1h/0h/2h", + qr_density=SettingsConstants.DENSITY__MEDIUM + ) + # TODO: For Nick assert e.next_part() == "UR:CRYPTO-ACCOUNT/1-4/LPADAACSJKCYYNRDRTYAHDCAOEADCYSSMECPONAOLYTAADMETAADDLOXAXHDCLAOKSRLNLKPUEGYATHPMNRTAAOLAH" assert e.next_part() == "UR:CRYPTO-ACCOUNT/2-4/LPAOAACSJKCYYNRDRTYAHDCASNKKGHZMLUZORPVDGUOTECSTTKTOLPCWPTNTLKZTTIZTBEAAHDCXVDTPMYQDLAWNGL" assert e.next_part() == "UR:CRYPTO-ACCOUNT/3-4/LPAXAACSJKCYYNRDRTYAHDCARSTDSPZSBZSPGERLGDATUYNLPYBTGYIYYKBTWTAOSWKSVTSGCHBYDKYAVDSEPDJLAT" assert e.next_part() == "UR:CRYPTO-ACCOUNT/4-4/LPAAAACSJKCYYNRDRTYAHDCAAMTAADDYOEADLOCSDYYKADYKAEYKAOYKAOCYSSMECPONAYCYIOREKKJKAECADRRKIE" - diff --git a/tests/test_seed.py b/tests/test_seed.py index cc5eeaa3..45e597eb 100644 --- a/tests/test_seed.py +++ b/tests/test_seed.py @@ -6,10 +6,11 @@ from embit import bip39 from seedsigner.models.settings import SettingsConstants -spanish_wordlist = ["ábaco", "abdomen", "abeja", "abierto", "abogado", "abono", "aborto", "abrazo", "abrir", "abuelo", "abuso", "acabar", "academia", "acceso", "acción", "aceite", "acelga", "acento", "aceptar", "ácido", "aclarar", "acné", "acoger", "acoso", "activo", "acto", "actriz", "actuar", "acudir", "acuerdo", "acusar", "adicto", "admitir", "adoptar", "adorno", "aduana", "adulto", "aéreo", "afectar", "afición", "afinar", "afirmar", "ágil", "agitar", "agonía", "agosto", "agotar", "agregar", "agrio", "agua", "agudo", "águila", "aguja", "ahogo", "ahorro", "aire", "aislar", "ajedrez", "ajeno", "ajuste", "alacrán", "alambre", "alarma", "alba", "álbum", "alcalde", "aldea", "alegre", "alejar", "alerta", "aleta", "alfiler", "alga", "algodón", "aliado", "aliento", "alivio", "alma", "almeja", "almíbar", "altar", "alteza", "altivo", "alto", "altura", "alumno", "alzar", "amable", "amante", "amapola", "amargo", "amasar", "ámbar", "ámbito", "ameno", "amigo", "amistad", "amor", "amparo", "amplio", "ancho", "anciano", "ancla", "andar", "andén", "anemia", "ángulo", "anillo", "ánimo", "anís", "anotar", "antena", "antiguo", "antojo", "anual", "anular", "anuncio", "añadir", "añejo", "año", "apagar", "aparato", "apetito", "apio", "aplicar", "apodo", "aporte", "apoyo", "aprender", "aprobar", "apuesta", "apuro", "arado", "araña", "arar", "árbitro", "árbol", "arbusto", "archivo", "arco", "arder", "ardilla", "arduo", "área", "árido", "aries", "armonía", "arnés", "aroma", "arpa", "arpón", "arreglo", "arroz", "arruga", "arte", "artista", "asa", "asado", "asalto", "ascenso", "asegurar", "aseo", "asesor", "asiento", "asilo", "asistir", "asno", "asombro", "áspero", "astilla", "astro", "astuto", "asumir", "asunto", "atajo", "ataque", "atar", "atento", "ateo", "ático", "atleta", "átomo", "atraer", "atroz", "atún", "audaz", "audio", "auge", "aula", "aumento", "ausente", "autor", "aval", "avance", "avaro", "ave", "avellana", "avena", "avestruz", "avión", "aviso", "ayer", "ayuda", "ayuno", "azafrán", "azar", "azote", "azúcar", "azufre", "azul", "baba", "babor", "bache", "bahía", "baile", "bajar", "balanza", "balcón", "balde", "bambú", "banco", "banda", "baño", "barba", "barco", "barniz", "barro", "báscula", "bastón", "basura", "batalla", "batería", "batir", "batuta", "baúl", "bazar", "bebé", "bebida", "bello", "besar", "beso", "bestia", "bicho", "bien", "bingo", "blanco", "bloque", "blusa", "boa", "bobina", "bobo", "boca", "bocina", "boda", "bodega", "boina", "bola", "bolero", "bolsa", "bomba", "bondad", "bonito", "bono", "bonsái", "borde", "borrar", "bosque", "bote", "botín", "bóveda", "bozal", "bravo", "brazo", "brecha", "breve", "brillo", "brinco", "brisa", "broca", "broma", "bronce", "brote", "bruja", "brusco", "bruto", "buceo", "bucle", "bueno", "buey", "bufanda", "bufón", "búho", "buitre", "bulto", "burbuja", "burla", "burro", "buscar", "butaca", "buzón", "caballo", "cabeza", "cabina", "cabra", "cacao", "cadáver", "cadena", "caer", "café", "caída", "caimán", "caja", "cajón", "cal", "calamar", "calcio", "caldo", "calidad", "calle", "calma", "calor", "calvo", "cama", "cambio", "camello", "camino", "campo", "cáncer", "candil", "canela", "canguro", "canica", "canto", "caña", "cañón", "caoba", "caos", "capaz", "capitán", "capote", "captar", "capucha", "cara", "carbón", "cárcel", "careta", "carga", "cariño", "carne", "carpeta", "carro", "carta", "casa", "casco", "casero", "caspa", "castor", "catorce", "catre", "caudal", "causa", "cazo", "cebolla", "ceder", "cedro", "celda", "célebre", "celoso", "célula", "cemento", "ceniza", "centro", "cerca", "cerdo", "cereza", "cero", "cerrar", "certeza", "césped", "cetro", "chacal", "chaleco", "champú", "chancla", "chapa", "charla", "chico", "chiste", "chivo", "choque", "choza", "chuleta", "chupar", "ciclón", "ciego", "cielo", "cien", "cierto", "cifra", "cigarro", "cima", "cinco", "cine", "cinta", "ciprés", "circo", "ciruela", "cisne", "cita", "ciudad", "clamor", "clan", "claro", "clase", "clave", "cliente", "clima", "clínica", "cobre", "cocción", "cochino", "cocina", "coco", "código", "codo", "cofre", "coger", "cohete", "cojín", "cojo", "cola", "colcha", "colegio", "colgar", "colina", "collar", "colmo", "columna", "combate", "comer", "comida", "cómodo", "compra", "conde", "conejo", "conga", "conocer", "consejo", "contar", "copa", "copia", "corazón", "corbata", "corcho", "cordón", "corona", "correr", "coser", "cosmos", "costa", "cráneo", "cráter", "crear", "crecer", "creído", "crema", "cría", "crimen", "cripta", "crisis", "cromo", "crónica", "croqueta", "crudo", "cruz", "cuadro", "cuarto", "cuatro", "cubo", "cubrir", "cuchara", "cuello", "cuento", "cuerda", "cuesta", "cueva", "cuidar", "culebra", "culpa", "culto", "cumbre", "cumplir", "cuna", "cuneta", "cuota", "cupón", "cúpula", "curar", "curioso", "curso", "curva", "cutis", "dama", "danza", "dar", "dardo", "dátil", "deber", "débil", "década", "decir", "dedo", "defensa", "definir", "dejar", "delfín", "delgado", "delito", "demora", "denso", "dental", "deporte", "derecho", "derrota", "desayuno", "deseo", "desfile", "desnudo", "destino", "desvío", "detalle", "detener", "deuda", "día", "diablo", "diadema", "diamante", "diana", "diario", "dibujo", "dictar", "diente", "dieta", "diez", "difícil", "digno", "dilema", "diluir", "dinero", "directo", "dirigir", "disco", "diseño", "disfraz", "diva", "divino", "doble", "doce", "dolor", "domingo", "don", "donar", "dorado", "dormir", "dorso", "dos", "dosis", "dragón", "droga", "ducha", "duda", "duelo", "dueño", "dulce", "dúo", "duque", "durar", "dureza", "duro", "ébano", "ebrio", "echar", "eco", "ecuador", "edad", "edición", "edificio", "editor", "educar", "efecto", "eficaz", "eje", "ejemplo", "elefante", "elegir", "elemento", "elevar", "elipse", "élite", "elixir", "elogio", "eludir", "embudo", "emitir", "emoción", "empate", "empeño", "empleo", "empresa", "enano", "encargo", "enchufe", "encía", "enemigo", "enero", "enfado", "enfermo", "engaño", "enigma", "enlace", "enorme", "enredo", "ensayo", "enseñar", "entero", "entrar", "envase", "envío", "época", "equipo", "erizo", "escala", "escena", "escolar", "escribir", "escudo", "esencia", "esfera", "esfuerzo", "espada", "espejo", "espía", "esposa", "espuma", "esquí", "estar", "este", "estilo", "estufa", "etapa", "eterno", "ética", "etnia", "evadir", "evaluar", "evento", "evitar", "exacto", "examen", "exceso", "excusa", "exento", "exigir", "exilio", "existir", "éxito", "experto", "explicar", "exponer", "extremo", "fábrica", "fábula", "fachada", "fácil", "factor", "faena", "faja", "falda", "fallo", "falso", "faltar", "fama", "familia", "famoso", "faraón", "farmacia", "farol", "farsa", "fase", "fatiga", "fauna", "favor", "fax", "febrero", "fecha", "feliz", "feo", "feria", "feroz", "fértil", "fervor", "festín", "fiable", "fianza", "fiar", "fibra", "ficción", "ficha", "fideo", "fiebre", "fiel", "fiera", "fiesta", "figura", "fijar", "fijo", "fila", "filete", "filial", "filtro", "fin", "finca", "fingir", "finito", "firma", "flaco", "flauta", "flecha", "flor", "flota", "fluir", "flujo", "flúor", "fobia", "foca", "fogata", "fogón", "folio", "folleto", "fondo", "forma", "forro", "fortuna", "forzar", "fosa", "foto", "fracaso", "frágil", "franja", "frase", "fraude", "freír", "freno", "fresa", "frío", "frito", "fruta", "fuego", "fuente", "fuerza", "fuga", "fumar", "función", "funda", "furgón", "furia", "fusil", "fútbol", "futuro", "gacela", "gafas", "gaita", "gajo", "gala", "galería", "gallo", "gamba", "ganar", "gancho", "ganga", "ganso", "garaje", "garza", "gasolina", "gastar", "gato", "gavilán", "gemelo", "gemir", "gen", "género", "genio", "gente", "geranio", "gerente", "germen", "gesto", "gigante", "gimnasio", "girar", "giro", "glaciar", "globo", "gloria", "gol", "golfo", "goloso", "golpe", "goma", "gordo", "gorila", "gorra", "gota", "goteo", "gozar", "grada", "gráfico", "grano", "grasa", "gratis", "grave", "grieta", "grillo", "gripe", "gris", "grito", "grosor", "grúa", "grueso", "grumo", "grupo", "guante", "guapo", "guardia", "guerra", "guía", "guiño", "guion", "guiso", "guitarra", "gusano", "gustar", "haber", "hábil", "hablar", "hacer", "hacha", "hada", "hallar", "hamaca", "harina", "haz", "hazaña", "hebilla", "hebra", "hecho", "helado", "helio", "hembra", "herir", "hermano", "héroe", "hervir", "hielo", "hierro", "hígado", "higiene", "hijo", "himno", "historia", "hocico", "hogar", "hoguera", "hoja", "hombre", "hongo", "honor", "honra", "hora", "hormiga", "horno", "hostil", "hoyo", "hueco", "huelga", "huerta", "hueso", "huevo", "huida", "huir", "humano", "húmedo", "humilde", "humo", "hundir", "huracán", "hurto", "icono", "ideal", "idioma", "ídolo", "iglesia", "iglú", "igual", "ilegal", "ilusión", "imagen", "imán", "imitar", "impar", "imperio", "imponer", "impulso", "incapaz", "índice", "inerte", "infiel", "informe", "ingenio", "inicio", "inmenso", "inmune", "innato", "insecto", "instante", "interés", "íntimo", "intuir", "inútil", "invierno", "ira", "iris", "ironía", "isla", "islote", "jabalí", "jabón", "jamón", "jarabe", "jardín", "jarra", "jaula", "jazmín", "jefe", "jeringa", "jinete", "jornada", "joroba", "joven", "joya", "juerga", "jueves", "juez", "jugador", "jugo", "juguete", "juicio", "junco", "jungla", "junio", "juntar", "júpiter", "jurar", "justo", "juvenil", "juzgar", "kilo", "koala", "labio", "lacio", "lacra", "lado", "ladrón", "lagarto", "lágrima", "laguna", "laico", "lamer", "lámina", "lámpara", "lana", "lancha", "langosta", "lanza", "lápiz", "largo", "larva", "lástima", "lata", "látex", "latir", "laurel", "lavar", "lazo", "leal", "lección", "leche", "lector", "leer", "legión", "legumbre", "lejano", "lengua", "lento", "leña", "león", "leopardo", "lesión", "letal", "letra", "leve", "leyenda", "libertad", "libro", "licor", "líder", "lidiar", "lienzo", "liga", "ligero", "lima", "límite", "limón", "limpio", "lince", "lindo", "línea", "lingote", "lino", "linterna", "líquido", "liso", "lista", "litera", "litio", "litro", "llaga", "llama", "llanto", "llave", "llegar", "llenar", "llevar", "llorar", "llover", "lluvia", "lobo", "loción", "loco", "locura", "lógica", "logro", "lombriz", "lomo", "lonja", "lote", "lucha", "lucir", "lugar", "lujo", "luna", "lunes", "lupa", "lustro", "luto", "luz", "maceta", "macho", "madera", "madre", "maduro", "maestro", "mafia", "magia", "mago", "maíz", "maldad", "maleta", "malla", "malo", "mamá", "mambo", "mamut", "manco", "mando", "manejar", "manga", "maniquí", "manjar", "mano", "manso", "manta", "mañana", "mapa", "máquina", "mar", "marco", "marea", "marfil", "margen", "marido", "mármol", "marrón", "martes", "marzo", "masa", "máscara", "masivo", "matar", "materia", "matiz", "matriz", "máximo", "mayor", "mazorca", "mecha", "medalla", "medio", "médula", "mejilla", "mejor", "melena", "melón", "memoria", "menor", "mensaje", "mente", "menú", "mercado", "merengue", "mérito", "mes", "mesón", "meta", "meter", "método", "metro", "mezcla", "miedo", "miel", "miembro", "miga", "mil", "milagro", "militar", "millón", "mimo", "mina", "minero", "mínimo", "minuto", "miope", "mirar", "misa", "miseria", "misil", "mismo", "mitad", "mito", "mochila", "moción", "moda", "modelo", "moho", "mojar", "molde", "moler", "molino", "momento", "momia", "monarca", "moneda", "monja", "monto", "moño", "morada", "morder", "moreno", "morir", "morro", "morsa", "mortal", "mosca", "mostrar", "motivo", "mover", "móvil", "mozo", "mucho", "mudar", "mueble", "muela", "muerte", "muestra", "mugre", "mujer", "mula", "muleta", "multa", "mundo", "muñeca", "mural", "muro", "músculo", "museo", "musgo", "música", "muslo", "nácar", "nación", "nadar", "naipe", "naranja", "nariz", "narrar", "nasal", "natal", "nativo", "natural", "náusea", "naval", "nave", "navidad", "necio", "néctar", "negar", "negocio", "negro", "neón", "nervio", "neto", "neutro", "nevar", "nevera", "nicho", "nido", "niebla", "nieto", "niñez", "niño", "nítido", "nivel", "nobleza", "noche", "nómina", "noria", "norma", "norte", "nota", "noticia", "novato", "novela", "novio", "nube", "nuca", "núcleo", "nudillo", "nudo", "nuera", "nueve", "nuez", "nulo", "número", "nutria", "oasis", "obeso", "obispo", "objeto", "obra", "obrero", "observar", "obtener", "obvio", "oca", "ocaso", "océano", "ochenta", "ocho", "ocio", "ocre", "octavo", "octubre", "oculto", "ocupar", "ocurrir", "odiar", "odio", "odisea", "oeste", "ofensa", "oferta", "oficio", "ofrecer", "ogro", "oído", "oír", "ojo", "ola", "oleada", "olfato", "olivo", "olla", "olmo", "olor", "olvido", "ombligo", "onda", "onza", "opaco", "opción", "ópera", "opinar", "oponer", "optar", "óptica", "opuesto", "oración", "orador", "oral", "órbita", "orca", "orden", "oreja", "órgano", "orgía", "orgullo", "oriente", "origen", "orilla", "oro", "orquesta", "oruga", "osadía", "oscuro", "osezno", "oso", "ostra", "otoño", "otro", "oveja", "óvulo", "óxido", "oxígeno", "oyente", "ozono", "pacto", "padre", "paella", "página", "pago", "país", "pájaro", "palabra", "palco", "paleta", "pálido", "palma", "paloma", "palpar", "pan", "panal", "pánico", "pantera", "pañuelo", "papá", "papel", "papilla", "paquete", "parar", "parcela", "pared", "parir", "paro", "párpado", "parque", "párrafo", "parte", "pasar", "paseo", "pasión", "paso", "pasta", "pata", "patio", "patria", "pausa", "pauta", "pavo", "payaso", "peatón", "pecado", "pecera", "pecho", "pedal", "pedir", "pegar", "peine", "pelar", "peldaño", "pelea", "peligro", "pellejo", "pelo", "peluca", "pena", "pensar", "peñón", "peón", "peor", "pepino", "pequeño", "pera", "percha", "perder", "pereza", "perfil", "perico", "perla", "permiso", "perro", "persona", "pesa", "pesca", "pésimo", "pestaña", "pétalo", "petróleo", "pez", "pezuña", "picar", "pichón", "pie", "piedra", "pierna", "pieza", "pijama", "pilar", "piloto", "pimienta", "pino", "pintor", "pinza", "piña", "piojo", "pipa", "pirata", "pisar", "piscina", "piso", "pista", "pitón", "pizca", "placa", "plan", "plata", "playa", "plaza", "pleito", "pleno", "plomo", "pluma", "plural", "pobre", "poco", "poder", "podio", "poema", "poesía", "poeta", "polen", "policía", "pollo", "polvo", "pomada", "pomelo", "pomo", "pompa", "poner", "porción", "portal", "posada", "poseer", "posible", "poste", "potencia", "potro", "pozo", "prado", "precoz", "pregunta", "premio", "prensa", "preso", "previo", "primo", "príncipe", "prisión", "privar", "proa", "probar", "proceso", "producto", "proeza", "profesor", "programa", "prole", "promesa", "pronto", "propio", "próximo", "prueba", "público", "puchero", "pudor", "pueblo", "puerta", "puesto", "pulga", "pulir", "pulmón", "pulpo", "pulso", "puma", "punto", "puñal", "puño", "pupa", "pupila", "puré", "quedar", "queja", "quemar", "querer", "queso", "quieto", "química", "quince", "quitar", "rábano", "rabia", "rabo", "ración", "radical", "raíz", "rama", "rampa", "rancho", "rango", "rapaz", "rápido", "rapto", "rasgo", "raspa", "rato", "rayo", "raza", "razón", "reacción", "realidad", "rebaño", "rebote", "recaer", "receta", "rechazo", "recoger", "recreo", "recto", "recurso", "red", "redondo", "reducir", "reflejo", "reforma", "refrán", "refugio", "regalo", "regir", "regla", "regreso", "rehén", "reino", "reír", "reja", "relato", "relevo", "relieve", "relleno", "reloj", "remar", "remedio", "remo", "rencor", "rendir", "renta", "reparto", "repetir", "reposo", "reptil", "res", "rescate", "resina", "respeto", "resto", "resumen", "retiro", "retorno", "retrato", "reunir", "revés", "revista", "rey", "rezar", "rico", "riego", "rienda", "riesgo", "rifa", "rígido", "rigor", "rincón", "riñón", "río", "riqueza", "risa", "ritmo", "rito", "rizo", "roble", "roce", "rociar", "rodar", "rodeo", "rodilla", "roer", "rojizo", "rojo", "romero", "romper", "ron", "ronco", "ronda", "ropa", "ropero", "rosa", "rosca", "rostro", "rotar", "rubí", "rubor", "rudo", "rueda", "rugir", "ruido", "ruina", "ruleta", "rulo", "rumbo", "rumor", "ruptura", "ruta", "rutina", "sábado", "saber", "sabio", "sable", "sacar", "sagaz", "sagrado", "sala", "saldo", "salero", "salir", "salmón", "salón", "salsa", "salto", "salud", "salvar", "samba", "sanción", "sandía", "sanear", "sangre", "sanidad", "sano", "santo", "sapo", "saque", "sardina", "sartén", "sastre", "satán", "sauna", "saxofón", "sección", "seco", "secreto", "secta", "sed", "seguir", "seis", "sello", "selva", "semana", "semilla", "senda", "sensor", "señal", "señor", "separar", "sepia", "sequía", "ser", "serie", "sermón", "servir", "sesenta", "sesión", "seta", "setenta", "severo", "sexo", "sexto", "sidra", "siesta", "siete", "siglo", "signo", "sílaba", "silbar", "silencio", "silla", "símbolo", "simio", "sirena", "sistema", "sitio", "situar", "sobre", "socio", "sodio", "sol", "solapa", "soldado", "soledad", "sólido", "soltar", "solución", "sombra", "sondeo", "sonido", "sonoro", "sonrisa", "sopa", "soplar", "soporte", "sordo", "sorpresa", "sorteo", "sostén", "sótano", "suave", "subir", "suceso", "sudor", "suegra", "suelo", "sueño", "suerte", "sufrir", "sujeto", "sultán", "sumar", "superar", "suplir", "suponer", "supremo", "sur", "surco", "sureño", "surgir", "susto", "sutil", "tabaco", "tabique", "tabla", "tabú", "taco", "tacto", "tajo", "talar", "talco", "talento", "talla", "talón", "tamaño", "tambor", "tango", "tanque", "tapa", "tapete", "tapia", "tapón", "taquilla", "tarde", "tarea", "tarifa", "tarjeta", "tarot", "tarro", "tarta", "tatuaje", "tauro", "taza", "tazón", "teatro", "techo", "tecla", "técnica", "tejado", "tejer", "tejido", "tela", "teléfono", "tema", "temor", "templo", "tenaz", "tender", "tener", "tenis", "tenso", "teoría", "terapia", "terco", "término", "ternura", "terror", "tesis", "tesoro", "testigo", "tetera", "texto", "tez", "tibio", "tiburón", "tiempo", "tienda", "tierra", "tieso", "tigre", "tijera", "tilde", "timbre", "tímido", "timo", "tinta", "tío", "típico", "tipo", "tira", "tirón", "titán", "títere", "título", "tiza", "toalla", "tobillo", "tocar", "tocino", "todo", "toga", "toldo", "tomar", "tono", "tonto", "topar", "tope", "toque", "tórax", "torero", "tormenta", "torneo", "toro", "torpedo", "torre", "torso", "tortuga", "tos", "tosco", "toser", "tóxico", "trabajo", "tractor", "traer", "tráfico", "trago", "traje", "tramo", "trance", "trato", "trauma", "trazar", "trébol", "tregua", "treinta", "tren", "trepar", "tres", "tribu", "trigo", "tripa", "triste", "triunfo", "trofeo", "trompa", "tronco", "tropa", "trote", "trozo", "truco", "trueno", "trufa", "tubería", "tubo", "tuerto", "tumba", "tumor", "túnel", "túnica", "turbina", "turismo", "turno", "tutor", "ubicar", "úlcera", "umbral", "unidad", "unir", "universo", "uno", "untar", "uña", "urbano", "urbe", "urgente", "urna", "usar", "usuario", "útil", "utopía", "uva", "vaca", "vacío", "vacuna", "vagar", "vago", "vaina", "vajilla", "vale", "válido", "valle", "valor", "válvula", "vampiro", "vara", "variar", "varón", "vaso", "vecino", "vector", "vehículo", "veinte", "vejez", "vela", "velero", "veloz", "vena", "vencer", "venda", "veneno", "vengar", "venir", "venta", "venus", "ver", "verano", "verbo", "verde", "vereda", "verja", "verso", "verter", "vía", "viaje", "vibrar", "vicio", "víctima", "vida", "vídeo", "vidrio", "viejo", "viernes", "vigor", "vil", "villa", "vinagre", "vino", "viñedo", "violín", "viral", "virgo", "virtud", "visor", "víspera", "vista", "vitamina", "viudo", "vivaz", "vivero", "vivir", "vivo", "volcán", "volumen", "volver", "voraz", "votar", "voto", "voz", "vuelo", "vulgar", "yacer", "yate", "yegua", "yema", "yerno", "yeso", "yodo", "yoga", "yogur", "zafiro", "zanja", "zapato", "zarza", "zona", "zorro", "zumo", "zurdo"] +# TODO: Re-enable once multi-language bip-39 wordlists are supported +@pytest.mark.skip def test_seed(): - seed = Seed(mnemonic="obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash") + seed = Seed(mnemonic="obscure bone gas open exotic abuse virus bunker shuffle nasty ship dash".split()) assert seed.seed_bytes == b'q\xb3\xd1i\x0c\x9b\x9b\xdf\xa7\xd9\xd97H\xa8,\xa7\xd9>\xeck\xc2\xf5ND?, \x88-\x07\x9aa\xc5\xee\xb7\xbf\xc4x\xd6\x07 X\xb6}?M\xaa\x05\xa6\xa7(>\xbf\x03\xb0\x9d\xef\xed":\xdf\x88w7' @@ -18,7 +19,7 @@ def test_seed(): assert seed.passphrase == "" # TODO: Not yet supported in new implementation - seed.set_wordlist_language_code(SettingsConstants.WORDLIST_LANGUAGE__SPANISH) + seed.set_wordlist_language_code("es") assert seed.mnemonic_str == "natural ayuda futuro nivel espejo abuelo vago bien repetir moreno relevo conga" @@ -29,7 +30,7 @@ def test_seed(): assert seed.mnemonic_str == "height demise useless trap grow lion found off key clown transfer enroll" # TODO: Not yet supported in new implementation - seed.set_wordlist_language_code(SettingsConstants.WORDLIST_LANGUAGE__SPANISH) + seed.set_wordlist_language_code("es") assert seed.mnemonic_str == "hebilla cría truco tigre gris llenar folio negocio laico casa tieso eludir" diff --git a/tests/test_seedqr.py b/tests/test_seedqr.py index b7668bee..7e2d6385 100644 --- a/tests/test_seedqr.py +++ b/tests/test_seedqr.py @@ -9,6 +9,7 @@ from seedsigner.models.qr_type import QRType from seedsigner.models.settings import SettingsConstants + def run_encode_decode_test(entropy: bytes, mnemonic_length, qr_type): """ Helper method to re-run multiple variations of the same encode/decode test """ print(entropy) @@ -16,7 +17,7 @@ def run_encode_decode_test(entropy: bytes, mnemonic_length, qr_type): print(seed_phrase) assert len(seed_phrase) == mnemonic_length - e = EncodeQR(seed_phrase=seed_phrase, qr_type=qr_type, wordlist=bip39.WORDLIST) + e = EncodeQR(seed_phrase=seed_phrase, qr_type=qr_type) data = e.next_part() print(data) @@ -28,7 +29,7 @@ def run_encode_decode_test(entropy: bytes, mnemonic_length, qr_type): border=3 ) - decoder = DecodeQR(wordlist_language_code=SettingsConstants.LANGUAGE__ENGLISH) + decoder = DecodeQR() status = decoder.add_image(image) assert status == DecodeQRStatus.COMPLETE