From 3869c07711c8dfa03d100e3abfe2cce65809429b Mon Sep 17 00:00:00 2001 From: meherett Date: Fri, 11 Jun 2021 22:52:06 +0300 Subject: [PATCH 01/23] Update: Testing doc and added development doc. --- README.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6893e2e7..0d7aed32 100644 --- a/README.md +++ b/README.md @@ -185,15 +185,24 @@ 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) -## Running test cases -Install the requirements -```python -pip install -e .[tests] -r requirements.txt +## Development + +To get started, just fork this repo, clone it locally, and run: + ``` -Run -```python -pytest tests/ +$ pip install -e .[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 From e630169666c012fc40cb15290711efdeadbff0ca Mon Sep 17 00:00:00 2001 From: meherett Date: Fri, 18 Jun 2021 17:11:01 +0300 Subject: [PATCH 02/23] Add: Root xpublic key derivation cleaner. --- hdwallet/hdwallet.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 5e226b7f..369d2135 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -719,13 +719,21 @@ def clean_derivation(self) -> "HDWallet": None """ - if self._i: + if self._root_private_key: self._path, self._depth, self._parent_fingerprint, self._index = ( "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._depth, self._parent_fingerprint, self._index = ( + "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: From 98b15fd9acba32877869b854f809c8ce01afcc97 Mon Sep 17 00:00:00 2001 From: meherett Date: Fri, 18 Jun 2021 17:15:07 +0300 Subject: [PATCH 03/23] Bump: HDWallet from v1.3.0 to v1.3.1 package. --- docs/conf.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 187c00e7..6b42da86 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ author = "Meheret Tesfaye" # The full version, including alpha/beta/rc tags -release = "1.3.0" +release = "1.3.1" # The master toctree document. master_doc = "toctree" diff --git a/setup.py b/setup.py index 62190794..29fde437 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name="hdwallet", - version="1.3.0", + version="1.3.1", description="Python-based library for the implementation of a " "hierarchical deterministic wallet generator for more than 140+ multiple cryptocurrencies.", long_description=long_description, From 749bf8c702dacb3b4e8d0cf78164aeb1f1ae5d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Hol=C3=BD?= Date: Tue, 22 Jun 2021 12:31:26 +0200 Subject: [PATCH 04/23] Fix: Incorrect output of Base58 decoding. --- hdwallet/libs/base58.py | 13 ++++++++----- tests/test_base58.py | 8 +++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hdwallet/libs/base58.py b/hdwallet/libs/base58.py index 98f0a39b..c025f8b5 100644 --- a/hdwallet/libs/base58.py +++ b/hdwallet/libs/base58.py @@ -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/tests/test_base58.py b/tests/test_base58.py index 2b602c08..f321e765 100644 --- a/tests/test_base58.py +++ b/tests/test_base58.py @@ -7,7 +7,7 @@ import pytest from hdwallet.libs.base58 import ( - check_encode, check_decode, string_to_int + check_encode, check_decode, decode, encode, string_to_int ) @@ -29,3 +29,9 @@ 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" From fcb16c730d62decb50d6d006487db3520d1cf9ea Mon Sep 17 00:00:00 2001 From: saloppe73 Date: Thu, 22 Jul 2021 03:19:35 +0200 Subject: [PATCH 05/23] add ZECTEST --- hdwallet/cryptocurrencies.py | 40 ++++++++++++++++++++++++++++++++++++ hdwallet/symbols.py | 4 ++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index 1099f4b5..cadcc6ba 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -6274,6 +6274,46 @@ class ZcashMainnet(Cryptocurrency): WIF_SECRET_KEY = 0x80 +class ZcashTestnet(Cryptocurrency): + + NAME = "Zcash" + SYMBOL = "ZECTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/zcash/zcashn" + 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 + }) + + MASSAGE_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" diff --git a/hdwallet/symbols.py b/hdwallet/symbols.py index e90c4621..be3a03d3 100644 --- a/hdwallet/symbols.py +++ b/hdwallet/symbols.py @@ -275,7 +275,7 @@ # ZClassic ZCL = "ZCL" # Zcash -ZEC = "ZEC" +ZEC, ZECTEST = "ZEC", "ZECTEST" # Zencash ZEN = "ZEN" @@ -418,6 +418,6 @@ "XUEZ", "XDC", "ZCL", - "ZEC", + "ZEC", "ZECTEST" "ZEN" ] From 697e9e72b2ca79cd8723807d947040a7fef3fe0a Mon Sep 17 00:00:00 2001 From: saloppe73 Date: Thu, 22 Jul 2021 03:33:12 +0200 Subject: [PATCH 06/23] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d7aed32..48cca639 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ This library simplifies the process of creating a new HDWallet's for: | 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` | +| [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 From b876ad42b4606cb911ef2506ce8eb8ef7d0f81bf Mon Sep 17 00:00:00 2001 From: saloppe73 Date: Thu, 22 Jul 2021 05:34:53 +0200 Subject: [PATCH 07/23] fix LTC/LTCTEST --- README.md | 2 +- hdwallet/cryptocurrencies.py | 42 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 48cca639..9cb0ca96 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ This library simplifies the process of creating a new HDWallet's for: | 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](https://github.com/zcash/zcash) | `ZEC`, `ZECTEST` | Yes | YES | No | 133 | `m/44'/133'/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 diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index cadcc6ba..d54f6447 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -3213,18 +3213,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 +3245,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): @@ -6239,7 +6239,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 @@ -6279,7 +6279,7 @@ class ZcashTestnet(Cryptocurrency): NAME = "Zcash" SYMBOL = "ZECTEST" NETWORK = "testnet" - SOURCE_CODE = "https://github.com/zcash/zcashn" + SOURCE_CODE = "https://github.com/zcash/zcash" COIN_TYPE = CoinType({ "INDEX": 1, "HARDENED": True From a480596a58993ccd869a73f72978eb3e0869ba9c Mon Sep 17 00:00:00 2001 From: Meheret Tesfaye Date: Mon, 26 Jul 2021 21:05:52 +0300 Subject: [PATCH 08/23] Update README.md --- README.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9cb0ca96..b23f6eba 100644 --- a/README.md +++ b/README.md @@ -363,17 +363,11 @@ This library simplifies the process of creating a new HDWallet's for: If You found this tool helpful consider making a donation: -Ethereum (ETH) or Tether (USDT-ERC20) address: - -```text -0x342798bbe9731a91e0557fa8ab0bce1eae6d6ae3 -``` - -Bitcoin (BTC) address: - -```text -3GGNPvgbSpMHShcaZJGDXQn5wUJyTz7uoC -``` +| Coins | Addresses | +| ----------------------------- | :----------------------------------------: | +| Bitcoin `BTC` | 3GGNPvgbSpMHShcaZJGDXQn5wUJyTz7uoC | +| Ethereum `ETH`, Tether `USDT` | 0x342798bbe9731a91e0557fa8ab0bce1eae6d6ae3 | +| Bytom `BTM` | bm1qhpzc42ahrsahmpranv6xddc74tk6wlrvxrw68c | ## License From e79db28a094126d058ac4662935e8e3b96084223 Mon Sep 17 00:00:00 2001 From: sokripon Date: Thu, 12 Aug 2021 16:58:57 +0200 Subject: [PATCH 09/23] Fixed BIP141 link Corrected the spec link for BIP141. --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index b59b75ce..66289d89 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,5 +26,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) From 78517c5e1e57114ed6652c0fe845b2e4a61492e1 Mon Sep 17 00:00:00 2001 From: sokripon Date: Thu, 12 Aug 2021 17:08:29 +0200 Subject: [PATCH 10/23] Fixed link for BIP84 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b23f6eba..623f5863 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ 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 | +| [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-0014.mediawiki) | Segregated Witness (Consensus layer) | ## Installation From 8da78de5d139a98599628064920102332a208d01 Mon Sep 17 00:00:00 2001 From: sokripon Date: Thu, 12 Aug 2021 17:08:52 +0200 Subject: [PATCH 11/23] Fixed link for BIP141 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 623f5863..8bd138f3 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ For more info see the BIP specs. | [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-0084.mediawiki) | Derivation scheme for P2WPKH based accounts | -| [BIP141](https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) | Segregated Witness (Consensus layer) | +| [BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) | Segregated Witness (Consensus layer) | ## Installation From 71620d2ee9e693f24a9bc4d12f50396a4d9b1b12 Mon Sep 17 00:00:00 2001 From: meherett Date: Thu, 2 Sep 2021 07:36:33 +0300 Subject: [PATCH 12/23] Bump: HDWallet from v1.3.1 to v1.3.2 package. --- README.md | 9 ++++----- setup.py | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8bd138f3..7775906d 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Coverage Status](https://coveralls.io/repos/github/meherett/python-hdwallet/badge.svg?branch=master)](https://coveralls.io/github/meherett/python-hdwallet?branch=master) 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. For more info see the BIP specs. @@ -190,7 +190,7 @@ Base HD Path: m/44'/60'/0'/0/{address_index} To get started, just fork this repo, clone it locally, and run: ``` -$ pip install -e .[tests,docs] -r requirements.txt +pip install -e .[tests,docs] -r requirements.txt ``` ## Testing @@ -198,7 +198,7 @@ $ pip install -e .[tests,docs] -r requirements.txt You can run the tests with: ``` -$ pytest +pytest ``` Or use `tox` to run the complete suite against the full set of build targets, or pytest to run specific @@ -215,7 +215,7 @@ For more information, see the [CONTRIBUTING.md](https://github.com/meherett/hdwa ## Available Cryptocurrencies -This library simplifies the process of creating a new HDWallet's for: +This library simplifies the process of creating a new hierarchical deterministic wallets for: | Cryptocurrencies | Symbols | Mainnet | Testnet | Segwit | Coin Type | Default Paths | | :---------------------------------------------------------------- | :------------------: | :-----: | :-----: | :----: | :-------: | :------------------: | @@ -367,7 +367,6 @@ If You found this tool helpful consider making a donation: | ----------------------------- | :----------------------------------------: | | Bitcoin `BTC` | 3GGNPvgbSpMHShcaZJGDXQn5wUJyTz7uoC | | Ethereum `ETH`, Tether `USDT` | 0x342798bbe9731a91e0557fa8ab0bce1eae6d6ae3 | -| Bytom `BTM` | bm1qhpzc42ahrsahmpranv6xddc74tk6wlrvxrw68c | ## License diff --git a/setup.py b/setup.py index 29fde437..8d174557 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ setup( name="hdwallet", - version="1.3.1", + version="1.3.2", description="Python-based library for the implementation of a " "hierarchical deterministic wallet generator for more than 140+ multiple cryptocurrencies.", long_description=long_description, @@ -23,7 +23,7 @@ author="Meheret Tesfaye", author_email="meherett@zoho.com", url="https://github.com/meherett/python-hdwallet", - keywords=["cryptography", "hd", "bip32", "bip44", "bip39", "wallet", "cryptocurrencies"], + keywords=["cryptography", "hd", "bip32", "bitcoin", "bip44", "bip39", "wallet", "hdwallet", "cryptocurrencies"], python_requires=">=3.6,<4", packages=find_packages(), install_requires=requirements, From 0fa4a5288d624b1466ef7d91c282e721c23f1f89 Mon Sep 17 00:00:00 2001 From: meherett Date: Thu, 2 Sep 2021 08:05:43 +0300 Subject: [PATCH 13/23] Fix: Zcash symbol ticker and added symbols tester. --- hdwallet/symbols.py | 2 +- tests/test_symbols.py | 164 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 tests/test_symbols.py diff --git a/hdwallet/symbols.py b/hdwallet/symbols.py index be3a03d3..0f3dcbf0 100644 --- a/hdwallet/symbols.py +++ b/hdwallet/symbols.py @@ -418,6 +418,6 @@ "XUEZ", "XDC", "ZCL", - "ZEC", "ZECTEST" + "ZEC", "ZECTEST", "ZEN" ] diff --git a/tests/test_symbols.py b/tests/test_symbols.py new file mode 100644 index 00000000..9177211b --- /dev/null +++ b/tests/test_symbols.py @@ -0,0 +1,164 @@ +# !/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 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 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 ZCL == "ZCL" + assert ZEC == "ZEC" + assert ZECTEST == "ZECTEST" + assert ZEN == "ZEN" From d7488efe50d697adc37422d2ff7371bcb4a17114 Mon Sep 17 00:00:00 2001 From: meherett Date: Thu, 2 Sep 2021 08:07:10 +0300 Subject: [PATCH 14/23] Bump: HDWallet from v1.3.1 to v1.3.2 package. --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6b42da86..0c5a95ba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ author = "Meheret Tesfaye" # The full version, including alpha/beta/rc tags -release = "1.3.1" +release = "1.3.2" # The master toctree document. master_doc = "toctree" From 500d840fa7223ebe869a5375a0181461f060754d Mon Sep 17 00:00:00 2001 From: meherett Date: Thu, 2 Sep 2021 08:42:30 +0300 Subject: [PATCH 15/23] Change: Coveralls runner python package version to 3.8 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 32023d42..c22e731a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ matrix: - 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 +after_success: if [ "${TRAVIS_PYTHON_VERSION}" == "3.8" ]; then coveralls; fi; \ No newline at end of file From 3b76caf6021be0dcf416498e5e2828ad783c0e37 Mon Sep 17 00:00:00 2001 From: meherett Date: Thu, 2 Sep 2021 08:46:02 +0300 Subject: [PATCH 16/23] Change: Coveralls runner python form v3.8 to v3.9 package. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c22e731a..32023d42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ matrix: - name: "3.9" python: 3.9 script: pytest -after_success: if [ "${TRAVIS_PYTHON_VERSION}" == "3.8" ]; then coveralls; fi; \ No newline at end of file +after_success: if [ "${TRAVIS_PYTHON_VERSION}" == "3.9" ]; then coveralls; fi; \ No newline at end of file From 41b6a01531b69c9507424e3a75023ab2f60a2565 Mon Sep 17 00:00:00 2001 From: Beomsoo Kim Date: Mon, 13 Sep 2021 13:12:15 +0900 Subject: [PATCH 17/23] Added version info --- hdwallet/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hdwallet/__init__.py b/hdwallet/__init__.py index ce4c736e..68a9e070 100644 --- a/hdwallet/__init__.py +++ b/hdwallet/__init__.py @@ -7,3 +7,5 @@ __all__ = [ "HDWallet", "BIP32HDWallet", "BIP44HDWallet", "BIP49HDWallet", "BIP84HDWallet", "BIP141HDWallet" ] + +__version__ = "1.3.2" From b8ce96812b6b8b33efaec2846186c19eee489f40 Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Fri, 8 Oct 2021 16:13:21 -0300 Subject: [PATCH 18/23] Fix derivation from xpubs This small patch fixes a check in order to allow arbitrary xpubs to be derived from without the need for root xpub/xprvs. --- hdwallet/hdwallet.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 369d2135..8834fca5 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -484,8 +484,12 @@ 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.") + if not self._public_key \ + and not self._chain_code \ + and not self._depth \ + and not self._index \ + and not self._parent_fingerprint: + raise ValueError("You can't drive this master key.") i_str = struct.pack(">L", index) if index & BIP32KEY_HARDEN: From 01aa68309d75c61aacdc6b6f4b5c59ca6e5110b2 Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Fri, 8 Oct 2021 16:21:11 -0300 Subject: [PATCH 19/23] Add a testcase for xpub derivation --- tests/test_from_xpublic_key.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_from_xpublic_key.py b/tests/test_from_xpublic_key.py index d8b90551..b0225958 100644 --- a/tests/test_from_xpublic_key.py +++ b/tests/test_from_xpublic_key.py @@ -4,6 +4,7 @@ import os from hdwallet import HDWallet +from hdwallet.utils import generate_entropy # Test Values base_path: str = os.path.dirname(__file__) @@ -81,3 +82,11 @@ def test_from_xpublic_key(): del dumps["xpublic_key_hex"] assert hdwallet.dumps() == dumps + +def test_derivation_from_xpublic_key(): + hdwallet: HDWallet = HDWallet().from_entropy(generate_entropy()) + wallet1: HDWallet = hdwallet.from_path("m/1'/2'/3'") + xpub: str = wallet1.xpublic_key() + wallet2: HDWallet = HDWallet().from_xpublic_key(xpub) + assert wallet1.xpublic_key() == wallet2.xpublic_key() + assert wallet1.from_path("m/1/2/3").xpublic_key() == wallet2.from_path("m/1/2/3").xpublic_key() From 30330b848147b1fd01583930b6a1dee55eb5b2cb Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Wed, 19 Jan 2022 19:29:18 -0300 Subject: [PATCH 20/23] Add support for DeSo - New entries in cryptocurrencies.py; - New {public,private}_key_base58check fields. --- docs/cryptocurrencies.rst | 7 +++ hdwallet/cryptocurrencies.py | 85 +++++++++++++++++++++++++++++++++++- hdwallet/hdwallet.py | 33 ++++++++++++++ hdwallet/symbols.py | 3 ++ tests/test_symbols.py | 2 + 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/docs/cryptocurrencies.rst b/docs/cryptocurrencies.rst index 81650354..cad1f47e 100644 --- a/docs/cryptocurrencies.rst +++ b/docs/cryptocurrencies.rst @@ -276,6 +276,13 @@ This library simplifies the process of generating a new HDWallet's for: - No - 116 - m/44'/116'/0'/0/0 + * - `DeSo `_ + - DESO, DESOTEST + - Yes + - Yes + - Yes + - 0 + - m/44'/0'/0'/0/0 * - Diamond - DMD - Yes diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index d54f6447..bfb78a12 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -63,7 +63,8 @@ class Cryptocurrency(NestedNamespace): COIN_TYPE: CoinType SCRIPT_ADDRESS: int - PUBLIC_KEY_ADDRESS: int + PUBLIC_KEY_ADDRESS: int = 0 + PRIVATE_KEY_ADDRESS: int = 0 SEGWIT_ADDRESS: SegwitAddress EXTENDED_PRIVATE_KEY: ExtendedPrivateKey @@ -1674,6 +1675,88 @@ class DenariusMainnet(Cryptocurrency): WIF_SECRET_KEY = 0x9e +class DeSoMainnet(Cryptocurrency): + + NAME = "DeSo" + SYMBOL = "DESO" + NETWORK = "mainnet" + SOURCE_CODE = "https://github.com/deso-protocol" + COIN_TYPE = CoinType({ + "INDEX": 0, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0xCD1400 + PRIVATE_KEY_ADDRESS = 0x350000 + 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 = "\x18DeSo Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + +class DeSoTestnet(Cryptocurrency): + + NAME = "DeSo" + SYMBOL = "DESOTEST" + NETWORK = "testnet" + SOURCE_CODE = "https://github.com/deso-protocol" + COIN_TYPE = CoinType({ + "INDEX": 0, + "HARDENED": True + }) + + SCRIPT_ADDRESS = 0x05 + PUBLIC_KEY_ADDRESS = 0x11C200 + PRIVATE_KEY_ADDRESS = 0x4F061B + 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 = "\x18DeSo Signed Message:\n" + DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" + WIF_SECRET_KEY = 0x80 + + class DiamondMainnet(Cryptocurrency): NAME = "Diamond" diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 8834fca5..5853d062 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -112,6 +112,10 @@ def __init__(self, symbol: str = "BTC", cryptocurrency: Any = None, self._private_key: Optional[bytes] = None self._public_key: Optional[str] = None self._chain_code: Optional[bytes] = None + + self._private_key_base58check: Optional[str] = None + self._public_key_base58check: Optional[str] = None + self._depth: int = 0 self._index: int = 0 @@ -211,6 +215,8 @@ def from_seed(self, seed: str) -> "HDWallet": if self._use_default_path: self.from_path(path=self._cryptocurrency.DEFAULT_PATH) self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() + self._private_key_base58check = self.private_key_base58check() if self._from_class: self.from_path(path=self._path_class) return self @@ -251,6 +257,8 @@ 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._public_key_base58check = self.public_key_base58check() + self._private_key_base58check = self.private_key_base58check() return self def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWallet": @@ -289,6 +297,7 @@ def from_root_xpublic_key(self, xpublic_key: str, strict: bool = True) -> "HDWal if self._from_class: self.from_path(path=self._path_class) self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() return self def from_xprivate_key(self, xprivate_key: str) -> "HDWallet": @@ -317,6 +326,8 @@ def from_xprivate_key(self, xprivate_key: str) -> "HDWallet": 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() + self._public_key_base58check = self.public_key_base58check() + self._private_key_base58check = self.private_key_base58check() return self def from_xpublic_key(self, xpublic_key: str) -> "HDWallet": @@ -346,6 +357,7 @@ def from_xpublic_key(self, xpublic_key: str) -> "HDWallet": _deserialize_xpublic_key[5], curve=SECP256k1 ) self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() return self def from_wif(self, wif: str) -> "HDWallet": @@ -372,6 +384,8 @@ def from_wif(self, wif: str) -> "HDWallet": self._key = ecdsa.SigningKey.from_string(self._private_key, curve=SECP256k1) self._verified_key = self._key.get_verifying_key() self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() + self._private_key_base58check = self.private_key_base58check() return self def from_private_key(self, private_key: str) -> "HDWallet": @@ -394,6 +408,8 @@ def from_private_key(self, private_key: str) -> "HDWallet": self._key = ecdsa.SigningKey.from_string(self._private_key, curve=SECP256k1) self._verified_key = self._key.get_verifying_key() self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() + self._private_key_base58check = self.private_key_base58check() return self def from_public_key(self, public_key: str) -> "HDWallet": @@ -416,6 +432,7 @@ def from_public_key(self, public_key: str) -> "HDWallet": unhexlify(public_key), curve=SECP256k1 ) self._public_key = self.compressed() + self._public_key_base58check = self.public_key_base58check() return self def from_path(self, path: Union[str, Derivation]) -> "HDWallet": @@ -521,6 +538,7 @@ def _derive_key_by_index(self, index) -> Optional["HDWallet"]: ) self._key = ecdsa.SigningKey.from_string(self._private_key, curve=SECP256k1) self._verified_key = self._key.get_verifying_key() + self._private_key_base58check = self.private_key_base58check() else: key_point = S256Point.parse(unhexlify(self.public_key())) left_point = il_int * G @@ -730,6 +748,7 @@ def clean_derivation(self) -> "HDWallet": 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() + self._private_key_base58check = self.private_key_base58check() elif self._root_public_key: self._path, self._depth, self._parent_fingerprint, self._index = ( "m", 0, b"\0\0\0\0", 0 @@ -847,6 +866,18 @@ def public_key(self, compressed: bool = True, private_key: Optional[str] = None) return hexlify(ck).decode() if compressed else self.uncompressed(compressed=hexlify(ck).decode()) return self.compressed() if compressed else self.uncompressed() + def public_key_base58check(self) -> str: + return base58.b58encode_check( + _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + + unhexlify(self.public_key()) + ) + + def private_key_base58check(self) -> str: + return base58.b58encode_check( + _unhexlify(self._cryptocurrency.PRIVATE_KEY_ADDRESS) + + unhexlify(self.private_key()) + ) + def strength(self) -> Optional[int]: """ Get Entropy strength. @@ -1281,6 +1312,8 @@ def dumps(self) -> dict: semantic=self.semantic(), path=self.path(), hash=self.hash(), + public_key_base58check=self.public_key_base58check(), + private_key_base58check=self.private_key_base58check(), addresses=dict( p2pkh=self.p2pkh_address(), p2sh=self.p2sh_address(), diff --git a/hdwallet/symbols.py b/hdwallet/symbols.py index 0f3dcbf0..2eae6344 100644 --- a/hdwallet/symbols.py +++ b/hdwallet/symbols.py @@ -74,6 +74,8 @@ DFC = "DFC" # Denarius DNR = "DNR" +# DeSo +DESO, DESOTEST = "DESO", "DESOTEST" # Diamond DMD = "DMD" # Digi Byte @@ -316,6 +318,7 @@ "CRAVE", "DASH", "DASHTEST", "ONION", + "DESO", "DESOTEST", "DFC", "DNR", "DMD", diff --git a/tests/test_symbols.py b/tests/test_symbols.py index 9177211b..86413d6f 100644 --- a/tests/test_symbols.py +++ b/tests/test_symbols.py @@ -45,6 +45,8 @@ def test_symbols(): assert ONION == "ONION" assert DFC == "DFC" assert DNR == "DNR" + assert DESO == "DESO" + assert DESOTEST == "DESOTEST" assert DMD == "DMD" assert DGB == "DGB" assert DGC == "DGC" From aa0c4a3131320a131fe521e8f55dbcaa647ab46a Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Wed, 26 Jan 2022 16:19:16 -0300 Subject: [PATCH 21/23] Convert bytes to str in *_base58check() --- hdwallet/hdwallet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 5853d062..ac31e3a0 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -870,13 +870,13 @@ def public_key_base58check(self) -> str: return base58.b58encode_check( _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + unhexlify(self.public_key()) - ) + ).decode() def private_key_base58check(self) -> str: return base58.b58encode_check( _unhexlify(self._cryptocurrency.PRIVATE_KEY_ADDRESS) + unhexlify(self.private_key()) - ) + ).decode() def strength(self) -> Optional[int]: """ From 075f7390004bcd3c58e6663f0a987afa2a34eebc Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Wed, 23 Feb 2022 22:40:46 -0300 Subject: [PATCH 22/23] Updates - Introduce `DEFAULT_SEMANTIC` to cryptocurrency description; - Introduce `"base58check"` semantic (for DeSo); - Introduce `address()` in `HDWallet`; - Fix xpub/xprv address prefixes for DESOTEST. The default semantic for Bitcoin is "p2wpkh". --- hdwallet/cryptocurrencies.py | 54 +++++++++--------------------------- hdwallet/hdwallet.py | 38 ++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/hdwallet/cryptocurrencies.py b/hdwallet/cryptocurrencies.py index bfb78a12..baff6d16 100644 --- a/hdwallet/cryptocurrencies.py +++ b/hdwallet/cryptocurrencies.py @@ -62,17 +62,19 @@ class Cryptocurrency(NestedNamespace): SOURCE_CODE: Optional[str] COIN_TYPE: CoinType - SCRIPT_ADDRESS: int + SCRIPT_ADDRESS: Optional[int] = None PUBLIC_KEY_ADDRESS: int = 0 PRIVATE_KEY_ADDRESS: int = 0 - SEGWIT_ADDRESS: SegwitAddress + SEGWIT_ADDRESS: Optional[SegwitAddress] = None EXTENDED_PRIVATE_KEY: ExtendedPrivateKey EXTENDED_PUBLIC_KEY: ExtendedPublicKey MESSAGE_PREFIX: Optional[str] DEFAULT_PATH: str - WIF_SECRET_KEY: int + WIF_SECRET_KEY: Optional[int] = None + + DEFAULT_SEMANTIC: str = "p2pkh" class AnonMainnet(Cryptocurrency): @@ -713,6 +715,7 @@ class BitcoinMainnet(Cryptocurrency): MESSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0x80 + DEFAULT_SEMANTIC = "p2wpkh" class BitcoinPlusMainnet(Cryptocurrency): @@ -833,6 +836,7 @@ class BitcoinTestnet(Cryptocurrency): MESSAGE_PREFIX = "\x18Bitcoin Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" WIF_SECRET_KEY = 0xef + DEFAULT_SEMANTIC = "p2wpkh" class BitcoinZMainnet(Cryptocurrency): @@ -1686,34 +1690,18 @@ class DeSoMainnet(Cryptocurrency): "HARDENED": True }) - SCRIPT_ADDRESS = 0x05 PUBLIC_KEY_ADDRESS = 0xCD1400 PRIVATE_KEY_ADDRESS = 0x350000 - 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 + "BASE58CHECK": 0x0488ade4 }) EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ - "P2PKH": 0x0488b21e, - "P2SH": 0x0488b21e, - "P2WPKH": 0x04b24746, - "P2WPKH_IN_P2SH": 0x049d7cb2, - "P2WSH": 0x02aa7ed3, - "P2WSH_IN_P2SH": 0x0295b43f + "BASE58CHECK": 0x0488b21e }) MESSAGE_PREFIX = "\x18DeSo Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0x80 + DEFAULT_SEMANTIC = "base58check" class DeSoTestnet(Cryptocurrency): @@ -1727,34 +1715,18 @@ class DeSoTestnet(Cryptocurrency): "HARDENED": True }) - SCRIPT_ADDRESS = 0x05 PUBLIC_KEY_ADDRESS = 0x11C200 PRIVATE_KEY_ADDRESS = 0x4F061B - 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 + "BASE58CHECK": 0x04358394 }) EXTENDED_PUBLIC_KEY = ExtendedPublicKey({ - "P2PKH": 0x0488b21e, - "P2SH": 0x0488b21e, - "P2WPKH": 0x04b24746, - "P2WPKH_IN_P2SH": 0x049d7cb2, - "P2WSH": 0x02aa7ed3, - "P2WSH_IN_P2SH": 0x0295b43f + "BASE58CHECK": 0x043587cf }) MESSAGE_PREFIX = "\x18DeSo Signed Message:\n" DEFAULT_PATH = f"m/44'/{str(COIN_TYPE)}/0'/0/0" - WIF_SECRET_KEY = 0x80 + DEFAULT_SEMANTIC = "base58check" class DiamondMainnet(Cryptocurrency): diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index ac31e3a0..96f4da97 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -67,7 +67,7 @@ class HDWallet: :type symbol: str :param cryptocurrency: Cryptocurrency instance, defaults to ``None``. :type cryptocurrency: Cryptocurrency - :param semantic: Extended semantic, defaults to ``P2PKH``. + :param semantic: Extended semantic :type semantic: str :param use_default_path: Use default derivation path, defaults to ``False``. :type use_default_path: bool @@ -79,7 +79,7 @@ class HDWallet: """ def __init__(self, symbol: str = "BTC", cryptocurrency: Any = None, - semantic: str = "p2pkh", use_default_path: bool = False): + semantic: str = None, use_default_path: bool = False): self._cryptocurrency: Any = None if cryptocurrency: if not issubclass(cryptocurrency, Cryptocurrency): @@ -88,6 +88,9 @@ def __init__(self, symbol: str = "BTC", cryptocurrency: Any = None, else: self._cryptocurrency: Any = get_cryptocurrency(symbol=symbol) + if semantic is None: + semantic = self._cryptocurrency.DEFAULT_SEMANTIC + self._strength: Optional[int] = None self._entropy: Optional[str] = None self._mnemonic: Optional[str] = None @@ -878,6 +881,9 @@ def private_key_base58check(self) -> str: unhexlify(self.private_key()) ).decode() + def base58check_address(self) -> str: + return self.public_key_base58check() + def strength(self) -> Optional[int]: """ Get Entropy strength. @@ -1142,7 +1148,7 @@ def p2pkh_address(self) -> str: network_hash160_bytes = _unhexlify(self._cryptocurrency.PUBLIC_KEY_ADDRESS) + public_key_hash return ensure_string(base58.b58encode_check(network_hash160_bytes)) - def p2sh_address(self) -> str: + def p2sh_address(self) -> Optional[str]: """ Get Pay to Script Hash (P2SH) address. @@ -1157,6 +1163,9 @@ def p2sh_address(self) -> str: "3Jp6ad4ErhibQmhSRfavbPRiUyg2xTTT4j" """ + if self._cryptocurrency.SCRIPT_ADDRESS is None: + return None + compressed_public_key = unhexlify(self.compressed()) public_key_hash = hashlib.new('ripemd160', sha256(compressed_public_key).digest()).hexdigest() public_key_hash_script = unhexlify("76a914" + public_key_hash + "88ac") @@ -1181,6 +1190,8 @@ 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 is None: + return None if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: return None return ensure_string(encode(self._cryptocurrency.SEGWIT_ADDRESS.HRP, 0, public_key_hash)) @@ -1200,10 +1211,15 @@ def p2wpkh_in_p2sh_address(self) -> Optional[str]: "3CCrxPrHNa6ePbnB7qjh7S3vaPx9qiLc3e" """ + if self._cryptocurrency.SCRIPT_ADDRESS is None: + return None + 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() network_hash160_bytes = _unhexlify(self._cryptocurrency.SCRIPT_ADDRESS) + script_hash + if self._cryptocurrency.SEGWIT_ADDRESS is None: + return None if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: return None return ensure_string(base58.b58encode_check(network_hash160_bytes)) @@ -1225,6 +1241,8 @@ 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 is None: + return None if self._cryptocurrency.SEGWIT_ADDRESS.HRP is None: return None return ensure_string(encode(self._cryptocurrency.SEGWIT_ADDRESS.HRP, 0, script_hash)) @@ -1244,6 +1262,9 @@ def p2wsh_in_p2sh_address(self) -> Optional[str]: "38YMonfh2yLFRViLrM2kdvZx8ctcp1vbbV" """ + if self._cryptocurrency.SCRIPT_ADDRESS is None: + return None + 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() @@ -1252,6 +1273,11 @@ def p2wsh_in_p2sh_address(self) -> Optional[str]: return None return ensure_string(base58.b58encode_check(network_hash160_bytes)) + def address(self, semantic=None): + if semantic == None: + semantic = self._cryptocurrency.DEFAULT_SEMANTIC + return getattr(self, f"{semantic}_address")() + def wif(self) -> Optional[str]: """ Get Wallet Important Format. @@ -1267,6 +1293,9 @@ def wif(self) -> Optional[str]: "KzsHWUJsrTWUUhBGPfMMxLLydiH7NhEn6z7mKHXD5qNkUWaC4TEn" """ + if self._cryptocurrency.WIF_SECRET_KEY is None: + return + return check_encode(_unhexlify(self._cryptocurrency.WIF_SECRET_KEY) + self._key.to_string() + b"\x01") if self._key else None def dumps(self) -> dict: @@ -1321,7 +1350,8 @@ def dumps(self) -> dict: p2wpkh_in_p2sh=self.p2wpkh_in_p2sh_address(), p2wsh=self.p2wsh_address(), p2wsh_in_p2sh=self.p2wsh_in_p2sh_address() - ) + ), + address=self.address() ) From 166f7aee3e9bb43fead9f9446997148821141783 Mon Sep 17 00:00:00 2001 From: Aleksey Covacevice Date: Mon, 14 Mar 2022 16:10:01 -0300 Subject: [PATCH 23/23] Add missing check in `private_key_base58check()` --- hdwallet/hdwallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdwallet/hdwallet.py b/hdwallet/hdwallet.py index 96f4da97..721714e5 100644 --- a/hdwallet/hdwallet.py +++ b/hdwallet/hdwallet.py @@ -879,7 +879,7 @@ def private_key_base58check(self) -> str: return base58.b58encode_check( _unhexlify(self._cryptocurrency.PRIVATE_KEY_ADDRESS) + unhexlify(self.private_key()) - ).decode() + ).decode() if self.private_key() is not None else None def base58check_address(self) -> str: return self.public_key_base58check()