diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index eceed53c..1cfa1afa 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: python-version: [ - "3.7", "3.8", "3.9", "3.10", "3.11" + "3.8", "3.9", "3.10", "3.11", "3.12", "3.13" ] steps: - uses: actions/checkout@master diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..db67ce9f --- /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 3c1a6c21..022fb51b 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/GNUmakefile b/GNUmakefile index 73be7d4c..17b58624 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,10 +1,19 @@ SHELL = /bin/bash PY3 ?= $(shell python3 --version >/dev/null 2>&1 && echo python3 || echo python ) -VERSION = $(shell $(PY3) -c 'from hdwallet import __version__; print( __version__.strip("v"))') +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 @@ -19,28 +28,30 @@ test-%: unit-%: $(PY3TEST) -k $* -build: clean wheel +nix-%: + nix-shell $(NIX_OPTS) --run "make $*" -build-check: - @$(PY3) -m build --version \ - || ( \ - echo -e "\n\n!!! Missing Python modules; run:"; \ - echo -e "\n\n $(PY3) -m pip install --upgrade pip setuptools wheel build\n"; \ - false; \ - ) +build: clean wheel wheel: $(WHEEL) -$(WHEEL): build-check FORCE +$(WHEEL): FORCE + $(PY3) -m pip install -r requirements-dev.txt $(PY3) -m build @ls -last dist -# Install from wheel, including all optional extra dependencies (except dev) -install-dev: $(WHEEL) FORCE - $(PY3) -m pip install --upgrade $<[tests] - install: $(WHEEL) FORCE - $(PY3) -m pip install --force-reinstall $<[cli,docs] + $(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 $ 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) diff --git a/default.nix b/default.nix new file mode 100644 index 00000000..e81323ba --- /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/hdwallet/__init__.py b/hdwallet/__init__.py index 071a8759..633d6b5f 100644 --- a/hdwallet/__init__.py +++ b/hdwallet/__init__.py @@ -10,7 +10,10 @@ ) # HDWallet Information's -__version__: str = "v2.2.1" +from .version import ( + __version__, + __version_info__ +) __license__: str = "MIT" __author__: str = "Meheret Tesfaye Batu" __email__: str = "meherett.batu@gmail.com" @@ -19,6 +22,7 @@ __all__: list = [ "__version__", + "__version_info__", "__license__", "__author__", "__email__", diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index ef24396a..aa8a83df 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -354,6 +354,45 @@ class AuroracoinMainnet(Cryptocurrency): 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" @@ -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" @@ -2154,6 +2393,86 @@ class EuropeCoinMainnet(Cryptocurrency): 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" @@ -2431,6 +2750,87 @@ class FluxMainnet(Cryptocurrency): 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 + }) + + MESSAGE_PREFIX = "Foxdcoin Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0xef + + class FujiCoinMainnet(Cryptocurrency): NAME = "Fuji Coin" @@ -4836,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 @@ -4845,32 +5245,68 @@ class RavencoinMainnet(Cryptocurrency): SCRIPT_ADDRESS = 0x7a PUBLIC_KEY_ADDRESS = 0x3c SEGWIT_ADDRESS = SegwitAddress({ - "HRP": None, - "VERSION": 0x00 + "HRP": "ra", + "VERSION": 0x0c }) EXTENDED_PRIVATE_KEY = ExtendedPrivateKey({ "P2PKH": 0x488ade4, "P2SH": 0x488ade4, - "P2WPKH": None, - "P2WPKH_IN_P2SH": None, - "P2WSH": None, - "P2WSH_IN_P2SH": None + "P2WPKH": 0x04b2430c, + "P2WPKH_IN_P2SH": 0x049d7878, + "P2WSH": 0x02aa7a99, + "P2WSH_IN_P2SH": 0x0295b005 }) EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ "P2PKH": 0x488b21e, "P2SH": 0x488b21e, - "P2WPKH": None, - "P2WPKH_IN_P2SH": None, - "P2WSH": None, - "P2WSH_IN_P2SH": None + "P2WPKH": 0x04b24746, + "P2WPKH_IN_P2SH": 0x049d7cb2, + "P2WSH": 0x02aa7ed3, + "P2WSH_IN_P2SH": 0x0295b43f }) - MESSAGE_PREFIX = "Raven Signed Message:\n" + 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" diff --git a/hdwallet/derivations.py b/hdwallet/derivations.py index b34a6d4a..c7d290d3 100644 --- a/hdwallet/derivations.py +++ b/hdwallet/derivations.py @@ -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") """ @@ -123,9 +123,9 @@ 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) diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 1592fb80..a08fec07 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -437,7 +437,7 @@ def from_path(self, path: Union[str, Derivation]) -> "HDWallet": >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> hdwallet.from_path(path="m/44'/0'/0'/0/0") """ @@ -483,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) @@ -598,7 +598,7 @@ 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" """ @@ -636,7 +636,7 @@ 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" """ @@ -679,7 +679,7 @@ 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" """ @@ -717,7 +717,7 @@ 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" """ @@ -750,9 +750,9 @@ def clean_derivation(self) -> "HDWallet": >>> from hdwallet.symbols import BTC >>> hdwallet = HDWallet(symbol=BTC) >>> hdwallet.from_xprivate_key(xprivate_key="xprv9s21ZrQH143K3xPGUzpogJeKtRdjHkK6muBJo8v7rEVRzT83xJgNcLpMoJXUf9wJFKfuHR4SGvfgdShh4t9VmjjrE9usBunK3LfNna31LGF") - >>> hdwallet.from_path(path="m/44'/0'/'0/0/0") + >>> 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() @@ -1196,9 +1196,10 @@ def p2wpkh_address(self) -> Optional[str]: compressed_public_key = unhexlify(self.compressed()) public_key_hash = ripemd160(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, public_key_hash)) + return ensure_string(encode(segwit.HRP, segwit.VERSION, public_key_hash)) def p2wpkh_in_p2sh_address(self) -> Optional[str]: """ @@ -1240,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]: """ diff --git a/hdwallet/symbols.py b/hdwallet/symbols.py index 531f6ea1..5fc4c06d 100644 --- a/hdwallet/symbols.py +++ b/hdwallet/symbols.py @@ -14,6 +14,8 @@ ATOM = "ATOM" # Auroracoin AUR = "AUR" +# Aviancoin +AVN = "AVN" # Axe AXE = "AXE" # Bata @@ -26,6 +28,8 @@ BTDX = "BTDX" # Bit Send BSD = "BSD" +# BNB Smart Chain +BSC = "BSC" # Bitcoin Cash BCH = "BCH" # Bitcoin Gold @@ -96,6 +100,8 @@ ETH = "ETH" # Europe Coin ERC = "ERC" +# Evrmore +EVR, EVRTEST = "EVR", "EVRTEST" # Exclusive Coin EXCL = "EXCL" # FIX @@ -108,6 +114,8 @@ FLASH = "FLASH" # Flux FLUX = "FLUX" +# Foxdcoin +FOXD, FOXDTEST = "FOXD", "FOXDTEST" # Fuji Coin FJC = "FJC" # GCR Coin @@ -154,6 +162,10 @@ LKR = "LKR" # Lynx LYNX = "LYNX" +# Polygon +MATIC = "MATIC" +# Arbitrum +ARB1 = "ARB1" # Mazacoin MZC = "MZC" # Megacoin @@ -217,7 +229,7 @@ # Rapids RPD = "RPD" # Ravencoin -RVN = "RVN" +RVN, RVNTEST = "RVN", "RVNTEST" # Reddcoin RDD = "RDD" # Rubycoin @@ -286,16 +298,24 @@ ZEC, ZECTEST = "ZEC", "ZECTEST" # Zencash ZEN = "ZEN" +# zkSync +ZKS = "ZKS" +# Linea +LINEA = "LINEA" __all__ = [ "ANON", "AGM", + "LINEA", + "ARB1", + "ZKS", "XAX", "AYA", "AC", "ATOM", "AUR", + "AVN", "AXE", "BTA", "BEET", @@ -303,6 +323,7 @@ "BTDX", "BSD", "BCH", + "BSC", "BTG", "BTC", "BTCTEST", "XBC", @@ -337,12 +358,14 @@ "NRG", "ETH", "ERC", + "EVR", "EVRTEST", "EXCL", "FIX", "FIXTEST", "FLUX", "FTC", "FRST", "FLASH", + "FOXD", "FOXDTEST", "FJC", "GCR", "GAME", @@ -370,6 +393,7 @@ "MEC", "MNX", "MONA", + "MATIC", "MONK", "XMY", "NIX", @@ -397,7 +421,7 @@ "QTUM", "QTUMTEST", "RBTC", "RBTCTEST", "RPD", - "RVN", + "RVN", "RVNTEST", "RDD", "RBY", "SAFE", diff --git a/hdwallet/version.py b/hdwallet/version.py new file mode 100644 index 00000000..f934d459 --- /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 00000000..7880ec3d --- /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 00000000..a6a72213 --- /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 00000000..bc210ece --- /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 00000000..c77b2466 --- /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 00000000..7f50a1f2 --- /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 5887f801..ad551687 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ecdsa>=0.13,<1 -mnemonic>=0.19,<1 -pycryptodome>=3.15,<4 -base58>=2.0.1,<3 +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 728237b7..9912180b 100644 --- a/setup.py +++ b/setup.py @@ -11,16 +11,27 @@ } # 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="v2.2.1", + 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, @@ -28,7 +39,7 @@ license="MIT", author="Meheret Tesfaye Batu", author_email="meherett.batu@gmail.com", - url="https://github.com/meherett/python-hdwallet", + url="https://github.com/pjkundert/python-hdwallet", project_urls=project_urls, keywords=[ "cryptography", "cli", "wallet", "bip32", "bip44", "bip39", "hdwallet", "cryptocurrencies", "bitcoin", "ethereum" @@ -38,32 +49,18 @@ }, python_requires=">=3.6,<4", packages=find_packages(), - install_requires=requirements, - extras_require={ - "cli": [ - "click>=8.1.3,<9", - "click-aliases>=1.0.1,<2", - "tabulate>=0.9.0,<1" - ], - "tests": [ - "pytest>=7.2.0,<8", - "pytest-cov>=4.0.0,<5", - "tox==3.28.0" - ], - "docs": [ - "sphinx>=5.3.0,<6", - "furo==2022.12.7", - "sphinx-click>=4.4.0,<5" - ] - }, + 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.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 00000000..aab28b37 --- /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!" + ''; +}