def get_xpub(hw_session: HwSessionInfo, bip32_path): client = hw_session.hw_client if client: if isinstance(bip32_path, str): bip32_path.strip() if bip32_path.lower().find('m/') >= 0: bip32_path = bip32_path[2:] if hw_session.app_config.hw_type == HWType.trezor: from trezorlib import btc if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return btc.get_public_node(client, bip32_path).xpub elif hw_session.app_config.hw_type == HWType.keepkey: if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return client.get_public_node(bip32_path).xpub elif hw_session.app_config.hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano as ledger if isinstance(bip32_path, list): # ledger requires bip32 path argument as a string bip32_path = bip32_path_n_to_string(bip32_path) return ledger.get_xpub(client, bip32_path) else: raise Exception('Unknown hardware wallet type: ' + hw_session.app_config.hw_type) else: raise Exception('HW client not open.')
def on_lbl_hw_account_base_path_linkActivated(self, text): path, ok = QInputDialog.getText(self, 'Account base path query', 'Enter a new BIP32 base path:', text=self.hw_account_base_bip32_path) if ok: try: dash_utils.bip32_path_string_to_n(path) if self.hw_account_base_bip32_path != path: self.hw_account_base_bip32_path = path self.display_bip32_base_path() self.load_utxos() except Exception: self.errorMsg('Invalid BIP32 path')
def on_btn_src_bip32_path_clicked(self, checked): path, ok = QInputDialog.getText(self, 'BIP32 path query', 'Enter a new BIP32 path:', text=self.hw_src_bip32_path) if ok: try: dash_utils.bip32_path_string_to_n(path) if self.hw_src_bip32_path != path: self.hw_src_bip32_path = path self.hw_src_address = '' # will be retrieved in self.load_utxos self.edt_src_bip32_path.setText(self.hw_src_bip32_path) self.load_utxos() except Exception as e: self.errorMsg('Invalid BIP32 path')
def sign_message(hw_session: HwSessionInfo, bip32path, message): client = hw_session.hw_client address_n = dash_utils.bip32_path_string_to_n(bip32path) try: return btc.sign_message(client, hw_session.app_config.hw_coin_name, address_n, message) except exceptions.Cancelled: raise CancelException('Cancelled')
def get_session_info_trezor(get_public_node_fun, hw_session: HwSessionInfo, hw_client): nonlocal hw_type def call_get_public_node(ctrl, get_public_node_fun, path_n): pk = get_public_node_fun(path_n).node.public_key return pk path = dash_utils.get_default_bip32_base_path( hw_session.app_config.dash_network) path_n = dash_utils.bip32_path_string_to_n(path) # show message for Trezor T device while waiting for the user to choose the passphrase input method pub = WndUtils.run_thread_dialog(call_get_public_node, (get_public_node_fun, path_n), title=DEFAULT_HW_BUSY_TITLE, text=DEFAULT_HW_BUSY_MESSAGE, force_close_dlg_callback=partial( cancel_hw_thread_dialog, hw_client), show_window_delay_ms=1000) if pub: hw_session.set_base_info(path, pub) else: raise Exception('Couldn\'t read data from the hardware wallet.')
def set_bip32_path(self, path): Bip44Entry.set_bip32_path(self, path) if path: path_n = bip32_path_string_to_n(path) if path_n[-2] == 1: self.__is_change = True else: self.__is_change = False
def get_address_and_pubkey(hw_session: HwSessionInfo, bip32_path): client = hw_session.hw_client if client: if isinstance(bip32_path, str): bip32_path.strip() if bip32_path.lower().find('m/') >= 0: # removing m/ prefix because of keepkey library bip32_path = bip32_path[2:] if hw_session.app_config.hw_type == HWType.trezor: from trezorlib import btc if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return { 'address': btc.get_address(client, hw_session.app_config.hw_coin_name, bip32_path, False), 'publicKey': btc.get_public_node(client, bip32_path).node.public_key } elif hw_session.app_config.hw_type == HWType.keepkey: if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return { 'address': client.get_address(hw_session.app_config.hw_coin_name, bip32_path, False), 'publicKey': client.get_public_node(bip32_path).node.public_key } elif hw_session.app_config.hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano as ledger if isinstance(bip32_path, list): # ledger requires bip32 path argument as a string bip32_path = bip32_path_n_to_string(bip32_path) return ledger.get_address_and_pubkey(client, bip32_path) else: raise Exception('Unknown hardware wallet type: ' + hw_session.app_config.hw_type)
def _get_address(ctrl, hw_session: HwSessionInfo, bip32_path: str, show_display: bool = False, message_to_display: str = None): if ctrl: ctrl.dlg_config_fun(dlg_title="Please confirm", show_progress_bar=False) if message_to_display: ctrl.display_msg_fun(message_to_display) else: ctrl.display_msg_fun('<b>Click the confirmation button on your hardware wallet to exit...</b>') client = hw_session.hw_client if client: if isinstance(bip32_path, str): bip32_path.strip() if bip32_path.lower().find('m/') >= 0: # removing m/ prefix because of keepkey library bip32_path = bip32_path[2:] if hw_session.app_config.hw_type == HWType.trezor: from trezorlib import btc if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return btc.get_address(client, hw_session.app_config.hw_coin_name, bip32_path, show_display) elif hw_session.app_config.hw_type == HWType.keepkey: if isinstance(bip32_path, str): bip32_path = dash_utils.bip32_path_string_to_n(bip32_path) return client.get_address(hw_session.app_config.hw_coin_name, bip32_path, show_display) elif hw_session.app_config.hw_type == HWType.ledger_nano_s: import hw_intf_ledgernano as ledger if isinstance(bip32_path, list): # ledger requires bip32 path argument as a string bip32_path = bip32_path_n_to_string(bip32_path) adr_pubkey = ledger.get_address_and_pubkey(client, bip32_path) return adr_pubkey.get('address') else: raise Exception('Unknown hardware wallet type: ' + hw_session.app_config.hw_type) else: raise Exception('HW client not open.')
def sign_message(hw_client, hw_coin_name: str, bip32path: str, message: str): address_n = dash_utils.bip32_path_string_to_n(bip32path) try: return btc.sign_message(hw_client, hw_coin_name, address_n, message) except exceptions.Cancelled: raise CancelException('Cancelled') except exceptions.TrezorFailure as e: if e.failure.message == 'Device not initialized': raise HwNotInitialized(e.failure.message) else: raise
def get_session_info_trezor(get_public_node_fun, hw_session: HwSessionInfo): nonlocal hw_type def call_get_public_node(ctrl, get_public_node_fun, path_n): pk = get_public_node_fun(path_n).node.public_key return pk path = dash_utils.get_default_bip32_base_path(hw_session.app_config.dash_network) path_n = dash_utils.bip32_path_string_to_n(path) # show message for Trezor T device while waiting for the user to choose the passphrase input method pub = WndUtils.run_thread_dialog(call_get_public_node, (get_public_node_fun, path_n), title='Confirm', text='<b>Complete the action on your hardware wallet device</b>', show_window_delay_ms=1000) hw_session.set_base_info(path, pub)
def get_child_entry(self, index) -> 'Bip44Entry': child = self.child_entries.get(index) if not child: key = self.get_bip32key() child_key = key.ChildKey(index) child_xpub = child_key.ExtendedKey(False, True) if self.bip32_path: bip32_path_n = bip32_path_string_to_n(self.bip32_path) bip32_path_n.append(index) bip32_path = bip32_path_n_to_string(bip32_path_n) else: raise Exception('Unknown BIP32 path of the parrent') child = Bip44Entry(tree_id=self.tree_id, id=None, parent=self, xpub=child_xpub, address_index=index, bip32_path=bip32_path, bip32_key=child_key) self.child_entries[index] = child return child
def refresh_adresses_preview(self): if self.mnemonic: bip32_path = self.edtHwOptionsBip32Path.text() passphrase = self.edtHwOptionsPassphrase.text() passphrase = self.mnemonic.normalize_string(passphrase) mnem_str = ' '.join(self.get_cur_mnemonic_words()) bip32_seed = self.mnemonic.to_seed(mnem_str, passphrase) bip32_master_key = bitcoin.bip32_master_key(bip32_seed) bip32_path_n = bip32_path_string_to_n(bip32_path) if len(bip32_path_n) > 0: last_idx = bip32_path_n[-1] addresses = [] for idx in range(10): bip32_path_n[-1] = last_idx + idx pk = self.get_bip32_private_key(bip32_path_n, bip32_master_key) pubkey = bitcoin.privkey_to_pubkey(pk) addr = pubkey_to_address(pubkey) path_str = bip32_path_n_to_string(bip32_path_n) addresses.append((path_str, addr)) self.address_preview_model.apply_addresses(addresses) self.address_preview_model.refresh_view() self.viewAddresses.resizeColumnsToContents()
def get_addresses_to_scan(self, thread_ctrl: CtrlObject, addr_scan_ctrl: dict): """ :param self: :param addr_scan_ctrl: (only for self.utxo_src_mode == 2) penultimate element of bip32 path to scan, used to switch sanning between normal and change addresses :return: yield List[Tuple[str (address), str (bip32 path)]] """ try: if self.utxo_src_mode == 1: if self.mn_src_index is not None: if self.mn_src_index == len(self.masternode_addresses): # show addresses of all masternodes for chunk_nr in range(int(math.ceil(len(self.masternode_addresses) / ADDRESS_CHUNK))): if self.finishing or thread_ctrl.finish: return yield [x for x in self.masternode_addresses[ chunk_nr * ADDRESS_CHUNK : (chunk_nr + 1) * ADDRESS_CHUNK] if x[0] and x[1]] elif self.mn_src_index < len(self.masternode_addresses) and self.mn_src_index >= 0: if self.finishing or thread_ctrl.finish: return if self.masternode_addresses[self.mn_src_index][0] and \ self.masternode_addresses[self.mn_src_index][1]: yield [self.masternode_addresses[self.mn_src_index]] elif self.utxo_src_mode == 2: # hw wallet account: scan all addresses and change addresses for a specific account # stop when a defined number of subsequent address has balance 0 addr_count = 0 addr_n = dash_utils.bip32_path_string_to_n(self.hw_account_base_bip32_path) db_cur = self.db_intf.get_cursor() try: bip32_path_n = addr_n[:] + [self.hw_account_number + 0x80000000, 0, 0] cur_addr_buf = [] last_level2_nr = addr_scan_ctrl.get('level2') while True: restart_iteration = False for nr in range(1000): if self.finishing or thread_ctrl.finish: return if last_level2_nr != addr_scan_ctrl.get('level2'): last_level2_nr = addr_scan_ctrl.get('level2') restart_iteration = True break bip32_path_n[-2] = addr_scan_ctrl.get('level2') bip32_path_n[-1] = nr cur_addr = hw_intf.get_address_ext(self.main_ui.hw_session, bip32_path_n, db_cur, self.app_config.hw_encrypt_string, self.app_config.hw_decrypt_string) bip32_path = dash_utils.bip32_path_n_to_string(bip32_path_n) cur_addr_buf.append((cur_addr, bip32_path)) addr_count += 1 if len(cur_addr_buf) >= ADDRESS_CHUNK: yield cur_addr_buf cur_addr_buf.clear() if restart_iteration: continue if cur_addr_buf: yield cur_addr_buf break finally: if db_cur.connection.total_changes > 0: self.db_intf.commit() self.db_intf.release_cursor() elif self.utxo_src_mode == 3: db_cur = self.db_intf.get_cursor() try: # address from a specific bip32 path bip32_path_n = dash_utils.bip32_path_string_to_n(self.hw_src_bip32_path) cur_addr = hw_intf.get_address_ext(self.main_ui.hw_session, bip32_path_n, db_cur, self.app_config.hw_encrypt_string, self.app_config.hw_decrypt_string) self.hw_src_address = cur_addr yield [(cur_addr, self.hw_src_bip32_path)] finally: if db_cur.connection.total_changes > 0: self.db_intf.commit() self.db_intf.release_cursor() except Exception as e: logging.exception('Exception occurred') raise
def get_session_info_trezor(cli, hw_session: HwSessionInfo): path = dash_utils.get_default_bip32_base_path( hw_session.app_config.dash_network) path_n = dash_utils.bip32_path_string_to_n(path) pub = cli.get_public_node(path_n).node.public_key hw_session.set_base_info(path, pub)
def sign_tx(hw_session: HWSessionBase, rt_data: AppRuntimeData, utxos_to_spend: List[wallet_common.UtxoType], tx_outputs: List[wallet_common.TxOutputType], tx_fee): """ Creates a signed transaction. :param hw_session: :param utxos_to_spend: list of utxos to send :param tx_outputs: list of transaction outputs :param tx_fee: transaction fee :return: tuple (serialized tx, total transaction amount in satoshis) """ def load_prev_txes(tx_api_, skip_cache_: bool = False): txes_ = {} tx_api_.skip_cache = skip_cache_ for utxo_ in utxos_to_spend: prev_hash_bin = bytes.fromhex(utxo_.txid) if prev_hash_bin not in txes_: tx = tx_api_.get_tx(utxo_.txid) txes_[prev_hash_bin] = tx return txes_ insight_network = 'insight_dash' if rt_data.is_testnet: insight_network += '_testnet' dash_network = rt_data.dash_network tx_api = MyTxApiInsight(rt_data.dashd_intf, rt_data.tx_cache_dir) client = hw_session.hw_client inputs = [] outputs = [] inputs_amount = 0 for utxo_index, utxo in enumerate(utxos_to_spend): if not utxo.bip32_path: raise Exception('No BIP32 path for UTXO ' + utxo.txid) address_n = dash_utils.bip32_path_string_to_n(utxo.bip32_path) it = trezor_proto.TxInputType(address_n=address_n, amount=utxo.satoshis, prev_hash=binascii.unhexlify(utxo.txid), prev_index=int(utxo.output_index)) inputs.append(it) inputs_amount += utxo.satoshis outputs_amount = 0 for out in tx_outputs: outputs_amount += out.satoshis if out.address[0] in dash_utils.get_chain_params( dash_network).B58_PREFIXES_SCRIPT_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOSCRIPTHASH logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype)) elif out.address[0] in dash_utils.get_chain_params( dash_network).B58_PREFIXES_PUBKEY_ADDRESS: stype = trezor_proto.OutputScriptType.PAYTOADDRESS logging.debug('Transaction type: PAYTOADDRESS ' + str(stype)) else: raise Exception('Invalid prefix of the destination address.') if out.bip32_path: address_n = dash_utils.bip32_path_string_to_n(out.bip32_path) else: address_n = None ot = trezor_proto.TxOutputType( address=out.address if address_n is None else None, address_n=address_n, amount=out.satoshis, script_type=stype) outputs.append(ot) if outputs_amount + tx_fee != inputs_amount: raise Exception( 'Transaction validation failure: inputs + fee != outputs') try: for skip_cache in (False, True): txes = load_prev_txes(tx_api, skip_cache) try: signed = btc.sign_tx(client, rt_data.hw_coin_name, inputs, outputs, prev_txes=txes) return signed[1], inputs_amount except exceptions.Cancelled: raise except Exception: if skip_cache: raise log.exception( 'Exception occurred while signing transaction. Turning off the transaction cache ' 'and retrying...') raise Exception('Internal error: transaction not signed') except exceptions.Cancelled: raise CancelException('Cancelled') except exceptions.TrezorFailure as e: if e.failure.message == 'Device not initialized': raise HwNotInitialized(e.failure.message) else: raise