mm-btc 0.1.2__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mm_btc/wallet.py CHANGED
@@ -1,8 +1,12 @@
1
1
  from dataclasses import dataclass
2
+ from enum import Enum, unique
2
3
 
3
- from hdwallet import BIP44HDWallet, BIP84HDWallet
4
- from hdwallet.symbols import BTC, BTCTEST
5
- from hdwallet.utils import generate_mnemonic as new_mnemonic
4
+ from hdwallet import HDWallet
5
+ from hdwallet.cryptocurrencies import Bitcoin
6
+ from hdwallet.derivations import CustomDerivation
7
+ from hdwallet.hds import BIP32HD
8
+ from hdwallet.mnemonics import BIP39Mnemonic
9
+ from mnemonic import Mnemonic
6
10
 
7
11
  BIP44_MAINNET_PATH = "m/44'/0'/0'/0"
8
12
  BIP44_TESTNET_PATH = "m/44'/1'/0'/0"
@@ -18,30 +22,45 @@ class Account:
18
22
  path: str
19
23
 
20
24
 
25
+ @unique
26
+ class AddressType(str, Enum):
27
+ P2PKH = "P2PKH" # Pay to Public Key Hash
28
+ P2SH = "P2SH" # Pay to Script Hash
29
+ P2TR = "P2TR" # Taproot
30
+ P2WPKH = "P2WPKH" # Native SegWit
31
+ P2WPKH_IN_P2SH = "P2WPKH-In-P2SH"
32
+ P2WSH = "P2WSH" # Native SegWit
33
+ P2WSH_IN_P2SH = "P2WSH-In-P2SH"
34
+
35
+
21
36
  def generate_mnemonic(language: str = "english", words: int = 12) -> str:
22
- strength = mnemonic_words_to_strenght(words)
23
- return new_mnemonic(language=language, strength=strength) # type: ignore[no-any-return]
24
-
25
-
26
- def derive_accounts(mnemonic: str, passphrase: str, path: str, limit: int) -> list[Account]:
27
- if path.startswith("m/84'/1'"):
28
- w = BIP84HDWallet(symbol=BTCTEST)
29
- elif path.startswith("m/44'/1'"):
30
- w = BIP44HDWallet(symbol=BTCTEST)
31
- elif path.startswith("m/84'/0'"):
32
- w = BIP84HDWallet(symbol=BTC)
33
- elif path.startswith("m/44'/0'"):
34
- w = BIP44HDWallet(symbol=BTC)
37
+ return Mnemonic(language).generate(strength=mnemonic_words_to_strenght(words))
38
+
39
+
40
+ def derive_accounts(mnemonic: str, passphrase: str, path_prefix: str, address_type: AddressType, limit: int) -> list[Account]:
41
+ coin = Bitcoin
42
+ if path_prefix.startswith("m/84'/1'"):
43
+ network = coin.NETWORKS.TESTNET
44
+ elif path_prefix.startswith("m/44'/1'"):
45
+ network = coin.NETWORKS.TESTNET
46
+ elif path_prefix.startswith("m/84'/0'"):
47
+ network = coin.NETWORKS.MAINNET
48
+ elif path_prefix.startswith("m/44'/0'"):
49
+ network = coin.NETWORKS.MAINNET
35
50
  else:
36
51
  raise ValueError("Invalid path")
37
52
 
38
- w.from_mnemonic(mnemonic, passphrase=passphrase)
39
- w.clean_derivation()
53
+ wallet = HDWallet(cryptocurrency=coin, network=network, hd=BIP32HD, passphrase=passphrase).from_mnemonic(
54
+ BIP39Mnemonic(mnemonic)
55
+ )
56
+ wallet.clean_derivation()
40
57
 
41
58
  accounts = []
42
59
  for index_path in range(limit):
43
- w.from_path(path=f"{path}/{index_path}")
44
- accounts.append(Account(address=w.address(), private=w.private_key(), wif=w.wif(), path=f"{path}/{index_path}"))
60
+ wallet.clean_derivation()
61
+ path = f"{path_prefix}/{index_path}"
62
+ w = wallet.from_derivation(derivation=CustomDerivation(path=path))
63
+ accounts.append(Account(address=w.address(address_type), private=w.private_key(), wif=w.wif(), path=path))
45
64
  w.clean_derivation()
46
65
 
47
66
  return accounts
@@ -0,0 +1,9 @@
1
+ Metadata-Version: 2.4
2
+ Name: mm-btc
3
+ Version: 0.2.0
4
+ Requires-Python: >=3.12
5
+ Requires-Dist: bitcoinlib~=0.7.1
6
+ Requires-Dist: bit~=0.8.0
7
+ Requires-Dist: hdwallet~=3.2.0
8
+ Requires-Dist: mm-std~=0.1.9
9
+ Requires-Dist: mnemonic>=0.21
@@ -0,0 +1,8 @@
1
+ mm_btc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ mm_btc/blockstream.py,sha256=U2_pc6RYAkFcCvH_WrxjIm13VNavyY3WgK8ePowV-Ic,3620
3
+ mm_btc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ mm_btc/tx.py,sha256=7KTMNuL1n8rRj_245BV1bH9M2_PctNvlvPsLEsRTYx4,245
5
+ mm_btc/wallet.py,sha256=E9XKZMQx48JiGRDG8ij7cbilNPVmcpmS6jAGBzXfV9U,2475
6
+ mm_btc-0.2.0.dist-info/METADATA,sha256=drZ2vHDl89rFCn6SJDDaELptn97EiCTGnXIwD92rWXg,223
7
+ mm_btc-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ mm_btc-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.26.3
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
mm_btc/cli/__init__.py DELETED
File without changes
mm_btc/cli/cli.py DELETED
@@ -1,76 +0,0 @@
1
- from pathlib import Path
2
- from typing import Annotated
3
-
4
- import typer
5
- import typer.core
6
- from mm_std import print_plain
7
-
8
- from mm_btc.cli import cli_utils
9
- from mm_btc.cli.cmd import address_cmd, create_tx_cmd, decode_tx_cmd, mnemonic_cmd, utxo_cmd
10
-
11
- app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False, add_completion=False)
12
-
13
-
14
- @app.command("mnemonic")
15
- @app.command(name="m", hidden=True)
16
- def mnemonic_command( # nosec B107:hardcoded_password_default
17
- mnemonic: Annotated[str, typer.Option("--mnemonic", "-m", help="")] = "",
18
- passphrase: Annotated[str, typer.Option("--passphrase", "-p")] = "",
19
- path: Annotated[str, typer.Option("--path", help="Derivation path. Examples: bip44, bip88, m/44'/0'/0'/0")] = "bip44",
20
- hex_: Annotated[bool, typer.Option("--hex", help="Print private key in hex format instead of WIF")] = False,
21
- words: int = typer.Option(12, "--words", "-w", help="Number of mnemonic words"),
22
- limit: int = typer.Option(10, "--limit", "-l"),
23
- testnet: bool = typer.Option(False, "--testnet", "-t", help="Testnet network"),
24
- ) -> None:
25
- """Generate keys based on a mnemonic"""
26
- mnemonic_cmd.run(
27
- mnemonic_cmd.Args(
28
- mnemonic=mnemonic,
29
- passphrase=passphrase,
30
- words=words,
31
- limit=limit,
32
- path=path,
33
- hex=hex_,
34
- testnet=testnet,
35
- )
36
- )
37
-
38
-
39
- @app.command(name="address")
40
- @app.command(name="a", hidden=True)
41
- def address_command(address: str) -> None:
42
- """Get address info from Blockstream API"""
43
- address_cmd.run(address)
44
-
45
-
46
- @app.command("create-tx")
47
- def create_tx_command(config_path: Annotated[Path, typer.Argument(exists=True)]) -> None:
48
- """Create a transaction"""
49
- create_tx_cmd.run(config_path)
50
-
51
-
52
- @app.command("decode-tx")
53
- def decode_tx_command(tx_hex: str, testnet: Annotated[bool, typer.Option("--testnet", "-t")] = False) -> None:
54
- """Decode a transaction"""
55
- decode_tx_cmd.run(tx_hex, testnet)
56
-
57
-
58
- @app.command("utxo")
59
- def utxo_command(address: str) -> None:
60
- """Get UTXOs from Blockstream API"""
61
- utxo_cmd.run(address)
62
-
63
-
64
- def version_callback(value: bool) -> None:
65
- if value:
66
- print_plain(f"mm-btc: v{cli_utils.get_version()}")
67
- raise typer.Exit()
68
-
69
-
70
- @app.callback()
71
- def main(_version: bool = typer.Option(None, "--version", callback=version_callback, is_eager=True)) -> None:
72
- pass
73
-
74
-
75
- if __name__ == "__main_":
76
- app()
mm_btc/cli/cli_utils.py DELETED
@@ -1,5 +0,0 @@
1
- import importlib.metadata
2
-
3
-
4
- def get_version() -> str:
5
- return importlib.metadata.version("mm-btc")
File without changes
@@ -1,10 +0,0 @@
1
- from mm_std import print_json
2
-
3
- from mm_btc.blockstream import BlockstreamClient
4
- from mm_btc.wallet import is_testnet_address
5
-
6
-
7
- def run(address: str) -> None:
8
- client = BlockstreamClient(testnet=is_testnet_address(address))
9
- res = client.get_address(address)
10
- print_json(res)
@@ -1,27 +0,0 @@
1
- from pathlib import Path
2
-
3
- from bit import PrivateKey, PrivateKeyTestnet
4
- from mm_std import BaseConfig, print_console
5
-
6
- from mm_btc.wallet import is_testnet_address
7
-
8
-
9
- class Config(BaseConfig):
10
- class Output(BaseConfig):
11
- address: str
12
- amount: int
13
-
14
- from_address: str
15
- private: str
16
- outputs: list[Output]
17
-
18
-
19
- def run(config_path: Path) -> None:
20
- config = Config.read_config(config_path)
21
- testnet = is_testnet_address(config.from_address)
22
- key = PrivateKeyTestnet(config.private) if testnet else PrivateKey(config.private)
23
-
24
- outputs = [(o.address, o.amount, "satoshi") for o in config.outputs]
25
-
26
- tx = key.create_transaction(outputs)
27
- print_console(tx)
@@ -1,8 +0,0 @@
1
- from mm_std import print_json
2
-
3
- from mm_btc.tx import decode_tx
4
-
5
-
6
- def run(tx_hex: str, testnet: bool = False) -> None:
7
- res = decode_tx(tx_hex, testnet)
8
- print_json(res)
@@ -1,48 +0,0 @@
1
- from dataclasses import dataclass
2
- from enum import Enum
3
-
4
- from mm_std import print_plain
5
-
6
- from mm_btc.wallet import derive_accounts, generate_mnemonic
7
-
8
-
9
- class PrivateType(str, Enum):
10
- hex = "hex"
11
- wif = "wif"
12
-
13
-
14
- @dataclass
15
- class Args:
16
- mnemonic: str
17
- passphrase: str
18
- words: int
19
- limit: int
20
- hex: bool # Print private key in hex format instead of WIF
21
- path: str
22
- testnet: bool
23
-
24
-
25
- def run(args: Args) -> None:
26
- mnemonic = args.mnemonic or generate_mnemonic()
27
- passphrase = args.passphrase
28
- path = get_derivation_path_prefix(args.path, args.testnet)
29
- accounts = derive_accounts(mnemonic, passphrase, path, args.limit)
30
-
31
- print_plain(f"{mnemonic}")
32
- if passphrase:
33
- print_plain(f"{passphrase}")
34
- for acc in accounts:
35
- private = acc.private if args.hex else acc.wif
36
- print_plain(f"{acc.path} {acc.address} {private}")
37
-
38
-
39
- def get_derivation_path_prefix(path: str, testnet: bool) -> str:
40
- if path.startswith("m/"):
41
- return path
42
- coin = "1" if testnet else "0"
43
- if path == "bip44":
44
- return f"m/44'/{coin}'/0'/0"
45
- if path == "bip84":
46
- return f"m/84'/{coin}'/0'/0"
47
-
48
- raise ValueError("Invalid path")
@@ -1,11 +0,0 @@
1
- from mm_std import print_json
2
-
3
- from mm_btc.blockstream import BlockstreamClient
4
- from mm_btc.wallet import is_testnet_address
5
-
6
-
7
- def run(address: str) -> None:
8
- client = BlockstreamClient(testnet=is_testnet_address(address))
9
- res = client.get_utxo(address)
10
-
11
- print_json(res.ok_or_err())
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: mm-btc
3
- Version: 0.1.2
4
- Requires-Python: >=3.12
5
- Requires-Dist: bitcoinlib~=0.7.0
6
- Requires-Dist: bit~=0.8.0
7
- Requires-Dist: hdwallet~=2.2.1
8
- Requires-Dist: mm-std~=0.1.6
9
- Requires-Dist: typer>=0.13.0
@@ -1,18 +0,0 @@
1
- mm_btc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- mm_btc/blockstream.py,sha256=U2_pc6RYAkFcCvH_WrxjIm13VNavyY3WgK8ePowV-Ic,3620
3
- mm_btc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- mm_btc/tx.py,sha256=7KTMNuL1n8rRj_245BV1bH9M2_PctNvlvPsLEsRTYx4,245
5
- mm_btc/wallet.py,sha256=0ejOIl5gbm1oMO4WY3AsQRiF3PCrB4WC2LknaYPmMfY,1838
6
- mm_btc/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- mm_btc/cli/cli.py,sha256=D_yQ_L7oBY9aJ3_TKeJOQmXFsx8yK3lmARTAsmMXjO8,2413
8
- mm_btc/cli/cli_utils.py,sha256=g2o5ySLu-Tw8dZm84ZAsx8862yHij4sDfz4z6uLS2hw,102
9
- mm_btc/cli/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- mm_btc/cli/cmd/address_cmd.py,sha256=fipX9FiQ2EgCEq8nVN6ELnDMoR5KTIX7bpAaRK3t_yg,284
11
- mm_btc/cli/cmd/create_tx_cmd.py,sha256=dIuQBTOqTSefC6aMbrBN6Pq0EwV2G2ESM1tLU4WyFoU,690
12
- mm_btc/cli/cmd/decode_tx_cmd.py,sha256=0jGlUjnA1X2Q2aYwSBeAjqVNZIBsW5X2lEwIpSfWJsU,175
13
- mm_btc/cli/cmd/mnemonic_cmd.py,sha256=zAAHr9j0SLJX5BXoiMTZj8pIzTPX26aJEOUi7IN40Ug,1192
14
- mm_btc/cli/cmd/utxo_cmd.py,sha256=mp-lVLURpXFqO3IeBIEwnHusEvT5tFjUKxnRYC-rFqQ,294
15
- mm_btc-0.1.2.dist-info/METADATA,sha256=7f3giSslf4D6JXMCSSlm85n1RJTx3PSdD0m40DXnBiI,222
16
- mm_btc-0.1.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
17
- mm_btc-0.1.2.dist-info/entry_points.txt,sha256=KphzLNE9eb9H1DO-L0gvBQaQT5ImedyVCN4a6svfiRg,46
18
- mm_btc-0.1.2.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- mm-btc = mm_btc.cli.cli:app