예제 #1
0
    def get_wallet(configuration):
        """
        Get account address and private key from default keystore location
        :param configuration: loaded configuration file instance
        :return: account object
        """
        address = Wallet(configuration).get_address()
        pub_key = Wallet(configuration).get_public_key()

        return address, pub_key
예제 #2
0
    def new_wallet(configuration, password):
        """
        Create new wallet account and save encrypted keystore
        :param configuration: loaded configuration file instance
        :param password: set password from keystore and used also as entropy for CSPRNG
        :return: created wallet object and saved keystore path
        """
        wallet = Wallet(configuration).create(password)
        wallet.save_keystore(password)

        return wallet
예제 #3
0
    def restore_wallet(configuration, mnemonic_sentence, passphrase):
        """
        Create new wallet account and save encrypted keystore
        :param configuration: loaded configuration file instance
        :param mnemonic_sentence: user's mnemonic sentence to restore wallet
        :param password: set password from keystore and used also as entropy for CSPRNG
        :return: restored wallet object and saved keystore path
        """
        wallet = Wallet(configuration).restore(mnemonic_sentence, passphrase)
        wallet.save_keystore(passphrase)

        return wallet
예제 #4
0
 def get_balance(configuration, token_symbol=None):
     """
     Get balance from account address.
     :param configuration: loaded configuration file instance
     :param token_symbol: None for ETH, ERC20 symbol for other tokens
     :return:
     """
     wallet_address = Wallet(configuration).get_address()
     if token_symbol is None:
         balance = Wallet(configuration).get_balance(wallet_address)
     else:
         contract_address = configuration.contracts[token_symbol]
         contract = Contract(configuration, contract_address)
         balance = contract.get_balance(wallet_address)
     return balance, wallet_address
예제 #5
0
 def get_balance(configuration, token_symbol=None):
     """
     Get balance from account address.
     :param configuration: loaded configuration file instance
     :param token_symbol: None for ETH, ERC20 symbol for other tokens
     :return:
     """
     wallet_address = Wallet(configuration).get_address()
     if token_symbol is None:
         balance = Wallet(configuration).get_balance(wallet_address)
     else:
         try:  # check if token is added to the wallet
             contract_address = configuration.contracts[token_symbol]
         except KeyError:
             raise ERC20NotExistsException()
         contract = Contract(configuration, contract_address)
         balance = contract.get_balance(wallet_address)
     return balance, wallet_address
예제 #6
0
    def get_private_key(configuration, keystore_password):
        """
        Get account private key from default keystore location
        :param configuration: loaded configuration file instance
        :param keystore_password: user password from keystore
        :return: account object
        """
        wallet = Wallet(configuration).load_keystore(keystore_password)

        return wallet
예제 #7
0
def test_lengths(configuration):
    wallet = Wallet(configuration)
    wallet.create('eXtR4 EntroPy Str1Ng')

    # check length of private key
    assert len(wallet.get_private_key()) == 32

    # check length of public key
    public_key_bytes = decode_hex(wallet.get_public_key())
    assert len(public_key_bytes) == 64

    # check length of address
    address_bytes = decode_hex(wallet.get_address())
    assert len(address_bytes) == 20
예제 #8
0
def test_from_seed():

    wallet = Wallet()
    wallet.from_seed(seed=SEED)

    wallet.from_path("m/44'/60'/0'/0/0'")

    assert wallet.entropy() is None
    assert wallet.mnemonic() is None
    assert wallet.language() is None
    assert wallet.passphrase() is None
    assert wallet.seed() == "bd421c81fbbb1cea7910851857817ac18f1fce9b9577a3e732ad28ae8ba4e097b072c48e694e5053df5db" \
                            "8a86d5cbacbbfee02b42d12c554d06313a0dadacf6b"
    assert wallet.private_key(
    ) == "656905e908b7349a8a894dda3fe1d1792a5d3484a29175e318caa8bd8dbfb10e"
    assert wallet.public_key(
    ) == "03d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf"
    assert wallet.uncompressed() == \
        "d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf621eb61a050b753b6fb775e4a319aa15682df03d3" \
        "93ac3dc798c03f68a977355"
    assert wallet.compressed(
    ) == "03d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf"
    assert wallet.wallet_import_format(
    ) == "Kzcqd9d9jTzbeh7bNSjGkqQhNNFXnPT7gWopsLSuYbP3MEUAwwJC"
    assert wallet.finger_print() == "f91947eb"
    assert wallet.chain_code(
    ) == "d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef"
    assert wallet.path() == "m/44'/60'/0'/0/0'"
    assert wallet.address() == "0x9A610e8A2B40d010C9804451742233E182052851"

    assert wallet.extended_key(private_key=True, encoded=False) == \
        "0488ade40589afb94b80000000d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef00656905e908b73" \
        "49a8a894dda3fe1d1792a5d3484a29175e318caa8bd8dbfb10e"
    assert wallet.extended_key(private_key=False, encoded=False) == \
        "0488b21e0589afb94b80000000d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef03d9ce6ac4d32b2" \
        "b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf"
    assert wallet.extended_key(private_key=True, encoded=True) == \
        "xprvA3SPJ3k2vNjT7Fa3V6dg8vEieXud4ARAhLwFd4GM6i4TxsjADB4wrm2AzhcYjc5nSEkXB9EX4kuGeZS4v9Ut2PNpZdAR9zKvqiBFA" \
        "sqGrqv"
    assert wallet.extended_key(private_key=False, encoded=True) == \
        "xpub6GRjhZGvkkHkKjeWb8AgW4BTCZk7Td924ZrrRSfxf3bSqg4JkiPCQZLer1UKXzncTRrVvy5Lpc9SQNjJPqjoiMLRjqzPnYiAnbXx2" \
        "12kVLC"

    assert wallet.dumps() == {
        "entropy": None,
        "mnemonic": None,
        "language": None,
        "passphrase": None,
        "seed":
        "bd421c81fbbb1cea7910851857817ac18f1fce9b9577a3e732ad28ae8ba4e097b072c48e694e5053df5db8a86d5cbacbbfee02b42d12c554d06313a0dadacf6b",
        "root_private_key":
        "5464f216361795edff8cdde60381fb52d9dc2b67a5fa1307caadb5ef5a041df192d4e95bbb37efcfad579f3319ab685b4aae0a448eddde606e6d3b0f0c6d5f57",
        "root_public_key":
        "8458cbbf8183c95f480b5b2d06f7faa9993e946e2bb9e55f9d7a033bbc8bcbeaeae6bab68b074725ca4efdcbc0986de0384f192cae4c6184fe1f3c4523252824",
        "uncompressed":
        "d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf621eb61a050b753b6fb775e4a319aa15682df03d393ac3dc798c03f68a977355",
        "compressed":
        "03d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf",
        "chain_code":
        "d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef",
        "private_key":
        "656905e908b7349a8a894dda3fe1d1792a5d3484a29175e318caa8bd8dbfb10e",
        "public_key":
        "03d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf",
        "wif": "Kzcqd9d9jTzbeh7bNSjGkqQhNNFXnPT7gWopsLSuYbP3MEUAwwJC",
        "finger_print": "f91947eb",
        "path": "m/44'/60'/0'/0/0'",
        "address": "0x9A610e8A2B40d010C9804451742233E182052851",
        "serialized": {
            "private_key_hex":
            "0488ade40589afb94b80000000d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef00656905e908b7349a8a894dda3fe1d1792a5d3484a29175e318caa8bd8dbfb10e",
            "public_key_hex":
            "0488b21e0589afb94b80000000d7b70a1271342a03662b93112c388662b7e96714913c358e0dd3db57702259ef03d9ce6ac4d32b2b711016d4eddf3c28c2169e2f5a393a59569f9232ce21ec2fdf",
            "private_key_base58":
            "xprvA3SPJ3k2vNjT7Fa3V6dg8vEieXud4ARAhLwFd4GM6i4TxsjADB4wrm2AzhcYjc5nSEkXB9EX4kuGeZS4v9Ut2PNpZdAR9zKvqiBFAsqGrqv",
            "public_key_base58":
            "xpub6GRjhZGvkkHkKjeWb8AgW4BTCZk7Td924ZrrRSfxf3bSqg4JkiPCQZLer1UKXzncTRrVvy5Lpc9SQNjJPqjoiMLRjqzPnYiAnbXx212kVLC"
        }
    }

    with pytest.raises(
            ValueError,
            match="Bad path, please insert like this type of path \"m/0'/0\"! "
    ):
        assert wallet.from_path("meherett")

    with pytest.raises(ValueError,
                       match="Bad index, Please import only integer number!"):
        assert wallet.from_index("meherett")
예제 #9
0
    def send_transaction(
        configuration,
        keystore_password,
        to_address,
        value,
        token_symbol=None,
        gas_price_speed=20  # MetaMask default transaction speedup is gasPrice*10
    ):
        """
        Sign and send transaction
        :param configuration: loaded configuration file instance
        :param keystore_password: password from encrypted keystore with private key for transaction sign
        :param to_address: address in hex string where originator's funds will be sent
        :param value: amount of funds to send in ETH or token defined in token_symbol
        :param token_symbol: None for ETH, ERC20 symbol for other tokens transaction
        :param gas_price_speed: gas price will be multiplied with this number to speed up transaction
        :return: tuple of transaction hash and transaction cost
        """
        # my MetaMask address: 0xAAD533eb7Fe7F2657960AC7703F87E10c73ae73b
        wallet = Wallet(configuration).load_keystore(keystore_password)
        w3 = Infura().get_web3()
        transaction = Transaction(account=wallet.get_account(), w3=w3)

        # check if value to send is possible to convert to the number
        try:
            float(value)
        except ValueError:
            raise InvalidValueException()

        if token_symbol is None:  # create ETH transaction dictionary
            tx_dict = transaction.build_transaction(
                to_address=to_address,
                value=Web3.toWei(value, "ether"),
                gas=
                21000,  # fixed gasLimit to transfer ether from one EOA to another EOA (doesn't include contracts)
                gas_price=w3.eth.gasPrice * gas_price_speed,
                # be careful about sending more transactions in row, nonce will be duplicated
                nonce=w3.eth.getTransactionCount(wallet.get_address()),
                chain_id=configuration.network)
        else:  # create ERC20 contract transaction dictionary
            try:  # check if token is added to the wallet
                contract_address = configuration.contracts[token_symbol]
            except KeyError:
                raise ERC20NotExistsException()
            contract = Contract(configuration, contract_address)
            erc20_decimals = contract.get_decimals()
            token_amount = int(float(value) * (10**erc20_decimals))
            data_for_contract = Transaction.get_tx_erc20_data_field(
                to_address, token_amount)

            # check whether there is sufficient ERC20 token balance
            erc20_balance, _ = WalletAPI.get_balance(configuration,
                                                     token_symbol)
            if float(value) > erc20_balance:
                raise InsufficientERC20FundsException()

            # calculate how much gas I need, unused gas is returned to the wallet
            estimated_gas = w3.eth.estimateGas({
                'to': contract_address,
                'from': wallet.get_address(),
                'data': data_for_contract
            })

            tx_dict = transaction.build_transaction(
                to_address=
                contract_address,  # receiver address is defined in data field for this contract
                value=
                0,  # amount of tokens to send is defined in data field for contract
                gas=estimated_gas,
                gas_price=w3.eth.gasPrice * gas_price_speed,
                # be careful about sending more transactions in row, nonce will be duplicated
                nonce=w3.eth.getTransactionCount(wallet.get_address()),
                chain_id=configuration.network,
                data=data_for_contract)

        # check whether to address is valid checksum address
        if not Web3.isChecksumAddress(to_address):
            raise InvalidAddress()

        # check whether there is sufficient eth balance for this transaction
        balance, _ = WalletAPI.get_balance(configuration)
        transaction_const_wei = tx_dict['gas'] * tx_dict['gasPrice']
        transaction_const_eth = w3.fromWei(transaction_const_wei, 'ether')
        if token_symbol is None:
            if (transaction_const_eth + Decimal(value)) > balance:
                raise InsufficientFundsException()
        else:
            if transaction_const_eth > balance:
                raise InsufficientFundsException()

        # send transaction
        tx_hash = transaction.send_transaction(tx_dict)

        print('Pending', end='', flush=True)
        while True:
            tx_receipt = w3.eth.getTransactionReceipt(tx_hash)
            if tx_receipt is None:
                print('.', end='', flush=True)
                time.sleep(1)
            else:
                print('\nTransaction mined!')
                break

        return tx_hash, transaction_const_eth
예제 #10
0
def test_addresses(configuration):
    wallet = Wallet(configuration)
    wallet.create('eXtR4 EntroPy Str1Ng')
    assert Web3.isAddress(wallet.get_address())
    assert Web3.isChecksumAddress(wallet.get_address())
예제 #11
0
def test_from_private_key():

    wallet = Wallet()
    wallet.from_root_private_key(root_private_key=ROOT_PRIVATE_KEY)

    wallet.from_index(44, harden=True)
    wallet.from_index(60, harden=True)
    wallet.from_index(0, harden=True)
    wallet.from_index(0)
    wallet.from_index(0, harden=True)

    assert wallet.entropy() is None
    assert wallet.mnemonic() is None
    assert wallet.language() is None
    assert wallet.passphrase() is None
    assert wallet.seed() is None
    assert wallet.private_key() == "678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0"
    assert wallet.public_key() == "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f"
    assert wallet.uncompressed() == \
        "df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f1e4f78a8cae1daf5dd1a716a96475b16" \
        "dcfb455e7d97fe75dd8f1f8ea5cc0a41"
    assert wallet.compressed() == "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f"
    assert wallet.wallet_import_format() == "KzgzzJkyzqcy8bLJDPLwXV5VmJER3f35q9zyAgSdMLn6aqMovQ66"
    assert wallet.finger_print() == "2004e94c"
    assert wallet.chain_code() == "67a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def287754"
    assert wallet.path() == "m/44'/60'/0'/0/0'"
    assert wallet.address() == "0xAaB4E88BCa0d7C1e40CE540b9642558d6f9a3a05"

    assert wallet.extended_key(private_key=True, encoded=False)
    assert wallet.extended_key(private_key=False, encoded=False)
    assert wallet.extended_key(private_key=True, encoded=True)
    assert wallet.extended_key(private_key=False, encoded=True)

    assert wallet.dumps() == {
        "entropy": None,
        "mnemonic": None,
        "language": None,
        "passphrase": None,
        "seed": None,
        "root_private_key": "f7239ecece685b42e768a3b3d5f8f67946e6f8e5f008a46fb80d34a69977be9a93d3aaf6c13639763807811805101ccab1ef09774e71afa028847dadfb0232e0",
        "root_public_key": "222d5011dfc66eabaa4d994ee66754a54eac0cf2633e4c9920abb7ba94ab4b7cb18aed261ccdd9d50e2bd2ca6a776d826201e1b1b0d953fae75f4da1167337e7",
        "uncompressed": "df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f1e4f78a8cae1daf5dd1a716a96475b16dcfb455e7d97fe75dd8f1f8ea5cc0a41",
        "compressed": "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
        "chain_code": "67a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def287754",
        "private_key": "678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0",
        "public_key": "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
        "wif": "KzgzzJkyzqcy8bLJDPLwXV5VmJER3f35q9zyAgSdMLn6aqMovQ66",
        "finger_print": "2004e94c",
        "path": "m/44'/60'/0'/0/0'",
        "address": "0xAaB4E88BCa0d7C1e40CE540b9642558d6f9a3a05",
        "serialized": {
            "private_key_hex": "0488ade405f450d7af8000000067a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def28775400678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0",
            "public_key_hex": "0488b21e05f450d7af8000000067a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def28775403df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
            "private_key_base58": "xprvA4Dqp8w5LcQejoog9rci7sadBJetitNj1wvbG7uHLLkSxoFhkzVnZ7A8Z6Kz4VRMpFSJ2Kct9KFf8uVpuWiqU9vBrkh9w6dVfThmF4RUxHV",
            "public_key_base58": "xpub6HDCDeTyAyxwxHt9Ft9iV1XMjLVP8M6aPArC4WJttgHRqbarJXp36uUcQQDJwBK3GEhKy7cbV1Fs4UoRDRpbhTFRZmPJ3coUuenN2TARncR"
        }
    }

    assert wallet.clean_derivation()
    assert wallet.path() is None
예제 #12
0
def test_from_mnemonic():

    wallet = Wallet()
    wallet.from_mnemonic(mnemonic=MNEMONIC,
                         passphrase=PASSPHRASE,
                         language=LANGUAGE)

    wallet.from_index(44, harden=True)
    wallet.from_index(60, harden=True)
    wallet.from_index(0, harden=True)
    wallet.from_index(0)
    wallet.from_index(0, harden=True)

    assert wallet.entropy() is None
    assert wallet.mnemonic() == \
        "indicate warm sock mistake code spot acid ribbon sing over taxi toast"
    assert wallet.language() == "english"
    assert wallet.passphrase() is None
    assert wallet.seed() == "baff3e1fe60e1f2a2d840d304acc98d1818140c79354a353b400fb019bfb256bc392d7aa9047adff1f14b" \
                            "ce0342e14605c6743a6c08e02150588375eb2eb7d49"
    assert wallet.private_key(
    ) == "678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0"
    assert wallet.public_key(
    ) == "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f"
    assert wallet.uncompressed() == "df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f1e4f78a8cae1d" \
                                    "af5dd1a716a96475b16dcfb455e7d97fe75dd8f1f8ea5cc0a41"
    assert wallet.compressed(
    ) == "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f"
    assert wallet.wallet_import_format(
    ) == "KzgzzJkyzqcy8bLJDPLwXV5VmJER3f35q9zyAgSdMLn6aqMovQ66"
    assert wallet.finger_print() == "2004e94c"
    assert wallet.chain_code(
    ) == "67a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def287754"
    assert wallet.path() == "m/44'/60'/0'/0/0'"
    assert wallet.address() == "0xAaB4E88BCa0d7C1e40CE540b9642558d6f9a3a05"

    assert wallet.extended_key(private_key=True, encoded=False) == "0488ade405f450d7af8000000067a537696eecbfdd5755" \
                                                                   "734eee16dca622e62bb3c98f66db89cad93def28775400" \
                                                                   "678d12447649cc9eeede87562069c2ff1524f31df025f5" \
                                                                   "21be255d4a6c8eaed0"
    assert wallet.extended_key(private_key=False, encoded=False) == "0488b21e05f450d7af8000000067a537696eecbfdd575" \
                                                                    "5734eee16dca622e62bb3c98f66db89cad93def287754" \
                                                                    "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8" \
                                                                    "074fc2415d78ed1a3e73f"
    assert wallet.extended_key(private_key=True, encoded=True) == "xprvA4Dqp8w5LcQejoog9rci7sadBJetitNj1wvbG7uHLLk" \
                                                                  "SxoFhkzVnZ7A8Z6Kz4VRMpFSJ2Kct9KFf8uVpuWiqU9vBrk" \
                                                                  "h9w6dVfThmF4RUxHV"
    assert wallet.extended_key(private_key=False, encoded=True) == "xpub6HDCDeTyAyxwxHt9Ft9iV1XMjLVP8M6aPArC4WJttg" \
                                                                   "HRqbarJXp36uUcQQDJwBK3GEhKy7cbV1Fs4UoRDRpbhTFR" \
                                                                   "ZmPJ3coUuenN2TARncR"

    assert wallet.dumps() == {
        "entropy": None,
        "mnemonic":
        "indicate warm sock mistake code spot acid ribbon sing over taxi toast",
        "language": "english",
        "passphrase": None,
        "seed":
        "baff3e1fe60e1f2a2d840d304acc98d1818140c79354a353b400fb019bfb256bc392d7aa9047adff1f14bce0342e14605c6743a6c08e02150588375eb2eb7d49",
        "root_private_key":
        "f7239ecece685b42e768a3b3d5f8f67946e6f8e5f008a46fb80d34a69977be9a93d3aaf6c13639763807811805101ccab1ef09774e71afa028847dadfb0232e0",
        "root_public_key":
        "222d5011dfc66eabaa4d994ee66754a54eac0cf2633e4c9920abb7ba94ab4b7cb18aed261ccdd9d50e2bd2ca6a776d826201e1b1b0d953fae75f4da1167337e7",
        "uncompressed":
        "df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f1e4f78a8cae1daf5dd1a716a96475b16dcfb455e7d97fe75dd8f1f8ea5cc0a41",
        "compressed":
        "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
        "chain_code":
        "67a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def287754",
        "private_key":
        "678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0",
        "public_key":
        "03df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
        "wif": "KzgzzJkyzqcy8bLJDPLwXV5VmJER3f35q9zyAgSdMLn6aqMovQ66",
        "finger_print": "2004e94c",
        "path": "m/44'/60'/0'/0/0'",
        "address": "0xAaB4E88BCa0d7C1e40CE540b9642558d6f9a3a05",
        "serialized": {
            "private_key_hex":
            "0488ade405f450d7af8000000067a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def28775400678d12447649cc9eeede87562069c2ff1524f31df025f521be255d4a6c8eaed0",
            "public_key_hex":
            "0488b21e05f450d7af8000000067a537696eecbfdd5755734eee16dca622e62bb3c98f66db89cad93def28775403df79315f83cfeaadbd88bfc0033367ebd2ca7e08df8074fc2415d78ed1a3e73f",
            "private_key_base58":
            "xprvA4Dqp8w5LcQejoog9rci7sadBJetitNj1wvbG7uHLLkSxoFhkzVnZ7A8Z6Kz4VRMpFSJ2Kct9KFf8uVpuWiqU9vBrkh9w6dVfThmF4RUxHV",
            "public_key_base58":
            "xpub6HDCDeTyAyxwxHt9Ft9iV1XMjLVP8M6aPArC4WJttgHRqbarJXp36uUcQQDJwBK3GEhKy7cbV1Fs4UoRDRpbhTFRZmPJ3coUuenN2TARncR"
        }
    }

    with pytest.raises(ValueError, match=r".*12 word mnemonic.*"):
        wallet.from_mnemonic(mnemonic=MNEMONIC,
                             passphrase=PASSPHRASE,
                             language="chinese_traditional")

    assert wallet.from_mnemonic(mnemonic=MNEMONIC,
                                passphrase=PASSPHRASE,
                                language=None)

    with pytest.raises(ValueError, match=r"Invalid language, .*"):
        wallet.from_mnemonic(mnemonic=MNEMONIC,
                             passphrase=PASSPHRASE,
                             language="amharic")