def get_client(self, noPin=False): if not BTCHIP: self.give_error('please install github.com/btchip/btchip-python') aborted = False if not self.client or self.client.bad: try: d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) ver = self.client.getFirmwareVersion() firmware = ver['version'].split(".") self.canAlternateCoinVersions = ( ver['specialVersion'] >= 0x20 and map(int, firmware) >= [1, 0, 1]) if not checkFirmware(firmware): d.close() try: updateFirmware() except Exception, e: aborted = True raise e d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) try: self.client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = self.client.getVerifyPinRemainingAttempts( ) if remaining_attempts <> 1: msg = "Enter your BTChip PIN - remaining attempts : " + str( remaining_attempts) else: msg = "Enter your BTChip PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: aborted = True raise Exception( 'Aborted by user - please unplug the dongle and plug it again before retrying' ) pin = pin.encode() self.client.verifyPin(pin) if self.canAlternateCoinVersions: self.client.setAlternateCoinVersions(48, 5)
def get_client(self, noPin=False): if not BTCHIP: give_error('please install github.com/btchip/btchip-python') aborted = False if not self.client or self.client.bad: try: d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) firmware = self.client.getFirmwareVersion()['version'].split(".") if int(firmware[0]) <> 1 or int(firmware[1]) <> 4: aborted = True raise Exception("Unsupported firmware version") if int(firmware[2]) < 9: aborted = True raise Exception("Please update your firmware - 1.4.9 or higher is necessary") try: self.client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = self.client.getVerifyPinRemainingAttempts() if remaining_attempts <> 1: msg = "Enter your BTChip PIN - remaining attempts : " + str(remaining_attempts) else: msg = "Enter your BTChip PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: aborted = True raise Exception('Aborted by user - please unplug the dongle and plug it again before retrying') pin = pin.encode() self.client.verifyPin(pin) except BTChipException, e: try: self.client.dongle.close() except: pass self.client = None if (e.sw == 0x6faa): raise Exception("Dongle is temporarily locked - please unplug it and replug it again") if ((e.sw & 0xFFF0) == 0x63c0): raise Exception("Invalid PIN - please unplug the dongle and plug it again before retrying") raise e
def get_client(self, noPin=False): if not BTCHIP: self.give_error('please install github.com/btchip/btchip-python') aborted = False if not self.client or self.client.bad: try: d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) ver = self.client.getFirmwareVersion() firmware = ver['version'].split(".") self.canAlternateCoinVersions = (ver['specialVersion'] >= 0x20 and map(int, firmware) >= [1, 0, 1]) if not checkFirmware(firmware): d.close() try: updateFirmware() except Exception, e: aborted = True raise e d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) try: self.client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = self.client.getVerifyPinRemainingAttempts() if remaining_attempts <> 1: msg = "Enter your BTChip PIN - remaining attempts : " + str(remaining_attempts) else: msg = "Enter your BTChip PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: aborted = True raise Exception('Aborted by user - please unplug the dongle and plug it again before retrying') pin = pin.encode() self.client.verifyPin(pin) if self.canAlternateCoinVersions: self.client.setAlternateCoinVersions(48, 5)
def get_client(self, wallet, force_pair=True, noPin=False): aborted = False client = self.client if not client or client.bad: try: d = getDongle(BTCHIP_DEBUG) client = btchip(d) ver = client.getFirmwareVersion() firmware = ver['version'].split(".") wallet.canAlternateCoinVersions = ( ver['specialVersion'] >= 0x20 and map(int, firmware) >= [1, 0, 1]) if not checkFirmware(firmware): d.close() try: updateFirmware() except Exception, e: aborted = True raise e d = getDongle(BTCHIP_DEBUG) client = btchip(d) try: client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = client.getVerifyPinRemainingAttempts() if remaining_attempts <> 1: msg = "Enter your Ledger PIN - remaining attempts : " + str( remaining_attempts) else: msg = "Enter your Ledger PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = wallet.password_dialog(msg) if not confirmed: aborted = True raise Exception( 'Aborted by user - please unplug the dongle and plug it again before retrying' ) pin = pin.encode() client.verifyPin(pin) if wallet.canAlternateCoinVersions: client.setAlternateCoinVersions( PUBKEY_ADDR, SCRIPT_ADDR)
def __init__(self, hidDevice, *, product_key: Tuple[int, int], plugin: HW_PluginBase): HardwareClientBase.__init__(self, plugin=plugin) self.dongleObject = btchip(hidDevice) self.preflightDone = False self._product_key = product_key self._soft_device_id = None
def get_client(self, noPin=False): if not BTCHIP: self.give_error("please install github.com/btchip/btchip-python") aborted = False if not self.client or self.client.bad: try: d = getDongle(BTCHIP_DEBUG) self.client = btchip(d) self.client.handler = self.plugin.handler firmware = self.client.getFirmwareVersion()["version"].split(".") if not checkFirmware(firmware): d.close() try: updateFirmware() except Exception, e: aborted = True raise e d = getDongle(BTCHIP_DEBUG) self.client = btchip(d) try: self.client.getOperationMode() except BTChipException, e: if e.sw == 0x6985: d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) self.client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = self.client.getVerifyPinRemainingAttempts() if remaining_attempts <> 1: msg = "Enter your BTChip PIN - remaining attempts : " + str(remaining_attempts) else: msg = "Enter your BTChip PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: aborted = True raise Exception("Aborted by user - please unplug the dongle and plug it again before retrying") pin = pin.encode() self.client.verifyPin(pin)
def get_client(self, wallet, noPin=False): aborted = False client = self.client if not client or client.bad: try: d = getDongle(BTCHIP_DEBUG) client = btchip(d) firmware = client.getFirmwareVersion()['version'].split(".") if not checkFirmware(firmware): d.close() try: updateFirmware() except Exception, e: aborted = True raise e d = getDongle(BTCHIP_DEBUG) client = btchip(d) try: client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = client.getVerifyPinRemainingAttempts() if remaining_attempts <> 1: msg = "Enter your Ledger PIN - remaining attempts : " + str(remaining_attempts) else: msg = "Enter your Ledger PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = wallet.password_dialog(msg) if not confirmed: aborted = True raise Exception('Aborted by user - please unplug the dongle and plug it again before retrying') pin = pin.encode() client.verifyPin(pin)
def sign_message(self, sequence, message, password): #client = self.get_client() #address_path = self.get_derivation() + "/%d/%d"%sequence #address_n = client.expand_path(address_path) #msg_sig = client.sign_message(self.plugin.get_coin_name(), address_n, message) #return msg_sig.signature self.signing = True message = message.encode('utf8') message_hash = hashlib.sha256(message).hexdigest().upper() # prompt for the PIN before displaying the dialog if necessary # client = self.get_client() app = btchip(self.get_client()) address_path = self.get_derivation()[2:] + "/%d/%d" % sequence self.handler.show_message("Signing message ...\r\nMessage hash: " + message_hash) try: info = app.signMessagePrepare(address_path, message) pin = "" if info['confirmationNeeded']: pin = self.handler.get_auth( info) # does the authenticate dialog and returns pin if not pin: raise UserWarning(_('Cancelled by user')) pin = str(pin).encode() signature = app.signMessageSign(pin) except BTChipException as e: if e.sw == 0x6a80: self.give_error( "Unfortunately, this message cannot be signed by the Ledger wallet. Only alphanumerical messages shorter than 140 characters are supported. Please remove any extra characters (tab, carriage return) and retry." ) else: self.give_error(e, True) except UserWarning: self.handler.show_error(_('Cancelled by user')) return '' except Exception as e: self.give_error(e, True) finally: self.handler.finished() self.signing = False # Parse the ASN.1 signature rLength = signature[3] r = signature[4:4 + rLength] sLength = signature[4 + rLength + 1] s = signature[4 + rLength + 2:] if rLength == 33: r = r[1:] if sLength == 33: s = s[1:] # And convert it return bytes([27 + 4 + (signature[0] & 0x01)]) + r + s
def get_client(self, keystore, force_pair=True): devmgr = self.device_manager() handler = keystore.handler with devmgr.hid_lock: client = devmgr.client_for_keystore(self, handler, keystore, force_pair) if client != None: man_string = client.dongleObject.dongle.device.get_manufacturer_string( ) if man_string == None: client.dongleObject = btchip( self.get_secalot_device(client.hidDevicePath)) return client
def initDevice(self): with self.lock: self.status = 0 self.clearDevice() self.dongle = getDongle(False) printOK('Ledger Nano S drivers found') self.chip = btchip(self.dongle) printDbg("Ledger Initialized") ver = self.chip.getFirmwareVersion() printOK("Ledger HW device connected [v. %s]" % str(ver.get('version'))) # Check device is unlocked bip32_path = MPATH + "%d'/0/%d" % (0, 0) self.status = 1 firstKey = self.chip.getWalletPublicKey(bip32_path) self.status = 2
def initDevice(self): printDbg("Initializing Ledger") with self.lock: self.status = 0 self.dongle = getDongle(False) printOK('Ledger Nano drivers found') self.chip = btchip(self.dongle) printDbg("Ledger Initialized") self.status = 1 ver = self.chip.getFirmwareVersion() printOK("Ledger HW device connected [v. %s]" % str(ver.get('version'))) # Check device is unlocked bip32_path = MPATH + "%d'/0/%d" % (0, 0) _ = self.chip.getWalletPublicKey(bip32_path) self.status = 2 self.sig_progress.connect(self.updateSigProgress)
def initDevice(self): try: if hasattr(self, 'dongle'): self.dongle.close() self.dongle = getDongle(False) printOK('Ledger Nano S drivers found') self.chip = btchip(self.dongle) printDbg("Ledger Initialized") self.initialized = True ver = self.chip.getFirmwareVersion() printOK("Ledger HW device connected [v. %s]" % str(ver.get('version'))) except Exception as e: err_msg = 'error Initializing Ledger' printException(getCallerName(), getFunctionName(), err_msg, e.args) self.initialized = False if hasattr(self, 'dongle'): self.dongle.close()
def initDevice(self): try: self.lock.acquire() self.status = 0 if hasattr(self, 'dongle'): self.dongle.close() self.dongle = getDongle(False) printOK('Ledger Nano S drivers found') self.chip = btchip(self.dongle) printDbg("Ledger Initialized") ver = self.chip.getFirmwareVersion() printOK("Ledger HW device connected [v. %s]" % str(ver.get('version'))) self.status = 2 except Exception as e: if hasattr(self, 'dongle'): self.status = 1 self.dongle.close() finally: self.lock.release()
def get_xpub(self, bip32_path, xtype): self.checkDevice() # bip32_path is of the form 44'/0'/1' # S-L-O-W - we don't handle the fingerprint directly, so compute # it manually from the previous node # This only happens once so it's bearable #self.get_client() # prompt for the PIN before displaying the dialog if necessary #self.handler.show_message("Computing master public key") if xtype in ['p2wpkh', 'p2wsh'] and not self.supports_native_segwit(): raise Exception(MSG_NEEDS_FW_UPDATE_SEGWIT) if xtype in ['p2wpkh-p2sh', 'p2wsh-p2sh' ] and not self.supports_segwit(): raise Exception(MSG_NEEDS_FW_UPDATE_SEGWIT) splitPath = bip32_path.split('/') if splitPath[0] == 'm': splitPath = splitPath[1:] bip32_path = bip32_path[2:] fingerprint = 0 app = btchip(self.dongleObject) if len(splitPath) > 1: prevPath = "/".join(splitPath[0:len(splitPath) - 1]) nodeData = app.getWalletPublicKey(prevPath) publicKey = compress_public_key(nodeData['publicKey']) h = hashlib.new('ripemd160') h.update(hashlib.sha256(publicKey).digest()) fingerprint = unpack(">I", h.digest()[0:4])[0] nodeData = app.getWalletPublicKey(bip32_path) publicKey = compress_public_key(nodeData['publicKey']) depth = len(splitPath) lastChild = splitPath[len(splitPath) - 1].split('\'') childnum = int(lastChild[0]) if len( lastChild) == 1 else 0x80000000 | int(lastChild[0]) xpub = bitcoin.serialize_xpub(xtype, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum)) return xpub
def __init__(self, hidDevice): self.dongleObject = btchip(hidDevice) self.preflightDone = False
pw = getpass() print("Applying hard key derivation function. Wait a little") k = decode_keystore_json(json, pw) # Prepare a new transaction (decoded transaction seems immutable...) tx = Transaction( tx.nonce, tx.gasprice, tx.startgas, tx.to, tx.value, tx.data ) tx.sign(k) # Using Ledger HW1 in DEV mode (SIGNVERIFY_IMMEDIATE) if args.keytype == 'dongle': from btchip.btchip import getDongle, btchip from bitcoin import decode_sig as bitcoin_decode_sig dongle = getDongle(True) app = btchip(dongle) print("Enter pin of dongle or ctrl+c to cancel") pin = getpass('Pin:') app.verifyPin(pin) # Sign with dongle rawhash = sha3(encode(tx, UnsignedTransaction)) signature = app.signImmediate(bytearray(decode_hex(args.keyfile)), rawhash) # ASN.1 Decoding inspired from electrum rLength = signature[3] r = signature[4: 4 + rLength] sLength = signature[4 + rLength + 1] s = signature[4 + rLength + 2:] if rLength == 33: r = r[1:]
def __init__(self, plugin, hidDevice, isHW1=False): self.device = plugin.device self.dongleObject = btchip(hidDevice) self.preflightDone = False self.isHW1 = isHW1
from btchip.btchip import btchip from btchip.btchipComm import getDongle def sha256(text): import hashlib m = hashlib.sha256() m.update(bytearray.fromhex(text)) return m.digest() dongle = getDongle(True) app = btchip(dongle) # Set passwords # empty password app.setBTCVPassword("1", btchip.BTCV_PASSWORD_INSTANT) instantPassword = "******" recoveryPassword = "******" app.setBTCVPassword(instantPassword, btchip.BTCV_PASSWORD_INSTANT) app.setBTCVPassword(recoveryPassword, btchip.BTCV_PASSWORD_RECOVERY) # Set password use instantPasswordHash = sha256(bytearray(instantPassword.encode('utf-8')).hex().ljust(64, '0')) recoveryPasswordHash = sha256(bytearray(recoveryPassword.encode('utf-8')).hex().ljust(64, '0')) app.setBTCVPasswordUse(bytearray(32), btchip.BTCV_TX_ALERT)
def __init__(self, hidDevice, *, product_key: Tuple[int, int]): self.dongleObject = btchip(hidDevice) self.preflightDone = False self._product_key = product_key self._soft_device_id = None
def __init__(self, hidDevice, hidDevicePath): self.dongleObject = btchip(hidDevice) self.hidDevicePath = hidDevicePath
def __init__(self, hidDevice, *, is_hw1: bool = False): self.dongleObject = btchip(hidDevice) self.preflightDone = False self._is_hw1 = is_hw1
def perform_hw1_preflight(self): try: app = btchip(self.dongleObject) firmwareInfo = app.getFirmwareVersion() firmware = firmwareInfo['version'] self.multiOutputSupported = versiontuple(firmware) >= versiontuple( MULTI_OUTPUT_SUPPORT) self.nativeSegwitSupported = versiontuple( firmware) >= versiontuple(SEGWIT_SUPPORT) self.segwitSupported = self.nativeSegwitSupported or ( firmwareInfo['specialVersion'] == 0x20 and versiontuple(firmware) >= versiontuple(SEGWIT_SUPPORT_SPECIAL)) if not checkFirmware(firmwareInfo): self.dongleObject.dongle.close() raise Exception(MSG_NEEDS_FW_UPDATE_GENERIC) try: app.getOperationMode() except BTChipException as e: if (e.sw == 0x6985): self.dongleObject.dongle.close() self.handler.get_setup() # Acquire the new client on the next run else: raise e status, remaining_attempts = app.getVerifyPinRemainingAttempts() if (status == False): if remaining_attempts <= 0: raise Exception("PIN is blocked - please unblock") if self.handler is not None: if remaining_attempts > 1: msg = "Enter your PIN. Remaining attempts : " + str( remaining_attempts) else: msg = "Enter your PIN. WARNING: LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: raise Exception( 'Aborted by user - please unplug the dongle and plug it again before retrying' ) # pin = pin.encode() app.verifyPin(pin) except BTChipException as e: if (e.sw == 0x6faa): raise Exception( "Dongle is temporarily locked - please unplug it and replug it again" ) if ((e.sw & 0xFFF0) == 0x63c0): raise Exception( "Invalid PIN - please unplug the dongle and plug it again before retrying" ) if e.sw == 0x6f00 and e.message == 'Invalid channel': # based on docs 0x6f00 might be a more general error, hence we also compare message to be sure raise Exception( "Invalid channel.\n" "Please make sure that 'Browser support' is disabled on your device." ) raise e
def get_client(self, noPin=False): if not BTCHIP: give_error('please install github.com/btchip/btchip-python') aborted = False if not self.client or self.client.bad: try: d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) firmware = self.client.getFirmwareVersion()['version'].split( ".") if int(firmware[0]) <> 1 or int(firmware[1]) <> 4: aborted = True raise Exception("Unsupported firmware version") if int(firmware[2]) < 9: aborted = True raise Exception( "Please update your firmware - 1.4.9 or higher is necessary" ) try: self.client.getOperationMode() except BTChipException, e: if (e.sw == 0x6985): d.close() dialog = StartBTChipPersoDialog() dialog.exec_() # Then fetch the reference again as it was invalidated d = getDongle(BTCHIP_DEBUG) d.setWaitImpl(DongleWaitQT(d)) self.client = btchip(d) else: raise e if not noPin: # Immediately prompts for the PIN remaining_attempts = self.client.getVerifyPinRemainingAttempts( ) if remaining_attempts <> 1: msg = "Enter your BTChip PIN - remaining attempts : " + str( remaining_attempts) else: msg = "Enter your BTChip PIN - WARNING : LAST ATTEMPT. If the PIN is not correct, the dongle will be wiped." confirmed, p, pin = self.password_dialog(msg) if not confirmed: aborted = True raise Exception( 'Aborted by user - please unplug the dongle and plug it again before retrying' ) pin = pin.encode() self.client.verifyPin(pin) except BTChipException, e: try: self.client.dongle.close() except: pass self.client = None if (e.sw == 0x6faa): raise Exception( "Dongle is temporarily locked - please unplug it and replug it again" ) if ((e.sw & 0xFFF0) == 0x63c0): raise Exception( "Invalid PIN - please unplug the dongle and plug it again before retrying" ) raise e
def sign_transaction(self, tx, password): if tx.is_complete(): return # client = self.get_client() app = btchip(self.get_client()) self.signing = True inputs = [] inputsPaths = [] pubKeys = [] chipInputs = [] redeemScripts = [] signatures = [] preparedTrustedInputs = [] changePath = "" changeAmount = None output = None outputAmount = None p2shTransaction = False segwitTransaction = False pin = "" self.get_client( ) # prompt for the PIN before displaying the dialog if necessary # Fetch inputs of the transaction to sign derivations = self.get_tx_derivations(tx) for txin in tx.inputs(): if txin['type'] == 'coinbase': self.give_error( "Coinbase not supported") # should never happen if txin['type'] in ['p2sh']: p2shTransaction = True if txin['type'] in ['p2wpkh-p2sh', 'p2wsh-p2sh']: if not self.get_client_electrum().supports_segwit(): self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT) segwitTransaction = True if txin['type'] in ['p2wpkh', 'p2wsh']: if not self.get_client_electrum().supports_native_segwit(): self.give_error(MSG_NEEDS_FW_UPDATE_SEGWIT) segwitTransaction = True pubkeys, x_pubkeys = tx.get_sorted_pubkeys(txin) for i, x_pubkey in enumerate(x_pubkeys): if x_pubkey in derivations: signingPos = i s = derivations.get(x_pubkey) hwAddress = "%s/%d/%d" % (self.get_derivation()[2:], s[0], s[1]) break else: self.give_error("No matching x_key for sign_transaction" ) # should never happen redeemScript = Transaction.get_preimage_script(txin) inputs.append([ txin['prev_tx'].raw, txin['prevout_n'], redeemScript, txin['prevout_hash'], signingPos, txin.get('sequence', 0xffffffff - 1) ]) inputsPaths.append(hwAddress) pubKeys.append(pubkeys) # Sanity check if p2shTransaction: for txin in tx.inputs(): if txin['type'] != 'p2sh': self.give_error( "P2SH / regular input mixed in same transaction not supported" ) # should never happen txOutput = var_int(len(tx.outputs())) for txout in tx.outputs(): output_type, addr, amount = txout txOutput += int_to_hex(amount, 8) script = tx.pay_script(output_type, addr) txOutput += var_int(len(script) // 2) txOutput += script txOutput = bfh(txOutput) # Recognize outputs - only one output and one change is authorized if not p2shTransaction: if not self.get_client_electrum().supports_multi_output(): if len(tx.outputs()) > 2: self.give_error( "Transaction with more than 2 outputs not supported") for _type, address, amount in tx.outputs(): assert _type == TYPE_ADDRESS info = tx.output_info.get(address) if (info is not None) and (len(tx.outputs()) != 1): index, xpubs, m = info changePath = self.get_derivation()[2:] + "/%d/%d" % index changeAmount = amount else: output = address outputAmount = amount # self.handler.show_message(_("Confirm Transaction on your Ledger device...")) try: # Get trusted inputs from the original transactions for utxo in inputs: sequence = int_to_hex(utxo[5], 4) if segwitTransaction: txtmp = bitcoinTransaction(bfh(utxo[0])) tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) tmp += txtmp.outputs[utxo[1]].amount chipInputs.append({ 'value': tmp, 'witness': True, 'sequence': sequence }) redeemScripts.append(bfh(utxo[2])) elif not p2shTransaction: txtmp = bitcoinTransaction(bfh(utxo[0])) trustedInput = app.getTrustedInput(txtmp, utxo[1]) trustedInput['sequence'] = sequence chipInputs.append(trustedInput) redeemScripts.append(txtmp.outputs[utxo[1]].script) else: tmp = bfh(utxo[3])[::-1] tmp += bfh(int_to_hex(utxo[1], 4)) chipInputs.append({'value': tmp, 'sequence': sequence}) redeemScripts.append(bfh(utxo[2])) # Sign all inputs firstTransaction = True inputIndex = 0 rawTx = tx.serialize() # app.enableAlternate2fa(False) if segwitTransaction: app.startUntrustedTransaction(True, inputIndex, chipInputs, redeemScripts[inputIndex]) outputData = app.finalizeInputFull(txOutput) outputData['outputData'] = txOutput transactionOutput = outputData['outputData'] if outputData['confirmationNeeded']: outputData['address'] = output self.handler.finished() pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin if not pin: raise UserWarning() if pin != 'paired': self.handler.show_message( _("Confirmed. Signing Transaction...")) while inputIndex < len(inputs): singleInput = [chipInputs[inputIndex]] app.startUntrustedTransaction(False, 0, singleInput, redeemScripts[inputIndex]) inputSignature = app.untrustedHashSign( inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ signatures.append(inputSignature) inputIndex = inputIndex + 1 else: while inputIndex < len(inputs): app.startUntrustedTransaction(firstTransaction, inputIndex, chipInputs, redeemScripts[inputIndex]) outputData = app.finalizeInputFull(txOutput) outputData['outputData'] = txOutput if firstTransaction: transactionOutput = outputData['outputData'] #if outputData['confirmationNeeded']: # outputData['address'] = output # self.handler.finished() # pin = self.handler.get_auth( outputData ) # does the authenticate dialog and returns pin # if not pin: # raise UserWarning() # if pin != 'paired': # self.handler.show_message(_("Confirmed. Signing Transaction...")) #else: # # Sign input with the provided PIN inputSignature = app.untrustedHashSign( inputsPaths[inputIndex], pin, lockTime=tx.locktime) inputSignature[0] = 0x30 # force for 1.4.9+ signatures.append(inputSignature) inputIndex = inputIndex + 1 #if pin != 'paired': # firstTransaction = False except UserWarning: self.handler.show_error(_('Cancelled by user')) return except BaseException as e: traceback.print_exc(file=sys.stdout) self.give_error(e, True) finally: self.handler.finished() for i, txin in enumerate(tx.inputs()): signingPos = inputs[i][4] txin['signatures'][signingPos] = bh2u(signatures[i]) tx.raw = tx.serialize() self.signing = False