ledger-bitcoin


Nameledger-bitcoin JSON
Version 0.3.0 PyPI version JSON
download
home_pagehttps://github.com/LedgerHQ/app-bitcoin-new
SummaryClient for Ledger Nano Bitcoin application
upload_time2024-02-15 14:47:58
maintainer
docs_urlNone
authorLedger
requires_python>=3.7
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Ledger Bitcoin application client

## Overview

Client library for Ledger Bitcoin application.

Main repository and documentation: https://github.com/LedgerHQ/app-bitcoin-new

## Install

If you just want to communicate through TCP socket (for example with the Speculos emulator), there is no dependency:

```bash
$ pip install ledger_bitcoin
```

otherwise, [hidapi](https://github.com/trezor/cython-hidapi) must be installed as an extra dependency:

```bash
$ pip install ledger_bitcoin[hid]
```

## Getting started

The main method exported by the library is `createClient`, which queries the hardware wallet for the version of the running app, and then returns the appropriate implementation of the `Client` class.

See the documentation of the class and the example below for the supported methods.

When running on a legacy version of the app (below version `2.0.0`), only the features that were available on the app are supported. Any unsopported method (e.g.: multisig registration or addresses, taproot addresses) will raise a `NotImplementedError`.

### Running with speculos

It is possible to run the app and the library with the [speculos](https://github.com/LedgerHQ/speculos) emulator.

⚠️ Currently, speculos does not correctly emulate the version of the app, always returning a dummy value; in order to use the library, it is necessary to set the `SPECULOS_APPNAME` environment variable before starting speculos, for example with:

```
$ export SPECULOS_APPNAME="Bitcoin Test:2.1.0"
```

Similarly, to test the library behavior on a legacy version of the app, one can set the version to `1.6.5` (the final version of the 1.X series).

The expected application name is `Bitcoin` for mainnet, `Bitcoin Test` for testnet.

### Example

The following example showcases all the main methods of the `Client`'s interface.

If you are not using the context manager syntax when creating the client, remember to call the `stop()` method to release the communication channel.

Testing the `sign_psbt` method requires producing a valid PSBT (with any external tool that supports either PSBTv0 or PSBTv2), and provide the corresponding wallet policy; it is skipped by default in the following example.


```python
from typing import Optional
from ledger_bitcoin import createClient, Chain, MultisigWallet, MultisigWallet, WalletPolicy, AddressType, TransportClient
from ledger_bitcoin.psbt import PSBT


def main():
    # speculos on default host/port
    # with createClient(TransportClient(), chain=Chain.TEST) as client:

    # Ledger Nano connected via USB
    with createClient(chain=Chain.TEST) as client:
        # ==> Get the master key fingerprint

        fpr = client.get_master_fingerprint().hex()
        print(f"Master key fingerprint: {fpr}")

        # ==> Get and display on screen the first taproot address

        first_taproot_account_pubkey = client.get_extended_pubkey("m/86'/1'/0'")
        first_taproot_account_policy = WalletPolicy(
            "",
            "tr(@0/**)",
            [
                f"[{fpr}/86'/1'/0']{first_taproot_account_pubkey}/**"
            ],
        )
        first_taproot_account_address = client.get_wallet_address(
            first_taproot_account_policy,
            None,
            change=0,
            address_index=0,
            display=True # show address on the wallet's screen
        )

        print(f"First taproot account receive address: {first_taproot_account_address}")

        # ==> Register a multisig wallet named "Cold storage"

        our_pubkey = client.get_extended_pubkey("m/48'/1'/0'/2'")
        other_key_info = "[76223a6e/48'/1'/0'/2']tpubDE7NQymr4AFtewpAsWtnreyq9ghkzQBXpCZjWLFVRAvnbf7vya2eMTvT2fPapNqL8SuVvLQdbUbMfWLVDCZKnsEBqp6UK93QEzL8Ck23AwF/**"

        multisig_policy = MultisigWallet(
            name="Cold storage",
            address_type=AddressType.WIT,
            threshold=2,
            keys_info=[
                other_key_info,                       # some other bitcoiner
                f"[{fpr}/48'/1'/0'/2']{our_pubkey}",  # that's us
            ],
        )

        policy_id, policy_hmac = client.register_wallet(multisig_policy)

        print(f"Policy hmac: {policy_hmac.hex()}. Store it safely (together with the policy).")

        assert policy_id == multisig_policy.id  # should never fail

        # ==> Derive and show an address for "Cold storage"

        multisig_address = client.get_wallet_address(multisig_policy, policy_hmac, change=0, address_index=0, display=True)
        print(f"Multisig wallet address: {multisig_address}")

        # ==> Sign a psbt

        # TODO: set a wallet policy and a valid psbt file in order to test psbt signing
        psbt_filename: Optional[str] = None
        signing_policy: Optional[WalletPolicy] = None
        signing_policy_hmac: Optional[bytes] = None
        if not psbt_filename or not signing_policy:
            print("Nothing to sign :(")
            return

        raw_psbt_base64 = open(psbt_filename, "r").read()
        psbt = PSBT()
        psbt.deserialize(raw_psbt_base64)

        result = client.sign_psbt(psbt, signing_policy, signing_policy_hmac)

        print("Returned signatures:")
        print(result)

if __name__ == "__main__":
    main()
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/LedgerHQ/app-bitcoin-new",
    "name": "ledger-bitcoin",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "",
    "author": "Ledger",
    "author_email": "hello@ledger.fr",
    "download_url": "https://files.pythonhosted.org/packages/b2/80/5cfc334832a4d783e224a0e05f944f37d7f018871a56c62025c237564b7c/ledger_bitcoin-0.3.0.tar.gz",
    "platform": null,
    "description": "# Ledger Bitcoin application client\n\n## Overview\n\nClient library for Ledger Bitcoin application.\n\nMain repository and documentation: https://github.com/LedgerHQ/app-bitcoin-new\n\n## Install\n\nIf you just want to communicate through TCP socket (for example with the Speculos emulator), there is no dependency:\n\n```bash\n$ pip install ledger_bitcoin\n```\n\notherwise, [hidapi](https://github.com/trezor/cython-hidapi) must be installed as an extra dependency:\n\n```bash\n$ pip install ledger_bitcoin[hid]\n```\n\n## Getting started\n\nThe main method exported by the library is `createClient`, which queries the hardware wallet for the version of the running app, and then returns the appropriate implementation of the `Client` class.\n\nSee the documentation of the class and the example below for the supported methods.\n\nWhen running on a legacy version of the app (below version `2.0.0`), only the features that were available on the app are supported. Any unsopported method (e.g.: multisig registration or addresses, taproot addresses) will raise a `NotImplementedError`.\n\n### Running with speculos\n\nIt is possible to run the app and the library with the [speculos](https://github.com/LedgerHQ/speculos) emulator.\n\n\u26a0\ufe0f Currently, speculos does not correctly emulate the version of the app, always returning a dummy value; in order to use the library, it is necessary to set the `SPECULOS_APPNAME` environment variable before starting speculos, for example with:\n\n```\n$ export SPECULOS_APPNAME=\"Bitcoin Test:2.1.0\"\n```\n\nSimilarly, to test the library behavior on a legacy version of the app, one can set the version to `1.6.5` (the final version of the 1.X series).\n\nThe expected application name is `Bitcoin` for mainnet, `Bitcoin Test` for testnet.\n\n### Example\n\nThe following example showcases all the main methods of the `Client`'s interface.\n\nIf you are not using the context manager syntax when creating the client, remember to call the `stop()` method to release the communication channel.\n\nTesting the `sign_psbt` method requires producing a valid PSBT (with any external tool that supports either PSBTv0 or PSBTv2), and provide the corresponding wallet policy; it is skipped by default in the following example.\n\n\n```python\nfrom typing import Optional\nfrom ledger_bitcoin import createClient, Chain, MultisigWallet, MultisigWallet, WalletPolicy, AddressType, TransportClient\nfrom ledger_bitcoin.psbt import PSBT\n\n\ndef main():\n    # speculos on default host/port\n    # with createClient(TransportClient(), chain=Chain.TEST) as client:\n\n    # Ledger Nano connected via USB\n    with createClient(chain=Chain.TEST) as client:\n        # ==> Get the master key fingerprint\n\n        fpr = client.get_master_fingerprint().hex()\n        print(f\"Master key fingerprint: {fpr}\")\n\n        # ==> Get and display on screen the first taproot address\n\n        first_taproot_account_pubkey = client.get_extended_pubkey(\"m/86'/1'/0'\")\n        first_taproot_account_policy = WalletPolicy(\n            \"\",\n            \"tr(@0/**)\",\n            [\n                f\"[{fpr}/86'/1'/0']{first_taproot_account_pubkey}/**\"\n            ],\n        )\n        first_taproot_account_address = client.get_wallet_address(\n            first_taproot_account_policy,\n            None,\n            change=0,\n            address_index=0,\n            display=True # show address on the wallet's screen\n        )\n\n        print(f\"First taproot account receive address: {first_taproot_account_address}\")\n\n        # ==> Register a multisig wallet named \"Cold storage\"\n\n        our_pubkey = client.get_extended_pubkey(\"m/48'/1'/0'/2'\")\n        other_key_info = \"[76223a6e/48'/1'/0'/2']tpubDE7NQymr4AFtewpAsWtnreyq9ghkzQBXpCZjWLFVRAvnbf7vya2eMTvT2fPapNqL8SuVvLQdbUbMfWLVDCZKnsEBqp6UK93QEzL8Ck23AwF/**\"\n\n        multisig_policy = MultisigWallet(\n            name=\"Cold storage\",\n            address_type=AddressType.WIT,\n            threshold=2,\n            keys_info=[\n                other_key_info,                       # some other bitcoiner\n                f\"[{fpr}/48'/1'/0'/2']{our_pubkey}\",  # that's us\n            ],\n        )\n\n        policy_id, policy_hmac = client.register_wallet(multisig_policy)\n\n        print(f\"Policy hmac: {policy_hmac.hex()}. Store it safely (together with the policy).\")\n\n        assert policy_id == multisig_policy.id  # should never fail\n\n        # ==> Derive and show an address for \"Cold storage\"\n\n        multisig_address = client.get_wallet_address(multisig_policy, policy_hmac, change=0, address_index=0, display=True)\n        print(f\"Multisig wallet address: {multisig_address}\")\n\n        # ==> Sign a psbt\n\n        # TODO: set a wallet policy and a valid psbt file in order to test psbt signing\n        psbt_filename: Optional[str] = None\n        signing_policy: Optional[WalletPolicy] = None\n        signing_policy_hmac: Optional[bytes] = None\n        if not psbt_filename or not signing_policy:\n            print(\"Nothing to sign :(\")\n            return\n\n        raw_psbt_base64 = open(psbt_filename, \"r\").read()\n        psbt = PSBT()\n        psbt.deserialize(raw_psbt_base64)\n\n        result = client.sign_psbt(psbt, signing_policy, signing_policy_hmac)\n\n        print(\"Returned signatures:\")\n        print(result)\n\nif __name__ == \"__main__\":\n    main()\n```\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Client for Ledger Nano Bitcoin application",
    "version": "0.3.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/LedgerHQ/app-bitcoin-new/issues",
        "Homepage": "https://github.com/LedgerHQ/app-bitcoin-new"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "460e9ee7e51fd030e8cf3760af4f54b45c7aed19d52d354f23d8c3574002618c",
                "md5": "752717a9dfd2893cce6b0619628bb1ae",
                "sha256": "e7c33404d02044c3810b294a510f7ad97bc65ab12dbdd180d873f2b4ebc0711a"
            },
            "downloads": -1,
            "filename": "ledger_bitcoin-0.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "752717a9dfd2893cce6b0619628bb1ae",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 118718,
            "upload_time": "2024-02-15T14:45:54",
            "upload_time_iso_8601": "2024-02-15T14:45:54.585213Z",
            "url": "https://files.pythonhosted.org/packages/46/0e/9ee7e51fd030e8cf3760af4f54b45c7aed19d52d354f23d8c3574002618c/ledger_bitcoin-0.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b2805cfc334832a4d783e224a0e05f944f37d7f018871a56c62025c237564b7c",
                "md5": "5f33b7cc215d94842b644aff623035d7",
                "sha256": "ad9cdeaf33a45562bbd5bae6751025b869a2f81d6eb0267dd062a01f5925a4d5"
            },
            "downloads": -1,
            "filename": "ledger_bitcoin-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "5f33b7cc215d94842b644aff623035d7",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 103125,
            "upload_time": "2024-02-15T14:47:58",
            "upload_time_iso_8601": "2024-02-15T14:47:58.051281Z",
            "url": "https://files.pythonhosted.org/packages/b2/80/5cfc334832a4d783e224a0e05f944f37d7f018871a56c62025c237564b7c/ledger_bitcoin-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-15 14:47:58",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "LedgerHQ",
    "github_project": "app-bitcoin-new",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "ledger-bitcoin"
}
        
Elapsed time: 0.35490s