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 +39 -20
- mm_btc-0.2.0.dist-info/METADATA +9 -0
- mm_btc-0.2.0.dist-info/RECORD +8 -0
- {mm_btc-0.1.2.dist-info → mm_btc-0.2.0.dist-info}/WHEEL +1 -1
- mm_btc/cli/__init__.py +0 -0
- mm_btc/cli/cli.py +0 -76
- mm_btc/cli/cli_utils.py +0 -5
- mm_btc/cli/cmd/__init__.py +0 -0
- mm_btc/cli/cmd/address_cmd.py +0 -10
- mm_btc/cli/cmd/create_tx_cmd.py +0 -27
- mm_btc/cli/cmd/decode_tx_cmd.py +0 -8
- mm_btc/cli/cmd/mnemonic_cmd.py +0 -48
- mm_btc/cli/cmd/utxo_cmd.py +0 -11
- mm_btc-0.1.2.dist-info/METADATA +0 -9
- mm_btc-0.1.2.dist-info/RECORD +0 -18
- mm_btc-0.1.2.dist-info/entry_points.txt +0 -2
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
|
|
4
|
-
from hdwallet.
|
|
5
|
-
from hdwallet.
|
|
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
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if
|
|
28
|
-
|
|
29
|
-
elif
|
|
30
|
-
|
|
31
|
-
elif
|
|
32
|
-
|
|
33
|
-
elif
|
|
34
|
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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,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,,
|
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
mm_btc/cli/cmd/__init__.py
DELETED
|
File without changes
|
mm_btc/cli/cmd/address_cmd.py
DELETED
|
@@ -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)
|
mm_btc/cli/cmd/create_tx_cmd.py
DELETED
|
@@ -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)
|
mm_btc/cli/cmd/decode_tx_cmd.py
DELETED
mm_btc/cli/cmd/mnemonic_cmd.py
DELETED
|
@@ -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")
|
mm_btc/cli/cmd/utxo_cmd.py
DELETED
|
@@ -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())
|
mm_btc-0.1.2.dist-info/METADATA
DELETED
mm_btc-0.1.2.dist-info/RECORD
DELETED
|
@@ -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,,
|