async def menu(self, show_screen): buttons = [ (None, "Dice Roller"), (DICE_ROLL_DEFAULT, "Roll default (d6) dice"), (DICE_ROLL_D3, "Roll d3 dice"), (DICE_ROLL_D4, "Roll d4 dice"), (DICE_ROLL_D6, "Roll d6 dice"), (DICE_ROLL_D8, "Roll d8 dice"), (DICE_ROLL_D10, "Roll d10 dice"), (DICE_ROLL_D12, "Roll d12 dice"), (DICE_ROLL_D20, "Roll d20 dice"), ] menuitem = await show_screen( Menu(buttons, title="Which dice do you want to roll?", last=(255, None))) while menuitem != 255: if menuitem in [ DICE_ROLL_DEFAULT, DICE_ROLL_D3, DICE_ROLL_D4, DICE_ROLL_D6, DICE_ROLL_D8, DICE_ROLL_D10, DICE_ROLL_D12, DICE_ROLL_D20, DICE_ROLL_D100 ]: roll = True while roll: scr = DiceRollScreen( title="Rolled dice ", note="Choosen dice: d%s" % menuitem, message="%s" % roll_dice(menuitem), ) roll = await show_screen(scr) menuitem = await show_screen(Menu(buttons, last=(255, None)))
async def storage_menu(self): """Manage storage""" buttons = [ # id, text (None, "Key management"), (0, "Save key to flash"), (1, "Load key from flash"), (2, "Delete key from flash"), ] # we stay in this menu until back is pressed while True: # wait for menu selection menuitem = await self.show(Menu(buttons, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: await self.save_mnemonic() await self.show( Alert("Success!", "Your key is stored in flash now.", button_text="OK")) elif menuitem == 1: await self.load_mnemonic() await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: await self.delete_mnemonic() await self.show( Alert("Success!", "Your key is deleted from flash.", button_text="OK"))
async def menu(self, show_screen): buttons = [(None, "Your wallets")] buttons += [(w, w.name) for w in self.wallets if not w.is_watchonly] if len(buttons) != (len(self.wallets) + 1): buttons += [(None, "Watch only wallets")] buttons += [(w, w.name) for w in self.wallets if w.is_watchonly] menuitem = await show_screen(Menu(buttons, last=(255, None))) if menuitem == 255: # we are done return False else: w = menuitem # pass wallet and network self.show_loader(title="Loading wallet...") cmd = await w.show(self.network, show_screen) if cmd == DELETE: scr = Prompt( "Delete wallet?", 'You are deleting wallet "%s".\n' "Are you sure you want to do it?" % w.name, ) conf = await show_screen(scr) if conf: self.delete_wallet(w) elif cmd == EDIT: scr = InputScreen(title="Enter new wallet name", note="", suggestion=w.name) name = await show_screen(scr) if name is not None and name != w.name and name != "": w.name = name w.save(self.keystore) return True
async def menu(self, show_screen): buttons = [(None, "Your wallets")] buttons += [(w, w.name) for w in self.wallets] menuitem = await show_screen(Menu(buttons, last=(255, None))) if menuitem == 255: # we are done return False else: w = menuitem # pass wallet and network scr = WalletScreen(w, self.network, idx=w.unused_recv) cmd = await show_screen(scr) if cmd == DELETE: scr = Prompt( "Delete wallet?", "You are deleting wallet \"%s\".\n" "Are you sure you want to do it?" % w.name) conf = await show_screen(scr) if conf: self.delete_wallet(w) elif cmd == EDIT: scr = InputScreen(title="Enter new wallet name", note="", suggestion=w.name) name = await show_screen(scr) if name is not None and name != w.name and name != "": w.name = name w.save(self.keystore) return True
async def show(self, network, show_screen): while True: scr = WalletScreen(self, network, idx=self.unused_recv) cmd = await show_screen(scr) if cmd == MENU: buttons = [ (INFO, "Show detailed information"), (EDIT, lv.SYMBOL.EDIT + " Change the name"), # value, label, enabled, color (DELETE, lv.SYMBOL.TRASH + " Delete wallet", True, 0x951E2D ), ] cmd = await show_screen( Menu(buttons, last=(255, None), title=self.name, note="What do you want to do?")) if cmd == 255: continue elif cmd == INFO: keys = self.get_key_dicts(network) for k in keys: k["mine"] = True if self.keystore and self.keystore.owns( k["key"]) else False await show_screen( WalletInfoScreen(self.name, self.full_policy, keys, self.is_miniscript)) continue # other commands go to the wallet manager return cmd
async def storage_menu(self): """Manage storage""" enabled = self.connection.isCardInserted() buttons = [ # id, text (None, "Smartcard storage"), (0, "Save key to the card", enabled), (1, "Load key from the card", enabled), (2, "Delete key from the card", enabled), (3, "Use a different card", enabled) ] # we stay in this menu until back is pressed while True: note = "Card fingerprint: %s" % self.hexid # wait for menu selection menuitem = await self.show( Menu(buttons, note=note, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: await self.save_mnemonic() await self.show( Alert( "Success!", "Your key is stored on the smartcard now.", button_text="OK", )) elif menuitem == 1: await self.load_mnemonic() await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: await self.delete_mnemonic() await self.show( Alert( "Success!", "Your key is deleted from the smartcard.", button_text="OK", )) elif menuitem == 3: if await self.show( Prompt( "Switching the smartcard", "To use a different smartcard you need " "to provide a PIN for current one first!\n\n" "Continue?")): self.lock() await self.unlock() self.lock() self.applet.close_secure_channel() await self.show( Alert("Please swap the card", "Now you can insert another card and set it up.", button_text="Continue")) await self.check_card(check_pin=True) await self.unlock()
async def menu(self, show_screen): buttons = [ (None, "Dice Rolls (D6)"), (FLUSH_ROLLS, "Create new seed"), (ADD_ROLL, "Continue current seed"), ] menuitem = await show_screen(Menu(buttons, title="Seed creation by rolling dice", last=(255, None))) while menuitem != 255: if menuitem in PIPS or menuitem in [FLUSH_ROLLS, ADD_ROLL]: if menuitem == FLUSH_ROLLS: self.rolls = [] elif menuitem == ADD_ROLL: pass # continue mix into current seed roll = True while roll: if menuitem in PIPS: self.rolls.append(str(menuitem)) warn_message, words, word_ids, hash = rolls(''.join(self.rolls) ) ans_hash = hexlify(hash).decode('utf-8') middle = int(len(ans_hash)/2) hash1 = ans_hash[:middle] hash2 = ans_hash[middle:] if ans_hash == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855": warn_message = "WARNING: Input is empty. This is a known wallet!" # overwrite low entropy warn message if warn_message: message = "%s\n%s" % (warn_message, words) else: message = words scr = DiceRollsScreen( title="Press 1-6 for each roll to mix in.", note="%s rolls: %s\n-\n%s\n%s" % (len(self.rolls), ''.join(self.rolls), hash1, hash2 ), message ="%s" % (message), ) menuitem = await show_screen(scr) if menuitem == USE_SEED: print("TODO: USE SEED!") roll = False elif menuitem == ADD_ROLL: roll = False elif menuitem == BACK: roll = False menuitem = await show_screen(Menu(buttons, title="Seed creation by rolling dice", last=(255, None)))
async def create_wallet(self, derivation, xpub, prefix, version, show_screen): """Shows a wallet creation menu and passes descriptor to the wallets app""" net = NETWORKS[self.network] descriptors = OrderedDict({ "zpub": ("wpkh(%s%s/{0,1}/*)" % (prefix, xpub), "Native Segwit"), "ypub": ("sh(wpkh(%s%s/{0,1}/*))" % (prefix, xpub), "Nested Segwit"), "legacy": ("pkh(%s%s/{0,1}/*)" % (prefix, xpub), "Legacy"), # multisig is not supported yet - requires cosigners app }) if version == net["ypub"]: buttons = [ (None, "Recommended"), descriptors.pop("ypub"), (None, "Other"), ] elif version == net["zpub"]: buttons = [ (None, "Recommended"), descriptors.pop("zpub"), (None, "Other"), ] else: buttons = [] buttons += [descriptors[k] for k in descriptors] menuitem = await show_screen(Menu(buttons, last=(255, None), title="Select wallet type to create")) if menuitem == 255: return else: # get wallet names from the wallets app s, _ = await self.communicate(BytesIO(b"listwallets"), app="wallets") names = json.load(s) if menuitem.startswith("pkh("): name_suggestion = "Legacy %d" % self.account elif menuitem.startswith("wpkh("): name_suggestion = "Native %d" % self.account elif menuitem.startswith("sh(wpkh("): name_suggestion = "Nested %d" % self.account else: name_suggestion = "Wallet %d" % self.account nn = name_suggestion i = 1 # make sure we don't suggest existing name while name_suggestion in names: name_suggestion = "%s (%d)" % (nn, i) i += 1 name = await show_screen(InputScreen(title="Name your wallet", note="", suggestion=name_suggestion, min_length=1, strip=True )) if not name: return # send the wallets app addwallet command with descriptor data = "addwallet %s&%s" % (name, menuitem) stream = BytesIO(data.encode()) await self.communicate(stream, app="wallets")
async def save_menu(self, show_screen): buttons = [(0, "Specter-DIY (plaintext)"), (1, "Cold Card (json)")] # wait for menu selection menuitem = await show_screen(Menu(buttons, last=(255, None), title="Select a format")) # process the menu button: # back button if menuitem == 255: return None elif menuitem == 0: return self.export_specter_diy elif menuitem == 1: return self.export_coldcard return None
async def select_file(self): buttons = [] buttons += [(None, 'Internal storage')] buttons += self.load_files(self.flashpath) buttons += [(None, 'SD card')] if platform.is_sd_present(): platform.mount_sdcard() buttons += self.load_files(self.sdpath) platform.unmount_sdcard() else: buttons += [(None, 'No SD card present')] return await self.show( Menu(buttons, title="Select a file", last=(None, "Cancel")))
async def menu(self, show_screen, show_all=False): net = NETWORKS[self.network] buttons = [ (None, "Recommended"), ("m/84h/%dh/0h" % net["bip32"], "Single key"), ("m/48h/%dh/0h/2h" % net["bip32"], "Multisig"), (None, "Other keys"), ] if show_all: coin = net["bip32"] buttons += [ ("m/84h/%dh/0h" % coin, "Single Native Segwit\nm/84h/%dh/0h" % coin), ("m/49h/%dh/0h" % coin, "Single Nested Segwit\nm/49h/%dh/0h" % coin), ( "m/48h/%dh/0h/2h" % coin, "Multisig Native Segwit\nm/48h/%dh/0h/2h" % coin, ), ( "m/48h/%dh/0h/1h" % coin, "Multisig Nested Segwit\nm/48h/%dh/0h/1h" % coin, ), ] else: buttons += [(0, "Show more keys"), (1, "Enter custom derivation")] # wait for menu selection menuitem = await show_screen(Menu(buttons, last=(255, None))) # process the menu button: # back button if menuitem == 255: return False elif menuitem == 0: return await self.menu(show_screen, show_all=True) elif menuitem == 1: der = await show_screen(DerivationScreen()) if der is not None: await self.show_xpub(der, show_screen) return True else: await self.show_xpub(menuitem, show_screen) return True return False
async def storage_menu(self): """Manage storage""" buttons = [ # id, text (None, "Manage keys on SD card and internal flash"), (0, "Save key"), (1, "Load key"), (2, "Delete key"), ] # disabled if SD card is not present buttons.append( (3, "Export recovery phrase to SD", platform.is_sd_present())) # we stay in this menu until back is pressed while True: # wait for menu selection menuitem = await self.show(Menu(buttons, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: filename = await self.save_mnemonic() if filename: await self.show( Alert("Success!", "Your key is stored now.\n\nName: %s" % filename, button_text="OK")) elif menuitem == 1: if await self.load_mnemonic(): await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: if await self.delete_mnemonic(): await self.show( Alert("Success!", "Your key is deleted.", button_text="OK")) elif menuitem == 3: await self.export_mnemonic()
async def export_menu(self, show_screen): while True: buttons = [ (None, "Export options"), (1, "Show QR code"), (2, "Save to SD card", platform.is_sd_present()), ] menuitem = await show_screen( Menu(buttons, last=(255, None), title="Export wallet %s" % self.name)) desc = add_checksum(str(self.descriptor.branch(0))) obj = { "descriptor": desc, "label": self.name, } if self.descriptor.num_branches > 2: obj["branches"] = [ add_checksum(str(self.descriptor.branch(i))) for i in range(self.descriptor.num_branches) ] if menuitem == 1: await show_screen( QRAlert( title="Export wallet %s" % self.name, qr_width=450, message= "Scan this QR code with compatible software wallet", qr_message=json.dumps(obj))) elif menuitem == 2: if not platform.is_sd_present(): raise WalletError("SD card is not present") platform.mount_sdcard() fname = "/sd/%s.json" % self.name with open(platform.fpath(fname), "w") as f: json.dump(obj, f) platform.unmount_sdcard() await show_screen( Alert("Success!", "Wallet descriptor is written to\n\n%s" % fname)) else: return
async def storage_menu(self): """Manage storage and display of the recovery phrase""" enabled = self.connection.isCardInserted() buttons = [ # id, text (None, "Smartcard storage"), (0, "Save key to the card", enabled), (1, "Load key from the card", enabled), (2, "Delete key from the card", enabled), (3, "Show recovery phrase"), ] # we stay in this menu until back is pressed while True: # wait for menu selection menuitem = await self.show(Menu(buttons, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: await self.save_mnemonic() await self.show( Alert( "Success!", "Your key is stored on the smartcard now.", button_text="OK", )) elif menuitem == 1: await self.load_mnemonic() await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: await self.delete_mnemonic() await self.show( Alert( "Success!", "Your key is deleted from the smartcard.", button_text="OK", )) elif menuitem == 3: await self.show(MnemonicScreen(self.mnemonic))
async def get_keypath(self, title="Select media", only_if_exist=True, **kwargs): # enable / disable buttons enable_flash = (not only_if_exist) or platform.file_exists( self.flashpath) enable_sd = False if platform.is_sd_present(): platform.mount_sdcard() enable_sd = (not only_if_exist) or platform.file_exists( self.sdpath) platform.unmount_sdcard() buttons = [ (None, "Make your choice"), (self.flashpath, "Internal flash", enable_flash), (self.sdpath, "SD card", enable_sd), ] scr = Menu(buttons, title=title, last=(None, ), **kwargs) res = await self.show(scr) return res
async def storage_menu(self): """Manage storage and display of the recovery phrase""" buttons = [ # id, text (None, "Manage keys on SD card and internal flash"), (0, "Save key"), (1, "Load key"), (2, "Delete key"), (None, "Other"), (3, "Show recovery phrase"), ] # we stay in this menu until back is pressed while True: # wait for menu selection menuitem = await self.show(Menu(buttons, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: if await self.save_mnemonic(): await self.show( Alert("Success!", "Your key is stored now.", button_text="OK")) elif menuitem == 1: if await self.load_mnemonic(): await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: if await self.delete_mnemonic(): await self.show( Alert("Success!", "Your key is deleted.", button_text="OK")) elif menuitem == 3: await self.show_mnemonic()
async def menu(self, show_screen, show_all=False): net = NETWORKS[self.network] coin = net["bip32"] if not show_all: buttons = [ (None, "Recommended"), ("m/84h/%dh/%dh" % (coin, self.account), "Single key"), ("m/48h/%dh/%dh/2h" % (coin, self.account), "Multisig"), (None, "Other keys"), (0, "Show more keys"), (2, "Change account number"), (1, "Enter custom derivation"), (3, "Export all keys to SD"), ] else: buttons = [ (None, "Recommended"), ( "m/84h/%dh/%dh" % (coin, self.account), "Single Native Segwit\nm/84h/%dh/%dh" % (coin, self.account) ), ( "m/48h/%dh/%dh/2h" % (coin, self.account), "Multisig Native Segwit\nm/48h/%dh/%dh/2h" % (coin, self.account), ), (None, "Other keys"), ] if self.is_taproot_enabled: buttons.append(( "m/86h/%dh/%dh" % (coin, self.account), "Single Taproot\nm/86h/%dh/%dh" % (coin, self.account) )) buttons.extend([ ( "m/49h/%dh/%dh" % (coin, self.account), "Single Nested Segwit\nm/49h/%dh/%dh" % (coin, self.account) ), ( "m/48h/%dh/%dh/1h" % (coin, self.account), "Multisig Nested Segwit\nm/48h/%dh/%dh/1h" % (coin, self.account), ), ]) # wait for menu selection menuitem = await show_screen(Menu(buttons, last=(255, None), title="Select the key", note="Current account number: %d" % self.account)) # process the menu button: # back button if menuitem == 255: return False elif menuitem == 0: return await self.menu(show_screen, show_all=True) elif menuitem == 1: der = await show_screen(DerivationScreen()) if der is not None: await self.show_xpub(der, show_screen) return True elif menuitem == 3: file_format = await self.save_menu(show_screen) if file_format: filename = self.save_all_to_sd(file_format) await show_screen( Alert("Saved!", "Public keys are saved to the file:\n\n%s" % filename, button_text="Close") ) elif menuitem == 2: account = await show_screen(NumericScreen(current_val=str(self.account))) if account and int(account) > 0x80000000: raise AppError('Account number too large') try: self.account = int(account) except: self.account = 0 return await self.menu(show_screen) else: await self.show_xpub(menuitem, show_screen) return True return False
async def storage_menu(self): """Manage storage""" enabled = self.connection.isCardInserted() buttons = [ # id, text, enabled, color (None, "Smartcard storage"), (0, "Save key to the card", enabled), (1, "Load key from the card", enabled and self.is_key_saved), (2, "Delete key from the card", enabled and self.is_key_saved), (3, "Use a different card", enabled), (4, lv.SYMBOL.SETTINGS + " Get card info", enabled), # (5, lv.SYMBOL.TRASH + " Wipe the card", enabled, 0x951E2D), ] # we stay in this menu until back is pressed while True: # check updated status buttons[2] = (1, "Load key from the card", enabled and self.is_key_saved) buttons[3] = (2, "Delete key from the card", enabled and self.is_key_saved) note = "Card fingerprint: %s" % self.hexid # wait for menu selection menuitem = await self.show( Menu(buttons, note=note, last=(255, None))) # process the menu button: # back button if menuitem == 255: return elif menuitem == 0: await self.save_mnemonic() await self.show( Alert( "Success!", "Your key is stored on the smartcard now.", button_text="OK", )) elif menuitem == 1: await self.load_mnemonic() await self.show( Alert("Success!", "Your key is loaded.", button_text="OK")) elif menuitem == 2: if await self.show( Prompt("Are you sure?", "\n\nDelete the key from the card?")): await self.delete_mnemonic() await self.show( Alert( "Success!", "Your key is deleted from the smartcard.", button_text="OK", )) elif menuitem == 3: if await self.show( Prompt( "Switching the smartcard", "To use a different smartcard you need " "to provide a PIN for current one first!\n\n" "Continue?")): self.lock() await self.unlock() self.lock() self.applet.close_secure_channel() self._userkey = None await self.show( Alert("Please swap the card", "Now you can insert another card and set it up.", button_text="Continue")) await self.check_card(check_pin=True) await self.unlock() elif menuitem == 4: await self.show_card_info() else: raise KeyStoreError("Invalid menu")
async def menu(self, show_screen, show_all=False): net = NETWORKS[self.network] coin = net["bip32"] buttons = [ (None, "Recommended"), ("m/84h/%dh/%dh" % (coin, self.account), "Single key"), ("m/48h/%dh/%dh/2h" % (coin, self.account), "Multisig"), (None, "Other keys"), ] if show_all: buttons += [ ("m/84h/%dh/%dh" % (coin, self.account), "Single Native Segwit\nm/84h/%dh/%dh" % (coin, self.account)), ("m/49h/%dh/%dh" % (coin, self.account), "Single Nested Segwit\nm/49h/%dh/%dh" % (coin, self.account)), ( "m/48h/%dh/%dh/2h" % (coin, self.account), "Multisig Native Segwit\nm/48h/%dh/%dh/2h" % (coin, self.account), ), ( "m/48h/%dh/%dh/1h" % (coin, self.account), "Multisig Nested Segwit\nm/48h/%dh/%dh/1h" % (coin, self.account), ), ] else: buttons += [(0, "Show more keys"), (2, "Change account number"), (1, "Enter custom derivation")] # wait for menu selection menuitem = await show_screen( Menu(buttons, last=(255, None), title="Select the key", note="Current account number: %d" % self.account)) # process the menu button: # back button if menuitem == 255: return False elif menuitem == 0: return await self.menu(show_screen, show_all=True) elif menuitem == 1: der = await show_screen(DerivationScreen()) if der is not None: await self.show_xpub(der, show_screen) return True elif menuitem == 2: account = await show_screen( NumericScreen(current_val=str(self.account))) if account and int(account) > 0x80000000: raise AppError('Account number too large') try: self.account = int(account) except: self.account = 0 return await self.menu(show_screen) else: await self.show_xpub(menuitem, show_screen) return True return False