Git Product home page Git Product logo

ledger-eth-lib's Introduction

ledgereth

Documentation Status

This library is beta. Please report any bugs you find.

This is a library to interact with app-ethereum, the Ethereum app for the Ledger hardware wallets. It's goal is to make interfacing with the Ledger easy.

Quickstart

Here’s the quickest way to get started.

pip install ledgereth

Please see the ledgereth documentation for more detailed information.

Compatability

Ledger Devices

This lib has been tested to work on Ledger Nano S and Nano X. It will probalby work with Ledger Blue and any devices the ledgerblue library and app-ethereum supports.

Ledger Account Derivations

The Ledger-provided desktop apps have changed the way accounts are derived with the release of Ledger Live. If you created your Ledger account(s) with the older Chrome app and want to use those account(s) with this library, you will need to set the LEDGER_LEGACY_ACCOUNTS env var. You can only use one or the other at a time. See the notes in source for more information.

ledger-eth-lib's People

Contributors

antazoey avatar basnijholt avatar mikeshultz avatar moh-eulith avatar moisses89 avatar mushroomizer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ledger-eth-lib's Issues

feat request: support HexBytes more

so many places have assert type(thing) == bytes
if we did assert isinstance(thing, bytes), it'd allow HexBytes

But also, assertion errors are not the best to encounter, the message is not helpful without digging into the tb; a TypeError("Expecting bytes, not blah blah") would be better for the lib

Issue with comms.py

When I want to retrieve the accounts from the ledger (v0.7.1), I have this error :

File "../lib/python3.8/site-packages/ledgereth/comms.py", line 168, in init_dongle
    if not is_usable_version(DONGLE_CONFIG_CACHE):
NameError: name 'DONGLE_CONFIG_CACHE' is not defined

The workaround that I found is the initialisation of the global variables

DONGLE_CACHE: Dongle = None
DONGLE_CONFIG_CACHE: bytes = None

Let me know if I can give you more information in order to help you

bug: legacy (type 0) transactions and high chain IDs fail signature recovery

type 0 transactions seem to have an issue with high chain IDs (e.g. 131277322940420). I've tested on hardware and it works up to mumbai (80001). Type 1 and 2 don't have the same problem.

I think @moh-eulith tried to address this by updating MockDongle to get the tests to pass but I'm seeing issues using a chain ID like this on hardware. Probably indicative of another issue.

Here's a test that will cause an invalid signature recovery on hardware:

def test_zero_gas_price(yield_dongle):
    """Test a transaction with a 0 gas price"""
    chain_id = 131277322940420
    destination = "0xf0155486a14539f784739be1c02e93f28eb8e960"

    with yield_dongle() as dongle:
        sender = get_accounts(dongle=dongle, count=1)[0].address

        signed = create_transaction(
            destination=destination,
            amount=int(10e17),
            gas=int(1e6),
            # TODO
            gas_price=int(1e9),
            data="",
            nonce=2023,
            chain_id=chain_id,
            dongle=dongle,
        )

        print("signed:", signed)

        # assert signed.v in [(chain_id * 2 + 35) + x for x in (0, 1)]
        # assert signed.r
        # assert signed.s
        assert sender == Account.recover_transaction(signed.rawTransaction)

I'm not sure if it's a limitation of the transaction type, RLP, or my implementation.

Input validation

Might want to do some basic input validation on user helper functions (e.g. create_transaction()). Things like Ethereum address checksum validation and making sure values are within expected bounds.

Regex bip32 eth patterns

Your bip32 path regex might be incorrect

it only allows for paths
44'/60'/[one digit]'/[one digit]/[one digit]

whereas ledger generates valid eth addresses for any eth path
meaning

it should allow for paths
44'/60'/[any amount digit]'/[any amount digit]/[any amount digit]

This is the current regex
BIP32_ETH_PATTERN = r"^44'/60'/[0-9]'/[0-9]/[0-9]$"
BIP32_LEGACY_LEDGER_PATTERN = r"^44'/60'/[0-9]'/[0-9]$"

This is the fixed regex
BIP32_ETH_PATTERN = r"^44'/60'/[0-9]+'/[0-9]+/[0-9]+$"
BIP32_LEGACY_LEDGER_PATTERN = r"^44'/60'/[0-9]+'/[0-9]+$"

Issue signing large transactions

Recently saw an issue signing a large contract transaction. Haven't had the chance to dig into it too far but wanted to document it for reference.

This is the encoded tx:

0xf907308084b2d05e00835b8d808080b90721608060405234801561001057600080fd5b506040516020806107018339810180604052602081101561003057600080fd5b5051610045338264010000000061004b810204565b5061011c565b600160a060020a038216151561006057600080fd5b60025461007a908264010000000061059161010382021704565b600255600160a060020a0382166000908152602081905260409020546100ad908264010000000061059161010382021704565b600160a060020a0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b60008282018381101561011557600080fd5b9392505050565b6105d68061012b6000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c01000000000000000000000000000000000000000000000000000000009004806370a082311161007857806370a0823114610166578063a457c2d71461018c578063a9059cbb146101b8578063dd62ed3e146101e4576100a5565b8063095ea7b3146100aa57806318160ddd146100ea57806323b872dd14610104578063395093511461013a575b600080fd5b6100d6600480360360408110156100c057600080fd5b50600160a060020a038135169060200135610212565b604080519115158252519081900360200190f35b6100f2610290565b60408051918252519081900360200190f35b6100d66004803603606081101561011a57600080fd5b50600160a060020a03813581169160208101359091169060400135610296565b6100d66004803603604081101561015057600080fd5b50600160a060020a038135169060200135610333565b6100f26004803603602081101561017c57600080fd5b5035600160a060020a03166103e3565b6100d6600480360360408110156101a257600080fd5b50600160a060020a0381351690602001356103fe565b6100d6600480360360408110156101ce57600080fd5b50600160a060020a038135169060200135610449565b6100f2600480360360408110156101fa57600080fd5b50600160a060020a038135811691602001351661045f565b6000600160a060020a038316151561022957600080fd5b336000818152600160209081526040808320600160a060020a03881680855290835292819020869055805186815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a350600192915050565b60025490565b600160a060020a03831660009081526001602090815260408083203384529091528120548211156102c657600080fd5b600160a060020a03841660009081526001602090815260408083203384529091529020546102fa908363ffffffff61048a16565b600160a060020a038516600090815260016020908152604080832033845290915290205561032984848461049f565b5060019392505050565b6000600160a060020a038316151561034a57600080fd5b336000908152600160209081526040808320600160a060020a038716845290915290205461037e908363ffffffff61059116565b336000818152600160209081526040808320600160a060020a0389168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b600160a060020a031660009081526020819052604090205490565b6000600160a060020a038316151561041557600080fd5b336000908152600160209081526040808320600160a060020a038716845290915290205461037e908363ffffffff61048a16565b600061045633848461049f565b50600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b60008282111561049957600080fd5b50900390565b600160a060020a0383166000908152602081905260409020548111156104c457600080fd5b600160a060020a03821615156104d957600080fd5b600160a060020a038316600090815260208190526040902054610502908263ffffffff61048a16565b600160a060020a038085166000908152602081905260408082209390935590841681522054610537908263ffffffff61059116565b600160a060020a038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000828201838110156105a357600080fd5b939250505056fea165627a7a72305820c1007c25cbb2c51d6c0aa6c7962374874a574895dffe42ae6eef70e4009c2c60002900000000000000000000000000000000000000000000003635c9adc5dea00000

This tx was assembled by web3.py using solidbyte and the LedgerSignerMiddleware.

Traceback (most recent call last):
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 372, in deployed
    return self._deploy(*args, **kwargs)
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 595, in _deploy
    deploy_txhash = self._transact(deploy_tx)
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 492, in _transact
    signed_tx = ledgereth.sign_transaction(ledger_tx, sender_path=ledger_account.path)
  File "/home/mike/dev/ledger-eth-lib/ledgereth/transactions.py", line 61, in sign_transaction
    raise Exception('Invalid response from Ledger')
Exception: Invalid response from Ledger
Traceback (most recent call last):
  File "/home/mike/.venvs/solidbyte/bin/sb", line 11, in <module>
    load_entry_point('solidbyte', 'console_scripts', 'sb')()
  File "/home/mike/dev/solidbyte/solidbyte/cli/handler.py", line 86, in main
    IMPORTED_MODULES[args.command].main(parser_args=args)
  File "/home/mike/dev/solidbyte/solidbyte/cli/deploy.py", line 55, in main
    deployer.deploy()
  File "/home/mike/dev/solidbyte/solidbyte/deploy/__init__.py", line 226, in deploy
    self._execute_deploy_scripts()
  File "/home/mike/dev/solidbyte/solidbyte/deploy/__init__.py", line 310, in _execute_deploy_scripts
    retval = script.main(**script_kwargs)
  File "/home/mike/dev/erc20-project/deploy/deploy_main.py", line 38, in main
    web3_contract_instance = token.deployed(initialSupply=initial_supply)
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 375, in deployed
    raise e
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 372, in deployed
    return self._deploy(*args, **kwargs)
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 595, in _deploy
    deploy_txhash = self._transact(deploy_tx)
  File "/home/mike/dev/solidbyte/solidbyte/deploy/objects.py", line 492, in _transact
    signed_tx = ledgereth.sign_transaction(ledger_tx, sender_path=ledger_account.path)
  File "/home/mike/dev/ledger-eth-lib/ledgereth/transactions.py", line 61, in sign_transaction
    raise Exception('Invalid response from Ledger')
Exception: Invalid response from Ledger

The ledger is responding with 9000 as if it was expecting further data(ledgerblue lib is returning an empty bytearray). I'm inferring that the ledger doesn't see this as a properly formatted transaction. I have not yet verified this rlp decodes properly yet. Could be as simple as a missing or extra field.

Code documentation

Spend some time on user and code documentation (especially docstrings, mainly). Maybe generate a short & sweet RtD manual as well.

Exception handling improvements

The error experience when not properly connected to a device could be improved.

Another case would be to explore errors for not having the app installed and making APDU specific errors come out okay.

Type 1 transactions and access lists

Add support for EIP-2930 access lists and type 1 transactions.

It's been partially implemented in PR #10 but I need to learn more about it and get encoding working for more than blank access lists.

EIP-1559 Transactions

Hello!

This is a feature request for EIP-1559 support.

Thank you for this repo, it has been a nice resource to look at.

I have been trying implement this myself using the eth-account library in another project but am running into issues

ledgereth.exceptions.LedgerError: Unexpected error: 0x6983 UNKNOWN

Hi,

I have been experiencing the following problem with Ledger nano s plus.

After command "python -m ledgereth accounts" in CLI and also any time trying to access ledger device following exception is risen
(ledgereth.exceptions.LedgerError: Unexpected error: 0x6983 UNKNOWN).
Problem occurred after updating ledger firmware to 1.0.4.

Devices with older version of firmware do not experience this error.

Device data:
model: Ledger nano s plus
Firmware version: 1.0.4
Ethereum app version: 1.10.0
Polygon app version: 1.10.0

Cheers,

Instances of LedgerAccount with the same attributes are currently evaluated as different

Thanks for this project, is really helpful for communicate with Ledger using python :)

Issue Description

Instances of LedgerAccount with the same attributes are currently evaluated as different.

from ledgereth.accounts import LedgerAccount, get_account_by_path
from ledgereth.comms import init_dongle
dongle = init_dongle()
account_one = get_account_by_path("44'/60'/0'/0/0", dongle)
account_two = get_account_by_path("44'/60'/0'/0/0", dongle)
account_one == account_two

Where account_one == account_two is evaluated as False.

Expected behavior

I'd like to suggest that instances of LedgerAccount with same attributes were evaluated as equals.

Related issue

safe-global/safe-cli#302

feat: Add support for all rlp.Serializable derived transactions

Right now most of our funcs check for native-types. For example:

if isinstance(tx, Transaction):
encoded_tx = encode(tx, Transaction)
elif isinstance(tx, Type1Transaction):
encoded_tx = tx.transaction_type.to_byte() + encode(tx, Type1Transaction)
elif isinstance(tx, Type2Transaction):
encoded_tx = tx.transaction_type.to_byte() + encode(tx, Type2Transaction)
else:
raise ValueError(
"Only Transaction and Type2Transaction objects are currently supported"
)

Look into supporting any rlp.Serializable objects to allow for easier integration. May need to validate the objects for the necessary props/types (Python Protocols could be useful?) to make sure but it should be doable.

Install issues (from ledgerblue)

I tried install on macos and am getting this error:

      wheel.vendored.packaging.requirements.InvalidRequirement: Expected end or semicolon (after version specifier)
          python-pyscard>=1.6.12-4build1
                        ~~~~~~~~~~^
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for ledgerblue
  Running setup.py clean for ledgerblue
Failed to build ledgerblue
ERROR: Could not build wheels for ledgerblue, which is required to install pyproject.toml-based projects

Add type hints

May be a simple as adding a py.typed marker, otherwise we have type ignore imports

assert statements in code

I have noticed asserts statements around, like here: https://github.com/mikeshultz/ledger-eth-lib/blob/master/ledgereth/objects.py#L36

I want to caution that when running python with the -O flag, these asserts get stripped out of the code. So if you are expecting an error, it wouldn't happen in that case.

It is less clean, but I find it is just better to raise AssertionError or a custom error for this reason.

Here is some more info: https://bandit.readthedocs.io/en/latest/plugins/b101_assert_used.html

Unable to have gas price of 0

Some dev networks allows gas price of 0 but when I try it here, I get

  File .../ledger-eth-lib/ledgereth/transactions.py", line 217, in create_transaction
    raise ValueError("gas_price or max_fee_per_gas must be provided")
ValueError: gas_price or max_fee_per_gas must be provided

The code is:

    # we need a gas price for a valid transaction
    if not gas_price and not max_fee_per_gas:
        raise ValueError("gas_price or max_fee_per_gas must be provided")

it probably should be

    # we need a gas price for a valid transaction
    if gas_price is None and max_fee_per_gas is None:
        raise ValueError("gas_price or max_fee_per_gas must be provided")

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.