diff --git a/.travis.yml b/.travis.yml
index 7845927b0170ef046b99ff1324849c359361bf9b..07a9cfc861db5185e4e2f5f4583b35c193305132 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -58,7 +58,7 @@ before_install:
   - pip install --upgrade wheel
   # Set numpy version first, other packages link against it
   - pip install six nose coverage codecov pytest pytest-cov coveralls codacy-coverage parameterized secp256k1prp cryptography scrypt
-  - pip install pycryptodomex  pyyaml appdirs pylibscrypt tox diff_match_patch
+  - pip install pycryptodomex  pyyaml appdirs pylibscrypt tox diff_match_patch asn1
   - pip install ecdsa requests future websocket-client pytz six Click events prettytable click_shell
 
 script:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 6dd40c71ba68c9ce1d9781ee000ac0b194d61f9c..217ecf99a08e5f1de8be4c9e15be5cb0b6a7fe34 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,5 +1,15 @@
 Changelog
 =========
+0.23.7
+------
+* Fix update_account_jsonmetadata and add posting_json_metadata property to Account
+* Add Ledger Nano S support
+* beempy -u activates ledger signing
+* beempy -u listkeys shows pubkey from ledger
+* beempy -u listaccounts searches for accounts that have pubkey derived from attached ledger
+* beempy -u keygen creates pubkey lists that can be used for newaccount and changekeys
+* new option use_ledger and path for Hive
+
 0.23.6
 ------
 * beempy --key key_list.json command can be used to set keys in beempy without using the wallet.
diff --git a/README.rst b/README.rst
index 66334035cbc1bafcde9e4e87b556dce4db7ae9ec..7442115336183e2eeaed370f40e0589bf3823167 100644
--- a/README.rst
+++ b/README.rst
@@ -156,6 +156,12 @@ A command line tool is available. The help output shows the available commands:
 
     beempy --help
 
+Ledger support
+--------------
+For Ledger (Nano S) signing, the following package must be installed:
+
+    pip install ledgerblue
+
 Stand alone version of CLI tool beempy
 --------------------------------------
 With the help of pyinstaller, a stand alone version of beempy was created for Windows, OSX and linux.
diff --git a/appveyor.yml b/appveyor.yml
index c772261d829f652292cd25d7fefaed5370e305e9..e2736cc7f5ce5499877d0afaaa25e406f0f94fe4 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -52,7 +52,7 @@ install:
 - cmd: conda install --yes conda-build setuptools pip parameterized cryptography
 - cmd: conda install --yes pycryptodomex pyyaml pytest pytest-mock coverage mock appdirs pylibscrypt pywin32
 - cmd: pip install scrypt -U
-- cmd: conda install --yes ecdsa requests future websocket-client pytz six Click events prettytable pyinstaller click-shell
+- cmd: conda install --yes ecdsa requests future websocket-client pytz six Click events prettytable pyinstaller click-shell asn1
 
 
 build_script:
diff --git a/beem/account.py b/beem/account.py
index e67d44c4f66b4fd0b28920e14b3a574787c6536a..555ba88ef579fbdf7de973534e90ecdc5822a186 100644
--- a/beem/account.py
+++ b/beem/account.py
@@ -321,6 +321,12 @@ class Account(BlockchainObject):
             return {}
         return json.loads(self["json_metadata"])
 
+    @property
+    def posting_json_metadata(self):
+        if self["posting_json_metadata"] == '':
+            return {}
+        return json.loads(self["posting_json_metadata"])
+
     def print_info(self, force_refresh=False, return_str=False, use_table=False, **kwargs):
         """ Prints import information about the account
         """
@@ -2489,7 +2495,7 @@ class Account(BlockchainObject):
             metadata = json.dumps(metadata)
         elif not isinstance(metadata, str):
             raise ValueError("Profile must be a dict or string!")
-        op = operations.Account_update(
+        op = operations.Account_update2(
             **{
                 "account": account["name"],
                 "posting_json_metadata": metadata,
diff --git a/beem/blockchaininstance.py b/beem/blockchaininstance.py
index 3b220762d2f45b8c9c6fcaf20294df50cebd9f7d..f1bff90dd4715802e271a15b8afdba9455095b3f 100644
--- a/beem/blockchaininstance.py
+++ b/beem/blockchaininstance.py
@@ -170,6 +170,8 @@ class BlockChainInstance(object):
             :param bool use_sc2: When True, a steemconnect object is created. Can be used for broadcast
                 posting op or creating hot_links  (default is False)
             :param SteemConnect steemconnect: A SteemConnect object can be set manually, set use_sc2 to True
+            :param bool use_ledger: When True, a ledger Nano S is used for signing
+            :param str path: bip32 path from which the pubkey is derived, when use_ledger is True
 
         """
 
@@ -187,9 +189,13 @@ class BlockChainInstance(object):
         self.use_hs = bool(kwargs.get("use_hs", False))        
         self.blocking = kwargs.get("blocking", False)
         self.custom_chains = kwargs.get("custom_chains", {})
+        self.use_ledger = bool(kwargs.get("use_ledger", False))
+        self.path = kwargs.get("path", None)
 
         # Store config for access through other Classes
         self.config = get_default_config_storage()
+        if self.path is None:
+            self.path = self.config["default_path"]
 
         if not self.offline:
             self.connect(node=node,
diff --git a/beem/cli.py b/beem/cli.py
index 073d5bf5b0efba0dc4d06b365ed66f2f88a3a039..3199627455aa07b894f53103d46e089033d0bc96 100644
--- a/beem/cli.py
+++ b/beem/cli.py
@@ -80,6 +80,7 @@ availableConfigurationKeys = [
     "nodes",
     "password_storage",
     "client_id",
+    "default_path"
 ]
 
 
@@ -107,6 +108,8 @@ def prompt_flag_callback(ctx, param, value):
 def unlock_wallet(stm, password=None, allow_wif=True):
     if stm.unsigned and stm.nobroadcast:
         return True
+    if stm.use_ledger:
+        return True
     if not stm.wallet.locked():
         return True
     if len(stm.wallet.keys) > 0:
@@ -186,6 +189,10 @@ def node_answer_time(node):
     '--hive', '-h', is_flag=True, default=False, help="Connect to the Hive blockchain")
 @click.option(
     '--keys', '-k', help="JSON file that contains account keys, when set, the wallet cannot be used.")
+@click.option(
+    '--use-ledger', '-u', is_flag=True, default=False, help="Uses the ledger device Nano S for signing.")
+@click.option(
+    '--path', help="BIP32 path from which the keys are derived, when not set, default_path is used.")
 @click.option(
     '--token', '-t', is_flag=True, default=False, help="Uses a hivesigner/steemconnect token to broadcast (only broadcast operation with posting permission)")
 @click.option(
@@ -194,7 +201,7 @@ def node_answer_time(node):
 @click.option(
     '--verbose', '-v', default=3, help='Verbosity')
 @click.version_option(version=__version__)
-def cli(node, offline, no_broadcast, no_wallet, unsigned, create_link, steem, hive, keys, token, expires, verbose):
+def cli(node, offline, no_broadcast, no_wallet, unsigned, create_link, steem, hive, keys, use_ledger, path, token, expires, verbose):
 
     # Logging
     log = logging.getLogger(__name__)
@@ -246,6 +253,8 @@ def cli(node, offline, no_broadcast, no_wallet, unsigned, create_link, steem, hi
             use_hs=token,
             expiration=expires,
             hivesigner=sc2,
+            use_ledger=use_ledger,
+            path=path,
             debug=debug,
             num_retries=10,
             num_retries_call=3,
@@ -263,6 +272,8 @@ def cli(node, offline, no_broadcast, no_wallet, unsigned, create_link, steem, hi
             use_sc2=token,
             expiration=expires,
             steemconnect=sc2,
+            use_ledger=use_ledger,
+            path=path,
             debug=debug,
             num_retries=10,
             num_retries_call=3,
@@ -324,6 +335,8 @@ def set(key, value):
         stm.config["hs_api_url"] = value
     elif key == "oauth_base_url":
         stm.config["oauth_base_url"] = value
+    elif key == "default_path":
+        stm.config["default_path"] = value
     else:
         print("wrong key")
 
@@ -559,8 +572,10 @@ def config():
             t.add_row([key, stm.config[key]])
     node = stm.get_default_nodes()
     blockchain = stm.config["default_chain"]
+    ledger_path = stm.config["default_path"]
     nodes = json.dumps(node, indent=4)
     t.add_row(["default_chain", blockchain])
+    t.add_row(["default_path", ledger_path])
     t.add_row(["nodes", nodes])
     if "password_storage" not in availableConfigurationKeys:
         t.add_row(["password_storage", stm.config["password_storage"]])
@@ -721,7 +736,7 @@ def delkey(confirm, pub):
 
 @cli.command()
 @click.option('--import-word-list', '-l', help='Imports a BIP39 wordlist and derives a private and public key', is_flag=True, default=False)
-@click.option('--strength', '-s', help='Defines word list length for BIP39 (default = 256).', default=256)
+@click.option('--strength', help='Defines word list length for BIP39 (default = 256).', default=256)
 @click.option('--passphrase', '-p', help='Sets a BIP39 passphrase', is_flag=True, default=False)
 @click.option('--path', '-m', help='Sets a path for BIP39 key creations. When path is set, network, role, account_keys, account and sequence is not used')
 @click.option('--network', '-n', help='Network index, when using BIP39, 0 for steem and 13 for hive, (default is 13)', default=13)
@@ -742,8 +757,6 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
     stm = shared_blockchain_instance()
     if not account and import_password or create_password:
         account = stm.config["default_account"]
-    else:
-        account = 0
     if import_password:
         import_password = click.prompt("Enter password", confirmation_prompt=False, hide_input=True)
     elif create_password:
@@ -777,7 +790,41 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
         if wif > 0:
             t.add_row(["WIF itersions", wif])
             t.add_row(["Entered/created Password", import_password])
+    elif stm.use_ledger:
+        if stm.rpc is not None:
+            stm.rpc.rpcconnect()        
+        ledgertx = stm.new_tx()
+        ledgertx.constructTx()
+        if account is None:
+            account = 0
+        else:
+            account = int(account)
+        t = PrettyTable(["Key", "Value"])
+        t_pub = PrettyTable(["Key", "Value"])
+        t.align = "l"
+        t_pub.align = "l"
+        t.add_row(["Account sequence", account])
+        t.add_row(["Key sequence", sequence])
+        if account_keys and path is None:  
+            for role in ['owner', 'active', 'posting', 'memo']:
+                path = ledgertx.ledgertx.build_path(role, account, sequence)
+                pubkey = ledgertx.ledgertx.get_pubkey(path, request_screen_approval=False)
+                t_pub.add_row(["%s Public Key" % role, format(pubkey, "STM")])
+                t.add_row(["%s path" % role, path])               
+                pub_json[role] = format(pubkey, "STM")
+        else:
+            if path is None:
+                path = ledgertx.ledgertx.build_path(role, account, sequence)            
+            t.add_row(["Key role", role])
+            t.add_row(["path", path])
+            pubkey = ledgertx.ledgertx.get_pubkey(path, request_screen_approval=False)
+            t_pub.add_row(["Public Key", format(pubkey, "STM")])
+            pub_json[role] = format(pubkey, "STM")        
     else:
+        if account is None:
+            account = 0
+        else:
+            account = int(account)
         if import_word_list:
             n_words = click.prompt("Enter word list length or complete word list")
             if len(n_words.split(" ")) > 0:
@@ -822,8 +869,8 @@ def keygen(import_word_list, strength, passphrase, path, network, role, account_
         t.add_row(["Key sequence", sequence])   
         if account_keys and path is None:  
             for role in ['owner', 'active', 'posting', 'memo']:
-                mk.set_path_BIP48(network_index=network, role=role, account_sequence=account, key_sequence=sequence)
                 t.add_row(["%s Private Key" % role, str(mk.get_private())])
+                mk.set_path_BIP48(network_index=network, role=role, account_sequence=account, key_sequence=sequence)
                 t_pub.add_row(["%s Public Key" % role, format(mk.get_public(), "STM")])
                 t.add_row(["%s path" % role, mk.get_path()])               
                 pub_json[role] = format(mk.get_public(), "STM")
@@ -897,18 +944,35 @@ def deltoken(confirm, name):
 
 
 @cli.command()
-def listkeys():
+@click.option('--path', '-p', help='Set path (when using ledger)')
+@click.option('--ledger-approval', '-a', is_flag=True, default=False, help='When set, you can confirm the shown pubkey on your ledger.')
+def listkeys(path, ledger_approval):
     """ Show stored keys
+    
+    Can be used to receive and approve the pubkey obtained from the ledger
     """
     stm = shared_blockchain_instance()
     if stm.rpc is not None:
         stm.rpc.rpcconnect()
-    t = PrettyTable(["Available Key"])
-    t.align = "l"
-    for key in stm.wallet.getPublicKeys():
-        t.add_row([key])
-    print(t)
 
+    if stm.use_ledger:
+        if path is None:
+            path = stm.config["default_path"]
+        t = PrettyTable(["Available Key for %s" % path])
+        t.align = "l"        
+        ledgertx = stm.new_tx()
+        ledgertx.constructTx()
+        pubkey = ledgertx.ledgertx.get_pubkey(path, request_screen_approval=False)
+        t.add_row([str(pubkey)])
+        if ledger_approval:
+            print(t)
+            ledgertx.ledgertx.get_pubkey(path, request_screen_approval=True)
+    else:
+        t = PrettyTable(["Available Key"])
+        t.align = "l"        
+        for key in stm.wallet.getPublicKeys():
+            t.add_row([key])
+    print(t)
 
 @cli.command()
 def listtoken():
@@ -930,18 +994,50 @@ def listtoken():
 
 
 @cli.command()
-def listaccounts():
-    """Show stored accounts"""
+@click.option('--role', '-r', help='When set, limits the shown keys for this role')
+@click.option('--max-account-index', '-a', help='Set maximum account index to check pubkeys (only when using ledger)', default=5)
+@click.option('--max-sequence', '-s', help='Set maximum key sequence to check pubkeys (only when using ledger)', default=2)
+def listaccounts(role, max_account_index, max_sequence):
+    """Show stored accounts
+    
+    Can be used with the ledger to obtain all accounts that uses pubkeys derived from this ledger
+    """
     stm = shared_blockchain_instance()
     if stm.rpc is not None:
         stm.rpc.rpcconnect()
-    t = PrettyTable(["Name", "Type", "Available Key"])
-    t.align = "l"
-    for account in stm.wallet.getAccounts():
-        t.add_row([
-            account["name"] or "n/a", account["type"] or "n/a",
-            account["pubkey"]
-        ])
+
+    if stm.use_ledger:
+        t = PrettyTable(["Name", "Type", "Available Key", "Path"])
+        t.align = "l"        
+        ledgertx = stm.new_tx()
+        ledgertx.constructTx()
+        key_found = False
+        path = None
+        current_account_index = 0
+        current_key_index = 0
+        role_list = ["owner", "active", "posting", "memo"]
+        if role:
+            role_list = [role]
+        while not key_found and current_account_index < max_account_index:
+            for perm in role_list:
+                path = ledgertx.ledgertx.build_path(perm, current_account_index, current_key_index)
+                current_pubkey = ledgertx.ledgertx.get_pubkey(path)
+                account = stm.wallet.getAccountFromPublicKey(str(current_pubkey))
+                if account is not None:
+                    t.add_row([str(account), perm, str(current_pubkey), path])
+            if current_key_index < max_sequence:
+                current_key_index += 1
+            else:
+                current_key_index = 0
+                current_account_index += 1  
+    else:
+        t = PrettyTable(["Name", "Type", "Available Key"])
+        t.align = "l"        
+        for account in stm.wallet.getAccounts():
+            t.add_row([
+                account["name"] or "n/a", account["type"] or "n/a",
+                account["pubkey"]
+            ])
     print(t)
 
 
diff --git a/beem/storage.py b/beem/storage.py
index 33be4d0050a1fdf9567ddd9185001de43e8c6002..370a690e118bc8e7945cdc8e11f1964406283570 100644
--- a/beem/storage.py
+++ b/beem/storage.py
@@ -425,7 +425,8 @@ class Configuration(DataDir):
         "sc2_api_url": "https://api.steemconnect.com/api/",
         "oauth_base_url": "https://api.steemconnect.com/oauth2/",
         "hs_api_url": "https://hivesigner.com/api/",
-        "hs_oauth_base_url": "https://hivesigner.com/oauth2/"}
+        "hs_oauth_base_url": "https://hivesigner.com/oauth2/",
+        "default_path": "48'/13'/0'/0'/0'"}
 
     def __init__(self):
         super(Configuration, self).__init__()
diff --git a/beem/transactionbuilder.py b/beem/transactionbuilder.py
index 91143e22d3e57f3513160c693d1d934cab410726..8a928ed5703a05b37dff3c32a80007ef2b2f5b8c 100644
--- a/beem/transactionbuilder.py
+++ b/beem/transactionbuilder.py
@@ -13,6 +13,7 @@ from .steemconnect import SteemConnect
 from beembase.objects import Operation
 from beemgraphenebase.account import PrivateKey, PublicKey
 from beembase.signedtransactions import Signed_Transaction
+from beembase.ledgertransactions import Ledger_Transaction
 from beembase import transactions, operations
 from .exceptions import (
     InsufficientAuthorityError,
@@ -72,6 +73,8 @@ class TransactionBuilder(dict):
             self._require_reconstruction = False
         else:
             self._require_reconstruction = True
+        self._use_ledger = self.blockchain.use_ledger
+        self.path = self.blockchain.path
         self._use_condenser_api = use_condenser_api
         self.set_expiration(kwargs.get("expiration", self.blockchain.expiration))
 
@@ -166,6 +169,28 @@ class TransactionBuilder(dict):
             raise AssertionError("Could not access permission")
 
         required_treshold = account[permission]["weight_threshold"]
+        if self._use_ledger:
+            if not self._is_constructed() or self._is_require_reconstruction():
+                self.constructTx()
+
+            key_found = False
+            if self.path is not None:
+                current_pubkey = self.ledgertx.get_pubkey(self.path)
+                for authority in account[permission]["key_auths"]:
+                    if str(current_pubkey) == authority[1]:
+                        key_found = True
+                if permission == "posting" and not key_found:
+                        for authority in account["active"]["key_auths"]:
+                            if str(current_pubkey) == authority[1]:
+                                key_found = True
+                if not key_found:
+                        for authority in account["owner"]["key_auths"]:
+                            if str(current_pubkey) == authority[1]:
+                                key_found = True
+            if not key_found:
+                raise AssertionError("Could not find pubkey from %s in path: %s!" % (account["name"], self.path))
+            return
+        
         if self.blockchain.wallet.locked():
             raise WalletLocked()
         if self.blockchain.use_sc2 and self.blockchain.steemconnect is not None:
@@ -239,6 +264,35 @@ class TransactionBuilder(dict):
         """Clear all stored wifs"""
         self.wifs = set()
 
+    def setPath(self, path):
+        self.path = path
+
+    def searchPath(self, account, perm):
+        if not self.blockchain.use_ledger:
+            return
+        if not self._is_constructed() or self._is_require_reconstruction():
+            self.constructTx()
+        key_found = False
+        path = None
+        current_account_index = 0
+        current_key_index = 0
+        while not key_found and current_account_index < 5:
+            path = self.ledgertx.build_path(perm, current_account_index, current_key_index)
+            current_pubkey = self.ledgertx.get_pubkey(path)
+            key_found = False
+            for authority in account[perm]["key_auths"]:
+                if str(current_pubkey) == authority[1]:
+                    key_found = True
+            if not key_found and current_key_index < 5:
+                current_key_index += 1
+            elif not key_found and current_key_index >= 5:
+                current_key_index = 0
+                current_account_index += 1
+        if not key_found:
+            return None
+        else:
+            return path
+
     def constructTx(self, ref_block_num=None, ref_block_prefix=None):
         """ Construct the actual transaction and store it in the class's dict
             store
@@ -262,6 +316,16 @@ class TransactionBuilder(dict):
         if ref_block_num is None or ref_block_prefix is None:
             ref_block_num, ref_block_prefix = transactions.getBlockParams(
                 self.blockchain.rpc)
+        if self._use_ledger:
+            self.ledgertx = Ledger_Transaction(
+                ref_block_prefix=ref_block_prefix,
+                expiration=expiration,
+                operations=ops,
+                ref_block_num=ref_block_num,
+                custom_chains=self.blockchain.custom_chains,
+                prefix=self.blockchain.prefix
+            )
+
         self.tx = Signed_Transaction(
             ref_block_prefix=ref_block_prefix,
             expiration=expiration,
@@ -300,19 +364,30 @@ class TransactionBuilder(dict):
                 self.blockchain.chain_params["prefix"])
         elif "blockchain" in self:
             operations.default_prefix = self["blockchain"]["prefix"]
-
-        try:
-            signedtx = Signed_Transaction(**self.json(with_prefix=True))
-            signedtx.add_custom_chains(self.blockchain.custom_chains)
-        except:
-            raise ValueError("Invalid TransactionBuilder Format")
-
-        if not any(self.wifs):
-            raise MissingKeyError
-
-        signedtx.sign(self.wifs, chain=self.blockchain.chain_params)
-        self["signatures"].extend(signedtx.json().get("signatures"))
-        return signedtx
+        
+        if self._use_ledger:
+            #try:
+            #    ledgertx = Ledger_Transaction(**self.json(with_prefix=True))
+            #    ledgertx.add_custom_chains(self.blockchain.custom_chains)
+            #except:
+            #    raise ValueError("Invalid TransactionBuilder Format")
+            #ledgertx.sign(self.path, chain=self.blockchain.chain_params)
+            self.ledgertx.sign(self.path, chain=self.blockchain.chain_params)
+            self["signatures"].extend(self.ledgertx.json().get("signatures"))
+            return self.ledgertx
+        else:
+            try:
+                signedtx = Signed_Transaction(**self.json(with_prefix=True))
+                signedtx.add_custom_chains(self.blockchain.custom_chains)
+            except:
+                raise ValueError("Invalid TransactionBuilder Format")
+    
+            if not any(self.wifs):
+                raise MissingKeyError
+
+            signedtx.sign(self.wifs, chain=self.blockchain.chain_params)
+            self["signatures"].extend(signedtx.json().get("signatures"))
+            return signedtx
 
     def verify_authority(self):
         """ Verify the authority of the signed transaction
diff --git a/beem/version.py b/beem/version.py
index 0ffc41134b688754a333b27cfcb9286f8d757dcc..807d3748088d9fa8a2180e86f12af0d6ea504966 100644
--- a/beem/version.py
+++ b/beem/version.py
@@ -1,2 +1,2 @@
 """THIS FILE IS GENERATED FROM beem SETUP.PY."""
-version = '0.23.6'
+version = '0.23.7'
diff --git a/beemapi/version.py b/beemapi/version.py
index 0ffc41134b688754a333b27cfcb9286f8d757dcc..807d3748088d9fa8a2180e86f12af0d6ea504966 100644
--- a/beemapi/version.py
+++ b/beemapi/version.py
@@ -1,2 +1,2 @@
 """THIS FILE IS GENERATED FROM beem SETUP.PY."""
-version = '0.23.6'
+version = '0.23.7'
diff --git a/beembase/__init__.py b/beembase/__init__.py
index ede480dae5958c740a3d12f53c032397950a8bfb..2e16525b58e83504db50d2a3a98aabedad12e8cb 100644
--- a/beembase/__init__.py
+++ b/beembase/__init__.py
@@ -7,5 +7,6 @@ __all__ = [
     'operationids',
     'operations',
     'signedtransactions',
+    'ledgertransactions',
     'transactions',
 ]
diff --git a/beembase/ledgertransactions.py b/beembase/ledgertransactions.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe30ffbc0e926137fbcdf261d9ff6e1805fea65c
--- /dev/null
+++ b/beembase/ledgertransactions.py
@@ -0,0 +1,70 @@
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+from builtins import int, str
+from beemgraphenebase.unsignedtransactions import Unsigned_Transaction as GrapheneUnsigned_Transaction
+from .operations import Operation
+from beemgraphenebase.chains import known_chains
+from beemgraphenebase.py23 import py23_bytes
+from beemgraphenebase.account import PublicKey
+from beemgraphenebase.types import (
+    Array,
+    Signature,
+)
+from binascii import hexlify
+import logging
+log = logging.getLogger(__name__)
+
+
+class Ledger_Transaction(GrapheneUnsigned_Transaction):
+    """ Create an unsigned transaction and offer method to send it to a ledger device for signing
+
+        :param num refNum: parameter ref_block_num (see :func:`beembase.transactions.getBlockParams`)
+        :param num refPrefix: parameter ref_block_prefix (see :func:`beembase.transactions.getBlockParams`)
+        :param str expiration: expiration date
+        :param array operations:  array of operations
+        :param dict custom_chains: custom chain which should be added to the known chains
+    """
+    def __init__(self, *args, **kwargs):
+        self.known_chains = known_chains
+        custom_chain = kwargs.get("custom_chains", {})
+        if len(custom_chain) > 0:
+            for c in custom_chain:
+                if c not in self.known_chains:
+                    self.known_chains[c] = custom_chain[c]
+        super(Ledger_Transaction, self).__init__(*args, **kwargs)
+
+    def add_custom_chains(self, custom_chain):
+        if len(custom_chain) > 0:
+            for c in custom_chain:
+                if c not in self.known_chains:
+                    self.known_chains[c] = custom_chain[c]
+
+    def getOperationKlass(self):
+        return Operation
+
+    def getKnownChains(self):
+        return self.known_chains
+
+    def sign(self, path="48'/13'/0'/0'/0'", chain=u"STEEM"):
+        from ledgerblue.comm import getDongle
+        dongle = getDongle(True)
+        apdu_list = self.build_apdu(path, chain)
+        for apdu in apdu_list:
+            result = dongle.exchange(py23_bytes(apdu))
+        sigs = []
+        signature = result
+        sigs.append(Signature(signature))
+        self.data["signatures"] = Array(sigs)
+        return self
+
+    def get_pubkey(self, path="48'/13'/0'/0'/0'", request_screen_approval=False, prefix="STM"):
+        from ledgerblue.comm import getDongle
+        dongle = getDongle(True)
+        apdu = self.build_apdu_pubkey(path, request_screen_approval)
+        result = dongle.exchange(py23_bytes(apdu))
+        offset = 1 + result[0]
+        address = result[offset + 1: offset + 1 + result[offset]]
+        # public_key = result[1: 1 + result[0]]
+        return PublicKey(address.decode(), prefix=prefix)
diff --git a/beembase/operations.py b/beembase/operations.py
index 8d517b588c1dc7008c7250f0eabc0c4a5a59ffa4..11bea656f669911d728a8b5e0bc6dbd7f82c4e05 100644
--- a/beembase/operations.py
+++ b/beembase/operations.py
@@ -285,6 +285,7 @@ class Account_update2(GrapheneObject):
         if len(args) == 1 and len(kwargs) == 0:
             kwargs = args[0]
         prefix = kwargs.get("prefix", default_prefix)
+        extensions = Array([])
 
         if "owner" in kwargs:
             owner = Optional(Permission(kwargs["owner"], prefix=prefix))
@@ -302,7 +303,7 @@ class Account_update2(GrapheneObject):
             posting = Optional(None)
 
         if "memo_key" in kwargs:
-            memo_key = Optional(Permission(kwargs["memo_key"], prefix=prefix))
+            memo_key = Optional(PublicKey(kwargs["memo_key"], prefix=prefix))
         else:
             memo_key = Optional(None)        
 
@@ -327,6 +328,7 @@ class Account_update2(GrapheneObject):
             ('memo_key', memo_key),
             ('json_metadata', String(meta)),
             ('posting_json_metadata', String(posting_meta)),
+            ('extensions', extensions)
         ]))
 
 
diff --git a/beembase/version.py b/beembase/version.py
index 0ffc41134b688754a333b27cfcb9286f8d757dcc..807d3748088d9fa8a2180e86f12af0d6ea504966 100644
--- a/beembase/version.py
+++ b/beembase/version.py
@@ -1,2 +1,2 @@
 """THIS FILE IS GENERATED FROM beem SETUP.PY."""
-version = '0.23.6'
+version = '0.23.7'
diff --git a/beemgraphenebase/__init__.py b/beemgraphenebase/__init__.py
index 487c905f10355d430333de3a4cb423d87a636f66..f7a36fbf49782fd8a53176f07fd812c9d1a6644a 100644
--- a/beemgraphenebase/__init__.py
+++ b/beemgraphenebase/__init__.py
@@ -18,5 +18,6 @@ __all__ = ['account',
            'objects',
            'operations',
            'signedtransactions',
+           'unsignedtransactions',
            'objecttypes',
            'py23']
diff --git a/beemgraphenebase/bip32.py b/beemgraphenebase/bip32.py
index 3e1ffe8ba75605cae1ce048a41cb606739d0450c..7249cbd37885fef55b52c79d2692479d0b56f007 100644
--- a/beemgraphenebase/bip32.py
+++ b/beemgraphenebase/bip32.py
@@ -10,6 +10,7 @@ import hashlib
 import struct
 import codecs
 from beemgraphenebase.base58 import base58CheckDecode, base58CheckEncode
+from beemgraphenebase.py23 import py23_bytes
 from hashlib import sha256
 from binascii import hexlify, unhexlify
 import ecdsa
@@ -33,7 +34,11 @@ EX_TEST_PRIVATE = [codecs.decode('04358394', 'hex')]  # Version strings for test
 EX_TEST_PUBLIC = [codecs.decode('043587CF', 'hex')]  # Version strings for testnet extended public keys
 
 
-def parse_path(nstr):
+def int_to_hex(x):
+    return py23_bytes(hex(x)[2:], encoding="utf-8")
+
+
+def parse_path(nstr, as_bytes=False):
     """"""
     r = list()
     for s in nstr.split('/'):
@@ -43,7 +48,15 @@ def parse_path(nstr):
             r.append(int(s[:-1]) + BIP32_HARDEN)
         else:
             r.append(int(s))
-    return r
+    if not as_bytes:
+        return r
+    path = None
+    for p in r:
+        if path is None:
+            path = int_to_hex(p)
+        else:
+            path += int_to_hex(p)
+    return path
 
 
 class BIP32Key(object):
diff --git a/beemgraphenebase/unsignedtransactions.py b/beemgraphenebase/unsignedtransactions.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3eb933c446f81fffe07bf978945989197602942
--- /dev/null
+++ b/beemgraphenebase/unsignedtransactions.py
@@ -0,0 +1,290 @@
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+from builtins import bytes, str, int
+from beemgraphenebase.py23 import py23_bytes, bytes_types
+import ecdsa
+import hashlib
+from binascii import hexlify, unhexlify
+from collections import OrderedDict
+import asn1
+import struct
+from future.utils import python_2_unicode_compatible
+from collections import OrderedDict
+import json
+
+from .py23 import py23_bytes, bytes_types, integer_types, string_types, py23_chr
+from .objecttypes import object_type
+from .bip32 import parse_path
+
+from .account import PublicKey
+from .types import (
+    Array,
+    Set,
+    Signature,
+    PointInTime,
+    Uint16,
+    Uint32,
+    JsonObj,
+    String,
+    Varint32,
+    Optional
+)
+from .objects import GrapheneObject, isArgsThisClass
+from .operations import Operation
+from .chains import known_chains
+from .ecdsasig import sign_message, verify_message
+import logging
+log = logging.getLogger(__name__)
+
+try:
+    import secp256k1prp as secp256k1
+    USE_SECP256K1 = True
+    log.debug("Loaded secp256k1prp binding.")    
+except:
+    try:
+        import secp256k1
+        USE_SECP256K1 = True
+        log.debug("Loaded secp256k1 binding.")
+    except Exception:
+        USE_SECP256K1 = False
+        log.debug("To speed up transactions signing install \n"
+                  "    pip install secp256k1\n"
+                  "or  pip install secp256k1prp")
+
+
+@python_2_unicode_compatible
+class GrapheneObjectASN1(object):
+    """ Core abstraction class
+
+        This class is used for any JSON reflected object in Graphene.
+
+        * ``instance.__json__()``: encodes data into json format
+        * ``bytes(instance)``: encodes data into wire format
+        * ``str(instances)``: dumps json object as string
+
+    """
+    def __init__(self, data=None):
+        self.data = data
+
+    def __bytes__(self):
+        if self.data is None:
+            return py23_bytes()
+        b = b""
+        encoder = asn1.Encoder()
+        encoder.start()
+        for name, value in list(self.data.items()):
+            if name == "operations":
+                for operation in value:
+                    if isinstance(value, string_types):
+                        b = py23_bytes(operation, 'utf-8')
+                    else:
+                        b = py23_bytes(operation)                      
+                    encoder.write(b, asn1.Numbers.OctetString)                
+            elif name != "signatures":
+                if isinstance(value, string_types):
+                    b = py23_bytes(value, 'utf-8')
+                else:
+                    b = py23_bytes(value)                
+                encoder.write(b, asn1.Numbers.OctetString)
+        return encoder.output()
+
+    def __json__(self):
+        if self.data is None:
+            return {}
+        d = {}  # JSON output is *not* ordered
+        for name, value in list(self.data.items()):
+            if isinstance(value, Optional) and value.isempty():
+                continue
+
+            if isinstance(value, String):
+                d.update({name: str(value)})
+            else:
+                try:
+                    d.update({name: JsonObj(value)})
+                except Exception:
+                    d.update({name: value.__str__()})
+        return d
+
+    def __str__(self):
+        return json.dumps(self.__json__())
+
+    def toJson(self):
+        return self.__json__()
+
+    def json(self):
+        return self.__json__()
+
+
+class Unsigned_Transaction(GrapheneObjectASN1):
+    """ Create an unsigned transaction with ASN1 encoder for using it with ledger
+
+        :param num refNum: parameter ref_block_num (see :func:`beembase.transactions.getBlockParams`)
+        :param num refPrefix: parameter ref_block_prefix (see :func:`beembase.transactions.getBlockParams`)
+        :param str expiration: expiration date
+        :param array operations:  array of operations
+    """
+    def __init__(self, *args, **kwargs):
+        if isArgsThisClass(self, args):
+            self.data = args[0].data
+        else:
+            if len(args) == 1 and len(kwargs) == 0:
+                kwargs = args[0]
+            prefix = kwargs.pop("prefix", "STM")
+            if "extensions" not in kwargs:
+                kwargs["extensions"] = Set([])
+            elif not kwargs.get("extensions"):
+                kwargs["extensions"] = Set([])
+            if "signatures" not in kwargs:
+                kwargs["signatures"] = Array([])
+            else:
+                kwargs["signatures"] = Array([Signature(unhexlify(a)) for a in kwargs["signatures"]])
+            operations_count = 0
+            if "operations" in kwargs:
+                operations_count = len(kwargs["operations"])
+                #opklass = self.getOperationKlass()
+                #if all([not isinstance(a, opklass) for a in kwargs["operations"]]):
+                #    kwargs['operations'] = Array([opklass(a, prefix=prefix) for a in kwargs["operations"]])
+                #else:
+                #    kwargs['operations'] = (kwargs["operations"])
+
+            super(Unsigned_Transaction, self).__init__(OrderedDict([
+                ('ref_block_num', Uint16(kwargs['ref_block_num'])),
+                ('ref_block_prefix', Uint32(kwargs['ref_block_prefix'])),
+                ('expiration', PointInTime(kwargs['expiration'])),
+                ('operations_count', Varint32(operations_count)),
+                ('operations', kwargs['operations']),
+                ('extensions', kwargs['extensions']),
+                ('signatures', kwargs['signatures']),
+            ]))
+
+    @property
+    def id(self):
+        """ The transaction id of this transaction
+        """
+        # Store signatures temporarily since they are not part of
+        # transaction id
+        sigs = self.data["signatures"]
+        self.data.pop("signatures", None)
+
+        # Generage Hash of the seriliazed version
+        h = hashlib.sha256(py23_bytes(self)).digest()
+
+        # recover signatures
+        self.data["signatures"] = sigs
+
+        # Return properly truncated tx hash
+        return hexlify(h[:20]).decode("ascii")
+
+    def getOperationKlass(self):
+        return Operation
+
+    def derSigToHexSig(self, s):
+        """ Format DER to HEX signature
+        """
+        s, junk = ecdsa.der.remove_sequence(unhexlify(s))
+        if junk:
+            log.debug('JUNK: %s', hexlify(junk).decode('ascii'))
+        if not (junk == b''):
+            raise AssertionError()
+        x, s = ecdsa.der.remove_integer(s)
+        y, s = ecdsa.der.remove_integer(s)
+        return '%064x%064x' % (x, y)
+
+    def getKnownChains(self):
+        return known_chains
+
+    def getChainParams(self, chain):
+        # Which network are we on:
+        chains = self.getKnownChains()
+        if isinstance(chain, str) and chain in chains:
+            chain_params = chains[chain]
+        elif isinstance(chain, dict):
+            chain_params = chain
+        else:
+            raise Exception("sign() only takes a string or a dict as chain!")
+        if "chain_id" not in chain_params:
+            raise Exception("sign() needs a 'chain_id' in chain params!")
+        return chain_params
+
+    def deriveDigest(self, chain):
+        chain_params = self.getChainParams(chain)
+        # Chain ID
+        self.chainid = chain_params["chain_id"]
+
+        # Do not serialize signatures
+        sigs = self.data["signatures"]
+        self.data["signatures"] = []
+
+        # Get message to sign
+        #   bytes(self) will give the wire formated data according to
+        #   GrapheneObject and the data given in __init__()
+        encoder = asn1.Encoder()
+        encoder.start()
+        encoder.write(unhexlify(self.chainid), asn1.Numbers.OctetString)
+        for name, value in list(self.data.items()):
+            if name == "operations":
+                for operation in value:
+                    if isinstance(value, string_types):
+                        b = py23_bytes(operation, 'utf-8')
+                    else:
+                        b = py23_bytes(operation)                      
+                    encoder.write(b, asn1.Numbers.OctetString)                
+            elif name != "signatures":
+                if isinstance(value, string_types):
+                    b = py23_bytes(value, 'utf-8')
+                else:
+                    b = py23_bytes(value)                
+                encoder.write(b, asn1.Numbers.OctetString)
+        
+        self.message = encoder.output()
+        self.digest = hashlib.sha256(self.message).digest()
+
+        # restore signatures
+        self.data["signatures"] = sigs
+
+    def build_path(self, role, account_index, key_index):
+        if role == "owner":
+            return "48'/13'/0'/%d'/%d'" % (account_index, key_index)
+        elif role == "active":
+            return "48'/13'/1'/%d'/%d'" % (account_index, key_index)
+        elif role == "posting":
+            return "48'/13'/4'/%d'/%d'" % (account_index, key_index)
+        elif role == "memo":
+            return "48'/13'/3'/%d'/%d'" % (account_index, key_index)        
+
+    def build_apdu(self, path="48'/13'/0'/0'/0'", chain=None):
+        self.deriveDigest(chain)
+        path = unhexlify(parse_path(path, as_bytes=True))
+
+        message = self.message
+        path_size = int(len(path) / 4)
+        message_size = len(message)
+        
+        offset = 0
+        first = True
+        result = []
+        while offset != message_size:
+            if message_size - offset > 200:
+                chunk = message[offset: offset + 200]
+            else:
+                chunk = message[offset:]
+    
+            if first:
+                total_size = int(len(path)) + 1 + len(chunk)
+                apdu = unhexlify("d4040000") + py23_chr(total_size) + py23_chr(path_size) + path + chunk
+                first = False
+            else:
+                total_size = len(chunk)
+                apdu = unhexlify("d4048000") + py23_chr(total_size) + chunk
+            result.append(apdu)
+            offset += len(chunk)
+        return result
+
+    def build_apdu_pubkey(self, path="48'/13'/0'/0'/0'", request_screen_approval=False):
+        path = unhexlify(parse_path(path, as_bytes=True))
+        if not request_screen_approval:
+            return unhexlify("d4020001") + py23_chr(int(len(path)) + 1) + py23_chr(int(len(path) / 4)) + path
+        else:
+            return unhexlify("d4020101") + py23_chr(int(len(path)) + 1) + py23_chr(int(len(path) / 4)) + path
diff --git a/beemgraphenebase/version.py b/beemgraphenebase/version.py
index 0ffc41134b688754a333b27cfcb9286f8d757dcc..807d3748088d9fa8a2180e86f12af0d6ea504966 100644
--- a/beemgraphenebase/version.py
+++ b/beemgraphenebase/version.py
@@ -1,2 +1,2 @@
 """THIS FILE IS GENERATED FROM beem SETUP.PY."""
-version = '0.23.6'
+version = '0.23.7'
diff --git a/docs/beembase.ledgertransactions.rst b/docs/beembase.ledgertransactions.rst
new file mode 100644
index 0000000000000000000000000000000000000000..fd05673680ce6913d49e64df226e899960cb1d42
--- /dev/null
+++ b/docs/beembase.ledgertransactions.rst
@@ -0,0 +1,7 @@
+beembase\.ledgertransactions
+============================
+
+.. automodule:: beembase.ledgertransactions
+    :members:
+    :undoc-members:
+    :show-inheritance:
\ No newline at end of file
diff --git a/docs/beemgraphenebase.unsignedtransactions.rst b/docs/beemgraphenebase.unsignedtransactions.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b328d5cd349c1786622ec2d9033532a99e143672
--- /dev/null
+++ b/docs/beemgraphenebase.unsignedtransactions.rst
@@ -0,0 +1,7 @@
+beemgraphenebase\.unsignedtransactions 
+======================================
+
+.. automodule:: beemgraphenebase.unsignedtransactions
+    :members:
+    :undoc-members:
+    :show-inheritance:
\ No newline at end of file
diff --git a/docs/modules.rst b/docs/modules.rst
index 5de6a58f27fa039f6d1695f325e58587da3f4053..cbae7f58292aaeede71bccfc2f9e6961f025d64c 100644
--- a/docs/modules.rst
+++ b/docs/modules.rst
@@ -62,6 +62,7 @@ beembase Modules
    beembase.operationids
    beembase.operations
    beembase.signedtransactions
+   beembase.ledgertransactions
    beembase.transactions
 
 
@@ -78,4 +79,5 @@ beemgraphenebase Modules
    beemgraphenebase.objects
    beemgraphenebase.objecttypes
    beemgraphenebase.operations
-   beemgraphenebase.signedtransactions
\ No newline at end of file
+   beemgraphenebase.signedtransactions
+   beemgraphenebase.unsignedtransactions
\ No newline at end of file
diff --git a/requirements-test.txt b/requirements-test.txt
index a11278a40ea9dbe954ef016e15f1e7ef01e7d32a..819e1de9061bc370ff1d98630aea874ad0469537 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -29,4 +29,5 @@ tox
 codacy-coverage
 virtualenv
 codecov
-diff_match_patch
\ No newline at end of file
+diff_match_patch
+asn1
\ No newline at end of file
diff --git a/setup.py b/setup.py
index a80cdcf2683cafa5823c9bc191e3aa965e254d5f..b8a64dd5bc08d420e5ab29d47ad06bf6fbaa0b65 100755
--- a/setup.py
+++ b/setup.py
@@ -16,7 +16,7 @@ except LookupError:
     ascii = codecs.lookup('ascii')
     codecs.register(lambda name, enc=ascii: {True: enc}.get(name == 'mbcs'))
 
-VERSION = '0.23.6'
+VERSION = '0.23.7'
 
 tests_require = ['mock >= 2.0.0', 'pytest', 'pytest-mock', 'parameterized']
 
@@ -35,7 +35,8 @@ requires = [
     "click_shell",
     "prettytable",
     "pyyaml",
-    "diff_match_patch"
+    "diff_match_patch",
+    "asn1"
 ]
 
 
diff --git a/tests/beembase/test_ledgertransactions.py b/tests/beembase/test_ledgertransactions.py
new file mode 100644
index 0000000000000000000000000000000000000000..d05eb672d98582bc4af609a978784d27dd33f9d5
--- /dev/null
+++ b/tests/beembase/test_ledgertransactions.py
@@ -0,0 +1,118 @@
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+from builtins import bytes
+from builtins import chr
+from builtins import range
+from builtins import super
+import random
+import unittest
+from pprint import pprint
+from binascii import hexlify, unhexlify
+from collections import OrderedDict
+
+from beembase import (
+    transactions,
+    memo,
+    operations,
+    objects
+)
+from beembase.objects import Operation
+from beembase.ledgertransactions import Ledger_Transaction
+from beemgraphenebase.account import PrivateKey
+from beemgraphenebase import account
+from beembase.operationids import getOperationNameForId
+from beemgraphenebase.py23 import py23_bytes, bytes_types
+from beem.amount import Amount
+from beem.asset import Asset
+from beem.steem import Steem
+
+
+TEST_AGAINST_CLI_WALLET = False
+
+prefix = u"STEEM"
+default_prefix = u"STM"
+ref_block_num = 34843
+ref_block_prefix = 1663841413
+expiration = "2020-05-10T20:30:57"
+path = "48'/13'/0'/0'/0'"
+
+
+class Testcases(unittest.TestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        self.stm = Steem(
+            offline=True
+        )
+
+    def doit(self, printWire=False, ops=None):
+        if ops is None:
+            ops = [Operation(self.op)]
+        tx = Ledger_Transaction(ref_block_num=ref_block_num,
+                                ref_block_prefix=ref_block_prefix,
+                                expiration=expiration,
+                                operations=ops)
+        txWire = hexlify(py23_bytes(tx)).decode("ascii")
+        txApdu = tx.build_apdu(path, chain=prefix)
+        if printWire:
+            print()
+            print(txWire)
+            print()
+        if len(self.cm) > 0:
+            self.assertEqual(self.cm, txWire)
+        if len(self.apdu) > 0:
+            self.assertEqual(len(self.apdu), len(txApdu))
+            for i in range(len(txApdu)):
+                self.assertEqual(self.apdu[i], hexlify(txApdu[i]))
+
+    def test_Transfer(self):
+        self.op = operations.Transfer(**{
+            "from": "nettybot",
+            "to": "netuoso",
+            "amount": Amount("0.001 STEEM", steem_instance=self.stm),
+            "memo": "",
+            "prefix": default_prefix
+        })
+        self.apdu = ([b"d40400007205800000308000000d80000000800000008000000004"
+                      b"200000000000000000000000000000000000000000000000000000"
+                      b"00000000000004021b88040485342c6304048164b85e0401010423"
+                      b"02086e65747479626f74076e6574756f736f010000000000000003"
+                      b"535445454d000000040100"])
+        self.cm = (u"04021b88040485342c6304048164b85e040101042302086e65747479626f74076e6574756f736f010000000000000003535445454d000000040100")
+        self.doit()
+
+    def test_createclaimedaccount(self):
+        self.op = operations.Create_claimed_account(
+            **{
+                  "creator": "netuoso",
+                  "new_account_name": "netuoso2",
+                  "owner": {"weight_threshold":1,"account_auths":[],"key_auths":[["STM7QtTRvd1owAh4uGaC6trxjR9M1cpqfi2WfLQed1GbUGPomt9DP",1]]},
+                  "active": {"weight_threshold":1,"account_auths":[],"key_auths":[["STM7QtTRvd1owAh4uGaC6trxjR9M1cpqfi2WfLQed1GbUGPomt9DP",1]]},
+                  "posting": {"weight_threshold":1,"account_auths":[],"key_auths":[["STM7QtTRvd1owAh4uGaC6trxjR9M1cpqfi2WfLQed1GbUGPomt9DP",1]]},
+                  "memo_key": "STM7QtTRvd1owAh4uGaC6trxjR9M1cpqfi2WfLQed1GbUGPomt9DP",
+                  "json_metadata": "{}"
+                 })
+        self.apdu = ([b"d4040000dd05800000308000000d800000008000000080000000042000000000000000000000000000000000000000000000000000000000000000000402bd8c04045fe26f450404f179a8570401010481b217076e6574756f736f086e6574756f736f32010000000001034c6a518a9b9e9cb8099176854a322c87db6c7e82c47bd5fe68c273ba63a647160100010000000001034c6a518a9b9e9cb8099176854a322c87db6c7e82c47bd5fe68c273ba63a647160100010000000001034c6a518a9b9e9cb8099176854a322c87db6c7e82c47bd5fe68c273ba63a647160100034c6a",
+                      b"d404800025518a9b9e9cb8099176854a322c87db6c7e82c47bd5fe68c273ba63a6471600000000040100"])
+
+    def test_vote(self):
+        self.op = operations.Vote(
+        **{
+        "voter": "nettybot",
+        "author": "jrcornel",
+        "permlink": "hive-sitting-back-at-previous-support-levels-is-this-a-buy",
+        "weight": 10000
+        }
+        )
+        self.cm = b"0402528804049ce2ccea04047660b85e040101045000086e65747479626f74086a72636f726e656c3a686976652d73697474696e672d6261636b2d61742d70726576696f75732d737570706f72742d6c6576656c732d69732d746869732d612d6275791027040100"
+        self.apdu = ([b"d40400009f05800000308000000d800000008000000080000000042000000000000000000000000000000000000000000000000000000000000000000402528804049ce2ccea04047660b85e040101045000086e65747479626f74086a72636f726e656c3a686976652d73697474696e672d6261636b2d61742d70726576696f75732d737570706f72742d6c6576656c732d69732d746869732d612d6275791027040100"])
+
+    def test_pubkey(self):
+        tx = Ledger_Transaction(ref_block_num=ref_block_num,
+                                ref_block_prefix=ref_block_prefix,
+                                expiration=expiration,
+                                operations=[])
+        apdu = tx.build_apdu_pubkey()
+        self.assertEqual((py23_bytes(apdu)), b'\xd4\x02\x00\x01\x15\x05\x80\x00\x000\x80\x00\x00\r\x80\x00\x00\x00\x80\x00\x00\x00\x80\x00\x00\x00')
diff --git a/tests/beemgraphene/test_bip32.py b/tests/beemgraphene/test_bip32.py
index db6c8363364ac0c53a8166276f4c50cf4af8f04b..ce9dcef8c2668df56c9ad0858016b94dd8dc4a89 100644
--- a/tests/beemgraphene/test_bip32.py
+++ b/tests/beemgraphene/test_bip32.py
@@ -164,5 +164,12 @@ class Testcases(unittest.TestCase):
         self.assertEqual(m.ExtendedKey(), "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L")
         self.assertEqual(m.ExtendedKey(private=False, encoded=True), "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y")
 
+    def test_parse_path(self):
+        path = "48'/13'/0'/0'/0'"
+
+        bin_path = parse_path(path, as_bytes=True)    
+        self.assertEqual(b'800000308000000d800000008000000080000000', bin_path)
+
+
 if __name__ == '__main__':
     unittest.main()