diff --git a/crypto/identity/address.py b/crypto/identity/address.py index 477ec9e..5f4429f 100644 --- a/crypto/identity/address.py +++ b/crypto/identity/address.py @@ -4,76 +4,81 @@ from crypto.identity.private_key import PrivateKey from Cryptodome.Hash import keccak -from coincurve import PrivateKey, PublicKey +from coincurve import PublicKey -def get_checksum_address(address: str) -> str: - """Get checksum address +class Address: + @classmethod + def from_public_key(cls, public_key: str) -> str: + """Get an address from a public key - Args: - address (str): address to get checksum + Args: + public_key (str): public key to get address - Returns: - str: checksum address - """ - address = address.lower() + Returns: + str: address + """ - chars = list(address[2:]) + public_key_bytes = PublicKey(bytes.fromhex(public_key)).format(compressed=False)[1:] - expanded = bytearray(40) - for i in range(40): - expanded[i] = ord(chars[i]) + keccak_hash = keccak.new( + data=bytearray.fromhex(public_key_bytes.hex()), + digest_bits=256, + ) - hashed = keccak.new(data=bytes(expanded), digest_bits=256).digest() + return cls.get_checksum_address(unhexlify(keccak_hash.hexdigest()[22:]).hex()) - for i in range(0, 40, 2): - if (hashed[i >> 1] >> 4) >= 8: - chars[i] = chars[i].upper() - if (hashed[i >> 1] & 0x0F) >= 8: - chars[i + 1] = chars[i + 1].upper() + @classmethod + def from_private_key(cls, private_key: str) -> str: + """Get an address from private key - return "0x" + ''.join(chars) + Args: + private_key (string): private key to get address -def address_from_public_key(public_key: str) -> str: - """Get an address from a public key + Returns: + str: address + """ + private_key_object = PrivateKey.from_hex(private_key) - Args: - public_key (str): public key to get address + return cls.from_public_key(private_key_object.public_key) - Returns: - str: address - """ + @classmethod + def from_passphrase(cls, passphrase: str) -> str: + """Get an address from passphrase - public_key_bytes = PublicKey(bytes.fromhex(public_key)).format(compressed=False)[1:] + Args: + passphrase (str): passphrase to get address - keccak_hash = keccak.new( - data=bytearray.fromhex(public_key_bytes.hex()), - digest_bits=256, - ) + Returns: + str: address + """ + private_key = hashlib.sha256(passphrase.encode()).hexdigest() - return get_checksum_address(unhexlify(keccak_hash.hexdigest()[22:]).hex()) + return cls.from_private_key(private_key) -def address_from_private_key(private_key: str) -> str: - """Get an address from private key + @classmethod + def get_checksum_address(cls, address: str) -> str: + """Get checksum address - Args: - private_key (string): private key to get address + Args: + address (str): address to get checksum - Returns: - str: address - """ - private_key_object = PrivateKey.from_hex(private_key) + Returns: + str: checksum address + """ + address = address.lower() - return address_from_public_key(private_key_object.public_key.format(compressed=False).hex()) + chars = list(address[2:]) -def address_from_passphrase(passphrase: str) -> str: - """Get an address from passphrase + expanded = bytearray(40) + for i in range(40): + expanded[i] = ord(chars[i]) - Args: - passphrase (str): passphrase to get address + hashed = keccak.new(data=bytes(expanded), digest_bits=256).digest() - Returns: - str: address - """ - private_key = hashlib.sha256(passphrase.encode()).hexdigest() + for i in range(0, 40, 2): + if (hashed[i >> 1] >> 4) >= 8: + chars[i] = chars[i].upper() + if (hashed[i >> 1] & 0x0F) >= 8: + chars[i + 1] = chars[i + 1].upper() - return address_from_private_key(private_key) + return "0x" + ''.join(chars) diff --git a/crypto/transactions/types/abstract_transaction.py b/crypto/transactions/types/abstract_transaction.py index 5e26d35..5cf2cf6 100644 --- a/crypto/transactions/types/abstract_transaction.py +++ b/crypto/transactions/types/abstract_transaction.py @@ -1,14 +1,12 @@ import json from typing import Optional -from crypto.configuration.network import get_network from crypto.enums.constants import Constants from crypto.enums.contract_abi_type import ContractAbiType -from crypto.identity.address import address_from_public_key +from crypto.identity.address import Address from crypto.identity.private_key import PrivateKey from crypto.utils.transaction_utils import TransactionUtils from coincurve import PublicKey -from crypto.utils.abi_decoder import AbiDecoder class AbstractTransaction: def __init__(self, data: dict): @@ -50,7 +48,7 @@ def recover_sender(self): hash_ = bytes.fromhex(self.hash(skip_signature=True)) public_key = self.get_public_key(signature_with_recid, hash_) self.data['senderPublicKey'] = public_key.format().hex() - self.data['senderAddress'] = address_from_public_key(self.data['senderPublicKey']) + self.data['senderAddress'] = Address.from_public_key(self.data['senderPublicKey']) def verify(self) -> bool: signature_with_recid = self.get_signature() diff --git a/crypto/utils/abi_base.py b/crypto/utils/abi_base.py index 96731cd..f557a25 100644 --- a/crypto/utils/abi_base.py +++ b/crypto/utils/abi_base.py @@ -3,11 +3,10 @@ import json import os import re -from binascii import unhexlify from typing import Optional from Cryptodome.Hash import keccak from crypto.enums.contract_abi_type import ContractAbiType -from crypto.identity.address import get_checksum_address +from crypto.identity.address import Address class AbiBase: @@ -38,7 +37,7 @@ def strip_hex_prefix(self, hex_str): def is_valid_address(self, address): # Compute the checksum address and compare - computed_checksum_address = get_checksum_address(address.lower()) + computed_checksum_address = Address.get_checksum_address(address.lower()) return address.lower() == computed_checksum_address.lower() diff --git a/crypto/utils/abi_decoder.py b/crypto/utils/abi_decoder.py index 1bf9ddc..434c5c2 100644 --- a/crypto/utils/abi_decoder.py +++ b/crypto/utils/abi_decoder.py @@ -3,7 +3,7 @@ from crypto.utils.abi_base import AbiBase import binascii import re -from crypto.identity.address import get_checksum_address +from crypto.identity.address import Address class AbiDecoder(AbiBase): @@ -88,7 +88,7 @@ def decode_address(bytes_data, offset): data = bytes_data[offset:offset+32] address_bytes = data[12:32] address = '0x' + address_bytes.hex() - address = get_checksum_address(address) + address = Address.get_checksum_address(address) return address, 32 diff --git a/tests/identity/test_address.py b/tests/identity/test_address.py index 95070d5..7e70678 100644 --- a/tests/identity/test_address.py +++ b/tests/identity/test_address.py @@ -1,18 +1,15 @@ -import pytest -from crypto.identity.address import ( - address_from_passphrase, address_from_private_key, address_from_public_key -) +from crypto.identity.address import Address def test_address_from_public_key(identity): - address = address_from_public_key(identity['data']['public_key']) + address = Address.from_public_key(identity['data']['public_key']) assert address == identity['data']['address'] def test_address_from_private_key(identity): - address = address_from_private_key(identity['data']['private_key']) + address = Address.from_private_key(identity['data']['private_key']) assert address == identity['data']['address'] def test_address_from_passphrase(identity): - address = address_from_passphrase(identity['passphrase']) + address = Address.from_passphrase(identity['passphrase']) assert address == identity['data']['address']