def test_to_cash_p2sh(self): self.assertEqual( convert.to_cash_address('3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC'), 'bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq') self.assertEqual( convert.to_cash_address( 'bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq'), 'bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq')
def test_to_cash_p2sh_testnet(self): self.assertEqual( convert.to_cash_address('2MwikwR6hoVijCmr1u8UgzFMHFP6rpQyRvP'), 'bchtest:pqc3tyspqwn95retv5k3c5w4fdq0cxvv95u36gfk00') self.assertEqual( convert.to_cash_address( 'bchtest:pqc3tyspqwn95retv5k3c5w4fdq0cxvv95u36gfk00'), 'bchtest:pqc3tyspqwn95retv5k3c5w4fdq0cxvv95u36gfk00')
def test_to_cash_p2pkh(self): self.assertEqual( convert.to_cash_address('155fzsEBHy9Ri2bMQ8uuuR3tv1YzcDywd4'), 'bitcoincash:qqkv9wr69ry2p9l53lxp635va4h86wv435995w8p2h') self.assertEqual( convert.to_cash_address( 'bitcoincash:qqkv9wr69ry2p9l53lxp635va4h86wv435995w8p2h'), 'bitcoincash:qqkv9wr69ry2p9l53lxp635va4h86wv435995w8p2h')
def test_to_cash_p2pkh_testnet(self): self.assertEqual( convert.to_cash_address('mqp7vM7eU7Vu9NPH1V7s7pPg5FFBMo6SWK'), 'bchtest:qpc0qh2xc3tfzsljq79w37zx02kwvzm4gydm222qg8') self.assertEqual( convert.to_cash_address( 'bchtest:qpc0qh2xc3tfzsljq79w37zx02kwvzm4gydm222qg8'), 'bchtest:qpc0qh2xc3tfzsljq79w37zx02kwvzm4gydm222qg8')
def form_transaction_dict(cls, transaction): if not cls.is_memo(transaction): raise ValueError('Not valid transaction dict!') memo = Memo() memo.transaction_dict = transaction memo.transaction_hash = transaction['txid'] memo.blockheight = transaction['blockheight'] # memo.transaction_time=transaction['time'] memo.__get_transfer() for vout in transaction['vout']: if vout['scriptPubKey']['hex'][0:2] == '6a' \ and vout['scriptPubKey']['hex'][4:8] in SUPPORTED_PREFIX: memo.prefix = vout['scriptPubKey']['hex'][4:8] memo.values = vout['scriptPubKey']['hex'][10:] break else: raise NotMemoTransaction( 'No OP_RETURN data in the transaction or none memo supported data.' ) addr_vin = [] for vin in transaction['vin']: # type:dict if 'addr' in vin: addr_vin.append(to_cash_address(vin['addr'])) if len(addr_vin) >= 1: memo.sender = addr_vin[0] memo.transaction_time = transaction['time'] return memo
def address_to_public_key_hash(address): # LEGACYADDRESSDEPRECATION # FIXME: This legacy address support will be removed. address = cashaddress.to_cash_address(address) get_version(address) Address = cashaddress.Address._cash_string(address) return bytes(Address.payload)
def get_xpub_address(xpub, index): # 0 => public addresses # 1 => change addresses, only for internal use account_type = 0 xpub_subkey = xpub.subkey(account_type) addr = xpub_subkey.subkey(index).bitcoin_address() caddr = convert.to_cash_address(addr) #print(caddr) #return caddr.upper() return caddr
def __get_transfer(self): """ generate transfer form transaction dict """ transfer = [] for vout in self.transaction_dict['vout']: if 'addresses' in vout['scriptPubKey']: transfer.append( (to_cash_address(vout['scriptPubKey']['addresses'][0]), vout['value'])) self.transfer = transfer
def pubkey_to_legacy_address(pubkey, main_net=True): pubkey = pubkey.decode("hex") addr_prefix = ADDR_PREFIX if not main_net: addr_prefix = ADDR_PREFIX_TEST h20 = utils.hash160(pubkey) d21 = addr_prefix + h20 c4 = utils.checksum(d21) d25 = d21 + c4 return to_cash_address(base58.b58encode(d25))
def redeemscript_to_p2sh_address(redeem_script, main_net=True): redeem_script = redeem_script.decode("hex") script_prefix = SCRIPT_PREFIX if not main_net: script_prefix = SCRIPT_PREFIX_TEST h20 = utils.hash160(redeem_script) d21 = script_prefix + h20 c4 = utils.checksum(d21) d25 = d21 + c4 return to_cash_address(base58.b58encode(d25))
def pub2add(pubkey): """Convert a Bitcoin public key to a cash address """ # Public key from a known safely stored private key # pub_hex = '0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352' pub_hex = pubkey pub = bytes.fromhex(pub_hex) # print('pubkey', pub) # Perform SHA-256 hashing on the public key m = hashlib.sha256() m.update(pub) pub_sha256 = m.digest() # print('pub_sha256', pub_sha256) # Perform RIPEMD-160 hashing on the result of SHA-256 h = hashlib.new('ripemd160') h.update(pub_sha256) pub_double = h.digest() # print('\npub_double', pub_double) # Add version byte in front of RIPEMD-160 hash (0x00 for Main Network) version_byte = bytes.fromhex('00') pub_double_full = version_byte + pub_double # print('version bytes added', pub_double_full) # Perform SHA-256 hash on the extended RIPEMD-160 result shan1 = hashlib.sha256() shan1.update(pub_double_full) shan1 = shan1.digest() # print('\nFirst SHA256:', shan1) # Perform SHA-256 hash on the result of the previous SHA-256 hash shan2 = hashlib.sha256() shan2.update(shan1) shan2 = shan2.digest() # print('\nSecond SHA256:', shan2) # Append the first 4 bytes of the second SHA-256 hash (checksum) # This is the 25-byte binary Bitcoin Address. checksum = shan2[:4] twenty5byte = pub_double_full + checksum # print('twenty5byte', twenty5byte) # Convert the result from a byte string into a base58 string using Base58Check # encoding. leg_address = encodeb58(twenty5byte) # Convert to cashaddress address = convert.to_cash_address(leg_address) print(address)
def get_uncompressed_coin(private_key): print("Warning Uncompressed key") config_alias = BitcoinConf coin_type = Bip44Coins.BITCOIN decodedWif = WifDecoder.Decode( wif_str=private_key, net_addr_ver=config_alias.WIF_NET_VER.Main()) bip44_mst = Bip44.FromAddressPrivKey(decodedWif, coin_type) to_hex = bip44_mst.PublicKey().RawUncompressed().ToBytes() pub_key_bytes = b'\x04' + to_hex legacy_address = Base58Encoder.CheckEncode( config_alias.P2PKH_NET_VER.Main() + CryptoUtils.Hash160(pub_key_bytes)) address = convert.to_cash_address(legacy_address).replace( 'bitcoincash:', '') return CryptoCoin(address, private_key)
def sign_message(message, coin, key=None, encoding='utf8'): # message = message.encode('utf8') coin_dispatcher = { 'btc': cr.Bitcoin(), 'bch': cr.BitcoinCash(), 'ltc': cr.Litecoin() } client = coin_dispatcher[coin] # if no key provided, create one randomly if key is None: priv = random.randint(1, KEY_UPPER_LIMIT) pub = client.privtopub(priv) addr = client.privtoaddr(priv) else: try: priv = int(key) pub = client.privtopub(priv) addr = client.privtoaddr(priv) except: priv = cr.sha256(key) pub = client.privtopub(priv) addr = client.privtoaddr(priv) # sign message # if coin == 'ltc': # signature = cr.litecoin_ecdsa_sign(message, priv) # else: # signature = cr.ecdsa_sign(message, priv) signature = cr.bytes_ecdsa_sign(message, priv, coin, encoding) if coin == 'bch': addr = convert.to_cash_address(addr) # output output = { "address": addr, "signature": signature, "message": message, "private_key": priv, "public_key": pub, "coin": coin } return output
def __init__(self,address): if not isinstance(address,str): raise TypeError('address should be str!') if not is_valid(address): raise ValueError('{} is not a valid address'.format(address)) self._address = to_cash_address(address) self.memos_send=[] # list of memos sent by user self.memos_post=[] # list of post memo sent by user self.memos_like=[] # list of like / tip memo sent by user self.memos_receive=[] # list of memos that are not sent by user but transfer BCH to user self._private_key=None self.name=None self.following=set()
def address_to_public_key_hash(address): address = convert.to_cash_address(address) Address = convert.Address._cash_string(address) return bytes(Address.payload)
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True, custom_pushdata=False): """ sanitize_tx_data() fee is in satoshis per byte. """ outputs = deque(outputs) for i, output in enumerate(outputs): dest, amount, currency = output # LEGACYADDRESSDEPRECATION # FIXME: Will be removed in an upcoming release, breaking compatibility with legacy addresses. dest = cashaddress.to_cash_address(dest) outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') # Temporary storage so all outputs precede messages. messages = deque() total_op_return_size = 0 if message and (custom_pushdata is False): try: message = message.encode('utf-8') except AttributeError: pass # assume message is already a bytes-like object message_chunks = chunk_data(message, MESSAGE_LIMIT) for message in message_chunks: messages.appendleft((message, 0)) total_op_return_size += get_op_return_size(message, custom_pushdata=False) elif message and (custom_pushdata is True): if (len(message) >= MESSAGE_LIMIT): # FIXME add capability for >220 bytes for custom pushdata elements raise ValueError("Currently cannot exceed 220 bytes with custom_pushdata.") else: messages.append((message, 0)) total_op_return_size += get_op_return_size(message, custom_pushdata=True) # Include return address in fee estimate. total_in = 0 num_outputs = len(outputs) + 1 sum_outputs = sum(out[1] for out in outputs) if combine: # calculated_fee is in total satoshis. calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee, compressed, total_op_return_size) total_out = sum_outputs + calculated_fee unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount calculated_fee = estimate_tx_fee(len(unspents[:index + 1]), num_outputs, fee, compressed, total_op_return_size) total_out = sum_outputs + calculated_fee if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > DUST_LIMIT: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extendleft(messages) return unspents, list(outputs)
def sanitize_tx_data(unspents, outputs, fee, leftover, combine=True, message=None, compressed=True): """ sanitize_tx_data() fee is in satoshis per byte. """ outputs = outputs.copy() for i, output in enumerate(outputs): dest, amount, currency = output # LEGACYADDRESSDEPRECATION # FIXME: Will be removed in an upcoming release, breaking compatibility with legacy addresses. dest = cashaddress.to_cash_address(dest) outputs[i] = (dest, currency_to_satoshi_cached(amount, currency)) if not unspents: raise ValueError('Transactions must have at least one unspent.') # Temporary storage so all outputs precede messages. messages = [] if message: message_chunks = chunk_data(message.encode('utf-8'), MESSAGE_LIMIT) for message in message_chunks: messages.append((message, 0)) # Include return address in fee estimate. total_in = 0 num_outputs = len(outputs) + len(messages) + 1 sum_outputs = sum(out[1] for out in outputs) if combine: # calculated_fee is in total satoshis. calculated_fee = estimate_tx_fee(len(unspents), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee unspents = unspents.copy() total_in += sum(unspent.amount for unspent in unspents) else: unspents = sorted(unspents, key=lambda x: x.amount) index = 0 for index, unspent in enumerate(unspents): total_in += unspent.amount calculated_fee = estimate_tx_fee(len(unspents[:index + 1]), num_outputs, fee, compressed) total_out = sum_outputs + calculated_fee if total_in >= total_out: break unspents[:] = unspents[:index + 1] remaining = total_in - total_out if remaining > 0: outputs.append((leftover, remaining)) elif remaining < 0: raise InsufficientFunds('Balance {} is less than {} (including ' 'fee).'.format(total_in, total_out)) outputs.extend(messages) return unspents, outputs
print() print( get_transaction_btc( 'a7e3babfd7658cfa5ebf5d9b1477da0b40cab68d75c7bc8638eaafcba066b062')) print() print(get_transactions('qqa0dwrk79um6wgmzk9rrv303l2qwppuk5vmr8taqq')) k = Key('L3KavUvcjBj7pzKBMS4doKyJpBY4nJJbm31VnVwhcC26mTvCP3Lh') # k = PrivateKeyTestnet('cPW1zL9JJzgTKwQyHYeQ8KE5Cdo33fGE15QcZiWDCWKHhU43KsU2') # print(k.public_key) print(k.address) # print(k._public_key) # print(k.public_point) address = convert.to_legacy_address(k.address) print(address) bchaddr = convert.to_cash_address('13A8QNwEeuYyvcPSJwR4F5xDr6RUryLVfw') # print(bchaddr) # print(k.to_wif()) print(k.get_balance(currency='satoshi')) # print(k.unspents) # print(k.transactions) print(k.get_transactions()) print(k.get_unspents()) txid = k.send([('13A8QNwEeuYyvcPSJwR4F5xDr6RUryLVfw', 0.01001, 'bch')], fee=452) print(txid) print(get_balance('qz7xc0vl85nck65ffrsx5wvewjznp9lflgktxc5878', currency='bch')) print( get_balance_btc('bc1q5j8j9y55mc05ws84smk36ndau4ptj9yj72eldz',
def test_to_cash_p2pkh_regtest(self): self.assertEqual(convert.to_cash_address('moehusBtUt3aKW5c2p3ZTRkSTRrr3dpnwe', regtest=True), 'bchreg:qpvns5lcufh5haf5jt79fk8trcw4j8c3nsvhdappvt') self.assertEqual(convert.to_cash_address('bchreg:qpvns5lcufh5haf5jt79fk8trcw4j8c3nsvhdappvt', regtest=True), 'bchreg:qpvns5lcufh5haf5jt79fk8trcw4j8c3nsvhdappvt')
def update(self, dt): # only one factor at a time if len(self.listener.received) != 0: return # poll server for each id_2FA print("Satochip update...") for keyhash in self.myfactors.datastore.keys(): # if keyhash in self.listener.received: # continue try: message = server.get(keyhash) except Exception as e: self.display = "Error: cannot contact server:" + str(e) Logger.warning("Satochip: cannot contact server: " + str(e)) break if message: self.listener.received.add(keyhash) label = self.myfactors.datastore.get(keyhash)['label_2FA'] Logger.debug("Satochip: Received challenge for: " + keyhash) Logger.debug("Satochip: Corresponding label: " + label) Logger.debug("Satochip: Challenge received: " + message) # decrypt message & remove padding key_2FA = bytes.fromhex( self.myfactors.datastore.get(keyhash)['key_2FA']) message = base64.b64decode(message) iv = message[0:16] ciphertext = message[16:] decrypter = pyaes.Decrypter( pyaes.AESModeOfOperationCBC(key_2FA, iv)) decrypted = decrypter.feed(ciphertext) decrypted += decrypter.feed() Logger.debug("Satochip: Challenge decrypted: " + decrypted.decode('ascii')) message = json.loads(decrypted) if 'action' in message: action = message['action'] else: action = "sign_tx" if action == "reset_seed": authentikeyx = message['authentikeyx'] txt = "Request to reset the seed!\nAuthentikey:" + authentikeyx challenge = authentikeyx + 32 * 'FF' elif action == "reset_2FA": txt = "Request to reset 2FA!\nID_2FA:" + keyhash try: id_2FA_20b = self.myfactors.datastore.get( keyhash)['id_2FA_20b'] except Exception as ex: # not supported for 2FA created in app version <=0.8/0.9 id_2FA_20b = keyhash challenge = id_2FA_20b + 44 * 'AA' elif action == "sign_msg": msg = message['msg'] if 'alt' in message: altcoin = message['alt'] headersize = bytes([len(altcoin) + 17]) paddedmsgbytes = headersize + altcoin.encode( 'utf8') + b" Signed Message:\n" + num_to_var_int( len(msg)) + bytes(msg, 'utf-8') else: altcoin = "Bitcoin" paddedmsgbytes = b"\x18Bitcoin Signed Message:\n" + num_to_var_int( len(msg)) + bytes(msg, 'utf-8') txt = "Request to sign " + altcoin + " message:\n" + msg + "\n" paddedmsghash = sha256(paddedmsgbytes).hexdigest() challenge = paddedmsghash + 32 * "BB" elif action == "sign_tx": is_segwit = message['sw'] txt = "2FA: " + label + "\n" # coin type: coin_type = message['ct'] if coin_type == 0: coin = Bitcoin(False) elif coin_type == 1: #btc testnet coin = Bitcoin(True) elif coin_type == 2: #litecoin istest = message['tn'] coin = Litecoin(testnet=istest) elif coin_type == 145: #bcash istest = message['tn'] coin = BitcoinCash(testnet=istest) is_segwit = True # bcash uses BIP143 for signature hash creation else: Logger.warning("Satochip: Coin not (yet) supported: " + str(coin_type)) coin = BaseCoin() txt += "Coin: " + coin.display_name + "\n" # parse tx into a clear message for approval pre_tx_hex = message['tx'] pre_tx = bytes.fromhex(pre_tx_hex) pre_hash_hex = sha256(sha256(pre_tx).digest()).hexdigest() challenge = pre_hash_hex + 32 * '00' if is_segwit: #parse segwit tx txin_type = message['ty'] txparser = TxParser(pre_tx) while not txparser.is_parsed(): chunk = txparser.parse_segwit_transaction() Logger.debug("Satochip: hashPrevouts: " + txparser.hashPrevouts.hex()) Logger.debug("Satochip: hashSequence: " + txparser.hashSequence.hex()) Logger.debug("Satochip: txOutHash: " + txparser.txOutHash[::-1].hex()) Logger.debug("Satochip: txOutIndex: " + str(txparser.txOutIndexLong)) Logger.debug("Satochip: inputScript: " + txparser.inputScript.hex()) Logger.debug("Satochip: inputAmount: " + str(txparser.inputAmountLong)) Logger.debug("Satochip: nSequence: " + txparser.nSequence.hex()) Logger.debug("Satochip: hashOutputs: " + txparser.hashOutputs.hex()) Logger.debug("Satochip: nLocktime: " + txparser.nLocktime.hex()) Logger.debug("Satochip: nHashType: " + txparser.nHashType.hex()) script = txparser.inputScript.hex() if txin_type == 'p2wpkh': hash = transaction.output_script_to_h160(script) hash = bytes.fromhex(hash) addr = coin.hash_to_segwit_addr(hash) Logger.debug("Satochip: p2wpkh address: " + addr) elif txin_type == 'p2wsh': #multisig-segwit addr = coin.script_to_p2wsh(script) Logger.debug("Satochip: p2wsh address: " + addr) elif txin_type == 'p2wsh-p2sh': h = transaction.output_script_to_h160(script) addr = coin.p2sh_scriptaddr("0020" + h) Logger.debug("Satochip: p2wsh-p2sh address: " + addr) elif txin_type == 'p2wpkh-p2sh': # for p2wpkh-p2sh addres is derived from script hash, see https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#P2WPKH_nested_in_BIP16_P2SH h = transaction.output_script_to_h160(script) addr = coin.p2sh_scriptaddr("0014" + h) Logger.debug("Satochip: p2wpkh-p2sh address: " + addr) elif (coin_type == 145) and (txin_type == 'p2pkh' or txin_type == 'p2sh'): # for bcash addr = coin.scripttoaddr(script) addr = convert.to_cash_address( addr) #cashAddr conversion addr = addr.split(":", 1)[-1] #remove prefix Logger.debug("Satochip: txin type: " + txin_type + " address: " + addr) else: addr = "unsupported script:" + script + "\n" txt += "input:\n" txt += " " + "address: " + addr + " spent: " + str( txparser.inputAmountLong / 100000) + "\n" #satoshi to mBtc #parse outputs outputs_hex = message['txo'] outputs = bytes.fromhex(outputs_hex) hashOutputs = sha256(sha256( outputs[1:]).digest()).hexdigest() outparser = TxParser(outputs) while not outparser.is_parsed(): chunk = outparser.parse_outputs() nb_outs = outparser.txCurrentOutput Logger.debug("Satochip: nbrOutputs: " + str(nb_outs)) txt += "nb_outputs: " + str(nb_outs) + "\n" txt += "outputs:\n" amnt_out = 0 for i in range(nb_outs): amnt = outparser.outAmounts[i] amnt_out += amnt script = outparser.outScripts[i].hex() is_data_script = False Logger.debug("Satochip: outScripts: " + script) Logger.debug("Satochip: amount: " + str(amnt)) if script.startswith('76a914'): #p2pkh addr = coin.scripttoaddr(script) elif script.startswith('a914'): #p2sh addr = coin.scripttoaddr(script) elif script.startswith('0014'): #p2wpkh hash = bytes.fromhex(script[4:]) addr = coin.hash_to_segwit_addr(hash) elif script.startswith('0020'): #p2wsh hash = bytes.fromhex(script[4:]) addr = coin.hash_to_segwit_addr(hash) elif script.startswith( '6a'): # op_return data script addr = "DATA: " + bytes.fromhex( script[6:]).decode('utf-8') is_data_script = True else: addr = "unsupported script:" + script + "\n" if coin_type == 145 and not is_data_script: addr = convert.to_cash_address( addr) #cashAddr conversion addr = addr.split(":", 1)[-1] #remove prefix Logger.debug("Satochip: address: " + addr) txt += " " + "address: " + addr + " spent: " + str( amnt / 100000) + "\n" #satoshi to mBtc txt += " " + "total: " + str( amnt_out / 100000 ) + " m" + coin.coin_symbol + "\n" #satoshi to mBtc if hashOutputs != txparser.hashOutputs.hex(): txt += "Warning! inconsistent output hashes!\n" # non-segwit tx else: pre_tx_dic = {} try: pre_tx_dic = transaction.deserialize(pre_tx) except Exception as e: Logger.warning( "Exception during (non-segwit) tx parsing: " + str(e)) txt = "Error parsing tx!" self.listener.clear(keyhash) break Logger.debug("Satochip: pre_tx_dic: " + str(pre_tx_dic)) # inputs amount_in = 0 ins = pre_tx_dic['ins'] nb_ins = len(ins) txt += "nb_inputs: " + str(nb_ins) + "\n" txt += "inputs:\n" for i in ins: script = i['script'].hex() Logger.debug("Satochip: input script: " + script) # recover script and corresponding addresse if script == "": # all input scripts are removed for signing except 1 outpoint = i['outpoint'] hash = outpoint['hash'].hex() index = outpoint['index'] #Logger.debug('Satochip: hash: hash:index: ' +hash+":"+str(index)) tx = coin.fetchtx(hash) #Logger.debug('Satochip: tx: '+str(tx)) outs = tx['out'] out = outs[index] val = out['value'] script = out['script'] addr = coin.scripttoaddr(script) addr = "(empty for signing: " + addr[ 0:16] + "...)" if script.endswith("ae"): #m-of-n pay-to-multisig m = int(script[0:2], 16) - 80 n = int(script[-4:-2], 16) - 80 txt += " " + "multisig " + str( m) + "-of-" + str(n) + "\n" addr = coin.p2sh_scriptaddr(script) Logger.debug("Satochip: address multisig: " + addr) else: #p2pkh, p2sh addr = coin.scripttoaddr(script) Logger.debug("Satochip: address: " + addr) # get value from blockchain explorer val = 0 try: unspent = coin.unspent_web(addr) for d in unspent: val += d['value'] except Exception as e: Logger.warning( "Exception during coin.unspent_web request: " + str(e)) #try to get value from electrum server (seem slow...) # try: # hs= sha256(bytes.fromhex(script)).digest() # hs= hs[::-1] # balances= coin.balance(True, hs.hex()) # val= sum(balances) # except Exception as e: # Logger.warning("Exception during coin.balance request: "+str(e)) txt += " " + "address: " + addr + " balance: " + str( val / 100000) + "\n" amount_in += val txt += " " + "total: " + str( amount_in / 100000 ) + " m" + coin.coin_symbol + "\n" #satoshi to mBtc # outputs fee = 0 amount_out = 0 outs = pre_tx_dic['outs'] nb_outs = len(outs) txt += "nb_outputs: " + str(nb_outs) + "\n" txt += "outputs:\n" for o in outs: val = (o['value']) script = o['script'].hex() Logger.debug("Satochip: output script: " + script) if script.startswith('76a914'): # p2pkh addr = coin.scripttoaddr(script) elif script.startswith('a914'): # p2sh addr = coin.scripttoaddr(script) elif script.startswith('0014'): #p2wpkh hash = bytes.fromhex(script[4:]) addr = coin.hash_to_segwit_addr(hash) elif script.startswith('0020'): #p2wsh hash = bytes.fromhex(script[4:]) addr = coin.hash_to_segwit_addr(hash) else: addr = "unsupported script:" + script + "\n" txt += " " + "address: " + addr + " spent: " + str( val / 100000) + "\n" #satoshi to mBtc amount_out += val txt += " " + "total: " + str( amount_out / 100000 ) + " m" + coin.coin_symbol + "\n" #satoshi to mBtc fee = amount_in - amount_out if fee >= 0: txt += " " + "fees: " + str( fee / 100000 ) + " m" + coin.coin_symbol + "\n" #satoshi to mBtc else: txt = "Unsupported operation: " + decrypted.decode('ascii') # 2FA challenges: # - Tx approval: [ 32b Tx hash | 32-bit 0x00-padding ] # - ECkey import:[ 32b coordx | 32-bit (0x10^key_nb)-padding ] # - ECkey reset: [ 32b coordx | 32-bit (0x20^key_nb)-padding ] # - 2FA reset: [ 20b 2FA_ID | 32-bit 0xAA-padding ] # - Seed reset: [ 32b authntikey-coordx | 32-bit 0xFF-padding ] # - Msg signing: [ 32b SHA26(btcHeader+msg) | 32-bit 0xBB-padding ] self.listener.postbox.append([keyhash, challenge]) self.display = txt self.label_logs += txt + "\n" Logger.info("Satochip: \nNew challenge: " + challenge + "\nReceived on " + str(datetime.now()) + ":\n" + txt) self.btn_disabled = False break
def test_to_cash_p2sh_regtest(self): self.assertEqual(convert.to_cash_address('2MwSNRexxm3uhAKF696xq3ztdiqgMj36rJo', regtest=True), 'bchreg:pqklc8ehp365xvtru6a394e4wxz52nt5nurac3g7rq') self.assertEqual(convert.to_cash_address('bchreg:pqklc8ehp365xvtru6a394e4wxz52nt5nurac3g7rq', regtest=True), 'bchreg:pqklc8ehp365xvtru6a394e4wxz52nt5nurac3g7rq')
def to_cash_addr(addr): return convert.to_cash_address(addr)[12:] # remove "bitcoincash:" prefix