def tx_inputs(self, tx: Transaction, xpub_path: Dict[str, str]) -> List[types.TxInputType]: inputs = [] for txin in tx.inputs: txinputtype = types.TxInputType() x_pubkeys = txin.x_pubkeys if len(x_pubkeys) == 1: x_pubkey = x_pubkeys[0] xpub, path = x_pubkey.bip32_extended_key_and_path() xpub_n = bip32_decompose_chain_string(xpub_path[xpub]) txinputtype.address_n.extend(xpub_n) txinputtype.address_n.extend(path) txinputtype.script_type = types.SPENDADDRESS else: def f(x_pubkey): if x_pubkey.is_bip32_key(): xpub, path = x_pubkey.bip32_extended_key_and_path() else: xpub = BIP32PublicKey(x_pubkey.to_public_key(), NULL_DERIVATION, Net.COIN) xpub = xpub.to_extended_key_string() path = [] node = keepkeylib.ckd_public.deserialize(xpub) return types.HDNodePathType(node=node, address_n=path) pubkeys = [f(x) for x in x_pubkeys] multisig = types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=txin.stripped_signatures_with_blanks(), m=txin.threshold, ) script_type = types.SPENDMULTISIG txinputtype = types.TxInputType(script_type=script_type, multisig=multisig) # find which key is mine for x_pubkey in x_pubkeys: if x_pubkey.is_bip32_key(): xpub, path = x_pubkey.bip32_extended_key_and_path() if xpub in xpub_path: xpub_n = tuple( bip32_decompose_chain_string(xpub_path[xpub])) txinputtype.address_n.extend(xpub_n) txinputtype.address_n.extend(path) break txinputtype.prev_hash = bytes(reversed(txin.prev_hash)) txinputtype.prev_index = txin.prev_idx txinputtype.sequence = txin.sequence txinputtype.amount = txin.value inputs.append(txinputtype) return inputs
def tx_outputs(self, keystore: KeepKey_KeyStore, derivation: str, tx: Transaction): has_change = False account_derivation = tuple(bip32_decompose_chain_string(derivation)) keystore_fingerprint = keystore.get_fingerprint() outputs = [] assert tx.output_info is not None for tx_output, output_metadatas in zip(tx.outputs, tx.output_info): info = output_metadatas.get(keystore_fingerprint) if info is not None and not has_change: has_change = True # no more than one change address key_derivation, xpubs, m = info if len(xpubs) == 1: script_type = types.PAYTOADDRESS txoutputtype = types.TxOutputType( amount=tx_output.value, script_type=script_type, address_n=account_derivation + key_derivation, ) else: script_type = types.PAYTOMULTISIG nodes = [ keepkeylib.ckd_public.deserialize(xpub) for xpub in xpubs ] pubkeys = [ types.HDNodePathType(node=node, address_n=key_derivation) for node in nodes ] multisig = types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=[b''] * len(pubkeys), m=m) txoutputtype = types.TxOutputType( multisig=multisig, amount=tx_output.value, address_n=account_derivation + key_derivation, script_type=script_type) else: txoutputtype = types.TxOutputType() txoutputtype.amount = tx_output.value address = classify_tx_output(tx_output) if isinstance(address, Address): txoutputtype.script_type = types.PAYTOADDRESS txoutputtype.address = address.to_string() outputs.append(txoutputtype) return outputs
def tx_inputs(self, tx, for_sig=False): inputs = [] for txin in tx.inputs: txinputtype = types.TxInputType() if txin.get('is_coinbase'): prev_hash = "\0" * 32 prev_index = 0xffffffff # signed int -1 else: if for_sig: x_pubkeys = txin['x_pubkeys'] if len(x_pubkeys) == 1: x_pubkey = x_pubkeys[0] xpub, s = BIP32_Account.parse_xpubkey(x_pubkey) xpub_n = self.get_client().expand_path( self.xpub_path[xpub]) txinputtype.address_n.extend(xpub_n + s) else: def f(x_pubkey): if is_extended_pubkey(x_pubkey): xpub, s = BIP32_Account.parse_xpubkey(x_pubkey) else: xpub = xpub_from_pubkey(x_pubkey.decode('hex')) s = [] node = ckd_public.deserialize(xpub) return types.HDNodePathType(node=node, address_n=s) pubkeys = map(f, x_pubkeys) multisig = types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=map( lambda x: x.decode('hex') if x else '', txin.get('signatures')), m=txin.get('num_sig'), ) txinputtype = types.TxInputType( script_type=types.SPENDMULTISIG, multisig=multisig) # find which key is mine for x_pubkey in x_pubkeys: xpub, s = BIP32_Account.parse_xpubkey(x_pubkey) if xpub in self.xpub_path: xpub_n = self.get_client().expand_path( self.xpub_path[xpub]) txinputtype.address_n.extend(xpub_n + s) break else: raise prev_hash = unhexlify(txin['prevout_hash']) prev_index = txin['prevout_n'] txinputtype.prev_hash = prev_hash txinputtype.prev_index = prev_index if 'scriptSig' in txin: script_sig = txin['scriptSig'].decode('hex') txinputtype.script_sig = script_sig if 'sequence' in txin: sequence = txin['sequence'] txinputtype.sequence = sequence inputs.append(txinputtype) return inputs