def generate_keys(self): eth_btc_root_pub_key = get_root_key() eth_btc_root_key = BIP32Key.fromExtendedKey(eth_btc_root_pub_key, public=True) eth_btc_child_key = eth_btc_root_key.ChildKey(self.user.id) btc_address = eth_btc_child_key.Address() registration_btc_address(btc_address) eth_address = keys.PublicKey( eth_btc_child_key.K.to_string()).to_checksum_address().lower() duc_root_key = DucatusWallet.deserialize( ROOT_KEYS['ducatus']['public']) duc_address = duc_root_key.get_child(self.user.id, is_prime=False).to_address() ducx_root_pub_key = ROOT_KEYS['ducatusx']['public'] ducx_root_key = BIP32Key.fromExtendedKey(ducx_root_pub_key, public=True) ducx_child_key = ducx_root_key.ChildKey(self.user.id) ducx_address = keys.PublicKey( ducx_child_key.K.to_string()).to_checksum_address().lower() self.btc_address = btc_address self.eth_address = eth_address self.duc_address = duc_address self.ducx_address = ducx_address self.save()
def init_profile(user, is_social=False, metamask_address=None, lang='en'): m = hashlib.sha256() memo_str1 = generate_memo(m) # memo_str2 = generate_memo(m) # memo_str3 = generate_memo(m) memo_str4 = generate_memo(m) wish_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY, public=True) # eosish_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_EOSISH, public=True) # tron_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_TRON, public=True) swaps_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_SWAPS, public=True) btc_address1 = wish_key.ChildKey(user.id).Address() # btc_address2 = eosish_key.ChildKey(user.id).Address() # btc_address3 = tron_key.ChildKey(user.id).Address() btc_address4 = swaps_key.ChildKey(user.id).Address() eth_address1 = keys.PublicKey(wish_key.ChildKey( user.id).K.to_string()).to_checksum_address().lower() # eth_address2 = keys.PublicKey(eosish_key.ChildKey(user.id).K.to_string()).to_checksum_address().lower() # eth_address3 = keys.PublicKey(tron_key.ChildKey(user.id).K.to_string()).to_checksum_address().lower() eth_address4 = keys.PublicKey(swaps_key.ChildKey( user.id).K.to_string()).to_checksum_address().lower() Profile(user=user, is_social=is_social, metamask_address=metamask_address, lang=lang).save() create_wish_balance(user, eth_address1, btc_address1, memo_str1) # create_eosish_balance(user, eth_address2, btc_address2, memo_str2) # create_tron_balance(user, eth_address3, btc_address3, memo_str3) create_swaps_balance(user, eth_address4, btc_address4, memo_str4) registration_btc_address(btc_address1) # registration_btc_address(btc_address2) # registration_btc_address(btc_address3) registration_btc_address(btc_address4)
def generate(cls, xprv=None, prv=None, seed=None, child=None, username=None): mnemonic = Mnemonic('english') # generate 12 word mnemonic seed if not seed and not xprv and not prv: seed = mnemonic.generate(256) private_key = None if seed: # create bitcoin wallet entropy = mnemonic.to_entropy(seed) key = BIP32Key.fromEntropy(entropy) private_key = key.PrivateKey().hex() extended_key = key.ExtendedKey() else: raise Exception('No Seed') if prv: private_key = PrivateKey.from_hex(bytes.fromhex(prv)).to_hex() extended_key = '' if xprv: key = BIP32Key.fromExtendedKey(xprv) private_key = key.PrivateKey().hex() extended_key = key.ExtendedKey() if xprv and child: for x in child: key = key.ChildKey(int(x)) private_key = key.PrivateKey().hex() if not private_key: raise Exception('No key') return cls({ "seed": seed or '', "xprv": extended_key or '', "private_key": private_key, "wif": cls.generate_wif(private_key), "public_key": PublicKey.from_point(key.K.pubkey.point.x(), key.K.pubkey.point.y()).format().hex(), "address": str(key.Address()), "serve_host": "0.0.0.0", "serve_port": 8000, "use_pnp": True, "ssl": False, "origin": '', "polling": 0, "post_peer": False, # "public_ip": "", # TODO "peer_host": "", "peer_port": 8000, "web_server_host": "0.0.0.0", "web_server_port": 5000, "peer": "http://localhost:8000", "callbackurl": "http://0.0.0.0:5000/create-relationship", "fcm_key": "", "database": "yadacoin", "site_database": "yadacoinsite", "mongodb_host": "localhost", "mixpanel": "", "username": username or '', "network": "mainnet" })
def init_profile(user, is_social=False, metamask_address=None, lang='en', swaps=False): m = hashlib.sha256() memo_str1 = generate_memo(m) # memo_str2 = generate_memo(m) # memo_str3 = generate_memo(m) memo_str4 = generate_memo(m) memo_str5 = generate_memo(m) # memo_str6 = generate_memo(m) wish_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY, public=True) # eosish_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_EOSISH, public=True) # tron_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_TRON, public=True) swaps_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_SWAPS, public=True) protector_key = BIP32Key.fromExtendedKey(ROOT_PUBLIC_KEY_PROTECTOR, public=True) btc_address1 = wish_key.ChildKey(user.id).Address() # btc_address2 = eosish_key.ChildKey(user.id).Address() # btc_address3 = tron_key.ChildKey(user.id).Address() btc_address4 = swaps_key.ChildKey(user.id).Address() btc_address5 = protector_key.ChildKey(user.id).Address() # btc_address6 = swaps_key.ChildKey(user.id).Address() eth_address1 = keys.PublicKey(wish_key.ChildKey( user.id).K.to_string()).to_checksum_address().lower() # eth_address2 = keys.PublicKey(eosish_key.ChildKey(user.id).K.to_string()).to_checksum_address().lower() # eth_address3 = keys.PublicKey(tron_key.ChildKey(user.id).K.to_string()).to_checksum_address().lower() eth_address4 = keys.PublicKey(swaps_key.ChildKey( user.id).K.to_string()).to_checksum_address().lower() eth_address5 = keys.PublicKey( protector_key.ChildKey( user.id).K.to_string()).to_checksum_address().lower()
def create_fake_transaction(self, inputs, outputs, payload, key: BIP32Key): return FakeTransaction(header=FakeTransactionHeader( batcher_public_key=key.PublicKey().hex(), dependencies=[], family_name="datahub", family_version="0.1", inputs=inputs, outputs=outputs, signer_public_key=key.PublicKey().hex()), payload=payload)
def rootkey_from_seed(seed, network): if network == 'bitcoin' or network == 'ethereum': xprv = BIP32Key.fromEntropy(seed).ExtendedKey() elif network == 'bitcoin-testnet': xprv = BIP32Key.fromEntropy(seed, testnet=True).ExtendedKey() else: print("network should not be" + network) sys.exit( "Wrong Network : should be ethereum or bitcoin or bitcoin-testnet!" ) rootkey = BIP32Key.fromExtendedKey(xprv) return rootkey
def subkey(index): qtctl_env = os.environ.copy() qtctl_env["QTCTL_KEY"] = "xprv9v3URixxtyRbDyys2zmY7xxtt2NvjpsdR3DHu7djw9AckBowqBFuSDamhVpn127WDfcbsGbSwqLayFueXEPrpyPTqMNbJ6XCnS7obNyDsyn" qtctl_env["QTCTL_ADDRESSVERSION"] = "0" ex_key = BIP32Key.fromExtendedKey(qtctl_env["QTCTL_KEY"]) key = ex_key.ChildKey(int(index)) child_key = BIP32Key.fromExtendedKey(key.ExtendedKey()) private_key = child_key.PrivateKey().hex() public_key = child_key.PublicKey().hex() address = str(P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(public_key))) return {'public_key': public_key, 'index': index, "private_key": private_key, 'address': address}
def entropy2prvhex(entropy, derivation_path): """Entropy Bytes -> Private Key Hex""" from bip32utils import BIP32Key, BIP32_HARDEN assert isinstance(derivation_path, str), 'str_ should be str' path_list = derivation_path.split('/') assert path_list[0] == 'm', 'Derivation path should start with char "m"' xkey = BIP32Key.fromEntropy(entropy).ExtendedKey() key = BIP32Key.fromExtendedKey(xkey) for path in path_list[1:]: if path[-1] == "'": key = key.ChildKey(int(path[:-1]) + BIP32_HARDEN) else: key = key.ChildKey(int(path)) return key.PrivateKey().hex()
def __init__(self, xpub): self.addresses = [] self.transactions = [] self.gap = 10 self.acc_node = BIP32Key.fromExtendedKey(xpub) self.ext_node = self.acc_node.ChildKey(0) self.int_node = self.acc_node.ChildKey(1)
def key(self): """ Returns the ledger key for this meteringpoint. :rtype: BIP32Key """ return BIP32Key.fromExtendedKey(self.ledger_extended_key)
def test_transfer_ggo_no_src_ggo(self): key = BIP32Key.fromEntropy( "the_valid_key_that_owns_the_specific_ggo".encode()) ggo_src = generate_address(AddressPrefix.GGO, key.PublicKey()) ggo_dst = 'ggonextc37509b1de4a7f9f1c59e0efc2ed285e7c96c29d5271edd8b4c2714e3c8979c' context = MockContext(states={}) payload = class_schema(SplitGGORequest)().dumps( SplitGGORequest(origin=ggo_src, parts=[ SplitGGOPart(address="split1_add", amount=10), SplitGGOPart(address="split2_add", amount=20) ])).encode('utf8') transaction = self.create_fake_transaction(inputs=[ggo_src, ggo_dst], outputs=[ggo_src, ggo_dst], payload=payload, key=key) with self.assertRaises(InvalidTransaction) as invalid_transaction: SplitGGOTransactionHandler().apply(transaction, context) self.assertEqual(str(invalid_transaction.exception), f'Address "{ggo_src}" does not contain a valid GGO.')
def derive_address(list_of_mnemonics): """ :param list_of_mnemonics: list of unique mnemonic phrases with valid checksums """ addresses = {} print("\nDeriving addresses") for possibility in list_of_mnemonics: str_poss = ' '.join(possibility) seed = bip39.seed_from_mnemonic( str_poss, "") # Converting mnemonic to BIP39 Seed key = BIP32Key.fromEntropy(seed) # Converting to BIP32 Root Key account_number = 0 # This variable can be changed to attain a different derivation path i = 0 # This variable can be changed to attain a different derivation path # For the following account derivation `BIP32_HARDEN` can be simply removed to access unhardened addresses addr = (key.ChildKey(49 + BIP32_HARDEN).ChildKey( 0 + BIP32_HARDEN).ChildKey(account_number + BIP32_HARDEN).ChildKey( 0).ChildKey(i).P2WPKHoP2SHAddress()) addresses[addr] = str_poss print(f"\n{len(addresses)} addresses derived.") for address in addresses: print(f"Checking address {address}") if blockcypher.get_total_num_transactions(address) > 0: print( f'\nThe correct address is: {address}\nThe correct mnemonic is: \n{addresses[addr]}' ) quit()
def mnemonic_to_key(mnemonic): # Mnemonic to seed. No custom passphrase supported mnemonic = normalize('NFKD', ' '.join(mnemonic)) seed = PBKDF2(mnemonic, u'mnemonic', iterations=2048, macmodule=hmac, digestmodule=sha512).read(64) # Seed to key secret, chain = seed[:32], seed[32:] key = BIP32Key(secret=secret, chain=chain, depth=0, index=0, fpr=b'\0\0\0\0', public=False, testnet=rein.testnet) return key
def get_bip32_addrs(xpub): acc_node = BIP32Key.fromExtendedKey(xpub) i = 0 while True: addr_node = acc_node.ChildKey(i) child_address = addr_node.Address() yield i, child_address i = i + 1
def getPrivateKey(self, seed, account, change, address_index): m = BIP32Key.fromEntropy(Mnemonic.to_seed(seed)) m = m.ChildKey(44 + BIP32_HARDEN) m = m.ChildKey(195 + BIP32_HARDEN) m = m.ChildKey(account + BIP32_HARDEN) m = m.ChildKey(change) m = m.ChildKey(address_index) return m
async def post(self): key_or_wif = self.get_secure_cookie("key_or_wif") if not key_or_wif and self.jwt.get('key_or_wif') != 'true': return self.render_as_json({'error': 'not authorized'}) args = json.loads(self.request.body) if not args.get('uid'): return self.render_as_json({ "error": True, "message": "no user account provided" }) keyhash = hashlib.sha256( TU.generate_deterministic_signature( self.config, 'child_wallet').encode()).hexdigest() exkey = BIP32Key.fromExtendedKey(self.config.xprv) last_child_key = self.config.mongo.db.child_keys.find( {'signature': keyhash}, sort=[('inc', -1)]) inc = last_child_key.count() + 1 key = exkey.ChildKey(inc) child_key = BIP32Key.fromExtendedKey(key.ExtendedKey()) child_key = child_key.ChildKey(inc) public_key = child_key.PublicKey().hex() address = str( P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(public_key))) private_key = child_key.PrivateKey().hex() wif = self.to_wif(private_key) await self.config.mongo.async_db.child_keys.insert_one({ 'account': args.get('uid'), 'inc': inc, 'extended': child_key.ExtendedKey(), 'public_key': public_key, 'address': address, 'private_key': private_key, 'wif': wif, 'signature': keyhash }) return self.render_as_json({"address": address})
def derive_child(root: BIP32Key, account: int = 0, index: int = 0, coin_type: int = LUNA_COIN_TYPE): # HD Path: 44'/330'/<acc>'/0/<idx> return (root.ChildKey(44 + BIP32_HARDEN).ChildKey( coin_type + BIP32_HARDEN).ChildKey(account + BIP32_HARDEN).ChildKey(0).ChildKey(index))
def init_from_entropy(self, entropy): entropy = entropy.encode() key = BIP32Key.fromEntropy(entropy, public=False) self.private_key = key.PrivateKey() self.public_key = key.PublicKey() self.uncompressed_public_key = decode_hex( Bip32Keys.to_uncompressed_public_key(self.get_public_key()))[0]
def generate_keys(self): eth_btc_root_pub_key = get_root_key() eth_btc_root_key = BIP32Key.fromExtendedKey(eth_btc_root_pub_key, public=True) eth_btc_child_key = eth_btc_root_key.ChildKey(self.id) btc_address = eth_btc_child_key.Address() eth_address = keys.PublicKey(eth_btc_child_key.K.to_string()).to_checksum_address().lower() self.btc_address = btc_address self.eth_address = eth_address self.save()
def derive_child( root: bip32utils.BIP32Key, account: int = 0, index: int = 0 ) -> bip32utils.BIP32Key: return ( root.ChildKey(44 + bip32utils.BIP32_HARDEN) .ChildKey(1217 + bip32utils.BIP32_HARDEN) .ChildKey(account + bip32utils.BIP32_HARDEN) .ChildKey(0) .ChildKey(index) )
def process(data, lst, mnemo): code = mnemo.to_mnemonic(unhexlify(data)) _seed = Mnemonic.to_seed(code, passphrase='TREZOR') xprv = BIP32Key.fromEntropy(_seed).ExtendedKey() _seed = b2h(_seed) print('input : %s (%d bits)' % (data, len(data) * 4)) print('mnemonic : %s (%d words)' % (code, len(code.split(' ')))) print('seed : %s (%d bits)' % (_seed, len(_seed) * 4)) print('xprv : %s\n' % xprv) lst.append((data, code, _seed, xprv))
def seed_to_key(seed): secret, chain = seed[:32], seed[32:] key = BIP32Key(secret=secret, chain=chain, depth=0, index=0, fpr=b'\0\0\0\0', public=False, testnet=rein.testnet) return key
def createWallet(entropy): I = hmac.new("Bitcoin seed", entropy, hashlib.sha512).digest() Il, Ir = I[:32], I[32:] key = BIP32Key(secret=Il, chain=Ir, depth=0, index=0, fpr='\0\0\0\0', public=False) return key
def process(data, lst): code = mnemo.to_mnemonic(unhexlify(data)).decode() seed = Mnemonic.to_seed(code, passphrase='TREZOR') xprv = BIP32Key.fromEntropy(seed).ExtendedKey() seed = b2h(seed) print('input : %s (%d bits)' % (data, len(data) * 4)) print('mnemonic : %s (%d words)' % (code, len(code.split(' ')))) print('seed : %s (%d bits)' % (seed, len(seed) * 4)) print('xprv : %s' % xprv) print() lst.append((data, code, seed, xprv))
def process(data, lst): code = mnemo.to_mnemonic(unhexlify(data)) seed = Mnemonic.to_seed(code, passphrase="TREZOR") xprv = BIP32Key.fromEntropy(seed).ExtendedKey() seed = b2h(seed) print("input : %s (%d bits)" % (data, len(data) * 4)) print("mnemonic : %s (%d words)" % (code, len(code.split(" ")))) print("seed : %s (%d bits)" % (seed, len(seed) * 4)) print("xprv : %s" % xprv) print() lst.append((data, code, seed, xprv))
def test_from_extended_key(self): extkey = 'xpub6BLBYTKDDbdgAmfVeZRE1VFTKCFtRv9CDkpUnSfrDiA3eN9NPPS8zLi4ykGgdQKoRvWhjnz6o1VffVGfjhdMnaby6Kmn8YLiJiCzuw8KugM' key = BIP32Key.fromExtendedKey(extkey) child = key.ChildKey(0).ChildKey(0) self.assertEqual('FjxiGJ7kkTHY1x3MBnZc9AHKFs9rRVUTKp', child.Address()) self.assertEqual('020d54f0c23eb2f16d319e0168a9c7dfea90454f234b0b81359339db44d005e12a', child.PublicKey().encode('hex')) child = key.ChildKey(0).ChildKey(1) self.assertEqual('FZgDwnt2MbPPBtxNRLuG4xSxEvCeG11znT', child.Address()) self.assertEqual('03e4e5e55b653cbe56555f31560df892b0d4ed967eae11754e6f35cedfc96e1fde', child.PublicKey().encode('hex'))
def to_private_key(word): ''' get private key from word! ''' #generate seed from mnemonic word by mnemonic package m = mnemonic.Mnemonic("english") #xprv=m.to_hd_master_key(m.to_seed(words)) ;the same with BIP32Key.fromEntropy(seed) seed = m.to_seed(word) #generate extended private key(xprv) from seed key = BIP32Key.fromEntropy(seed) xprv = BIP32Key.fromEntropy(seed).ExtendedKey() # redefined key with extended private key key = BIP32Key.fromExtendedKey(xprv) #get the first account private for derivation path m/44'/60'/0' x=key.ChildKey(44 + BIP32_HARDEN) \ .ChildKey(60 + BIP32_HARDEN) \ .ChildKey(0 + BIP32_HARDEN) \ .ChildKey(0) \ .ChildKey(0) \ .PrivateKey().hex() return x
def test__KeyGenerator__set_key_for_user_from_entropy(): # Arrange entropy = b'SomethingVeryRandomWithAMinimumLengthWhichIDontQuiteRememberRightNow' user = Mock() # Act KeyGenerator.set_key_for_user_from_entropy(user, entropy) # Assert assert user.master_extended_key == BIP32Key.fromEntropy( entropy).ExtendedKey()
def test_transfer_ggo_not_authorized(self): key_owner = BIP32Key.fromEntropy( "the_valid_key_that_owns_the_specific_ggo".encode()) key_criminal = BIP32Key.fromEntropy( "this_key_should_not_be_authorized".encode()) ggo_src = generate_address(AddressPrefix.GGO, key_owner.PublicKey()) ggo_dst = 'ggonextc37509b1de4a7f9f1c59e0efc2ed285e7c96c29d5271edd8b4c2714e3c8979c' ggo = GGO.get_schema().dumps( GGO(origin= 'meaaaa1c37509b1de4a7f9f1c59e0efc2ed285e7c96c29d5271edd8b4c2714e3c8979c', amount=30, begin=datetime(2020, 1, 1, 12, tzinfo=timezone.utc), end=datetime(2020, 1, 1, 13, tzinfo=timezone.utc), tech_type='T12412', fuel_type='F010101', sector='DK1', next=None)).encode('utf8') context = MockContext(states={ggo_src: ggo}) payload = class_schema(SplitGGORequest)().dumps( SplitGGORequest(origin=ggo_src, parts=[ SplitGGOPart(address="split1_add", amount=10), SplitGGOPart(address="split2_add", amount=20) ])).encode('utf8') transaction = self.create_fake_transaction(inputs=[ggo_src, ggo_dst], outputs=[ggo_src, ggo_dst], payload=payload, key=key_criminal) with self.assertRaises(InvalidTransaction) as invalid_transaction: SplitGGOTransactionHandler().apply(transaction, context) self.assertEqual(str(invalid_transaction.exception), 'Invalid key for GGO')
def __init__(self, entropy): # todo: init from private key entropy = entropy.encode() self.decode_hex = codecs.getdecoder("hex_codec") self.encode_hex = codecs.getencoder("hex_codec") key = BIP32Key.fromEntropy(entropy, public=False) private_key = key.PrivateKey() public_key = key.PublicKey() wif = key.WalletImportFormat() sk = SigningKey.from_string(string=private_key, curve=ecdsa.SECP256k1, hashfunc=sha256) vk = sk.get_verifying_key() #print(public_key) output = sha256(public_key).digest() #print(binascii.hexlify(output)) ripemd160 = hashlib.new('ripemd160') ripemd160.update(output) output = binascii.hexlify(ripemd160.digest()) #print(output) output = b'3A' + output # 3A is magic byte extended_ripmd160 = output #print(output) output = self.decode_hex(output)[0] output = sha256(output).digest() #print(binascii.hexlify(output)) output = sha256(output).hexdigest().encode() #print(binascii.hexlify(output)) checksum = output[:8] #print(checksum) output = extended_ripmd160 + checksum #print(output) output = self.decode_hex(output)[0] output = base58check.b58encode(output) #print(output) self.wif = wif self.private_key = private_key self.public_key = public_key self.uncompressed_public_key = vk.to_string() self.qtum_address = output
def main(): import binascii import sys if len(sys.argv) > 1: data = sys.argv[1] else: data = sys.stdin.readline().strip() data = binascii.unhexlify(data) m = Mnemonic('english') # example mnemonic print("Mnemonic generated from entropy " + m.to_mnemonic(data)) from bip32utils import BIP32Key print("\nExample mnemonic: " + "profit hood vibrant fiscal survey traffic quality rely soap fury helmet once") seed = m.to_seed("profit hood vibrant fiscal survey traffic quality rely soap fury helmet once") print("Seed " + seed.encode('hex')) key = BIP32Key.fromEntropy(seed) xprv = BIP32Key.fromEntropy(seed).ExtendedKey() print("Extended private key is " + xprv) # redefined key with extended private key key = BIP32Key.fromExtendedKey(xprv) from bip32utils import BIP32_HARDEN # first address for derivation path m/44'/0'/0' print(key.ChildKey(44 + BIP32_HARDEN) \ .ChildKey(0 + BIP32_HARDEN) \ .ChildKey(0 + BIP32_HARDEN) \ .ChildKey(0) \ .ChildKey(0) \ .Address()) # second address for derivation path m/44'/0'/0' print(key.ChildKey(44 + BIP32_HARDEN) \ .ChildKey(0 + BIP32_HARDEN) \ .ChildKey(0 + BIP32_HARDEN) \ .ChildKey(0) \ .ChildKey(1) \ .Address())
def create_wallet(self, backup_key): # check for existing wallet result = yield self.bitgo.wallet() for wallet in result["wallets"]: if result["wallets"][wallet]["label"] == "sputnik": raise MultiSigException("Wallet already exists.") # create a new key # TODO: allow testnet key = BIP32Key.fromEntropy("".join(map(chr, [random.getrandbits(8) for i in range(32)])), public=False) # TODO: save private key private = key.ExtendedKey(private=True, encoded=True) user_key = key.ExtendedKey(private=False, encoded=True) # create a new bitgo key result = yield self.bitgo.keychain("bitgo") bitgo_key = result["xpub"] # create the wallet keychains = [{"xpub":user_key}, {"xpub":backup_key}, {"xpub":bitgo_key}] yield self.bitgo.wallet(label="sputnik", m=2, n=3, keychains=keychains)
def get_wallet_from_xpub(xpub, no): return BIP32Key.fromExtendedKey(xpub).ChildKey(0).ChildKey(no).Address()