diff --git a/src/krux/pages/wallet_settings.py b/src/krux/pages/wallet_settings.py index 60e8d22fe..b4eb7e4b6 100644 --- a/src/krux/pages/wallet_settings.py +++ b/src/krux/pages/wallet_settings.py @@ -21,6 +21,7 @@ # THE SOFTWARE. from embit.networks import NETWORKS +from embit.bip32 import HARDENED_INDEX from ..display import FONT_HEIGHT, DEFAULT_PADDING from ..krux_settings import t from . import ( @@ -43,7 +44,6 @@ from ..key import P2PKH, P2SH_P2WPKH, P2WPKH, P2WSH, P2TR PASSPHRASE_MAX_LEN = 200 -ACCOUNT_MAX = 2**31 - 1 # Maximum account index class PassphraseEditor(Page): @@ -212,11 +212,11 @@ def _account(self, initial_account=None): return None try: account = int(account) - if account > ACCOUNT_MAX: + if account >= HARDENED_INDEX: raise ValueError except: self.flash_error( - t("Value %s out of range: [%s, %s]") % (account, 0, ACCOUNT_MAX) + t("Value %s out of range: [%s, %s]") % (account, 0, HARDENED_INDEX - 1) ) return None return account diff --git a/tests/pages/test_wallet_settings.py b/tests/pages/test_wallet_settings.py index a37b915ec..507820fdd 100644 --- a/tests/pages/test_wallet_settings.py +++ b/tests/pages/test_wallet_settings.py @@ -1,4 +1,38 @@ from . import create_ctx +from .home_pages.test_home import tdata + + +def test_type_passphrase(m5stickv, mocker): + from krux.pages.wallet_settings import PassphraseEditor + + TEST_VALUE = "Test value" + ctx = create_ctx(mocker, TEST_VALUE) + passphrase_editor = PassphraseEditor(ctx) + mocker.patch.object( + passphrase_editor, + "capture_from_keypad", + mocker.MagicMock(return_value=TEST_VALUE), + ) + test_passphrase = passphrase_editor._load_passphrase() + + assert test_passphrase == TEST_VALUE + + +def test_type_passphrase_esc(m5stickv, mocker): + from krux.pages.wallet_settings import PassphraseEditor + from krux.pages import BUTTON_ENTER, BUTTON_PAGE_PREV + + BTN_SEQUENCE = [ + BUTTON_ENTER, # Type BIP39 Passphrase + *([BUTTON_PAGE_PREV] * 2), # Go to "Esc" + BUTTON_ENTER, # Press Esc + BUTTON_ENTER, # Confirm Esc + ] + ctx = create_ctx(mocker, BTN_SEQUENCE) + passphrase_editor = PassphraseEditor(ctx) + test_passphrase = passphrase_editor.load_passphrase_menu() + + assert test_passphrase is None def test_qr_passphrase(m5stickv, mocker): @@ -44,3 +78,268 @@ def test_qr_passphrase_fail(m5stickv, mocker): test_passphrase = passphrase_editor._load_qr_passphrase() assert test_passphrase == MENU_CONTINUE + + +def test_change_multisig_changes(m5stickv, mocker, tdata): + from krux.pages.wallet_settings import WalletSettings + from krux.wallet import Wallet + from krux.key import Key + from krux.pages import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV + + BTN_SEQUENCE_1 = [ + BUTTON_PAGE, # Go to "Single/Multisig" + BUTTON_ENTER, # Enter "Single/Multisig" + BUTTON_PAGE, # Change to Multisig + BUTTON_ENTER, # Confirm Multisig + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE_1, Wallet(tdata.SINGLESIG_12_WORD_KEY)) + mnemonic = ctx.wallet.key.mnemonic + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + + assert ctx.wallet.is_multisig() is True + + # Change back to singlesig + BTN_SEQUENCE_2 = [ + BUTTON_PAGE, # Go to "Single/Multisig" + BUTTON_ENTER, # Enter "Single/Multisig" + BUTTON_ENTER, # Confirm Single + *([BUTTON_PAGE] * 2), # Choose Native Segwit + BUTTON_ENTER, # Confirm Native Segwit + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + ctx = create_ctx(mocker, BTN_SEQUENCE_2, ctx.wallet) + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + assert ctx.wallet.is_multisig() is False + + +def test_change_script_type(m5stickv, mocker, tdata): + from krux.pages.wallet_settings import WalletSettings + from krux.wallet import Wallet + from krux.key import Key + from krux.pages import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV + + BTN_SEQUENCE_1 = [ + *([BUTTON_PAGE] * 2), # Go to "Script Type" + BUTTON_ENTER, # Enter "Script Type" + BUTTON_PAGE_PREV, # Move to Taproot + BUTTON_ENTER, # Confirm Taproot + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE_1, Wallet(tdata.SINGLESIG_12_WORD_KEY)) + mnemonic = ctx.wallet.key.mnemonic + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + + assert ctx.wallet.key.script_type == "p2tr" + + # Change back to legacy + BTN_SEQUENCE_2 = [ + *([BUTTON_PAGE] * 2), # Go to "Script Type" + BUTTON_ENTER, # Enter "Script Type" + BUTTON_ENTER, # Confirm Legacy + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + ctx = create_ctx(mocker, BTN_SEQUENCE_2, ctx.wallet) + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + assert ctx.wallet.key.script_type == "p2pkh" + + +def test_change_account(m5stickv, mocker, tdata): + from krux.pages.wallet_settings import WalletSettings + from krux.wallet import Wallet + from krux.key import Key + from krux.pages import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV + + BTN_SEQUENCE_1 = [ + *([BUTTON_PAGE] * 3), # Go to "Account" + BUTTON_ENTER, # Enter "Account" + BUTTON_PAGE, # Move to number 1 + BUTTON_ENTER, # Confirm number 1 + *([BUTTON_PAGE_PREV] * 2), # Move to "Go" + BUTTON_ENTER, # Go + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE_1, Wallet(tdata.SINGLESIG_12_WORD_KEY)) + mnemonic = ctx.wallet.key.mnemonic + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + + assert ctx.wallet.key.account_index == 1 + + # Change back to account 0 + BTN_SEQUENCE_2 = [ + *([BUTTON_PAGE] * 3), # Go to "Account" + BUTTON_ENTER, # Enter "Account" + *([BUTTON_PAGE_PREV] * 3), # Move to del number + BUTTON_ENTER, # Confirm del number + *([BUTTON_PAGE] * 3), # Move to "0" + BUTTON_ENTER, # Enter 0 + BUTTON_PAGE_PREV, # Move to "Go" + BUTTON_ENTER, # Go + BUTTON_PAGE_PREV, # Move to Back + BUTTON_ENTER, # Leave + ] + ctx = create_ctx(mocker, BTN_SEQUENCE_2, ctx.wallet) + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + assert ctx.wallet.key.account_index == 0 + + +def test_change_account_esc(m5stickv, mocker, tdata): + from krux.pages.wallet_settings import WalletSettings + from krux.wallet import Wallet + from krux.key import Key + from krux.pages import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV + + BTN_SEQUENCE_1 = [ + *([BUTTON_PAGE] * 3), # Go to "Account" + BUTTON_ENTER, # Enter "Account" + *([BUTTON_PAGE_PREV] * 2), # Move to Esc + BUTTON_ENTER, # Press Esc + BUTTON_ENTER, # Confirm Esc + BUTTON_PAGE_PREV, # Move to Back + BUTTON_ENTER, # Leave + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE_1, Wallet(tdata.SINGLESIG_12_WORD_KEY)) + mnemonic = ctx.wallet.key.mnemonic + wallet_settings = WalletSettings(ctx) + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + assert ctx.wallet.key.account_index == 0 + + +def test_account_out_of_range(m5stickv, mocker, tdata): + from krux.pages.wallet_settings import WalletSettings + from krux.wallet import Wallet + from krux.key import Key + from krux.pages import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV + + BTN_SEQUENCE_1 = [ + *([BUTTON_PAGE] * 3), # Go to "Account" + BUTTON_ENTER, # Enter "Account" + BUTTON_PAGE, # Move to number 1 + *([BUTTON_ENTER] * 11), # Press number 1 11 times + *([BUTTON_PAGE_PREV] * 2), # Move to "Go" + BUTTON_ENTER, # Go + BUTTON_PAGE_PREV, # Go to Back + BUTTON_ENTER, # Leave + ] + + ctx = create_ctx(mocker, BTN_SEQUENCE_1, Wallet(tdata.SINGLESIG_12_WORD_KEY)) + mnemonic = ctx.wallet.key.mnemonic + wallet_settings = WalletSettings(ctx) + wallet_settings.flash_error = mocker.MagicMock() + network, multisig, script_type, account = wallet_settings.customize_wallet( + ctx.wallet.key + ) + ctx.wallet = Wallet( + Key( + mnemonic, + multisig, + network, + "", # passphrase + account, + script_type, + ) + ) + + wallet_settings.flash_error.assert_called_with( + "Value 11111111111 out of range: [0, 2147483647]" + ) + assert ctx.wallet.key.account_index == 0