diff --git a/aptos_sdk/account.py b/aptos_sdk/account.py index a5be668..97e195f 100644 --- a/aptos_sdk/account.py +++ b/aptos_sdk/account.py @@ -31,18 +31,18 @@ def __eq__(self, other: object) -> bool: self.account_address == other.account_address and self.private_key == other.private_key ) - @staticmethod - def generate() -> Account: + @classmethod + def generate(cls) -> Account: """Generate a new Ed25519 account with a random private key. :returns: A new Account with a freshly generated Ed25519 key pair. """ private_key = ed25519.PrivateKey.random() account_address = AccountAddress.from_key(private_key.public_key()) - return Account(account_address, private_key) + return cls(account_address, private_key) - @staticmethod - def generate_secp256k1_ecdsa() -> Account: + @classmethod + def generate_secp256k1_ecdsa(cls) -> Account: """Generate a new Secp256k1 ECDSA account with a random private key. :returns: A new Account with a freshly generated Secp256k1 key pair. @@ -50,10 +50,10 @@ def generate_secp256k1_ecdsa() -> Account: private_key = secp256k1_ecdsa.PrivateKey.random() public_key = asymmetric_crypto_wrapper.PublicKey(private_key.public_key()) account_address = AccountAddress.from_key(public_key) - return Account(account_address, private_key) + return cls(account_address, private_key) - @staticmethod - def load_key(key: str) -> Account: + @classmethod + def load_key(cls, key: str) -> Account: """Create an Account from an Ed25519 private key hex string. :param key: Hex-encoded private key string. @@ -61,10 +61,10 @@ def load_key(key: str) -> Account: """ private_key = ed25519.PrivateKey.from_str(key) account_address = AccountAddress.from_key(private_key.public_key()) - return Account(account_address, private_key) + return cls(account_address, private_key) - @staticmethod - def load(path: str) -> Account: + @classmethod + def load(cls, path: str) -> Account: """Load an Account from a JSON file containing ``account_address`` and ``private_key``. :param path: Path to the JSON file. @@ -72,7 +72,7 @@ def load(path: str) -> Account: """ with open(path) as file: data = json.load(file) - return Account( + return cls( AccountAddress.from_str_relaxed(data["account_address"]), ed25519.PrivateKey.from_str(data["private_key"]), ) diff --git a/aptos_sdk/account_address.py b/aptos_sdk/account_address.py index be46a40..51b46ef 100644 --- a/aptos_sdk/account_address.py +++ b/aptos_sdk/account_address.py @@ -83,8 +83,8 @@ def is_special(self): """ return all(b == 0 for b in self.address[:-1]) and self.address[-1] < 0b10000 - @staticmethod - def from_str(address: str) -> AccountAddress: + @classmethod + def from_str(cls, address: str) -> AccountAddress: """ NOTE: This function has strict parsing behavior. For relaxed behavior, please use `from_string_relaxed` function. @@ -117,7 +117,7 @@ def from_str(address: str) -> AccountAddress: if not address.startswith("0x"): raise RuntimeError("Hex string must start with a leading 0x.") - out = AccountAddress.from_str_relaxed(address) + out = cls.from_str_relaxed(address) # Check if the address is in LONG form. If it is not, this is only allowed for # special addresses, in which case we check it is in proper SHORT form. @@ -144,8 +144,8 @@ def from_str(address: str) -> AccountAddress: return out - @staticmethod - def from_str_relaxed(address: str) -> AccountAddress: + @classmethod + def from_str_relaxed(cls, address: str) -> AccountAddress: """ NOTE: This function has relaxed parsing behavior. For strict behavior, please use the `from_string` function. Where possible, use `from_string` rather than this @@ -194,10 +194,10 @@ def from_str_relaxed(address: str) -> AccountAddress: pad = "0" * (AccountAddress.LENGTH * 2 - len(addr)) addr = pad + addr - return AccountAddress(bytes.fromhex(addr)) + return cls(bytes.fromhex(addr)) - @staticmethod - def from_key(key: asymmetric_crypto.PublicKey) -> AccountAddress: + @classmethod + def from_key(cls, key: asymmetric_crypto.PublicKey) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(key.to_crypto_bytes()) @@ -212,49 +212,49 @@ def from_key(key: asymmetric_crypto.PublicKey) -> AccountAddress: else: raise InvalidKeyError("Unsupported asymmetric_crypto.PublicKey key type.") - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_resource_account(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_resource_account(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DeriveResourceAccountAddress) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_guid_object(creator: AccountAddress, creation_num: int) -> AccountAddress: + @classmethod + def for_guid_object(cls, creator: AccountAddress, creation_num: int) -> AccountAddress: hasher = hashlib.sha3_256() serializer = Serializer() serializer.u64(creation_num) hasher.update(serializer.output()) hasher.update(creator.address) hasher.update(AuthKeyScheme.DeriveObjectAddressFromGuid) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_named_object(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_named_object(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DeriveObjectAddressFromSeed) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod + @classmethod def for_named_token( - creator: AccountAddress, collection_name: str, token_name: str + cls, creator: AccountAddress, collection_name: str, token_name: str ) -> AccountAddress: collection_bytes = collection_name.encode() token_bytes = token_name.encode() - return AccountAddress.for_named_object(creator, collection_bytes + b"::" + token_bytes) + return cls.for_named_object(creator, collection_bytes + b"::" + token_bytes) - @staticmethod - def for_named_collection(creator: AccountAddress, collection_name: str) -> AccountAddress: - return AccountAddress.for_named_object(creator, collection_name.encode()) + @classmethod + def for_named_collection(cls, creator: AccountAddress, collection_name: str) -> AccountAddress: + return cls.for_named_object(creator, collection_name.encode()) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddress: - return AccountAddress(deserializer.fixed_bytes(AccountAddress.LENGTH)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddress: + return cls(deserializer.fixed_bytes(AccountAddress.LENGTH)) def serialize(self, serializer: Serializer): serializer.fixed_bytes(self.address) diff --git a/aptos_sdk/aptos_token_client.py b/aptos_sdk/aptos_token_client.py index 5e33b1c..f281b68 100644 --- a/aptos_sdk/aptos_token_client.py +++ b/aptos_sdk/aptos_token_client.py @@ -23,9 +23,9 @@ def __init__(self, allow_ungated_transfer, owner): self.allow_ungated_transfer = allow_ungated_transfer self.owner = owner - @staticmethod - def parse(resource: dict[str, Any]) -> Object: - return Object( + @classmethod + def parse(cls, resource: dict[str, Any]) -> Object: + return cls( resource["allow_ungated_transfer"], AccountAddress.from_str_relaxed(resource["owner"]), ) @@ -51,9 +51,9 @@ def __init__(self, creator, description, name, uri): def __str__(self) -> str: return f"AccountAddress[creator: {self.creator}, description: {self.description}, name: {self.name}, ur: {self.uri}]" - @staticmethod - def parse(resource: dict[str, Any]) -> Collection: - return Collection( + @classmethod + def parse(cls, resource: dict[str, Any]) -> Collection: + return cls( AccountAddress.from_str_relaxed(resource["creator"]), resource["description"], resource["name"], @@ -76,9 +76,9 @@ def __init__(self, numerator, denominator, payee_address): def __str__(self) -> str: return f"Royalty[numerator: {self.numerator}, denominator: {self.denominator}, payee_address: {self.payee_address}]" - @staticmethod - def parse(resource: dict[str, Any]) -> Royalty: - return Royalty( + @classmethod + def parse(cls, resource: dict[str, Any]) -> Royalty: + return cls( resource["numerator"], resource["denominator"], AccountAddress.from_str_relaxed(resource["payee_address"]), @@ -111,9 +111,9 @@ def __init__( def __str__(self) -> str: return f"Token[collection: {self.collection}, index: {self.index}, description: {self.description}, name: {self.name}, uri: {self.uri}]" - @staticmethod - def parse(resource: dict[str, Any]): - return Token( + @classmethod + def parse(cls, resource: dict[str, Any]): + return cls( AccountAddress.from_str_relaxed(resource["collection"]["inner"]), int(resource["index"]), resource["description"], @@ -190,67 +190,67 @@ def to_transaction_arguments(self) -> List[TransactionArgument]: TransactionArgument(self.serialize_value(), Serializer.to_bytes), ] - @staticmethod - def parse(name: str, property_type: int, value: bytes) -> Property: + @classmethod + def parse(cls, name: str, property_type: int, value: bytes) -> Property: deserializer = Deserializer(value) if property_type == Property.BOOL: - return Property(name, "bool", deserializer.bool()) + return cls(name, "bool", deserializer.bool()) elif property_type == Property.U8: - return Property(name, "u8", deserializer.u8()) + return cls(name, "u8", deserializer.u8()) elif property_type == Property.U16: - return Property(name, "u16", deserializer.u16()) + return cls(name, "u16", deserializer.u16()) elif property_type == Property.U32: - return Property(name, "u32", deserializer.u32()) + return cls(name, "u32", deserializer.u32()) elif property_type == Property.U64: - return Property(name, "u64", deserializer.u64()) + return cls(name, "u64", deserializer.u64()) elif property_type == Property.U128: - return Property(name, "u128", deserializer.u128()) + return cls(name, "u128", deserializer.u128()) elif property_type == Property.U256: - return Property(name, "u256", deserializer.u256()) + return cls(name, "u256", deserializer.u256()) elif property_type == Property.ADDRESS: - return Property(name, "address", AccountAddress.deserialize(deserializer)) + return cls(name, "address", AccountAddress.deserialize(deserializer)) elif property_type == Property.STRING: - return Property(name, "0x1::string::String", deserializer.str()) + return cls(name, "0x1::string::String", deserializer.str()) elif property_type == Property.BYTE_VECTOR: - return Property(name, "vector", deserializer.to_bytes()) + return cls(name, "vector", deserializer.to_bytes()) raise InvalidPropertyType(property_type) - @staticmethod - def bool(name: str, value: bool) -> Property: - return Property(name, "bool", value) + @classmethod + def bool(cls, name: str, value: bool) -> Property: + return cls(name, "bool", value) - @staticmethod - def u8(name: str, value: int) -> Property: - return Property(name, "u8", value) + @classmethod + def u8(cls, name: str, value: int) -> Property: + return cls(name, "u8", value) - @staticmethod - def u16(name: str, value: int) -> Property: - return Property(name, "u16", value) + @classmethod + def u16(cls, name: str, value: int) -> Property: + return cls(name, "u16", value) - @staticmethod - def u32(name: str, value: int) -> Property: - return Property(name, "u32", value) + @classmethod + def u32(cls, name: str, value: int) -> Property: + return cls(name, "u32", value) - @staticmethod - def u64(name: str, value: int) -> Property: - return Property(name, "u64", value) + @classmethod + def u64(cls, name: str, value: int) -> Property: + return cls(name, "u64", value) - @staticmethod - def u128(name: str, value: int) -> Property: - return Property(name, "u128", value) + @classmethod + def u128(cls, name: str, value: int) -> Property: + return cls(name, "u128", value) - @staticmethod - def u256(name: str, value: int) -> Property: - return Property(name, "u256", value) + @classmethod + def u256(cls, name: str, value: int) -> Property: + return cls(name, "u256", value) - @staticmethod - def string(name: str, value: str) -> Property: - return Property(name, "0x1::string::String", value) + @classmethod + def string(cls, name: str, value: str) -> Property: + return cls(name, "0x1::string::String", value) - @staticmethod - def bytes(name: str, value: bytes) -> Property: - return Property(name, "vector", value) + @classmethod + def bytes(cls, name: str, value: bytes) -> Property: + return cls(name, "vector", value) class PropertyMap: @@ -282,8 +282,8 @@ def to_tuple(self) -> Tuple[List[str], List[str], List[bytes]]: return (names, types, values) - @staticmethod - def parse(resource: dict[str, Any]) -> PropertyMap: + @classmethod + def parse(cls, resource: dict[str, Any]) -> PropertyMap: props = resource["inner"]["data"] properties = [] for prop in props: @@ -295,7 +295,7 @@ def parse(resource: dict[str, Any]) -> PropertyMap: ) ) - return PropertyMap(properties) + return cls(properties) class ReadObject: diff --git a/aptos_sdk/asymmetric_crypto_wrapper.py b/aptos_sdk/asymmetric_crypto_wrapper.py index 81b5304..7330ca5 100644 --- a/aptos_sdk/asymmetric_crypto_wrapper.py +++ b/aptos_sdk/asymmetric_crypto_wrapper.py @@ -37,8 +37,8 @@ def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: return self.public_key.verify(data, sig.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> PublicKey: variant = deserializer.uleb128() if variant == PublicKey.ED25519: @@ -48,7 +48,7 @@ def deserialize(deserializer: Deserializer) -> PublicKey: else: raise InvalidTypeError(f"Invalid type: {variant}") - return PublicKey(public_key) + return cls(public_key) def serialize(self, serializer: Serializer): serializer.uleb128(self.variant) @@ -71,8 +71,8 @@ def __init__(self, signature: asymmetric_crypto.Signature): raise NotImplementedError() self.signature = signature - @staticmethod - def deserialize(deserializer: Deserializer) -> Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Signature: variant = deserializer.uleb128() if variant == Signature.ED25519: @@ -82,7 +82,7 @@ def deserialize(deserializer: Deserializer) -> Signature: else: raise InvalidTypeError(f"Invalid type: {variant}") - return Signature(signature) + return cls(signature) def serialize(self, serializer: Serializer): serializer.uleb128(self.variant) @@ -132,8 +132,8 @@ def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: return False return True - @staticmethod - def from_crypto_bytes(indata: bytes) -> MultiPublicKey: + @classmethod + def from_crypto_bytes(cls, indata: bytes) -> MultiPublicKey: deserializer = Deserializer(indata) return deserializer.struct(MultiPublicKey) @@ -142,11 +142,11 @@ def to_crypto_bytes(self) -> bytes: serializer.struct(self) return serializer.output() - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiPublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiPublicKey: keys = deserializer.sequence(PublicKey.deserialize) threshold = deserializer.u8() - return MultiPublicKey(keys, threshold) + return cls(keys, threshold) def serialize(self, serializer: Serializer): serializer.sequence(self.keys, Serializer.struct) @@ -177,8 +177,8 @@ def __eq__(self, other: object): def __str__(self) -> str: return f"{self.signatures}" - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiSignature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiSignature: signatures = deserializer.sequence(Signature.deserialize) bitmap_raw = deserializer.to_bytes() bitmap = int.from_bytes(bitmap_raw, "little") @@ -192,7 +192,7 @@ def deserialize(deserializer: Deserializer) -> MultiSignature: indexed_signatures.append((i, signatures[sig_index])) sig_index += 1 - return MultiSignature(indexed_signatures) + return cls(indexed_signatures) def serialize(self, serializer: Serializer): actual_sigs = [] diff --git a/aptos_sdk/authenticator.py b/aptos_sdk/authenticator.py index 2c5ab96..0a00167 100644 --- a/aptos_sdk/authenticator.py +++ b/aptos_sdk/authenticator.py @@ -64,8 +64,8 @@ def __str__(self) -> str: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Authenticator: variant = deserializer.uleb128() if variant == Authenticator.ED25519: @@ -81,7 +81,7 @@ def deserialize(deserializer: Deserializer) -> Authenticator: else: raise InvalidTypeError(f"Invalid type: {variant}") - return Authenticator(authenticator) + return cls(authenticator) def serialize(self, serializer: Serializer): serializer.uleb128(self.variant) @@ -124,8 +124,8 @@ def __str__(self) -> str: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAuthenticator: variant = deserializer.uleb128() if variant == AccountAuthenticator.ED25519: @@ -139,7 +139,7 @@ def deserialize(deserializer: Deserializer) -> AccountAuthenticator: else: raise InvalidTypeError(f"Invalid type: {variant}") - return AccountAuthenticator(authenticator) + return cls(authenticator) def serialize(self, serializer: Serializer): serializer.uleb128(self.variant) @@ -166,11 +166,11 @@ def __str__(self) -> str: def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519Authenticator: key = deserializer.struct(ed25519.PublicKey) signature = deserializer.struct(ed25519.Signature) - return Ed25519Authenticator(key, signature) + return cls(key, signature) def serialize(self, serializer: Serializer): serializer.struct(self.public_key) @@ -217,14 +217,14 @@ def verify(self, data: bytes) -> bool: return False return all([x[1].verify(data) for x in self.secondary_signers]) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerAuthenticator: sender = deserializer.struct(AccountAuthenticator) secondary_addresses = deserializer.sequence(AccountAddress.deserialize) secondary_authenticators = deserializer.sequence(AccountAuthenticator.deserialize) fee_payer_address = deserializer.struct(AccountAddress) fee_payer_authenticator = deserializer.struct(AccountAuthenticator) - return FeePayerAuthenticator( + return cls( sender, list(zip(secondary_addresses, secondary_authenticators)), (fee_payer_address, fee_payer_authenticator), @@ -263,14 +263,12 @@ def verify(self, data: bytes) -> bool: return False return all([x[1].verify(data) for x in self.secondary_signers]) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentAuthenticator: sender = deserializer.struct(AccountAuthenticator) secondary_addresses = deserializer.sequence(AccountAddress.deserialize) secondary_authenticators = deserializer.sequence(AccountAuthenticator.deserialize) - return MultiAgentAuthenticator( - sender, list(zip(secondary_addresses, secondary_authenticators)) - ) + return cls(sender, list(zip(secondary_addresses, secondary_authenticators))) def serialize(self, serializer: Serializer): serializer.struct(self.sender) @@ -289,8 +287,8 @@ def __init__(self, public_key, signature): def verify(self, data: bytes) -> bool: raise NotImplementedError - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiEd25519Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiEd25519Authenticator: raise NotImplementedError def serialize(self, serializer: Serializer): @@ -315,10 +313,10 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.sender.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleSenderAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleSenderAuthenticator: sender = deserializer.struct(AccountAuthenticator) - return SingleSenderAuthenticator(sender) + return cls(sender) def serialize(self, serializer: Serializer): serializer.struct(self.sender) @@ -346,11 +344,11 @@ def __init__( def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleKeyAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleKeyAuthenticator: public_key = deserializer.struct(asymmetric_crypto_wrapper.PublicKey) signature = deserializer.struct(asymmetric_crypto_wrapper.Signature) - return SingleKeyAuthenticator(public_key, signature) + return cls(public_key, signature) def serialize(self, serializer: Serializer): serializer.struct(self.public_key) @@ -372,11 +370,11 @@ def __init__( def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiKeyAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiKeyAuthenticator: public_key = deserializer.struct(asymmetric_crypto_wrapper.MultiPublicKey) signature = deserializer.struct(asymmetric_crypto_wrapper.MultiSignature) - return MultiKeyAuthenticator(public_key, signature) + return cls(public_key, signature) def serialize(self, serializer: Serializer): serializer.struct(self.public_key) diff --git a/aptos_sdk/bcs.py b/aptos_sdk/bcs.py index 400753c..c14855d 100644 --- a/aptos_sdk/bcs.py +++ b/aptos_sdk/bcs.py @@ -32,8 +32,8 @@ def from_bytes(cls, indata: bytes) -> Deserializable: der = Deserializer(indata) return der.struct(cls) - @staticmethod - def deserialize(deserializer: Deserializer) -> Deserializable: ... + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Deserializable: ... class Serializable(Protocol): diff --git a/aptos_sdk/ed25519.py b/aptos_sdk/ed25519.py index dc8dc8e..6f4880b 100644 --- a/aptos_sdk/ed25519.py +++ b/aptos_sdk/ed25519.py @@ -29,8 +29,8 @@ def __eq__(self, other: object): def __str__(self): return self.aip80() - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> PrivateKey: """ Parse a HexInput that may be a hex string, bytes, or an AIP-80 compliant string to a private key. @@ -38,16 +38,14 @@ def from_hex(value: str | bytes, strict: bool | None = None) -> PrivateKey: :param strict: If true, the value MUST be compliant with AIP-80. :return: Parsed Ed25519 private key. """ - return PrivateKey( + return cls( SigningKey( - PrivateKey.parse_hex_input( - value, asymmetric_crypto.PrivateKeyVariant.Ed25519, strict - ) + cls.parse_hex_input(value, asymmetric_crypto.PrivateKeyVariant.Ed25519, strict) ) ) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> PrivateKey: """ Parse a HexInput that may be a hex string or an AIP-80 compliant string to a private key. @@ -55,7 +53,7 @@ def from_str(value: str, strict: bool | None = None) -> PrivateKey: :param strict: If true, the value MUST be compliant with AIP-80. :return: Parsed Ed25519 private key. """ - return PrivateKey.from_hex(value, strict) + return cls.from_hex(value, strict) def hex(self) -> str: return f"0x{self.key.encode().hex()}" @@ -68,20 +66,20 @@ def aip80(self) -> str: def public_key(self) -> PublicKey: return PublicKey(self.key.verify_key) - @staticmethod - def random() -> PrivateKey: - return PrivateKey(SigningKey.generate()) + @classmethod + def random(cls) -> PrivateKey: + return cls(SigningKey.generate()) def sign(self, data: bytes) -> Signature: return Signature(self.key.sign(data).signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> PrivateKey: key = deserializer.to_bytes() if len(key) != PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") - return PrivateKey(SigningKey(key)) + return cls(SigningKey(key)) def serialize(self, serializer: Serializer): serializer.to_bytes(self.key.encode()) @@ -103,11 +101,11 @@ def __eq__(self, other: object): def __str__(self) -> str: return f"0x{self.key.encode().hex()}" - @staticmethod - def from_str(value: str) -> PublicKey: + @classmethod + def from_str(cls, value: str) -> PublicKey: if value[0:2] == "0x": value = value[2:] - return PublicKey(VerifyKey(bytes.fromhex(value))) + return cls(VerifyKey(bytes.fromhex(value))) def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: try: @@ -120,13 +118,13 @@ def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: def to_crypto_bytes(self) -> bytes: return self.key.encode() - @staticmethod - def deserialize(deserializer: Deserializer) -> PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> PublicKey: key = deserializer.to_bytes() if len(key) != PublicKey.LENGTH: raise InvalidKeyError("Length mismatch") - return PublicKey(VerifyKey(key)) + return cls(VerifyKey(key)) def serialize(self, serializer: Serializer): serializer.to_bytes(self.key.encode()) @@ -167,8 +165,8 @@ def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: return False return True - @staticmethod - def from_crypto_bytes(indata: bytes) -> MultiPublicKey: + @classmethod + def from_crypto_bytes(cls, indata: bytes) -> MultiPublicKey: total_keys = int(len(indata) / PublicKey.LENGTH) keys: List[PublicKey] = [] for idx in range(total_keys): @@ -176,7 +174,7 @@ def from_crypto_bytes(indata: bytes) -> MultiPublicKey: end = (idx + 1) * PublicKey.LENGTH keys.append(PublicKey(VerifyKey(indata[start:end]))) threshold = indata[-1] - return MultiPublicKey(keys, threshold) + return cls(keys, threshold) def to_crypto_bytes(self) -> bytes: key_bytes = bytearray() @@ -185,10 +183,10 @@ def to_crypto_bytes(self) -> bytes: key_bytes.append(self.threshold) return key_bytes - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiPublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiPublicKey: indata = deserializer.to_bytes() - return MultiPublicKey.from_crypto_bytes(indata) + return cls.from_crypto_bytes(indata) def serialize(self, serializer: Serializer): serializer.to_bytes(self.to_crypto_bytes()) @@ -213,19 +211,19 @@ def __str__(self) -> str: def data(self) -> bytes: return self.signature - @staticmethod - def deserialize(deserializer: Deserializer) -> Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Signature: signature = deserializer.to_bytes() if len(signature) != Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Signature(signature) + return cls(signature) - @staticmethod - def from_str(value: str) -> Signature: + @classmethod + def from_str(cls, value: str) -> Signature: if value[0:2] == "0x": value = value[2:] - return Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) def serialize(self, serializer: Serializer): serializer.to_bytes(self.signature) @@ -249,8 +247,9 @@ def __eq__(self, other: object): def __str__(self) -> str: return f"{self.signatures}" - @staticmethod + @classmethod def from_key_map( + cls, public_key: MultiPublicKey, signatures_map: List[Tuple[PublicKey, Signature]], ) -> MultiSignature: @@ -258,10 +257,10 @@ def from_key_map( for entry in signatures_map: signatures.append((public_key.keys.index(entry[0]), entry[1])) - return MultiSignature(signatures) + return cls(signatures) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiSignature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiSignature: signature_bytes = deserializer.to_bytes() count = len(signature_bytes) // Signature.LENGTH if count * Signature.LENGTH + MultiSignature.BITMAP_NUM_OF_BYTES != len(signature_bytes): @@ -281,7 +280,7 @@ def deserialize(deserializer: Deserializer) -> MultiSignature: current += 1 position += 1 - return MultiSignature(signatures) + return cls(signatures) def serialize(self, serializer: Serializer): signature_bytes = bytearray() diff --git a/aptos_sdk/secp256k1_ecdsa.py b/aptos_sdk/secp256k1_ecdsa.py index c0ad04d..e416220 100644 --- a/aptos_sdk/secp256k1_ecdsa.py +++ b/aptos_sdk/secp256k1_ecdsa.py @@ -36,8 +36,8 @@ def __eq__(self, other: object): def __str__(self): return self.aip80() - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> PrivateKey: """ Parse a HexInput that may be a hex string, bytes, or an AIP-80 compliant string to a private key. @@ -45,7 +45,7 @@ def from_hex(value: str | bytes, strict: bool | None = None) -> PrivateKey: :param strict: If true, the value MUST be compliant with AIP-80. :return: Parsed private key as bytes. """ - parsed_value = PrivateKey.parse_hex_input( + parsed_value = cls.parse_hex_input( value, asymmetric_crypto.PrivateKeyVariant.Secp256k1, strict ) if len(parsed_value) != PrivateKey.LENGTH: @@ -53,10 +53,10 @@ def from_hex(value: str | bytes, strict: bool | None = None) -> PrivateKey: private_int = int.from_bytes(parsed_value, "big") if not (1 <= private_int < _SECP256K1_ORDER): raise InvalidKeyError("Invalid Secp256k1 private key scalar") - return PrivateKey(ec.derive_private_key(private_int, ec.SECP256K1())) + return cls(ec.derive_private_key(private_int, ec.SECP256K1())) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> PrivateKey: """ Parse a HexInput that may be a hex string or an AIP-80 compliant string to a private key. @@ -64,7 +64,7 @@ def from_str(value: str, strict: bool | None = None) -> PrivateKey: :param strict: If true, the value MUST be compliant with AIP-80. :return: Parsed Secp256k1 private key. """ - return PrivateKey.from_hex(value, strict) + return cls.from_hex(value, strict) def hex(self) -> str: raw = self.key.private_numbers().private_value.to_bytes(PrivateKey.LENGTH, "big") @@ -78,9 +78,9 @@ def aip80(self) -> str: def public_key(self) -> PublicKey: return PublicKey(self.key.public_key()) - @staticmethod - def random() -> PrivateKey: - return PrivateKey(ec.generate_private_key(ec.SECP256K1())) + @classmethod + def random(cls) -> PrivateKey: + return cls(ec.generate_private_key(ec.SECP256K1())) def sign(self, data: bytes) -> Signature: der_sig = self.key.sign(data, ec.ECDSA(hashes.SHA3_256())) @@ -92,15 +92,15 @@ def sign(self, data: bytes) -> Signature: sig_bytes = r.to_bytes(32, "big") + s.to_bytes(32, "big") return Signature(sig_bytes) - @staticmethod - def deserialize(deserializer: Deserializer) -> PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> PrivateKey: key = deserializer.to_bytes() if len(key) != PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") private_int = int.from_bytes(key, "big") if not (1 <= private_int < _SECP256K1_ORDER): raise InvalidKeyError("Invalid Secp256k1 private key scalar") - return PrivateKey(ec.derive_private_key(private_int, ec.SECP256K1())) + return cls(ec.derive_private_key(private_int, ec.SECP256K1())) def serialize(self, serializer: Serializer): raw = self.key.private_numbers().private_value.to_bytes(PrivateKey.LENGTH, "big") @@ -126,8 +126,8 @@ def __eq__(self, other: object): def __str__(self) -> str: return self.hex() - @staticmethod - def from_str(value: str) -> PublicKey: + @classmethod + def from_str(cls, value: str) -> PublicKey: if value[0:2] == "0x": value = value[2:] # Hex values are twice the length of their binary counterpart. @@ -141,7 +141,7 @@ def from_str(value: str) -> PublicKey: raw = b"\x04" + raw elif raw[0] != 0x04: raise InvalidKeyError("Invalid uncompressed point prefix") - return PublicKey(ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), raw)) + return cls(ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), raw)) def _raw_bytes(self) -> bytes: nums = self.key.public_numbers() @@ -171,8 +171,8 @@ def verify(self, data: bytes, signature: asymmetric_crypto.Signature) -> bool: def to_crypto_bytes(self) -> bytes: return b"\x04" + self._raw_bytes() - @staticmethod - def deserialize(deserializer: Deserializer) -> PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> PublicKey: key = deserializer.to_bytes() if len(key) == PublicKey.LENGTH_WITH_PREFIX_LENGTH: if key[0] != 0x04: @@ -180,9 +180,7 @@ def deserialize(deserializer: Deserializer) -> PublicKey: key = key[1:] elif len(key) != PublicKey.LENGTH: raise InvalidKeyError("Length mismatch") - return PublicKey( - ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), b"\x04" + key) - ) + return cls(ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256K1(), b"\x04" + key)) def serialize(self, serializer: Serializer): serializer.to_bytes(self.to_crypto_bytes()) @@ -207,24 +205,24 @@ def __str__(self) -> str: def hex(self) -> str: return f"0x{self.signature.hex()}" - @staticmethod - def from_str(value: str) -> Signature: + @classmethod + def from_str(cls, value: str) -> Signature: if value[0:2] == "0x": value = value[2:] if len(value) != Signature.LENGTH * 2: raise InvalidSignatureError("Length mismatch") - return Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) def data(self) -> bytes: return self.signature - @staticmethod - def deserialize(deserializer: Deserializer) -> Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Signature: signature = deserializer.to_bytes() if len(signature) != Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Signature(signature) + return cls(signature) def serialize(self, serializer: Serializer): serializer.to_bytes(self.signature) diff --git a/aptos_sdk/transactions.py b/aptos_sdk/transactions.py index 81c0a5f..2db2d0b 100644 --- a/aptos_sdk/transactions.py +++ b/aptos_sdk/transactions.py @@ -75,8 +75,8 @@ def inner(self) -> RawTransaction: def prehash(self) -> bytes: return _RAW_TXN_WITH_DATA_PREHASH - @staticmethod - def deserialize(deserializer: Deserializer) -> RawTransactionWithData: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> RawTransactionWithData: enum_type = deserializer.u8() if enum_type == 0: return MultiAgentRawTransaction.deserialize_inner(deserializer) @@ -148,9 +148,9 @@ def __str__(self): def prehash(self) -> bytes: return _RAW_TXN_PREHASH - @staticmethod - def deserialize(deserializer: Deserializer) -> RawTransaction: - return RawTransaction( + @classmethod + def deserialize(cls, deserializer: Deserializer) -> RawTransaction: + return cls( AccountAddress.deserialize(deserializer), deserializer.u64(), TransactionPayload.deserialize(deserializer), @@ -183,20 +183,20 @@ def serialize(self, serializer: Serializer) -> None: serializer.struct(self.raw_transaction) serializer.sequence(self.secondary_signers, Serializer.struct) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: raw_txn_type = deserializer.u8() if raw_txn_type != 0: raise DeserializationError(f"Enum type mismatch, expected 0 got {raw_txn_type}") - return MultiAgentRawTransaction.deserialize_inner(deserializer) + return cls.deserialize_inner(deserializer) - @staticmethod - def deserialize_inner(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def deserialize_inner(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary_signers = deserializer.sequence(AccountAddress.deserialize) - return MultiAgentRawTransaction(raw_txn, secondary_signers) + return cls(raw_txn, secondary_signers) class FeePayerRawTransaction(RawTransactionWithData): @@ -220,16 +220,16 @@ def serialize(self, serializer: Serializer) -> None: fee_payer = AccountAddress.from_str("0x0") if self.fee_payer is None else self.fee_payer serializer.struct(fee_payer) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerRawTransaction: raw_txn_type = deserializer.u8() if raw_txn_type != 1: raise DeserializationError(f"Enum type mismatch, expected 1 got {raw_txn_type}") - return FeePayerRawTransaction.deserialize_inner(deserializer) + return cls.deserialize_inner(deserializer) - @staticmethod - def deserialize_inner(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def deserialize_inner(cls, deserializer: Deserializer) -> FeePayerRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary_signers = deserializer.sequence(AccountAddress.deserialize) fee_payer = AccountAddress.deserialize(deserializer) @@ -238,7 +238,7 @@ def deserialize_inner(deserializer: Deserializer) -> FeePayerRawTransaction: else: fee_payer_optional = fee_payer - return FeePayerRawTransaction(raw_txn, secondary_signers, fee_payer_optional) + return cls(raw_txn, secondary_signers, fee_payer_optional) class TransactionPayload: @@ -268,8 +268,8 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return self.value.__str__() - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionPayload: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionPayload: variant = deserializer.uleb128() if variant == TransactionPayload.SCRIPT: @@ -281,7 +281,7 @@ def deserialize(deserializer: Deserializer) -> TransactionPayload: else: raise InvalidTypeError("Invalid type") - return TransactionPayload(payload) + return cls(payload) def serialize(self, serializer: Serializer) -> None: serializer.uleb128(self.variant) @@ -292,8 +292,8 @@ class ModuleBundle: def __init__(self): raise NotImplementedError - @staticmethod - def deserialize(deserializer: Deserializer) -> ModuleBundle: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ModuleBundle: raise NotImplementedError def serialize(self, serializer: Serializer) -> None: @@ -310,12 +310,12 @@ def __init__(self, code: bytes, ty_args: List[TypeTag], args: List[ScriptArgumen self.ty_args = ty_args self.args = args - @staticmethod - def deserialize(deserializer: Deserializer) -> Script: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Script: code = deserializer.to_bytes() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(ScriptArgument.deserialize) - return Script(code, ty_args, args) + return cls(code, ty_args, args) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self.code) @@ -352,8 +352,8 @@ def __init__(self, variant: int, value: Any): self.variant = variant self.value = value - @staticmethod - def deserialize(deserializer: Deserializer) -> ScriptArgument: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ScriptArgument: variant = deserializer.u8() if variant == ScriptArgument.U8: value: Any = deserializer.u8() @@ -375,7 +375,7 @@ def deserialize(deserializer: Deserializer) -> ScriptArgument: value = deserializer.bool() else: raise DeserializationError("Invalid variant") - return ScriptArgument(variant, value) + return cls(variant, value) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.variant) @@ -435,8 +435,9 @@ def __eq__(self, other: object) -> bool: def __str__(self): return f"{self.module}::{self.function}::<{self.ty_args}>({self.args})" - @staticmethod + @classmethod def natural( + cls, module: str, function: str, ty_args: List[TypeTag], @@ -447,15 +448,15 @@ def natural( byte_args = [] for arg in args: byte_args.append(arg.encode()) - return EntryFunction(module_id, function, ty_args, byte_args) + return cls(module_id, function, ty_args, byte_args) - @staticmethod - def deserialize(deserializer: Deserializer) -> EntryFunction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> EntryFunction: module = ModuleId.deserialize(deserializer) function = deserializer.str() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(Deserializer.to_bytes) - return EntryFunction(module, function, ty_args, args) + return cls(module, function, ty_args, args) def serialize(self, serializer: Serializer) -> None: self.module.serialize(serializer) @@ -480,16 +481,16 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"{self.address}::{self.name}" - @staticmethod - def from_str(module_id: str) -> ModuleId: + @classmethod + def from_str(cls, module_id: str) -> ModuleId: split = module_id.split("::") - return ModuleId(AccountAddress.from_str(split[0]), split[1]) + return cls(AccountAddress.from_str(split[0]), split[1]) - @staticmethod - def deserialize(deserializer: Deserializer) -> ModuleId: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ModuleId: addr = AccountAddress.deserialize(deserializer) name = deserializer.str() - return ModuleId(addr, name) + return cls(addr, name) def serialize(self, serializer: Serializer) -> None: self.address.serialize(serializer) @@ -574,11 +575,11 @@ def verify(self) -> bool: transaction = self.transaction return self.authenticator.verify(transaction.keyed()) - @staticmethod - def deserialize(deserializer: Deserializer) -> SignedTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SignedTransaction: transaction = RawTransaction.deserialize(deserializer) authenticator = Authenticator.deserialize(deserializer) - return SignedTransaction(transaction, authenticator) + return cls(transaction, authenticator) def serialize(self, serializer: Serializer) -> None: self.transaction.serialize(serializer) diff --git a/aptos_sdk/type_tag.py b/aptos_sdk/type_tag.py index ba6e765..30e9dce 100644 --- a/aptos_sdk/type_tag.py +++ b/aptos_sdk/type_tag.py @@ -43,31 +43,31 @@ def __str__(self): def __repr__(self): return self.__str__() - @staticmethod - def deserialize(deserializer: Deserializer) -> TypeTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TypeTag: variant = deserializer.uleb128() if variant == TypeTag.BOOL: - return TypeTag(BoolTag.deserialize(deserializer)) + return cls(BoolTag.deserialize(deserializer)) elif variant == TypeTag.U8: - return TypeTag(U8Tag.deserialize(deserializer)) + return cls(U8Tag.deserialize(deserializer)) elif variant == TypeTag.U16: - return TypeTag(U16Tag.deserialize(deserializer)) + return cls(U16Tag.deserialize(deserializer)) elif variant == TypeTag.U32: - return TypeTag(U32Tag.deserialize(deserializer)) + return cls(U32Tag.deserialize(deserializer)) elif variant == TypeTag.U64: - return TypeTag(U64Tag.deserialize(deserializer)) + return cls(U64Tag.deserialize(deserializer)) elif variant == TypeTag.U128: - return TypeTag(U128Tag.deserialize(deserializer)) + return cls(U128Tag.deserialize(deserializer)) elif variant == TypeTag.U256: - return TypeTag(U256Tag.deserialize(deserializer)) + return cls(U256Tag.deserialize(deserializer)) elif variant == TypeTag.ACCOUNT_ADDRESS: - return TypeTag(AccountAddressTag.deserialize(deserializer)) + return cls(AccountAddressTag.deserialize(deserializer)) elif variant == TypeTag.SIGNER: raise NotImplementedError elif variant == TypeTag.VECTOR: raise NotImplementedError elif variant == TypeTag.STRUCT: - return TypeTag(StructTag.deserialize(deserializer)) + return cls(StructTag.deserialize(deserializer)) raise NotImplementedError def serialize(self, serializer: Serializer): @@ -92,9 +92,9 @@ def __str__(self): def variant(self): return TypeTag.BOOL - @staticmethod - def deserialize(deserializer: Deserializer) -> BoolTag: - return BoolTag(deserializer.bool()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> BoolTag: + return cls(deserializer.bool()) def serialize(self, serializer: Serializer): serializer.bool(self.value) @@ -117,9 +117,9 @@ def __str__(self): def variant(self): return TypeTag.U8 - @staticmethod - def deserialize(deserializer: Deserializer) -> U8Tag: - return U8Tag(deserializer.u8()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U8Tag: + return cls(deserializer.u8()) def serialize(self, serializer: Serializer): serializer.u8(self.value) @@ -142,9 +142,9 @@ def __str__(self): def variant(self): return TypeTag.U16 - @staticmethod - def deserialize(deserializer: Deserializer) -> U16Tag: - return U16Tag(deserializer.u16()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U16Tag: + return cls(deserializer.u16()) def serialize(self, serializer: Serializer): serializer.u16(self.value) @@ -167,9 +167,9 @@ def __str__(self): def variant(self): return TypeTag.U32 - @staticmethod - def deserialize(deserializer: Deserializer) -> U32Tag: - return U32Tag(deserializer.u32()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U32Tag: + return cls(deserializer.u32()) def serialize(self, serializer: Serializer): serializer.u32(self.value) @@ -192,9 +192,9 @@ def __str__(self): def variant(self): return TypeTag.U64 - @staticmethod - def deserialize(deserializer: Deserializer) -> U64Tag: - return U64Tag(deserializer.u64()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U64Tag: + return cls(deserializer.u64()) def serialize(self, serializer: Serializer): serializer.u64(self.value) @@ -217,9 +217,9 @@ def __str__(self): def variant(self): return TypeTag.U128 - @staticmethod - def deserialize(deserializer: Deserializer) -> U128Tag: - return U128Tag(deserializer.u128()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U128Tag: + return cls(deserializer.u128()) def serialize(self, serializer: Serializer): serializer.u128(self.value) @@ -242,9 +242,9 @@ def __str__(self): def variant(self): return TypeTag.U256 - @staticmethod - def deserialize(deserializer: Deserializer) -> U256Tag: - return U256Tag(deserializer.u256()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U256Tag: + return cls(deserializer.u256()) def serialize(self, serializer: Serializer): serializer.u256(self.value) @@ -267,9 +267,9 @@ def __str__(self): def variant(self): return TypeTag.ACCOUNT_ADDRESS - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddressTag: - return AccountAddressTag(deserializer.struct(AccountAddress)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddressTag: + return cls(deserializer.struct(AccountAddress)) def serialize(self, serializer: Serializer): serializer.struct(self.value) @@ -306,13 +306,13 @@ def __str__(self) -> str: value += ">" return value - @staticmethod + @classmethod @lru_cache(maxsize=256) - def from_str(type_tag: str) -> StructTag: - return StructTag._from_str_internal(type_tag, 0)[0][0].value + def from_str(cls, type_tag: str) -> StructTag: + return cls._from_str_internal(type_tag, 0)[0][0].value - @staticmethod - def _from_str_internal(type_tag: str, index: int) -> Tuple[List[TypeTag], int]: + @classmethod + def _from_str_internal(cls, type_tag: str, index: int) -> Tuple[List[TypeTag], int]: name = "" tags = [] inner_tags: List[TypeTag] = [] @@ -325,7 +325,7 @@ def _from_str_internal(type_tag: str, index: int) -> Tuple[List[TypeTag], int]: continue if letter == "<": - inner_tags, index = StructTag._from_str_internal(type_tag, index) + inner_tags, index = cls._from_str_internal(type_tag, index) elif letter == ",": split = name.split("::") tag = TypeTag( @@ -359,13 +359,13 @@ def _from_str_internal(type_tag: str, index: int) -> Tuple[List[TypeTag], int]: def variant(self): return TypeTag.STRUCT - @staticmethod - def deserialize(deserializer: Deserializer) -> StructTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> StructTag: address = deserializer.struct(AccountAddress) module = deserializer.str() name = deserializer.str() type_args = deserializer.sequence(TypeTag.deserialize) - return StructTag(address, module, name, type_args) + return cls(address, module, name, type_args) def serialize(self, serializer: Serializer): self.address.serialize(serializer) diff --git a/aptos_sdk/v2/account/account.py b/aptos_sdk/v2/account/account.py index 9c76a46..19f4ae2 100644 --- a/aptos_sdk/v2/account/account.py +++ b/aptos_sdk/v2/account/account.py @@ -26,34 +26,35 @@ def __init__(self, private_key: PrivateKey, address: AccountAddress) -> None: self._private_key = private_key self._address = address - @staticmethod - def generate() -> Account: + @classmethod + def generate(cls) -> Account: """Generate a new Ed25519 account.""" key = Ed25519PrivateKey.generate() pub = key.public_key() auth_key = AuthenticationKey.from_public_key(pub) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod - def generate_secp256k1() -> Account: + @classmethod + def generate_secp256k1(cls) -> Account: """Generate a new Secp256k1 account.""" key = Secp256k1PrivateKey.generate() pub = AnyPublicKey(key.public_key()) auth_key = AuthenticationKey.from_public_key(pub) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod - def from_private_key(key: PrivateKey) -> Account: + @classmethod + def from_private_key(cls, key: PrivateKey) -> Account: """Create an account from an existing private key.""" pub = key.public_key() if isinstance(pub, Ed25519PublicKey): auth_key = AuthenticationKey.from_public_key(pub) else: auth_key = AuthenticationKey.from_public_key(AnyPublicKey(pub)) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod + @classmethod def from_mnemonic( + cls, phrase: str, path: str = DEFAULT_DERIVATION_PATH, *, @@ -65,7 +66,7 @@ def from_mnemonic( key = derive_secp256k1_private_key(phrase, path) else: key = derive_ed25519_private_key(phrase, path) - return Account.from_private_key(key) + return cls.from_private_key(key) @property def address(self) -> AccountAddress: diff --git a/aptos_sdk/v2/bcs/protocols.py b/aptos_sdk/v2/bcs/protocols.py index e7165fd..e2bc1eb 100644 --- a/aptos_sdk/v2/bcs/protocols.py +++ b/aptos_sdk/v2/bcs/protocols.py @@ -27,8 +27,8 @@ def to_bytes(self) -> bytes: class Deserializable(Protocol): """Types that can be deserialized from BCS bytes.""" - @staticmethod - def deserialize(deserializer: Deserializer) -> Any: ... + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Any: ... @classmethod def from_bytes(cls, data: bytes) -> Any: diff --git a/aptos_sdk/v2/crypto/authentication_key.py b/aptos_sdk/v2/crypto/authentication_key.py index 69bfb41..94cda63 100644 --- a/aptos_sdk/v2/crypto/authentication_key.py +++ b/aptos_sdk/v2/crypto/authentication_key.py @@ -19,8 +19,8 @@ class AuthenticationKey: def __init__(self, data: bytes) -> None: self._data = data - @staticmethod - def from_public_key(key: PublicKey) -> AuthenticationKey: + @classmethod + def from_public_key(cls, key: PublicKey) -> AuthenticationKey: # Auto-wrap non-Ed25519 keys into AnyPublicKey for single-key auth if isinstance(key, Secp256k1PublicKey): key = AnyPublicKey(key) @@ -35,7 +35,7 @@ def from_public_key(key: PublicKey) -> AuthenticationKey: else: raise ValueError(f"Unsupported public key type: {type(key).__name__}") - return AuthenticationKey(hasher.digest()) + return cls(hasher.digest()) def account_address(self) -> AccountAddress: return AccountAddress(self._data) diff --git a/aptos_sdk/v2/crypto/ed25519.py b/aptos_sdk/v2/crypto/ed25519.py index 58fdb9e..3158efc 100644 --- a/aptos_sdk/v2/crypto/ed25519.py +++ b/aptos_sdk/v2/crypto/ed25519.py @@ -29,27 +29,27 @@ def __eq__(self, other: object) -> bool: def _variant(self) -> PrivateKeyVariant: return PrivateKeyVariant.ED25519 - @staticmethod - def generate() -> Ed25519PrivateKey: - return Ed25519PrivateKey(SigningKey.generate()) + @classmethod + def generate(cls) -> Ed25519PrivateKey: + return cls(SigningKey.generate()) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> Ed25519PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> Ed25519PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.ED25519, strict) if len(raw) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError( f"Ed25519 private key must be {Ed25519PrivateKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PrivateKey(SigningKey(raw)) + return cls(SigningKey(raw)) - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> Ed25519PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> Ed25519PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.ED25519, strict) if len(raw) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError( f"Ed25519 private key must be {Ed25519PrivateKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PrivateKey(SigningKey(raw)) + return cls(SigningKey(raw)) def hex(self) -> str: return f"0x{self._key.encode().hex()}" @@ -60,12 +60,12 @@ def public_key(self) -> Ed25519PublicKey: def sign(self, data: bytes) -> Ed25519Signature: return Ed25519Signature(self._key.sign(data).signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519PrivateKey: key = deserializer.to_bytes() if len(key) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") - return Ed25519PrivateKey(SigningKey(key)) + return cls(SigningKey(key)) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._key.encode()) @@ -88,8 +88,8 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"0x{self._key.encode().hex()}" - @staticmethod - def from_str(value: str) -> Ed25519PublicKey: + @classmethod + def from_str(cls, value: str) -> Ed25519PublicKey: if value.startswith("0x"): value = value[2:] raw = bytes.fromhex(value) @@ -97,7 +97,7 @@ def from_str(value: str) -> Ed25519PublicKey: raise InvalidKeyError( f"Ed25519 public key must be {Ed25519PublicKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PublicKey(VerifyKey(raw)) + return cls(VerifyKey(raw)) def to_crypto_bytes(self) -> bytes: return self._key.encode() @@ -109,12 +109,12 @@ def verify(self, data: bytes, signature: SignatureBase) -> bool: except Exception: return False - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519PublicKey: key = deserializer.to_bytes() if len(key) != Ed25519PublicKey.LENGTH: raise InvalidKeyError("Length mismatch") - return Ed25519PublicKey(VerifyKey(key)) + return cls(VerifyKey(key)) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._key.encode()) @@ -140,18 +140,18 @@ def __str__(self) -> str: def data(self) -> bytes: return self._signature - @staticmethod - def from_str(value: str) -> Ed25519Signature: + @classmethod + def from_str(cls, value: str) -> Ed25519Signature: if value.startswith("0x"): value = value[2:] - return Ed25519Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519Signature: sig = deserializer.to_bytes() if len(sig) != Ed25519Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Ed25519Signature(sig) + return cls(sig) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._signature) diff --git a/aptos_sdk/v2/crypto/keys.py b/aptos_sdk/v2/crypto/keys.py index 98a43b7..fcf5886 100644 --- a/aptos_sdk/v2/crypto/keys.py +++ b/aptos_sdk/v2/crypto/keys.py @@ -34,9 +34,9 @@ def sign(self, data: bytes) -> Signature: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> PrivateKey: ... + def deserialize(cls, deserializer: Deserializer) -> PrivateKey: ... def aip80(self) -> str: return format_private_key(self.hex(), self._variant()) @@ -60,9 +60,9 @@ def verify(self, data: bytes, signature: Signature) -> bool: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> PublicKey: ... + def deserialize(cls, deserializer: Deserializer) -> PublicKey: ... class Signature(ABC): @@ -74,9 +74,9 @@ def data(self) -> bytes: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> Signature: ... + def deserialize(cls, deserializer: Deserializer) -> Signature: ... # --- AIP-80 helpers --- diff --git a/aptos_sdk/v2/crypto/secp256k1.py b/aptos_sdk/v2/crypto/secp256k1.py index 43098a6..0319ee3 100644 --- a/aptos_sdk/v2/crypto/secp256k1.py +++ b/aptos_sdk/v2/crypto/secp256k1.py @@ -39,28 +39,28 @@ def __eq__(self, other: object) -> bool: def _variant(self) -> PrivateKeyVariant: return PrivateKeyVariant.SECP256K1 - @staticmethod - def generate() -> Secp256k1PrivateKey: - return Secp256k1PrivateKey(ec.generate_private_key(ec.SECP256K1())) + @classmethod + def generate(cls) -> Secp256k1PrivateKey: + return cls(ec.generate_private_key(ec.SECP256K1())) - @staticmethod - def _from_raw(raw: bytes) -> Secp256k1PrivateKey: + @classmethod + def _from_raw(cls, raw: bytes) -> Secp256k1PrivateKey: if len(raw) != Secp256k1PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") private_int = int.from_bytes(raw, "big") if not (1 <= private_int < _N): raise InvalidKeyError("Secp256k1 private key scalar must be in [1, N)") - return Secp256k1PrivateKey(ec.derive_private_key(private_int, ec.SECP256K1())) + return cls(ec.derive_private_key(private_int, ec.SECP256K1())) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> Secp256k1PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> Secp256k1PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.SECP256K1, strict) - return Secp256k1PrivateKey._from_raw(raw) + return cls._from_raw(raw) - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> Secp256k1PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> Secp256k1PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.SECP256K1, strict) - return Secp256k1PrivateKey._from_raw(raw) + return cls._from_raw(raw) def hex(self) -> str: raw = self._key.private_numbers().private_value.to_bytes(self.LENGTH, "big") @@ -81,10 +81,10 @@ def sign(self, data: bytes) -> Secp256k1Signature: sig_bytes = r.to_bytes(32, "big") + s.to_bytes(32, "big") return Secp256k1Signature(sig_bytes) - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1PrivateKey: key = deserializer.to_bytes() - return Secp256k1PrivateKey._from_raw(key) + return cls._from_raw(key) def serialize(self, serializer: Serializer) -> None: raw = self._key.private_numbers().private_value.to_bytes(self.LENGTH, "big") @@ -114,14 +114,14 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"0x04{self._raw.hex()}" - @staticmethod - def from_str(value: str) -> Secp256k1PublicKey: + @classmethod + def from_str(cls, value: str) -> Secp256k1PublicKey: if value.startswith("0x"): value = value[2:] raw = bytes.fromhex(value) if len(raw) == 65 and raw[0] == 0x04: raw = raw[1:] - return Secp256k1PublicKey(raw) + return cls(raw) def to_crypto_bytes(self) -> bytes: return b"\x04" + self._raw @@ -144,10 +144,10 @@ def verify(self, data: bytes, signature: SignatureBase) -> bool: return False return True - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1PublicKey: key = deserializer.to_bytes() - return Secp256k1PublicKey(key) + return cls(key) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self.to_crypto_bytes()) @@ -173,20 +173,20 @@ def __str__(self) -> str: def data(self) -> bytes: return self._signature - @staticmethod - def from_str(value: str) -> Secp256k1Signature: + @classmethod + def from_str(cls, value: str) -> Secp256k1Signature: if value.startswith("0x"): value = value[2:] if len(value) != Secp256k1Signature.LENGTH * 2: raise InvalidSignatureError("Length mismatch") - return Secp256k1Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1Signature: sig = deserializer.to_bytes() if len(sig) != Secp256k1Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Secp256k1Signature(sig) + return cls(sig) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._signature) diff --git a/aptos_sdk/v2/crypto/single_key.py b/aptos_sdk/v2/crypto/single_key.py index eeea0f1..99f543e 100644 --- a/aptos_sdk/v2/crypto/single_key.py +++ b/aptos_sdk/v2/crypto/single_key.py @@ -57,14 +57,14 @@ def verify(self, data: bytes, signature: Signature) -> bool: return self._inner.verify(data, signature.inner) return self._inner.verify(data, signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> AnyPublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AnyPublicKey: variant = deserializer.uleb128() match variant: case AnyPublicKeyVariant.ED25519: - return AnyPublicKey(Ed25519PublicKey.deserialize(deserializer)) + return cls(Ed25519PublicKey.deserialize(deserializer)) case AnyPublicKeyVariant.SECP256K1: - return AnyPublicKey(Secp256k1PublicKey.deserialize(deserializer)) + return cls(Secp256k1PublicKey.deserialize(deserializer)) case _: raise InvalidKeyError(f"Unknown AnyPublicKey variant: {variant}") @@ -106,14 +106,14 @@ def inner(self) -> Signature: def data(self) -> bytes: return self._inner.data() - @staticmethod - def deserialize(deserializer: Deserializer) -> AnySignature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AnySignature: variant = deserializer.uleb128() match variant: case AnyPublicKeyVariant.ED25519: - return AnySignature(Ed25519Signature.deserialize(deserializer)) + return cls(Ed25519Signature.deserialize(deserializer)) case AnyPublicKeyVariant.SECP256K1: - return AnySignature(Secp256k1Signature.deserialize(deserializer)) + return cls(Secp256k1Signature.deserialize(deserializer)) case _: raise InvalidSignatureError(f"Unknown AnySignature variant: {variant}") diff --git a/aptos_sdk/v2/transactions/authenticator.py b/aptos_sdk/v2/transactions/authenticator.py index 25af634..50588f0 100644 --- a/aptos_sdk/v2/transactions/authenticator.py +++ b/aptos_sdk/v2/transactions/authenticator.py @@ -30,11 +30,11 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519Authenticator: key = deserializer.struct(Ed25519PublicKey) sig = deserializer.struct(Ed25519Signature) - return Ed25519Authenticator(key, sig) + return cls(key, sig) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.public_key) @@ -62,11 +62,11 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleKeyAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleKeyAuthenticator: pub = deserializer.struct(AnyPublicKey) sig = deserializer.struct(AnySignature) - return SingleKeyAuthenticator(pub, sig) + return cls(pub, sig) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.public_key) @@ -89,10 +89,10 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.sender.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleSenderAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleSenderAuthenticator: sender = deserializer.struct(AccountAuthenticator) - return SingleSenderAuthenticator(sender) + return cls(sender) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.sender) @@ -124,12 +124,12 @@ def verify(self, data: bytes) -> bool: return False return all(auth.verify(data) for _, auth in self.secondary_signers) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentAuthenticator: sender = deserializer.struct(AccountAuthenticator) addresses = deserializer.sequence(AccountAddress.deserialize) authenticators = deserializer.sequence(AccountAuthenticator.deserialize) - return MultiAgentAuthenticator(sender, list(zip(addresses, authenticators))) + return cls(sender, list(zip(addresses, authenticators))) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.sender) @@ -174,14 +174,14 @@ def verify(self, data: bytes) -> bool: return False return all(auth.verify(data) for _, auth in self.secondary_signers) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerAuthenticator: sender = deserializer.struct(AccountAuthenticator) addresses = deserializer.sequence(AccountAddress.deserialize) authenticators = deserializer.sequence(AccountAuthenticator.deserialize) fee_payer_addr = deserializer.struct(AccountAddress) fee_payer_auth = deserializer.struct(AccountAuthenticator) - return FeePayerAuthenticator( + return cls( sender, list(zip(addresses, authenticators)), (fee_payer_addr, fee_payer_auth), @@ -225,14 +225,14 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAuthenticator: variant = deserializer.uleb128() match variant: case AccountAuthenticator.ED25519: - return AccountAuthenticator(Ed25519Authenticator.deserialize(deserializer)) + return cls(Ed25519Authenticator.deserialize(deserializer)) case AccountAuthenticator.SINGLE_KEY: - return AccountAuthenticator(SingleKeyAuthenticator.deserialize(deserializer)) + return cls(SingleKeyAuthenticator.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Unknown AccountAuthenticator variant: {variant}") @@ -281,18 +281,18 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Authenticator: variant = deserializer.uleb128() match variant: case Authenticator.ED25519: - return Authenticator(Ed25519Authenticator.deserialize(deserializer)) + return cls(Ed25519Authenticator.deserialize(deserializer)) case Authenticator.MULTI_AGENT: - return Authenticator(MultiAgentAuthenticator.deserialize(deserializer)) + return cls(MultiAgentAuthenticator.deserialize(deserializer)) case Authenticator.FEE_PAYER: - return Authenticator(FeePayerAuthenticator.deserialize(deserializer)) + return cls(FeePayerAuthenticator.deserialize(deserializer)) case Authenticator.SINGLE_SENDER: - return Authenticator(SingleSenderAuthenticator.deserialize(deserializer)) + return cls(SingleSenderAuthenticator.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Unknown Authenticator variant: {variant}") diff --git a/aptos_sdk/v2/transactions/payload.py b/aptos_sdk/v2/transactions/payload.py index 14d98e6..1d8cf8a 100644 --- a/aptos_sdk/v2/transactions/payload.py +++ b/aptos_sdk/v2/transactions/payload.py @@ -28,20 +28,20 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"{self.address}::{self.name}" - @staticmethod - def from_str(module_id: str) -> ModuleId: + @classmethod + def from_str(cls, module_id: str) -> ModuleId: parts = module_id.split("::") if len(parts) != 2 or not parts[0] or not parts[1]: raise ValueError( f"Invalid module ID '{module_id}': expected format 'address::module_name'" ) - return ModuleId(AccountAddress.from_str(parts[0]), parts[1]) + return cls(AccountAddress.from_str(parts[0]), parts[1]) - @staticmethod - def deserialize(deserializer: Deserializer) -> ModuleId: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ModuleId: addr = AccountAddress.deserialize(deserializer) name = deserializer.str() - return ModuleId(addr, name) + return cls(addr, name) def serialize(self, serializer: Serializer) -> None: self.address.serialize(serializer) @@ -93,8 +93,9 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"{self.module}::{self.function}::<{self.ty_args}>({self.args})" - @staticmethod + @classmethod def natural( + cls, module: str, function: str, ty_args: list[TypeTag], @@ -102,15 +103,15 @@ def natural( ) -> EntryFunction: module_id = ModuleId.from_str(module) byte_args = [arg.encode() for arg in args] - return EntryFunction(module_id, function, ty_args, byte_args) + return cls(module_id, function, ty_args, byte_args) - @staticmethod - def deserialize(deserializer: Deserializer) -> EntryFunction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> EntryFunction: module = ModuleId.deserialize(deserializer) function = deserializer.str() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(Deserializer.to_bytes) - return EntryFunction(module, function, ty_args, args) + return cls(module, function, ty_args, args) def serialize(self, serializer: Serializer) -> None: self.module.serialize(serializer) @@ -134,12 +135,12 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.code == other.code and self.ty_args == other.ty_args and self.args == other.args - @staticmethod - def deserialize(deserializer: Deserializer) -> Script: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Script: code = deserializer.to_bytes() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(ScriptArgument.deserialize) - return Script(code, ty_args, args) + return cls(code, ty_args, args) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self.code) @@ -171,8 +172,8 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.variant == other.variant and self.value == other.value - @staticmethod - def deserialize(deserializer: Deserializer) -> ScriptArgument: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ScriptArgument: variant = deserializer.u8() value: Any match variant: @@ -196,7 +197,7 @@ def deserialize(deserializer: Deserializer) -> ScriptArgument: value = deserializer.bool() case _: raise BcsDeserializationError(f"Invalid ScriptArgument variant: {variant}") - return ScriptArgument(variant, value) + return cls(variant, value) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.variant) @@ -246,14 +247,14 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.variant == other.variant and self.value == other.value - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionExecutable: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionExecutable: variant = deserializer.uleb128() match variant: case TransactionExecutable.SCRIPT: - return TransactionExecutable(Script.deserialize(deserializer)) + return cls(Script.deserialize(deserializer)) case TransactionExecutable.ENTRY_FUNCTION: - return TransactionExecutable(EntryFunction.deserialize(deserializer)) + return cls(EntryFunction.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Invalid TransactionExecutable variant: {variant}") @@ -284,14 +285,14 @@ def __eq__(self, other: object) -> bool: and self.replay_protection_nonce == other.replay_protection_nonce ) - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionExtraConfig: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionExtraConfig: variant = deserializer.uleb128() if variant != 0: raise BcsDeserializationError(f"Invalid TransactionExtraConfig variant: {variant}") multisig = deserializer.option(AccountAddress.deserialize) nonce = deserializer.option(Deserializer.u64) - return TransactionExtraConfig(multisig_address=multisig, replay_protection_nonce=nonce) + return cls(multisig_address=multisig, replay_protection_nonce=nonce) def serialize(self, serializer: Serializer) -> None: serializer.uleb128(0) # V1 @@ -317,14 +318,14 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.executable == other.executable and self.extra_config == other.extra_config - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionInnerPayload: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionInnerPayload: variant = deserializer.uleb128() if variant != 0: raise BcsDeserializationError(f"Invalid TransactionInnerPayload variant: {variant}") executable = TransactionExecutable.deserialize(deserializer) extra_config = TransactionExtraConfig.deserialize(deserializer) - return TransactionInnerPayload(executable, extra_config) + return cls(executable, extra_config) def serialize(self, serializer: Serializer) -> None: serializer.uleb128(0) # V1 @@ -360,16 +361,16 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionPayload: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionPayload: variant = deserializer.uleb128() match variant: case TransactionPayload.SCRIPT: - return TransactionPayload(Script.deserialize(deserializer)) + return cls(Script.deserialize(deserializer)) case TransactionPayload.ENTRY_FUNCTION: - return TransactionPayload(EntryFunction.deserialize(deserializer)) + return cls(EntryFunction.deserialize(deserializer)) case TransactionPayload.PAYLOAD: - return TransactionPayload(TransactionInnerPayload.deserialize(deserializer)) + return cls(TransactionInnerPayload.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Invalid TransactionPayload variant: {variant}") diff --git a/aptos_sdk/v2/transactions/raw_transaction.py b/aptos_sdk/v2/transactions/raw_transaction.py index 92df114..ee81953 100644 --- a/aptos_sdk/v2/transactions/raw_transaction.py +++ b/aptos_sdk/v2/transactions/raw_transaction.py @@ -103,9 +103,9 @@ def sign_simulated(self, public_key: PublicKey) -> AccountAuthenticator: def verify(self, key: PublicKey, signature: Signature) -> bool: return key.verify(self.keyed(), signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> RawTransaction: - return RawTransaction( + @classmethod + def deserialize(cls, deserializer: Deserializer) -> RawTransaction: + return cls( AccountAddress.deserialize(deserializer), deserializer.u64(), TransactionPayload.deserialize(deserializer), @@ -154,18 +154,18 @@ def serialize(self, serializer: Serializer) -> None: serializer.struct(self.raw_transaction) serializer.sequence(self.secondary_signers, Serializer.struct) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: tag = deserializer.u8() if tag != 0: raise BcsDeserializationError(f"Expected multi-agent tag 0, got {tag}") - return MultiAgentRawTransaction._deserialize_inner(deserializer) + return cls._deserialize_inner(deserializer) - @staticmethod - def _deserialize_inner(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def _deserialize_inner(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary = deserializer.sequence(AccountAddress.deserialize) - return MultiAgentRawTransaction(raw_txn, secondary) + return cls(raw_txn, secondary) class FeePayerRawTransaction: @@ -203,18 +203,18 @@ def serialize(self, serializer: Serializer) -> None: fee_payer = self.fee_payer if self.fee_payer is not None else AccountAddress.from_str("0x0") serializer.struct(fee_payer) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerRawTransaction: tag = deserializer.u8() if tag != 1: raise BcsDeserializationError(f"Expected fee-payer tag 1, got {tag}") - return FeePayerRawTransaction._deserialize_inner(deserializer) + return cls._deserialize_inner(deserializer) - @staticmethod - def _deserialize_inner(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def _deserialize_inner(cls, deserializer: Deserializer) -> FeePayerRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary = deserializer.sequence(AccountAddress.deserialize) fee_payer_addr = AccountAddress.deserialize(deserializer) if fee_payer_addr == AccountAddress.from_str("0x0"): - return FeePayerRawTransaction(raw_txn, secondary, None) - return FeePayerRawTransaction(raw_txn, secondary, fee_payer_addr) + return cls(raw_txn, secondary, None) + return cls(raw_txn, secondary, fee_payer_addr) diff --git a/aptos_sdk/v2/transactions/signed_transaction.py b/aptos_sdk/v2/transactions/signed_transaction.py index 4981cb4..2a4eae8 100644 --- a/aptos_sdk/v2/transactions/signed_transaction.py +++ b/aptos_sdk/v2/transactions/signed_transaction.py @@ -70,11 +70,11 @@ def verify(self) -> bool: else: return self.authenticator.verify(self.transaction.keyed()) - @staticmethod - def deserialize(deserializer: Deserializer) -> SignedTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SignedTransaction: transaction = RawTransaction.deserialize(deserializer) authenticator = Authenticator.deserialize(deserializer) - return SignedTransaction(transaction, authenticator) + return cls(transaction, authenticator) def serialize(self, serializer: Serializer) -> None: self.transaction.serialize(serializer) diff --git a/aptos_sdk/v2/types/account_address.py b/aptos_sdk/v2/types/account_address.py index 6ac9b7d..405cd78 100644 --- a/aptos_sdk/v2/types/account_address.py +++ b/aptos_sdk/v2/types/account_address.py @@ -41,13 +41,13 @@ def is_special(self) -> bool: # --- Parsing --- - @staticmethod - def from_str(address: str) -> AccountAddress: + @classmethod + def from_str(cls, address: str) -> AccountAddress: """Strict AIP-40 parsing: LONG form or SHORT form for special addresses only.""" if not address.startswith("0x"): raise InvalidAddressError("Hex string must start with a leading 0x.") - out = AccountAddress.from_str_relaxed(address) + out = cls.from_str_relaxed(address) if len(address) != LENGTH * 2 + 2: if not out.is_special(): @@ -61,8 +61,8 @@ def from_str(address: str) -> AccountAddress: return out - @staticmethod - def from_str_relaxed(address: str) -> AccountAddress: + @classmethod + def from_str_relaxed(cls, address: str) -> AccountAddress: """Relaxed parsing: allows short form, padding zeroes, and optional 0x prefix.""" addr = address if addr.startswith("0x"): @@ -77,55 +77,53 @@ def from_str_relaxed(address: str) -> AccountAddress: addr = addr.zfill(LENGTH * 2) try: - return AccountAddress(bytes.fromhex(addr)) + return cls(bytes.fromhex(addr)) except ValueError as e: raise InvalidAddressError(f"Invalid hex in address: {e}") from e # --- Derived addresses --- - @staticmethod - def for_resource_account(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_resource_account(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DERIVE_RESOURCE_ACCOUNT) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_named_object(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_named_object(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DERIVE_OBJECT_FROM_SEED) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_guid_object(creator: AccountAddress, creation_num: int) -> AccountAddress: + @classmethod + def for_guid_object(cls, creator: AccountAddress, creation_num: int) -> AccountAddress: hasher = hashlib.sha3_256() ser = Serializer() ser.u64(creation_num) hasher.update(ser.output()) hasher.update(creator.address) hasher.update(AuthKeyScheme.DERIVE_OBJECT_FROM_GUID) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_named_collection(creator: AccountAddress, collection_name: str) -> AccountAddress: - return AccountAddress.for_named_object(creator, collection_name.encode()) + @classmethod + def for_named_collection(cls, creator: AccountAddress, collection_name: str) -> AccountAddress: + return cls.for_named_object(creator, collection_name.encode()) - @staticmethod + @classmethod def for_named_token( - creator: AccountAddress, collection_name: str, token_name: str + cls, creator: AccountAddress, collection_name: str, token_name: str ) -> AccountAddress: - return AccountAddress.for_named_object( - creator, collection_name.encode() + b"::" + token_name.encode() - ) + return cls.for_named_object(creator, collection_name.encode() + b"::" + token_name.encode()) # --- BCS --- - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddress: - return AccountAddress(deserializer.fixed_bytes(LENGTH)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddress: + return cls(deserializer.fixed_bytes(LENGTH)) def serialize(self, serializer: Serializer) -> None: serializer.fixed_bytes(self.address) diff --git a/aptos_sdk/v2/types/chain_id.py b/aptos_sdk/v2/types/chain_id.py index 2fab210..d31d1a2 100644 --- a/aptos_sdk/v2/types/chain_id.py +++ b/aptos_sdk/v2/types/chain_id.py @@ -21,9 +21,9 @@ def __post_init__(self) -> None: if not (0 <= self.value <= 255): raise ValueError(f"Chain ID must be 0-255, got {self.value}") - @staticmethod - def deserialize(deserializer: Deserializer) -> ChainId: - return ChainId(deserializer.u8()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ChainId: + return cls(deserializer.u8()) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.value) diff --git a/aptos_sdk/v2/types/type_tag.py b/aptos_sdk/v2/types/type_tag.py index 2ec182a..c930593 100644 --- a/aptos_sdk/v2/types/type_tag.py +++ b/aptos_sdk/v2/types/type_tag.py @@ -51,9 +51,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> BoolTag: - return BoolTag(deserializer.bool()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> BoolTag: + return cls(deserializer.bool()) def serialize(self, serializer: Serializer) -> None: serializer.bool(self.value) @@ -69,9 +69,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U8Tag: - return U8Tag(deserializer.u8()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U8Tag: + return cls(deserializer.u8()) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.value) @@ -87,9 +87,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U16Tag: - return U16Tag(deserializer.u16()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U16Tag: + return cls(deserializer.u16()) def serialize(self, serializer: Serializer) -> None: serializer.u16(self.value) @@ -105,9 +105,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U32Tag: - return U32Tag(deserializer.u32()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U32Tag: + return cls(deserializer.u32()) def serialize(self, serializer: Serializer) -> None: serializer.u32(self.value) @@ -123,9 +123,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U64Tag: - return U64Tag(deserializer.u64()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U64Tag: + return cls(deserializer.u64()) def serialize(self, serializer: Serializer) -> None: serializer.u64(self.value) @@ -141,9 +141,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U128Tag: - return U128Tag(deserializer.u128()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U128Tag: + return cls(deserializer.u128()) def serialize(self, serializer: Serializer) -> None: serializer.u128(self.value) @@ -159,9 +159,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U256Tag: - return U256Tag(deserializer.u256()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U256Tag: + return cls(deserializer.u256()) def serialize(self, serializer: Serializer) -> None: serializer.u256(self.value) @@ -177,9 +177,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddressTag: - return AccountAddressTag(deserializer.struct(AccountAddress)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddressTag: + return cls(deserializer.struct(AccountAddress)) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.value) @@ -193,9 +193,9 @@ def variant(self) -> int: def __str__(self) -> str: return "signer" - @staticmethod - def deserialize(deserializer: Deserializer) -> SignerTag: - return SignerTag() + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SignerTag: + return cls() def serialize(self, serializer: Serializer) -> None: pass @@ -231,8 +231,8 @@ def __str__(self) -> str: value += f"<{args}>" return value - @staticmethod - def from_str(type_tag: str) -> StructTag: + @classmethod + def from_str(cls, type_tag: str) -> StructTag: tags, _ = _parse_type_tags(type_tag, 0) if not tags: # pragma: no cover — parser always appends via _make_struct_tag raise InvalidTypeTagError(f"Cannot parse type tag: {type_tag}") @@ -241,13 +241,13 @@ def from_str(type_tag: str) -> StructTag: raise InvalidTypeTagError(f"Expected StructTag, got {type(inner).__name__}") return inner - @staticmethod - def deserialize(deserializer: Deserializer) -> StructTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> StructTag: address = deserializer.struct(AccountAddress) module = deserializer.str() name = deserializer.str() type_args = deserializer.sequence(TypeTag.deserialize) - return StructTag(address, module, name, type_args) + return cls(address, module, name, type_args) def serialize(self, serializer: Serializer) -> None: self.address.serialize(serializer) @@ -274,9 +274,9 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"vector<{self.element_type}>" - @staticmethod - def deserialize(deserializer: Deserializer) -> VectorTag: - return VectorTag(TypeTag.deserialize(deserializer)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> VectorTag: + return cls(TypeTag.deserialize(deserializer)) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.element_type) @@ -319,34 +319,34 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - @staticmethod - def deserialize(deserializer: Deserializer) -> TypeTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TypeTag: variant = deserializer.uleb128() match variant: # Primitive variants carry no BCS payload after the discriminant. case TypeTagVariant.BOOL: - return TypeTag(BoolTag(False)) + return cls(BoolTag(False)) case TypeTagVariant.U8: - return TypeTag(U8Tag(0)) + return cls(U8Tag(0)) case TypeTagVariant.U16: - return TypeTag(U16Tag(0)) + return cls(U16Tag(0)) case TypeTagVariant.U32: - return TypeTag(U32Tag(0)) + return cls(U32Tag(0)) case TypeTagVariant.U64: - return TypeTag(U64Tag(0)) + return cls(U64Tag(0)) case TypeTagVariant.U128: - return TypeTag(U128Tag(0)) + return cls(U128Tag(0)) case TypeTagVariant.U256: - return TypeTag(U256Tag(0)) + return cls(U256Tag(0)) case TypeTagVariant.ACCOUNT_ADDRESS: - return TypeTag(AccountAddressTag(AccountAddress(b"\x00" * 32))) + return cls(AccountAddressTag(AccountAddress(b"\x00" * 32))) case TypeTagVariant.SIGNER: - return TypeTag(SignerTag()) + return cls(SignerTag()) # Composite variants do have inner BCS data. case TypeTagVariant.VECTOR: - return TypeTag(VectorTag.deserialize(deserializer)) + return cls(VectorTag.deserialize(deserializer)) case TypeTagVariant.STRUCT: - return TypeTag(StructTag.deserialize(deserializer)) + return cls(StructTag.deserialize(deserializer)) case _: raise InvalidTypeTagError(f"Unknown TypeTag variant: {variant}") @@ -357,8 +357,8 @@ def serialize(self, serializer: Serializer) -> None: if isinstance(self.value, (VectorTag, StructTag)): serializer.struct(self.value) - @staticmethod - def from_str(type_tag: str) -> TypeTag: + @classmethod + def from_str(cls, type_tag: str) -> TypeTag: """Parse a Move type-tag string into a :class:`TypeTag`. Supports: diff --git a/v2/CLAUDE.md b/v2/CLAUDE.md index 92c075c..1724d12 100644 --- a/v2/CLAUDE.md +++ b/v2/CLAUDE.md @@ -81,8 +81,8 @@ Every BCS type implements: ```python def serialize(self, serializer: Serializer) -> None: ... -@staticmethod -def deserialize(deserializer: Deserializer) -> Self: ... +@classmethod +def deserialize(cls, deserializer: Deserializer) -> Self: ... ``` Use `Serializable` and `Deserializable` protocols from `bcs/protocols.py`. Call `serializer.struct(obj)` for nested types, `serializer.sequence(items, Serializer.struct)` for lists. diff --git a/v2/src/aptos_sdk_v2/account/account.py b/v2/src/aptos_sdk_v2/account/account.py index 9c76a46..19f4ae2 100644 --- a/v2/src/aptos_sdk_v2/account/account.py +++ b/v2/src/aptos_sdk_v2/account/account.py @@ -26,34 +26,35 @@ def __init__(self, private_key: PrivateKey, address: AccountAddress) -> None: self._private_key = private_key self._address = address - @staticmethod - def generate() -> Account: + @classmethod + def generate(cls) -> Account: """Generate a new Ed25519 account.""" key = Ed25519PrivateKey.generate() pub = key.public_key() auth_key = AuthenticationKey.from_public_key(pub) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod - def generate_secp256k1() -> Account: + @classmethod + def generate_secp256k1(cls) -> Account: """Generate a new Secp256k1 account.""" key = Secp256k1PrivateKey.generate() pub = AnyPublicKey(key.public_key()) auth_key = AuthenticationKey.from_public_key(pub) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod - def from_private_key(key: PrivateKey) -> Account: + @classmethod + def from_private_key(cls, key: PrivateKey) -> Account: """Create an account from an existing private key.""" pub = key.public_key() if isinstance(pub, Ed25519PublicKey): auth_key = AuthenticationKey.from_public_key(pub) else: auth_key = AuthenticationKey.from_public_key(AnyPublicKey(pub)) - return Account(key, auth_key.account_address()) + return cls(key, auth_key.account_address()) - @staticmethod + @classmethod def from_mnemonic( + cls, phrase: str, path: str = DEFAULT_DERIVATION_PATH, *, @@ -65,7 +66,7 @@ def from_mnemonic( key = derive_secp256k1_private_key(phrase, path) else: key = derive_ed25519_private_key(phrase, path) - return Account.from_private_key(key) + return cls.from_private_key(key) @property def address(self) -> AccountAddress: diff --git a/v2/src/aptos_sdk_v2/bcs/protocols.py b/v2/src/aptos_sdk_v2/bcs/protocols.py index e7165fd..e2bc1eb 100644 --- a/v2/src/aptos_sdk_v2/bcs/protocols.py +++ b/v2/src/aptos_sdk_v2/bcs/protocols.py @@ -27,8 +27,8 @@ def to_bytes(self) -> bytes: class Deserializable(Protocol): """Types that can be deserialized from BCS bytes.""" - @staticmethod - def deserialize(deserializer: Deserializer) -> Any: ... + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Any: ... @classmethod def from_bytes(cls, data: bytes) -> Any: diff --git a/v2/src/aptos_sdk_v2/crypto/authentication_key.py b/v2/src/aptos_sdk_v2/crypto/authentication_key.py index 69bfb41..94cda63 100644 --- a/v2/src/aptos_sdk_v2/crypto/authentication_key.py +++ b/v2/src/aptos_sdk_v2/crypto/authentication_key.py @@ -19,8 +19,8 @@ class AuthenticationKey: def __init__(self, data: bytes) -> None: self._data = data - @staticmethod - def from_public_key(key: PublicKey) -> AuthenticationKey: + @classmethod + def from_public_key(cls, key: PublicKey) -> AuthenticationKey: # Auto-wrap non-Ed25519 keys into AnyPublicKey for single-key auth if isinstance(key, Secp256k1PublicKey): key = AnyPublicKey(key) @@ -35,7 +35,7 @@ def from_public_key(key: PublicKey) -> AuthenticationKey: else: raise ValueError(f"Unsupported public key type: {type(key).__name__}") - return AuthenticationKey(hasher.digest()) + return cls(hasher.digest()) def account_address(self) -> AccountAddress: return AccountAddress(self._data) diff --git a/v2/src/aptos_sdk_v2/crypto/ed25519.py b/v2/src/aptos_sdk_v2/crypto/ed25519.py index 58fdb9e..3158efc 100644 --- a/v2/src/aptos_sdk_v2/crypto/ed25519.py +++ b/v2/src/aptos_sdk_v2/crypto/ed25519.py @@ -29,27 +29,27 @@ def __eq__(self, other: object) -> bool: def _variant(self) -> PrivateKeyVariant: return PrivateKeyVariant.ED25519 - @staticmethod - def generate() -> Ed25519PrivateKey: - return Ed25519PrivateKey(SigningKey.generate()) + @classmethod + def generate(cls) -> Ed25519PrivateKey: + return cls(SigningKey.generate()) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> Ed25519PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> Ed25519PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.ED25519, strict) if len(raw) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError( f"Ed25519 private key must be {Ed25519PrivateKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PrivateKey(SigningKey(raw)) + return cls(SigningKey(raw)) - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> Ed25519PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> Ed25519PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.ED25519, strict) if len(raw) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError( f"Ed25519 private key must be {Ed25519PrivateKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PrivateKey(SigningKey(raw)) + return cls(SigningKey(raw)) def hex(self) -> str: return f"0x{self._key.encode().hex()}" @@ -60,12 +60,12 @@ def public_key(self) -> Ed25519PublicKey: def sign(self, data: bytes) -> Ed25519Signature: return Ed25519Signature(self._key.sign(data).signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519PrivateKey: key = deserializer.to_bytes() if len(key) != Ed25519PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") - return Ed25519PrivateKey(SigningKey(key)) + return cls(SigningKey(key)) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._key.encode()) @@ -88,8 +88,8 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"0x{self._key.encode().hex()}" - @staticmethod - def from_str(value: str) -> Ed25519PublicKey: + @classmethod + def from_str(cls, value: str) -> Ed25519PublicKey: if value.startswith("0x"): value = value[2:] raw = bytes.fromhex(value) @@ -97,7 +97,7 @@ def from_str(value: str) -> Ed25519PublicKey: raise InvalidKeyError( f"Ed25519 public key must be {Ed25519PublicKey.LENGTH} bytes, got {len(raw)}" ) - return Ed25519PublicKey(VerifyKey(raw)) + return cls(VerifyKey(raw)) def to_crypto_bytes(self) -> bytes: return self._key.encode() @@ -109,12 +109,12 @@ def verify(self, data: bytes, signature: SignatureBase) -> bool: except Exception: return False - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519PublicKey: key = deserializer.to_bytes() if len(key) != Ed25519PublicKey.LENGTH: raise InvalidKeyError("Length mismatch") - return Ed25519PublicKey(VerifyKey(key)) + return cls(VerifyKey(key)) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._key.encode()) @@ -140,18 +140,18 @@ def __str__(self) -> str: def data(self) -> bytes: return self._signature - @staticmethod - def from_str(value: str) -> Ed25519Signature: + @classmethod + def from_str(cls, value: str) -> Ed25519Signature: if value.startswith("0x"): value = value[2:] - return Ed25519Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519Signature: sig = deserializer.to_bytes() if len(sig) != Ed25519Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Ed25519Signature(sig) + return cls(sig) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._signature) diff --git a/v2/src/aptos_sdk_v2/crypto/keys.py b/v2/src/aptos_sdk_v2/crypto/keys.py index 98a43b7..fcf5886 100644 --- a/v2/src/aptos_sdk_v2/crypto/keys.py +++ b/v2/src/aptos_sdk_v2/crypto/keys.py @@ -34,9 +34,9 @@ def sign(self, data: bytes) -> Signature: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> PrivateKey: ... + def deserialize(cls, deserializer: Deserializer) -> PrivateKey: ... def aip80(self) -> str: return format_private_key(self.hex(), self._variant()) @@ -60,9 +60,9 @@ def verify(self, data: bytes, signature: Signature) -> bool: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> PublicKey: ... + def deserialize(cls, deserializer: Deserializer) -> PublicKey: ... class Signature(ABC): @@ -74,9 +74,9 @@ def data(self) -> bytes: ... @abstractmethod def serialize(self, serializer: Serializer) -> None: ... - @staticmethod + @classmethod @abstractmethod - def deserialize(deserializer: Deserializer) -> Signature: ... + def deserialize(cls, deserializer: Deserializer) -> Signature: ... # --- AIP-80 helpers --- diff --git a/v2/src/aptos_sdk_v2/crypto/secp256k1.py b/v2/src/aptos_sdk_v2/crypto/secp256k1.py index 43098a6..0319ee3 100644 --- a/v2/src/aptos_sdk_v2/crypto/secp256k1.py +++ b/v2/src/aptos_sdk_v2/crypto/secp256k1.py @@ -39,28 +39,28 @@ def __eq__(self, other: object) -> bool: def _variant(self) -> PrivateKeyVariant: return PrivateKeyVariant.SECP256K1 - @staticmethod - def generate() -> Secp256k1PrivateKey: - return Secp256k1PrivateKey(ec.generate_private_key(ec.SECP256K1())) + @classmethod + def generate(cls) -> Secp256k1PrivateKey: + return cls(ec.generate_private_key(ec.SECP256K1())) - @staticmethod - def _from_raw(raw: bytes) -> Secp256k1PrivateKey: + @classmethod + def _from_raw(cls, raw: bytes) -> Secp256k1PrivateKey: if len(raw) != Secp256k1PrivateKey.LENGTH: raise InvalidKeyError("Length mismatch") private_int = int.from_bytes(raw, "big") if not (1 <= private_int < _N): raise InvalidKeyError("Secp256k1 private key scalar must be in [1, N)") - return Secp256k1PrivateKey(ec.derive_private_key(private_int, ec.SECP256K1())) + return cls(ec.derive_private_key(private_int, ec.SECP256K1())) - @staticmethod - def from_str(value: str, strict: bool | None = None) -> Secp256k1PrivateKey: + @classmethod + def from_str(cls, value: str, strict: bool | None = None) -> Secp256k1PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.SECP256K1, strict) - return Secp256k1PrivateKey._from_raw(raw) + return cls._from_raw(raw) - @staticmethod - def from_hex(value: str | bytes, strict: bool | None = None) -> Secp256k1PrivateKey: + @classmethod + def from_hex(cls, value: str | bytes, strict: bool | None = None) -> Secp256k1PrivateKey: raw = parse_hex_input(value, PrivateKeyVariant.SECP256K1, strict) - return Secp256k1PrivateKey._from_raw(raw) + return cls._from_raw(raw) def hex(self) -> str: raw = self._key.private_numbers().private_value.to_bytes(self.LENGTH, "big") @@ -81,10 +81,10 @@ def sign(self, data: bytes) -> Secp256k1Signature: sig_bytes = r.to_bytes(32, "big") + s.to_bytes(32, "big") return Secp256k1Signature(sig_bytes) - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1PrivateKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1PrivateKey: key = deserializer.to_bytes() - return Secp256k1PrivateKey._from_raw(key) + return cls._from_raw(key) def serialize(self, serializer: Serializer) -> None: raw = self._key.private_numbers().private_value.to_bytes(self.LENGTH, "big") @@ -114,14 +114,14 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"0x04{self._raw.hex()}" - @staticmethod - def from_str(value: str) -> Secp256k1PublicKey: + @classmethod + def from_str(cls, value: str) -> Secp256k1PublicKey: if value.startswith("0x"): value = value[2:] raw = bytes.fromhex(value) if len(raw) == 65 and raw[0] == 0x04: raw = raw[1:] - return Secp256k1PublicKey(raw) + return cls(raw) def to_crypto_bytes(self) -> bytes: return b"\x04" + self._raw @@ -144,10 +144,10 @@ def verify(self, data: bytes, signature: SignatureBase) -> bool: return False return True - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1PublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1PublicKey: key = deserializer.to_bytes() - return Secp256k1PublicKey(key) + return cls(key) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self.to_crypto_bytes()) @@ -173,20 +173,20 @@ def __str__(self) -> str: def data(self) -> bytes: return self._signature - @staticmethod - def from_str(value: str) -> Secp256k1Signature: + @classmethod + def from_str(cls, value: str) -> Secp256k1Signature: if value.startswith("0x"): value = value[2:] if len(value) != Secp256k1Signature.LENGTH * 2: raise InvalidSignatureError("Length mismatch") - return Secp256k1Signature(bytes.fromhex(value)) + return cls(bytes.fromhex(value)) - @staticmethod - def deserialize(deserializer: Deserializer) -> Secp256k1Signature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Secp256k1Signature: sig = deserializer.to_bytes() if len(sig) != Secp256k1Signature.LENGTH: raise InvalidSignatureError("Length mismatch") - return Secp256k1Signature(sig) + return cls(sig) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self._signature) diff --git a/v2/src/aptos_sdk_v2/crypto/single_key.py b/v2/src/aptos_sdk_v2/crypto/single_key.py index eeea0f1..99f543e 100644 --- a/v2/src/aptos_sdk_v2/crypto/single_key.py +++ b/v2/src/aptos_sdk_v2/crypto/single_key.py @@ -57,14 +57,14 @@ def verify(self, data: bytes, signature: Signature) -> bool: return self._inner.verify(data, signature.inner) return self._inner.verify(data, signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> AnyPublicKey: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AnyPublicKey: variant = deserializer.uleb128() match variant: case AnyPublicKeyVariant.ED25519: - return AnyPublicKey(Ed25519PublicKey.deserialize(deserializer)) + return cls(Ed25519PublicKey.deserialize(deserializer)) case AnyPublicKeyVariant.SECP256K1: - return AnyPublicKey(Secp256k1PublicKey.deserialize(deserializer)) + return cls(Secp256k1PublicKey.deserialize(deserializer)) case _: raise InvalidKeyError(f"Unknown AnyPublicKey variant: {variant}") @@ -106,14 +106,14 @@ def inner(self) -> Signature: def data(self) -> bytes: return self._inner.data() - @staticmethod - def deserialize(deserializer: Deserializer) -> AnySignature: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AnySignature: variant = deserializer.uleb128() match variant: case AnyPublicKeyVariant.ED25519: - return AnySignature(Ed25519Signature.deserialize(deserializer)) + return cls(Ed25519Signature.deserialize(deserializer)) case AnyPublicKeyVariant.SECP256K1: - return AnySignature(Secp256k1Signature.deserialize(deserializer)) + return cls(Secp256k1Signature.deserialize(deserializer)) case _: raise InvalidSignatureError(f"Unknown AnySignature variant: {variant}") diff --git a/v2/src/aptos_sdk_v2/transactions/authenticator.py b/v2/src/aptos_sdk_v2/transactions/authenticator.py index 25af634..50588f0 100644 --- a/v2/src/aptos_sdk_v2/transactions/authenticator.py +++ b/v2/src/aptos_sdk_v2/transactions/authenticator.py @@ -30,11 +30,11 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> Ed25519Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Ed25519Authenticator: key = deserializer.struct(Ed25519PublicKey) sig = deserializer.struct(Ed25519Signature) - return Ed25519Authenticator(key, sig) + return cls(key, sig) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.public_key) @@ -62,11 +62,11 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.public_key.verify(data, self.signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleKeyAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleKeyAuthenticator: pub = deserializer.struct(AnyPublicKey) sig = deserializer.struct(AnySignature) - return SingleKeyAuthenticator(pub, sig) + return cls(pub, sig) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.public_key) @@ -89,10 +89,10 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.sender.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> SingleSenderAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SingleSenderAuthenticator: sender = deserializer.struct(AccountAuthenticator) - return SingleSenderAuthenticator(sender) + return cls(sender) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.sender) @@ -124,12 +124,12 @@ def verify(self, data: bytes) -> bool: return False return all(auth.verify(data) for _, auth in self.secondary_signers) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentAuthenticator: sender = deserializer.struct(AccountAuthenticator) addresses = deserializer.sequence(AccountAddress.deserialize) authenticators = deserializer.sequence(AccountAuthenticator.deserialize) - return MultiAgentAuthenticator(sender, list(zip(addresses, authenticators))) + return cls(sender, list(zip(addresses, authenticators))) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.sender) @@ -174,14 +174,14 @@ def verify(self, data: bytes) -> bool: return False return all(auth.verify(data) for _, auth in self.secondary_signers) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerAuthenticator: sender = deserializer.struct(AccountAuthenticator) addresses = deserializer.sequence(AccountAddress.deserialize) authenticators = deserializer.sequence(AccountAuthenticator.deserialize) fee_payer_addr = deserializer.struct(AccountAddress) fee_payer_auth = deserializer.struct(AccountAuthenticator) - return FeePayerAuthenticator( + return cls( sender, list(zip(addresses, authenticators)), (fee_payer_addr, fee_payer_auth), @@ -225,14 +225,14 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAuthenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAuthenticator: variant = deserializer.uleb128() match variant: case AccountAuthenticator.ED25519: - return AccountAuthenticator(Ed25519Authenticator.deserialize(deserializer)) + return cls(Ed25519Authenticator.deserialize(deserializer)) case AccountAuthenticator.SINGLE_KEY: - return AccountAuthenticator(SingleKeyAuthenticator.deserialize(deserializer)) + return cls(SingleKeyAuthenticator.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Unknown AccountAuthenticator variant: {variant}") @@ -281,18 +281,18 @@ def __eq__(self, other: object) -> bool: def verify(self, data: bytes) -> bool: return self.authenticator.verify(data) - @staticmethod - def deserialize(deserializer: Deserializer) -> Authenticator: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Authenticator: variant = deserializer.uleb128() match variant: case Authenticator.ED25519: - return Authenticator(Ed25519Authenticator.deserialize(deserializer)) + return cls(Ed25519Authenticator.deserialize(deserializer)) case Authenticator.MULTI_AGENT: - return Authenticator(MultiAgentAuthenticator.deserialize(deserializer)) + return cls(MultiAgentAuthenticator.deserialize(deserializer)) case Authenticator.FEE_PAYER: - return Authenticator(FeePayerAuthenticator.deserialize(deserializer)) + return cls(FeePayerAuthenticator.deserialize(deserializer)) case Authenticator.SINGLE_SENDER: - return Authenticator(SingleSenderAuthenticator.deserialize(deserializer)) + return cls(SingleSenderAuthenticator.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Unknown Authenticator variant: {variant}") diff --git a/v2/src/aptos_sdk_v2/transactions/payload.py b/v2/src/aptos_sdk_v2/transactions/payload.py index 14d98e6..1d8cf8a 100644 --- a/v2/src/aptos_sdk_v2/transactions/payload.py +++ b/v2/src/aptos_sdk_v2/transactions/payload.py @@ -28,20 +28,20 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"{self.address}::{self.name}" - @staticmethod - def from_str(module_id: str) -> ModuleId: + @classmethod + def from_str(cls, module_id: str) -> ModuleId: parts = module_id.split("::") if len(parts) != 2 or not parts[0] or not parts[1]: raise ValueError( f"Invalid module ID '{module_id}': expected format 'address::module_name'" ) - return ModuleId(AccountAddress.from_str(parts[0]), parts[1]) + return cls(AccountAddress.from_str(parts[0]), parts[1]) - @staticmethod - def deserialize(deserializer: Deserializer) -> ModuleId: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ModuleId: addr = AccountAddress.deserialize(deserializer) name = deserializer.str() - return ModuleId(addr, name) + return cls(addr, name) def serialize(self, serializer: Serializer) -> None: self.address.serialize(serializer) @@ -93,8 +93,9 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"{self.module}::{self.function}::<{self.ty_args}>({self.args})" - @staticmethod + @classmethod def natural( + cls, module: str, function: str, ty_args: list[TypeTag], @@ -102,15 +103,15 @@ def natural( ) -> EntryFunction: module_id = ModuleId.from_str(module) byte_args = [arg.encode() for arg in args] - return EntryFunction(module_id, function, ty_args, byte_args) + return cls(module_id, function, ty_args, byte_args) - @staticmethod - def deserialize(deserializer: Deserializer) -> EntryFunction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> EntryFunction: module = ModuleId.deserialize(deserializer) function = deserializer.str() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(Deserializer.to_bytes) - return EntryFunction(module, function, ty_args, args) + return cls(module, function, ty_args, args) def serialize(self, serializer: Serializer) -> None: self.module.serialize(serializer) @@ -134,12 +135,12 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.code == other.code and self.ty_args == other.ty_args and self.args == other.args - @staticmethod - def deserialize(deserializer: Deserializer) -> Script: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> Script: code = deserializer.to_bytes() ty_args = deserializer.sequence(TypeTag.deserialize) args = deserializer.sequence(ScriptArgument.deserialize) - return Script(code, ty_args, args) + return cls(code, ty_args, args) def serialize(self, serializer: Serializer) -> None: serializer.to_bytes(self.code) @@ -171,8 +172,8 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.variant == other.variant and self.value == other.value - @staticmethod - def deserialize(deserializer: Deserializer) -> ScriptArgument: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ScriptArgument: variant = deserializer.u8() value: Any match variant: @@ -196,7 +197,7 @@ def deserialize(deserializer: Deserializer) -> ScriptArgument: value = deserializer.bool() case _: raise BcsDeserializationError(f"Invalid ScriptArgument variant: {variant}") - return ScriptArgument(variant, value) + return cls(variant, value) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.variant) @@ -246,14 +247,14 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.variant == other.variant and self.value == other.value - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionExecutable: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionExecutable: variant = deserializer.uleb128() match variant: case TransactionExecutable.SCRIPT: - return TransactionExecutable(Script.deserialize(deserializer)) + return cls(Script.deserialize(deserializer)) case TransactionExecutable.ENTRY_FUNCTION: - return TransactionExecutable(EntryFunction.deserialize(deserializer)) + return cls(EntryFunction.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Invalid TransactionExecutable variant: {variant}") @@ -284,14 +285,14 @@ def __eq__(self, other: object) -> bool: and self.replay_protection_nonce == other.replay_protection_nonce ) - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionExtraConfig: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionExtraConfig: variant = deserializer.uleb128() if variant != 0: raise BcsDeserializationError(f"Invalid TransactionExtraConfig variant: {variant}") multisig = deserializer.option(AccountAddress.deserialize) nonce = deserializer.option(Deserializer.u64) - return TransactionExtraConfig(multisig_address=multisig, replay_protection_nonce=nonce) + return cls(multisig_address=multisig, replay_protection_nonce=nonce) def serialize(self, serializer: Serializer) -> None: serializer.uleb128(0) # V1 @@ -317,14 +318,14 @@ def __eq__(self, other: object) -> bool: return NotImplemented return self.executable == other.executable and self.extra_config == other.extra_config - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionInnerPayload: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionInnerPayload: variant = deserializer.uleb128() if variant != 0: raise BcsDeserializationError(f"Invalid TransactionInnerPayload variant: {variant}") executable = TransactionExecutable.deserialize(deserializer) extra_config = TransactionExtraConfig.deserialize(deserializer) - return TransactionInnerPayload(executable, extra_config) + return cls(executable, extra_config) def serialize(self, serializer: Serializer) -> None: serializer.uleb128(0) # V1 @@ -360,16 +361,16 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> TransactionPayload: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TransactionPayload: variant = deserializer.uleb128() match variant: case TransactionPayload.SCRIPT: - return TransactionPayload(Script.deserialize(deserializer)) + return cls(Script.deserialize(deserializer)) case TransactionPayload.ENTRY_FUNCTION: - return TransactionPayload(EntryFunction.deserialize(deserializer)) + return cls(EntryFunction.deserialize(deserializer)) case TransactionPayload.PAYLOAD: - return TransactionPayload(TransactionInnerPayload.deserialize(deserializer)) + return cls(TransactionInnerPayload.deserialize(deserializer)) case _: raise BcsDeserializationError(f"Invalid TransactionPayload variant: {variant}") diff --git a/v2/src/aptos_sdk_v2/transactions/raw_transaction.py b/v2/src/aptos_sdk_v2/transactions/raw_transaction.py index 92df114..ee81953 100644 --- a/v2/src/aptos_sdk_v2/transactions/raw_transaction.py +++ b/v2/src/aptos_sdk_v2/transactions/raw_transaction.py @@ -103,9 +103,9 @@ def sign_simulated(self, public_key: PublicKey) -> AccountAuthenticator: def verify(self, key: PublicKey, signature: Signature) -> bool: return key.verify(self.keyed(), signature) - @staticmethod - def deserialize(deserializer: Deserializer) -> RawTransaction: - return RawTransaction( + @classmethod + def deserialize(cls, deserializer: Deserializer) -> RawTransaction: + return cls( AccountAddress.deserialize(deserializer), deserializer.u64(), TransactionPayload.deserialize(deserializer), @@ -154,18 +154,18 @@ def serialize(self, serializer: Serializer) -> None: serializer.struct(self.raw_transaction) serializer.sequence(self.secondary_signers, Serializer.struct) - @staticmethod - def deserialize(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: tag = deserializer.u8() if tag != 0: raise BcsDeserializationError(f"Expected multi-agent tag 0, got {tag}") - return MultiAgentRawTransaction._deserialize_inner(deserializer) + return cls._deserialize_inner(deserializer) - @staticmethod - def _deserialize_inner(deserializer: Deserializer) -> MultiAgentRawTransaction: + @classmethod + def _deserialize_inner(cls, deserializer: Deserializer) -> MultiAgentRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary = deserializer.sequence(AccountAddress.deserialize) - return MultiAgentRawTransaction(raw_txn, secondary) + return cls(raw_txn, secondary) class FeePayerRawTransaction: @@ -203,18 +203,18 @@ def serialize(self, serializer: Serializer) -> None: fee_payer = self.fee_payer if self.fee_payer is not None else AccountAddress.from_str("0x0") serializer.struct(fee_payer) - @staticmethod - def deserialize(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> FeePayerRawTransaction: tag = deserializer.u8() if tag != 1: raise BcsDeserializationError(f"Expected fee-payer tag 1, got {tag}") - return FeePayerRawTransaction._deserialize_inner(deserializer) + return cls._deserialize_inner(deserializer) - @staticmethod - def _deserialize_inner(deserializer: Deserializer) -> FeePayerRawTransaction: + @classmethod + def _deserialize_inner(cls, deserializer: Deserializer) -> FeePayerRawTransaction: raw_txn = RawTransaction.deserialize(deserializer) secondary = deserializer.sequence(AccountAddress.deserialize) fee_payer_addr = AccountAddress.deserialize(deserializer) if fee_payer_addr == AccountAddress.from_str("0x0"): - return FeePayerRawTransaction(raw_txn, secondary, None) - return FeePayerRawTransaction(raw_txn, secondary, fee_payer_addr) + return cls(raw_txn, secondary, None) + return cls(raw_txn, secondary, fee_payer_addr) diff --git a/v2/src/aptos_sdk_v2/transactions/signed_transaction.py b/v2/src/aptos_sdk_v2/transactions/signed_transaction.py index 4981cb4..2a4eae8 100644 --- a/v2/src/aptos_sdk_v2/transactions/signed_transaction.py +++ b/v2/src/aptos_sdk_v2/transactions/signed_transaction.py @@ -70,11 +70,11 @@ def verify(self) -> bool: else: return self.authenticator.verify(self.transaction.keyed()) - @staticmethod - def deserialize(deserializer: Deserializer) -> SignedTransaction: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SignedTransaction: transaction = RawTransaction.deserialize(deserializer) authenticator = Authenticator.deserialize(deserializer) - return SignedTransaction(transaction, authenticator) + return cls(transaction, authenticator) def serialize(self, serializer: Serializer) -> None: self.transaction.serialize(serializer) diff --git a/v2/src/aptos_sdk_v2/types/account_address.py b/v2/src/aptos_sdk_v2/types/account_address.py index 6ac9b7d..405cd78 100644 --- a/v2/src/aptos_sdk_v2/types/account_address.py +++ b/v2/src/aptos_sdk_v2/types/account_address.py @@ -41,13 +41,13 @@ def is_special(self) -> bool: # --- Parsing --- - @staticmethod - def from_str(address: str) -> AccountAddress: + @classmethod + def from_str(cls, address: str) -> AccountAddress: """Strict AIP-40 parsing: LONG form or SHORT form for special addresses only.""" if not address.startswith("0x"): raise InvalidAddressError("Hex string must start with a leading 0x.") - out = AccountAddress.from_str_relaxed(address) + out = cls.from_str_relaxed(address) if len(address) != LENGTH * 2 + 2: if not out.is_special(): @@ -61,8 +61,8 @@ def from_str(address: str) -> AccountAddress: return out - @staticmethod - def from_str_relaxed(address: str) -> AccountAddress: + @classmethod + def from_str_relaxed(cls, address: str) -> AccountAddress: """Relaxed parsing: allows short form, padding zeroes, and optional 0x prefix.""" addr = address if addr.startswith("0x"): @@ -77,55 +77,53 @@ def from_str_relaxed(address: str) -> AccountAddress: addr = addr.zfill(LENGTH * 2) try: - return AccountAddress(bytes.fromhex(addr)) + return cls(bytes.fromhex(addr)) except ValueError as e: raise InvalidAddressError(f"Invalid hex in address: {e}") from e # --- Derived addresses --- - @staticmethod - def for_resource_account(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_resource_account(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DERIVE_RESOURCE_ACCOUNT) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_named_object(creator: AccountAddress, seed: bytes) -> AccountAddress: + @classmethod + def for_named_object(cls, creator: AccountAddress, seed: bytes) -> AccountAddress: hasher = hashlib.sha3_256() hasher.update(creator.address) hasher.update(seed) hasher.update(AuthKeyScheme.DERIVE_OBJECT_FROM_SEED) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_guid_object(creator: AccountAddress, creation_num: int) -> AccountAddress: + @classmethod + def for_guid_object(cls, creator: AccountAddress, creation_num: int) -> AccountAddress: hasher = hashlib.sha3_256() ser = Serializer() ser.u64(creation_num) hasher.update(ser.output()) hasher.update(creator.address) hasher.update(AuthKeyScheme.DERIVE_OBJECT_FROM_GUID) - return AccountAddress(hasher.digest()) + return cls(hasher.digest()) - @staticmethod - def for_named_collection(creator: AccountAddress, collection_name: str) -> AccountAddress: - return AccountAddress.for_named_object(creator, collection_name.encode()) + @classmethod + def for_named_collection(cls, creator: AccountAddress, collection_name: str) -> AccountAddress: + return cls.for_named_object(creator, collection_name.encode()) - @staticmethod + @classmethod def for_named_token( - creator: AccountAddress, collection_name: str, token_name: str + cls, creator: AccountAddress, collection_name: str, token_name: str ) -> AccountAddress: - return AccountAddress.for_named_object( - creator, collection_name.encode() + b"::" + token_name.encode() - ) + return cls.for_named_object(creator, collection_name.encode() + b"::" + token_name.encode()) # --- BCS --- - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddress: - return AccountAddress(deserializer.fixed_bytes(LENGTH)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddress: + return cls(deserializer.fixed_bytes(LENGTH)) def serialize(self, serializer: Serializer) -> None: serializer.fixed_bytes(self.address) diff --git a/v2/src/aptos_sdk_v2/types/chain_id.py b/v2/src/aptos_sdk_v2/types/chain_id.py index 2fab210..d31d1a2 100644 --- a/v2/src/aptos_sdk_v2/types/chain_id.py +++ b/v2/src/aptos_sdk_v2/types/chain_id.py @@ -21,9 +21,9 @@ def __post_init__(self) -> None: if not (0 <= self.value <= 255): raise ValueError(f"Chain ID must be 0-255, got {self.value}") - @staticmethod - def deserialize(deserializer: Deserializer) -> ChainId: - return ChainId(deserializer.u8()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> ChainId: + return cls(deserializer.u8()) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.value) diff --git a/v2/src/aptos_sdk_v2/types/type_tag.py b/v2/src/aptos_sdk_v2/types/type_tag.py index 2ec182a..c930593 100644 --- a/v2/src/aptos_sdk_v2/types/type_tag.py +++ b/v2/src/aptos_sdk_v2/types/type_tag.py @@ -51,9 +51,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> BoolTag: - return BoolTag(deserializer.bool()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> BoolTag: + return cls(deserializer.bool()) def serialize(self, serializer: Serializer) -> None: serializer.bool(self.value) @@ -69,9 +69,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U8Tag: - return U8Tag(deserializer.u8()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U8Tag: + return cls(deserializer.u8()) def serialize(self, serializer: Serializer) -> None: serializer.u8(self.value) @@ -87,9 +87,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U16Tag: - return U16Tag(deserializer.u16()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U16Tag: + return cls(deserializer.u16()) def serialize(self, serializer: Serializer) -> None: serializer.u16(self.value) @@ -105,9 +105,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U32Tag: - return U32Tag(deserializer.u32()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U32Tag: + return cls(deserializer.u32()) def serialize(self, serializer: Serializer) -> None: serializer.u32(self.value) @@ -123,9 +123,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U64Tag: - return U64Tag(deserializer.u64()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U64Tag: + return cls(deserializer.u64()) def serialize(self, serializer: Serializer) -> None: serializer.u64(self.value) @@ -141,9 +141,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U128Tag: - return U128Tag(deserializer.u128()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U128Tag: + return cls(deserializer.u128()) def serialize(self, serializer: Serializer) -> None: serializer.u128(self.value) @@ -159,9 +159,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> U256Tag: - return U256Tag(deserializer.u256()) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> U256Tag: + return cls(deserializer.u256()) def serialize(self, serializer: Serializer) -> None: serializer.u256(self.value) @@ -177,9 +177,9 @@ def variant(self) -> int: def __str__(self) -> str: return str(self.value) - @staticmethod - def deserialize(deserializer: Deserializer) -> AccountAddressTag: - return AccountAddressTag(deserializer.struct(AccountAddress)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> AccountAddressTag: + return cls(deserializer.struct(AccountAddress)) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.value) @@ -193,9 +193,9 @@ def variant(self) -> int: def __str__(self) -> str: return "signer" - @staticmethod - def deserialize(deserializer: Deserializer) -> SignerTag: - return SignerTag() + @classmethod + def deserialize(cls, deserializer: Deserializer) -> SignerTag: + return cls() def serialize(self, serializer: Serializer) -> None: pass @@ -231,8 +231,8 @@ def __str__(self) -> str: value += f"<{args}>" return value - @staticmethod - def from_str(type_tag: str) -> StructTag: + @classmethod + def from_str(cls, type_tag: str) -> StructTag: tags, _ = _parse_type_tags(type_tag, 0) if not tags: # pragma: no cover — parser always appends via _make_struct_tag raise InvalidTypeTagError(f"Cannot parse type tag: {type_tag}") @@ -241,13 +241,13 @@ def from_str(type_tag: str) -> StructTag: raise InvalidTypeTagError(f"Expected StructTag, got {type(inner).__name__}") return inner - @staticmethod - def deserialize(deserializer: Deserializer) -> StructTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> StructTag: address = deserializer.struct(AccountAddress) module = deserializer.str() name = deserializer.str() type_args = deserializer.sequence(TypeTag.deserialize) - return StructTag(address, module, name, type_args) + return cls(address, module, name, type_args) def serialize(self, serializer: Serializer) -> None: self.address.serialize(serializer) @@ -274,9 +274,9 @@ def __eq__(self, other: object) -> bool: def __str__(self) -> str: return f"vector<{self.element_type}>" - @staticmethod - def deserialize(deserializer: Deserializer) -> VectorTag: - return VectorTag(TypeTag.deserialize(deserializer)) + @classmethod + def deserialize(cls, deserializer: Deserializer) -> VectorTag: + return cls(TypeTag.deserialize(deserializer)) def serialize(self, serializer: Serializer) -> None: serializer.struct(self.element_type) @@ -319,34 +319,34 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - @staticmethod - def deserialize(deserializer: Deserializer) -> TypeTag: + @classmethod + def deserialize(cls, deserializer: Deserializer) -> TypeTag: variant = deserializer.uleb128() match variant: # Primitive variants carry no BCS payload after the discriminant. case TypeTagVariant.BOOL: - return TypeTag(BoolTag(False)) + return cls(BoolTag(False)) case TypeTagVariant.U8: - return TypeTag(U8Tag(0)) + return cls(U8Tag(0)) case TypeTagVariant.U16: - return TypeTag(U16Tag(0)) + return cls(U16Tag(0)) case TypeTagVariant.U32: - return TypeTag(U32Tag(0)) + return cls(U32Tag(0)) case TypeTagVariant.U64: - return TypeTag(U64Tag(0)) + return cls(U64Tag(0)) case TypeTagVariant.U128: - return TypeTag(U128Tag(0)) + return cls(U128Tag(0)) case TypeTagVariant.U256: - return TypeTag(U256Tag(0)) + return cls(U256Tag(0)) case TypeTagVariant.ACCOUNT_ADDRESS: - return TypeTag(AccountAddressTag(AccountAddress(b"\x00" * 32))) + return cls(AccountAddressTag(AccountAddress(b"\x00" * 32))) case TypeTagVariant.SIGNER: - return TypeTag(SignerTag()) + return cls(SignerTag()) # Composite variants do have inner BCS data. case TypeTagVariant.VECTOR: - return TypeTag(VectorTag.deserialize(deserializer)) + return cls(VectorTag.deserialize(deserializer)) case TypeTagVariant.STRUCT: - return TypeTag(StructTag.deserialize(deserializer)) + return cls(StructTag.deserialize(deserializer)) case _: raise InvalidTypeTagError(f"Unknown TypeTag variant: {variant}") @@ -357,8 +357,8 @@ def serialize(self, serializer: Serializer) -> None: if isinstance(self.value, (VectorTag, StructTag)): serializer.struct(self.value) - @staticmethod - def from_str(type_tag: str) -> TypeTag: + @classmethod + def from_str(cls, type_tag: str) -> TypeTag: """Parse a Move type-tag string into a :class:`TypeTag`. Supports: