diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 0ddd342..1cfa1af 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -1,21 +1,25 @@ # This workflow will install Swap package dependencies, run tests and lint with a variety of Python versions. -name: workflow +name: hdwallet-workflow on: push: - branches: [master] + branches: [ + master + ] pull_request: - branches: [master] + branches: [ + master + ] jobs: python: - runs-on: ubuntu-latest strategy: matrix: - python-version: [3.6, 3.7, 3.8, 3.9] - + python-version: [ + "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" + ] steps: - uses: actions/checkout@master - name: Set up Python ${{ matrix.python-version }} @@ -25,6 +29,6 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -e .[tests] + pip install -e .[cli,tests,docs] - name: Test with pytest run: pytest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..db67ce9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,27 @@ +name: Release + +on: + push: + branches: + - master + +jobs: + pypi-publish: + name: Upload release to PyPI + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/python-hdwallet-slip39 + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + - name: Build + run: | + python -m pip install -r requirements-dev.txt + python -m build . + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore index 3c1a6c2..022fb51 100644 --- a/.gitignore +++ b/.gitignore @@ -4,9 +4,11 @@ make.bat Makefile # Folders stuff +env/ experiment/ .idea/ .tox/ +.vs/ # Setuptools stuff build/ @@ -18,3 +20,5 @@ __pycache__/ # py.test stuff .pytest_cache/ +*~ +.#* diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 12d2ae5..de81385 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,15 +1,23 @@ +# .readthedocs.yaml + version: 2 -formats: all -sphinx: - builder: html - configuration: docs/conf.py - fail_on_warning: false +build: + os: ubuntu-22.04 + tools: + python: "3.11" python: - version: 3.8 install: - method: pip path: . extra_requirements: - - docs \ No newline at end of file + - cli + - docs + +formats: all + +sphinx: + builder: html + configuration: docs/conf.py + fail_on_warning: false diff --git a/.travis.yml b/.travis.yml index 32023d4..abb78b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,20 @@ language: python -dist: xenial -sudo: true +dist: bionic +before_install: + - python -m pip install --upgrade pip install: - - sudo add-apt-repository -y ppa:deadsnakes/ppa - - sudo apt-get update - - sudo apt-get install -y python$TRAVIS_PYTHON_VERSION-dev - - pip install -e .[tests,docs] tox-travis coveralls + - pip install -e .[cli,tests,docs] tox-travis coveralls matrix: include: - - name: "3.6" - python: 3.6 - name: "3.7" python: 3.7 - name: "3.8" python: 3.8 - name: "3.9" python: 3.9 -script: pytest -after_success: if [ "${TRAVIS_PYTHON_VERSION}" == "3.9" ]; then coveralls; fi; \ No newline at end of file + - name: "3.10" + python: 3.10 + - name: "3.11" + python: 3.11 +script: tox +after_success: if [ "${TRAVIS_PYTHON_VERSION}" == "3.11" ]; then coveralls; fi; \ No newline at end of file diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..17b5862 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,57 @@ +SHELL = /bin/bash +PY3 ?= $(shell python3 --version >/dev/null 2>&1 && echo python3 || echo python ) +PY3_V = $(shell $(PY3) -c "import sys; print('-'.join((next(iter(filter(None,sys.executable.split('/')))),sys.platform,sys.implementation.cache_tag)))" 2>/dev/null ) +VERSION = $(shell $(PY3) -c 'exec(open("hdwallet/version.py", "r").read()); print( __version__.strip("v"))') +WHEEL = dist/hdwallet-$(VERSION)-py3-none-any.whl + +PY3TEST = $(PY3) -m pytest + +GHUB_NAME = python-hdwallet +VENV_DIR = $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/.. ) +VENV_NAME = $(GHUB_NAME)-$(VERSION)-$(PY3_V) +VENV = $(VENV_DIR)/$(VENV_NAME) +VENV_OPTS = + +NIX_OPTS ?= # --pure + +.PHONY: all test build build-check wheel install-dev install clean FORCE + +all: build + +test: + $(PY3TEST) + +# Run only tests with a prefix containing the target string, eg test-blah +test-%: + $(PY3TEST) *$*_test.py + +unit-%: + $(PY3TEST) -k $* + +nix-%: + nix-shell $(NIX_OPTS) --run "make $*" + +build: clean wheel + +wheel: $(WHEEL) + +$(WHEEL): FORCE + $(PY3) -m pip install -r requirements-dev.txt + $(PY3) -m build + @ls -last dist + +install: $(WHEEL) FORCE + $(PY3) -m pip install --force-reinstall .[cli,docs] + +clean: + @rm -rf build dist *.egg-info $(shell find . -name '__pycache__' ) + +venv: $(VENV) + @echo; echo "*** Activating $< VirtualEnv for Interactive $(SHELL)" + @bash --init-file $ +Copyright © 2021-2022, Meheret Tesfaye Batu -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index a179080..61bf6c0 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include LICENSE include README.md -include requirements.txt +include requirements*.txt +global-exclude *~ recursive-exclude * __pycache__ recursive-exclude * *.py[co] \ No newline at end of file diff --git a/README.md b/README.md index 406156c..2519395 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,26 @@ - # Hierarchical Deterministic Wallet -[![Build Status](https://travis-ci.org/meherett/python-hdwallet.svg?branch=master)](https://travis-ci.org/meherett/python-hdwallet?branch=master) +> Note: This hdwallet-slip39 package is a temporary upgrade shim for the great hdwallet package +> https://pypi.org/project/hdwallet/. + +> Use it only until the upstream hdwallet package merges support for BSC, Nix, etc in : +> https://github.com/meherett/python-hdwallet/pull/1020 + +> Until then, substitute "hdwallet-slip39" for "hdwallet" in your "pip install" or requirements.txt +> Both supply the hdwallet package, eg. "import hdwallet". Specify version >= 2.3 to ensure you are +> using this shim. + +[![Build Status](https://app.travis-ci.com/meherett/python-hdwallet.svg?branch=master)](https://app.travis-ci.com/meherett/python-hdwallet) [![PyPI Version](https://img.shields.io/pypi/v/hdwallet.svg?color=blue)](https://pypi.org/project/hdwallet) -[![Documentation Status](https://readthedocs.org/projects/hdwallet/badge/?version=master)](https://hdwallet.readthedocs.io/en/master/?badge=master) +[![Documentation Status](https://readthedocs.org/projects/hdwallet/badge/?version=master)](https://hdwallet.readthedocs.io) +[![PyPI License](https://img.shields.io/pypi/l/hdwallet?color=black)](https://pypi.org/project/hdwallet) [![PyPI Python Version](https://img.shields.io/pypi/pyversions/hdwallet.svg)](https://pypi.org/project/hdwallet) -[![Coverage Status](https://coveralls.io/repos/github/meherett/python-hdwallet/badge.svg?branch=master)](https://coveralls.io/github/meherett/python-hdwallet?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/meherett/python-hdwallet/badge.svg?branch=master)](https://coveralls.io/github/meherett/python-hdwallet) Python-based library for the implementation of a hierarchical deterministic wallet generator for more than 140+ multiple cryptocurrencies. -It allows the handling of multiple coins, multiple accounts, external and internal chains per account and millions of addresses per the chain. +It allows the handling of multiple coins, multiple accounts, external and internal chains per account and millions of addresses per chain. + +![HDWallet-CLI](https://raw.githubusercontent.com/meherett/python-hdwallet/master/docs/static/svg/hdwallet-cli.svg) For more info see the BIP specs. @@ -19,17 +31,23 @@ For more info see the BIP specs. | [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) | Hierarchical Deterministic Wallets | | [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) | Multi-Account Hierarchy for Deterministic Wallets | | [BIP49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki) | Derivation scheme for P2WPKH-nested-in-P2SH based accounts | -| [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0048.mediawiki) | Derivation scheme for P2WPKH based accounts | -| [BIP141](https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) | Segregated Witness (Consensus layer) | +| [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki) | Derivation scheme for P2WPKH based accounts | +| [BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) | Segregated Witness (Consensus layer) | ## Installation -PIP to install `hdwallet` globally, for Linux `sudo` may be required: +The easiest way to install `hdwallet` is via pip: ``` pip install hdwallet ``` +To install `hdwallet` command line interface globally, for Linux `sudo` may be required: + +``` +pip install hdwallet[cli] +``` + If you want to run the latest version of the code, you can install from the git: ``` @@ -40,14 +58,14 @@ For the versions available, see the [tags on this repository](https://github.com ## Quick Usage -Simple Bitcoin mainnet hierarchical deterministic wallet generator: +Simple Bitcoin mainnet HDWallet generator: ```python #!/usr/bin/env python3 from hdwallet import HDWallet from hdwallet.utils import generate_entropy -from hdwallet.symbols import BTC +from hdwallet.symbols import BTC as SYMBOL from typing import Optional import json @@ -62,7 +80,7 @@ ENTROPY: str = generate_entropy(strength=STRENGTH) PASSPHRASE: Optional[str] = None # "meherett" # Initialize Bitcoin mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=BTC) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL, use_default_path=False) # Get Bitcoin HDWallet from entropy hdwallet.from_entropy( entropy=ENTROPY, language=LANGUAGE, passphrase=PASSPHRASE @@ -121,7 +139,7 @@ print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) ``` -Ethereum mainnet [Ganache-CLI](https://github.com/trufflesuite/ganache-cli) wallet look's like: +Ethereum mainnet [Ganache](https://github.com/trufflesuite/ganache) wallet look's like: ```python #!/usr/bin/env python3 @@ -168,7 +186,7 @@ for address_index in range(10): ```shell script Mnemonic: bright demand olive glance crater key head glory quantum leisure intact age -Base HD Path: m/44'/60'/0'/0/{address_index} +Base HD Path: m/44'/60'/0'/0/{address_index} (0) m/44'/60'/0'/0/0 0x3a149f0c5dc5c0F1E29e573215C23710dE9c4f87 0xa45f9af43912fdd5e88c492226be082029f257681d4b3e73b68be535d2fb0526 (1) m/44'/60'/0'/0/1 0x9e8A4fD9bA74DbB0c7F465EF56b47489793AA102 0x6e5ab2a3ae20c7b3a1c0645b03689e88e8cdff16f6a39d6a420bfebc20e8a941 @@ -185,177 +203,193 @@ Base HD Path: m/44'/60'/0'/0/{address_index} [Click this to see more examples :)](https://github.com/meherett/python-hdwallet/blob/master/examples) +## Development + +To get started, just fork this repo, clone it locally, and run: + +``` +pip install -e .[cli,tests,docs] -r requirements.txt +``` + +## Testing + +You can run the tests with: + +``` +pytest +``` + +Or use `tox` to run the complete suite against the full set of build targets, or pytest to run specific +tests against a specific version of Python. + ## Contributing -Feel free to open an [issue](https://github.com/meherett/hdwallet/issues) if you find a problem, -or a pull request if you've solved an issue. And also any help in testing, development, -documentation and other tasks is highly appreciated and useful to the project. +Feel free to open an [issue](https://github.com/meherett/hdwallet/issues) if you find a problem, +or a pull request if you've solved an issue. And also any help in testing, development, +documentation and other tasks is highly appreciated and useful to the project. There are tasks for contributors of all experience levels. For more information, see the [CONTRIBUTING.md](https://github.com/meherett/hdwallet/blob/master/CONTRIBUTING.md) file. ## Available Cryptocurrencies -This library simplifies the process of creating a new HDWallet's for: - -| Cryptocurrencies | Symbols | Mainnet | Testnet | Segwit | Coin Type | Default Paths | -| :---------------------------------------------------------------- | :------------------: | :-----: | :-----: | :----: | :-------: | :------------------: | -| Anon | `ANON` | Yes | No | No | 220 | `m/44'/220'/0'/0/0` | -| Argoneum | `AGM` | Yes | No | No | 421 | `m/44'/421'/0'/0/0` | -| Artax | `XAX` | Yes | No | No | 219 | `m/44'/219'/0'/0/0` | -| Aryacoin | `AYA` | Yes | No | No | 357 | `m/44'/357'/0'/0/0` | -| Asiacoin | `AC` | Yes | No | No | 51 | `m/44'/51'/0'/0/0` | -| Atom | `ATOM` | Yes | No | Yes | 118 | `m/44'/118'/0'/0/0` | -| Auroracoin | `AUR` | Yes | No | No | 85 | `m/44'/85'/0'/0/0` | -| Axe | `AXE` | Yes | No | No | 4242 | `m/44'/4242'/0'/0/0` | -| Bata | `BTA` | Yes | No | No | 89 | `m/44'/89'/0'/0/0` | -| Beetle Coin | `BEET` | Yes | No | No | 800 | `m/44'/800'/0'/0/0` | -| Bela Coin | `BELA` | Yes | No | No | 73 | `m/44'/73'/0'/0/0` | -| Bit Cloud | `BTDX` | Yes | No | No | 218 | `m/44'/218'/0'/0/0` | -| Bit Send | `BSD` | Yes | No | No | 91 | `m/44'/91'/0'/0/0` | -| [Bitcoin Cash](https://github.com/bitcoincashorg/bitcoincash.org) | `BCH` | Yes | No | Yes | 145 | `m/44'/145'/0'/0/0` | -| [Bitcoin Gold](https://github.com/BTCGPU/BTCGPU) | `BTG` | Yes | No | Yes | 156 | `m/44'/156'/0'/0/0` | -| [Bitcoin](https://github.com/bitcoin/bitcoin) | `BTC`, `BTCTEST` | Yes | Yes | Yes | 0 | `m/44'/0'/0'/0/0` | -| Bitcoin Plus | `XBC` | Yes | No | No | 65 | `m/44'/65'/0'/0/0` | -| Bitcoin SV | `BSV` | Yes | No | No | 236 | `m/44'/236'/0'/0/0` | -| BitcoinZ | `BTCZ` | Yes | No | No | 177 | `m/44'/177'/0'/0/0` | -| Bitcore | `BTX` | Yes | No | Yes | 160 | `m/44'/160'/0'/0/0` | -| Blackcoin | `BLK` | Yes | No | No | 10 | `m/44'/10'/0'/0/0` | -| Block Stamp | `BST` | Yes | No | Yes | 254 | `m/44'/254'/0'/0/0` | -| Blocknode | `BND`, `BNDTEST` | Yes | Yes | No | 2941 | `m/44'/2941'/0'/0/0` | -| Bolivarcoin | `BOLI` | Yes | No | No | 278 | `m/44'/278'/0'/0/0` | -| Brit Coin | `BRIT` | Yes | No | No | 70 | `m/44'/70'/0'/0/0` | -| CPU Chain | `CPU` | Yes | No | Yes | 363 | `m/44'/363'/0'/0/0` | -| Canada eCoin | `CDN` | Yes | No | No | 34 | `m/44'/34'/0'/0/0` | -| Cannacoin | `CCN` | Yes | No | No | 19 | `m/44'/19'/0'/0/0` | -| Clams | `CLAM` | Yes | No | No | 23 | `m/44'/23'/0'/0/0` | -| Club Coin | `CLUB` | Yes | No | No | 79 | `m/44'/79'/0'/0/0` | -| Compcoin | `CMP` | Yes | No | No | 71 | `m/44'/71'/0'/0/0` | -| Crane Pay | `CRP` | Yes | No | Yes | 2304 | `m/44'/2304'/0'/0/0` | -| Crave | `CRAVE` | Yes | No | No | 186 | `m/44'/186'/0'/0/0` | -| [Dash](https://github.com/dashpay/dash) | `DASH`, `DASHTEST` | Yes | Yes | No | 5 | `m/44'/5'/0'/0/0` | -| Deep Onion | `ONION` | Yes | No | Yes | 305 | `m/44'/305'/0'/0/0` | -| Defcoin | `DFC` | Yes | No | No | 1337 | `m/44'/1337'/0'/0/0` | -| Denarius | `DNR` | Yes | No | No | 116 | `m/44'/116'/0'/0/0` | -| Diamond | `DMD` | Yes | No | No | 152 | `m/44'/152'/0'/0/0` | -| Digi Byte | `DGB` | Yes | No | Yes | 20 | `m/44'/20'/0'/0/0` | -| Digitalcoin | `DGC` | Yes | No | No | 18 | `m/44'/18'/0'/0/0` | -| [Dogecoin](https://github.com/dogecoin/dogecoin) | `DOGE`, `DOGETEST` | Yes | Yes | No | 3 | `m/44'/3'/0'/0/0` | -| EDR Coin | `EDRC` | Yes | No | No | 56 | `m/44'/56'/0'/0/0` | -| Ecoin | `ECN` | Yes | No | No | 115 | `m/44'/115'/0'/0/0` | -| Einsteinium | `EMC2` | Yes | No | No | 41 | `m/44'/41'/0'/0/0` | -| Elastos | `ELA` | Yes | No | No | 2305 | `m/44'/2305'/0'/0/0` | -| Energi | `NRG` | Yes | No | No | 9797 | `m/44'/9797'/0'/0/0` | -| [Ethereum](https://github.com/ethereum/go-ethereum) | `ETH` | Yes | No | Yes | 60 | `m/44'/60'/0'/0/0` | -| Europe Coin | `ERC` | Yes | No | No | 151 | `m/44'/151'/0'/0/0` | -| Exclusive Coin | `EXCL` | Yes | No | No | 190 | `m/44'/190'/0'/0/0` | -| FIX | `FIX`, `FIXTEST` | Yes | Yes | No | 336 | `m/44'/336'/0'/0/0` | -| Feathercoin | `FTC` | Yes | No | No | 8 | `m/44'/8'/0'/0/0` | -| Firstcoin | `FRST` | Yes | No | No | 167 | `m/44'/167'/0'/0/0` | -| Flashcoin | `FLASH` | Yes | No | No | 120 | `m/44'/120'/0'/0/0` | -| Fuji Coin | `FJC` | Yes | No | Yes | 75 | `m/44'/75'/0'/0/0` | -| GCR Coin | `GCR` | Yes | No | No | 49 | `m/44'/49'/0'/0/0` | -| Game Credits | `GAME` | Yes | No | No | 101 | `m/44'/101'/0'/0/0` | -| Go Byte | `GBX` | Yes | No | No | 176 | `m/44'/176'/0'/0/0` | -| Gridcoin | `GRC` | Yes | No | No | 84 | `m/44'/84'/0'/0/0` | -| Groestl Coin | `GRS`, `GRSTEST` | Yes | Yes | Yes | 17 | `m/44'/17'/0'/0/0` | -| Gulden | `NLG` | Yes | No | No | 87 | `m/44'/87'/0'/0/0` | -| Helleniccoin | `HNC` | Yes | No | No | 168 | `m/44'/168'/0'/0/0` | -| Hempcoin | `THC` | Yes | No | No | 113 | `m/44'/113'/0'/0/0` | -| Hush | `HUSH` | Yes | No | No | 197 | `m/44'/197'/0'/0/0` | -| IX Coin | `IXC` | Yes | No | No | 86 | `m/44'/86'/0'/0/0` | -| Insane Coin | `INSN` | Yes | No | No | 68 | `m/44'/68'/0'/0/0` | -| Internet Of People | `IOP` | Yes | No | No | 66 | `m/44'/66'/0'/0/0` | -| Jumbucks | `JBS` | Yes | No | No | 26 | `m/44'/26'/0'/0/0` | -| Kobocoin | `KOBO` | Yes | No | No | 196 | `m/44'/196'/0'/0/0` | -| Komodo | `KMD` | Yes | No | No | 141 | `m/44'/141'/0'/0/0` | -| LBRY Credits | `LBC` | Yes | No | No | 140 | `m/44'/140'/0'/0/0` | -| Linx | `LINX` | Yes | No | No | 114 | `m/44'/114'/0'/0/0` | -| Litecoin Cash | `LCC` | Yes | No | No | 192 | `m/44'/192'/0'/0/0` | -| [Litecoin](https://github.com/litecoin-project/litecoin) | `LTC`, `LTCTEST` | Yes | Yes | Yes | 2 | `m/44'/2'/0'/0/0` | -| LitecoinZ | `LTZ` | Yes | No | No | 221 | `m/44'/221'/0'/0/0` | -| Lkrcoin | `LKR` | Yes | No | No | 557 | `m/44'/557'/0'/0/0` | -| Lynx | `LYNX` | Yes | No | No | 191 | `m/44'/191'/0'/0/0` | -| Mazacoin | `MZC` | Yes | No | No | 13 | `m/44'/13'/0'/0/0` | -| Megacoin | `MEC` | Yes | No | No | 217 | `m/44'/217'/0'/0/0` | -| Minexcoin | `MNX` | Yes | No | No | 182 | `m/44'/182'/0'/0/0` | -| Monacoin | `MONA` | Yes | No | Yes | 22 | `m/44'/22'/0'/0/0` | -| Monkey Project | `MONK` | Yes | No | Yes | 214 | `m/44'/214'/0'/0/0` | -| Myriadcoin | `XMY` | Yes | No | No | 90 | `m/44'/90'/0'/0/0` | -| NIX | `NIX` | Yes | No | Yes | 400 | `m/44'/400'/0'/0/0` | -| Namecoin | `NMC` | Yes | No | No | 7 | `m/44'/7'/0'/0/0` | -| [Navcoin](https://github.com/navcoin/navcoin-core) | `NAV` | Yes | No | No | 130 | `m/44'/130'/0'/0/0` | -| Neblio | `NEBL` | Yes | No | No | 146 | `m/44'/146'/0'/0/0` | -| Neoscoin | `NEOS` | Yes | No | No | 25 | `m/44'/25'/0'/0/0` | -| Neurocoin | `NRO` | Yes | No | No | 110 | `m/44'/110'/0'/0/0` | -| New York Coin | `NYC` | Yes | No | No | 179 | `m/44'/179'/0'/0/0` | -| Novacoin | `NVC` | Yes | No | No | 50 | `m/44'/50'/0'/0/0` | -| NuBits | `NBT` | Yes | No | No | 12 | `m/44'/12'/0'/0/0` | -| NuShares | `NSR` | Yes | No | No | 11 | `m/44'/11'/0'/0/0` | -| OK Cash | `OK` | Yes | No | No | 69 | `m/44'/69'/0'/0/0` | -| [Omni](https://github.com/omnilayer/omnicore) | `OMNI`, `OMNITEST` | Yes | Yes | No | 200 | `m/44'/200'/0'/0/0` | -| Onix Coin | `ONX` | Yes | No | No | 174 | `m/44'/174'/0'/0/0` | -| Peercoin | `PPC` | Yes | No | No | 6 | `m/44'/6'/0'/0/0` | -| Pesobit | `PSB` | Yes | No | No | 62 | `m/44'/62'/0'/0/0` | -| Phore | `PHR` | Yes | No | No | 444 | `m/44'/444'/0'/0/0` | -| Pinkcoin | `PINK` | Yes | No | No | 117 | `m/44'/117'/0'/0/0` | -| Pivx | `PIVX`, `PIVXTEST` | Yes | Yes | No | 119 | `m/44'/119'/0'/0/0` | -| Posw Coin | `POSW` | Yes | No | No | 47 | `m/44'/47'/0'/0/0` | -| Potcoin | `POT` | Yes | No | No | 81 | `m/44'/81'/0'/0/0` | -| Project Coin | `PRJ` | Yes | No | No | 533 | `m/44'/533'/0'/0/0` | -| Putincoin | `PUT` | Yes | No | No | 122 | `m/44'/122'/0'/0/0` | -| [Qtum](https://github.com/qtumproject/qtum) | `QTUM`, `QTUMTEST` | Yes | Yes | Yes | 2301 | `m/44'/2301'/0'/0/0` | -| RSK | `RBTC`, `RBTCTEST` | Yes | Yes | No | 137 | `m/44'/137'/0'/0/0` | -| Rapids | `RPD` | Yes | No | No | 320 | `m/44'/320'/0'/0/0` | -| Ravencoin | `RVN` | Yes | No | No | 175 | `m/44'/175'/0'/0/0` | -| Reddcoin | `RDD` | Yes | No | No | 4 | `m/44'/4'/0'/0/0` | -| Rubycoin | `RBY` | Yes | No | No | 16 | `m/44'/16'/0'/0/0` | -| Safecoin | `SAFE` | Yes | No | No | 19165 | `m/44'/19165'/0'/0/0` | -| Saluscoin | `SLS` | Yes | No | No | 572 | `m/44'/572'/0'/0/0` | -| Scribe | `SCRIBE` | Yes | No | No | 545 | `m/44'/545'/0'/0/0` | -| [Shadow Cash](https://github.com/shadowproject/shadow) | `SDC`, `SDCTEST` | Yes | Yes | No | 35 | `m/44'/35'/0'/0/0` | -| Slimcoin | `SLM`, `SLMTEST` | Yes | Yes | No | 63 | `m/44'/63'/0'/0/0` | -| Smileycoin | `SMLY` | Yes | No | No | 59 | `m/44'/59'/0'/0/0` | -| Solarcoin | `SLR` | Yes | No | No | 58 | `m/44'/58'/0'/0/0` | -| Stash | `STASH` | Yes | No | No | 49344 | `m/44'/49344'/0'/0/0` | -| Stratis | `STRAT`, `STRATTEST` | Yes | Yes | No | 105 | `m/44'/105'/0'/0/0` | -| Sugarchain | `SUGAR`, `SUGARTEST` | Yes | Yes | Yes | 408 | `m/44'/408'/0'/0/0` | -| Syscoin | `SYS` | Yes | No | Yes | 57 | `m/44'/57'/0'/0/0` | -| TOA Coin | `TOA` | Yes | No | No | 159 | `m/44'/159'/0'/0/0` | -| Thought AI | `THT` | Yes | No | No | 502 | `m/44'/502'/0'/0/0` | -| Twins | `TWINS`, `TWINSTEST` | Yes | Yes | No | 970 | `m/44'/970'/0'/0/0` | -| Ultimate Secure Cash | `USC` | Yes | No | No | 112 | `m/44'/112'/0'/0/0` | -| Unobtanium | `UNO` | Yes | No | No | 92 | `m/44'/92'/0'/0/0` | -| Virtual Cash | `VASH` | Yes | No | No | 33 | `m/44'/33'/0'/0/0` | -| Vcash | `VC` | Yes | No | No | 127 | `m/44'/127'/0'/0/0` | -| Verge Currency | `XVG` | Yes | No | No | 77 | `m/44'/77'/0'/0/0` | -| Vertcoin | `VTC` | Yes | No | Yes | 28 | `m/44'/28'/0'/0/0` | -| [Viacoin](https://github.com/viacoin/viacore-viacoin) | `VIA`, `VIATEST` | Yes | Yes | Yes | 14 | `m/44'/14'/0'/0/0` | -| Vivo | `VIVO` | Yes | No | No | 166 | `m/44'/166'/0'/0/0` | -| Whitecoin | `XWC` | Yes | No | No | 559 | `m/44'/559'/0'/0/0` | -| Wincoin | `WC` | Yes | No | No | 181 | `m/44'/181'/0'/0/0` | -| XUEZ | `XUEZ` | Yes | No | No | 225 | `m/44'/225'/0'/0/0` | -| [XinFin](https://github.com/XinFinOrg/XDPoSChain) | `XDC` | Yes | No | Yes | 550 | `m/44'/550'/0'/0/0` | -| ZClassic | `ZCL` | Yes | No | No | 147 | `m/44'/147'/0'/0/0` | -| Zcash | `ZEC` | Yes | No | No | 133 | `m/44'/133'/0'/0/0` | -| Zencash | `ZEN` | Yes | No | No | 121 | `m/44'/121'/0'/0/0` | +This library simplifies the process of creating a new hierarchical deterministic wallets for: + +| Cryptocurrencies | Symbols | Mainnet | Testnet | Segwit | Coin Type | Default Paths | +|:------------------------------------------------------------------|:--------------------:|:-------:|:-------:|:------:|:---------:|:---------------------:| +| Anon | `ANON` | Yes | No | No | 220 | `m/44'/220'/0'/0/0` | +| Argoneum | `AGM` | Yes | No | No | 421 | `m/44'/421'/0'/0/0` | +| Artax | `XAX` | Yes | No | No | 219 | `m/44'/219'/0'/0/0` | +| Aryacoin | `AYA` | Yes | No | No | 357 | `m/44'/357'/0'/0/0` | +| Asiacoin | `AC` | Yes | No | No | 51 | `m/44'/51'/0'/0/0` | +| Atom | `ATOM` | Yes | No | Yes | 118 | `m/44'/118'/0'/0/0` | +| Auroracoin | `AUR` | Yes | No | No | 85 | `m/44'/85'/0'/0/0` | +| Axe | `AXE` | Yes | No | No | 4242 | `m/44'/4242'/0'/0/0` | +| Bata | `BTA` | Yes | No | No | 89 | `m/44'/89'/0'/0/0` | +| Beetle Coin | `BEET` | Yes | No | No | 800 | `m/44'/800'/0'/0/0` | +| Bela Coin | `BELA` | Yes | No | No | 73 | `m/44'/73'/0'/0/0` | +| Bit Cloud | `BTDX` | Yes | No | No | 218 | `m/44'/218'/0'/0/0` | +| Bit Send | `BSD` | Yes | No | No | 91 | `m/44'/91'/0'/0/0` | +| [Bitcoin Cash](https://github.com/bitcoincashorg/bitcoincash.org) | `BCH` | Yes | No | Yes | 145 | `m/44'/145'/0'/0/0` | +| [Bitcoin Gold](https://github.com/BTCGPU/BTCGPU) | `BTG` | Yes | No | Yes | 156 | `m/44'/156'/0'/0/0` | +| [Bitcoin](https://github.com/bitcoin/bitcoin) | `BTC`, `BTCTEST` | Yes | Yes | Yes | 0 | `m/44'/0'/0'/0/0` | +| Bitcoin Plus | `XBC` | Yes | No | No | 65 | `m/44'/65'/0'/0/0` | +| Bitcoin SV | `BSV` | Yes | No | No | 236 | `m/44'/236'/0'/0/0` | +| BitcoinZ | `BTCZ` | Yes | No | No | 177 | `m/44'/177'/0'/0/0` | +| Bitcore | `BTX` | Yes | No | Yes | 160 | `m/44'/160'/0'/0/0` | +| Blackcoin | `BLK` | Yes | No | No | 10 | `m/44'/10'/0'/0/0` | +| Block Stamp | `BST` | Yes | No | Yes | 254 | `m/44'/254'/0'/0/0` | +| Blocknode | `BND`, `BNDTEST` | Yes | Yes | No | 2941 | `m/44'/2941'/0'/0/0` | +| Bolivarcoin | `BOLI` | Yes | No | No | 278 | `m/44'/278'/0'/0/0` | +| Brit Coin | `BRIT` | Yes | No | No | 70 | `m/44'/70'/0'/0/0` | +| CPU Chain | `CPU` | Yes | No | Yes | 363 | `m/44'/363'/0'/0/0` | +| Canada eCoin | `CDN` | Yes | No | No | 34 | `m/44'/34'/0'/0/0` | +| Cannacoin | `CCN` | Yes | No | No | 19 | `m/44'/19'/0'/0/0` | +| Clams | `CLAM` | Yes | No | No | 23 | `m/44'/23'/0'/0/0` | +| Club Coin | `CLUB` | Yes | No | No | 79 | `m/44'/79'/0'/0/0` | +| Compcoin | `CMP` | Yes | No | No | 71 | `m/44'/71'/0'/0/0` | +| Crane Pay | `CRP` | Yes | No | Yes | 2304 | `m/44'/2304'/0'/0/0` | +| Crave | `CRAVE` | Yes | No | No | 186 | `m/44'/186'/0'/0/0` | +| [Dash](https://github.com/dashpay/dash) | `DASH`, `DASHTEST` | Yes | Yes | No | 5 | `m/44'/5'/0'/0/0` | +| Deep Onion | `ONION` | Yes | No | Yes | 305 | `m/44'/305'/0'/0/0` | +| Defcoin | `DFC` | Yes | No | No | 1337 | `m/44'/1337'/0'/0/0` | +| Denarius | `DNR` | Yes | No | No | 116 | `m/44'/116'/0'/0/0` | +| Diamond | `DMD` | Yes | No | No | 152 | `m/44'/152'/0'/0/0` | +| Digi Byte | `DGB` | Yes | No | Yes | 20 | `m/44'/20'/0'/0/0` | +| Digitalcoin | `DGC` | Yes | No | No | 18 | `m/44'/18'/0'/0/0` | +| [Dogecoin](https://github.com/dogecoin/dogecoin) | `DOGE`, `DOGETEST` | Yes | Yes | No | 3 | `m/44'/3'/0'/0/0` | +| EDR Coin | `EDRC` | Yes | No | No | 56 | `m/44'/56'/0'/0/0` | +| Ecoin | `ECN` | Yes | No | No | 115 | `m/44'/115'/0'/0/0` | +| Einsteinium | `EMC2` | Yes | No | No | 41 | `m/44'/41'/0'/0/0` | +| Elastos | `ELA` | Yes | No | No | 2305 | `m/44'/2305'/0'/0/0` | +| Energi | `NRG` | Yes | No | No | 9797 | `m/44'/9797'/0'/0/0` | +| [Ethereum](https://github.com/ethereum/go-ethereum) | `ETH` | Yes | No | Yes | 60 | `m/44'/60'/0'/0/0` | +| Europe Coin | `ERC` | Yes | No | No | 151 | `m/44'/151'/0'/0/0` | +| Exclusive Coin | `EXCL` | Yes | No | No | 190 | `m/44'/190'/0'/0/0` | +| FIX | `FIX`, `FIXTEST` | Yes | Yes | No | 336 | `m/44'/336'/0'/0/0` | +| Feathercoin | `FTC` | Yes | No | No | 8 | `m/44'/8'/0'/0/0` | +| Firstcoin | `FRST` | Yes | No | No | 167 | `m/44'/167'/0'/0/0` | +| Flashcoin | `FLASH` | Yes | No | No | 120 | `m/44'/120'/0'/0/0` | +| [Flux](https://github.com/RunOnFlux/fluxd) | `FLUX` | Yes | No | No | 19167 | `m/44'/19167'/0'/0/0` | +| Fuji Coin | `FJC` | Yes | No | Yes | 75 | `m/44'/75'/0'/0/0` | +| GCR Coin | `GCR` | Yes | No | No | 49 | `m/44'/49'/0'/0/0` | +| Game Credits | `GAME` | Yes | No | No | 101 | `m/44'/101'/0'/0/0` | +| Go Byte | `GBX` | Yes | No | No | 176 | `m/44'/176'/0'/0/0` | +| Gridcoin | `GRC` | Yes | No | No | 84 | `m/44'/84'/0'/0/0` | +| Groestl Coin | `GRS`, `GRSTEST` | Yes | Yes | Yes | 17 | `m/44'/17'/0'/0/0` | +| Gulden | `NLG` | Yes | No | No | 87 | `m/44'/87'/0'/0/0` | +| Helleniccoin | `HNC` | Yes | No | No | 168 | `m/44'/168'/0'/0/0` | +| Hempcoin | `THC` | Yes | No | No | 113 | `m/44'/113'/0'/0/0` | +| Hush | `HUSH` | Yes | No | No | 197 | `m/44'/197'/0'/0/0` | +| IX Coin | `IXC` | Yes | No | No | 86 | `m/44'/86'/0'/0/0` | +| Insane Coin | `INSN` | Yes | No | No | 68 | `m/44'/68'/0'/0/0` | +| Internet Of People | `IOP` | Yes | No | No | 66 | `m/44'/66'/0'/0/0` | +| Jumbucks | `JBS` | Yes | No | No | 26 | `m/44'/26'/0'/0/0` | +| Kobocoin | `KOBO` | Yes | No | No | 196 | `m/44'/196'/0'/0/0` | +| Komodo | `KMD` | Yes | No | No | 141 | `m/44'/141'/0'/0/0` | +| LBRY Credits | `LBC` | Yes | No | No | 140 | `m/44'/140'/0'/0/0` | +| Linx | `LINX` | Yes | No | No | 114 | `m/44'/114'/0'/0/0` | +| Litecoin Cash | `LCC` | Yes | No | No | 192 | `m/44'/192'/0'/0/0` | +| [Litecoin](https://github.com/litecoin-project/litecoin) | `LTC`, `LTCTEST` | Yes | Yes | Yes | 2 | `m/44'/2'/0'/0/0` | +| LitecoinZ | `LTZ` | Yes | No | No | 221 | `m/44'/221'/0'/0/0` | +| Lkrcoin | `LKR` | Yes | No | No | 557 | `m/44'/557'/0'/0/0` | +| Lynx | `LYNX` | Yes | No | No | 191 | `m/44'/191'/0'/0/0` | +| Mazacoin | `MZC` | Yes | No | No | 13 | `m/44'/13'/0'/0/0` | +| Megacoin | `MEC` | Yes | No | No | 217 | `m/44'/217'/0'/0/0` | +| Minexcoin | `MNX` | Yes | No | No | 182 | `m/44'/182'/0'/0/0` | +| Monacoin | `MONA` | Yes | No | Yes | 22 | `m/44'/22'/0'/0/0` | +| Monkey Project | `MONK` | Yes | No | Yes | 214 | `m/44'/214'/0'/0/0` | +| Myriadcoin | `XMY` | Yes | No | No | 90 | `m/44'/90'/0'/0/0` | +| NIX | `NIX` | Yes | No | Yes | 400 | `m/44'/400'/0'/0/0` | +| Namecoin | `NMC` | Yes | No | No | 7 | `m/44'/7'/0'/0/0` | +| [Navcoin](https://github.com/navcoin/navcoin-core) | `NAV` | Yes | No | No | 130 | `m/44'/130'/0'/0/0` | +| Neblio | `NEBL` | Yes | No | No | 146 | `m/44'/146'/0'/0/0` | +| Neoscoin | `NEOS` | Yes | No | No | 25 | `m/44'/25'/0'/0/0` | +| Neurocoin | `NRO` | Yes | No | No | 110 | `m/44'/110'/0'/0/0` | +| New York Coin | `NYC` | Yes | No | No | 179 | `m/44'/179'/0'/0/0` | +| Novacoin | `NVC` | Yes | No | No | 50 | `m/44'/50'/0'/0/0` | +| NuBits | `NBT` | Yes | No | No | 12 | `m/44'/12'/0'/0/0` | +| NuShares | `NSR` | Yes | No | No | 11 | `m/44'/11'/0'/0/0` | +| OK Cash | `OK` | Yes | No | No | 69 | `m/44'/69'/0'/0/0` | +| [Omni](https://github.com/omnilayer/omnicore) | `OMNI`, `OMNITEST` | Yes | Yes | No | 200 | `m/44'/200'/0'/0/0` | +| Onix Coin | `ONX` | Yes | No | No | 174 | `m/44'/174'/0'/0/0` | +| Peercoin | `PPC` | Yes | No | No | 6 | `m/44'/6'/0'/0/0` | +| Pesobit | `PSB` | Yes | No | No | 62 | `m/44'/62'/0'/0/0` | +| Phore | `PHR` | Yes | No | No | 444 | `m/44'/444'/0'/0/0` | +| Pinkcoin | `PINK` | Yes | No | No | 117 | `m/44'/117'/0'/0/0` | +| Pivx | `PIVX`, `PIVXTEST` | Yes | Yes | No | 119 | `m/44'/119'/0'/0/0` | +| Posw Coin | `POSW` | Yes | No | No | 47 | `m/44'/47'/0'/0/0` | +| Potcoin | `POT` | Yes | No | No | 81 | `m/44'/81'/0'/0/0` | +| Project Coin | `PRJ` | Yes | No | No | 533 | `m/44'/533'/0'/0/0` | +| Putincoin | `PUT` | Yes | No | No | 122 | `m/44'/122'/0'/0/0` | +| [Qtum](https://github.com/qtumproject/qtum) | `QTUM`, `QTUMTEST` | Yes | Yes | Yes | 2301 | `m/44'/2301'/0'/0/0` | +| RSK | `RBTC`, `RBTCTEST` | Yes | Yes | No | 137 | `m/44'/137'/0'/0/0` | +| Rapids | `RPD` | Yes | No | No | 320 | `m/44'/320'/0'/0/0` | +| Ravencoin | `RVN` | Yes | No | No | 175 | `m/44'/175'/0'/0/0` | +| Reddcoin | `RDD` | Yes | No | No | 4 | `m/44'/4'/0'/0/0` | +| Ripple | `XRP` | Yes | No | No | 144 | `m/44'/144'/0'/0/0` | +| Rubycoin | `RBY` | Yes | No | No | 16 | `m/44'/16'/0'/0/0` | +| Safecoin | `SAFE` | Yes | No | No | 19165 | `m/44'/19165'/0'/0/0` | +| Saluscoin | `SLS` | Yes | No | No | 572 | `m/44'/572'/0'/0/0` | +| Scribe | `SCRIBE` | Yes | No | No | 545 | `m/44'/545'/0'/0/0` | +| [Shadow Cash](https://github.com/shadowproject/shadow) | `SDC`, `SDCTEST` | Yes | Yes | No | 35 | `m/44'/35'/0'/0/0` | +| Slimcoin | `SLM`, `SLMTEST` | Yes | Yes | No | 63 | `m/44'/63'/0'/0/0` | +| Smileycoin | `SMLY` | Yes | No | No | 59 | `m/44'/59'/0'/0/0` | +| Solarcoin | `SLR` | Yes | No | No | 58 | `m/44'/58'/0'/0/0` | +| Stash | `STASH` | Yes | No | No | 49344 | `m/44'/49344'/0'/0/0` | +| Stratis | `STRAT`, `STRATTEST` | Yes | Yes | No | 105 | `m/44'/105'/0'/0/0` | +| Sugarchain | `SUGAR`, `SUGARTEST` | Yes | Yes | Yes | 408 | `m/44'/408'/0'/0/0` | +| Syscoin | `SYS` | Yes | No | Yes | 57 | `m/44'/57'/0'/0/0` | +| TOA Coin | `TOA` | Yes | No | No | 159 | `m/44'/159'/0'/0/0` | +| Thought AI | `THT` | Yes | No | No | 502 | `m/44'/502'/0'/0/0` | +| [Tron](https://github.com/tronprotocol/java-tron) | `TRX` | Yes | No | No | 195 | `m/44'/195'/0'/0/0` | +| Twins | `TWINS`, `TWINSTEST` | Yes | Yes | No | 970 | `m/44'/970'/0'/0/0` | +| Ultimate Secure Cash | `USC` | Yes | No | No | 112 | `m/44'/112'/0'/0/0` | +| Unobtanium | `UNO` | Yes | No | No | 92 | `m/44'/92'/0'/0/0` | +| Virtual Cash | `VASH` | Yes | No | No | 33 | `m/44'/33'/0'/0/0` | +| Vcash | `VC` | Yes | No | No | 127 | `m/44'/127'/0'/0/0` | +| Verge Currency | `XVG` | Yes | No | No | 77 | `m/44'/77'/0'/0/0` | +| Vertcoin | `VTC` | Yes | No | Yes | 28 | `m/44'/28'/0'/0/0` | +| [Viacoin](https://github.com/viacoin/viacore-viacoin) | `VIA`, `VIATEST` | Yes | Yes | Yes | 14 | `m/44'/14'/0'/0/0` | +| Vivo | `VIVO` | Yes | No | No | 166 | `m/44'/166'/0'/0/0` | +| Whitecoin | `XWC` | Yes | No | No | 559 | `m/44'/559'/0'/0/0` | +| Wincoin | `WC` | Yes | No | No | 181 | `m/44'/181'/0'/0/0` | +| XUEZ | `XUEZ` | Yes | No | No | 225 | `m/44'/225'/0'/0/0` | +| [XinFin](https://github.com/XinFinOrg/XDPoSChain) | `XDC` | Yes | No | Yes | 550 | `m/44'/550'/0'/0/0` | +| [Ycash](https://github.com/ycashfoundation/ycash) | `YEC` | Yes | No | No | 347 | `m/44'/347'/0'/0/0` | +| ZClassic | `ZCL` | Yes | No | No | 147 | `m/44'/147'/0'/0/0` | +| [Zcash](https://github.com/zcash/zcash) | `ZEC`, `ZECTEST` | Yes | Yes | No | 133 | `m/44'/133'/0'/0/0` | +| Zencash | `ZEN` | Yes | No | No | 121 | `m/44'/121'/0'/0/0` | ## Donations -If You found this tool helpful consider making a donation: - -Ethereum (ETH) or Tether (USDT-ERC20) address: - -```text -0x342798bbe9731a91e0557fa8ab0bce1eae6d6ae3 -``` - -Bitcoin (BTC) address: +If You found this tool helpful consider making a donation: -```text -3GGNPvgbSpMHShcaZJGDXQn5wUJyTz7uoC -``` +| Coins | Addresses | +| ----------------------------- | :----------------------------------------: | +| Bitcoin `BTC` | 3GGNPvgbSpMHShcaZJGDXQn5wUJyTz7uoC | +| Ethereum `ETH`, Tether `USDT` | 0x342798bbe9731a91e0557fa8ab0bce1eae6d6ae3 | ## License -Distributed under the [ISC](https://github.com/meherett/python-hdwallet/blob/master/LICENSE) license. See ``LICENSE`` for more information. +Distributed under the [MIT](https://github.com/meherett/python-hdwallet/blob/master/LICENSE) license. See ``LICENSE`` for more information. diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..e81323b --- /dev/null +++ b/default.nix @@ -0,0 +1,62 @@ +{ pkgs ? import ./nixpkgs.nix {} }: + +with pkgs; + +let +in +{ + py313 = stdenv.mkDerivation rec { + name = "python313-with-pytest"; + + buildInputs = [ + git + openssh + python313 + python313Packages.pytest + ]; + }; + + py312 = stdenv.mkDerivation rec { + name = "python312-with-pytest"; + + buildInputs = [ + git + openssh + python312 + python312Packages.pytest + ]; + }; + + py311 = stdenv.mkDerivation rec { + name = "python311-with-pytest"; + + buildInputs = [ + git + openssh + python311 + python311Packages.pytest + ]; + }; + + py310 = stdenv.mkDerivation rec { + name = "python310-with-pytest"; + + buildInputs = [ + git + openssh + python310 + python310Packages.pytest + ]; + }; + + py39 = stdenv.mkDerivation rec { + name = "python39-with-pytest"; + + buildInputs = [ + git + openssh + python39 + python39Packages.pytest + ]; + }; +} diff --git a/docs/cli.rst b/docs/cli.rst new file mode 100644 index 0000000..4e8c76e --- /dev/null +++ b/docs/cli.rst @@ -0,0 +1,10 @@ +============================ +Command Line Interface (CLI) +============================ + +.. image:: static/svg/hdwallet-cli.svg + :alt: HDWallet CLI + +.. click:: hdwallet.cli.__main__:main + :prog: hdwallet + :show-nested: \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 187c00e..ad6d527 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,9 @@ import sys import datetime +from hdwallet import ( + __version__, __author__ +) sys.path.insert(0, os.path.abspath("../..")) sys.path.insert(1, os.path.abspath("./extensions")) @@ -22,11 +25,11 @@ # -- Project information ----------------------------------------------------- project = "HDWallet" -copyright = f"{datetime.datetime.now().year}, Meheret Tesfaye Batu" -author = "Meheret Tesfaye" +copyright = f"2021-{datetime.datetime.now().year}, {__author__}" +author = __author__ # The full version, including alpha/beta/rc tags -release = "1.3.0" +release = __version__ # The master toctree document. master_doc = "toctree" @@ -37,7 +40,8 @@ # extensions coming with Sphinx (named "sphinx.ext.*") or your custom # ones. extensions = [ - "sphinx.ext.autodoc" + "sphinx.ext.autodoc", + "sphinx_click.ext" ] # Add any paths that contain templates here, relative to this directory. @@ -52,15 +56,15 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "sphinx_rtd_theme" +html_theme = "furo" # Product logo name # html_logo = "static/png/hdwallet.png" # Theme options html_theme_options = { # "canonical_url": "", # "analytics_id": "UA-XXXXXXX-1", # Provided by Google in your dashboard - "logo_only": False, - "display_version": True, + # "logo_only": False, + # "display_version": True, # "prev_next_buttons_location": "bottom", # "style_external_links": False, # "vcs_pageview_mode": "", @@ -71,12 +75,26 @@ # "navigation_depth": 4, # "includehidden": True, # "titles_only": False + + # "light_css_variables": { + # "color-brand-primary": "darkblue", + # "color-brand-content": "darkblue", + # "color-admonition-background": "black", + # }, + # "dark_css_variables": { + # "color-brand-primary": "green", + # "color-brand-content": "green", + # "color-admonition-background": "white", + # }, + # "sidebar_hide_name": True, + # "navigation_with_keys": True, + # "announcement": "Important announcement!", } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["static", "static/css"] +html_static_path = ["static", "static/css", "static/gif"] # Autodoc member order autodoc_member_order = "bysource" diff --git a/docs/cryptocurrencies.rst b/docs/cryptocurrencies.rst index 8165035..4ea15aa 100644 --- a/docs/cryptocurrencies.rst +++ b/docs/cryptocurrencies.rst @@ -1,11 +1,15 @@ :orphan: -========================== -Available Cryptocurrencies -========================== +================ +Cryptocurrencies +================ This library simplifies the process of generating a new HDWallet's for: +.. note:: + + All Cryptocurrencies testnet networks default paths are set to ``m/44'/1'/0'/0/0`` value. + .. list-table:: :widths: 25 25 25 25 15 25 50 :header-rows: 1 @@ -388,6 +392,13 @@ This library simplifies the process of generating a new HDWallet's for: - No - 120 - m/44'/120'/0'/0/0 + * - `Flux `_ + - FLUX + - Yes + - No + - No + - 19167 + - m/44'/19167'/0'/0/0 * - Fuji Coin - FJC - Yes @@ -780,6 +791,13 @@ This library simplifies the process of generating a new HDWallet's for: - No - 4 - m/44'/4'/0'/0/0 + * - Ripple + - XRP + - Yes + - No + - No + - 144 + - m/44'/144'/0'/0/0 * - Rubycoin - RBY - Yes @@ -878,6 +896,13 @@ This library simplifies the process of generating a new HDWallet's for: - No - 502 - m/44'/502'/0'/0/0 + * - `Tron `_ + - TRX + - Yes + - No + - No + - 195 + - m/44'/195'/0'/0/0 * - Twins - TWINS, TWINSTEST - Yes @@ -969,6 +994,13 @@ This library simplifies the process of generating a new HDWallet's for: - Yes - 550 - m/44'/550'/0'/0/0 + * - `Ycash `_ + - YEC + - Yes + - No + - No + - 347 + - m/44'/347'/0'/0/0 * - ZClassic - ZCL - Yes @@ -977,9 +1009,9 @@ This library simplifies the process of generating a new HDWallet's for: - 147 - m/44'/147'/0'/0/0 * - Zcash - - ZEC + - ZEC, ZECTEST + - Yes - Yes - - No - No - 133 - m/44'/133'/0'/0/0 @@ -990,5 +1022,3 @@ This library simplifies the process of generating a new HDWallet's for: - No - 121 - m/44'/121'/0'/0/0 - -**NOTICE:** All Cryptocurrencies testnet networks default paths are set to **`m/44'/1'/0'/0/0`** value. diff --git a/docs/index.rst b/docs/index.rst index b59b75c..0a06737 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,14 +2,119 @@ Hierarchical Deterministic Wallet ================================= +|Build Status| |PyPI Version| |Documentation Status| |PyPI License| |PyPI Python Version| |Coverage Status| + +.. |Build Status| image:: https://travis-ci.org/meherett/python-hdwallet.svg?branch=master + :target: https://travis-ci.org/meherett/python-hdwallet?branch=master + +.. |PyPI Version| image:: https://img.shields.io/pypi/v/hdwallet.svg?color=blue + :target: https://pypi.org/project/hdwallet + +.. |Documentation Status| image:: https://readthedocs.org/projects/hdwallet/badge/?version=master + :target: https://hdwallet.readthedocs.io/en/master/?badge=master + +.. |PyPI License| image:: https://img.shields.io/pypi/l/hdwallet?color=black + :target: https://pypi.org/project/hdwallet + +.. |PyPI Python Version| image:: https://img.shields.io/pypi/pyversions/hdwallet.svg + :target: https://pypi.org/project/hdwallet + +.. |Coverage Status| image:: https://coveralls.io/repos/github/meherett/python-hdwallet/badge.svg?branch=master + :target: https://coveralls.io/github/meherett/python-hdwallet?branch=master + Python-based library for the implementation of a hierarchical deterministic wallet generator for over 140+ multiple cryptocurrencies. It allows the handling of multiple coins, multiple accounts, external and internal chains per account and millions of addresses per the chain. +Simple Bitcoin mainnet HDWallet generator: + +:: + + #!/usr/bin/env python3 + + from hdwallet import HDWallet + from hdwallet.utils import generate_entropy + from hdwallet.symbols import BTC as SYMBOL + from typing import Optional + + import json + + # Choose strength 128, 160, 192, 224 or 256 + STRENGTH: int = 160 # Default is 128 + # Choose language english, french, italian, spanish, chinese_simplified, chinese_traditional, japanese or korean + LANGUAGE: str = "korean" # Default is english + # Generate new entropy hex string + ENTROPY: str = generate_entropy(strength=STRENGTH) + # Secret passphrase for mnemonic + PASSPHRASE: Optional[str] = None # "meherett" + + # Initialize Bitcoin mainnet HDWallet + hdwallet: HDWallet = HDWallet(symbol=SYMBOL, use_default_path=False) + # Get Bitcoin HDWallet from entropy + hdwallet.from_entropy( + entropy=ENTROPY, language=LANGUAGE, passphrase=PASSPHRASE + ) + + # Derivation from path + # hdwallet.from_path("m/44'/0'/0'/0/0") + # Or derivation from index + hdwallet.from_index(44, hardened=True) + hdwallet.from_index(0, hardened=True) + hdwallet.from_index(0, hardened=True) + hdwallet.from_index(0) + hdwallet.from_index(0) + + # Print all Bitcoin HDWallet information's + print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) + +.. raw:: html + +
+ Output + +.. code-block:: python + + { + "cryptocurrency": "Bitcoin", + "symbol": "BTC", + "network": "mainnet", + "strength": 160, + "entropy": "c5b0d0ee698f3f72b6265f1bc591f8f2d7afa6dd", + "mnemonic": "주일 액수 명단 천둥 해수욕장 전망 추천 직업 그룹 단위 신체 파란색 시청 천천히 스트레스", + "language": "korean", + "passphrase": null, + "seed": "5a9b9667ccd07b3c641b1ba95e9119dd1d5a3034fd46cd2f27fc1f160c7dcd824fc0ab4710a9ae90582dffc3b0803bcbc0a8160feeaab4c70511c5035859decf", + "root_xprivate_key": "xprv9s21ZrQH143K2qMHU8aghJ4MoQR5g5mowXbeP2vCP937bseZGX929dmJudL7u4xRxtKvh58pxz1PhtCbWW2yUH14jdduKVMV9FkBMpM2Hyw", + "root_xpublic_key": "xpub661MyMwAqRbcFKRkaA7h4S16MSFa5YVfJkXFBRKowUa6Ufyhp4TGhS5nkvkLXSmdNjoszzDkU26WW2rg1zBsQBt6Pv3T8oLEAExGHD3hcQs", + "xprivate_key": "xprvA2YyMZWyPK2xo4eZgyypp2CzcHnxNzGbruGg7vmgaAVCtBtrjwzuhXJBNM3FrwBh85ajxHErNR6ByN77WJARpC1HDC7kTwa2yr7Mu9Pz5Qq", + "xpublic_key": "xpub6FYKm53sDgbG1Yj2o1WqBA9jAKdSnSzTE8CGvKBJ8W2BkzE1HVKAFKcfDcCHKpL5BQRg2HjbNSt55jpFshY7W1KFtp7zjB3DhNAmiFv6kzB", + "uncompressed": "081016370b45d7e23bd89b07d6886036f5e4df9a129eee3b488c177ba7881856e24d337b280f9d32539a22445e567543b39b708edf5289442f36dcde958a3433", + "compressed": "03081016370b45d7e23bd89b07d6886036f5e4df9a129eee3b488c177ba7881856", + "chain_code": "cf9ee427ed8073e009a5743056e8cf19167f67ca5082c2c6635b391e9a4e0b0d", + "private_key": "f79495fda777197ce73551bcd8e162ceca19167575760d3cc2bced4bf2a213dc", + "public_key": "03081016370b45d7e23bd89b07d6886036f5e4df9a129eee3b488c177ba7881856", + "wif": "L5WyVfBu8Sz3iGZtrwJVSP2wDJmu7HThGd1EGekFBnviWgzLXpJd", + "finger_print": "ac13e305", + "semantic": "p2pkh", + "path": "m/44'/0'/0'/0/0", + "hash": "ac13e305a88bd9968f1c058fcf5d9a6b1b9ef484", + "addresses": { + "p2pkh": "1Ggs3kkNrPPWoW17iDFQWgMdw3CD8BzBiv", + "p2sh": "3GQVUFePz517Hf61Vsa9H2tHj5jw5y6ngV", + "p2wpkh": "bc1q4sf7xpdg30vedrcuqk8u7hv6dvdeaayy3uw5cj", + "p2wpkh_in_p2sh": "3JyV5aSgdVYEjQodPWHfvehQ5227EDr3sN", + "p2wsh": "bc1qnk0s9q4379n6v9vg0lnhdu5qhjyx99u2xm238pmckmjg9v29q54saddzp9", + "p2wsh_in_p2sh": "3MmsEoP7GLHzuLVgkAtcRtyXLTWh8zNAcd" + } + } + +.. raw:: html + +
For more info see the BIP specs. .. list-table:: - :widths: 15 80 + :widths: 10 185 :header-rows: 1 * - BIP's @@ -26,5 +131,5 @@ For more info see the BIP specs. - Derivation scheme for P2WPKH-nested-in-P2SH based accounts * - `BIP84 `_ - Derivation scheme for P2WPKH based accounts - * - `BIP141 `_ + * - `BIP141 `_ - Segregated Witness (Consensus layer) diff --git a/docs/install.rst b/docs/install.rst index 0a54b6d..e23b637 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -2,13 +2,36 @@ Installing HDWallet =================== -The easiest way to install HDWallet is via pip: +The easiest way to install ``hdwallet`` is via pip: :: $ pip install hdwallet +To install ``hdwallet`` command line interface globally, for Linux `sudo` may be required: + +:: + + $ pip install hdwallet[cli] + + +After you have installed, type ``hdwallet`` to verify that it worked: + +:: + + $ hdwallet + Usage: hdwallet [OPTIONS] COMMAND [ARGS]... + + Options: + -v, --version Show HDWallet version and exit. + -h, --help Show this message and exit. + + Commands: + generate (g) Select Generate for HDWallet. + list (l) Select List for HDWallet information. + + If you want to run the latest version of the code, you can install from git: :: @@ -25,4 +48,4 @@ We welcome pull requests. To get started, just fork this `github repository + + + + + + + + + + + + + meheret@meherett:~$ meheret@meherett:~$ h meheret@meherett:~$ hd meheret@meherett:~$ hdw meheret@meherett:~$ hdwa meheret@meherett:~$ hdwal meheret@meherett:~$ hdwall meheret@meherett:~$ hdwalle meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet Usage: hdwallet [OPTIONS] COMMAND [ARGS]...Options: -v, --version Show HDWallet version and exit. -h, --help Show this message and exit.Commands: generate (g) Select Generate for HDWallet. list (l) Select List for HDWallet information.meheret@meherett:~$ c meheret@meherett:~$ cl meheret@meherett:~$ cle meheret@meherett:~$ clea meheret@meherett:~$ clear meheret@meherett:~$ clear meheret@meherett:~$ meheret@meherett:~$ h meheret@meherett:~$ hd meheret@meherett:~$ hdw meheret@meherett:~$ hdwa meheret@meherett:~$ hdwal meheret@meherett:~$ hdwall meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet g meheret@meherett:~$ hdwallet ge meheret@meherett:~$ hdwallet gen meheret@meherett:~$ hdwallet gene meheret@meherett:~$ hdwallet gener meheret@meherett:~$ hdwallet genera meheret@meherett:~$ hdwallet generat meheret@meherett:~$ hdwallet generate meheret@meherett:~$ hdwallet generate meheret@meherett:~$ hdwallet generate - meheret@meherett:~$ hdwallet generate -- meheret@meherett:~$ hdwallet generate --s meheret@meherett:~$ hdwallet generate --sy meheret@meherett:~$ hdwallet generate --sym meheret@meherett:~$ hdwallet generate --symb meheret@meherett:~$ hdwallet generate --symbo meheret@meherett:~$ hdwallet generate --symbol meheret@meherett:~$ hdwallet generate --symbol meheret@meherett:~$ hdwallet generate --symbol Q meheret@meherett:~$ hdwallet generate --symbol QT meheret@meherett:~$ hdwallet generate --symbol QTU meheret@meherett:~$ hdwallet generate --symbol QTUM meheret@meherett:~$ hdwallet generate --symbol QTUM { "cryptocurrency": "Qtum", "symbol": "QTUM", "network": "mainnet", "strength": 128, "entropy": "29ce968ac3606c3a7bd11ffba28f2b28", "mnemonic": "clap input pencil man almost brush urban catalog wing behave skull faculty", "language": "english", "passphrase": null, "seed": "346753900c4c3e8e19c2b5f535ef4a6894bb25591904381b1e1229b14adc7bc8179568fd27ed77cbc49b27ff594d8d5eb4e67877a306b1e176c9c16d854040fe", "root_xprivate_key": "xprv9s21ZrQH143K2Q2ovmMfhJjn7jk7V4BW7TrghQyCxE7rpo2ZYVzmXHusyPxTm5dmLsy411Qy8QEY4cZGRSw8k2d3zBNQ3pYTrRch4Yxsnxp", "root_xpublic_key": "xpub661MyMwAqRbcEt7H2ntg4SgWfmabtWuMUgnHVoNpWZeqhbMi63K256EMpfHXA3JScJNe9TsftFuicz16owjSMw6b2NCX5iHEGGvUdvpJ67j", "xprivate_key": "xprvA38LBjBU5PvsrKPrS7Fx2HbR2nyRc1mxxWDBodjw64nEmoUaEPFMkLJ3HioRGFfuj8LX3NEZTA2KdisLpgTwFptUgusTt46EuVvGVhTtTs1", "xpublic_key": "xpub6G7gbEiMumVB4oUKY8nxPRY9apov1UVpKj8nc29YeQKDeboimvZcJ8cX8zbK7xCPUb7qbqJPqEmwrcZzKuZKy6x16BqNpMuC42V4fLuGcKF", "uncompressed": " "uncompressed": "9f79144e375383aff745f03a814097bf6614d20343b80aad734335cab43a973b3d0e908be915f90c79ecb89c12cb286eb0f49fb0a67d983c006d5e2524c24ccc", "compressed": "029f79144e375383aff745f03a814097bf6614d20343b80aad734335cab43a973b", "chain_code": "4d14397b48d60a89bf76bff01629165b980cf8604e5d9fe7ef09e810e78dfd47", "private_key": "3b467a3fa9fe7d9e66c1bf77cfdc4dcfe552154295f06e6ad25196a6521047ad", "public_key": "029f79144e375383aff745f03a814097bf6614d20343b80aad734335cab43a973b", "wif": "KyCw9KY8PDBQ9pDzErdpfcW1HhR9gtNrR3QgNiSbuLzPFhHdgT3P", "finger_print": "6001ae5e", "semantic": "p2pkh", "path": "m/44'/2301'/0'/0/0", "hash": "6001ae5e1bc833de0eb83cb7dae20b4a0f45524a", "addresses": { "p2pkh": "QVMczXBHSxY7upAXHJKYCGz53Ma5BzkHof", "p2sh": "MNfPLr1K6Ez6TjxZHpiR2cTCpA863HR9fG", "p2wpkh": "qc11qvqq6uhsmeqeaur4c8jma4cstfg8525j2mjr3sd", "p2wpkh_in_p2sh": "M9pJejvuAKrVdKFB58uDgST3LAjkDd6Lrs", "p2wsh": "qc11qaxxx23hn5s4x2drsgqmaj4jcsv7p0hnl343 "p2wsh": "qc11qaxxx23hn5s4x2drsgqmaj4jcsv7p0hnl343w8q4s9ejs26mkucdsy4cnpg", "p2wsh_in_p2sh": "MW3V33v8qJNFWAzLRwgaRP7eHEpWV6MsRN" }} meheret@meherett:~$ meheret@meherett:~$ h meheret@meherett:~$ hd meheret@meherett:~$ hdw meheret@meherett:~$ hdwa meheret@meherett:~$ hdwal meheret@meherett:~$ hdwall meheret@meherett:~$ hdwalle meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet g meheret@meherett:~$ hdwallet ge meheret@meherett:~$ hdwallet gen meheret@meherett:~$ hdwallet gene meheret@meherett:~$ hdwallet gener meheret@meherett:~$ hdwallet genera meheret@meherett:~$ hdwallet generat meheret@meherett:~$ hdwallet generate meheret@meherett:~$ hdwallet generate meheret@meherett:~$ hdwallet generate a meheret@meherett:~$ hdwallet generate ad meheret@meherett:~$ hdwallet generate add meheret@meherett:~$ hdwallet generate addr meheret@meherett:~$ hdwallet generate addre meheret@meherett:~$ hdwallet generate addres meheret@meherett:~$ hdwallet generate address meheret@meherett:~$ hdwallet generate addresse meheret@meherett:~$ hdwallet generate addresses meheret@meherett:~$ hdwallet generate addresses meheret@meherett:~$ hdwallet generate addresses - meheret@meherett:~$ hdwallet generate addresses -- meheret@meherett:~$ hdwallet generate addresses --s meheret@meherett:~$ hdwallet generate addresses --sy meheret@meherett:~$ hdwallet generate addresses --sym meheret@meherett:~$ hdwallet generate addresses --symb meheret@meherett:~$ hdwallet generate addresses --symbo meheret@meherett:~$ hdwallet generate addresses --symbol meheret@meherett:~$ hdwallet generate addresses --symbol meheret@meherett:~$ hdwallet generate addresses --symbol T meheret@meherett:~$ hdwallet generate addresses --symbol TR meheret@meherett:~$ hdwallet generate addresses --symbol TRX meheret@meherett:~$ hdwallet generate addresses --symbol TRX meheret@meherett:~$ hdwallet generate addresses --symbol TRX - meheret@meherett:~$ hdwallet generate addresses --symbol TRX -- meheret@meherett:~$ hdwallet generate addresses --symbol TRX --m meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mn meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mne meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnem meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemo meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemon meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemoni meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic " meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" - meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" -- meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --e meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --en meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end- meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-i meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-in meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-ind meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-inde meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-index meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-index meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-index 3 meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-index 30 meheret@meherett:~$ hdwallet generate addresses --symbol TRX --mnemonic "bright demand olive glance crater key head glory quantum leisure intact age" --end-index 30 m/44'/195'/0'/0/0 TQ1zagMpHAfHkJ1P4RdrCLas2NVaBMkuUT 029b7a26adc6eb619b87a726b5406b8bd2a3296072a0e2157a61db1a06c90d664a KwjDSqmczRaZLFP3e5xV1CydvsCLrwPTEzj7sGCShvg5FtQpMSRc m/44'/195'/0'/0/1 TKjvZzLn8jiWs31fAeX6uZN7Hz7QzpWCRb 02911c3b471321afea66ad319eb1cab8efbcc090e554868e995ba318de02f1d549 KztBEMcLabJzjYT8jwQL8qPaAXpxt8Gyrba91mRXD1f5kctZ99sk m/44'/195'/0'/0/2 TTdKxmbJQdRXgRvgcVJ5arPZDZhhFyqPPH 03971ff2ec684e61747d9c2f699cd72d164aa0b76964cf5c38666b16aaeed7f9b4 KxFZ2qpFGqBYtUB3iN9rLcaeZnFZZ2zuteecnMemUBVYAmuKBKWm m/44'/195'/0'/0/3 TTyGhrkj5BZxspTygGqaXuaRq3o9fb4qQA 02785ba6a95e3b57cb828e1979f68e6d076b3c3c4be53bae1098288b84bee87b27 KxiDoDPTN7FJkGZvr5AjDT5bjrZmD1xbfQSkVDpMymHAtVUg19QC m/44'/195'/0'/0/4 TEDasJFGHY7WXySZJsnDtAH1oKF2YGCdn7 02a1e4740f0d07985687c7beaf71b39f4f7342497cccb1efc2976dd8934f8d6dd1 KyZHqZhnEs94whkZNd692oZn8SRp5FWxJapZjH1MwLr7ookpX4LR m/44'/195'/0'/0/5 TDXa4PypD4btqJf8iFuo8LokbPT9q6NKXZ 0347002a0053d5310828acc3ca8d4ea8f8c6473b6f964f0a56c0737d28c13efd10 L46yP2f5kopuGmhgi4nZW5EKUEVVvNxxhPbEnWMXByfSDxXfezkq m/44'/195'/0'/0/6 TJgSaKajDbDvv1MsijP2PPKnC9AccuNqME 02ab61c2c68a6235ca1dddf691b664e19954c38736e36621d408e6361813a00706 L51KvG7sEwCMKcoF9VBRWasLrABXypFZwTv6HtRCwrNsN4Y8vTJC m/44'/195'/0'/0/7 TZ6UQMXbvxwA3SqNxiaqwH7tPR574cad9f 02feac616db00651ff0718bf1276bca09a4e1ba861dab8ebc8d9dd1713693fe88f KyRgBKNXyRE9aJAGFGEbp9PCiEib7pbWnXsQbpbWQT2jRob62Wmo m/44'/195'/0'/0/8 TZHq4W99r3jYqF1VZkSnNiddrNq9jEBKKC 02b46a81fd7822e424f197be6e22d916b25d9acf8687886c2273c6e51e2669227d KzxUtnQpRTzjXzFyG4JoJJdNMi62ugp4M4hA4NP4V7R9uTEq84PD m/44'/195'/0'/0/9 TPqHvZyRnNjbn2uuKWEDRKrbDjTAx1ioy5 0211e66cd8f0aeb9564459afbf9040effba2386668f4b98137fcf68daf3e64ad5b L4snKWy8o2kS8iksx82vU4xCxSVwrRgsLZLMqsKMSCzGoodMTYQG m/44'/195'/0'/0/10 TWAG8HBPrA7i52pLXfsPu2hBwjqMLE2NCN 0232a0ae9829418793804899f7d7823ce1564682fdc3be834e5abe93d7392b885f L5L9rvwybjUhtDmLoPu4GZCyb4JnFTFMZz8N5QhPZ9KzvYgt5qG4 m/44'/195'/0'/0/11 TLg8etRwRvx7tKvcAWAvs3792RcCNWQ6tb 025403d1ccda817fb2665a28cd26895181655b80266f8fc09a321b0dee2fe57553 L5bA1TqwsKac4bKWr7VJtZGUBUNH6oXQcBFjSotCEL813vtNFutV m/44'/195'/0'/0/12 TPVz8VMQzE89mF6VrSdHCommVPqtq64mmH 03e46b9d2291854d7f50a497dec96fb48c9f7b47e5fd5688e810d0124fb41696af L112D1CZpB7wiEg19HcFWRR7JYx7EBPQ9e8BqBzk9QEi9ZcWYycg m/44'/195'/0'/0/13 TVaAwMiuv9HP9LDEQ5jbsyoPKEG92dt1K8 0375bfdc1339ad8ea75ed9e03bcab04e427ba51b2fcdd5ed135891d4b4c0272445 L5d9roSm26vxBLx71rL6uQhZG6zJ9AERMuNVnrTCNSZRoE8fHNkt m/44'/195'/0'/0/14 TYrV7tNXw3UesHQpEC7oyKQW2wDqqtv3GN 03e07692db1b4c5fb79c0d440d9d2d9afeda7a6c37c275eccfce7b434a4792539f L42XFpYHp5WAi1uUMsCWQzxdf6BcFkYDdiXkNtVbZ3dLAeL1DdQb m/44'/195'/0'/0/15 TXVGx5Kfy6nBFc9rxeBdUV9P9Cc6Hc9jPL 0279caecefba0e50691a3a11e42b97fc307afb16abd37a642712288733add69e37 KwgiCbEXviTLT74vWnZq8hNpCAhUzpUgeHXptJnMUR1zBNGVYe7b m/44'/195'/0'/0/16 TV1bLkoaiTXJeCfe1pKnvKtP9XcmzcrqZF 02902b569f8591fe4470666e352d14c13b3bc3c18f615569baf0befac518f33eae L3Hrg6AkgwHAQ9V4KtjyQc3Csqq4VGDhZ135KkYTTu49yvVq6dK3m/44'/195'/0'/0/17 TMR2WpaPuKf2zwTzbPfqNbVRDF2ibokLff 020d8c4cc8fefb4ed734cc5584384313f3aefbac27a3d340f346613d41394a64a3 L3AkJLU39uQf8VbfFeYY2iy3vTCAi8Ts9HCGueCxjd3LRREmYJxG m/44'/195'/0'/0/18 TSBEeZEcqBqGCHoKyr2cFmWggcN6tMhECH 0399066a7946396d6dc8495d7ce2ad541651d929c233c9d7f0bf4bc0dafb02ced2 L3EoBHNbSD9c1Qjt5RAdnqWvuTW6mb1eVvTp5zam787CaTCaWBDw m/44'/195'/0'/0/19 TW1LC4KUTuUfWEiPWV8y9HvzCQz42g1E4o 03dfcde88b940359a81774e878aa698a39b3d68ac1aea6c743708416b90ecd14ba L3RMqBbeAbQNZHtLyihm6HzSqt4T3smwCU9hzbwKRDeLPYp2LaCw m/44'/195'/0'/0/20 TPX382v5n8uzzTBgcGtAp6eMc5wrcS67qB 03bbae4f70402653991a32ee715f86c6db7efae88e8efdd9ad165f87276cefbbd8 L43jGQoHVtw48QrBJnjSXP8b9vmazBV7AQfPkGGx2dgKxua3kVdL m/44'/195'/0'/0/21 TFao1cUyx6BHLTJ4ydmB1TwCPunA4MPakk 02ad5b42b1e6122ea9886f346fdc2459892c4d879cc2729aea826c429782960906 KxEMNNfHWtFsoBamMHxiLxt4fFKcpmsQcj2iAhyRZyHqqcocrn9q m/44'/195'/0'/0/22 TRWXKUT7mqW5aDyGdRdC6BGEqyWRBt8sFB 034e1aa4d9e31e8614447e31cb9801a533df7aa5d9fdce8d7c98c46cef4afd576e KwdSMU3uasveW6Zshf4eBVeYha2VgMxKDkpM9pyXUF5GZZnP13TS m/44'/195'/0'/0/23 TSAd6nnKkzjCHvkDMt2yvfrVmZTJgAHzU1 039a5d9e4f1ae50fb067bd74113c37949e3217d9232d04f0f705d4eb58b74e25aa KyAMrqzEyy4cYygE6ssnvEpyiyERucXVpmqxJzgbbqw3z9a87iYC m/44'/195'/0'/0/24 TYhGooxqWEDh2jfuQNdLfpJz7QVKyQd5rx 029030ae7b41124a8056e0925815f61fbada3960c671f57b5e68ea01b906cc8175 KymQWvM6vgZHZXAnCPczAGoU6vGpMz6pgFsFZYie8EUQLLzFpyKWm/44'/195'/0'/0/25 TLfPTruqhoFHre8iYFnH4nQvhMEZ9Zy9tG 0205ca1d3d5e4bef5bb36877b4cc9541d81353433578daf8894127776818703568 KxuwJpqBSteXTBqq9fWpQgRZ7w7karug9aEaeE7ajgismMR3yTjr m/44'/195'/0'/0/26 TGRzU4XU3FpftNm26xYv5nyEvB9eJHAizN 03cc5f2bdcb761718ae26d9cf8dd7e3d5c1c91af20a7395f16f9992e98b1917acf L1DTmQSjKCj23b7RPxiJbr2ytfmmeyRrYDoEVHY9bS8YdV1fgjES m/44'/195'/0'/0/27 TVdEwPAuD897d4p9jui6vHgcpwGtxqwzBF 024ded326a286155f2c056e8a9ffb14f07d06c71b990afb9c6d29255273e08a8db L2VTjhgXiSSSGenA3sLz67As8DoJxjMU5nTJCFsSBigotJJkNPSP m/44'/195'/0'/0/28 TE17yisStvQokoZBavYY6yBtxjZMJGvqfN 029baa8da7c4077851d99041384558b7ff1055fa5dbe5c36f5634db39347f33530 L56RFzmW2viLAZpWbuYU6J13EkLoJ1XV15Mt7Dq1RQ3Edxabsg9E m/44'/195'/0'/0/29 THRsfRLt1tYnHzhvxLVYeEngejWtP2reHn 022fd7ffe8fd5474303a3d695a36ab1db861c8120e9e95cf9d8244dfc794928947 L5ZWTJGTJ4FMmjSZbEsXjVCue415i1fFt97JYQdpwGuwjzhVUz1W meheret@meherett:~$ meheret@meherett:~$ h meheret@meherett:~$ hd meheret@meherett:~$ hdw meheret@meherett:~$ hdwa meheret@meherett:~$ hdwal meheret@meherett:~$ hdwall meheret@meherett:~$ hdwalle meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet meheret@meherett:~$ hdwallet g meheret@meherett:~$ hdwallet g meheret@meherett:~$ hdwallet g a meheret@meherett:~$ hdwallet g a meheret@meherett:~$ hdwallet g a - meheret@meherett:~$ hdwallet g a -s meheret@meherett:~$ hdwallet g a -s meheret@meherett:~$ hdwallet g a -s E meheret@meherett:~$ hdwallet g a -s ET meheret@meherett:~$ hdwallet g a -s ETH meheret@meherett:~$ hdwallet g a -s ETH meheret@meherett:~$ hdwallet g a -s ETH - meheret@meherett:~$ hdwallet g a -s ETH -p meheret@meherett:~$ hdwallet g a -s ETH -p meheret@meherett:~$ hdwallet g a -s ETH -p " meheret@meherett:~$ hdwallet g a -s ETH -p "m meheret@meherett:~$ hdwallet g a -s ETH -p "m/ meheret@meherett:~$ hdwallet g a -s ETH -p "m/5 meheret@meherett:~$ hdwallet g a -s ETH -p "m/55 meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/ meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/5 meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56 meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" - meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -x meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xp meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpu meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub " meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub "xpub661MyMwAqRbcFKRkaA7h4S16MSFa5YVfJkXFBRKowUa6Ufyhp4TGhS5nkvkLXSmdNjoszzDkU26WW2rg1zBsQBt6Pv3T8oLEAExGHD3hcQs meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub "xpub661MyMwAqRbcFKRkaA7h4S16MSFa5YVfJkXFBRKowUa6Ufyhp4TGhS5nkvkLXSmdNjoszzDkU26WW2rg1zBsQBt6Pv3T8oLEAExGHD3hcQs meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub "xpub661MyMwAqRbcFKRkaA7h4S16MSFa5YVfJkXFBRKowUa6Ufyhp4TGhS5nkvkLXSmdNjoszzDkU26WW2rg1zBsQBt6Pv3T8oLEAExGHD3hcQs" meheret@meherett:~$ hdwallet g a -s ETH -p "m/55/56" -xpub "xpub661MyMwAqRbcFKRkaA7h4S16MSFa5YVfJkXFBRKowUa6Ufyhp4TGhS5nkvkLXSmdNjoszzDkU26WW2rg1zBsQBt6Pv3T8oLEAExGHD3hcQs" m/55/56/0 0x9E4DA0ed75De4ddc756B5960a8a2fe2f6619aa0a 0399880907701ed93fba8f7fcd0b6577ddce5b4757a0eedfbdfe34eba58774f01a None m/55/56/1 0x3605971Ff24bd4773CEBF5C464eb690b787B8C0e 02eaa9ded5fada16a787b3cf8bae2eded293277f634bf0389620ebb18a900495da None m/55/56/2 0xDD2BB9C752DDcfF68a80fF083Ce048f7cE8C637a 026032e1928f11ee8c6062064337d7f55766c6c25e4300b76aefd798ff7bb7d2c6 None m/55/56/3 0xe8799F0047eBbe6Ab2920aDe268C86fFc0e69B31 03742fe4d0e8be5f5998372dc68f8834886a2843dfe6186a4f77766f3d5482c499 None m/55/56/4 0x8adedCA2053248B96D20C268f83B541d9f5A82E3 024a6b9a32646490a7cfb2b85b1545ed97f7b53fb51f82ac3e053efdda8e1f0b49 None m/55/56/5 0x7Ad84124c6F5dc269072fF26EfcC3ff0D6d5aECB 027897b67245e044d01befb584075c671b3e3cf083ec48d67b1783d22f423f2a7d None m/55/56/6 0x22D3bF5E8a7a77e7d5469A64eC027e5bEE0EeD54 0364b82fb06c0c3574609c1b205d545fd9900c6423fb0b196b18119acc1cb13d64 None m/55/56/7 0x92170DFed4EDb55936517934e1a084e3E60A62dF 03040106d21e43225f7db05d32453bc61ae00d5ad327f9205fe26a874e2c904b7c None m/55/56/8 0xF5D47DBEd337d1346f7319b12D1072fFa96d9618 024db83a48945d2bba14aedb09a798d5c101d18c9f8054f26f319ca8c691a5fa6e None m/55/56/9 0x48f84Ec0F56763E1d1e5a1E7DAee1583fD904A7A 02542fe476502ae02c71ca5dda3f9bdc3711b5d5c487ae6f536ba9df819455ed13 None m/55/56/10 0x68eC626dB1bb947f5B8bf2E4C8ad3c28badEB8f4 033724fcb3580d5cc1df5fbdbb2fc590b7121fd16418edff22b7b3dc02773340e7 None m/55/56/11 0x291FD8A3B5173cC47C3B4ddD6778C734b3E870b4 036d75d980680e517effa21408e4178a92af3a1282d5279d17309f60adf78acd8c None m/55/56/12 0xbF5879CDC6138626F1f404193d9daBdd4538db8F 035e0a8860cd6416581d59ca86045cc2416948c4bc49fc5aaaaf4bf417b6b38594 None m/55/56/13 0x85e7e03Ef655cF00e956B29becc780A468b88c8B 03d3f1c0448838f9438dbf327494dfa65949892c5bcf6c99e37ba8e8e77baf54f8 None m/55/56/14 0xfA8b48F2A6DABDa771619248e3AE8474Ab7C0113 034e402e9445d6a1d2d3ca514508b0c229ca7027e2aa69c7766a446bb9d852e94c None m/55/56/15 0x015E590C1bc21c4ABf8497648C5Fe3659F63afd5 0286982173a103479df45e836408312bda4b8f7636b403ad1f069efe3fd30ffc65 None m/55/56/16 0x46baD561Fc3b7DC871dB13A3f62a31085a0C473B 02f0b96c57b087b85e6b7c122a8bcacd7abede2c456e6fff2532d4b757232f8cac None m/55/56/17 0x26fcCa2256f05fFE4981b7B9A8b571629A316927 0399af0378ec902d12d879904597af32243f3421319c439797332d1e63aed54777 None m/55/56/18 0x071Dcafb31161D7B5F0e6FD3Df8C0ffB9d585754 02b3aa3c9dc13f534a66de18a8b2620208eebf9136d45c067cc86ec5488d29c979 None m/55/56/19 0x54dd69AB113230b84dDf250cafd37eb33571f545 02cbe4c82aa2261177fece874b8c1c2ef4f2f731158a24a02e0e81692b838c2e57 None meheret@meherett:~$ meheret@meherett:~$ e meheret@meherett:~$ ex meheret@meherett:~$ exi meheret@meherett:~$ exit meheret@meherett:~$ exit exit + \ No newline at end of file diff --git a/docs/toctree.rst b/docs/toctree.rst index 152b506..4ff632c 100644 --- a/docs/toctree.rst +++ b/docs/toctree.rst @@ -7,7 +7,8 @@ HDWallet Overview install.rst - Cryptocurrencies + cli.rst + Available Cryptocurrencies .. toctree:: :maxdepth: 3 diff --git a/examples/from_entropy.py b/examples/from_entropy.py index 3b83069..66d7817 100644 --- a/examples/from_entropy.py +++ b/examples/from_entropy.py @@ -2,7 +2,7 @@ from hdwallet import HDWallet from hdwallet.utils import generate_entropy -from hdwallet.symbols import BTC +from hdwallet.symbols import TRX as SYMBOL from typing import Optional import json @@ -17,7 +17,7 @@ PASSPHRASE: Optional[str] = None # "meherett" # Initialize Bitcoin mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=BTC) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) # Get Bitcoin HDWallet from entropy hdwallet.from_entropy( entropy=ENTROPY, language=LANGUAGE, passphrase=PASSPHRASE diff --git a/examples/from_private_key.py b/examples/from_private_key.py index 05f5480..421b7eb 100644 --- a/examples/from_private_key.py +++ b/examples/from_private_key.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from hdwallet import HDWallet -from hdwallet.symbols import QTUM +from hdwallet.symbols import QTUM as SYMBOL import json @@ -9,7 +9,7 @@ PRIVATE_KEY: str = "f86d5afe2a457c29357485ebf853a1e5ff5f6fcf1ba4d7d1412665e01449902e" # Initialize Qtum mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=QTUM) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) # Get Qtum HDWallet from private key hdwallet.from_private_key(private_key=PRIVATE_KEY) @@ -25,8 +25,6 @@ print("Public Key:", hdwallet.public_key()) print("Wallet Important Format:", hdwallet.wif()) print("Finger Print:", hdwallet.finger_print()) -print("Semantic:", hdwallet.semantic()) -print("Path:", hdwallet.path()) print("Hash:", hdwallet.hash()) print("P2PKH Address:", hdwallet.p2pkh_address()) print("P2SH Address:", hdwallet.p2sh_address()) diff --git a/examples/from_public_key.py b/examples/from_public_key.py index 2aee74d..cf76dc6 100644 --- a/examples/from_public_key.py +++ b/examples/from_public_key.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from hdwallet import HDWallet -from hdwallet.symbols import ETH +from hdwallet.symbols import ETH as SYMBOL import json @@ -9,7 +9,7 @@ PUBLIC_KEY = "034f6922d19e8134de23eb98396921c02cdcf67e8c0ff23dfd955839cd557afd10" # Initialize Ethereum mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=ETH) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) # Get Ethereum HDWallet from public key hdwallet.from_public_key(public_key=PUBLIC_KEY) @@ -23,7 +23,6 @@ print("Compressed:", hdwallet.compressed()) print("Public Key:", hdwallet.public_key()) print("Finger Print:", hdwallet.finger_print()) -print("Semantic:", hdwallet.semantic()) print("Hash:", hdwallet.hash()) print("P2PKH Address:", hdwallet.p2pkh_address()) print("P2SH Address:", hdwallet.p2sh_address()) diff --git a/examples/from_root_xprivate_key.py b/examples/from_root_xprivate_key.py deleted file mode 100644 index dc6258f..0000000 --- a/examples/from_root_xprivate_key.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python3 - -from hdwallet import HDWallet as HDWallet -from hdwallet.utils import is_root_xprivate_key -from hdwallet.symbols import BTC - -import json - -# Strict for root xpublic key -STRICT: bool = True -# Bitcoin root xprivate key -XPRIVATE_KEY: str = "xprv9s21ZrQH143K24t96gCaezzt1QQmnqiEGm8m6TP8yb8e3TmGfkCgcLEVss" \ - "kufMW9R4KH27pD1kyyEfJkYz1eiPwjhFzB4gtabH3PzMSmXSM" -# Bitcoin not root xprivate key -# XPRIVATE_KEY: str = "xprvA3KRgVDh45mbQT1VmWPx73YeAWM4629Q2D9pMuqjFMnjTqDGhKiww6H532rg" \ -# "YRNj37fngd4Mvp7GfUD8rKeQzUZjCWeisT92tX8FfjWx3BL" - -if STRICT: - # Check root xprivate key - assert is_root_xprivate_key(xprivate_key=XPRIVATE_KEY, symbol=BTC, semantic="p2pkh"), "Invalid root xprivate key." - -# Initialize Bitcoin mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=BTC) -# Get Bitcoin HDWallet from root xprivate key -hdwallet.from_root_xprivate_key(xprivate_key=XPRIVATE_KEY, strict=STRICT) - -# Derivation from path -# hdwallet.from_path("m/44'/0'/0'/0/0") -# Or derivation from index -hdwallet.from_index(44, hardened=True) -hdwallet.from_index(0, hardened=True) -hdwallet.from_index(0, hardened=True) -hdwallet.from_index(0) -hdwallet.from_index(0) - -# Print all Bitcoin HDWallet information's -# print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) - -print("Cryptocurrency:", hdwallet.cryptocurrency()) -print("Symbol:", hdwallet.symbol()) -print("Network:", hdwallet.network()) -print("Root XPrivate Key:", hdwallet.root_xprivate_key()) -print("Root XPublic Key:", hdwallet.root_xpublic_key()) -print("XPrivate Key:", hdwallet.xprivate_key()) -print("XPublic Key:", hdwallet.xpublic_key()) -print("Uncompressed:", hdwallet.uncompressed()) -print("Compressed:", hdwallet.compressed()) -print("Chain Code:", hdwallet.chain_code()) -print("Private Key:", hdwallet.private_key()) -print("Public Key:", hdwallet.public_key()) -print("Wallet Important Format:", hdwallet.wif()) -print("Finger Print:", hdwallet.finger_print()) -print("Semantic:", hdwallet.semantic()) -print("Path:", hdwallet.path()) -print("Hash:", hdwallet.hash()) -print("P2PKH Address:", hdwallet.p2pkh_address()) -print("P2SH Address:", hdwallet.p2sh_address()) -print("P2WPKH Address:", hdwallet.p2wpkh_address()) -print("P2WPKH In P2SH Address:", hdwallet.p2wpkh_in_p2sh_address()) -print("P2WSH Address:", hdwallet.p2wsh_address()) -print("P2WSH In P2SH Address:", hdwallet.p2wsh_in_p2sh_address()) diff --git a/examples/from_root_xpublic_key.py b/examples/from_root_xpublic_key.py deleted file mode 100644 index ad2ba34..0000000 --- a/examples/from_root_xpublic_key.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -from hdwallet import HDWallet as HDWallet -from hdwallet.utils import is_root_xpublic_key -from hdwallet.symbols import BTC - -import json - -# Strict for root xpublic key -STRICT: bool = True -# Bitcoin root xpublic key -XPUBLIC_KEY: str = "xpub661MyMwAqRbcEqD3v24ZWHGDMqqAfbDbmnUFJXfbpxGZaAshq7evA7fB75CHFbNHSot" \ - "LadDZw6M6ic4ZkdN6jQ2KMGR66Z2EybgdLFjNrpf" -# Bitcoin not root xpublic key -# XPUBLIC_KEY: str = "xpub6FbWJtnc3eJHBwfTqhaE9yQNkmi56UDy9Rm1pbhvuSSigr6xKihuFpnnf4jz8G9ba2m3wFaF" \ -# "Gj7eH7FE451Jo5hPJhbaCdmxoBwWbFzk1Sn" - -if STRICT: - # Check root xpublic key - assert is_root_xpublic_key(xpublic_key=XPUBLIC_KEY, symbol=BTC, semantic="p2pkh"), "Invalid root xpublic key." - -# Initialize Bitcoin mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=BTC) -# Get Bitcoin HDWallet from root xpublic key -hdwallet.from_root_xpublic_key(xpublic_key=XPUBLIC_KEY, strict=STRICT) - -# Derivation from path -# hdwallet.from_path("m/44/0/0/0/0") -# Or derivation from index -hdwallet.from_index(44, hardened=False) -hdwallet.from_index(0, hardened=False) -hdwallet.from_index(0, hardened=False) -hdwallet.from_index(0) -hdwallet.from_index(0) - -# Print all Bitcoin HDWallet information's -# print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) - -print("Cryptocurrency:", hdwallet.cryptocurrency()) -print("Symbol:", hdwallet.symbol()) -print("Network:", hdwallet.network()) -print("Root XPublic Key:", hdwallet.root_xpublic_key()) -print("XPublic Key:", hdwallet.xpublic_key()) -print("Uncompressed:", hdwallet.uncompressed()) -print("Compressed:", hdwallet.compressed()) -print("Chain Code:", hdwallet.chain_code()) -print("Public Key:", hdwallet.public_key()) -print("Finger Print:", hdwallet.finger_print()) -print("Semantic:", hdwallet.semantic()) -print("Path:", hdwallet.path()) -print("Hash:", hdwallet.hash()) -print("P2PKH Address:", hdwallet.p2pkh_address()) -print("P2SH Address:", hdwallet.p2sh_address()) -print("P2WPKH Address:", hdwallet.p2wpkh_address()) -print("P2WPKH In P2SH Address:", hdwallet.p2wpkh_in_p2sh_address()) -print("P2WSH Address:", hdwallet.p2wsh_address()) -print("P2WSH In P2SH Address:", hdwallet.p2wsh_in_p2sh_address()) diff --git a/examples/from_seed.py b/examples/from_seed.py index 18766b1..9104176 100644 --- a/examples/from_seed.py +++ b/examples/from_seed.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from hdwallet import HDWallet -from hdwallet.symbols import DOGE +from hdwallet.symbols import DOGE as SYMBOL import json @@ -10,7 +10,7 @@ "8723bc545a4bd51f5cd29a3e8bd1433bd1d26e6bf866ff53d1493f" # Initialize Dogecoin mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=DOGE) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) # Get Dogecoin HDWallet from seed hdwallet.from_seed(seed=SEED) diff --git a/examples/from_wif.py b/examples/from_wif.py index 2c27e7b..517ffc4 100644 --- a/examples/from_wif.py +++ b/examples/from_wif.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 from hdwallet import HDWallet -from hdwallet.symbols import BTCTEST +from hdwallet.symbols import BTCTEST as SYMBOL import json @@ -9,7 +9,7 @@ WALLET_IMPORTANT_FORMAT: str = "cVpnZ6XRfL5VVggwZDyndAU5KGVdT2TP1j1HB3td6ZKWCbh5wYvf" # Initialize Bitcoin testnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=BTCTEST) +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) # Get Bitcoin HDWallet from wallet important format hdwallet.from_wif(wif=WALLET_IMPORTANT_FORMAT) @@ -25,8 +25,6 @@ print("Public Key:", hdwallet.public_key()) print("Wallet Important Format:", hdwallet.wif()) print("Finger Print:", hdwallet.finger_print()) -print("Semantic:", hdwallet.semantic()) -print("Path:", hdwallet.path()) print("Hash:", hdwallet.hash()) print("P2PKH Address:", hdwallet.p2pkh_address()) print("P2SH Address:", hdwallet.p2sh_address()) diff --git a/examples/from_xprivate_key.py b/examples/from_xprivate_key.py index 5eb1913..2af64e1 100644 --- a/examples/from_xprivate_key.py +++ b/examples/from_xprivate_key.py @@ -1,25 +1,46 @@ #!/usr/bin/env python3 -from hdwallet import HDWallet -from hdwallet.symbols import ETH +from hdwallet import HDWallet as HDWallet +from hdwallet.utils import is_root_xprivate_key +from hdwallet.symbols import BTC as SYMBOL import json -# Ethereum xprivate key -XPRIVATE_KEY = "xprvA3KRgVDh45mbQT1VmWPx73YeAWM4629Q2D9pMuqjFMnjTqDGhKiww6H" \ - "532rgYRNj37fngd4Mvp7GfUD8rKeQzUZjCWeisT92tX8FfjWx3BL" +# Strict for root xpublic key +STRICT: bool = True +# Bitcoin root xprivate key +XPRIVATE_KEY: str = "xprv9s21ZrQH143K24t96gCaezzt1QQmnqiEGm8m6TP8yb8e3TmGfkCgcLEVss" \ + "kufMW9R4KH27pD1kyyEfJkYz1eiPwjhFzB4gtabH3PzMSmXSM" +# Bitcoin non-root xprivate key +# XPRIVATE_KEY: str = "yprvAMZNWbcSVmxMiVoKgQuKmemTpEz8dJs3v8hmgkRVUjncqkXsgoxyqZ8rDb" \ +# "eXzMqRQZEsTcB4T5iQQx7WazLyy3KiHZrdcHo6DmGAibeMxQV" -# Initialize Ethereum mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=ETH) -# Get Ethereum HDWallet from xprivate key -hdwallet.from_xprivate_key(xprivate_key=XPRIVATE_KEY) +if STRICT: + # Check root xprivate key + assert is_root_xprivate_key(xprivate_key=XPRIVATE_KEY, symbol=SYMBOL), "Invalid Root XPrivate Key." -# Print all Ethereum HDWallet information's +# Initialize Bitcoin mainnet HDWallet +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) +# Get Bitcoin HDWallet from xprivate key +hdwallet.from_xprivate_key(xprivate_key=XPRIVATE_KEY, strict=STRICT) + +# Derivation from path +# hdwallet.from_path("m/44'/0'/0'/0/0") +# Or derivation from index +hdwallet.from_index(44, hardened=True) +hdwallet.from_index(0, hardened=True) +hdwallet.from_index(0, hardened=True) +hdwallet.from_index(0) +hdwallet.from_index(0) + +# Print all Bitcoin HDWallet information's # print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) print("Cryptocurrency:", hdwallet.cryptocurrency()) print("Symbol:", hdwallet.symbol()) print("Network:", hdwallet.network()) +print("Root XPrivate Key:", hdwallet.root_xprivate_key()) +print("Root XPublic Key:", hdwallet.root_xpublic_key()) print("XPrivate Key:", hdwallet.xprivate_key()) print("XPublic Key:", hdwallet.xpublic_key()) print("Uncompressed:", hdwallet.uncompressed()) diff --git a/examples/from_xpublic_key.py b/examples/from_xpublic_key.py index c12d4e0..04e9079 100644 --- a/examples/from_xpublic_key.py +++ b/examples/from_xpublic_key.py @@ -1,25 +1,45 @@ #!/usr/bin/env python3 -from hdwallet import HDWallet -from hdwallet.symbols import ETH +from hdwallet import HDWallet as HDWallet +from hdwallet.utils import is_root_xpublic_key +from hdwallet.symbols import BTC as SYMBOL import json -# Ethereum xpublic key -XPUBLIC_KEY = "xpub6GYVAAuBNfDxWKfSoNPR262M6uW7wWTuxE6LLRtgdBZkvmgzWFGhk41NKHydAxa" \ - "6RMZP3pY2318KG4iUfZa22nUA4q8hfrqhrDpBUJcfvWu" +# Strict for root xpublic key +STRICT: bool = True +# Bitcoin root xpublic key +XPUBLIC_KEY: str = "xpub661MyMwAqRbcEqD3v24ZWHGDMqqAfbDbmnUFJXfbpxGZaAshq7evA7fB75CHFbNHSot" \ + "LadDZw6M6ic4ZkdN6jQ2KMGR66Z2EybgdLFjNrpf" +# Bitcoin non-root xpublic key +# XPUBLIC_KEY: str = "zpub6uxKjJ8pnanQKU2betFrDPVmcVUvVgyAhgWS74iaN7yUE8RADoRRnztyVEQtnzi9Fh1Vp" \ +# "6iJ8RT6mMqjGnS6AxGjud3P2DLzpMHUw2zT1n2" -# Initialize Ethereum mainnet HDWallet -hdwallet: HDWallet = HDWallet(symbol=ETH) -# Get Ethereum HDWallet from xpublic key -hdwallet.from_xpublic_key(xpublic_key=XPUBLIC_KEY) +if STRICT: + # Check root xpublic key + assert is_root_xpublic_key(xpublic_key=XPUBLIC_KEY, symbol=SYMBOL), "Invalid Root XPublic Key." -# Print all Ethereum HDWallet information's +# Initialize Bitcoin mainnet HDWallet +hdwallet: HDWallet = HDWallet(symbol=SYMBOL) +# Get Bitcoin HDWallet from xpublic key +hdwallet.from_xpublic_key(xpublic_key=XPUBLIC_KEY, strict=STRICT) + +# Derivation from path +# hdwallet.from_path("m/44/0/0/0/0") +# Or derivation from index +hdwallet.from_index(44, hardened=False) +hdwallet.from_index(0, hardened=False) +hdwallet.from_index(0, hardened=False) +hdwallet.from_index(0) +hdwallet.from_index(0) + +# Print all Bitcoin HDWallet information's # print(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) print("Cryptocurrency:", hdwallet.cryptocurrency()) print("Symbol:", hdwallet.symbol()) print("Network:", hdwallet.network()) +print("Root XPublic Key:", hdwallet.root_xpublic_key()) print("XPublic Key:", hdwallet.xpublic_key()) print("Uncompressed:", hdwallet.uncompressed()) print("Compressed:", hdwallet.compressed()) @@ -27,6 +47,7 @@ print("Public Key:", hdwallet.public_key()) print("Finger Print:", hdwallet.finger_print()) print("Semantic:", hdwallet.semantic()) +print("Path:", hdwallet.path()) print("Hash:", hdwallet.hash()) print("P2PKH Address:", hdwallet.p2pkh_address()) print("P2SH Address:", hdwallet.p2sh_address()) diff --git a/hdwallet/__init__.py b/hdwallet/__init__.py index ce4c736..633d6b5 100644 --- a/hdwallet/__init__.py +++ b/hdwallet/__init__.py @@ -1,9 +1,36 @@ #!/usr/bin/env python3 from .hdwallet import ( - HDWallet, BIP32HDWallet, BIP44HDWallet, BIP49HDWallet, BIP84HDWallet, BIP141HDWallet + HDWallet, + BIP32HDWallet, + BIP44HDWallet, + BIP49HDWallet, + BIP84HDWallet, + BIP141HDWallet ) -__all__ = [ - "HDWallet", "BIP32HDWallet", "BIP44HDWallet", "BIP49HDWallet", "BIP84HDWallet", "BIP141HDWallet" +# HDWallet Information's +from .version import ( + __version__, + __version_info__ +) +__license__: str = "MIT" +__author__: str = "Meheret Tesfaye Batu" +__email__: str = "meherett.batu@gmail.com" +__description__: str = "Python-based library for the implementation of a hierarchical deterministic wallet " \ + "generator for more than 140+ multiple cryptocurrencies." + +__all__: list = [ + "__version__", + "__version_info__", + "__license__", + "__author__", + "__email__", + "__description__", + "HDWallet", + "BIP32HDWallet", + "BIP44HDWallet", + "BIP49HDWallet", + "BIP84HDWallet", + "BIP141HDWallet" ] diff --git a/hdwallet/cli/__init__.py b/hdwallet/cli/__init__.py new file mode 100644 index 0000000..9a7b09f --- /dev/null +++ b/hdwallet/cli/__init__.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import textwrap +import click +import sys + + +__all__ = [ + "textwrap", + "click", + "sys" +] diff --git a/hdwallet/cli/__main__.py b/hdwallet/cli/__main__.py new file mode 100644 index 0000000..71b1d60 --- /dev/null +++ b/hdwallet/cli/__main__.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python + +from click_aliases import ClickAliasedGroup +from typing import Optional + +from hdwallet import __version__ +from hdwallet.cli.generate.hdwallet import generate_hdwallet +from hdwallet.cli.generate.addresses import generate_addresses +from hdwallet.cli.list.cryptocurrencies import list_cryptocurrencies +from hdwallet.cli.list.languages import list_languages +from hdwallet.cli.list.strengths import list_strengths +from hdwallet.cli import click + + +CONTEXT_SETTINGS = dict( + help_option_names=["-h", "--help"], +) + + +def print_version(ctx, param, value): + if not value or ctx.resilient_parsing: + return + click.echo(__version__) + ctx.exit() + + +@click.group(cls=ClickAliasedGroup, + options_metavar="[OPTIONS]", context_settings=CONTEXT_SETTINGS) +@click.option("-v", "--version", is_flag=True, callback=print_version, + expose_value=False, help="Show HDWallet version and exit.") +def main(): + pass + + +@main.group("generate", aliases=["g"], cls=ClickAliasedGroup, options_metavar="[OPTIONS]", + short_help="Select Generate for HDWallet.", invoke_without_command=True) +@click.option("-s", "--symbol", type=str, default="BTC", + help="Set Cryptocurrency ticker symbol.") +@click.option("-sg", "--strength", type=int, default=128, + help="Set Strength for entropy, choose strength 128, 160, 192, 224 or 256 only.", show_default=True) +@click.option("-e", "--entropy", type=str, default=None, + help="Set Master key from entropy hex string.", show_default=True) +@click.option("-m", "--mnemonic", type=str, default=None, + help="Set Master key from mnemonic words.", show_default=True) +@click.option("-l", "--language", type=str, default="english", + help="Set Language for mnemonic, choose language english, french, italian, spanish, " + "chinese_simplified, chinese_traditional, japanese or korean only.", show_default=True) +@click.option("-pa", "--passphrase", type=str, default=None, + help="Set Passphrase for mnemonic.", show_default=True) +@click.option("-sd", "--seed", type=str, default=None, + help="Set Master key from seed hex string.", show_default=True) +@click.option("-xprv", "--xprivate-key", type=str, default=None, + help="Set Master key from xprivate key.", show_default=True) +@click.option("-xpub", "--xpublic-key", type=str, default=None, + help="Set Master key from xpublic key.", show_default=True) +@click.option("-st", "--strict", type=bool, default=False, + help="Set Strict for root keys.", show_default=True) +@click.option("-ac", "--account", type=int, default=0, + help="Set derivation from account.", show_default=True) +@click.option("-ch", "--change", type=bool, default=False, + help="Set Derivation from change.", show_default=True) +@click.option("-ad", "--address", type=int, default=0, + help="Set Derivation from address.", show_default=True) +@click.option("-p", "--path", type=str, default=None, + help="Set Master key derivation path.", show_default=True) +@click.option("-prv", "--private-key", type=str, default=None, + help="Set Master key from private key.", show_default=True) +@click.option("-pub", "--public-key", type=str, default=None, + help="Set Master key from public key.", show_default=True) +@click.option("-w", "--wif", type=str, default=None, + help="Set Master key from wallet important format.", show_default=True) +@click.option("-sm", "--semantic", type=str, default="p2pkh", + help="Set Semantic for xprivate and xpublic keys.", show_default=True) +@click.pass_context +def generate( + context: click.core.Context, + symbol: str, + strength: int, + entropy: Optional[str], + mnemonic: Optional[str], + language: Optional[str], + passphrase: Optional[str], + seed: Optional[str], + xprivate_key: Optional[str], + xpublic_key: Optional[str], + strict: bool, + account: int, + change: bool, + address: int, + path: Optional[str], + private_key: Optional[str], + public_key: Optional[str], + wif: Optional[str], + semantic: str +): + if context.invoked_subcommand is None: + return generate_hdwallet( + symbol=symbol, + strength=strength, + entropy=entropy, + mnemonic=mnemonic, + language=language, + passphrase=passphrase, + seed=seed, + xprivate_key=xprivate_key, + xpublic_key=xpublic_key, + strict=strict, + account=account, + change=change, + address=address, + path=path, + private_key=private_key, + public_key=public_key, + wif=wif, + semantic=semantic + ) + + +@generate.command("addresses", aliases=["a"], options_metavar="[OPTIONS]", + short_help="Select Addresses for generation HDWallet addresses.") +@click.option("-s", "--symbol", type=str, default="BTC", + help="Set Cryptocurrency ticker symbol.") +@click.option("-sg", "--strength", type=int, default=128, + help="Set Strength for entropy, choose strength 128, 160, 192, 224 or 256 only.", show_default=True) +@click.option("-e", "--entropy", type=str, default=None, + help="Set Master key from entropy hex string.", show_default=True) +@click.option("-m", "--mnemonic", type=str, default=None, + help="Set Master key from mnemonic words.", show_default=True) +@click.option("-l", "--language", type=str, default="english", + help="Set Language for mnemonic, choose language english, french, italian, spanish, " + "chinese_simplified, chinese_traditional, japanese or korean only.", show_default=True) +@click.option("-pa", "--passphrase", type=str, default=None, + help="Set Passphrase for mnemonic.", show_default=True) +@click.option("-sd", "--seed", type=str, default=None, + help="Set Master key from seed hex string.", show_default=True) +@click.option("-xprv", "--xprivate-key", type=str, default=None, + help="Set Master key from xprivate key.", show_default=True) +@click.option("-xpub", "--xpublic-key", type=str, default=None, + help="Set Master key from xpublic key.", show_default=True) +@click.option("-st", "--strict", type=bool, default=False, + help="Set Strict for root keys.", show_default=True) +@click.option("-ac", "--account", type=int, default=0, + help="Set derivation from account.", show_default=True) +@click.option("-ch", "--change", type=bool, default=False, + help="Set Derivation from change.", show_default=True) +@click.option("-p", "--path", type=str, default=None, + help="Set Master key derivation path.", show_default=True) +@click.option("-se", "--semantic", type=str, default="p2pkh", + help="Set Semantic for xprivate and xpublic keys.", show_default=True) +@click.option("-h", "--hardened", type=bool, default=False, + help="Set Hardened for addresses.", show_default=True) +@click.option("-si", "--start-index", type=int, default=0, + help="Set Start from address index.", show_default=True) +@click.option("-ei", "--end-index", type=int, default=20, + help="Set End to address index.", show_default=True) +@click.option("-sh", "--show", type=str, default="path,addresses:p2pkh,public_key,wif", + help="Set Value key of generated HDWallet data to show.", show_default=True) +def addresses( + symbol: str, + strength: int, + entropy: Optional[str], + mnemonic: Optional[str], + language: Optional[str], + passphrase: Optional[str], + seed: Optional[str], + xprivate_key: Optional[str], + xpublic_key: Optional[str], + strict: bool, + account: int, + change: bool, + path: Optional[str], + semantic: str, + start_index: int, + end_index: int, + hardened: bool, + show: str +): + return generate_addresses( + symbol=symbol, + strength=strength, + entropy=entropy, + mnemonic=mnemonic, + language=language, + passphrase=passphrase, + seed=seed, + xprivate_key=xprivate_key, + xpublic_key=xpublic_key, + strict=strict, + account=account, + change=change, + path=path, + semantic=semantic, + start_index=start_index, + end_index=end_index, + hardened=hardened, + show=show + ) + + +@main.group("list", aliases=["l"], cls=ClickAliasedGroup, options_metavar="[OPTIONS]", + short_help="Select List for HDWallet information.", invoke_without_command=True) +def list(): + pass + + +@list.command("cryptocurrencies", aliases=["c"], options_metavar="[OPTIONS]", + short_help="List Available cryptocurrencies of HDWallet.") +def cryptocurrencies(): + return list_cryptocurrencies() + + +@list.command("languages", aliases=["l"], options_metavar="[OPTIONS]", + short_help="List Languages of mnemonic words.") +def languages(): + return list_languages() + + +@list.command("strengths", aliases=["s"], options_metavar="[OPTIONS]", + short_help="List Strengths of mnemonic words.") +def strengths(): + return list_strengths() diff --git a/hdwallet/cli/generate/__init__.py b/hdwallet/cli/generate/__init__.py new file mode 100644 index 0000000..4265cc3 --- /dev/null +++ b/hdwallet/cli/generate/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python diff --git a/hdwallet/cli/generate/addresses.py b/hdwallet/cli/generate/addresses.py new file mode 100644 index 0000000..0f37ed3 --- /dev/null +++ b/hdwallet/cli/generate/addresses.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +from typing import Optional + +from hdwallet import HDWallet +from hdwallet.derivations import ( + Derivation, BIP32Derivation +) +from hdwallet.cryptocurrencies import ( + Cryptocurrency, get_cryptocurrency +) +from hdwallet.utils import generate_mnemonic +from hdwallet.cli import ( + click, sys +) + + +def generate_addresses( + symbol: str, + strength: int, + entropy: Optional[str], + mnemonic: Optional[str], + language: Optional[str], + passphrase: Optional[str], + seed: Optional[str], + xprivate_key: Optional[str], + xpublic_key: Optional[str], + strict: bool, + account: int, + change: bool, + path: Optional[str], + semantic: str, + start_index: int, + end_index: int, + hardened: bool, + show: str +): + try: + hdwallet: HDWallet = HDWallet( + symbol=symbol, semantic=semantic + ) + if entropy: + hdwallet.from_entropy( + entropy=entropy, language=language, passphrase=passphrase + ) + elif mnemonic: + hdwallet.from_mnemonic( + mnemonic=mnemonic, passphrase=passphrase + ) + elif seed: + hdwallet.from_seed( + seed=seed + ) + elif xprivate_key: + hdwallet.from_xprivate_key( + xprivate_key=xprivate_key, strict=strict + ) + elif xpublic_key: + hdwallet.from_xpublic_key( + xpublic_key=xpublic_key, strict=strict + ) + else: + mnemonic = generate_mnemonic(language=language, strength=strength) + hdwallet.from_mnemonic( + mnemonic=mnemonic, language=language, passphrase=passphrase + ) + + for index in range(start_index, end_index): + if path: + derivation: Derivation = Derivation(path=path) + derivation.from_index(index=index, hardened=hardened) + hdwallet.from_path(path=derivation) + else: + cryptocurrency: Cryptocurrency = get_cryptocurrency(symbol=symbol) + bip32_derivation: BIP32Derivation = BIP32Derivation( + purpose=( + 44, False if xpublic_key else True + ), + coin_type=( + cryptocurrency.COIN_TYPE.INDEX, + False if xpublic_key else cryptocurrency.COIN_TYPE.HARDENED + ), + account=( + account, False if xpublic_key else True + ), + change=change, + address=index + ) + hdwallet.from_path(path=bip32_derivation) + + rows: str = "" + dumps = hdwallet.dumps() + for i, key in enumerate([keys.split(":") for keys in show.split(",")]): + rows += ( + f"{dumps[key[0]][key[1]] if len(key) == 2 else dumps[key[0]]}" + if i == 0 else + f" {dumps[key[0]][key[1]] if len(key) == 2 else dumps[key[0]]}" + ) + click.echo(rows) + + hdwallet.clean_derivation() + + except TimeoutError as exception: + click.echo(click.style(f"Error: {str(exception)}"), err=True) + sys.exit() diff --git a/hdwallet/cli/generate/hdwallet.py b/hdwallet/cli/generate/hdwallet.py new file mode 100644 index 0000000..d7e0172 --- /dev/null +++ b/hdwallet/cli/generate/hdwallet.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +from typing import Optional + +import json + +from hdwallet import HDWallet +from hdwallet.derivations import ( + Derivation, BIP32Derivation +) +from hdwallet.cryptocurrencies import ( + Cryptocurrency, get_cryptocurrency +) +from hdwallet.utils import generate_mnemonic +from hdwallet.cli import ( + click, sys +) + + +def generate_hdwallet( + symbol: str, + strength: Optional[int], + entropy: Optional[str], + mnemonic: Optional[str], + language: Optional[str], + passphrase: Optional[str], + seed: Optional[str], + xprivate_key: Optional[str], + xpublic_key: Optional[str], + strict: Optional[bool], + account: int, + change: bool, + address: int, + path: Optional[str], + private_key: Optional[str], + public_key: Optional[str], + wif: Optional[str], + semantic: str +): + try: + hdwallet: HDWallet = HDWallet( + symbol=symbol, semantic=semantic + ) + if entropy: + hdwallet.from_entropy( + entropy=entropy, language=language, passphrase=passphrase + ) + elif mnemonic: + hdwallet.from_mnemonic( + mnemonic=mnemonic, passphrase=passphrase + ) + elif seed: + hdwallet.from_seed( + seed=seed + ) + elif xprivate_key: + hdwallet.from_xprivate_key( + xprivate_key=xprivate_key, strict=strict + ) + elif xpublic_key: + hdwallet.from_xpublic_key( + xpublic_key=xpublic_key, strict=strict + ) + elif private_key: + hdwallet.from_private_key( + private_key=private_key + ) + elif public_key: + hdwallet.from_public_key( + public_key=public_key + ) + elif wif: + hdwallet.from_wif( + wif=wif + ) + else: + mnemonic = generate_mnemonic(language=language, strength=strength) + hdwallet.from_mnemonic( + mnemonic=mnemonic, language=language, passphrase=passphrase + ) + + if wif or private_key or public_key: + pass + else: + if path: + derivation: Derivation = Derivation(path=path) + hdwallet.from_path(path=derivation) + else: + cryptocurrency: Cryptocurrency = get_cryptocurrency(symbol=symbol) + bip32_derivation: BIP32Derivation = BIP32Derivation( + purpose=( + 44, False if xpublic_key else True + ), + coin_type=( + cryptocurrency.COIN_TYPE.INDEX, + False if xpublic_key else cryptocurrency.COIN_TYPE.HARDENED + ), + account=( + account, False if xpublic_key else True + ), + change=change, + address=address + ) + hdwallet.from_path(path=bip32_derivation) + + click.echo(json.dumps(hdwallet.dumps(), indent=4, ensure_ascii=False)) + + except Exception as exception: + click.echo(click.style(f"Error: {str(exception)}"), err=True) + sys.exit() diff --git a/hdwallet/cli/list/__init__.py b/hdwallet/cli/list/__init__.py new file mode 100644 index 0000000..4265cc3 --- /dev/null +++ b/hdwallet/cli/list/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python diff --git a/hdwallet/cli/list/cryptocurrencies.py b/hdwallet/cli/list/cryptocurrencies.py new file mode 100644 index 0000000..d55a60e --- /dev/null +++ b/hdwallet/cli/list/cryptocurrencies.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +from tabulate import tabulate + +import inspect + +from hdwallet import cryptocurrencies +from hdwallet.cli import click + + +def list_cryptocurrencies(): + + documents, table, headers = [], [], [ + "Cryptocurrency", "Symbol", "Mainnet", "Testnet", "Segwit", "Coin Type", "Default Path" + ] + + for name, cryptocurrency in inspect.getmembers(cryptocurrencies): + if inspect.isclass(cryptocurrency): + if issubclass(cryptocurrency, cryptocurrencies.Cryptocurrency) \ + and cryptocurrency != cryptocurrencies.Cryptocurrency: + + if cryptocurrency.NETWORK == "mainnet": + document: dict = { + "name": cryptocurrency.NAME, + "symbol": cryptocurrency.SYMBOL, + "source_code": cryptocurrency.SOURCE_CODE, + "mainnet": "Yes" if cryptocurrency.NETWORK == "mainnet" else "No", + "testnet": "Yes" if cryptocurrency.NETWORK == "testnet" else "No", + "segwit": "Yes" if cryptocurrency.SEGWIT_ADDRESS.HRP else "No", + "coin_type": cryptocurrency.COIN_TYPE.INDEX, + "default_path": cryptocurrency.DEFAULT_PATH + } + documents.append(document) + elif cryptocurrency.NETWORK == "testnet": + for index, document in enumerate(documents): + if document["name"] == cryptocurrency.NAME: + documents[index]["symbol"] = f"{document['symbol']}, {cryptocurrency.SYMBOL}" + documents[index]["testnet"] = "Yes" + else: + raise Exception("Invalid cryptocurrency network type.") + + for document in documents: + table.append([ + document["name"], + document["symbol"], + document["mainnet"], + document["testnet"], + document["segwit"], + document["coin_type"], + document["default_path"] + ]) + + click.echo(tabulate(table, headers, tablefmt="github")) diff --git a/hdwallet/cli/list/languages.py b/hdwallet/cli/list/languages.py new file mode 100644 index 0000000..11aed27 --- /dev/null +++ b/hdwallet/cli/list/languages.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +from tabulate import tabulate + +from hdwallet.cli import click + + +def list_languages(): + + click.echo(tabulate( + [ + ["Chinese Simplified"], + ["Chinese Traditional"], + ["English"], + ["French"], + ["Italian"], + ["Japanese"], + ["Korean"], + ["Spanish"], + ], + [ + "Language" + ], + tablefmt="github" + )) diff --git a/hdwallet/cli/list/strengths.py b/hdwallet/cli/list/strengths.py new file mode 100644 index 0000000..d0e9114 --- /dev/null +++ b/hdwallet/cli/list/strengths.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +from tabulate import tabulate + +from hdwallet.cli import click + + +def list_strengths(): + + click.echo(tabulate( + [ + [128, 12], + [160, 15], + [192, 18], + [224, 21], + [256, 24], + ], + [ + "Strength", + "Words" + ], + tablefmt="github" + )) diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index 1099f4b..aa8a83d 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -109,7 +109,7 @@ class AnonMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18ANON Signed Message:\n" + MESSAGE_PREFIX = "\x18ANON Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -149,7 +149,7 @@ class ArgoneumMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -189,7 +189,7 @@ class ArtaxMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Artax Signed Message:\n" + MESSAGE_PREFIX = "\x18Artax Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x97 @@ -229,7 +229,7 @@ class AryacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Aryacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Aryacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x97 @@ -269,7 +269,7 @@ class AsiacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18AsiaCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18AsiaCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x97 @@ -309,7 +309,7 @@ class AtomMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bitcoin Atom Signed Message:\n" + MESSAGE_PREFIX = "\x18Bitcoin Atom Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -349,11 +349,50 @@ class AuroracoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18AuroraCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18AuroraCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x97 +class AviancoinMainnet(Cryptocurrency): + NAME = "Aviancoin" + SYMBOL = "AVN" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/AvianNetwork/Avian" + COIN_TYPE = CoinType({ + "INDEX": 921, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x7a + PUBLIC_KEY_ADDRESS = 0x3c + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "av", + "VERSION": 0x0d + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = "Aviancoin Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + class AxeMainnet(Cryptocurrency): NAME = "Axe" @@ -389,7 +428,7 @@ class AxeMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xcc @@ -429,7 +468,7 @@ class BataMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bata Signed Message:\n" + MESSAGE_PREFIX = "\x18Bata Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa4 @@ -469,7 +508,7 @@ class BeetleCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19Beetlecoin Signed Message:\n" + MESSAGE_PREFIX = "\x19Beetlecoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -509,7 +548,7 @@ class BelaCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BelaCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18BelaCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -549,7 +588,7 @@ class BitCloudMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BitCloud Signed Message:\n" + MESSAGE_PREFIX = "\x18BitCloud Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -589,7 +628,7 @@ class BitSendMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bitsend Signed Message:\n" + MESSAGE_PREFIX = "\x18Bitsend Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xcc @@ -749,7 +788,7 @@ class BitcoinPlusMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BitcoinPlus Signed Message:\n" + MESSAGE_PREFIX = "\x18BitcoinPlus Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -789,7 +828,7 @@ class BitcoinSVMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -869,7 +908,7 @@ class BitcoinZMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BitcoinZ Signed Message:\n" + MESSAGE_PREFIX = "\x18BitcoinZ Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -909,7 +948,7 @@ class BitcoreMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BitCore Signed Message:\n" + MESSAGE_PREFIX = "\x18BitCore Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -949,7 +988,7 @@ class BlackcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BlackCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18BlackCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -989,7 +1028,7 @@ class BlockStampMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BlockStamp Signed Message:\n" + MESSAGE_PREFIX = "\x18BlockStamp Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -1029,7 +1068,7 @@ class BlocknodeMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Blocknode Signed Message:\n" + MESSAGE_PREFIX = "\x18Blocknode Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x4b @@ -1069,7 +1108,7 @@ class BlocknodeTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Blocknode Testnet Signed Message:\n" + MESSAGE_PREFIX = "\x18Blocknode Testnet Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x89 @@ -1109,7 +1148,7 @@ class BolivarcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "Bolivarcoin Signed Message:\n" + MESSAGE_PREFIX = "Bolivarcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xd5 @@ -1149,7 +1188,7 @@ class BritCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18BritCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18BritCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -1189,7 +1228,7 @@ class CPUChainMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x1DCPUchain Signed Message:\n" + MESSAGE_PREFIX = "\x1DCPUchain Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -1229,7 +1268,7 @@ class CanadaECoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Canada eCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Canada eCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9c @@ -1269,7 +1308,7 @@ class CannacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Cannacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Cannacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9c @@ -1309,7 +1348,7 @@ class ClamsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x85 @@ -1349,7 +1388,7 @@ class ClubCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18ClubCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18ClubCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -1389,7 +1428,7 @@ class CompcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18CompCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18CompCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9c @@ -1429,7 +1468,7 @@ class CranePayMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x7b @@ -1469,7 +1508,7 @@ class CraveMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18DarkNet Signed Message:\n" + MESSAGE_PREFIX = "\x18DarkNet Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x99 @@ -1589,7 +1628,7 @@ class DeepOnionMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18DeepOnion Signed Message:\n" + MESSAGE_PREFIX = "\x18DeepOnion Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9f @@ -1629,7 +1668,7 @@ class DefcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18defcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18defcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9e @@ -1669,7 +1708,7 @@ class DenariusMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19Denarius Signed Message:\n" + MESSAGE_PREFIX = "\x19Denarius Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9e @@ -1709,7 +1748,7 @@ class DiamondMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Diamond Signed Message:\n" + MESSAGE_PREFIX = "\x18Diamond Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xda @@ -1749,7 +1788,7 @@ class DigiByteMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19DigiByte Signed Message:\n" + MESSAGE_PREFIX = "\x19DigiByte Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -1789,7 +1828,7 @@ class DigitalcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Digitalcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Digitalcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9e @@ -1909,7 +1948,7 @@ class EDRCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18EDRcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18EDRcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xdd @@ -1949,7 +1988,7 @@ class EcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18eCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18eCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xdc @@ -1989,7 +2028,7 @@ class EinsteiniumMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Einsteinium Signed Message:\n" + MESSAGE_PREFIX = "\x18Einsteinium Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa1 @@ -2029,7 +2068,7 @@ class ElastosMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef @@ -2069,7 +2108,7 @@ class EnergiMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "DarkCoin Signed Message:\n" + MESSAGE_PREFIX = "DarkCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x6a @@ -2114,6 +2153,206 @@ class EthereumMainnet(Cryptocurrency): WIF_SECRET_KEY = 0x80 +class BinanceSmartChainMainnet(Cryptocurrency): + + NAME = "Binance Smart Chain" + SYMBOL = "BSC" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/bnb-chain/bsc" + COIN_TYPE = CoinType({ + "INDEX": 9006, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x00 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class PolygonMainnet(Cryptocurrency): + + NAME = "Polygon" + SYMBOL = "MATIC" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/bnb-chain/bsc" + COIN_TYPE = CoinType({ + "INDEX": 966, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x00 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class ArbitrumMainnet(Cryptocurrency): + + NAME = "Arbitrum" + SYMBOL = "ARB1" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/bnb-chain/bsc" + COIN_TYPE = CoinType({ + "INDEX": 9001, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x00 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class zkSyncMainnet(Cryptocurrency): + + NAME = "zkSync" + SYMBOL = "ZKS" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/bnb-chain/bsc" + COIN_TYPE = CoinType({ + "INDEX": 804, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x00 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class LineaMainnet(Cryptocurrency): + + NAME = "Linea" + SYMBOL = "LINEA" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/bnb-chain/bsc" + COIN_TYPE = CoinType({ + "INDEX": 59144, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x00 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + class EuropeCoinMainnet(Cryptocurrency): NAME = "Europe Coin" @@ -2149,11 +2388,91 @@ class EuropeCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa8 +class EvrmoreMainnet(Cryptocurrency): + + NAME = "Evrmore" + SYMBOL = "EVR" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/EvrmoreOrg/Evrmore" + COIN_TYPE = CoinType({ + "INDEX": 175, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x5c + PUBLIC_KEY_ADDRESS = 0x21 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "ev", + "VERSION": 0x0b + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = "Evrmore Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class EvrmoreTestnet(Cryptocurrency): + + NAME = "Evrmore" + SYMBOL = "EVRTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/EvrmoreOrg/Evrmore" + COIN_TYPE = CoinType({ + "INDEX": 1, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0xc4 + PUBLIC_KEY_ADDRESS = 0x6f + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "te", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = "Evrmore Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0xef + + class ExclusiveCoinMainnet(Cryptocurrency): NAME = "Exclusive Coin" @@ -2189,7 +2508,7 @@ class ExclusiveCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18ExclusiveCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18ExclusiveCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa1 @@ -2229,7 +2548,7 @@ class FIXMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x3c @@ -2269,7 +2588,7 @@ class FIXTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xed @@ -2309,7 +2628,7 @@ class FeathercoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Feathercoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Feathercoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x8e @@ -2349,7 +2668,7 @@ class FirstcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18FirstCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18FirstCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa3 @@ -2383,15 +2702,133 @@ class FlashcoinMainnet(Cryptocurrency): EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ "P2PKH": 0x488b21e, "P2SH": 0x488b21e, - "P2WPKH": None, - "P2WPKH_IN_P2SH": None, - "P2WSH": None, - "P2WSH_IN_P2SH": None + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + + MESSAGE_PREFIX = "\x18Flashcoin Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0xc4 + +class FluxMainnet(Cryptocurrency): + + NAME = "Flux" + SYMBOL = "FLUX" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/RunOnFlux/fluxd" + COIN_TYPE = CoinType({ + "INDEX": 19167, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x1cbd + PUBLIC_KEY_ADDRESS = 0x1cb8 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": None, + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + MESSAGE_PREFIX = "\x18Zelcash Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class FoxdcoinMainnet(Cryptocurrency): + + NAME = "Foxdcoin" + SYMBOL = "FOXD" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/foxdproject/foxdcoin" + COIN_TYPE = CoinType({ + "INDEX": 175, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x1e + PUBLIC_KEY_ADDRESS = 0x23 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "fx", + "VERSION": 0x0d + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = "Foxdcoin Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class FoxdcoinTestnet(Cryptocurrency): + + NAME = "Foxdcoin" + SYMBOL = "FOXDTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/foxdproject/foxdcoin" + COIN_TYPE = CoinType({ + "INDEX": 1, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x5a + PUBLIC_KEY_ADDRESS = 0x5f + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "tf", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f }) - - MASSAGE_PREFIX = "\x18Flashcoin Signed Message:\n" + + MESSAGE_PREFIX = "Foxdcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0xc4 + WIF_SECRET_KEY = 0xef class FujiCoinMainnet(Cryptocurrency): @@ -2429,7 +2866,7 @@ class FujiCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19FujiCoin Signed Message:\n" + MESSAGE_PREFIX = "\x19FujiCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa4 @@ -2469,7 +2906,7 @@ class GCRCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18GCR Signed Message:\n" + MESSAGE_PREFIX = "\x18GCR Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9a @@ -2509,7 +2946,7 @@ class GameCreditsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa6 @@ -2549,7 +2986,7 @@ class GoByteMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18DarkCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18DarkCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc6 @@ -2589,7 +3026,7 @@ class GridcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Gridcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Gridcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbe @@ -2629,7 +3066,7 @@ class GroestlCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19GroestlCoin Signed Message:\n" + MESSAGE_PREFIX = "\x19GroestlCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -2669,7 +3106,7 @@ class GroestlCoinTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19GroestlCoin Signed Message:\n" + MESSAGE_PREFIX = "\x19GroestlCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef @@ -2709,7 +3146,7 @@ class GuldenMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Guldencoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Guldencoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x62 @@ -2749,7 +3186,7 @@ class HushMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Hush Signed Message:\n" + MESSAGE_PREFIX = "\x18Hush Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -2789,7 +3226,7 @@ class HelleniccoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18helleniccoin Signed Message:\n" + MESSAGE_PREFIX = "\x18helleniccoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb0 @@ -2829,7 +3266,7 @@ class HempcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Hempcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Hempcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa8 @@ -2869,7 +3306,7 @@ class IXCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Ixcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Ixcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -2909,7 +3346,7 @@ class InsaneCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18INSaNe Signed Message:\n" + MESSAGE_PREFIX = "\x18INSaNe Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x37 @@ -2949,7 +3386,7 @@ class InternetOfPeopleMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18IoP Signed Message:\n" + MESSAGE_PREFIX = "\x18IoP Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x31 @@ -2989,7 +3426,7 @@ class JumbucksMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x19Jumbucks Signed Message:\n" + MESSAGE_PREFIX = "\x19Jumbucks Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xab @@ -3029,7 +3466,7 @@ class KobocoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Kobocoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Kobocoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xa3 @@ -3069,7 +3506,7 @@ class KomodoMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Komodo Signed Message:\n" + MESSAGE_PREFIX = "\x18Komodo Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbc @@ -3109,7 +3546,7 @@ class LBRYCreditsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18LBRYcrd Signed Message:\n" + MESSAGE_PREFIX = "\x18LBRYcrd Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x1c @@ -3149,7 +3586,7 @@ class LinxMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18LinX Signed Message:\n" + MESSAGE_PREFIX = "\x18LinX Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xcb @@ -3189,7 +3626,7 @@ class LitecoinCashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Litecoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Litecoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb0 @@ -3213,18 +3650,18 @@ class LitecoinMainnet(Cryptocurrency): }) EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ - "P2PKH": 0x019d9cfe, - "P2SH": 0x019d9cfe, - "P2WPKH": 0x04b2430c, - "P2WPKH_IN_P2SH": 0x01b26792, + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, "P2WSH": None, "P2WSH_IN_P2SH": None }) EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ - "P2PKH": 0x019da462, - "P2SH": 0x019da462, - "P2WPKH": 0x04b24746, - "P2WPKH_IN_P2SH": 0x01b26ef6, + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, "P2WSH": None, "P2WSH_IN_P2SH": None }) @@ -3245,33 +3682,33 @@ class LitecoinTestnet(Cryptocurrency): "HARDENED": True }) - SCRIPT_ADDRESS = 0xc4 + SCRIPT_ADDRESS = 0x3a PUBLIC_KEY_ADDRESS = 0x6f SEGWIT_ADDRESS = SegwitAddress({ - "HRP": "litecointestnet", + "HRP": "tltc", "VERSION": 0x00 }) EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ - "P2PKH": 0x0436ef7d, - "P2SH": 0x0436ef7d, - "P2WPKH": 0x04358394, - "P2WPKH_IN_P2SH": 0x04358394, + "P2PKH": 0x04358394, + "P2SH": 0x04358394, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, "P2WSH": None, "P2WSH_IN_P2SH": None }) EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ - "P2PKH": 0x0436f6e1, - "P2SH": 0x0436f6e1, - "P2WPKH": 0x043587cf, - "P2WPKH_IN_P2SH": 0x043587cf, + "P2PKH": 0x043587cf, + "P2SH": 0x043587cf, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, "P2WSH": None, "P2WSH_IN_P2SH": None }) MESSAGE_PREFIX = "\x19Litecoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0xb0 + WIF_SECRET_KEY = 0xef class LitecoinZMainnet(Cryptocurrency): @@ -3309,7 +3746,7 @@ class LitecoinZMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18LitecoinZ Signed Message:\n" + MESSAGE_PREFIX = "\x18LitecoinZ Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -3349,7 +3786,7 @@ class LkrcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18LKRcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18LKRcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb0 @@ -3389,7 +3826,7 @@ class LynxMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Lynx Signed Message:\n" + MESSAGE_PREFIX = "\x18Lynx Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xad @@ -3429,7 +3866,7 @@ class MazacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xe0 @@ -3469,7 +3906,7 @@ class MegacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Megacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Megacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb2 @@ -3509,7 +3946,7 @@ class MinexcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -3549,7 +3986,7 @@ class MonacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Monacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Monacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb0 @@ -3589,7 +4026,7 @@ class MonkeyProjectMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "Monkey Signed Message:\n" + MESSAGE_PREFIX = "Monkey Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x37 @@ -3629,7 +4066,7 @@ class MyriadcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb2 @@ -3669,7 +4106,7 @@ class NIXMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Nix Signed Message:\n" + MESSAGE_PREFIX = "\x18Nix Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -3709,7 +4146,7 @@ class NamecoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -3789,7 +4226,7 @@ class NeblioMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Neblio Signed Message:\n" + MESSAGE_PREFIX = "\x18Neblio Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb5 @@ -3829,7 +4266,7 @@ class NeoscoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18NeosCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18NeosCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb1 @@ -3869,7 +4306,7 @@ class NeurocoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18PPCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18PPCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb5 @@ -3909,7 +4346,7 @@ class NewYorkCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18newyorkc Signed Message:\n" + MESSAGE_PREFIX = "\x18newyorkc Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbc @@ -3949,7 +4386,7 @@ class NovacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18NovaCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18NovaCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x88 @@ -3989,7 +4426,7 @@ class NuBitsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Nu Signed Message:\n" + MESSAGE_PREFIX = "\x18Nu Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x96 @@ -4029,7 +4466,7 @@ class NuSharesMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Nu Signed Message:\n" + MESSAGE_PREFIX = "\x18Nu Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x95 @@ -4069,7 +4506,7 @@ class OKCashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18OKCash Signed Message:\n" + MESSAGE_PREFIX = "\x18OKCash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x3 @@ -4189,7 +4626,7 @@ class OnixCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "ONIX Signed Message:\n" + MESSAGE_PREFIX = "ONIX Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xcb @@ -4229,7 +4666,7 @@ class PeercoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb7 @@ -4269,7 +4706,7 @@ class PesobitMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Pesobit Signed Message:\n" + MESSAGE_PREFIX = "\x18Pesobit Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb7 @@ -4309,7 +4746,7 @@ class PhoreMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Phore Signed Message:\n" + MESSAGE_PREFIX = "\x18Phore Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xd4 @@ -4349,7 +4786,7 @@ class PinkcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Pinkcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Pinkcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x83 @@ -4389,7 +4826,7 @@ class PivxMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xd4 @@ -4429,7 +4866,7 @@ class PivxTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef @@ -4469,7 +4906,7 @@ class PoswCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Poswcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Poswcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb7 @@ -4509,7 +4946,7 @@ class PotcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Potcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Potcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb7 @@ -4549,7 +4986,7 @@ class ProjectCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18ProjectCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18ProjectCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x75 @@ -4589,7 +5026,7 @@ class PutincoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18PutinCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18PutinCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xb7 @@ -4709,7 +5146,7 @@ class RSKMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18RSK Signed Message:\n" + MESSAGE_PREFIX = "\x18RSK Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -4749,7 +5186,7 @@ class RSKTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18RSK Testnet Signed Message:\n" + MESSAGE_PREFIX = "\x18RSK Testnet Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef @@ -4789,7 +5226,7 @@ class RapidsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "DarkNet Signed Message:\n" + MESSAGE_PREFIX = "DarkNet Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x2e @@ -4799,7 +5236,7 @@ class RavencoinMainnet(Cryptocurrency): NAME = "Ravencoin" SYMBOL = "RVN" NETWORK = "mainnet" - SOURCE_CODE = None + SOURCE_CODE = "https://github.com/RavenProject/Ravencoin" COIN_TYPE = CoinType({ "INDEX": 175, "HARDENED": True @@ -4807,6 +5244,82 @@ class RavencoinMainnet(Cryptocurrency): SCRIPT_ADDRESS = 0x7a PUBLIC_KEY_ADDRESS = 0x3c + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "ra", + "VERSION": 0x0c + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = "Raven Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class RavencoinTestnet(Cryptocurrency): + + NAME = "Ravencoin" + SYMBOL = "RVNTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/RavenProject/Ravencoin" + COIN_TYPE = CoinType({ + "INDEX": 1, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0xc4 + PUBLIC_KEY_ADDRESS = 0x6f + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "tr", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + +class ReddcoinMainnet(Cryptocurrency): + + NAME = "Reddcoin" + SYMBOL = "RDD" + NETWORK = "mainnet" + SOURCE_CODE = None + COIN_TYPE = CoinType({ + "INDEX": 4, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x5 + PUBLIC_KEY_ADDRESS = 0x3d SEGWIT_ADDRESS = SegwitAddress({ "HRP": None, "VERSION": 0x00 @@ -4829,24 +5342,24 @@ class RavencoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "Raven Signed Message:\n" + MESSAGE_PREFIX = "\x18Reddcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0x80 + WIF_SECRET_KEY = 0xbd -class ReddcoinMainnet(Cryptocurrency): +class RippleMainnet(Cryptocurrency): - NAME = "Reddcoin" - SYMBOL = "RDD" + NAME = "Ripple" + SYMBOL = "XRP" NETWORK = "mainnet" SOURCE_CODE = None COIN_TYPE = CoinType({ - "INDEX": 4, + "INDEX": 144, "HARDENED": True }) - SCRIPT_ADDRESS = 0x5 - PUBLIC_KEY_ADDRESS = 0x3d + SCRIPT_ADDRESS = 0x00 + PUBLIC_KEY_ADDRESS = 0x00 SEGWIT_ADDRESS = SegwitAddress({ "HRP": None, "VERSION": 0x00 @@ -4869,9 +5382,9 @@ class ReddcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Reddcoin Signed Message:\n" + MASSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0xbd + WIF_SECRET_KEY = 0x80 class RubycoinMainnet(Cryptocurrency): @@ -4909,7 +5422,7 @@ class RubycoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Rubycoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Rubycoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbc @@ -4949,7 +5462,7 @@ class SafecoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Safecoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Safecoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbd @@ -4989,7 +5502,7 @@ class SaluscoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Salus Signed Message:\n" + MESSAGE_PREFIX = "\x18Salus Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -5029,7 +5542,7 @@ class ScribeMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x6e @@ -5069,7 +5582,7 @@ class ShadowCashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -5109,7 +5622,7 @@ class ShadowCashTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xff @@ -5149,7 +5662,7 @@ class SlimcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x46 @@ -5189,7 +5702,7 @@ class SlimcoinTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x57 @@ -5229,7 +5742,7 @@ class SmileycoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Smileycoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Smileycoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x5 @@ -5269,7 +5782,7 @@ class SolarcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18SolarCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18SolarCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x92 @@ -5309,7 +5822,7 @@ class StashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Stash Signed Message:\n" + MESSAGE_PREFIX = "\x18Stash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xcc @@ -5349,7 +5862,7 @@ class StratisMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Stratis Signed Message:\n" + MESSAGE_PREFIX = "\x18Stratis Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -5389,7 +5902,7 @@ class StratisTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Stratis Test Signed Message:\n" + MESSAGE_PREFIX = "\x18Stratis Test Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -5429,7 +5942,7 @@ class SugarchainMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Sugarchain Signed Message:\n" + MESSAGE_PREFIX = "\x18Sugarchain Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -5469,7 +5982,7 @@ class SugarchainTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Sugarchain Signed Message:\n" + MESSAGE_PREFIX = "\x18Sugarchain Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef @@ -5509,7 +6022,7 @@ class SyscoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Syscoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Syscoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -5549,7 +6062,7 @@ class TOACoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18TOA Signed Message:\n" + MESSAGE_PREFIX = "\x18TOA Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc1 @@ -5589,11 +6102,53 @@ class ThoughtAIMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x7b +class TronMainnet(Cryptocurrency): + + NAME = "Tron" + SYMBOL = "TRX" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/tronprotocol/java-tron" + + COIN_TYPE = CoinType({ + "INDEX": 195, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x41 + + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": "bc", + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x0488ade4, + "P2SH": 0x0488ade4, + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x0488b21e, + "P2SH": 0x0488b21e, + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f + }) + + MESSAGE_PREFIX = None + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + class TwinsMainnet(Cryptocurrency): NAME = "Twins" @@ -5629,7 +6184,7 @@ class TwinsMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x42 @@ -5669,7 +6224,7 @@ class TwinsTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xed @@ -5709,7 +6264,7 @@ class UltimateSecureCashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18UltimateSecureCash Signed Message:\n" + MESSAGE_PREFIX = "\x18UltimateSecureCash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xbf @@ -5749,7 +6304,7 @@ class UnobtaniumMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Unobtanium Signed Message:\n" + MESSAGE_PREFIX = "\x18Unobtanium Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xe0 @@ -5789,7 +6344,7 @@ class VPNCoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18VpnCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18VpnCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc7 @@ -5829,7 +6384,7 @@ class VcashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Vcash Signed Message:\n" + MESSAGE_PREFIX = "\x18Vcash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc7 @@ -5869,7 +6424,7 @@ class VergeCurrencyMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18VERGE Signed Message:\n" + MESSAGE_PREFIX = "\x18VERGE Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x9e @@ -5909,7 +6464,7 @@ class VertcoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Vertcoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Vertcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -5949,7 +6504,7 @@ class ViacoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Viacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Viacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc7 @@ -5989,7 +6544,7 @@ class ViacoinTestnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Viacoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Viacoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xff @@ -6029,7 +6584,7 @@ class VivoMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18DarkCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18DarkCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc6 @@ -6069,7 +6624,7 @@ class WhitecoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Whitecoin Signed Message:\n" + MESSAGE_PREFIX = "\x18Whitecoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc9 @@ -6109,7 +6664,7 @@ class WincoinMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18WinCoin Signed Message:\n" + MESSAGE_PREFIX = "\x18WinCoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xc9 @@ -6149,7 +6704,7 @@ class XUEZMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = None + MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xd4 @@ -6192,6 +6747,45 @@ class XinFinMainnet(Cryptocurrency): MESSAGE_PREFIX = None DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 + +class YcashMainnet(Cryptocurrency): + + NAME = "Ycash" + SYMBOL = "YEC" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/ycashfoundation/ycash" + COIN_TYPE = CoinType({ + "INDEX": 347, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x1c2c + PUBLIC_KEY_ADDRESS = 0x1c28 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": None, + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x488ade4, + "P2SH": 0x488ade4, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x488b21e, + "P2SH": 0x488b21e, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + + MESSAGE_PREFIX = "\x18Ycash Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 class ZClassicMainnet(Cryptocurrency): @@ -6229,7 +6823,7 @@ class ZClassicMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Zcash Signed Message:\n" + MESSAGE_PREFIX = "\x18Zcash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 @@ -6239,7 +6833,7 @@ class ZcashMainnet(Cryptocurrency): NAME = "Zcash" SYMBOL = "ZEC" NETWORK = "mainnet" - SOURCE_CODE = None + SOURCE_CODE = "https://github.com/zcash/zcash" COIN_TYPE = CoinType({ "INDEX": 133, "HARDENED": True @@ -6269,11 +6863,51 @@ class ZcashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Zcash Signed Message:\n" + MESSAGE_PREFIX = "\x18Zcash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 +class ZcashTestnet(Cryptocurrency): + + NAME = "Zcash" + SYMBOL = "ZECTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/zcash/zcash" + COIN_TYPE = CoinType({ + "INDEX": 1, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x1cba + PUBLIC_KEY_ADDRESS = 0x1d25 + SEGWIT_ADDRESS = SegwitAddress({ + "HRP": None, + "VERSION": 0x00 + }) + + EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ + "P2PKH": 0x4358394, + "P2SH": 0x4358394, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ + "P2PKH": 0x43587cf, + "P2SH": 0x43587cf, + "P2WPKH": None, + "P2WPKH_IN_P2SH": None, + "P2WSH": None, + "P2WSH_IN_P2SH": None + }) + + MESSAGE_PREFIX = "\x18Zcash Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0xef + + class ZencashMainnet(Cryptocurrency): NAME = "Zencash" @@ -6309,7 +6943,7 @@ class ZencashMainnet(Cryptocurrency): "P2WSH_IN_P2SH": None }) - MASSAGE_PREFIX = "\x18Zcash Signed Message:\n" + MESSAGE_PREFIX = "\x18Zcash Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 diff --git a/hdwallet/derivations.py b/hdwallet/derivations.py index 9a49013..c7d290d 100644 --- a/hdwallet/derivations.py +++ b/hdwallet/derivations.py @@ -27,7 +27,7 @@ class Derivation: >>> Derivation() >>> str(Derivation()) - "" + "\0\0\0\0" >>> str(Derivation(path="m/44'/0'/0'/0/0", semantic="p2pkh")) "m/44'/0'/0'/0/0" @@ -67,7 +67,7 @@ def from_path(cls, path: str) -> "Derivation": >>> from hdwallet.derivations import Derivation >>> derivation = Derivation() - >>> derivation.from_path(path="m/44'/0'/'0/0/0") + >>> derivation.from_path(path="m/44'/0'/0'/0/0") """ @@ -106,6 +106,8 @@ def from_index(self, index: int, hardened: bool = False) -> "Derivation": if not isinstance(index, int): raise DerivationError("Bad derivation index, Please import only int type!") + if self.PATH == "\0\0\0\0": + self.PATH = "" self.PATH += ( (f"/{index}'" if hardened else f"/{index}") if self.PATH.startswith("m/") else @@ -121,13 +123,13 @@ def clean_derivation(self) -> "Derivation": >>> from hdwallet.derivations import Derivation >>> derivation = Derivation() - >>> derivation.from_path(path="m/44'/0'/'0/0/0") + >>> derivation.from_path(path="m/44'/0'/0'/0/0") >>> str(derivation) - "m/44'/0'/'0/0/0" + "m/44'/0'/0'/0/0" >>> derivation.clean_derivation() >>> str(derivation) - "" + "\0\0\0\0" """ self.PATH = "\0\0\0\0" @@ -510,7 +512,7 @@ class BIP84Derivation(BIP32Derivation): >>> BIP84Derivation(cryptocurrency=BitcoinMainnet) >>> str(BIP84Derivation(cryptocurrency=BitcoinMainnet)) - "m/49'/0'/0'/0/0" + "m/84'/0'/0'/0/0" """ PURPOSE: int = 84 @@ -547,7 +549,7 @@ class BIP141Derivation(Derivation): >>> BIP141Derivation(cryptocurrency=BitcoinMainnet) >>> str(BIP141Derivation(cryptocurrency=BitcoinMainnet)) - "m/49'/0'/0'/0/0" + "m/44'/0'/0'/0/0" """ def __init__(self, cryptocurrency: Any, path: Union[str, Derivation] = None, semantic: str = "p2wpkh"): diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 5e226b7..a08fec0 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -1,10 +1,35 @@ #!/usr/bin/env python3 +""" +The MIT License (MIT) + +Copyright © 2021-2022 by Meheret Tesfaye Batu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + from ecdsa.curves import SECP256k1 from ecdsa.ellipticcurve import Point from ecdsa.keys import ( SigningKey, VerifyingKey ) +from ecdsa.util import sigencode_der from ecdsa.ecdsa import ( int_to_string, string_to_int ) @@ -19,15 +44,17 @@ from typing import ( Optional, Any, Union ) +from functools import partial import hmac import ecdsa import struct -import sha3 +from Crypto.Hash import keccak import unicodedata import hashlib import base58 +from .libs.ripemd160 import ripemd160 from .libs.ecc import S256Point, N, G from .libs.bech32 import ( bech32_encode, encode, bech32_decode, decode @@ -39,19 +66,19 @@ Cryptocurrency, get_cryptocurrency, SegwitAddress ) from .derivations import ( - Derivation, BIP32Derivation, BIP44Derivation, - BIP49Derivation, BIP84Derivation, BIP141Derivation + Derivation, BIP32Derivation, BIP44Derivation, BIP49Derivation, BIP84Derivation, BIP141Derivation ) from .exceptions import ( SemanticError, DerivationError ) from .utils import ( get_bytes, is_entropy, is_mnemonic, get_entropy_strength, _unhexlify, is_root_xpublic_key, - get_mnemonic_language, is_root_xprivate_key, get_mnemonic_strength + get_mnemonic_language, is_root_xprivate_key, get_mnemonic_strength, get_semantic ) MIN_ENTROPY_LEN: int = 128 BIP32KEY_HARDEN: int = 0x80000000 +highest_s = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0 CURVE_GEN: Any = ecdsa.ecdsa.generator_secp256k1 CURVE_ORDER: int = CURVE_GEN.order() @@ -79,7 +106,7 @@ class HDWallet: """ def __init__(self, symbol: str = "BTC", cryptocurrency: Any = None, - semantic: str = "p2pkh", use_default_path: bool = False): + semantic: Optional[str] = None, use_default_path: bool = False): self._cryptocurrency: Any = None if cryptocurrency: if not issubclass(cryptocurrency, Cryptocurrency): @@ -115,6 +142,10 @@ def __init__(self, symbol: str = "BTC", cryptocurrency: Any = None, self._depth: int = 0 self._index: int = 0 + self._root_depth: int = 0 + self._root_parent_fingerprint: bytes = b"\0\0\0\0" + self._root_index: int = 0 + def from_entropy(self, entropy: str, language: str = "english", passphrase: str = None) -> "HDWallet": """ Master from Entropy hex string. @@ -140,7 +171,7 @@ def from_entropy(self, entropy: str, language: str = "english", passphrase: str if language and language not in ["english", "french", "italian", "japanese", "chinese_simplified", "chinese_traditional", "korean", "spanish"]: raise ValueError("Invalid language, choose only the following options 'english', 'french', 'italian', " - "'spanish', 'chinese_simplified', 'chinese_traditional', 'japanese or 'korean' languages.") + "'spanish', 'chinese_simplified', 'chinese_traditional', 'japanese' or 'korean' languages.") self._strength = get_entropy_strength(entropy=entropy) self._entropy, self._language = unhexlify(entropy), language @@ -148,6 +179,8 @@ def from_entropy(self, entropy: str, language: str = "english", passphrase: str mnemonic = Mnemonic(language=self._language).to_mnemonic(data=self._entropy) self._mnemonic = unicodedata.normalize("NFKD", mnemonic) self._seed = Mnemonic.to_seed(mnemonic=self._mnemonic, passphrase=self._passphrase) + if self._semantic is None: + self._semantic = "p2pkh" return self.from_seed(seed=hexlify(self._seed).decode()) def from_mnemonic(self, mnemonic: str, language: str = None, passphrase: str = None) -> "HDWallet": @@ -179,6 +212,8 @@ def from_mnemonic(self, mnemonic: str, language: str = None, passphrase: str = N self._entropy = Mnemonic(language=self._language).to_entropy(self._mnemonic) self._passphrase = str(passphrase) if passphrase else str() self._seed = Mnemonic.to_seed(mnemonic=self._mnemonic, passphrase=self._passphrase) + if self._semantic is None: + self._semantic = "p2pkh" return self.from_seed(seed=hexlify(self._seed).decode()) def from_seed(self, seed: str) -> "HDWallet": @@ -213,15 +248,17 @@ def from_seed(self, seed: str) -> "HDWallet": self._public_key = self.compressed() if self._from_class: self.from_path(path=self._path_class) + if self._semantic is None: + self._semantic = "p2pkh" return self - def from_root_xprivate_key(self, xprivate_key: str, strict: bool = True) -> "HDWallet": + def from_xprivate_key(self, xprivate_key: str, strict: bool = False) -> "HDWallet": """ - Master from Root XPrivate Key. + Master from XPrivate Key. - :param xprivate_key: Root xprivate key. + :param xprivate_key: Root or Non-Root XPrivate key. :type xprivate_key: str - :param strict: Strict for must be root xprivate key, default to ``True``. + :param strict: Strict for must be root xprivate key, default to ``False``. :type strict: bool :returns: HDWallet -- Hierarchical Deterministic Wallet instance. @@ -229,18 +266,25 @@ def from_root_xprivate_key(self, xprivate_key: str, strict: bool = True) -> "HDW >>> from hdwallet import HDWallet >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_root_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") + >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") """ if not is_root_xprivate_key(xprivate_key=xprivate_key, symbol=self._cryptocurrency.SYMBOL): if strict: raise ValueError("Invalid root xprivate key.") - else: - print("Warning: The xprivate key is not root xprivate key.") _deserialize_xprivate_key = self._deserialize_xprivate_key(xprivate_key=xprivate_key) - self._depth, self._parent_fingerprint, self._index = (0, b"\0\0\0\0", 0) + self._root_depth, self._root_parent_fingerprint, self._root_index = ( + int.from_bytes(_deserialize_xprivate_key[1], "big"), + _deserialize_xprivate_key[2], + struct.unpack(">L", _deserialize_xprivate_key[3])[0] + ) + self._depth, self._parent_fingerprint, self._index = ( + int.from_bytes(_deserialize_xprivate_key[1], "big"), + _deserialize_xprivate_key[2], + struct.unpack(">L", _deserialize_xprivate_key[3])[0] + ) self._i = _deserialize_xprivate_key[5] + _deserialize_xprivate_key[4] self._root_private_key = (_deserialize_xprivate_key[5], _deserialize_xprivate_key[4]) self._private_key, self._chain_code = self._i[:32], self._i[32:] @@ -251,15 +295,20 @@ def from_root_xprivate_key(self, xprivate_key: str, strict: bool = True) -> "HDW if self._from_class: self.from_path(path=self._path_class) self._public_key = self.compressed() + self._semantic = get_semantic( + _cryptocurrency=self._cryptocurrency, + version=_deserialize_xprivate_key[0], + key_type="private_key" + ) return self - def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWallet": + def from_xpublic_key(self, xpublic_key: str, strict: bool = False) -> "HDWallet": """ - Master from Root XPublic Key. + Master from XPublic Key. - :param xpublic_key: Root xpublic key. + :param xpublic_key: Root or Non-Root XPublic key. :type xpublic_key: str - :param strict: Strict for must be root xpublic key, default to ``True``. + :param strict: Strict for must be root xpublic key, default to ``False``. :type strict: bool :returns: HDWallet -- Hierarchical Deterministic Wallet instance. @@ -267,7 +316,7 @@ def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWal >>> from hdwallet import HDWallet >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_root_xpublic_key(xpublic_key="xpub661MyMwAqRbcGSTjb2Mp3Sb4STUDhD2x986ubXKjQa2QsFTCVqzdA98qeZjcncHT1AaZcMSjiP1HJ16jH97q72RwyFfiNhmG8zQ6KBB5PaQ") + >>> hdwallet.from_xpublic_key(xpublic_key="xpub661MyMwAqRbcGSTjb2Mp3Sb4STUDhD2x986ubXKjQa2QsFTCVqzdA98qeZjcncHT1AaZcMSjiP1HJ16jH97q72RwyFfiNhmG8zQ6KBB5PaQ") """ @@ -276,7 +325,16 @@ def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWal raise ValueError("Invalid root xpublic key.") _deserialize_xpublic_key = self._deserialize_xpublic_key(xpublic_key=xpublic_key) - self._depth, self._parent_fingerprint, self._index = (0, b"\0\0\0\0", 0) + self._root_depth, self._root_parent_fingerprint, self._root_index = ( + int.from_bytes(_deserialize_xpublic_key[1], "big"), + _deserialize_xpublic_key[2], + struct.unpack(">L", _deserialize_xpublic_key[3])[0] + ) + self._depth, self._parent_fingerprint, self._index = ( + int.from_bytes(_deserialize_xpublic_key[1], "big"), + _deserialize_xpublic_key[2], + struct.unpack(">L", _deserialize_xpublic_key[3])[0] + ) self._chain_code = _deserialize_xpublic_key[4] self._verified_key = ecdsa.VerifyingKey.from_string( _deserialize_xpublic_key[5], curve=SECP256k1 @@ -287,65 +345,13 @@ def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWal if self._use_default_path: self.from_path(path=self._cryptocurrency.DEFAULT_PATH) if self._from_class: - self.from_path(path=self._path_class) + self.from_path(path=str(self._path_class).replace("'", "")) self._public_key = self.compressed() - return self - - def from_xprivate_key(self, xprivate_key: str) -> "HDWallet": - """ - Master from XPrivate Key. - - :param xprivate_key: XPrivate key. - :type xprivate_key: str - - :returns: HDWallet -- Hierarchical Deterministic Wallet instance. - - >>> from hdwallet import HDWallet - >>> from hdwallet.symbols import BTC - >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_xprivate_key(xprivate_key="xprvA3BYGWQ9FmhyaNRRXB2f1LphNPnaY9T6gngw4BaTbkFtscSH4RCuJhgWUSKs9S6ciGioHd4TX4UeyUg53MkfN9Xh38xkS1j2Wb9YKsYpJHQ") - - """ - - _deserialize_xprivate_key = self._deserialize_xprivate_key(xprivate_key=xprivate_key) - self._depth, self._parent_fingerprint, self._index = ( - int.from_bytes(_deserialize_xprivate_key[1], "big"), - _deserialize_xprivate_key[2], - struct.unpack(">L", _deserialize_xprivate_key[3])[0] + self._semantic = get_semantic( + _cryptocurrency=self._cryptocurrency, + version=_deserialize_xpublic_key[0], + key_type="public_key" ) - self._private_key, self._chain_code = _deserialize_xprivate_key[5], _deserialize_xprivate_key[4] - self._key = ecdsa.SigningKey.from_string(_deserialize_xprivate_key[5], curve=SECP256k1) - self._verified_key = self._key.get_verifying_key() - self._public_key = self.compressed() - return self - - def from_xpublic_key(self, xpublic_key: str) -> "HDWallet": - """ - Master from XPublic Key. - - :param xpublic_key: XPublic key. - :type xpublic_key: str - - :returns: HDWallet -- Hierarchical Deterministic Wallet instance. - - >>> from hdwallet import HDWallet - >>> from hdwallet.symbols import BTC - >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_xpublic_key(xprivate_key="xpub661MyMwAqRbcGSTjb2Mp3Sb4STUDhD2x986ubXKjQa2QsFTCVqzdA98qeZjcncHT1AaZcMSjiP1HJ16jH97q72RwyFfiNhmG8zQ6KBB5PaQ") - - """ - - _deserialize_xpublic_key = self._deserialize_xpublic_key(xpublic_key=xpublic_key) - self._depth, self._parent_fingerprint, self._index = ( - int.from_bytes(_deserialize_xpublic_key[1], "big"), - _deserialize_xpublic_key[2], - struct.unpack(">L", _deserialize_xpublic_key[3])[0] - ) - self._chain_code = _deserialize_xpublic_key[4] - self._verified_key = ecdsa.VerifyingKey.from_string( - _deserialize_xpublic_key[5], curve=SECP256k1 - ) - self._public_key = self.compressed() return self def from_wif(self, wif: str) -> "HDWallet": @@ -430,15 +436,15 @@ def from_path(self, path: Union[str, Derivation]) -> "HDWallet": >>> from hdwallet import HDWallet >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_root_xprivate_key(root_xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") """ if isinstance(path, Derivation): path = str(path) elif str(path)[0:2] != "m/": - raise ValueError("Bad path, please insert like this type of path \"m/0'/0\"! ") + raise ValueError("Bad path, please insert like this type of path \"m/0'/0\"!, not: %r" % ( path )) for index in path.lstrip("m/").split("/"): if "'" in index: @@ -463,7 +469,7 @@ def from_index(self, index: int, hardened: bool = False) -> "HDWallet": >>> from hdwallet import HDWallet >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_root_xprivate_key(root_xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") + >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") >>> hdwallet.from_index(index=44, hardened=True) >>> hdwallet.from_index(index=0, hardened=True) >>> hdwallet.from_index(index=0, hardened=True) @@ -477,7 +483,7 @@ def from_index(self, index: int, hardened: bool = False) -> "HDWallet": if hardened: self._path += ("/%d'" % index) - self._derive_key_by_index(index + BIP32KEY_HARDEN) + return self._derive_key_by_index(index + BIP32KEY_HARDEN) else: self._path += ("/%d" % index) return self._derive_key_by_index(index) @@ -485,18 +491,18 @@ def from_index(self, index: int, hardened: bool = False) -> "HDWallet": def _derive_key_by_index(self, index) -> Optional["HDWallet"]: if not self._root_private_key and not self._root_public_key: - raise PermissionError("You can't drive this master key.") + raise ValueError("You can't drive this master key.") i_str = struct.pack(">L", index) if index & BIP32KEY_HARDEN: if self._key is None: - raise DerivationError("Hardened derivation path is invalid with root xpublic key") + raise DerivationError("Hardened derivation path is invalid for xpublic key.") data = b"\0" + self._key.to_string() + i_str else: data = unhexlify(self.public_key()) + i_str if not self._chain_code: - raise PermissionError("You can't drive xprivate_key and private_key.") + raise ValueError("You can't drive xprivate_key and private_key.") i = hmac.new(self._chain_code, data, hashlib.sha512).digest() il, ir = i[:32], i[32:] @@ -561,6 +567,24 @@ def _serialize_xkeys(version: bytes, depth: bytes, parent_fingerprint: bytes, in except TypeError: return None + def raw_sign(self, data, deterministic=True): + # sig_key = SigningKey.from_string(self._private_key, curve=SECP256k1) + sig_func = partial(self._key.sign_digest_deterministic, hashfunc=sha256) if deterministic else self._key.sign_digest + r, s, order = sig_func(data, sigencode=lambda *x: x) + if s < 0x01: + raise ValueError('Too low s value for signature: {}'.format(s)) + # ref: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures + if s > highest_s: + s = order - s + if s.to_bytes(32, 'big')[0] > 0x7f: + s = int.from_bytes(b'\x00' + s.to_bytes(32, 'big'), 'big') + if r.to_bytes(32, 'big')[0] > 0x7f: + r = int.from_bytes(b'\x00' + r.to_bytes(32, 'big'), 'big') + return r, s, order + + def sign(self, data, deterministic=True): + return sigencode_der(*self.raw_sign(data, deterministic)) + def root_xprivate_key(self, encoded: bool = True) -> Optional[str]: """ Get Root XPrivate Key. @@ -574,22 +598,26 @@ def root_xprivate_key(self, encoded: bool = True) -> Optional[str]: >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_entropy(entropy="ee535b143b0d9d1f87546f9df0d06b1a") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") >>> hdwallet.root_xprivate_key() "xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF" """ + if self._semantic is None: + return None version = self._cryptocurrency.EXTENDED_PRIVATE_KEY.__getattribute__( self._semantic.upper() ) if version is None: - raise NotImplementedError(self) + raise NotImplementedError( + f"{self.__class__.__name__} is not implemented for {self._cryptocurrency.NAME} {self._cryptocurrency.NETWORK} cryptocurrency." + ) if not self._i: return None secret_key, chain_code = self._i[:32], self._i[32:] - depth = bytes(bytearray([0])) - parent_fingerprint = b"\0\0\0\0" - index = struct.pack(">L", 0) + depth = bytes(bytearray([self._root_depth])) + parent_fingerprint = self._root_parent_fingerprint + index = struct.pack(">L", self._root_index) data = b"\x00" + secret_key return self._serialize_xkeys( _unhexlify(version), depth, parent_fingerprint, index, chain_code, data, encoded @@ -608,16 +636,20 @@ def root_xpublic_key(self, encoded: bool = True) -> Optional[str]: >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_entropy(entropy="ee535b143b0d9d1f87546f9df0d06b1a") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") >>> hdwallet.root_xpublic_key() "xpub661MyMwAqRbcGSTjb2Mp3Sb4STUDhD2x986ubXKjQa2QsFTCVqzdA98qeZjcncHT1AaZcMSjiP1HJ16jH97q72RwyFfiNhmG8zQ6KBB5PaQ" """ + if self._semantic is None: + return None version = self._cryptocurrency.EXTENDED_PUBLIC_KEY.__getattribute__( self._semantic.upper() ) if version is None: - raise NotImplementedError(self) + raise NotImplementedError( + f"{self.__class__.__name__} is not implemented for {self._cryptocurrency.NAME} {self._cryptocurrency.NETWORK} cryptocurrency." + ) if self._root_public_key: data, chain_code = ( self._root_public_key[0], self._root_public_key[1] @@ -627,9 +659,9 @@ def root_xpublic_key(self, encoded: bool = True) -> Optional[str]: else: secret_key, chain_code = self._i[:32], self._i[32:] data = unhexlify(self.public_key(private_key=secret_key.hex())) - depth = bytes(bytearray([0])) - parent_fingerprint = b"\0\0\0\0" - index = struct.pack(">L", 0) + depth = bytes(bytearray([self._root_depth])) + parent_fingerprint = self._root_parent_fingerprint + index = struct.pack(">L", self._root_index) return self._serialize_xkeys( _unhexlify(version), depth, parent_fingerprint, index, chain_code, data, encoded ) @@ -647,16 +679,20 @@ def xprivate_key(self, encoded=True) -> Optional[str]: >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_entropy(entropy="ee535b143b0d9d1f87546f9df0d06b1a") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") >>> hdwallet.xprivate_key() "xprvA3BYGWQ9FmhyaNRRXB2f1LphNPnaY9T6gngw4BaTbkFtscSH4RCuJhgWUSKs9S6ciGioHd4TX4UeyUg53MkfN9Xh38xkS1j2Wb9YKsYpJHQ" """ + if self._semantic is None: + return None version = self._cryptocurrency.EXTENDED_PRIVATE_KEY.__getattribute__( self._semantic.upper() ) if version is None: - raise NotImplementedError(self) + raise NotImplementedError( + f"{self.__class__.__name__} is not implemented for {self._cryptocurrency.NAME} {self._cryptocurrency.NETWORK} cryptocurrency." + ) depth = bytes(bytearray([self._depth])) parent_fingerprint = self._parent_fingerprint index = struct.pack(">L", self._index) @@ -681,16 +717,20 @@ def xpublic_key(self, encoded: bool = True) -> Optional[str]: >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_entropy(entropy="ee535b143b0d9d1f87546f9df0d06b1a") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") >>> hdwallet.xpublic_key() "xpub6GAtg1w369GGnrVtdCZfNUmRvRd4wcAx41cXrZz5A5nskQmRbxX9rVzzKiRU4JruirBrfm4KQXNSU7GfqL1tzZWpZYe9Zo4xKGJYohWoQe7" """ + if self._semantic is None: + return None version = self._cryptocurrency.EXTENDED_PUBLIC_KEY.__getattribute__( self._semantic.upper() ) if version is None: - raise NotImplementedError(self) + raise NotImplementedError( + f"{self.__class__.__name__} is not implemented for {self._cryptocurrency.NAME} {self._cryptocurrency.NETWORK} cryptocurrency." + ) depth = bytes(bytearray([self._depth])) parent_fingerprint = self._parent_fingerprint index = struct.pack(">L", self._index) @@ -709,23 +749,31 @@ def clean_derivation(self) -> "HDWallet": >>> from hdwallet import HDWallet >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) - >>> hdwallet.from_root_xprivate_key(root_xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") >>> hdwallet.path() - "m/44'/0'/'0/0/0" + "m/44'/0'/0'/0/0" >>> hdwallet.clean_derivation() >>> hdwallet.path() None """ - if self._i: - self._path, self._depth, self._parent_fingerprint, self._index = ( - "m", 0, b"\0\0\0\0", 0 + if self._root_private_key: + self._path, self._path_class, self._depth, self._parent_fingerprint, self._index = ( + "m", "m", 0, b"\0\0\0\0", 0 ) - self._private_key, self._chain_code = self._i[:32], self._i[32:] + self._private_key, self._chain_code = self._root_private_key self._key = ecdsa.SigningKey.from_string(self._private_key, curve=SECP256k1) self._verified_key = self._key.get_verifying_key() + elif self._root_public_key: + self._path, self._path_class, self._depth, self._parent_fingerprint, self._index = ( + "m", "m", 0, b"\0\0\0\0", 0 + ) + self._chain_code = self._root_public_key[1] + self._verified_key = ecdsa.VerifyingKey.from_string( + self._root_public_key[0], curve=SECP256k1 + ) return self def uncompressed(self, compressed: Optional[str] = None) -> str: @@ -1045,9 +1093,9 @@ def hash(self, private_key: str = None): "4d887566d408dfe5ea8090f2b716f9639523ca89" """ - return hashlib.new("ripemd160", sha256(unhexlify(self.public_key( + return hexlify(ripemd160(sha256(unhexlify(self.public_key( private_key=private_key if private_key else self.private_key() - ))).digest()).hexdigest() + ))).digest())).decode("utf-8") def finger_print(self) -> str: """ @@ -1082,20 +1130,30 @@ def p2pkh_address(self) -> str: """ if self._cryptocurrency.SYMBOL in ["ETH", "ETHTEST"]: - keccak_256 = sha3.keccak_256() - # keccak_256.update(unhexlify(self.compressed())) + keccak_256 = keccak.new(digest_bits=256) keccak_256.update(unhexlify(self.uncompressed())) address = keccak_256.hexdigest()[24:] return checksum_encode(address, crypto="eth") elif self._cryptocurrency.SYMBOL in ["XDC", "XDCTEST"]: - keccak_256 = sha3.keccak_256() - # keccak_256.update(unhexlify(self.compressed())) + keccak_256 = keccak.new(digest_bits=256) keccak_256.update(unhexlify(self.uncompressed())) address = keccak_256.hexdigest()[24:] return checksum_encode(address, crypto="xdc") + elif self._cryptocurrency.SYMBOL in ["TRX"]: + keccak_256 = keccak.new(digest_bits=256) + keccak_256.update(unhexlify(self.uncompressed())) + address = keccak_256.hexdigest()[24:] + network_hash160_bytes = _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + bytearray.fromhex(address) + return ensure_string(base58.b58encode_check(network_hash160_bytes)) + elif self._cryptocurrency.SYMBOL in ["XRP"]: + XRPL_ALPHABET = b"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz" + compressed_public_key = unhexlify(self.compressed()) + public_key_hash = hashlib.new("ripemd160", sha256(compressed_public_key).digest()).digest() + network_hash160_bytes = _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + public_key_hash + return ensure_string(base58.b58encode_check(network_hash160_bytes, alphabet=XRPL_ALPHABET)) compressed_public_key = unhexlify(self.compressed()) - public_key_hash = hashlib.new('ripemd160', sha256(compressed_public_key).digest()).digest() + public_key_hash = ripemd160(sha256(compressed_public_key).digest()) network_hash160_bytes = _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + public_key_hash return ensure_string(base58.b58encode_check(network_hash160_bytes)) @@ -1115,9 +1173,9 @@ def p2sh_address(self) -> str: """ compressed_public_key = unhexlify(self.compressed()) - public_key_hash = hashlib.new('ripemd160', sha256(compressed_public_key).digest()).hexdigest() + public_key_hash = hexlify(ripemd160(sha256(compressed_public_key).digest())).decode("utf-8") public_key_hash_script = unhexlify("76a914" + public_key_hash + "88ac") - script_hash = hashlib.new('ripemd160', sha256(public_key_hash_script).digest()).digest() + script_hash = ripemd160(sha256(public_key_hash_script).digest()) network_hash160_bytes = _unhexlify(self._cryptocurrency.SCRIPT_ADDRESS) + script_hash return ensure_string(base58.b58encode_check(network_hash160_bytes)) @@ -1137,10 +1195,11 @@ def p2wpkh_address(self) -> Optional[str]: """ compressed_public_key = unhexlify(self.compressed()) - public_key_hash = hashlib.new('ripemd160', sha256(compressed_public_key).digest()).digest() - if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: + public_key_hash = ripemd160(sha256(compressed_public_key).digest()) + segwit = self._cryptocurrency.SEGWIT_ADDRESS + if segwit.HRP is None: return None - return ensure_string(encode(self._cryptocurrency.SEGWIT_ADDRESS.HRP, 0, public_key_hash)) + return ensure_string(encode(segwit.HRP, segwit.VERSION, public_key_hash)) def p2wpkh_in_p2sh_address(self) -> Optional[str]: """ @@ -1158,8 +1217,8 @@ def p2wpkh_in_p2sh_address(self) -> Optional[str]: """ compressed_public_key = unhexlify(self.compressed()) - public_key_hash = hashlib.new('ripemd160', sha256(compressed_public_key).digest()).hexdigest() - script_hash = hashlib.new('ripemd160', sha256(unhexlify("0014" + public_key_hash)).digest()).digest() + public_key_hash = hexlify(ripemd160(sha256(compressed_public_key).digest())).decode("utf-8") + script_hash = ripemd160(sha256(unhexlify("0014" + public_key_hash)).digest()) network_hash160_bytes = _unhexlify(self._cryptocurrency.SCRIPT_ADDRESS) + script_hash if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: return None @@ -1182,9 +1241,10 @@ def p2wsh_address(self) -> Optional[str]: compressed_public_key = unhexlify("5121" + self.compressed() + "51ae") script_hash = sha256(compressed_public_key).digest() - if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: + segwit = self._cryptocurrency.SEGWIT_ADDRESS + if segwit.HRP is None: return None - return ensure_string(encode(self._cryptocurrency.SEGWIT_ADDRESS.HRP, 0, script_hash)) + return ensure_string(encode(segwit.HRP, segwit.VERSION, script_hash)) def p2wsh_in_p2sh_address(self) -> Optional[str]: """ @@ -1203,7 +1263,7 @@ def p2wsh_in_p2sh_address(self) -> Optional[str]: compressed_public_key = unhexlify("5121" + self.compressed() + "51ae") script_hash = unhexlify("0020" + sha256(compressed_public_key).hexdigest()) - script_hash = hashlib.new('ripemd160', sha256(script_hash).digest()).digest() + script_hash = ripemd160(sha256(script_hash).digest()) network_hash160_bytes = _unhexlify(self._cryptocurrency.SCRIPT_ADDRESS) + script_hash if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: return None diff --git a/hdwallet/libs/base58.py b/hdwallet/libs/base58.py index 98f0a39..cc94f13 100644 --- a/hdwallet/libs/base58.py +++ b/hdwallet/libs/base58.py @@ -2,7 +2,7 @@ from hashlib import sha256 -import sha3 +from Crypto.Hash import keccak import six @@ -13,10 +13,10 @@ def checksum_encode(address, crypto="eth"): out = "" - keccak = sha3.keccak_256() + keccak_256 = keccak.new(digest_bits=256) addr = address.lower().replace("0x", "") if crypto == "eth" else address.lower().replace("xdc", "") - keccak.update(addr.encode("ascii")) - hash_addr = keccak.hexdigest() + keccak_256.update(addr.encode("ascii")) + hash_addr = keccak_256.hexdigest() for i, c in enumerate(addr): if int(hash_addr[i], 16) >= 8: out += c.upper() @@ -67,15 +67,18 @@ def decode(data): data = bytes(data, "ascii") val = 0 - for (i, c) in enumerate(data[::-1]): - val += __base58_alphabet_bytes.find(c) * (__base58_radix ** i) + prefix = 0 + for c in data: + val = (val * __base58_radix) + __base58_alphabet_bytes.find(c) + if val == 0: + prefix += 1 dec = bytearray() - while val >= 256: + while val > 0: val, mod = divmod(val, 256) dec.append(mod) - if val: - dec.append(val) + + dec.extend(bytearray(prefix)) return bytes(dec[::-1]) diff --git a/hdwallet/libs/ripemd160.py b/hdwallet/libs/ripemd160.py new file mode 100644 index 0000000..496ed6a --- /dev/null +++ b/hdwallet/libs/ripemd160.py @@ -0,0 +1,141 @@ +# Copyright (c) 2021 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# source: https://github.com/richardkiss/pycoin/blob/main/pycoin/contrib/ripemd160.py +# Grudgingly ported to python2 compatibility by Richard Kiss + +import binascii +import struct +import unittest + + +if struct.calcsize("> (32 - i))) & 0xffffffff + + +def compress(h0, h1, h2, h3, h4, block): + """Compress state (h0, h1, h2, h3, h4) with block.""" + # Left path variables. + al, bl, cl, dl, el = h0, h1, h2, h3, h4 + # Right path variables. + ar, br, cr, dr, er = h0, h1, h2, h3, h4 + # Message variables. + x = [struct.unpack("> 4 + # Perform left side of the transformation. + al = rol(al + fi(bl, cl, dl, rnd) + x[ML[j]] + KL[rnd], RL[j]) + el + al, bl, cl, dl, el = el, al, bl, rol(cl, 10), dl + # Perform right side of the transformation. + ar = rol(ar + fi(br, cr, dr, 4 - rnd) + x[MR[j]] + KR[rnd], RR[j]) + er + ar, br, cr, dr, er = er, ar, br, rol(cr, 10), dr + + # Compose old state, left transform, and right transform into new state. + return h1 + cl + dr, h2 + dl + er, h3 + el + ar, h4 + al + br, h0 + bl + cr + + +def ripemd160(data): + """Compute the RIPEMD-160 hash of data.""" + # Initialize state. + state = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0) + # Process full 64-byte blocks in the input. + for b in range(len(data) >> 6): + args = list(state) + [data[64*b:64*(b+1)]] + state = compress(*args) + # Construct final blocks (with padding and size). + pad = b"\x80" + b"\x00" * ((119 - len(data)) & 63) + fin = data[len(data) & ~63:] + pad + struct.pack("> 6): + args = list(state) + [fin[64*b:64*(b+1)]] + state = compress(*args) + # Produce output. + return b"".join(struct.pack(" str: + for name, cryptocurrency in inspect.getmembers(cryptocurrencies): + if inspect.isclass(cryptocurrency): + if issubclass(cryptocurrency, cryptocurrencies.Cryptocurrency) and cryptocurrency == _cryptocurrency: + if key_type == "private_key": + for key, value in inspect.getmembers(cryptocurrency.EXTENDED_PRIVATE_KEY): + if value == int(version.hex(), 16): + return key.lower() + elif key_type == "public_key": + for key, value in inspect.getmembers(cryptocurrency.EXTENDED_PUBLIC_KEY): + if value == int(version.hex(), 16): + return key.lower() + + def get_bytes(string: AnyStr) -> bytes: if isinstance(string, bytes): byte = string @@ -119,7 +136,10 @@ def is_entropy(entropy: str) -> bool: True """ - return len(unhexlify(entropy)) in [16, 20, 24, 28, 32] + try: + return len(unhexlify(entropy)) in [16, 20, 24, 28, 32] + except: + return False def is_mnemonic(mnemonic: str, language: Optional[str] = None) -> bool: @@ -298,39 +318,31 @@ def mnemonic_to_entropy(mnemonic: str, language: Optional[str] = None) -> str: return Mnemonic(language=language).to_entropy(mnemonic).hex() -def is_root_xprivate_key(xprivate_key: str, symbol: str, semantic: str = "p2pkh") -> bool: - if semantic not in ["p2pkh", "p2sh", "p2wpkh", "p2wpkh_in_p2sh", "p2wsh", "p2wsh_in_p2sh"]: - raise SemanticError( - "Wrong extended semantic", - "choose only the following options 'p2pkh', 'p2sh', 'p2wpkh', 'p2wpkh_in_p2sh', 'p2wsh' or 'p2wsh_in_p2sh' semantics." - ) - decoded_xprivate_key = check_decode(xprivate_key).hex() - if len(decoded_xprivate_key) != 156: # 78 +def is_root_xprivate_key(xprivate_key: str, symbol: str) -> bool: + decoded_xprivate_key = check_decode(xprivate_key) + if len(decoded_xprivate_key) != 78: # 78, 156 raise ValueError("Invalid xprivate key.") cryptocurrency = get_cryptocurrency(symbol=symbol) + semantic = get_semantic(_cryptocurrency=cryptocurrency, version=decoded_xprivate_key[:4], key_type="private_key") version = cryptocurrency.EXTENDED_PRIVATE_KEY.__getattribute__( semantic.upper() ) if version is None: raise NotImplementedError(semantic) raw = f"{_unhexlify(version).hex()}000000000000000000" - return decoded_xprivate_key.startswith(raw) + return decoded_xprivate_key.hex().startswith(raw) -def is_root_xpublic_key(xpublic_key: str, symbol: str, semantic: str = "p2pkh") -> bool: - if semantic not in ["p2pkh", "p2sh", "p2wpkh", "p2wpkh_in_p2sh", "p2wsh", "p2wsh_in_p2sh"]: - raise SemanticError( - "Wrong extended semantic", - "choose only the following options 'p2pkh', 'p2sh', 'p2wpkh', 'p2wpkh_in_p2sh', 'p2wsh' or 'p2wsh_in_p2sh' semantics." - ) - decoded_xpublic_key = check_decode(xpublic_key).hex() - if len(decoded_xpublic_key) != 156: # 78 +def is_root_xpublic_key(xpublic_key: str, symbol: str) -> bool: + decoded_xpublic_key = check_decode(xpublic_key) + if len(decoded_xpublic_key) != 78: # 78, 156 raise ValueError("Invalid xpublic key.") cryptocurrency = get_cryptocurrency(symbol=symbol) + semantic = get_semantic(_cryptocurrency=cryptocurrency, version=decoded_xpublic_key[:4], key_type="public_key") version = cryptocurrency.EXTENDED_PUBLIC_KEY.__getattribute__( semantic.upper() ) if version is None: raise NotImplementedError(semantic) raw = f"{_unhexlify(version).hex()}000000000000000000" - return decoded_xpublic_key.startswith(raw) + return decoded_xpublic_key.hex().startswith(raw) diff --git a/hdwallet/version.py b/hdwallet/version.py new file mode 100644 index 0000000..f934d45 --- /dev/null +++ b/hdwallet/version.py @@ -0,0 +1,2 @@ +__version_info__ = ( 2, 3, 0 ) +__version__ = 'v' + '.'.join( map( str, __version_info__ )) diff --git a/nixpkgs.nix b/nixpkgs.nix new file mode 100644 index 0000000..7880ec3 --- /dev/null +++ b/nixpkgs.nix @@ -0,0 +1,4 @@ +import (fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/refs/tags/23.11.tar.gz"; + sha256 = "1ndiv385w1qyb3b18vw13991fzb9wg4cl21wglk89grsfsnra41k"; +}) diff --git a/requirements-cli.txt b/requirements-cli.txt new file mode 100644 index 0000000..a6a7221 --- /dev/null +++ b/requirements-cli.txt @@ -0,0 +1,3 @@ +click >=8.1.3,<9 +click-aliases >=1.0.1,<2 +tabulate >=0.9.0,<1 diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..bc210ec --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,4 @@ +build +packaging +setuptools +wheel diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 0000000..c77b246 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,3 @@ +sphinx >=5.3.0,<6 +furo ==2022.12.7 +sphinx-click >=4.4.0,<5 diff --git a/requirements-tests.txt b/requirements-tests.txt new file mode 100644 index 0000000..7f50a1f --- /dev/null +++ b/requirements-tests.txt @@ -0,0 +1,3 @@ +pytest >=7.2.0,<8 +pytest-cov >=4.0.0,<5 +tox ==3.28.0 diff --git a/requirements.txt b/requirements.txt index 477b76d..ad55168 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ecdsa>=0.13,<1 -mnemonic>=0.19,<1 -pysha3>=1.0.2,<2 -base58>=2.0.1,<3 \ No newline at end of file +ecdsa >=0.19.0,<1 +mnemonic >=0.21,<1 +pycryptodome >=3.21,<4 +base58 >=2.1.1,<3 diff --git a/setup.py b/setup.py index 6219079..9912180 100644 --- a/setup.py +++ b/setup.py @@ -4,46 +4,63 @@ setup, find_packages ) +# Project URLs +project_urls = { + "Tracker": "https://github.com/meherett/python-hdwallet/issues", + "Documentation": "https://hdwallet.readthedocs.io" +} + # README.md -with open("README.md", "r", encoding="utf-8") as readme: +with open( "README.md", "r", encoding="utf-8") as readme: long_description: str = readme.read() - -# requirements.txt -with open("requirements.txt", "r") as _requirements: - requirements: list = list(map(str.strip, _requirements.read().split("\n"))) +with open( "requirements.txt" ) as r: + install_requires: list = list( r.readlines() ) +with open( "requirements-tests.txt" ) as rt: + tests_require: list = list( rt.readlines() ) +extras_require: dict = { + option: list( + # Remove whitespace, elide blank lines and comments + ''.join( r.split() ) + for r in open( f"requirements-{option}.txt" ).readlines() + if r.strip() and not r.strip().startswith( '#' ) + ) + for option in ('cli', 'tests', 'docs') +} +with open( "hdwallet/version.py" ) as vpy: + exec( vpy.read() ) setup( - name="hdwallet", - version="1.3.0", - description="Python-based library for the implementation of a " - "hierarchical deterministic wallet generator for more than 140+ multiple cryptocurrencies.", + name="hdwallet-slip39", + version=__version__, + description="Python-based library for the implementation of a hierarchical deterministic wallet " + "generator for more than 140+ multiple cryptocurrencies.", long_description=long_description, long_description_content_type="text/markdown", - license="ISCL", - author="Meheret Tesfaye", - author_email="meherett@zoho.com", - url="https://github.com/meherett/python-hdwallet", - keywords=["cryptography", "hd", "bip32", "bip44", "bip39", "wallet", "cryptocurrencies"], + license="MIT", + author="Meheret Tesfaye Batu", + author_email="meherett.batu@gmail.com", + url="https://github.com/pjkundert/python-hdwallet", + project_urls=project_urls, + keywords=[ + "cryptography", "cli", "wallet", "bip32", "bip44", "bip39", "hdwallet", "cryptocurrencies", "bitcoin", "ethereum" + ], + entry_points={ + "console_scripts": ["hdwallet=hdwallet.cli.__main__:main"] + }, python_requires=">=3.6,<4", packages=find_packages(), - install_requires=requirements, - extras_require={ - "tests": [ - "pytest>=6.2.2,<7", - "pytest-cov>=2.11.1,<3" - ], - "docs": [ - "sphinx>=3.5.1,<4", - "sphinx-rtd-theme>=0.5.1,<1" - ] - }, + install_requires=install_requires, + extras_require=extras_require, + tests_require=tests_require, classifiers=[ "Development Status :: 5 - Production/Stable", "License :: OSI Approved :: ISC License (ISCL)", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Libraries :: Python Modules" ] ) diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..aab28b3 --- /dev/null +++ b/shell.nix @@ -0,0 +1,19 @@ +{ pkgs ? import ./nixpkgs.nix {} }: + +let + targets = import ./default.nix { + inherit pkgs; + }; + targeted = builtins.getEnv "TARGET"; + selected = targeted + pkgs.lib.optionalString (targeted == "") "py312"; +in + +with pkgs; + +mkShell { + buildInputs = lib.getAttrFromPath [ selected "buildInputs" ] targets; + + shellHook = '' + echo "Welcome to the Python ${selected} environment!" + ''; +} diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..5f7ce86 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 \ No newline at end of file diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py new file mode 100644 index 0000000..5f7ce86 --- /dev/null +++ b/tests/cli/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 \ No newline at end of file diff --git a/tests/cli/generate/__init__.py b/tests/cli/generate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/cli/generate/test_addresses.py b/tests/cli/generate/test_addresses.py new file mode 100644 index 0000000..52bb3b1 --- /dev/null +++ b/tests/cli/generate/test_addresses.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +import json +import os + +from hdwallet.cli.__main__ import main as cli_main + +# Test Values +base_path = os.path.dirname(__file__) +file_path = os.path.abspath(os.path.join(base_path, "..", "..", "values.json")) +values = open(file_path, "r", encoding="utf-8") +_ = json.loads(values.read()) +values.close() + + +def test_addresses(cli_tester): + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", "addresses", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--entropy", _["bitcoin"]["mainnet"]["entropy"], + "--passphrase", _["bitcoin"]["mainnet"]["passphrase"], + "--language", _["bitcoin"]["mainnet"]["language"] + ] + ) + + dumps: dict = _["bitcoin"]["mainnet"] + + del dumps["root_xprivate_key_hex"] + del dumps["root_xpublic_key_hex"] + del dumps["xprivate_key_hex"] + del dumps["xpublic_key_hex"] + + addresses: str = "" + for address in _["bitcoin"]["addresses"]: + addresses += f"{address}\n" + + assert hdwallet.exit_code == 0 + assert hdwallet.output == addresses + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", "addresses", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--mnemonic", _["bitcoin"]["mainnet"]["mnemonic"], + "--passphrase", _["bitcoin"]["mainnet"]["passphrase"], + "--language", _["bitcoin"]["mainnet"]["language"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output == addresses + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", "addresses", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--seed", _["bitcoin"]["mainnet"]["seed"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output == addresses + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", "addresses", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--xprivate-key", _["bitcoin"]["mainnet"]["root_xprivate_key"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output == addresses + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", "addresses", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--xpublic-key", _["bitcoin"]["mainnet"]["root_xpublic_key"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output diff --git a/tests/cli/generate/test_hdwallet.py b/tests/cli/generate/test_hdwallet.py new file mode 100644 index 0000000..33ab587 --- /dev/null +++ b/tests/cli/generate/test_hdwallet.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +import json +import os + +from hdwallet.cli.__main__ import main as cli_main + +# Test Values +base_path = os.path.dirname(__file__) +file_path = os.path.abspath(os.path.join(base_path, "..", "..", "values.json")) +values = open(file_path, "r", encoding="utf-8") +_ = json.loads(values.read()) +values.close() + + +def test_hdwallet(cli_tester): + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--entropy", _["bitcoin"]["mainnet"]["entropy"], + "--passphrase", _["bitcoin"]["mainnet"]["passphrase"], + "--language", _["bitcoin"]["mainnet"]["language"] + ] + ) + + dumps: dict = _["bitcoin"]["mainnet"] + + del dumps["root_xprivate_key_hex"] + del dumps["root_xpublic_key_hex"] + del dumps["xprivate_key_hex"] + del dumps["xpublic_key_hex"] + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--mnemonic", _["bitcoin"]["mainnet"]["mnemonic"], + "--passphrase", _["bitcoin"]["mainnet"]["passphrase"], + "--language", _["bitcoin"]["mainnet"]["language"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--seed", _["bitcoin"]["mainnet"]["seed"] + ] + ) + + dumps["strength"] = None + dumps["entropy"] = None + dumps["mnemonic"] = None + dumps["language"] = None + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--xprivate-key", _["bitcoin"]["mainnet"]["root_xprivate_key"] + ] + ) + + dumps["strength"] = None + dumps["entropy"] = None + dumps["mnemonic"] = None + dumps["language"] = None + dumps["seed"] = None + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--xpublic-key", _["bitcoin"]["mainnet"]["root_xpublic_key"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--private-key", _["bitcoin"]["mainnet"]["private_key"] + ] + ) + + dumps["root_xprivate_key"] = None + dumps["root_xpublic_key"] = None + dumps["xprivate_key"] = None + dumps["xpublic_key"] = None + dumps["chain_code"] = None + dumps["path"] = None + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--wif", _["bitcoin"]["mainnet"]["wif"] + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" + + hdwallet = cli_tester.invoke( + cli_main, [ + "generate", + "--symbol", _["bitcoin"]["mainnet"]["symbol"], + "--public-key", _["bitcoin"]["mainnet"]["public_key"] + ] + ) + + dumps["private_key"] = None + dumps["wif"] = None + + assert hdwallet.exit_code == 0 + assert hdwallet.output == str(json.dumps(dumps, indent=4, ensure_ascii=False)) + "\n" diff --git a/tests/cli/list/__init__.py b/tests/cli/list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/cli/list/test_cryptocurrencies.py b/tests/cli/list/test_cryptocurrencies.py new file mode 100644 index 0000000..e8fc25f --- /dev/null +++ b/tests/cli/list/test_cryptocurrencies.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + + +from hdwallet.cli.__main__ import main as cli_main + + +def test_cryptocurrencies(cli_tester): + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "cryptocurrencies" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "cryptocurrencies" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "c" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "c" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output diff --git a/tests/cli/list/test_languages.py b/tests/cli/list/test_languages.py new file mode 100644 index 0000000..2c9537d --- /dev/null +++ b/tests/cli/list/test_languages.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + + +from hdwallet.cli.__main__ import main as cli_main + + +def test_languages(cli_tester): + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "languages" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "languages" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "l" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "l" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output diff --git a/tests/cli/list/test_strengths.py b/tests/cli/list/test_strengths.py new file mode 100644 index 0000000..d3419dd --- /dev/null +++ b/tests/cli/list/test_strengths.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + + +from hdwallet.cli.__main__ import main as cli_main + + +def test_strengths(cli_tester): + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "strengths" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "strengths" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "list", "s" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output + + hdwallet = cli_tester.invoke( + cli_main, [ + "l", "s" + ] + ) + + assert hdwallet.exit_code == 0 + assert hdwallet.output diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py new file mode 100644 index 0000000..adf54fb --- /dev/null +++ b/tests/cli/test_cli.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +from hdwallet.cli.__main__ import main as cli_main +from hdwallet import __version__ + + +def test_hdwallet_cli(cli_tester): + + assert cli_tester.invoke(cli_main).exit_code == 0 + + assert cli_tester.invoke(cli_main, ["generate"]).exit_code == 0 + + version = cli_tester.invoke(cli_main, ["--version"]) + assert version.exit_code == 0 + assert version.output == "%s\n" % __version__ diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..9c6c3d1 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,20 @@ +#!/usr/bin/python3 + +from pathlib import Path +from click.testing import CliRunner + +import os +import pytest + + +@pytest.fixture(scope="module") +def project_path(): + original_path = os.getcwd() + os.chdir(original_path + "/tests") + yield Path(original_path + "/tests") + os.chdir(original_path) + + +@pytest.fixture(scope="module") +def cli_tester(): + return CliRunner() diff --git a/tests/hdwallet/__init__.py b/tests/hdwallet/__init__.py new file mode 100644 index 0000000..5f7ce86 --- /dev/null +++ b/tests/hdwallet/__init__.py @@ -0,0 +1 @@ +#!/usr/bin/env python3 \ No newline at end of file diff --git a/tests/test_from_entropy.py b/tests/hdwallet/test_from_entropy.py similarity index 98% rename from tests/test_from_entropy.py rename to tests/hdwallet/test_from_entropy.py index fc50085..30a1020 100644 --- a/tests/test_from_entropy.py +++ b/tests/hdwallet/test_from_entropy.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() diff --git a/tests/test_from_mnemonic.py b/tests/hdwallet/test_from_mnemonic.py similarity index 97% rename from tests/test_from_mnemonic.py rename to tests/hdwallet/test_from_mnemonic.py index 3bfcafd..2bad1df 100644 --- a/tests/test_from_mnemonic.py +++ b/tests/hdwallet/test_from_mnemonic.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() diff --git a/tests/test_from_private_key.py b/tests/hdwallet/test_from_private_key.py similarity index 95% rename from tests/test_from_private_key.py rename to tests/hdwallet/test_from_private_key.py index fe3295d..4251a0e 100644 --- a/tests/test_from_private_key.py +++ b/tests/hdwallet/test_from_private_key.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() @@ -47,7 +47,7 @@ def test_from_private_key(): assert hdwallet.public_key() == _["bitcoin"]["mainnet"]["public_key"] assert hdwallet.wif() == _["bitcoin"]["mainnet"]["wif"] assert hdwallet.finger_print() == _["bitcoin"]["mainnet"]["finger_print"] - assert hdwallet.semantic() == _["bitcoin"]["mainnet"]["semantic"] + assert hdwallet.semantic() is None assert hdwallet.path() == None assert hdwallet.hash() == _["bitcoin"]["mainnet"]["hash"] assert hdwallet.p2pkh_address() == _["bitcoin"]["mainnet"]["addresses"]["p2pkh"] @@ -71,6 +71,7 @@ def test_from_private_key(): dumps["root_xpublic_key"] = None dumps["xprivate_key"] = None dumps["xpublic_key"] = None + dumps["semantic"] = None dumps["chain_code"] = None dumps["path"] = None del dumps["root_xprivate_key_hex"] diff --git a/tests/test_from_public_key.py b/tests/hdwallet/test_from_public_key.py similarity index 96% rename from tests/test_from_public_key.py rename to tests/hdwallet/test_from_public_key.py index 3c75696..214857f 100644 --- a/tests/test_from_public_key.py +++ b/tests/hdwallet/test_from_public_key.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() @@ -50,7 +50,7 @@ def test_from_public_key(): assert hdwallet.public_key(compressed=False, private_key=_["bitcoin"]["testnet"]["private_key"]) == _["bitcoin"]["testnet"]["uncompressed"] assert hdwallet.wif() is None assert hdwallet.finger_print() == _["bitcoin"]["testnet"]["finger_print"] - assert hdwallet.semantic() == _["bitcoin"]["testnet"]["semantic"] + assert hdwallet.semantic() is None assert hdwallet.path() == None assert hdwallet.hash() == _["bitcoin"]["testnet"]["hash"] assert hdwallet.p2pkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2pkh"] @@ -74,6 +74,7 @@ def test_from_public_key(): dumps["root_xpublic_key"] = None dumps["xprivate_key"] = None dumps["xpublic_key"] = None + dumps["semantic"] = None dumps["chain_code"] = None dumps["private_key"] = None dumps["wif"] = None diff --git a/tests/test_from_seed.py b/tests/hdwallet/test_from_seed.py similarity index 97% rename from tests/test_from_seed.py rename to tests/hdwallet/test_from_seed.py index a85a76e..3eeeb10 100644 --- a/tests/test_from_seed.py +++ b/tests/hdwallet/test_from_seed.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() diff --git a/tests/test_from_wif.py b/tests/hdwallet/test_from_wif.py similarity index 95% rename from tests/test_from_wif.py rename to tests/hdwallet/test_from_wif.py index e4d666c..8a4d3a0 100644 --- a/tests/test_from_wif.py +++ b/tests/hdwallet/test_from_wif.py @@ -7,7 +7,7 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() @@ -47,7 +47,7 @@ def test_from_wallet_important_format(): assert hdwallet.public_key() == _["bitcoin"]["mainnet"]["public_key"] assert hdwallet.wif() == _["bitcoin"]["mainnet"]["wif"] assert hdwallet.finger_print() == _["bitcoin"]["mainnet"]["finger_print"] - assert hdwallet.semantic() == _["bitcoin"]["mainnet"]["semantic"] + assert hdwallet.semantic() is None assert hdwallet.path() == None assert hdwallet.hash() == _["bitcoin"]["mainnet"]["hash"] assert hdwallet.p2pkh_address() == _["bitcoin"]["mainnet"]["addresses"]["p2pkh"] @@ -71,6 +71,7 @@ def test_from_wallet_important_format(): dumps["root_xpublic_key"] = None dumps["xprivate_key"] = None dumps["xpublic_key"] = None + dumps["semantic"] = None dumps["chain_code"] = None dumps["path"] = None del dumps["root_xprivate_key_hex"] diff --git a/tests/test_from_root_xprivate_key.py b/tests/hdwallet/test_from_xprivate_key.py similarity index 50% rename from tests/test_from_root_xprivate_key.py rename to tests/hdwallet/test_from_xprivate_key.py index 043a051..17a4b68 100644 --- a/tests/test_from_root_xprivate_key.py +++ b/tests/hdwallet/test_from_xprivate_key.py @@ -7,18 +7,18 @@ # Test Values base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) values = open(file_path, "r", encoding="utf-8") _: dict = json.loads(values.read()) values.close() -def test_from_root_xprivate_key(): +def test_from_xprivate_key(): hdwallet: HDWallet = HDWallet( symbol=_["bitcoin"]["mainnet"]["symbol"] ) - hdwallet.from_root_xprivate_key( + hdwallet.from_xprivate_key( xprivate_key=_["bitcoin"]["mainnet"]["root_xprivate_key"], strict=True ) hdwallet.from_path( @@ -75,3 +75,65 @@ def test_from_root_xprivate_key(): del dumps["xpublic_key_hex"] assert hdwallet.dumps() == dumps + + hdwallet: HDWallet = HDWallet( + symbol=_["bitcoin"]["testnet"]["symbol"] + ) + + hdwallet.from_xprivate_key( + xprivate_key=_["bitcoin"]["testnet"]["xprivate_key"], strict=False + ) + + assert hdwallet.cryptocurrency() == _["bitcoin"]["testnet"]["cryptocurrency"] + assert hdwallet.symbol() == _["bitcoin"]["testnet"]["symbol"] + assert hdwallet.network() == _["bitcoin"]["testnet"]["network"] + assert hdwallet.strength() is None + assert hdwallet.entropy() is None + assert hdwallet.mnemonic() is None + assert hdwallet.language() is None + assert hdwallet.passphrase() is None + assert hdwallet.seed() is None + assert hdwallet.root_xprivate_key(encoded=False) == _["bitcoin"]["testnet"]["xprivate_key_hex"] + assert hdwallet.root_xprivate_key() == _["bitcoin"]["testnet"]["xprivate_key"] + assert hdwallet.root_xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] + assert hdwallet.root_xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] + assert hdwallet.xprivate_key(encoded=False) == _["bitcoin"]["testnet"]["xprivate_key_hex"] + assert hdwallet.xprivate_key() == _["bitcoin"]["testnet"]["xprivate_key"] + assert hdwallet.xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] + assert hdwallet.xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] + assert hdwallet.uncompressed() == _["bitcoin"]["testnet"]["uncompressed"] + assert hdwallet.compressed() == _["bitcoin"]["testnet"]["compressed"] + assert hdwallet.chain_code() == _["bitcoin"]["testnet"]["chain_code"] + assert hdwallet.private_key() == _["bitcoin"]["testnet"]["private_key"] + assert hdwallet.public_key() == _["bitcoin"]["testnet"]["public_key"] + assert hdwallet.wif() == _["bitcoin"]["testnet"]["wif"] + assert hdwallet.finger_print() == _["bitcoin"]["testnet"]["finger_print"] + assert hdwallet.semantic() == _["bitcoin"]["testnet"]["semantic"] + assert hdwallet.path() == None + assert hdwallet.hash() == _["bitcoin"]["testnet"]["hash"] + assert hdwallet.p2pkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2pkh"] + assert hdwallet.p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2sh"] + assert hdwallet.p2wpkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh"] + assert hdwallet.p2wpkh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh_in_p2sh"] + assert hdwallet.p2wsh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh"] + assert hdwallet.p2wsh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh_in_p2sh"] + + assert isinstance(hdwallet.dumps(), dict) + + dumps: dict = _["bitcoin"]["testnet"] + + dumps["strength"] = None + dumps["entropy"] = None + dumps["mnemonic"] = None + dumps["language"] = None + dumps["passphrase"] = None + dumps["seed"] = None + dumps["path"] = None + dumps["root_xprivate_key"] = _["bitcoin"]["testnet"]["xprivate_key"] + dumps["root_xpublic_key"] = _["bitcoin"]["testnet"]["xpublic_key"] + del dumps["root_xprivate_key_hex"] + del dumps["root_xpublic_key_hex"] + del dumps["xprivate_key_hex"] + del dumps["xpublic_key_hex"] + + assert hdwallet.dumps() == dumps diff --git a/tests/hdwallet/test_from_xpublic_key.py b/tests/hdwallet/test_from_xpublic_key.py new file mode 100644 index 0000000..bd783c5 --- /dev/null +++ b/tests/hdwallet/test_from_xpublic_key.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 + +import json +import os + +from hdwallet import HDWallet + +# Test Values +base_path: str = os.path.dirname(__file__) +file_path: str = os.path.abspath(os.path.join(base_path, "../values.json")) +values = open(file_path, "r", encoding="utf-8") +_: dict = json.loads(values.read()) +values.close() + + +def test_from_xpublic_key(): + + hdwallet: HDWallet = HDWallet( + symbol=_["bitcoin"]["mainnet"]["symbol"] + ) + hdwallet.from_xpublic_key( + xpublic_key=_["bitcoin"]["mainnet"]["root_xpublic_key"], strict=True + ) + hdwallet.from_path( + path="m/44/0/0/0/0" + ) + + assert hdwallet.cryptocurrency() == _["bitcoin"]["mainnet"]["cryptocurrency"] + assert hdwallet.symbol() == _["bitcoin"]["mainnet"]["symbol"] + assert hdwallet.network() == _["bitcoin"]["mainnet"]["network"] + assert hdwallet.strength() is None + assert hdwallet.entropy() is None + assert hdwallet.mnemonic() is None + assert hdwallet.language() is None + assert hdwallet.passphrase() is None + assert hdwallet.seed() is None + assert hdwallet.root_xprivate_key(encoded=False) is None + assert hdwallet.root_xprivate_key() is None + assert hdwallet.root_xpublic_key(encoded=False) == "0488b21e000000000000000000ad41ef910cdcae932cb4060777b4284ee38f5b29c5fb60fda8416f298a14702c02949b9f64223e124eb9a8383fba0b21b5845fcfbdc84dec7692d21c716410eab0" + assert hdwallet.root_xpublic_key() == "xpub661MyMwAqRbcGGUtsoFw2d6ARvD2ABd7z327zxt2XiBBwMx9GAuNrrE7tbRuWF5MjjZ1BzDsRdaSHc9nVKAgHzQrv6pwYW3Hd7LSzbh8sWS" + assert hdwallet.xprivate_key(encoded=False) is None + assert hdwallet.xprivate_key() is None + assert hdwallet.xpublic_key(encoded=False) == "0488b21e052c0269af000000006c95c19e932b9e8f3d834e874526768ca1b3d89933ad71fd8253bcca67ac283d038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" + assert hdwallet.xpublic_key() == "xpub6FjoSaU1JaG6fC6wTYmb1mJzaZxSunxASN7nTRHhFynh33gKRfmmNrtQ82s8YouLCrEniskjumfACiiTyVmi4aXyLL8HvLdZc8mjKsbzT9z" + assert hdwallet.uncompressed() == "8f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad8750a64d9e0ee3555225e4130c7e36a443ec20330bf0be1e4de913e31e00202993" + assert hdwallet.compressed() == "038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" + assert hdwallet.chain_code() == "6c95c19e932b9e8f3d834e874526768ca1b3d89933ad71fd8253bcca67ac283d" + assert hdwallet.private_key() is None + assert hdwallet.public_key() == "038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" + assert hdwallet.wif() is None + assert hdwallet.finger_print() == "4e749a26" + assert hdwallet.semantic() == "p2pkh" + assert hdwallet.path() == "m/44/0/0/0/0" + assert hdwallet.hash() == "4e749a26934bca5091a05ee6f55e7d0e21482647" + assert hdwallet.p2pkh_address() == "189qPd6J81ns9LEGx6kun7Xtg1bJV8GJXh" + assert hdwallet.p2sh_address() == "3C71bNRojv3Gc7zHvWygas4AFt34rKezcF" + assert hdwallet.p2wpkh_address() == "bc1qfe6f5f5nf099pydqtmn02hnapcs5sfj86dpqjm" + assert hdwallet.p2wpkh_in_p2sh_address() == "3NykoodgJ7Li43JPt5xsezQz8xfwwwFZUs" + assert hdwallet.p2wsh_address() == "bc1qazm6kznlgs06exh4cq2qxh567xrffppwujje5zg84upnng4essusd08nhz" + assert hdwallet.p2wsh_in_p2sh_address() == "32yGj8ncXBBTjXqg188ZHxd1xffoQDcjin" + + assert isinstance(hdwallet.dumps(), dict) + + hdwallet: HDWallet = HDWallet( + symbol=_["bitcoin"]["testnet"]["symbol"] + ) + + hdwallet.from_xpublic_key( + xpublic_key=_["bitcoin"]["testnet"]["xpublic_key"], strict=False + ) + + assert hdwallet.cryptocurrency() == _["bitcoin"]["testnet"]["cryptocurrency"] + assert hdwallet.symbol() == _["bitcoin"]["testnet"]["symbol"] + assert hdwallet.network() == _["bitcoin"]["testnet"]["network"] + assert hdwallet.strength() is None + assert hdwallet.entropy() is None + assert hdwallet.mnemonic() is None + assert hdwallet.language() is None + assert hdwallet.passphrase() is None + assert hdwallet.seed() is None + assert hdwallet.root_xprivate_key(encoded=False) is None + assert hdwallet.root_xprivate_key() is None + assert hdwallet.root_xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] + assert hdwallet.root_xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] + assert hdwallet.xprivate_key(encoded=False) is None + assert hdwallet.xprivate_key() is None + assert hdwallet.xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] + assert hdwallet.xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] + assert hdwallet.uncompressed() == _["bitcoin"]["testnet"]["uncompressed"] + assert hdwallet.uncompressed(compressed=_["bitcoin"]["testnet"]["compressed"]) == _["bitcoin"]["testnet"]["uncompressed"] + assert hdwallet.compressed() == _["bitcoin"]["testnet"]["compressed"] + assert hdwallet.compressed(uncompressed=_["bitcoin"]["testnet"]["uncompressed"]) == _["bitcoin"]["testnet"]["compressed"] + assert hdwallet.chain_code() == _["bitcoin"]["testnet"]["chain_code"] + assert hdwallet.private_key() is None + assert hdwallet.public_key() == _["bitcoin"]["testnet"]["public_key"] + assert hdwallet.wif() is None + assert hdwallet.finger_print() == _["bitcoin"]["testnet"]["finger_print"] + assert hdwallet.semantic() == _["bitcoin"]["testnet"]["semantic"] + assert hdwallet.path() == None + assert hdwallet.hash() == _["bitcoin"]["testnet"]["hash"] + assert hdwallet.p2pkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2pkh"] + assert hdwallet.p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2sh"] + assert hdwallet.p2wpkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh"] + assert hdwallet.p2wpkh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh_in_p2sh"] + assert hdwallet.p2wsh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh"] + assert hdwallet.p2wsh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh_in_p2sh"] + + assert isinstance(hdwallet.dumps(), dict) + + dumps: dict = _["bitcoin"]["testnet"] + + dumps["strength"] = None + dumps["entropy"] = None + dumps["mnemonic"] = None + dumps["language"] = None + dumps["passphrase"] = None + dumps["seed"] = None + dumps["root_xprivate_key"] = None + dumps["xprivate_key"] = None + dumps["private_key"] = None + dumps["wif"] = None + dumps["path"] = None + dumps["root_xpublic_key"] = _["bitcoin"]["testnet"]["xpublic_key"] + del dumps["root_xprivate_key_hex"] + del dumps["root_xpublic_key_hex"] + del dumps["xprivate_key_hex"] + del dumps["xpublic_key_hex"] + + assert hdwallet.dumps() == dumps diff --git a/tests/test_base58.py b/tests/test_base58.py index 2b602c0..a1848ef 100644 --- a/tests/test_base58.py +++ b/tests/test_base58.py @@ -1,13 +1,16 @@ #!/usr/bin/env python3 +from Crypto.Hash import keccak from binascii import ( hexlify, unhexlify ) import pytest +import hashlib +from hdwallet.libs.ripemd160 import ripemd160 from hdwallet.libs.base58 import ( - check_encode, check_decode, string_to_int + checksum_encode, check_encode, check_decode, decode, encode, string_to_int ) @@ -29,3 +32,31 @@ def test_base58(): with pytest.raises(TypeError, match="string argument without an encoding"): assert string_to_int(str("meherett")) + + assert decode("111233QC4") == b'\x00\x00\x00(\x7f\xb4\xcd' + + assert encode(decode("111233QC4")) == "111233QC4" + + # Ensure ETH address checksums are correct; these are Keccak hash of the lower-case hex address, + # with hash results mapped onto the upper/lower case bits of the address. + eth = "0xfc2077CA7F403cBECA41B1B0F62D91B5EA631B5E" + eth_lower = eth.lower() + eth_check = checksum_encode(eth_lower) + assert eth_check == eth + + +def test_keccak(): + """Keccak 256 hash is required by several crypto algorithms. Ensure our hash implementations + are correct. + """ + + data = 'hello'.encode("utf8") + + assert hexlify(hashlib.sha256(data).digest()) == b"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" + assert hexlify(hashlib.sha3_256(data).digest()) == b"3338be694f50c5f338814986cdf0686453a888b84f424d792af4b9202398f392" + assert hexlify(hashlib.new('blake2s', data).digest()) == b"19213bacc58dee6dbde3ceb9a47cbb330b3d86f8cca8997eb00be456f140ca25" + + assert hexlify(ripemd160(data)) == b"108f07b8382412612c048d07d13f814118445acd" + + assert hexlify(keccak.new(data=data, digest_bits=256).digest()) == b'1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8' + diff --git a/tests/test_derivations.py b/tests/test_derivations.py new file mode 100644 index 0000000..07bd1be --- /dev/null +++ b/tests/test_derivations.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 + +import pytest + +from hdwallet.cryptocurrencies import BitcoinMainnet +from hdwallet.derivations import ( + Derivation, BIP32Derivation, BIP44Derivation, BIP49Derivation, BIP84Derivation, BIP141Derivation +) +from hdwallet.exceptions import SemanticError + + +def test_derivations(): + + assert str( + Derivation(path="m/44'/0'/0'/0/0", semantic="p2pkh") + ) == "m/44'/0'/0'/0/0" + assert str( + Derivation(semantic="p2pkh").from_path( + path="m/44'/0'/0'/0/0" + ) + ) == "m/44'/0'/0'/0/0" + assert str( + Derivation(semantic="p2pkh").from_index( + index=44, hardened=True + ).from_index( + index=0, hardened=True + ).from_index( + index=0, hardened=True + ).from_index( + index=0, hardened=False + ).from_index( + index=0, hardened=False + ) + ) == "m/44'/0'/0'/0/0" + assert str( + Derivation(path="m/44'/0'/0'/0/0", semantic="p2pkh").clean_derivation() + ) == "\0\0\0\0" + + assert str( + BIP32Derivation(purpose=44, coin_type=0, account=0, change=False, address=0) + ) == "m/44'/0'/0'/0/0" + assert str( + BIP32Derivation(purpose=(44, False), coin_type=(0, False), account=0, change=False, address=0) + ) == "m/44/0/0'/0/0" + + bip32_derivation: BIP32Derivation = BIP32Derivation().from_purpose( + purpose=44, hardened=True + ).from_coin_type( + coin_type=0, hardened=True + ).from_account( + account=0, hardened=True + ).from_change( + change=False + ).from_address( + address=0, hardened=False + ) + assert str(bip32_derivation) == "m/44'/0'/0'/0/0" + assert bip32_derivation.purpose() == "44'" + assert bip32_derivation.coin_type() == "0'" + assert bip32_derivation.account() == "0'" + assert bip32_derivation.change() == 0 + assert bip32_derivation.address() == "0" + assert bip32_derivation.SEMANTIC == "p2pkh" + + bip32_derivation: BIP32Derivation = BIP32Derivation( + purpose=(44, True), coin_type=(0, True), account=(0, True), change=False, address=(0, False) + ) + assert str(bip32_derivation) == "m/44'/0'/0'/0/0" + assert bip32_derivation.purpose() == "44'" + assert bip32_derivation.coin_type() == "0'" + assert bip32_derivation.account() == "0'" + assert bip32_derivation.change() == 0 + assert bip32_derivation.address() == "0" + assert bip32_derivation.SEMANTIC == "p2pkh" + + bip44_derivation: BIP44Derivation = BIP44Derivation( + cryptocurrency=BitcoinMainnet + ).from_account( + account=0, hardened=True + ).from_change( + change=False + ).from_address( + address=0, hardened=False + ) + assert str(bip44_derivation) == "m/44'/0'/0'/0/0" + assert bip44_derivation.purpose() == "44'" + assert bip44_derivation.coin_type() == "0'" + assert bip44_derivation.account() == "0'" + assert bip44_derivation.change() == 0 + assert bip44_derivation.address() == "0" + assert bip44_derivation.SEMANTIC == "p2pkh" + + bip44_derivation: BIP44Derivation = BIP44Derivation( + cryptocurrency=BitcoinMainnet, account=(0, True), change=False, address=(0, False) + ) + assert str(bip44_derivation) == "m/44'/0'/0'/0/0" + assert bip44_derivation.purpose() == "44'" + assert bip44_derivation.coin_type() == "0'" + assert bip44_derivation.account() == "0'" + assert bip44_derivation.change() == 0 + assert bip44_derivation.address() == "0" + assert bip44_derivation.SEMANTIC == "p2pkh" + + bip49_derivation: BIP49Derivation = BIP49Derivation( + cryptocurrency=BitcoinMainnet + ).from_account( + account=0, hardened=True + ).from_change( + change=False + ).from_address( + address=0, hardened=False + ) + assert str(bip49_derivation) == "m/49'/0'/0'/0/0" + assert bip49_derivation.purpose() == "49'" + assert bip49_derivation.coin_type() == "0'" + assert bip49_derivation.account() == "0'" + assert bip49_derivation.change() == 0 + assert bip49_derivation.address() == "0" + assert bip49_derivation.SEMANTIC == "p2wpkh_in_p2sh" + + bip49_derivation: BIP49Derivation = BIP49Derivation( + cryptocurrency=BitcoinMainnet, account=(0, True), change=False, address=(0, False) + ) + assert str(bip49_derivation) == "m/49'/0'/0'/0/0" + assert bip49_derivation.purpose() == "49'" + assert bip49_derivation.coin_type() == "0'" + assert bip49_derivation.account() == "0'" + assert bip49_derivation.change() == 0 + assert bip49_derivation.address() == "0" + assert bip49_derivation.SEMANTIC == "p2wpkh_in_p2sh" + + bip84_derivation: BIP84Derivation = BIP84Derivation( + cryptocurrency=BitcoinMainnet + ).from_account( + account=0, hardened=True + ).from_change( + change=False + ).from_address( + address=0, hardened=False + ) + assert str(bip84_derivation) == "m/84'/0'/0'/0/0" + assert bip84_derivation.purpose() == "84'" + assert bip84_derivation.coin_type() == "0'" + assert bip84_derivation.account() == "0'" + assert bip84_derivation.change() == 0 + assert bip84_derivation.address() == "0" + assert bip84_derivation.SEMANTIC == "p2wpkh" + + bip84_derivation: BIP84Derivation = BIP84Derivation( + cryptocurrency=BitcoinMainnet, account=(0, True), change=False, address=(0, False) + ) + assert str(bip84_derivation) == "m/84'/0'/0'/0/0" + assert bip84_derivation.purpose() == "84'" + assert bip84_derivation.coin_type() == "0'" + assert bip84_derivation.account() == "0'" + assert bip84_derivation.change() == 0 + assert bip84_derivation.address() == "0" + assert bip84_derivation.SEMANTIC == "p2wpkh" + + bip141_derivation: BIP141Derivation = BIP141Derivation( + cryptocurrency=BitcoinMainnet, semantic="p2wsh_in_p2sh" + ) + assert str(bip141_derivation) == "m/44'/0'/0'/0/0" + assert bip141_derivation.SEMANTIC == "p2wsh_in_p2sh" + + with pytest.raises(SemanticError, match="Wrong extended semantic, choose only the following options 'p2wpkh', 'p2wpkh_in_p2sh', 'p2wsh' or 'p2wsh_in_p2sh' semantics."): + BIP141Derivation( + cryptocurrency=BitcoinMainnet, semantic="p2pkh" + ) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py new file mode 100644 index 0000000..8dd2699 --- /dev/null +++ b/tests/test_exceptions.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 + +from hdwallet.exceptions import ( + NetworkError, DerivationError, SemanticError, AddressError, SymbolError +) + +import pytest + + +def test_exceptions(): + + with pytest.raises(NetworkError, match="error"): + raise NetworkError("error") + with pytest.raises(NetworkError, match="error, error"): + raise NetworkError("error", "error") + with pytest.raises(DerivationError, match="error"): + raise DerivationError("error") + with pytest.raises(DerivationError, match="error, error"): + raise DerivationError("error", "error") + with pytest.raises(SemanticError, match="error"): + raise SemanticError("error") + with pytest.raises(SemanticError): + raise SemanticError("error", "error") + with pytest.raises(AddressError, match="error"): + raise AddressError("error") + with pytest.raises(AddressError, match="error, error"): + raise AddressError("error", "error") + with pytest.raises(SymbolError, match="error"): + raise SymbolError("error") + with pytest.raises(SymbolError, match="error, error"): + raise SymbolError("error", "error") diff --git a/tests/test_from_root_xpublic_key.py b/tests/test_from_root_xpublic_key.py deleted file mode 100644 index 6d5892c..0000000 --- a/tests/test_from_root_xpublic_key.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python3 - -import json -import os - -from hdwallet import HDWallet - -# Test Values -base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) -values = open(file_path, "r", encoding="utf-8") -_: dict = json.loads(values.read()) -values.close() - - -def test_from_root_xpublic_key(): - - hdwallet: HDWallet = HDWallet( - symbol=_["bitcoin"]["mainnet"]["symbol"] - ) - hdwallet.from_root_xpublic_key( - xpublic_key=_["bitcoin"]["mainnet"]["root_xpublic_key"], strict=True - ) - hdwallet.from_path( - path="m/44/0/0/0/0" - ) - - assert hdwallet.cryptocurrency() == _["bitcoin"]["mainnet"]["cryptocurrency"] - assert hdwallet.symbol() == _["bitcoin"]["mainnet"]["symbol"] - assert hdwallet.network() == _["bitcoin"]["mainnet"]["network"] - assert hdwallet.strength() is None - assert hdwallet.entropy() is None - assert hdwallet.mnemonic() is None - assert hdwallet.language() is None - assert hdwallet.passphrase() is None - assert hdwallet.seed() is None - assert hdwallet.root_xprivate_key(encoded=False) is None - assert hdwallet.root_xprivate_key() is None - assert hdwallet.root_xpublic_key(encoded=False) == "0488b21e000000000000000000ad41ef910cdcae932cb4060777b4284ee38f5b29c5fb60fda8416f298a14702c02949b9f64223e124eb9a8383fba0b21b5845fcfbdc84dec7692d21c716410eab0" - assert hdwallet.root_xpublic_key() == "xpub661MyMwAqRbcGGUtsoFw2d6ARvD2ABd7z327zxt2XiBBwMx9GAuNrrE7tbRuWF5MjjZ1BzDsRdaSHc9nVKAgHzQrv6pwYW3Hd7LSzbh8sWS" - assert hdwallet.xprivate_key(encoded=False) is None - assert hdwallet.xprivate_key() is None - assert hdwallet.xpublic_key(encoded=False) == "0488b21e052c0269af000000006c95c19e932b9e8f3d834e874526768ca1b3d89933ad71fd8253bcca67ac283d038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" - assert hdwallet.xpublic_key() == "xpub6FjoSaU1JaG6fC6wTYmb1mJzaZxSunxASN7nTRHhFynh33gKRfmmNrtQ82s8YouLCrEniskjumfACiiTyVmi4aXyLL8HvLdZc8mjKsbzT9z" - assert hdwallet.uncompressed() == "8f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad8750a64d9e0ee3555225e4130c7e36a443ec20330bf0be1e4de913e31e00202993" - assert hdwallet.compressed() == "038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" - assert hdwallet.chain_code() == "6c95c19e932b9e8f3d834e874526768ca1b3d89933ad71fd8253bcca67ac283d" - assert hdwallet.private_key() is None - assert hdwallet.public_key() == "038f24175db513b40c75503c25040e5f0ea4d38e912d1f83daf5fd8c4b9512ad87" - assert hdwallet.wif() is None - assert hdwallet.finger_print() == "4e749a26" - assert hdwallet.semantic() == "p2pkh" - assert hdwallet.path() == "m/44/0/0/0/0" - assert hdwallet.hash() == "4e749a26934bca5091a05ee6f55e7d0e21482647" - assert hdwallet.p2pkh_address() == "189qPd6J81ns9LEGx6kun7Xtg1bJV8GJXh" - assert hdwallet.p2sh_address() == "3C71bNRojv3Gc7zHvWygas4AFt34rKezcF" - assert hdwallet.p2wpkh_address() == "bc1qfe6f5f5nf099pydqtmn02hnapcs5sfj86dpqjm" - assert hdwallet.p2wpkh_in_p2sh_address() == "3NykoodgJ7Li43JPt5xsezQz8xfwwwFZUs" - assert hdwallet.p2wsh_address() == "bc1qazm6kznlgs06exh4cq2qxh567xrffppwujje5zg84upnng4essusd08nhz" - assert hdwallet.p2wsh_in_p2sh_address() == "32yGj8ncXBBTjXqg188ZHxd1xffoQDcjin" - - assert isinstance(hdwallet.dumps(), dict) diff --git a/tests/test_from_xprivate_key.py b/tests/test_from_xprivate_key.py deleted file mode 100644 index 939c717..0000000 --- a/tests/test_from_xprivate_key.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 - -import json -import os - -from hdwallet import HDWallet - -# Test Values -base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) -values = open(file_path, "r", encoding="utf-8") -_: dict = json.loads(values.read()) -values.close() - - -def test_from_xprivate_key(): - - hdwallet: HDWallet = HDWallet( - symbol=_["bitcoin"]["testnet"]["symbol"] - ) - - hdwallet.from_xprivate_key( - xprivate_key=_["bitcoin"]["testnet"]["xprivate_key"] - ) - - assert hdwallet.cryptocurrency() == _["bitcoin"]["testnet"]["cryptocurrency"] - assert hdwallet.symbol() == _["bitcoin"]["testnet"]["symbol"] - assert hdwallet.network() == _["bitcoin"]["testnet"]["network"] - assert hdwallet.strength() is None - assert hdwallet.entropy() is None - assert hdwallet.mnemonic() is None - assert hdwallet.language() is None - assert hdwallet.passphrase() is None - assert hdwallet.seed() is None - assert hdwallet.root_xprivate_key(encoded=False) is None - assert hdwallet.root_xprivate_key() is None - assert hdwallet.root_xpublic_key(encoded=False) is None - assert hdwallet.root_xpublic_key() is None - assert hdwallet.xprivate_key(encoded=False) == _["bitcoin"]["testnet"]["xprivate_key_hex"] - assert hdwallet.xprivate_key() == _["bitcoin"]["testnet"]["xprivate_key"] - assert hdwallet.xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] - assert hdwallet.xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] - assert hdwallet.uncompressed() == _["bitcoin"]["testnet"]["uncompressed"] - assert hdwallet.compressed() == _["bitcoin"]["testnet"]["compressed"] - assert hdwallet.chain_code() == _["bitcoin"]["testnet"]["chain_code"] - assert hdwallet.private_key() == _["bitcoin"]["testnet"]["private_key"] - assert hdwallet.public_key() == _["bitcoin"]["testnet"]["public_key"] - assert hdwallet.wif() == _["bitcoin"]["testnet"]["wif"] - assert hdwallet.finger_print() == _["bitcoin"]["testnet"]["finger_print"] - assert hdwallet.semantic() == _["bitcoin"]["testnet"]["semantic"] - assert hdwallet.path() == None - assert hdwallet.hash() == _["bitcoin"]["testnet"]["hash"] - assert hdwallet.p2pkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2pkh"] - assert hdwallet.p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2sh"] - assert hdwallet.p2wpkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh"] - assert hdwallet.p2wpkh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh_in_p2sh"] - assert hdwallet.p2wsh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh"] - assert hdwallet.p2wsh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh_in_p2sh"] - - assert isinstance(hdwallet.dumps(), dict) - - dumps: dict = _["bitcoin"]["testnet"] - - dumps["strength"] = None - dumps["entropy"] = None - dumps["mnemonic"] = None - dumps["language"] = None - dumps["passphrase"] = None - dumps["seed"] = None - dumps["root_xprivate_key"] = None - dumps["root_xpublic_key"] = None - dumps["path"] = None - del dumps["root_xprivate_key_hex"] - del dumps["root_xpublic_key_hex"] - del dumps["xprivate_key_hex"] - del dumps["xpublic_key_hex"] - - assert hdwallet.dumps() == dumps diff --git a/tests/test_from_xpublic_key.py b/tests/test_from_xpublic_key.py deleted file mode 100644 index d8b9055..0000000 --- a/tests/test_from_xpublic_key.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python3 - -import json -import os - -from hdwallet import HDWallet - -# Test Values -base_path: str = os.path.dirname(__file__) -file_path: str = os.path.abspath(os.path.join(base_path, "values.json")) -values = open(file_path, "r", encoding="utf-8") -_: dict = json.loads(values.read()) -values.close() - - -def test_from_xpublic_key(): - - hdwallet: HDWallet = HDWallet( - symbol=_["bitcoin"]["testnet"]["symbol"] - ) - - hdwallet.from_xpublic_key( - xpublic_key=_["bitcoin"]["testnet"]["xpublic_key"] - ) - - assert hdwallet.cryptocurrency() == _["bitcoin"]["testnet"]["cryptocurrency"] - assert hdwallet.symbol() == _["bitcoin"]["testnet"]["symbol"] - assert hdwallet.network() == _["bitcoin"]["testnet"]["network"] - assert hdwallet.strength() is None - assert hdwallet.entropy() is None - assert hdwallet.mnemonic() is None - assert hdwallet.language() is None - assert hdwallet.passphrase() is None - assert hdwallet.seed() is None - assert hdwallet.root_xprivate_key(encoded=False) is None - assert hdwallet.root_xprivate_key() is None - assert hdwallet.root_xpublic_key(encoded=False) is None - assert hdwallet.root_xpublic_key() is None - assert hdwallet.xprivate_key(encoded=False) is None - assert hdwallet.xprivate_key() is None - assert hdwallet.xpublic_key(encoded=False) == _["bitcoin"]["testnet"]["xpublic_key_hex"] - assert hdwallet.xpublic_key() == _["bitcoin"]["testnet"]["xpublic_key"] - assert hdwallet.uncompressed() == _["bitcoin"]["testnet"]["uncompressed"] - assert hdwallet.uncompressed(compressed=_["bitcoin"]["testnet"]["compressed"]) == _["bitcoin"]["testnet"]["uncompressed"] - assert hdwallet.compressed() == _["bitcoin"]["testnet"]["compressed"] - assert hdwallet.compressed(uncompressed=_["bitcoin"]["testnet"]["uncompressed"]) == _["bitcoin"]["testnet"]["compressed"] - assert hdwallet.chain_code() == _["bitcoin"]["testnet"]["chain_code"] - assert hdwallet.private_key() is None - assert hdwallet.public_key() == _["bitcoin"]["testnet"]["public_key"] - assert hdwallet.wif() is None - assert hdwallet.finger_print() == _["bitcoin"]["testnet"]["finger_print"] - assert hdwallet.semantic() == _["bitcoin"]["testnet"]["semantic"] - assert hdwallet.path() == None - assert hdwallet.hash() == _["bitcoin"]["testnet"]["hash"] - assert hdwallet.p2pkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2pkh"] - assert hdwallet.p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2sh"] - assert hdwallet.p2wpkh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh"] - assert hdwallet.p2wpkh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wpkh_in_p2sh"] - assert hdwallet.p2wsh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh"] - assert hdwallet.p2wsh_in_p2sh_address() == _["bitcoin"]["testnet"]["addresses"]["p2wsh_in_p2sh"] - - assert isinstance(hdwallet.dumps(), dict) - - dumps: dict = _["bitcoin"]["testnet"] - - dumps["strength"] = None - dumps["entropy"] = None - dumps["mnemonic"] = None - dumps["language"] = None - dumps["passphrase"] = None - dumps["seed"] = None - dumps["root_xprivate_key"] = None - dumps["root_xpublic_key"] = None - dumps["xprivate_key"] = None - dumps["private_key"] = None - dumps["wif"] = None - dumps["path"] = None - del dumps["root_xprivate_key_hex"] - del dumps["root_xpublic_key_hex"] - del dumps["xprivate_key_hex"] - del dumps["xpublic_key_hex"] - - assert hdwallet.dumps() == dumps diff --git a/tests/test_symbols.py b/tests/test_symbols.py new file mode 100644 index 0000000..f1d1d5f --- /dev/null +++ b/tests/test_symbols.py @@ -0,0 +1,168 @@ +# !/usr/bin/env python3 + +from hdwallet.symbols import * + + +def test_symbols(): + + assert ANON == "ANON" + assert AGM == "AGM" + assert XAX == "XAX" + assert AYA == "AYA" + assert AC == "AC" + assert ATOM == "ATOM" + assert AUR == "AUR" + assert AXE == "AXE" + assert BTA == "BTA" + assert BEET == "BEET" + assert BELA == "BELA" + assert BTDX == "BTDX" + assert BSD == "BSD" + assert BCH == "BCH" + assert BTG == "BTG" + assert BTC == "BTC" + assert BTCTEST == "BTCTEST" + assert XBC == "XBC" + assert BSV == "BSV" + assert BTCZ == "BTCZ" + assert BTX == "BTX" + assert BLK == "BLK" + assert BST == "BST" + assert BND == "BND" + assert BNDTEST == "BNDTEST" + assert BOLI == "BOLI" + assert BRIT == "BRIT" + assert CPU == "CPU" + assert CDN == "CDN" + assert CCN == "CCN" + assert CLAM == "CLAM" + assert CLUB == "CLUB" + assert CMP == "CMP" + assert CRP == "CRP" + assert CRAVE == "CRAVE" + assert DASH == "DASH" + assert DASHTEST == "DASHTEST" + assert ONION == "ONION" + assert DFC == "DFC" + assert DNR == "DNR" + assert DMD == "DMD" + assert DGB == "DGB" + assert DGC == "DGC" + assert DOGE == "DOGE" + assert DOGETEST == "DOGETEST" + assert EDRC == "EDRC" + assert ECN == "ECN" + assert EMC2 == "EMC2" + assert ELA == "ELA" + assert NRG == "NRG" + assert ETH == "ETH" + assert ERC == "ERC" + assert EXCL == "EXCL" + assert FIX == "FIX" + assert FIXTEST == "FIXTEST" + assert FTC == "FTC" + assert FRST == "FRST" + assert FLASH == "FLASH" + assert FLUX == "FLUX" + assert FJC == "FJC" + assert GCR == "GCR" + assert GAME == "GAME" + assert GBX == "GBX" + assert GRC == "GRC" + assert GRS == "GRS" + assert GRSTEST == "GRSTEST" + assert NLG == "NLG" + assert HNC == "HNC" + assert THC == "THC" + assert HUSH == "HUSH" + assert IXC == "IXC" + assert INSN == "INSN" + assert IOP == "IOP" + assert JBS == "JBS" + assert KOBO == "KOBO" + assert KMD == "KMD" + assert LBC == "LBC" + assert LINX == "LINX" + assert LCC == "LCC" + assert LTC == "LTC" + assert LTCTEST == "LTCTEST" + assert LTZ == "LTZ" + assert LKR == "LKR" + assert LYNX == "LYNX" + assert MZC == "MZC" + assert MEC == "MEC" + assert MNX == "MNX" + assert MONA == "MONA" + assert MONK == "MONK" + assert XMY == "XMY" + assert NIX == "NIX" + assert NMC == "NMC" + assert NAV == "NAV" + assert NEBL == "NEBL" + assert NEOS == "NEOS" + assert NRO == "NRO" + assert NYC == "NYC" + assert NVC == "NVC" + assert NBT == "NBT" + assert NSR == "NSR" + assert OK == "OK" + assert OMNI == "OMNI" + assert OMNITEST == "OMNITEST" + assert ONX == "ONX" + assert PPC == "PPC" + assert PSB == "PSB" + assert PHR == "PHR" + assert PINK == "PINK" + assert PIVX == "PIVX" + assert PIVXTEST == "PIVXTEST" + assert POSW == "POSW" + assert POT == "POT" + assert PRJ == "PRJ" + assert PUT == "PUT" + assert QTUM == "QTUM" + assert QTUMTEST == "QTUMTEST" + assert RBTC == "RBTC" + assert RBTCTEST == "RBTCTEST" + assert RPD == "RPD" + assert RVN == "RVN" + assert RDD == "RDD" + assert RBY == "RBY" + assert SAFE == "SAFE" + assert SLS == "SLS" + assert SCRIBE == "SCRIBE" + assert SDC == "SDC" + assert SDCTEST == "SDCTEST" + assert SLM == "SLM" + assert SLMTEST == "SLMTEST" + assert SMLY == "SMLY" + assert SLR == "SLR" + assert STASH == "STASH" + assert STRAT == "STRAT" + assert STRATTEST == "STRATTEST" + assert SUGAR == "SUGAR" + assert SUGARTEST == "SUGARTEST" + assert SYS == "SYS" + assert TOA == "TOA" + assert THT == "THT" + assert TRX == "TRX" + assert TWINS == "TWINS" + assert TWINSTEST == "TWINSTEST" + assert USC == "USC" + assert UNO == "UNO" + assert VASH == "VASH" + assert VC == "VC" + assert XVG == "XVG" + assert VTC == "VTC" + assert VIA == "VIA" + assert VIATEST == "VIATEST" + assert VIVO == "VIVO" + assert XWC == "XWC" + assert WC == "WC" + assert XUEZ == "XUEZ" + assert XDC == "XDC" + assert XRP == "XRP" + assert YEC == "YEC" + assert ZCL == "ZCL" + assert ZEC == "ZEC" + assert ZECTEST == "ZECTEST" + assert ZEN == "ZEN" diff --git a/tests/test_utils.py b/tests/test_utils.py index 6e6dba0..f390e5f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,8 +6,8 @@ from hdwallet.utils import ( get_bytes, generate_mnemonic, generate_entropy, is_entropy, get_mnemonic_strength, - get_entropy_strength, is_mnemonic, get_mnemonic_language, - is_root_xprivate_key, is_root_xpublic_key + get_entropy_strength, is_mnemonic, get_mnemonic_language, entropy_to_mnemonic, mnemonic_to_entropy, + is_root_xprivate_key, is_root_xpublic_key, generate_passphrase ) # Test Values @@ -40,6 +40,8 @@ def test_utils(): symbol=_["bitcoin"]["mainnet"]["symbol"] ) + assert len(generate_passphrase(length=19999)) == 19999 + def test_utils_entropy(): @@ -55,6 +57,10 @@ def test_utils_entropy(): assert get_entropy_strength(entropy["entropy"]) == entropy["strength"] assert is_entropy(entropy["entropy"]) + assert mnemonic_to_entropy( + mnemonic=_["bitcoin"]["mainnet"]["mnemonic"], language=_["bitcoin"]["mainnet"]["language"] + ) == _["bitcoin"]["mainnet"]["entropy"] + def test_utils_mnemonic(): @@ -73,3 +79,7 @@ def test_utils_mnemonic(): assert not is_mnemonic(mnemonic["mnemonic"], "korean") assert is_mnemonic(mnemonic["mnemonic"], mnemonic["language"]) assert get_mnemonic_language(mnemonic["mnemonic"]) == mnemonic["language"] + + assert entropy_to_mnemonic( + entropy=_["bitcoin"]["mainnet"]["entropy"], language=_["bitcoin"]["mainnet"]["language"] + ) == _["bitcoin"]["mainnet"]["mnemonic"] diff --git a/tests/values.json b/tests/values.json index 64c0217..b75f4c7 100644 --- a/tests/values.json +++ b/tests/values.json @@ -152,6 +152,28 @@ "p2wsh": "tb1qlp932cdsy78jfka7gcv9gk50cdku5g6thxjpzstcwn9gnqd5ll9qzhuqvw", "p2wsh_in_p2sh": "2NBzP3SsouDEVe41fYJBbGGPS18tk6mqZSh" } - } + }, + "addresses": [ + "m/44'/0'/0'/0/0 16W7JeQXEzmYKX8UMFMrg6FwNSPduVdYHo 02b506c3585ebaaf5553b5e3b767c958c6eec4d0eba8a9b9fe90ff2e512a70c30c L15H89HiXh6m4CNPkMvAg1Wduscw5wuvktACPzrHowDHufwPgR7k", + "m/44'/0'/0'/0/1 19rtbaqSprjGpE3pxUovx38t64dYLxJ5H4 023cef50818c538a76eaec937f566acbabb0f2047fc2a082c11a9dad398c15eab4 Ky6pHMChq9sT8EhM42rzCab9SxHbFU4CM7rXhZT7fRakAeS47eob", + "m/44'/0'/0'/0/2 1FBUJ5QkwgBbFgHnXR2BWnyjYAh8KDXbTk 0349e0525ee723e4e9db2fb1b01e8fe5a6bc73067c024ff6d3bee7036a14758059 Kxfgz2ZAXiJ3V5Uy4hL7YKssJV3VXf9N3k72DV8XQoF6ndzxYa2U", + "m/44'/0'/0'/0/3 1JBW45zCCCHZ58z9AnEdbqCQ4TBnq5hVfk 03028b9e813e4d7bdee5a2930272673decc0736820e4a65676ac2af3fef89b49f1 L2P9gZUoobY1Z9mmUNfParxeMDg5rejvptD7fZYbam8CrgnFJ6CM", + "m/44'/0'/0'/0/4 1Dxp9jGJqpZMybuj6RoD4qozUEbYMeJgET 0398e6783af803f5125c0d0eecaffd663d5873c961b65493fa31d29ade7eee2aea L3wFzjZDvf1znTFkfcDk7YRHDpG186o4Wfy6zzRSyerGGjdYqXG3", + "m/44'/0'/0'/0/5 17FymopXFtsz3FidDTXVYymEksfRVA8Prr 031900f3d2c249dd54c3c59c506bbdda65e61f614841c0254d309d5f206160b459 KxagjpYP8VGb4M2U1Q4tnZ8vuvt3BnwnzsiGen67kwZprMUeYCBx", + "m/44'/0'/0'/0/6 1ABU3xfqxYPMx37tK3ytNFMfF4EJhNCe4F 03c016cdac08271650e39748544ccb16bbcf89a470ca03aaed9cb61cb4eec79122 Kxong4YotFdirnM4eYKSq5Kyq55eKnqUqnyvEsskvb63Lwyk7oay", + "m/44'/0'/0'/0/7 178cLTCrTBRs1KD6rvkrGrtGBFibzwcWHS 03857c2f52bf8363566ecdf0c2f1aac249a8a09ad9b442f46782e397cd7ddf3b4f L1WyWVRf3sHMeJs6FRbE2fxq2Ld2PPUwQcqDHMKs7NY76naFjQtP", + "m/44'/0'/0'/0/8 1raCHQ7gUGKS8LCxSp18Dw6pWq28Mubc2 0209683884b033ea08fb9ce44c8fc77fdad2c7935ffab765b76976f2404d84a58d L2A1nHGoLGCMBS9BJioAEuHGQH4NYLqxEnSaBKYWrXmhL4xg8h5G", + "m/44'/0'/0'/0/9 16rs2as6bHkKxJCKkeFKB4dMra2QMGJifc 03055297a3a7cbbd6ff32958f5d82f0cd4f1a29330fbd83d67038e406c27eb7412 L4nDdMuCKnxM9oqGtse989sS6fwyX2UxgafgZBnc71Z6mhiMudBx", + "m/44'/0'/0'/0/10 13TZhvvzcK5WYqT88tpmc7zcirKRMB65Fc 03b2d37804e7c04b12035c9d87cb8f8ba6fdf11744b2b37a52b023073eeee2fe4b L3NHZhyLjvum8nbKeGSYMzyjQritbsbtm8iPMAtH8sVRkqNw8VfR", + "m/44'/0'/0'/0/11 1LEkeCdpvD3FRRbCajLqdEDwTnKjxEte4Z 02f88c7d8fc5b83f2f24c3868d3c5aba8ec4b8bef75338e09efe7f19f2653c10fb KxWhP2iqkbkS34MffJU94w1hsy6ixoyhh1xKWeRm1ZqX92khrv88", + "m/44'/0'/0'/0/12 1KAcnth9Ebr5bALRmFtWCRnd1vivgyGAnt 022f2f6a8a57c355b057d38c4e263760a50e085ba6b3afa25aa8c13fcb861c882f Kx1JcdaLVPt4EFseRYf6bhP8EwpNWjEkgLMLaNQT6HrU4hnCGe7g", + "m/44'/0'/0'/0/13 1AUMAcfiiXVqrthwtAPEJNEMoLQXYkLpx3 02695fd7ac3c09a3b568ec374965331d3146740ec938d1d3166cdf420e23688914 KxdtUhqVGD6HKUsCtaFm1vNXLzDQxWDzpTqhBk9y5RY1ACGj7BtW", + "m/44'/0'/0'/0/14 1E8Ywe96WNrGDb3V1zA8LLBbDqir1TBREo 02b2589ecb684684a332ad6753710af251e5455d387b60facbc78ea60998d4704a KxEZKXvR4pW3eVmuog714cHgJwxqm87uUcjrUU8e28uPzhq88qxX", + "m/44'/0'/0'/0/15 16oBYcHjoQ721NWPwuojmLuQbTmbFbsnyX 030f4b6d7f4ab090a9a4f912f6dc65d2b221b724fdb29fc06974aa011c3c072c20 Ky2Kpb9ephAmjyP2RsUtLfydwWZmhEWBkszfPfQJJPQFdmu8LyVD", + "m/44'/0'/0'/0/16 18dfhagZDyQcpFHN9XXG8WLJemhiYpkPSi 033b25fefbb04de60b7bffe61d0bcedb48916c08fa96f76a80c4e9288b61cb6044 KyAitBv7M7jVqtZXrJxypnZipfg9BdZhEVmUPDWvWRSN4KsB2gcH", + "m/44'/0'/0'/0/17 1ACpQPMNLewMbXWvVg78kZZKMf64bu8qtc 026691563d2ee9b7a5ae095b443a1199ff53d612928412d8965e163b78c31b89d6 L5dBkDYHfrTVy2ZKT9Xy8V5m34QTg3J2dbhhXMe8wMmAawLFpPGT", + "m/44'/0'/0'/0/18 14xgtqtqxvB8QFgaTihdTAgD9Wxm5tbonU 0306b36921313c59e4495bc1c4d9f6dc9c9303a8740767c7a1844c36c506b5f9e7 KwS6KDcNUA7WQ1FTZv9G3A6uWrPzEcYpiGQW5R8j5CkcjvmFduJh", + "m/44'/0'/0'/0/19 1BUauGHKJ69j7UsqcwX4p3NmELZuPbkY2d 03ded79d490a0c59ad79549acae0cbe9c8b102185c254f27a26993a5911f7cd038 L22FD2vSP6c2cxbD3ssyJZSKBvXxzjCGnGqAihdowkb3UADZn6q1" + ] } } \ No newline at end of file diff --git a/tox.ini b/tox.ini index 3c126b6..54bef60 100644 --- a/tox.ini +++ b/tox.ini @@ -1,29 +1,45 @@ [tox] -envlist = python36,python37,python38,python39 +envlist = python37,python38,python39,python310,python311 [travis] python = - 3.6: python36 3.7: python37 3.8: python38 3.9: python39 - -[testenv:python36] -install_command = - python -m pip install -e .[tests,docs] {opts} {packages} -commands = python -m pytest + 3.10: python310 + 3.11: python311 [testenv:python37] install_command = - python -m pip install -e .[tests,docs] {opts} {packages} + python -m pip install --upgrade pip {opts} {packages} + pip install -e . {opts} {packages} +extras = cli,tests,docs commands = python -m pytest [testenv:python38] install_command = - python -m pip install -e .[tests,docs] {opts} {packages} + python -m pip install --upgrade pip {opts} {packages} + pip install -e . {opts} {packages} +extras = cli,tests,docs commands = python -m pytest [testenv:python39] install_command = - python -m pip install -e .[tests,docs] {opts} {packages} + python -m pip install --upgrade pip {opts} {packages} + pip install -e . {opts} {packages} +extras = cli,tests,docs +commands = python -m pytest + +[testenv:python310] +install_command = + python -m pip install --upgrade pip {opts} {packages} + pip install -e . {opts} {packages} +extras = cli,tests,docs +commands = python -m pytest + +[testenv:python311] +install_command = + python -m pip install --upgrade pip {opts} {packages} + pip install -e . {opts} {packages} +extras = cli,tests,docs commands = python -m pytest