Completed
Push — main ( c8d24f...29322d )
by Switcheolytics
25s queued 11s
created

tradehub.wallet.Wallet.generate_12_word_wallet()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
import base64
2
import bech32
3
import ecdsa
4
import hashlib
5
import hdwallets
6
import mnemonic
7
8
from tradehub.utils import sort_and_stringify_json
9
10
11
class Wallet(object):
12
13
    _DEFAULT_DERIVATION_PATH = "m/44'/118'/0'/0/0"
14
15
    def __init__(self, mnemonic: str = None, network: str = "testnet"):
16
        """
17
18
        """
19
        self.DEFAULT_BECH32_PREFIX_DICT = {
20
            "main": "swth",
21
            "mainnet": "swth",
22
            "test": "tswth",
23
            "testnet": "tswth",
24
        }
25
        self.DEFAULT_BECH32_PREFIX = self.DEFAULT_BECH32_PREFIX_DICT[network.lower()]
26
27
        if mnemonic and len(mnemonic.split()) in [12, 24]:
28
            self._mnemonic = mnemonic
29
        else:
30
            self._mnemonic = self.generate_12_word_wallet()
31
32
        self._private_key = self.mnemonic_to_private_key(mnemonic_phrase=self._mnemonic)
33
        self.public_key = self.private_key_to_public_key(private_key=self._private_key)
34
        self.base64_public_key = base64.b64encode(self.public_key).decode("utf-8")
35
        self.address = self.private_key_to_address(private_key=self._private_key)
36
37
    def generate_12_word_wallet(self):
38
        return mnemonic.Mnemonic(language="english").generate(strength=128)
39
40
    def generate_24_word_wallet(self):
41
        return mnemonic.Mnemonic(language="english").generate(strength=256)
42
43
    def mnemonic_to_private_key(self, mnemonic_phrase: str = None, wallet_path: str = _DEFAULT_DERIVATION_PATH) -> bytes:
44
        mnemonic_bytes = mnemonic.Mnemonic.to_seed(mnemonic_phrase, passphrase="")
45
        hd_wallet = hdwallets.BIP32.from_seed(mnemonic_bytes)
46
        self._private_key = hd_wallet.get_privkey_from_path(wallet_path)
47
        return self._private_key
48
49
    def private_key_to_public_key(self, private_key: bytes = None) -> bytes:
50
        privkey_obj = ecdsa.SigningKey.from_string(self._private_key, curve=ecdsa.SECP256k1)
51
        self.public_key_obj = privkey_obj.get_verifying_key()
52
        self.public_key = self.public_key_obj.to_string("compressed")
53
        return self.public_key
54
55
    def public_key_to_address(self, public_key: bytes = None, hrp: str = None) -> str:
56
        if hrp is None:
57
            hrp = self.DEFAULT_BECH32_PREFIX
58
        s = hashlib.new("sha256", public_key).digest()
59
        r = hashlib.new("ripemd160", s).digest()
60
        five_bit_r = bech32.convertbits(r, 8, 5)
61
        assert five_bit_r is not None, "Unsuccessful bech32.convertbits call"
62
        return bech32.bech32_encode(hrp, five_bit_r)
63
64
    def private_key_to_address(self, private_key: bytes = None, hrp: str = None) -> str:
65
        if hrp is None:
66
            hrp = self.DEFAULT_BECH32_PREFIX
67
        public_key = self.private_key_to_public_key(private_key)
68
        return self.public_key_to_address(public_key=public_key, hrp=hrp)
69
70
    def _sign(self, message: dict) -> str:
71
        message_str = sort_and_stringify_json(message=message)
72
        message_bytes = message_str.encode("utf-8")
73
74
        private_key = ecdsa.SigningKey.from_string(self._private_key, curve=ecdsa.SECP256k1)
75
        signature_compact = private_key.sign_deterministic(
76
            message_bytes,
77
            hashfunc=hashlib.sha256,
78
            sigencode=ecdsa.util.sigencode_string_canonize
79
        )
80
81
        signature_base64_str = base64.b64encode(signature_compact).decode("utf-8")
82
        return signature_base64_str
83